############ # poe musician using distributed probabability # # # it should be pretty easy to get one musician to write a random # head, and get the others to jam along. # # Author: Steve McNabb (steve@justsomeguy.com) package POE::Framework::MIDI::Musician::Probability; use POE::Framework::MIDI::Musician; use POE::Framework::MIDI::Bar; use POE::Framework::MIDI::Note; use POE::Framework::MIDI::Rest; use vars qw/@ISA $VERSION/; $VERSION = 0.1; @ISA = qw(POE::Framework::MIDI::Musician); sub new { my($self,$class) = ({},shift); $self->{cfg} = shift; bless($self,$class); $self->set_weights; return $self; } sub make_bar { my $self = shift; my $barnum = shift; my $interval = rand_dist_weighted($weights); my $bar = new POE::Framework::MIDI::Bar( { number => $barnum } ); for(1..4) { my $name = rand_dist_weighted($self->{cfg}->{note_weights}); my $duration = rand_dist_weighted($self->{cfg}->{duration_weights}); my $note = new POE::Framework::MIDI::Note( { name => $name, duration => $duration, } ); print "make $_ in $barnum: $name $duration " .$self->name ." \n" if $self->{cfg}->{debug}; $bar->add_event($note); } return $bar; } # ripped off from m.a.w.p. # $selection = rand_dist_weighted( \%dist, \@key_order, $total_weight ) # Select an element from %dist. The total of the weights, and the # keys sorted by their weights can be provided, or else they are # computed. sub rand_dist_weighted { my( $dist, $key_order, $total_weight ) = @_; my $running_weight; $key_order = [ sort { $dist->{$a} <=> $dist->{$b} } keys %$dist ] unless $key_order; unless ( $total_weight ) { foreach (@$key_order) { $total_weight += $dist->{$_} } } # Get a random value. my $rand = rand( $total_weight ); # Use it to determine a key. foreach my $key (@$key_order) { return $key if ($running_weight += $dist->{$key}) >= $rand; } } sub set_weights { my $self = shift; # set some default weights just in case $self->{cfg}->{note_weights} = { C => 1, Cs => 1, D => 1, Ds => 1, E => 1, F => 1, Fs => 1, G => 1, Gs => 1, A => 1, As => 1, B => 1, } unless $self->{cfg}->{note_weights}; # some default octave weights. how often to switch octaves randomly $self->{cfg}->{octave_weights} = { same => 10, up => 3, down => 3 } unless $self->{cfg}->{octave_weights}; $self->{cfg}->{duration_weights} = { qn => 5, en => 12, sn => 10, tsn => 11, wn => 8, } unless $self->{cfg}->{duration_weights}; } 1;