MIDI-Perl
view release on metacpan or search on metacpan
lib/MIDI/Simple.pm view on Meta::CPAN
sub raw_data ($) { &_common_push('raw_data', @_) }
sub _common_push {
# I'm your doctor when you need / Have some coke
# / Want some weed / I'm Your Pusher Man
#print "*", map("<$_>", @_), "\n";
my(@p) = @_;
my $event = shift @p;
my $it;
if(ref($p[0]) eq "MIDI::Simple") {
$it = shift @p;
} else {
$it = ($package{ (caller(1))[0] } ||= &_package_object( (caller(1))[0] ) );
}
#print "**", map("<$_>", @p), " from ", ()[0], "\n";
#printf "Pushee to %s 's %s: e<%s>, t<%s>, p<%s>\n",
# $it, $it->{'Score'}, $event, ${$it->{'Time'}}, join("~", @p);
push @{$it->{'Score'}},
[ $event, ${$it->{'Time'}}, @p ];
return;
}
=head2 About Tempo
The chart above shows that tempo is set with a method/procedure that
takes the form set_tempo(I<tempo>), and L<MIDI::Event> says that
I<tempo> is "microseconds, a value 0 to 16,777,215 (0x00FFFFFF)".
But at the same time, you see that there's an attribute of the
MIDI::Simple object called "Tempo", which I've warned you to leave at
the default value of 96. So you may wonder what the deal is.
The "Tempo" attribute (AKA "Divisions") is an integer that specifies
the number of "ticks" per MIDI quarter note. Ticks is just the
notional timing unit all MIDI events are expressed in terms of.
Calling it "Tempo" is misleading, really; what you want to change to
make your music go faster or slower isn't that parameter, but instead
the mapping of ticks to actual time -- and that is what C<set_tempo>
does. Its one parameter is the number of microseconds each quarter
note should get.
Suppose you wanted a tempo of 120 quarter notes per minute. In terms
of microseconds per quarter note:
set_tempo 500_000; # you can use _ like a thousands-separator comma
In other words, this says to make each quarter note take up 500,000
microseconds, namely .5 seconds. And there's 120 of those
half-seconds to the minute; so, 120 quarter notes to the minute.
If you see a "[quarter note symbol] = 160" in a piece of sheet music,
and you want to figure out what number you need for the C<set_tempo>,
do:
60_000_000 / 160 ... and you get: 375_000
Therefore, you should call:
set_tempo 375_000;
So in other words, this general formula:
set_tempo int(60_000_000 / $quarter_notes_per_minute);
should do you fine.
As to the Tempo/Duration parameter, leave it alone and just assume
that 96 ticks-per-quarter-note is a universal constant, and you'll be
happy.
(You may wonder: Why 96? As far as I've worked out, all permutations
of the normal note lengths (whole, half, quarter, eighth, sixteenth,
and even thirty-second notes) and tripletting, dotting, or
double-dotting, times 96, all produce integers. For example, if a
quarter note is 96 ticks, then a double-dotted thirty-second note is
21 ticks (i.e., 1.75 * 1/8 * 96). But that'd be a messy 10.5 if there
were only 48 ticks to a quarter note. Now, if you wanted a quintuplet
anywhere, you'd be out of luck, since 96 isn't a factor of five. It's
actually 3 * (2 ** 5), i.e., three times two to the fifth. If you
really need quintuplets, then you have my very special permission to
mess with the Tempo attribute -- I suggest multiples of 96, e.g., 5 *
96.)
(You may also have read in L<MIDI::Filespec> that C<time_signature>
allows you to define an arbitrary mapping of your concept of quarter
note, to MIDI's concept of quarter note. For your sanity and mine,
leave them the same, at a 1:1 mapping -- i.e., with an '8' for
C<time_signature>'s last parameter, for "eight notated 32nd-notes per
MIDI quarter note". And this is relevant only if you're calling
C<time_signature> anyway, which is not necessarily a given.)
=cut
###########################################################################
###########################################################################
=head2 MORE ROUTINES
=over
=cut
sub _test_proc {
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
print " am method: $am_method\n it: $it\n params: <", join(',',@_), ">\n";
}
###########################################################################
=item $opus = write_score I<filespec>
=item $opus = $obj->write_score(I<filespec>)
Writes the score to the filespec (e.g, "../../samples/funk2.midi", or
a variable containing that value), with the score's Ticks as its tick
parameters (AKA "divisions"). Among other things, this function calls
the function C<make_opus>, below, and if you capture the output of
write_score, you'll get the opus created, if you want it for anything.
(Also: you can also use a filehandle-reference instead of the
( run in 0.970 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )