💾 Archived View for thrig.me › blog › 2023 › 10 › 07 › hybrid.pl captured on 2024-05-26 at 15:49:15.

View Raw

More Information

⬅️ Previous capture (2023-11-14)

-=-=-=-=-=-=-

#!/usr/bin/env perl
# hybrid - mix periodic and more whitenoise-y generation. probably there
# may be better ways of blending the generation methods
use 5.26.0;
use MIDI;
sub CCPAN ()   { 0x0A }
sub COWBELL () { 56 }
sub DRUMS ()   { 9 }
sub MAXTIME () { 10240 * 8 }
sub NOW ()     { 0 }
sub QUIET ()   { 0 }

my $file = shift // 'hybrid.midi';

my $track_count = 8;

my @velo = qw( 105 80 90 80 );

sub velorand { 80 + int rand 25 }

sub velostep {
    state $i = 0;
    my $v = $velo[$i];
    $i = ( $i + 1 ) % @velo;
    $v;
}

sub makeatrack {
    state $pan = 40;    # NOTE depends on track_count
    my $interval   = 32 * ( 1 + int rand 4 );
    my $periodic   = 1;
    my $sectionlen = 1024;
    my $rand       = 256;

    my $dur    = 32 * ( int rand 4 );
    my @events = ( [ marker => $dur ] );
    my ( $epoch, $subepoch ) = ( $dur, $dur );

    # the style transition ain't perfect but it works?
    while (1) {
        if ($periodic) {
            $subepoch += $interval;
            $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, DRUMS, CCPAN,   $pan ],
              [ note_on        => NOW, DRUMS, COWBELL, velostep ],
              [ note_off       => $interval, DRUMS, COWBELL, QUIET ];
        } else {
            my $delay = 1 + int rand $rand;
            $subepoch += $interval;
            $epoch    += $subepoch;
            if ( $subepoch >= ( $sectionlen / 2 ) ) {
                my $delta = $subepoch - ( $sectionlen / 2 );
                if ( $delta > 0 ) {
                    $epoch -= $delta;
                    push @events, [ marker => $delta ];
                }
                $subepoch = 0;
                $periodic ^= 1;
                next;
            }
            push @events,
              [ control_change => NOW, DRUMS, CCPAN,   $pan ],
              [ note_on        => NOW, DRUMS, COWBELL, velostep ],
              [ note_off       => $delay, DRUMS, COWBELL, QUIET ];
        }
    } continue {
        last if $epoch >= MAXTIME;
    }
    $pan += 6;    # NOTE depends on track_count
    MIDI::Track->new( { events => \@events } );
}

sub gentracks { [ map makeatrack, 1 .. $track_count ] }

MIDI::Opus->new( { tracks => gentracks } )->write_to_file($file);