The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

MIDI::Simple::Drummer - An algorithmic MIDI drummer

VERSION

version 0.0601

SYNOPSIS

  # A glorified metronome:
  use MIDI::Simple::Drummer;
  my $d = MIDI::Simple::Drummer->new(-bpm => 100);
  $d->count_in;
  for(1 .. $d->phrases * $d->bars) {
    $d->note($d->EIGHTH, $d->backbeat_rhythm(-beat => $_));
    $d->note($d->EIGHTH, $d->tick);
  }

  # Shuffle:
  use MIDI::Simple::Drummer;
  my $d = MIDI::Simple::Drummer->new(-bpm => 100);
  $d->count_in;
  for(1 .. $d->phrases * $d->bars) {
    $d->note($d->TRIPLET_EIGHTH, $d->backbeat_rhythm(-beat => $_));
    $d->rest($d->TRIPLET_EIGHTH);
    $d->note($d->TRIPLET_EIGHTH, $d->tick);
  }

  # A rock drummer:
  use MIDI::Simple::Drummer::Rock;
  $d = MIDI::Simple::Drummer::Rock->new(-bpm => 100);
  my ($beat, $fill) = (0, 0);
  $d->count_in;
  for my $p (1 .. $d->phrases) {
    if ($p % 2 > 0) {
        $beat = $d->beat(-name => 3, -fill => $fill);
    }
    else {
        $beat = $d->beat(-name => 4);
        $fill = $d->fill(-last => $fill);
    }
  }
  $d->patterns(fin => \&fin);
  $d->beat(-name => 'fin');
  $d->write;
  sub fin {
    my $d = shift;
    $d->note($d->EIGHTH, $d->option_strike;
    $d->note($d->EIGHTH, $d->strike('Splash Cymbal','Bass Drum 1'));
    $d->note($d->TRIPLET_SIXTEENTH, $d->snare) for 0 .. 2;
    $d->rest($d->SIXTEENTH);
    $d->note($d->EIGHTH, $d->strike('Splash Cymbal','Bass Drum 1'));
  }

  # Multi-tracking:
  use MIDI::Simple::Drummer;
  my $d = MIDI::Simple::Drummer->new(-file => "$0.mid");
  $d->patterns(b1 => \&hihat);
  $d->patterns(b2 => \&backbeat);
  $d->sync_tracks(
    sub { $d->beat(-name => 'b1') },
    sub { $d->beat(-name => 'b2') },
  );
  $d->write();
  sub hihat { # tick
    my $self = shift;
    $self->note($self->EIGHTH, $self->tick) for 1 .. 2 * $self->beats;
  }
  sub backbeat { # kick/snare
    my $self = shift;
    $self->note($self->div_name, $self->rotate($_)) for 1 .. $self->beats;
  }

DESCRIPTION

This is a "robotic" drummer that provides algorithmic methods to make beats, rhythms, noise, what have you. It is also a glorified metronome.

This is not a traditional "drum machine" that is controlled in a mechanical or "arithmetic" sense. It is a "sufficiently intelligent" drummer, with which you can practice, improvise, compose, record and experiment.

The "beats" are entirely constructed with Perl, and as such, any algorithmic procedure can be used to generate the phrases - Bayesian stochastic, evolutionary game simulation, L-system, recursive descent grammar, Markov chain, Quantum::Whatever...

Note that you, the programmer (and de facto drummer), should know what the kit elements are named and what the patterns do. For these things, "Use The Source, Luke." Also, check out the included style sub-classes, the eg/* files (and the *.mid files they produce).

The default drum kit is the exciting, General MIDI Kit. Fortunately, you can import the .mid file into your DAW with auto-separated tracks of "virtual instruments." But using the -patch parameter, you can change drum kits (to brushes or TR-808 for instance) and also have various extended MIDI voices available.

NAME

MIDI::Simple::Drummer - An algorithmic MIDI drummer

METHODS

new()

  my $d = MIDI::Simple::Drummer->new(%arguments);

Return a new MIDI::Simple::Drummer instance with these default arguments:

  # MIDI parameters:
  -channel    = 9    # MIDI-perl drum channel
  -volume     = 100  # 120 max
  -pan        = 64   # 0L .. 64M .. 127R
  -pan_width  = 0    # 0 .. 64 from center
  -patch      = 0    # Drum kit patch number
  -power      = 0    # A rock kit
  -room       = 0    # "
  -brushes    = 0    # A jazz kit
  -reverb     = 20   # Effect 0-127
  -chorus     = 0    # "
  # Rhythm metrics:
  -accent     = 30   # Volume increment
  -bpm        = 120  # 1 qn = .5 seconds = 500,000 microseconds
  -phrases    = 4    # Number of groups of measures
  -bars       = 4    # Number of measures
  -beats      = 4    # Number of beats in a measure
  -divisions  = 4    # Note values that "get the beat"
  -signature  = ''   # beats / divisions
  # The Goods™
  -file      => Drummer.mid # Set this to $0.mid, for instance.
  -kit       => Standard kit set by the API
  -patterns  => {}  # To be filled at run-time
  -score     => MIDI::Simple->new_score

These arguments can all be overridden in the constuctor or accessors of the same name.

volume(), pan(), pan_width(), bpm()

  $x = $d->method;
  $d->method($x);

Return and set the volume, pan, pan_width and beats-per-minute methods.

MIDI pan (CC#10) goes from 1 left to 127 right. That puts the middle at 63.

phrases(), bars(), beats(), divisions()

phrases is the number of bars (or measures) you want to play.

bars is the number of groups of beats you want to play. Each bar is one group of beats.

beats is the number of beats in a bar! This is the numerator of the time signature.

Measures are divided into the number of "note values" that constitute one beat. divisions is this number. It is also known as the denominator of the time signature; the part of the measure that "gets the beat" or simply, "the pulse."

These are all variables that you can use as rhythm metrics to control the groove. They are just numbers, not objects or lists.

signature()

Get or set the string ratio of -beats over -divisions. By default this is not defined, allowing unbridled free-form expression.

div_name()

The name of the denominator of the time signature.

patch()

The drum kit.

1: Standard. 33: Jazz. 41: Brushes. Etc.

channel()

Get or set the MIDI channel.

chorus(), reverb()

Effects 0 (off) to 127 (full)

file()

Get or set the name for the .mid file to write.

sync_tracks()

Combine beats in parallel with an argument list of anonymous subroutines.

patterns()

Return or set known style patterns.

score()

  $x = $d->score;
  $x = $d->score($score);
  $x = $d->score($score, 'V127');
  $x = $d->score('V127');

Return or set the "score" in MIDI::Simple if provided as the first argument. If there are any other arguments, they are treated as MIDI score settings.

accent_note()

  $x = $d->accent_note($d->EIGHTH);

Accent a single note.

accent()

  $x = $d->accent();

Either return the current volume plus the accent increment or set the accent increment. This has an upper limit of MIDI fff.

duck()

This is the mirror opposite of the accent method.

strike()

  $x = $d->strike;
  $x = $d->strike('Cowbell');
  $x = $d->strike('Cowbell','Tambourine');
  @x = $d->strike('Cowbell','Tambourine');

Return note values for percussion names from the standard MIDI percussion set (with "notenum2percussion" in MIDI) in either scalar or list context. (Default predefined snare patch)

option_strike()

  $x = $d->option_strike;
  $x = $d->option_strike('Short Guiro','Short Whistle','Vibraslap');

Return a note value from a list of patches (default predefined crash cymbals). If another set of patches is given, one of those is chosen at random.

note()

  $d->note($d->SIXTEENTH, $d->snare);
  $d->note('sn', 'n38');

Add a note to the score. This is a pass-through to "n" in MIDI::Simple.

rest()

  $d->rest($d->SIXTEENTH);
  $d->rest('sn');

Add a rest to the score. This is a pass-through to "r" in MIDI::Simple.

metronome()

  $d->metronome;
  $d->metronome('Mute Triangle');

Add (beats * phrases) of the Pedal Hi-Hat, unless another patch is provided.

count_in()

  $d->count_in;
  $d->count_in(2);
  $d->count_in(1, 'Side Stick');

And a-one and a-two!</Lawrence Welk> ..11</FZ>

If No arguments are provided, the Closed Hi-Hat patch is used.

rotate()

  $x = $d->rotate;
  $x = $d->rotate(3);
  $x = $d->rotate(5, ['Mute Hi Conga','Open Hi Conga','Low Conga']);

Rotate through a list of patches according to the given beat number. (Default backbeat patches)

backbeat_rhythm()

  $x = $d->backbeat_rhythm;
  $x = $d->backbeat_rhythm(-beat => $y);
  $x = $d->backbeat_rhythm(-backbeat => ['Bass Drum 1','Electric Snare']);
  $x = $d->backbeat_rhythm(-patches => ['Cowbell','Hand Clap']);
  $x = $d->backbeat_rhythm(-tick => ['Claves']);
  $x = $d->backbeat_rhythm(-fill => $z);

Add a rotating backbeat to the score.

Arguments:

beat is the beat we are on. backbeat is the list of patches to use instead of the stock bass and snare. patches is a list of possible patches to use instead of the crash cymbals. tick is the patch to use instead of the closed hi-hat. fill is the fill pattern we last played.

beat()

  $x = $d->beat;
  $x = $d->beat(-name => $n);
  $x = $d->beat(-last => $y);
  $x = $d->beat(-fill => $z);
  $x = $d->beat(-type => 'fill');

Play a beat type and return the id for the selected pattern. Beats and fills are both just patterns but drummers think of them as distinct animals.

This method adds an anecdotal "beat" to the MIDI score. You can indicate that we filled in the previous bar, and do something exciting like crash on the first beat, by supplying the -fill => $z argument, where $z is the fill we just played. Similarly, the -last => $y argument indicates that $y is the last beat we played, so that we can maintain "context sensitivity."

Unless specifically given a pattern to play with the -name argument, we try to play something different each time, so if the pattern is the same as the -last, or if there is no given pattern to play, another is chosen.

For -type => 'fill', we append a named fill to the MIDI score.

fill()

This is an alias to beat(-type => 'fill').

patterns()

  $x = $d->patterns;
  $x = $d->patterns('rock_1');
  @x = $d->patterns(
    paraflamaramadiddle => \&paraflamaramadiddle,
    'foo fill' => \&foo_fill,
  );

Return or set the code references to the named patterns. If no argument is given, all the known patterns are returned.

write()

  $x = $d->write;
  $x = $d->write('Buddy-Rich.mid');

This is an alias for "write_score" in MIDI::Simple but with unimaginably intelligent bits. It returns the name of the written file if successful. If no filename is given, we use the preset -file attribute.

KIT ACCESS

kit()

  $x = $d->kit;
  $x = $d->kit('snare');
  @x = $d->kit( clapsnare => ['Handclap','Electric Snare'],
                kickstick => ['Bass Drum 1','Side Stick']);
  @x = $d->kit('clapsnare');

Return or set part or all of the percussion set.

name_of()

  $x = $d->name_of('kick'); # "Acoustic Bass Drum"
  @x = $d->name_of('crash'); # ('Chinese Cymbal', 'Crash Cymbal 1...)

Return the instrument names behind the kit nick-name lists.

hhat()

    $x = $d->hhat;
    $x = $d->hhat('Cabasa','Maracas','Claves');

Strike or set the "hhat" patches. By default, these are the Closed Hi-Hat, Open Hi-Hat and the Pedal Hi-Hat.

crash()

    $x = $d->crash;
    $x = $d->crash(@crashes);

Strike or set the "crash" patches. By default, these are the Chinese Cymbal, Crash Cymbal 1, Crash Cymbal 2 and the Splash Cymbal.

ride()

    $x = $d->ride;
    $x = $d->ride(@rides);

Strike or set the "ride" patches. By default, these are the Ride Bell, Ride Cymbal 1 and the Ride Cymbal 2.

tom()

    $x = $d->tom;
    $x = $d->tom('Low Conga','Mute Hi Conga','Open Hi Conga');

Strike or set the "tom" patches. By default, these are the High Tom, Hi-Mid Tom, etc.

kick()

    $x = $d->kick;
    $x = $d->kick('Bass Drum 1');

Strike or set the "kick" patch. By default, this is the Acoustic Bass Drum.

tick()

    $x = $d->tick;
    $x = $d->tick('Mute Triangle');

Strike or set the "tick" patch. By default, this is the Closed Hi-Hat.

snare()

    $x = $d->snare;
    $x = $d->snare('Electric Snare');

Strike or set the "snare" patches. By default, this is the Acoustic Snare.

backbeat()

    $x = $d->backbeat;
    $x = $d->backbeat('Bass Drum 1','Side Stick');

Strike or set the "backbeat" patches. By default, these are the predefined kick and snare patches. But if the time signature is a multiple of three, the backbeat is set to a "kick snare kick" pattern.

CONVENIENCE METHODS

These are meant to avoid literal strings and the need to remember and type the relevant MIDI variables.

WHOLE or _1st

  $x = $d->WHOLE;
  $x = $d->_1st;

Return 'wn'.

HALF or or _2nd

Return 'hn'.

QUARTER or _4th

Return 'qn'.

EIGHTH or _8th

Return 'en'.

SIXTEENTH or _16th

Return 'sn'.

THIRTYSECOND or _32nd

Return 'yn'.

SIXTYFOURTH or _64th

Return 'xn'.

_p2n()

Return %MIDI::percussion2notenum a la "GOODIES" in MIDI.

_n2p()

Return the inverse: %MIDI::notenum2percussion.

_default_patterns()

Patterns provided by default. This is {}, that is, nothing. This is defined in a MIDI::Simple::Drummer::* style package.

_default_kit()

Kit provided by default. This is a subset of the exciting general MIDI kit. This can also be defined in a MIDI::Simple::Drummer::* style package, to use better patches.

SEE ALSO

The eg/* and t/* files, that come with this distribution show how to use it.

The MIDI::Simple::Drummer::* styles, which you can make (and upload).

MIDI::Simple itself, of course.

https://en.wikipedia.org/wiki/General_MIDI#Percussion

http://maps.google.com/maps?q=mike+avery+joplin - my drum teacher.

This distribution at https://github.com/ology/Music/tree/master/MIDI-Simple-Drummer, where interim changes are made, long before any CPAN release.

TO DO

* Be smart about swing timing (e.g. $d->TRIPLET_XXXX).

* Handle double and half time (via DIVISION hashref).

* Use "relative rhythm metrics" if given a time signature.

* Use "quantize" in MIDI::Score?

* Keep a running clock/total to know where we are in time, at all times.

* Intelligently modulate dynamics to add nuance and "humanize."

* Make a MIDI::Simple::Drummer::AC\x{26A1}DC (Phil Rudd) style.

* Leverage "from_drum_tab" in MIDI::Tab or "read_score" in MIDI::Simple?

CREDITS

Paul Evans <leonerd@leonerd.org.uk<gt> for help understanding constant importing.

Kevin Goroway <kgoroway@yahoo.com<gt> for asking where the time signature was and if the rudiments package was going to happen.

AUTHOR

Gene Boggs <gene@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2014 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.