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.0808

SYNOPSIS

  use MIDI::Simple::Drummer;

  # A glorified metronome:
  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:
  $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,
    -volume  => 100,
    -phrases => 8,
    -file    => 'rock-drums.mid',
  );
  my ($beat, $fill) = (0, 0);
  my @rotate = qw( 2.1 2.2 2.4 );
  $d->count_in;
  for my $p (1 .. $d->phrases) {
    if($p % 2 > 0) {
        $beat = $d->beat(-name => 2.3, -fill => $fill);
        $beat = $d->beat(-name => 2.3);
    }
    else {
        $beat = $d->beat(-name => (@rotate)[int(rand @rotate)]);
        $fill = $d->fill(-last => $fill);
    }
  }
  $d->patterns('end fill' => \&fin);
  $d->fill(-name => 'end');
  $d->write;
  sub fin {
    my $d = shift;
    $d->accent;
    # Crash and kick, simultaneously.
    $d->note('qn', $d->strike('Crash Cymbal 1', $d->name_of('kick')));
  }

  # Multi-tracking:
  $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->QUARTER, $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 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...

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 and reassign better patches.

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
  -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 with accessors.

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.

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'); # Same

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

rest

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

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

The MIDI::Simple::Drummer::* styles

MIDI::Simple itself

Music::Duration

MIDI::Drummer::Tiny - A Moo-based simplified drum module

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

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.

Jeremy Mates for the clever Euclidian rhythm algorithm.

AUTHOR

Gene Boggs <gene@cpan.org>

COPYRIGHT AND LICENSE

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