Skip to content

Instantly share code, notes, and snippets.

@justecorruptio
Created September 29, 2014 05:32
Show Gist options
  • Save justecorruptio/4037f167167a2c235b0d to your computer and use it in GitHub Desktop.
Save justecorruptio/4037f167167a2c235b0d to your computer and use it in GitHub Desktop.
Perl Synthsizer
$SPS = 16000;
$PI = 3.14159265359;
$PITCH_ROLL = 1;
$BPM = 170;
%FREQS = (
A => 440.000,
B => 493.883,
C => 261.626,
D => 293.665,
E => 329.628,
F => 349.228,
G => 391.995
);
$HALF_STEP = 2. ** (1. / 12);
sub add_phrase{
my ($track, $notes, $offset_bars, $inst) = @_;
my $pos = $offset_bars * $SPS * 60 * 4 / $BPM;
my $falloff_beats = $FALLOFF * $SPS * 60 * 4 / $BPM;
my $attack_beats = $ATTACK * $SPS * 60 * 4 / $BPM;
my @notes = split /\s+/, $notes;
my $last_dur;
for my $note(@notes){
my ($key, $acc, $octave, $mult, $div) = $note =~ /([_A-G])([b#]?)(?:(-?\d+))?(?:[*](\d+))?(?:[\/](\d+))?/ or next;
my $dur = $mult + $div? $SPS * 60 * 4 * ($mult||1) / $BPM / ($div||1): $last_dur;
$pos += $dur, next if $key eq '_';
$octave -= 4;
$key = $FREQS{$key};
my $freq = $key * (2 ** $octave);
$freq *= $HALF_STEP if $acc eq '#';
$freq /= $HALF_STEP if $acc eq 'b';
$note_len = $falloff_beats && $falloff_beats > $dur ? $falloff_beats: $dur;
if ($inst eq 'sine') {
$pitch = 1.;
for $i (0..$note_len){
$pitch *= $PITCH_ROLL;
my $h = sin( 1.0 * $i * $freq * 2 * $PI * $pitch/ $SPS);
my $falloff = 1;
$falloff = 1.0 - ($i / $note_len) ** .5 if $falloff_beats;
$falloff *= $i / $attack_beats if $attack_beats && $i < $attack_beats;
# prevent popping
$falloff *= 1.0 * ($i) / 10 if $i < 10;
$falloff *= 1.0 * ($note_len - $i) / 10 if $note_len - $i < 10;
$track->[$pos + $i] += $VELOCITY * (2 ** 24) * $falloff * $h;
}
}
elsif ($inst eq 'noise') {
for $i (0..$note_len){
my $falloff = 1;
if($falloff_beats){
my $factor = $i / $falloff_beats;
next if $factor > 1.;
$falloff = 1.0 - $factor ** .5
};
$falloff *= $i / $attack_beats if $attack_beats && $i < $attack_beats;
# prevent popping
$falloff *= 1.0 * ($i) / 10 if $i < 10;
$falloff *= 1.0 * ($note_len - $i) / 10 if $note_len - $i < 10;
$track->[$pos + $i] += $VELOCITY * (2 ** 24) * $falloff * (rand() * 2 - 1);
}
}
$pos += $dur;
$last_dur = $dur;
}
}
sub render_score{
my (@tracks) = @_;
print".snd",pack"N*",24,-1,5,$SPS,1;
my $max = 0;
for my $track (@tracks){
$max = $#$track if $#$track > $max;
}
for my $i (0..$max){
my $avg = 0.;
for $track(@tracks){
$avg += $track->[$i];
}
$avg /= $#tracks + 1;
$avg = 2**31 - 1 if $avg > 2**31 - 1;
$avg = - 2**31 if $avg < - 2**31;
print pack("N", $avg);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment