NAME
Music::Duration::Partition::Tutorial::Advanced
VERSION
version 0.0823
Usage Examples
Shuffling the Motif
By shuffling a single generated motif, you can get permutations of the durations.
use List::Util qw(shuffle);
use MIDI::Util qw(setup_score);
use Music::Duration::Partition ();
use Music::Scales qw(get_scale_MIDI);
my $score = setup_score(bpm => 90);
my @scale = get_scale_MIDI('A', 3, 'pminor');
# instantiate a 4 beat phrase generator
my $mdp = Music::Duration::Partition->new(
pool => [qw(qn en sn)],
#pool => [qw(twn thn tqn ten tsn)],
);
# get a single motif of note durations
my $motif = $mdp->motif;
# repeat 2 measures, 8 times
for my $i (1 .. 8) {
# get a fresh set of random scale pitches for the motif
my @voices = map { $scale[ int rand @scale ] } 0 .. $#$motif;
# every other measure, shuffle the motif durations
my @phrase = $i % 2 ? @$motif : shuffle @$motif;
$mdp->add_to_score($score, \@phrase, \@voices);
$score->r('wn');
}
$score->write_score('shuffled.mid');
Computing Voices
Play the same motif but with different voices computed by the Voss method.
use MIDI::Util qw(setup_score);
use Music::Duration::Partition ();
use Music::Scales qw(get_scale_MIDI);
use Music::Voss qw(powers);
my $score = setup_score(bpm => 90);
my $mdp = Music::Duration::Partition->new(
pool => [qw(qn en sn)],
);
my $motif = $mdp->motif;
# get the scale and compute a generating function
my ($scale, $genf) = voss('A', 5, 'minor');
for my $i (1 .. 8) {
my @voices = map { $scale->[ $genf->($_) % @$scale ] } 0 .. $#$motif;
$mdp->add_to_score($score, $motif, \@voices);
$score->r('wn');
}
$score->write_score('voss.mid');
sub voss {
my ($note, $octave, $named) = @_;
my @scale = get_scale_MIDI($note, $octave, $named);
my $seed = [ map { sub { int rand 2 } } @scale ];
my $genf = powers(calls => $seed);
return \@scale, $genf;
}
Weights and Grouping
Triplet durations will be twice as likely to be chosen, and will be played in groups of 3.
use MIDI::Util qw(setup_score);
use Music::Duration::Partition ();
use Music::Scales qw(get_scale_MIDI);
my $score = setup_score(bpm => 120);
my @scale = get_scale_MIDI('C', 4, 'major');
my $mdp = Music::Duration::Partition->new(
size => 8,
pool => [qw(hn qn ten)],
weights => [ 1, 1, 2 ],
groups => [ 1, 1, 3 ],
verbose => 1,
);
my $motif = $mdp->motif;
for my $i (1 .. 4) {
for my $n (0 .. $#$motif) {
$score->n($motif->[$n], $scale[ int rand @scale ]);
}
}
$score->n('wn', $scale[0]);
$score->write_score('weighted-grouped.mid');
Figured Bass
Play a an alternating, randomized bass-line of 2 motifs, for 3 beats and rest for the 4th. Also play a steady closed hi-hat simultaneously.
use MIDI::Drummer::Tiny ();
use MIDI::Util qw(set_chan_patch);
use Music::Duration::Partition ();
use Music::Scales qw(get_scale_MIDI);
use Music::VoiceGen ();
my $d = MIDI::Drummer::Tiny->new(file => 'figured.mid');
$d->sync(
\&beat, # must come first so the channel is 9
\&bass,
);
$d->write;
sub beat {
for my $n (1 .. 8) {
$d->note($d->quarter, $d->closed_hh) for 1 .. 4;
}
}
sub bass {
set_chan_patch($d->score, 0, 35); # fretless bass on channel 0
my $mdp = Music::Duration::Partition->new(
size => 3,
pool => [qw(qn en sn)],
);
my @motifs = $mdp->motifs(2);
my @pitches = get_scale_MIDI('A', 2, 'pminor');
my $voice = Music::VoiceGen->new(
pitches => \@pitches,
intervals => [qw(-4 -3 -2 2 3 4)],
);
my @notes1 = map { $voice->rand } $motifs[0]->@*;
for my $i (1 .. 8) {
if ($i % 2) {
$mdp->add_to_score($d->score, $motifs[0], \@notes1);
}
else {
my @notes2 = map { $voice->rand } $motifs[1]->@*;
$mdp->add_to_score($d->score, $motifs[1], \@notes2);
}
$d->rest($d->quarter);
}
}
7/8 Time
In x/8
time, the Music::Duration::Partition size
must be the number of beats (i.e. 7 here) divided by 2.
use MIDI::Drummer::Tiny ();
use MIDI::Util qw(set_chan_patch);
use Music::Duration::Partition ();
use Music::Scales qw(get_scale_MIDI);
use Music::VoiceGen ();
my $d = MIDI::Drummer::Tiny->new(
file => 'odd-meter.mid',
bpm => 90,
signature => '7/8',
bars => 8,
);
$d->sync(
\&drums,
\&bass,
);
$d->write;
sub drums {
$d->metronome78($d->bars * 2);
}
sub bass {
set_chan_patch($d->score, 0, 35);
my $mdp = Music::Duration::Partition->new(
size => 3.5, # == 7/2
pool => [qw(qn en)],
groups => [ 1, 2 ],
);
my ($motif1, $motif2) = $mdp->motifs(2);
my @pitches = get_scale_MIDI('C', 2, 'pminor');
my @intervals = qw(-3 -2 -1 1 2 3);
my $voice = Music::VoiceGen->new(
pitches => \@pitches,
intervals => \@intervals,
);
my @voices1 = map { $voice->rand } @$motif1;
# add 2 bars to the score
for my $n (1 .. $d->bars) {
$mdp->add_to_score($score, $motif1, \@voices1);
# get a fresh set of voices
my @voices2 = map { $voice->rand } @$motif2;
$mdp->add_to_score($score, $motif2, \@voices2);
}
$d->note($d->whole, $pitches[0]);
}
Quick-start
Go back to the Music::Duration::Partition::Tutorial::Quickstart tutorial.
AUTHOR
Gene Boggs <gene@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2019-2024 by Gene Boggs.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.