#!/usr/bin/perl # lsystem-to-midi - can we do something musical with the output of a # L-system? there are as ever things to TWEAK use 5.36.0; use MIDI; # TWEAK output from a L-system my $s = 'F+G+F-G+F+G-F-G+F+G+F-G-F+G-F-G+F+G+F-G+F+G-F-G-F+G+F-G-F+G-F-G+F+G+F-G+F+G-F-G+F+G+F-G-F+G-F-G-F+G+F-G+F+G-F-G-F+G+F-G-F+G-F-G+F+G+F-G+F+G-F-G+F+G+F-G-F+G-F-G+F+G+F-G+F+G-F-G-F+G+F-G-F+G-F-G-F+G+F-G+F+G-F-G+F+G+F-G-F+G-F-G-F+G+F-G+F+G-F-G-F+G+F-G-F+G-F-G+F+G+F-G+F+G-F-G+F+G+F-G-F+G-F-G+F+G+F-G+F+G-F-G-F+G+F-G-F+G-F-G+F+G+F-G+F+G-F-G+F+G+F-G-F+G-F-G-F+G+F-G+F+G-F-G-F+G+F-G-F+G-F-G-F+G+F-G+F+G-F-G+F+G+F-G-F+G-F-G+F+G+F-G+F+G-F-G-F+G+F-G-F+G-F-G-F+G+F-G+F+G-F-G+F+G+F-G-F+G-F-G-F+G+F-G+F+G-F-G-F+G+F-G-F+G-F-G'; my $chan = 0; # MIDI channel # TWEAK pitch selections my @table = ( [qw( 52 59 64 71 67 )], [qw( 59 54 62 54 59 )], ); my $ts = 0; # table selector my $i = 0; # sub-table index # TWEAK durations to change between (mostly used by rest()) my @duration = qw( 24 12 ); my $j = 0; # duration index my $leftover = 0; # MIDI dtime runover my $notes = 0; # how many notes have we burned through? my @events = ( [ patch_change => 0, $chan, 114 ], ); sub velonoise () { int( rand 4 + rand 4 + rand 4 ) } sub note ($i) { push @events, [ note_on => $leftover, $chan, $table[$ts][$i], 101 + velonoise() ], [ note_off => $duration[0], $chan, $table[$ts][$i], 0 ]; $leftover = 0; # TWEAK this shift should probably be some divisor of the total # number of notes if ( ++$notes % 32 == 0 ) { $ts ^= 1; } } sub rest { $leftover += $duration[$j] } # a 'F' generates a rest (of some changing duration), a 'G' a note (of # some changing pitch, and different selections of pitches over time), # and '+' and '-' shift the pitch- and duration- pointer for what F and # G select on for my $c ( split '', $s ) { if ( $c eq 'F' ) { rest(); } elsif ( $c eq 'G' ) { note($i); } elsif ( $c eq '+' ) { $i = ( $i + 1 ) % $table[$ts]->@*; } elsif ( $c eq '-' ) { $j = ( $i + 1 ) % @duration; } } # TWEAK plus a manual coda push @events, [ note_on => 24, $chan, 71, 107 + velonoise() ], [ note_off => 36, $chan, 71, 0 ], [ note_on => 0, $chan, 71, 107 + velonoise() ], [ note_off => 48, $chan, 71, 0 ]; MIDI::Opus->new( { format => 0, ticks => 96, tracks => [ MIDI::Track->new( { events => \@events } ) ], } )->write_to_file('out.midi');