Category: Sound
Author/Contact Info

/msg [OeufMayo] /msg [Mr. Muskrat]

Description:

Are you tired of those dull breakbeats and drumloops you listen to all day long on the radio? Well, now is the time to make your own! With the new and improved BeatBox 2003(TM), you'll be the coolest one in your neighbourhood when you start throwin' down some kickin' beats. We have added more instruments and improved the functionality. This all-in-one script will bring you thousands of hours of fun. So don't waste any more time, grab this one!

#!/usr/bin/perl -w
use strict;
use MIDI::Simple;
use Getopt::Long;

=head1 NAME

BeatBox2003 - Create kickin' beats

=head1 SYNOPSIS

C<beatbox.pl [-t=80] [-b=24] [-p=tph] [-f=input.tab] --nosave>

=head1 DESCRIPTION

This program enables you to create rhythm tracks from tabulature in a 
+very
short amount of time.  You can configure the instruments used, the vol
+ume and tempo
for your rhythm track.  You can send the MIDI data to STDOUT or write 
+it to a file.

=head2 COMMAND LINE OPTIONS

=over 4

=item B<-tempo>

Set the tempo.  (Defaults to 60.)

=item B<-beats>

Set the numbers of beats in a tabulature.
(Comes in handy with jeffa's Triple Paradiddle with Hi-hat.)

=item B<-play>

The name of the playlist to use.  (LIST by default.)  This option, if 
+used,
also creates a MIDI file with the same name (as opposed to sending it 
+to STDOUT).

=item B<--nosave>

This flag prevents the creation of a MIDI file named for the playlist.
+  This
option is recommended for use with timidity.

=item B<-file>

The name of the tabulation file to read from (F<sample.tab> is the def
+ault).

=back

=head1 USAGE EXAMPLES

=head2 *NIX

C<beatbox.pl -p=hh --nosave | timidity ->
C<beatbox.pl -p=x | XMM x.mid>

=head2 WINDOWS NT/2k/XP

C<beatbox.pl -t=80 -b=24 -p=tph | "C:\Program Files\Winamp\winamp.exe"
+ tph.mid>

=head2 WINDOWS 9x

C<perl beatbox.pl -p=m | "C:\Program Files\Winamp\winamp.exe" m.mid>

=head1 INPUT.TAB

The format of the input.tab files is pretty straightforward.

=over 4

=item MEASURE

A measure contains one or more instruments beat tracks and must
be listed in a playlist in order to be played.  Each instrument's
beat track in a measure must have the same number of beats.  Measures
should generally contain 16 beats.

=item *NAME*

Put the name of the measure inside of asterisks on a line by itself.

=item INSTRUMENT

The instrument must be a declared subroutine in your code.
New instruments if added to the DATA section will have a new
subroutine will be created for them as runtime provided that
you properly follow the instrument declaration format.  If you
choose not to add your new instrument to the DATA section, then
you must add in the appropriate subroutine for your instrument.

Note:  There must be a colon between the instrument name and the beat
track for that instrument.

=item BEAT TRACK

The "beat track" for an instrument looks like -x--x.  This is
where you define the beats for an instrument.  An "x" signifies
that a beat will be played.  A beat track should generally be 16
beats in length.

=item PLAYLIST

The playlist name allows you to have multiple playlists that you
can choose to play.  The name of the playlist and the playlist
itself must be separated by an "=".  The playlist is simply a list
of predeclared measures in the order they are to be played.

=back

=head1 SEE ALSO

F<sample.tab>, L<MIDI::Simple>, L<Getopt::Long>

=head1 AUTHOR

OeufMayo
Mr. Muskrat

=cut


my $tempo = 60;
my $beats = 16;
my $play;
my $save;
my $file = 'sample.tab';
my $out = 1;
my $list = qr/LIST\s*=/i;

GetOptions ('save!', \$out,
            't|tempo=i', \$tempo,
            'b|beats=i', \$beats,
            'p|play=s' , \$play,
            'f|file=s' , \$file,
           );

if (defined $play) {
  $save = lc($play).'.mid';
  $list = qr/$play\s*=/i;
}

$out = 0 if ($out && !defined $save);

$beats--; # adjust so that 0 .. $beats works right

new_score;
set_tempo( 100000 / ($tempo / 120) );

my %beatbox = process( $list, $file );
play_beat( $beats, \%beatbox );
write_score( $out ? $save : \*STDOUT );

exit;

### Process the 'music sheet' ###
sub process {
    my $list = shift;
    my $file = shift;
    my ( %beatbox, $module_flag );
    open(TAB, '<', $file);
    while (<TAB>) {
        next if /^#/;
        if (/^$list\s*PLAY\(([^)]+)\)/) {
            push @{ $beatbox{'PLAYLIST'} }, split ( /,/, $1 );
        }
        if (/^\s*\*(\w+)\*$/) { $module_flag = $1 }

        if (/^\s*(\w+)\s*:\s*([x|-]+)$/) {
            my ( $instr, $event ) = ( $1, $2 );
            @{ $beatbox{$module_flag}{$instr} } = split ( //, $event )
+;
        }
    }
    return %beatbox;
}

### Make some noise ###
sub play_beat {
    my $beats = shift;
    my %beatbox = %{ +shift };
    my $patches = load_patches();
    foreach my $segment ( @{ $beatbox{'PLAYLIST'} } ) {
        foreach my $beat ( 0 .. $beats ) {
            synch(map {
               $beatbox{$segment}{$_}[$beat] eq 'x' && exists $patches
+->{$_} ?
               $patches->{$_} : $patches->{'_silent_'};
              } keys %{ $beatbox{$segment} }
            );
        }
    }
}

 
sub load_patches {
    my $channel = 'c9'; # channel 10
    my $dur = 'qn';
    my $volume = 'ff';
    my $patches = {
        '_silent_' => sub { my $it = shift; $it->r },
    };
    while (my $line = <DATA>) {
      next if ($line =~ /^$/);
      next if ($line =~ /^#/);
      chomp $line;
      my (undef, $key, $note, $vol) = split',',$line;
      $key =~ s/\s+//;
      $vol ||= $volume;
      $patches->{$key} = sub {my $it = shift; $it->n($channel,$vol,$no
+te,$dur)};
    }
    return $patches;
};


__DATA__
# Instrument definitions follow
# Instrument Name,XXX,00[,Volume]
Agogo High        ,AH ,67,
Agogo Low         ,AL ,68,
Bass Drum 1       ,BD1,36,
Bass Drum Acoustic,BDA,35,
Bongo Hi          ,BH ,60,
Bongo Low         ,BL ,61,
Cymbal Chinese    ,CC ,52,
Cymbal Crash 1    ,CC1,49,
Cymbal Crash 2    ,CC2,57,
Cymbal Ride 1     ,CR1,51,
Cymbal Ride 2     ,CR2,59,
Cymbal Splash     ,CS ,55,
Conga Low         ,CL ,64,
Conga Mute Hi     ,CMH,62,
Conga Open Hi     ,COH,63,
Cuica Mute        ,CM ,78,
Cuica Open        ,CO ,79,
Guiro Long        ,GL ,74,
Guiro Short       ,GS ,73,
Hi-Hat Closed     ,HC ,42,
Hi-Hat Open       ,HO ,46,
Hi-Hat Pedal      ,HP ,44,
Timbale High      ,TBH,65,
Timbale Low       ,TBL,66,
Tom Low Floor     ,TLF,41,
Tom High Floor    ,THF,43,
Tom Low           ,TL ,45,
Tom Low-Mid       ,TLM,47,
Tom Hi-Mid        ,THM,48,
Tom High          ,TH ,50,
Snare Acoustic    ,SA ,38,
Snare Electric    ,SE ,40,
Triangle Mute     ,TM ,80,
Triangle Open     ,TO ,81,
Whistle Short     ,WS ,71,
Whistle Long      ,WL ,72,
Wood Block Hi     ,WBH,76,
Wood Block Low    ,WBL,77,
Side Stick        ,XSS,37,
Hand Clap         ,XHC,39,
Ride Bell         ,XRB,53,mf
Tambourine        ,XT ,54,
Cowbell           ,XCB,56,mf
Vibraslap         ,XV ,58,
Claves            ,XCL,75,
Cabasa            ,XCA,69,
Maracas           ,XM ,70,
Replies are listed 'Best First'.
BeatBox 2003 sample.tab
by Mr. Muskrat (Canon) on Mar 17, 2003 at 15:25 UTC

    The sample.tab file:

    # # Pretty straightforward format # *whateveryouwant* : name of the measure # instrumentname : must be a delared sub in your code # '--x-x-' line : is the beats of a measure, put a # 'x' if you want to make it sound. # NAME = : Allows you to have multiple playlists # that you can choose on the command line # PLAY(A1,A2,...) : The playlist, will play all the pre # declared measures in the given order # # (note that you have to put a colon between the # instrument's name and the miserable excuse for a partition # # If you make some cool grooves send'em my way! # *R0* SE : ----x-------x--- BDA : x-x---x---x----- HO : x-x-x-x-x-x-x-x- *R1* SE : ----x--x----x--- BDA : x-------x-x----- HO : x-x-x-x-x-x-x-x- *R2* SE : ----x--x----xxxx BDA : x---x---x---x--- HO : x-xxx-x-x-x-xxx- # from http://www.mxtabs.net/ *F1* HP : xxxx-xx-x-xx-x-x SA : ----x--x-x--x-x- BDA : x-x-----x-xx---- *F1FILL* TH : --x------------- TMH : -----------x---- SA : --x---x----x---x THF : ------x--------x BDA : x--xx--x-x--xx-- *HH1* HP : x-x-x-x-x-x-x-x- SA : ----x-------x--- BDA : x--x-xx--xx----- *HH2* HP : x-x-x-x-x-x-x-x- SA : ----x-------x--- BDA : x--x--x--xx----- *HH3* HP : x-x-x-x-x-x-x-x- SA : ----x-------x--- BDA : x-x--x-x-------- *X1* CR1 : x--------------- HO : --x-x-x-x-x-x-x- SA : ----x--x----x--- BD1 : x-x------xx--x-x *X2* CR2 : x--------------- HP : --x-x-x-x-x-x-x- SA : ----x--x-x--x--- BDA : xx-x--x-x--x-x-x *X3* CC1 : x--------------- HO : --x-x-x-x-x-x-x- SA : ----x--xx--xx--x BD1 : x-xx-x-x--x--x-x *XF* CS : x-----------x--- HC : --x-x---x------- SA : ----x-xx-x--x-x- BDA : -x-x------x--x-- *TPH1* SA : x-xx-x--x-xx-x--x-xx-x-- TH : -x--x-xx-x--x-xx-x--x-xx BDA : x--x--x--x--x--x--x--x-- HP : x---x---x---x---x---x--- *TPH2* SA : x-xx-x--x-xx-x--x-xx-x-- TH : -x--x-xx-x--x-xx-x--x-xx *TPH3* SA : x-xx-x--x-xx-x--x-xx-x-- TH : -x--x-xx-x--x-xx-x--x-xx *TPH4* SA : x-xx-x--x-xx-x--x-xx-x-- TL : -x--x-xx-x--x-xx-x--x-xx BDA : x--x--x--x--x--x--x--x-- HO : x---x---x---x---x---x--- *TPH5* SA : x-xx-x--x-xx-x--x-xx-x-- CS : -x--x-xx-x--x-xx-x--x-xx BDA : x--x--x--x--x--x--x--x-- HC : x---x---x---x---x---x--- *M1* CR1 : ---x---x---x---x TL : x-x----------x-- TLM : -x------x-x-x-x- THM : ----x-x--x---x-- TH : -----x------x-x- *M2* SA : xx--xx--xx--xx-- THF : --x--x--x--x--x- TH : x--x--xx----x--x BDA : --x--x----x----x M = PLAY(M1,M2,M2,M2,M1,M2,M2,M2,M1,M2,M2,M2) R = PLAY(R0,R1,R0,R1,R2,R1,R0,R2,R1,R1,R1,R0,R2) F = PLAY(F1,F1,F1,F1FILL,F1,F1,F1,F1FILL) HH = PLAY(HH3,HH1,HH2,HH1,HH2,HH1,HH1,HH2,HH3) X = PLAY(X1,X2,X3,XF,X1,X2,X3,XF,X1,X2,X3) TPH = PLAY(TPH1,TPH2,TPH4,TPH3,TPH5,TPH2,TPH1,TPH3); LIST = PLAY(M1,M2,R0,R1,F1,F1FILL);

Re: BeatBox 2003
by LTjake (Prior) on Aug 29, 2003 at 21:22 UTC

    Not exactly timely, but i deiced to play around with this script.

    first i made a basic beat -- Aerosmith's "Walk This Way"

    *WTW* HO : x--------------- HC : --x-x-x-x-x-x-x- SA : ----x-------x--- BDA : x------xx-x----- AS = PLAY(WTW,WTW,WTW,WTW);

    Command line:

    bbox.pl -f as.tab -p=as -t=90

    Then i went for something more complex (mostly in length :) CCR's "Down on the Corner"

    *DOTC1* HC : x---x---x---x--- *DOTC2* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : ---xx-x-x--xx-x- *DOTC3* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- *DOTC4* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : -----------xx--- TL : --------------x- *DOTC5* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--x----x--- BDA : x-------x-x----- CC1 : x--------------- *DOTC6* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--x----x--- BDA : x-------x-x----- *DOTC7* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--xxx-xx--- TL : --------------x- BDA : x--------------- *DOTC8* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--x-xxxxx-- TL : --------------x- BDA : x--------------- *DOTC9* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--x-xxxxx-- TL : --------x-----x- BDA : x--------------- *DOTC10* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--x-xxx---- TL : ------------xxx- BDA : x--------------- *DOTC11* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--x-xxxx--- TL : --------------x- BDA : x--------------- *DOTC12* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--x-xxxxxx- BDA : x--------------- *DOTC13* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--x-x-xx-x- BDA : x--------------- *DOTC14* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--xx-xxxx-- TL : ---------x----x- BDA : x--------------- *DOTC15* HC : x---x---x---x--- XCB : x---x---x---x--- XCA : x--xx-x-x--xx-x- SA : ----x--xx--xx--- TL : ---------x----x- BDA : x--------------- CCR = PLAY(DOTC1,DOTC2,DOTC3,DOTC3,DOTC3,DOTC4,DOTC5,DOTC6,DOTC6,DOTC6 +,DOTC6,DOTC6,DOTC6,DOTC6,DOTC5,DOTC6,DOTC6,DOTC6,DOTC6,DOTC7,DOTC5,DO +TC8,DOTC5,DOTC6,DOTC6,DOTC6,DOTC6,DOTC6,DOTC6,DOTC6,DOTC5,DOTC9,DOTC5 +,DOTC10,DOTC5,DOTC6,DOTC6,DOTC6,DOTC5,DOTC6,DOTC6,DOTC6,DOTC6,DOTC11, +DOTC5,DOTC10,DOTC5,DOTC6,DOTC6,DOTC12,DOTC5,DOTC6,DOTC6,DOTC13,DOTC5, +DOTC6,DOTC6,DOTC6,DOTC5,DOTC7,DOTC5,DOTC14,DOTC5,DOTC7,DOTC5,DOTC15,D +OTC5,DOTC14,DOTC5,DOTC7,DOTC5,DOTC14,DOTC5);

    Command line:

    bbox.pl -f ccr.tab -p=ccr -t=85

    The actual song fades out, so the midi sort of stops in a bad place...ah well.

    Neat script.

    --
    "To err is human, but to really foul things up you need a computer." --Paul Ehrlich

Re: BeatBox 2003
by Coruscate (Sexton) on Mar 18, 2003 at 08:48 UTC

    I wish I could ++ this more than once, because this is really quite very cool! I created my own little beat... it's quite cheap as I'm not very musical, but at least I can say I wrote it hehe. Here's the scoop:

    [...]$ cat >>beatbox.pl ZAP ,ZAP,27,mf ^D [...]$ cat >coruscate.tab *M1* WL: ---xxxxx-------- XT: x-x-x-x-x-x-x--- WBH: -x-x-x-x-x-x---- XHC: --------x-x-xxx- ZAP: -----x-x-xx---x- SA: ---------------x *M2* SA: -x---x---x---x-- THM: x-xxx-xxx-xxx-xx XRB: xx--xx--xx--xx-- *M3* SA: -x---x---x---x-- XHC: ---xxx-------xxx CC1: -------x---x---- *M4* CL: x--x--x--x-x-xxx SE: -x---x---x---xx- XHC: ----x-----x----x THF: --x--x--x--x-xx- *M5* TBL: x-xx-x-xx-x-xx-- TH: xx-x-xx-x-xx-x-- XRB: -------x------x- XM: -xx--xx--xxx-x-- *M6* SA: x-xx-xx-xxx----- TL: x--xx--x--xxx--- XHC: -------------xxx WL: ---------xxxxx-- CORUSCATE = PLAY(M1,M2,M2,M3,M4,M2,M5,M4,M6); ^D [...]$ ./beatbox.pl -f coruscate.tab -p=CORUSCATE --nosave | timidity +-


    If the above content is missing any vital points or you feel that any of the information is misleading, incorrect or irrelevant, please feel free to downvote the post. At the same time, please reply to this node or /msg me to inform me as to what is wrong with the post, so that I may update the node to the best of my ability.

Re: BeatBox 2003
by zentara (Cardinal) on Mar 18, 2003 at 15:23 UTC
    Ditto on wishing more ++'s on this great script. I was wondering how to adapt it to use other instruments. I changed the following:
    sub load_patches { #my $channel = 'c9'; # channel 10 my $channel = 'c8';
    That made it play as a piano. As a matter of fact, I changed it to alot of different values, and they all came out piano, so I guess piano is default when timidity dosn't know what else to use. Can anyone point me to some docs, concerning how to change patches and instruments. I read the hash in MIDI.pm for the patches, but changing them always comes out piano.

      Channel 10 is for percussion instruments. The pitch values determine what instrument to play.

      So in addition to changing the channel you will need to tell it what instrument to use by issuing a patch_change( $channel, $patch ); command. Where $patch is the MIDI instrument you wish to use (i.e. 8 for Celesta). However, usage of BeatBox in this manner is not recommended since there are easier ways of doing what you want. :)