package Rain; #Rain.pm - sound object that translates synthesis data into a csound script #Copyright (C) 2001 Jacob T. Joaquin # #This program is free software; you can redistribute it and/or #modify it under the terms of the GNU General Public License #as published by the Free Software Foundation; either version 2 #of the License, or (at your option) any later version. # #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. # #You should have received a copy of the GNU General Public License #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use strict; use ComputerMusic; use ScoreFilter; sub new { my $self = {}; $self->{INSTR} = 1; $self->{DURATION} = 1; $self->{AMP} = 1; $self->{PITCH} = 440; # base pitch of harmonics $self->{ATTACK} = 0.05; # attack time of amplitude $self->{PAN} = 0.5; # pan position $self->{LAG} = 1; # fixed time ratio between harmonics $self->{NHARMONICS} = 4; # number of harmonics to create $self->{BEND} = 1; # bend amount of harmonics $self->{SLOPE} = 1; # Slope of harmonic amplitude $self->{REVERB} = 1; $self->{REVERBMIX} = 1; $self->{CHAOS} = Chaos->new(0.5, 0.5); # chaos time ratio between harmonics bless($self); return $self; } sub instr { my $self = shift; if (@_) { $self->{INSTR} = shift } return $self->{INSTR}; } sub duration { my $self = shift; if (@_) { $self->{DURATION} = shift } return $self->{DURATION}; } sub amp { my $self = shift; if (@_) { $self->{AMP} = shift } return $self->{AMP}; } sub pitch { my $self = shift; if (@_) { $self->{PITCH} = shift } return $self->{PITCH}; } sub attack { my $self = shift; if (@_) { $self->{ATTACK} = shift } return $self->{ATTACK}; } sub pan { my $self = shift; if (@_) { $self->{PAN} = shift } return $self->{PAN}; } sub lag { my $self = shift; if (@_) { $self->{LAG} = shift } return $self->{LAG}; } sub nHarmonics { my $self = shift; if (@_) { $self->{NHARMONICS} = shift } return $self->{NHARMONICS}; } sub bend { my $self = shift; if (@_) { $self->{BEND} = shift } return $self->{BEND}; } sub slope { my $self = shift; if (@_) { $self->{SLOPE} = shift } return $self->{SLOPE}; } sub reverb { my $self = shift; if (@_) { $self->{REVERB} = shift } return $self->{REVERB}; } sub reverbMix { my $self = shift; if (@_) { $self->{REVERBMIX} = shift } return $self->{REVERBMIX}; } sub score { my $self = shift; my $triggerTime = shift; # time to trigger harmonics my $scoreReturn = ''; my $currentPitch = $self->pitch(); my @pitchList; # to store the pitches of each harmonic my @ampList; # to store the amplitudes of each harmonic undef @pitchList; # make sure list is empty undef @ampList; # create pitches of each harmonic and store in @pitchList push (@pitchList, $currentPitch); push (@ampList, $self->amp()); for(2..$self->nHarmonics()) { $currentPitch = ComputerMusic::harmonic($currentPitch, int(rand(2)+1), int(rand(3)+1), $self->bend()); push (@pitchList, $currentPitch); push (@ampList, $ampList[$#ampList] * $self->slope()); } my @temp; @temp = sort { $a <=> $b } @pitchList; # sort @pitchList undef @pitchList; push (@pitchList, $self->pitch()); shift @temp; foreach (@temp) { if ($_ > $self->pitch() && $_ < 22050) { push (@pitchList, $_) } } # write to $scoreReturn for (0..$#pitchList) { $scoreReturn .= sprintf "i%d %.8f %.4f %.4f %.4f %.4f %.4f %.4f %d\n", $self->{INSTR}, $triggerTime, $self->{DURATION}, $ampList[$_], $pitchList[$_], $self->{ATTACK}, $self->{PAN}, $self->{REVERBMIX}, $self->{REVERB}; # calculate time for next harmonic unless ($_==$self->nHarmonics()-1) {$triggerTime+=$self->{CHAOS}->normalized()*$self->lag()} } $scoreReturn .= "\n"; # $scoreReturn = ScoreFilter::bandpass($scoreReturn, 5, $self->pitch(), 22050) . "\n"; return $scoreReturn; } 1;