💾 Archived View for thrig.me › blog › 2023 › 10 › 07 › drums.pl captured on 2024-08-18 at 20:42:19.
⬅️ Previous capture (2023-11-04)
-=-=-=-=-=-=-
#!/usr/bin/env perl # drums - hybrid but with different instrumentation. Asian drums or # gamelan might not be terrible to use here? use 5.26.0; use MIDI; sub CCPAN () { 0x0A } sub CHAN () { 0 } sub MAXTIME () { 10240 * 8 } sub NOW () { 0 } sub QUIET () { 0 } my $file = shift // 'drums.midi'; my $track_count = 8; my @velo = qw( 105 80 90 80 ); sub velonoise { int( rand 4 + rand 4 + rand 4 ) } sub velorand { $velo[rand @velo] + velonoise } sub velostep { state $i = 0; my $v = $velo[$i]; $i = ( $i + 1 ) % @velo; $v + velonoise; } sub makeatrack { state $pan = 40; # NOTE depends on track_count state $pitch = 42; my $interval = 16 * ( 1 + int rand 8 ); my $periodic = 1; my $sectionlen = 1024; my $rand = 256; my $mul = 2; my $dur = 16 * ( int rand 8 ); my @events = ( [ set_tempo => NOW, 800_000 ], [ patch_change => NOW, CHAN, 47 ], [ marker => $dur ], ); my ( $epoch, $subepoch ) = ( $dur, $dur ); while (1) { if ($periodic) { $subepoch += $interval * $mul; $epoch += $subepoch; if ( $subepoch >= $sectionlen ) { my $delta = $subepoch - $sectionlen; if ( $delta > 0 ) { $epoch -= $delta; push @events, [ marker => $delta ]; } $subepoch = 0; $periodic ^= 1; next; } push @events, [ control_change => NOW, CHAN, CCPAN, $pan ], [ note_on => NOW, CHAN, $pitch, velostep ], [ note_off => $interval, CHAN, $pitch, QUIET ]; } else { my $delay = ( 1 + int rand $rand ) * $mul; $subepoch += $interval; $epoch += $subepoch; if ( $subepoch >= ( $sectionlen / 2 ) ) { my $delta = $subepoch - $sectionlen; # BUG ! if ( $delta > 0 ) { $epoch -= $delta; push @events, [ marker => $delta ]; } $subepoch = 0; $periodic ^= 1; next; } push @events, [ control_change => NOW, CHAN, CCPAN, $pan ], [ note_on => NOW, CHAN, $pitch, velostep ], [ note_off => $delay, CHAN, $pitch, QUIET ]; } } continue { last if $epoch >= MAXTIME; } $pan += 6; # NOTE depends on track_count my @leaps = ( 3, 5, 5, 5, 7 ); $pitch += $leaps[ rand @leaps ]; MIDI::Track->new( { events => \@events } ); } sub gentracks { [ map makeatrack, 1 .. $track_count ] } MIDI::Opus->new( { tracks => gentracks } )->write_to_file($file);