forked from ology/Music
-
Notifications
You must be signed in to change notification settings - Fork 0
/
drum-circle
91 lines (70 loc) · 2.31 KB
/
drum-circle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env perl
# Ex:
# $ perl drum-circle 11; timidity -c ~/timidity.cfg drum-circle.mid
use strict;
use warnings;
# Use my local libraries
use lib map { "$ENV{HOME}/sandbox/$_/lib" } qw(MIDI-Drummer-Tiny Music-Duration Music-Duration-Partition);
use MIDI::Drummer::Tiny;
use Music::Duration::Partition;
use Data::Dumper::Compact qw(ddc);
# The number of drummers
my $max = shift || 4;
# The number of bars to play after all drummers have entered
my $extend = shift || 4;
my $width = length $max;
# Setup a drum score
my $d = MIDI::Drummer::Tiny->new(
file => "$0.mid",
bpm => 90,
bars => $max * 4,
reverb => 15,
);
# List the available percussion instruments
my @DRUMS = (
# $d->hi_tom, $d->hi_mid_tom, $d->low_mid_tom, $d->low_tom, $d->hi_floor_tom, $d->low_floor_tom,
$d->hi_bongo, $d->low_bongo, $d->mute_hi_conga, $d->open_hi_conga, $d->low_conga,
$d->cabasa, $d->maracas, $d->short_guiro, $d->claves, $d->hi_wood_block, $d->low_wood_block,
);
die "Can't have more drummers than drums!"
if $max > @DRUMS;
my %seen; # Bucket of drums that have been selected
my @phrases; # List of code-ref MIDI phrases
# Make a phrase generator
my $mdp = Music::Duration::Partition->new(
size => 4,
pool => [qw(qn den en sn)],
);
# Build the phrases played by each drummer
push @phrases, phrase($_)
for 1 .. $max;
$d->score->synch(@phrases); # Play the phrases simultaneously
$d->write; # Write the score to a MIDI file
sub phrase {
my ($p) = @_; # Phrase number
# Get an unseen drum to use
my $drum = $DRUMS[int rand @DRUMS];
while ($seen{$drum}++) {
$drum = $DRUMS[int rand @DRUMS];
}
# Create a rhythmic phrase
my $motif = $mdp->motif;
printf "%*d. Drum: %s, Motif: %s", $width, $p, $drum, ddc($motif);
# Either rest or play the motif
my $phrase = sub {
for my $n (1 .. $d->bars + $extend) {
# If we are not up yet, then rest
if ($n < ($p * 4)) {
$d->rest($d->whole);
next;
}
# Otherwise play the rhythmic phrase!
for my $dura (@$motif) {
# Get a fluctuating velocity between f and fff
my $vol = 'v' . (96 + int(rand 32));
$d->note($dura, $drum, $vol);
}
}
};
return $phrase;
}