💾 Archived View for thrig.me › blog › 2024 › 10 › 04 › trig.pl captured on 2024-12-17 at 12:09:35.

View Raw

More Information

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

#!/usr/bin/env perl
# mess around with trig functions, producing MIDI of dubious merit
use 5.36.0;
use MIDI;
my @events;

my $out_file = shift // 'out.midi';

# how fine or coarse to check on the output of the equation (will depend
# on the equation, how many notes you want, how much silence from
# overchecking for zero-crossings, etc)
my $step = 0.05;

# how long to carry the steps for
my $max_step = 101;

# how long of a MIDI event to generate (also used for silence
# accumulation). the MIDI tempo could also be played around with,
# or $step could be used as a real-time value to sleep for, with a
# live synth
my $tick = 8;

sub equation ($t) {
    #sin( $t * 5 ) + cos( $t * 2 );
    sin( $t * 5 ) + cos( ( $t + sin( $t / 1 ) ) * 7 );
}

sub add_note ($dtime, $x) {
    my @n = qw(48 49 48 48 48 49 49 48);
    state $i = 0;
    my $n = $n[$i++ % @n];
    #my @n = qw(48 49 53 55 56);
    #my $n = $n[abs($x * @n)];
    #$n = 48;
    push @events,
      [ note_on  => $dtime, 0, $n, 100 ],
      [ note_off => $tick,  0, $n, 0 ];
}

my $t     = 0;
my $z     = 0;
my $swaps = 0;
my $dtime = 0;
while ( $t < $max_step ) {
    my $x = equation($t);
    # highlander with the previous value in a perhaps dubious use of xor
    # but it works so here we are
    if ( ( $x >= 0 ) ^ ( $z >= 0 ) ) {
        $swaps++;
        #say "$t $x $prev";
        add_note($dtime, $x);
        $dtime = 0;
    } else {
        $dtime += $tick;
    }
    $t += $step;
    $z = $x;
}
say "swaps $swaps";

sub make_tracks () { [ MIDI::Track->new( { events => \@events } ) ] }

MIDI::Opus->new(
    { format => 0, ticks => 96, tracks => make_tracks() } )
  ->write_to_file($out_file);