view release on metacpan or search on metacpan
lib/MIDI/Simple.pm view on Meta::CPAN
-- or no notes at all, if Notes is empty list.
Then it moves Time ahead as appropriate. See the section "Parameters
For n/r/noop", below.
=cut
sub n { # a note
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
&MIDI::Simple::_parse_options($it, @_);
foreach my $note_val (@{$it->{"Notes"}}) {
# which should presumably not be a null list
unless($note_val =~ /^\d+$/) {
carp "note value \"$note_val\" from Notes is non-numeric! Skipping.";
next;
}
push @{$it->{"Score"}},
['note',
int(${$it->{"Time"}}),
lib/MIDI/Simple.pm view on Meta::CPAN
This is exactly like C<n>, except it never pushes anything to Score,
but moves ahead Time. (In other words, there is no such thing as a
rest-event; it's just a item during which there are no note-events
playing.)
=cut
sub r { # a rest
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
&MIDI::Simple::_parse_options($it, @_);
${$it->{"Time"}} += ${$it->{"Duration"}};
return;
}
###########################################################################
=item noop(...parameters...) or $obj->noop(...parameters...)
This is exactly like C<n> and C<r>, except it never alters Score,
I<and> never changes Time. It is meant to be used for setting the
other state variables, i.e.: Channel, Duration, Octave, Volume, Notes.
=cut
sub noop { # no operation
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
&MIDI::Simple::_parse_options($it, @_);
return;
}
#--------------------------------------------------------------------------
=back
=cut
lib/MIDI/Simple.pm view on Meta::CPAN
my $it;
if(
defined($p1) &&
($p1 eq 'MIDI::Simple' or ref($p1) eq 'MIDI::Simple')
) { # I'm a method!
print "~ new_score as a MIDI::Simple constructor\n" if $Debug;
$it = bless {};
&_init_score($it);
} else { # I'm a proc!
my $cpackage = (caller)[0];
print "~ new_score as a proc for package $cpackage\n" if $Debug;
if( ref($package{ $cpackage }) ) { # Already exists in %package
print "~ reinitting pobj $cpackage\n" if $Debug;
&_init_score( $it = $package{ $cpackage } );
# no need to call _package_object
} else { # Doesn't exist in %package
print "~ new pobj $cpackage\n" if $Debug;
$package{ $cpackage } = $it = &_package_object( $cpackage );
# no need to call _init_score
}
lib/MIDI/Simple.pm view on Meta::CPAN
directly access the variables instead.
=cut
#--------------------------------------------------------------------------
# read-or-write methods
sub Score (;\@) { # yes, a prototype!
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
if(@_) {
if($am_method){
@{$it->{'Score'}} = @_;
} else {
@{$it->{'Score'}} = @{$_[0]}; # sneaky, huh!
}
return; # special case -- return nothing if this is a PUT
} else {
return @{$it->{'Score'}}; # you asked for it
}
}
sub Cookies {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
%{$it->{'Cookies'}} = @_ if @_; # Better have an even number of elements!
return %{$it->{'Cookies'}};
}
sub Time {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
${$it->{'Time'}} = $_[0] if @_;
return ${$it->{'Time'}};
}
sub Duration {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
${$it->{'Duration'}} = $_[0] if @_;
return ${$it->{'Duration'}};
}
sub Channel {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
${$it->{'Channel'}} = $_[0] if @_;
return ${$it->{'Channel'}};
}
sub Octave {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
${$it->{'Octave'}} = $_[0] if @_;
return ${$it->{'Octave'}};
}
sub Tempo {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
${$it->{'Tempo'}} = $_[0] if @_;
return ${$it->{'Tempo'}};
}
sub Notes {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
@{$it->{'Notes'}} = @_ if @_;
return @{$it->{'Notes'}};
}
sub Volume {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
${$it->{'Volume'}} = $_[0] if @_;
return ${$it->{'Volume'}};
}
#-#-#-#-#-#-#-#-##-#-#-#-#-#-#-#-#-#-#-#-##-#-#-#-#-#-#-#-##-#-#-#-#-#-#-#-
# read-only methods that return references
sub Score_r {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
return $it->{'Score'};
}
sub Time_r {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
return $it->{'Time'};
}
sub Duration_r {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
return $it->{'Duration'};
}
sub Channel_r {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
return $it->{'Channel'};
}
sub Octave_r {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
return $it->{'Octave'};
}
sub Tempo_r {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
return $it->{'Tempo'};
}
sub Notes_r {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
return $it->{'Notes'};
}
sub Volume_r {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
return $it->{'Volume'};
}
sub Cookies_r {
my($it) = (ref($_[0]) eq "MIDI::Simple") ? (shift @_)
: ($package{ (caller)[0] } ||= &_package_object( (caller)[0] ));
return $it->{'Cookies'};
}
###########################################################################
###########################################################################
=head2 MIDI EVENT ROUTINES
These routines, below, add a MIDI event to the Score, with a
start-time of Time. Example:
lib/MIDI/Simple.pm view on Meta::CPAN
=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
lib/MIDI/Simple.pm view on Meta::CPAN
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
filespec: C<write_score *STDOUT{IO}>.)
=cut
sub write_score {
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
my($out, $ticks, $score_r) =
( $_[0], (${$it->{'Tempo'}} || 96), $it->{'Score'} );
croak "First parameter to MIDI::Simple::write_score can't be null\n"
unless( ref($out) || length($out) );
croak "Ticks can't be 0" unless $ticks;
carp "Writing a score with no notes!" unless @$score_r;
my $opus = $it->make_opus;
# $opus->dump( { 'dump_tracks' => 1 } );
lib/MIDI/Simple.pm view on Meta::CPAN
# If ever you want just a single track as a score, here's how:
#my $score_r = ( MIDI::Score::events_r_to_score_r($track->events_r) )[0];
my( $score_r, $time) = MIDI::Score::events_r_to_score_r($track->events_r);
#print scalar(@$score_r), " notes in score\n";
my $it;
if($am_cons) { # just make a new object and return it.
$it = MIDI::Simple->new_score;
$it->{'Score'} = $score_r;
} else { # need to fudge it back into the pobj
my $cpackage = (caller)[0];
#print "~ read_score as a proc for package $cpackage\n";
if( ref($package{ $cpackage }) ) { # Already exists in %package
print "~ reinitting pobj $cpackage\n" if $Debug;
&_init_score( $it = $package{ $cpackage } );
# no need to call _package_object
} else { # Doesn't exist in %package
print "~ new pobj $cpackage\n" if $Debug;
$package{ $cpackage } = $it = &_package_object( $cpackage );
# no need to call _init_score
}
lib/MIDI/Simple.pm view on Meta::CPAN
my $phrase_number = ($measure + -1) % 4;
my @phrase = @{$phrases[$phrase_number]};
foreach my $note (@phrase) { $it->n($note); }
}
=cut
sub synch {
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
my @subs = grep(ref($_) eq 'CODE', @_);
print " My subs: ", map("<$_> ", @subs), ".\n"
if $Debug;
return unless @subs;
# my @end_times = (); # I am the Lone Array of the Apocalypse!
my $orig_time = ${$it->{'Time'}};
my $max_time = $orig_time;
foreach my $sub (@subs) {
lib/MIDI/Simple.pm view on Meta::CPAN
tick parameter (AKA "divisions") to $ticks. The opus is,
incidentally, format 0, with one track.
=cut
sub make_opus {
# Make a format-0 one-track MIDI out of this score.
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
my($ticks, $score_r) = (${$it->{'Tempo'}}, $it->{'Score'});
carp "Encoding a score with no notes!" unless @$score_r;
my $events_r = ( MIDI::Score::score_r_to_events_r($score_r) )[0];
carp "Creating a track with no events!" unless @$events_r;
my $opus =
MIDI::Opus->new({ 'ticks' => $ticks,
'format' => 0,
'tracks' => [ MIDI::Track->new({
lib/MIDI/Simple.pm view on Meta::CPAN
as it is (currently) just a call to C<&MIDI::Score::dump_score>; but in
the future I may (should?) make it output in C<n>/C<r> notation. In
the meantime I assume you'll use this, if at all, only for debugging
purposes.
=cut
sub dump_score {
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
return &MIDI::Score::dump_score( $it->{'Score'} );
}
###########################################################################
###########################################################################
=back
=head2 FUNCTIONS
lib/MIDI/Simple.pm view on Meta::CPAN
Items in LIST which aren't note specifications are passed thru
unaltered.
=cut
sub interval { # apply an interval to a list of notes.
my(@out);
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
my($interval_r, @notes) = @_;
croak "first argument to &MIDI::Simple::interval must be a listref\n"
unless ref($interval_r);
# or a valid key into a hash %Interval?
foreach my $note (@notes) {
my(@them, @status, $a_flag, $note_number);
@status = &is_note_spec($note);
unless(@status) { # not a note spec
lib/MIDI/Simple.pm view on Meta::CPAN
$package_opus = Self;
funkify($package_opus);
=cut
sub Self { # pointless as a method -- but as a sub, useful if
# you want to access your current package's object.
# Juuuuuust in case you need it.
my($am_method, $it) = (ref($_[0]) eq "MIDI::Simple")
? (1, shift @_)
: (0, ($package{ (caller)[0] } ||= &_package_object( (caller)[0] )) );
return $it;
}
=back
=cut
###########################################################################
=head1 COPYRIGHT