Algorithm-Gutter
view release on metacpan or search on metacpan
eg/rainmidi3000.pl view on Meta::CPAN
# Wire up the togglers to toggle a random toggler or pitch generator
# cell, if possible.
my @targets = shuffle grep { $_->enabled } @$glist;
for my $cell ( shuffle @$glist ) {
unless ( defined $cell->context ) {
if (@targets) {
$cell->context->{toggles} = shift @targets;
$cell->enabled = coinflip();
} else {
( $cell->enabled, $cell->threshold, $cell->update ) =
( 0, ~0, undef );
}
}
}
# What thing did we wire up? Some way to visualize this over time might
# also help direct one towards better wirings?
show_wiring($glist);
{
# TWEAK fewer slosh iterations makes the fluid more viscous and thus
# less able to spread out to adjacent cells
#my $slosh_iters;
my $slosh_iters = 2;
my %slosh;
my $offset = 0;
for my $turn ( 1 .. 128 ) {
$gobj->rain;
# TWEAK whether to drain all the fluid (1) or only up to the
# threshold (0) but whether this makes a difference depends on
# how much rain is being added, etc
my @pitches = $gobj->drain(0);
if (@pitches) {
sound( $offset, @pitches );
} else {
$offset += $tick + ticknoise();
}
my $r = $gobj->slosh( $slosh_iters // ~0 );
unless ( defined $slosh_iters ) {
$slosh{$r}++;
}
}
unless ( defined $slosh_iters ) {
warn Data::Dumper->Dump( [ \%slosh ], ['slosh_iters'] );
}
}
MIDI::Opus->new(
{ format => 0, ticks => 96, tracks => make_track() } )
->write_to_file($out_file);
########################################################################
#
# SUBROUTINES
sub coinflip { int rand 2 }
# This is for when you want random pitches, possibly when using a drum
# SountFont and to select from random drum samples. The MIDI number
# range may well need to be fiddled with. Softlocks if you try to
# request too many pitches from it, so don't do that.
{
my %seen;
sub getapitch {
my $p;
do {
$p = 24 + int rand( 77 - 24 );
} while exists $seen{$p};
$seen{$p} = 1;
return $p;
}
}
sub make_track () { [ MIDI::Track->new( { events => \@events } ) ] }
sub pitch { $_[0]->context->{pitch} }
sub show_wiring {
my ($gutter) = @_;
for my $cell (@$gutter) {
my $s = sprintf '% 3d ', $cell->id;
if ( defined $cell->update ) {
$s .= join ' ', $cell->enabled ? '+' : '-', sprintf '% 3d',
$cell->threshold;
my $c = $cell->context;
if ( $cell->update == \&pitch ) {
$s .= ' MIDI -> ' . $cell->context->{pitch};
} else {
$s .= ' TOGGLE #' . $cell->context->{toggles}->id;
}
}
say $s;
}
}
# Generate MIDI events for one or more pitches happening at the
# same time.
sub sound {
my ( $offset, @pitch ) = @_;
# TWEAK limit how notes can sound at the same time. Note choice will
# depend on how the pitches get shuffled into the gutter.
my $at_most = 4;
my $left = $at_most;
for my $n (@pitch) {
push @events, [ note_on => $offset, $ch, $n, velonoise() ];
$offset = 0;
last unless --$left;
}
# Note duration. This could be shortened and an $offset on the next
# start event added elsewhere to produce staccato notes, or you can
# get much the same effect by using a small $tick value and not
# having much rainfall.
$offset = $tick + ticknoise();
$left = $at_most;
for my $n (@pitch) {
push @events, [ note_off => $offset, $ch, $n, 0 ];
$offset = 0;
last unless --$left;
( run in 0.937 second using v1.01-cache-2.11-cpan-e1769b4cff6 )