File Coverage

blib/lib/MIDI/XML/Track.pm
Criterion Covered Total %
statement 98 502 19.5
branch 0 206 0.0
condition 0 15 0.0
subroutine 33 72 45.8
pod 38 39 97.4
total 169 834 20.2


line stmt bran cond sub pod time code
1             package MIDI::XML::Track;
2              
3 1     1   520 use 5.006;
  1         2  
4 1     1   4 use strict;
  1         1  
  1         14  
5 1     1   3 use warnings;
  1         1  
  1         23  
6 1     1   390 use MIDI::Track;
  1         1040  
  1         22  
7 1     1   442 use MIDI::Event;
  1         2383  
  1         25  
8 1     1   333 use MIDI::XML::NoteOn;
  1         1  
  1         22  
9 1     1   4 use MIDI::XML::NoteOff;
  1         1  
  1         13  
10 1     1   307 use MIDI::XML::PolyKeyPressure;
  1         2  
  1         36  
11 1     1   304 use MIDI::XML::ControlChange;
  1         3  
  1         36  
12 1     1   314 use MIDI::XML::ProgramChange;
  1         2  
  1         29  
13 1     1   366 use MIDI::XML::ChannelKeyPressure;
  1         3  
  1         36  
14 1     1   369 use MIDI::XML::PitchBend;
  1         1  
  1         21  
15 1     1   320 use MIDI::XML::SequenceNumber;
  1         2  
  1         21  
16 1     1   292 use MIDI::XML::TextEvent;
  1         1  
  1         24  
17 1     1   372 use MIDI::XML::CopyrightNotice;
  1         2  
  1         21  
18 1     1   298 use MIDI::XML::TrackName;
  1         1  
  1         20  
19 1     1   292 use MIDI::XML::InstrumentName;
  1         1  
  1         21  
20 1     1   291 use MIDI::XML::Lyric;
  1         2  
  1         21  
21 1     1   287 use MIDI::XML::Marker;
  1         2  
  1         32  
22 1     1   334 use MIDI::XML::CuePoint;
  1         2  
  1         20  
23 1     1   344 use MIDI::XML::ProgramName;
  1         2  
  1         21  
24 1     1   288 use MIDI::XML::DeviceName;
  1         1  
  1         23  
25 1     1   298 use MIDI::XML::MidiChannelPrefix;
  1         2  
  1         34  
26 1     1   292 use MIDI::XML::Port;
  1         2  
  1         24  
27 1     1   320 use MIDI::XML::EndOfTrack;
  1         2  
  1         19  
28 1     1   289 use MIDI::XML::SetTempo;
  1         1  
  1         21  
29 1     1   293 use MIDI::XML::SmpteOffset;
  1         1  
  1         21  
30 1     1   352 use MIDI::XML::TimeSignature;
  1         2  
  1         21  
31 1     1   297 use MIDI::XML::KeySignature;
  1         2  
  1         25  
32 1     1   295 use MIDI::XML::SequencerSpecific;
  1         1  
  1         30  
33 1     1   293 use MIDI::XML::MetaEvent;
  1         2  
  1         20  
34 1     1   291 use MIDI::XML::SystemExclusive;
  1         2  
  1         36  
35 1     1   314 use MIDI::XML::EndOfExclusive;
  1         2  
  1         3345  
36              
37             our @ISA = qw();
38              
39             =head1 NAME
40              
41             MIDI::XML::Track - MIDI Tracks.
42              
43             =head1 SYNOPSIS
44              
45             use MIDI::XML::Track;
46             use MIDI::XML::TrackName;
47              
48             $Track = MIDI::XML::Track->new();
49             $Track->number(0);
50              
51             $Track_Name = MIDI::XML::TrackName->new();
52             $Track_Name->delta(0);
53             $Track_Name->text('Silent Night');
54             $Track->append($Track_Name);
55             $Track->append(MIDI::XML::TimeSignature->new(['time_signature',0,4,2,96,8]));
56              
57              
58             @xml = $Track->as_MidiXML();
59             print join("\n",@xml);
60              
61             =head1 DESCRIPTION
62              
63             MIDI::XML::Track is an object oriented class for representing tracks in
64             Standard MIDI Files.
65              
66             =head2 EXPORT
67              
68             None.
69              
70             =cut
71              
72             our $VERSION = '0.01';
73              
74             #==========================================================================
75              
76             my $event2class = {
77             'note_off'=>'MIDI::XML::NoteOff',
78             'note_on'=>'MIDI::XML::NoteOn',
79             'key_after_touch'=>'MIDI::XML::PolyKeyPressure',
80             'control_change'=>'MIDI::XML::ControlChange',
81             'patch_change'=>'MIDI::XML::ProgramChange',
82             'channel_after_touch'=>'MIDI::XML::ChannelKeyPressure',
83             'pitch_wheel_change'=>'MIDI::XML::PitchBend',
84             'sysex_f0'=>'MIDI::XML::SystemExclusive',
85             'sysex_f7'=>'MIDI::XML::EndOfExclusive',
86             'set_sequence_number'=>'MIDI::XML::SequenceNumber',
87             'text_event'=>'MIDI::XML::TextEvent',
88             'copyright_text_event'=>'MIDI::XML::CopyrightNotice',
89             'track_name'=>'MIDI::XML::TrackName',
90             'instrument_name'=>'MIDI::XML::InstrumentName',
91             'lyric'=>'MIDI::XML::Lyric',
92             'marker'=>'MIDI::XML::Marker',
93             'cue_point'=>'MIDI::XML::CuePoint',
94             'program_name'=>'MIDI::XML::ProgramName',
95             'text_event_08'=>'MIDI::XML::ProgramName',
96             'device_name'=>'MIDI::XML::DeviceName',
97             'text_event_09'=>'MIDI::XML::DeviceName',
98             # 'text_event_0a'=>'',
99             # 'text_event_0b'=>'',
100             # 'text_event_0c'=>'',
101             # 'text_event_0d'=>'',
102             # 'text_event_0e'=>'',
103             # 'text_event_0f'=>'',
104             'midi_channel_prefix'=>'MIDI::XML::MidiChannelPrefix',
105             'port'=>'MIDI::XML::Port',
106             'end_track'=>'MIDI::XML::EndOfTrack',
107             'set_tempo'=>'MIDI::XML::SetTempo',
108             'smpte_offset'=>'MIDI::XML::SmpteOffset',
109             'time_signature'=>'MIDI::XML::TimeSignature',
110             'key_signature'=>'MIDI::XML::KeySignature',
111             'sequencer_specific'=>'MIDI::XML::SequencerSpecific',
112             'raw_meta_event'=>'MIDI::XML::MetaEvent',
113             # 'song_position'=>'MIDI::XML::SongPositionPointer',
114             # 'song_select'=>'MIDI::XML::SongSelect',
115             # 'tune_request'=>'MIDI::XML::TuneRequest'
116             # 'raw_data'=>''
117             };
118              
119             #==========================================================================
120              
121             =head1 METHODS AND ATTRIBUTES
122              
123             =over 4
124              
125             =item $xml_track = MIDI::XML::Track->new();
126              
127             This creates a new MIDI::XML::Track object.
128              
129             =item $xml_track = MIDI::XML::NoteOn->new({'from_track' => $midi_track});
130              
131             Creates a new Track object initialized with the events in a
132             MIDI::Track object.
133              
134             =cut
135              
136             sub new {
137 0     0 1   my $class = shift;
138 0   0       $class = ref($class) || $class;
139              
140 0 0 0       my $options_r = (defined($_[0]) and ref($_[0]) eq 'HASH') ? $_[0] : {};
141              
142 0           my $self = {
143             '_Number'=> undef,
144             '_Events'=> [],
145             '_NoteOff'=> undef,
146             '_NoteOn'=> undef,
147             '_KeyAftertouch'=> undef,
148             '_ControlChange'=> undef,
149             '_ProgramChange'=> undef,
150             '_ChannelAftertouch'=> undef,
151             '_PitchBend'=> undef,
152             '_SystemExclusive'=> undef,
153             '_MidiTimeCodeQuarterFrame'=> undef,
154             '_SongPositionPointer'=> undef,
155             '_SongSelect'=> undef,
156             '_TuneRequest'=> undef,
157             '_EndOfExclusive'=> undef,
158             '_SequenceNumber'=> undef,
159             '_TextEvent'=> undef,
160             '_CopyrightNotice'=> undef,
161             '_TrackName'=> undef,
162             '_InstrumentName'=> undef,
163             '_Lyric'=> undef,
164             '_Marker'=> undef,
165             '_CuePoint'=> undef,
166             '_ProgramName'=> undef,
167             '_DeviceName'=> undef,
168             '_MidiChannelPrefix'=> undef,
169             '_Port'=> undef,
170             '_EndOfTrack'=> undef,
171             '_SetTempo'=> undef,
172             '_SmpteOffset'=> undef,
173             '_TimeSignature'=> undef,
174             '_KeySignature'=> undef,
175             '_SequencerSpecific'=> undef,
176             '_MetaEvent'=> undef,
177             '_End'=> undef,
178             };
179              
180 0           bless($self,$class);
181 0 0 0       if( exists( $options_r->{'from_track'} )
182             && defined( $options_r->{'from_track'} ) )
183             {
184 0           $self->append_from_track( $options_r->{'from_track'}, $options_r );
185             }
186              
187 0           return $self;
188             }
189              
190             #==========================================================================
191              
192             =item MIDI::XML::Track->register_subclass($event_name, $sub_class)
193              
194             Registers a subclass the for MIDI::XML::Track objects to use to represent the
195             named event. To work properly with the array methods the subclass name should
196             be the same as the orignal name. For example:
197              
198             $Track->register_subclass('sequencer_specific', 'MIDI::Huh::SequencerSpecific');
199              
200             will allow the sequencer_specifics method to identify the subclass but
201              
202             $Track->register_subclass('sequencer_specific', 'MIDI::Huh::SequinsAreSpecific');
203              
204             will not.
205              
206             =cut
207              
208             sub register_subclass {
209 0     0 1   my $self = shift;
210              
211 0 0         if ($#_ >0) {
212 0           my ($event_name, $sub_class) = @_;
213 0           $event2class->{$event_name} = $event_name;
214             }
215             }
216              
217             #==========================================================================
218             =item $number = $Track->number() or $Track->number($number)
219              
220             Returns or optionally sets the track number for the Track object.
221              
222             =cut
223              
224             sub number {
225 0     0 0   my $self = shift;
226 0 0         if (@_) {
227 0           $self->{'_Number'} = shift;
228             }
229 0           return $self->{'_Number'};
230             }
231              
232             #==========================================================================
233              
234             =item $events = $Track->events()
235              
236             Returns a reference to the array containing all the events associated with
237             the track.
238              
239             =cut
240              
241             sub events {
242 0     0 1   my $self = shift;
243 0           return $self->{'_Events'};
244             }
245              
246             #==========================================================================
247              
248             =item $Track->append($Event)
249              
250             Appends an event to the event array in this MIDI::Xml:Track object.
251              
252             =cut
253              
254             sub append {
255 0     0 1   my $self = shift;
256 0           my $Event = shift;
257              
258 0 0         push @{$self->{'_Events'}},$Event if (defined($Event));
  0            
259             }
260              
261             #==========================================================================
262              
263             =item $Track->append_from_track($track)
264              
265             Appends the events in a MIDI::Track object to the event array in this
266             MIDI::Xml:Track object.
267              
268             =cut
269              
270             sub append_from_track {
271 0     0 1   my $self = shift;
272 0           my $track = shift;
273 0           my @events = $track->events();
274 0           my $xml_event;
275 0           foreach my $ev (@events) {
276 0           $xml_event = undef;
277 0 0 0       if ($ev->[0] eq 'note_on') {
    0 0        
    0          
    0          
278 0 0         if ($ev->[4] == 0) { # note_on events with vel=0
279 0           $ev->[0] = 'note_off'; # function as note_off
280 0           $xml_event = $event2class->{'note_off'}->new($ev);
281 0           $ev->[0] = 'note_on';
282             } else {
283 0           $xml_event = $event2class->{'note_on'}->new($ev);
284             }
285             } elsif ($ev->[0] eq 'raw_meta_event' and $ev->[2] == 0x20) {
286 0           my $pev = ['midi_channel_prefix',$ev->[1],ord($ev->[3])];
287 0           $xml_event = $event2class->{'midi_channel_prefix'}->new($pev);
288             } elsif ($ev->[0] eq 'raw_meta_event' and $ev->[2] == 0x21) {
289 0           my $pev = ['port',$ev->[1],ord($ev->[3])];
290 0           $xml_event = $event2class->{'port'}->new($pev);
291             # } elsif ($ev->[0] eq 'raw_data') {
292             } elsif ($event2class->{ $ev->[0] }) {
293 0           $xml_event = $event2class->{ $ev->[0] }->new($ev);
294             }
295 0 0         push @{$self->{'_Events'}},$xml_event if (defined($xml_event));
  0            
296             }
297             }
298              
299             #==========================================================================
300              
301             =item $Track->make_times_absolute()
302              
303             Converts the event times from delta values to absolute values.
304              
305             =cut
306              
307             sub make_times_absolute {
308 0     0 1   my $self = shift;
309 0           my $abs = 0;
310 0           my $del = 0;
311              
312 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
313 0 0         if (defined($event->delta())) {
    0          
314 0           $abs += $event->delta();
315 0           $event->absolute($abs);
316             } elsif (defined($event->absolute())) {
317 0           $abs = $event->absolute();
318             }
319             }
320 0           $self->{'_End'} = $abs;
321             }
322              
323             #==========================================================================
324              
325             =item $Track->make_times_delta()
326              
327             Converts the event times from absolute values to delta values.
328              
329             =cut
330              
331             sub make_times_delta {
332 0     0 1   my $self = shift;
333 0           my $abs = 0;
334 0           my $del = 0;
335              
336 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
337 0 0         if (defined($event->absolute())) {
    0          
338 0           $del = $abs - $event->absolute();
339 0           $abs += $del;
340 0           $event->delta($abs);
341             } elsif (defined($event->delta())) {
342 0           $abs += $event->delta();
343             }
344             }
345 0           $self->{'_End'} = $abs;
346             }
347              
348             #==========================================================================
349              
350             =item $array_ref = $Track->note_ons() or $Track->note_ons('refresh');
351              
352             Returns a reference to an array of all NoteOn objects within the track. If called with
353             any parameter the array is refreshed before the reference is returned.
354              
355             =cut
356              
357             sub note_ons {
358 0     0 1   my $self = shift;
359 0 0         if (@_) {
360 0           $self->{'_NoteOn'} = undef;
361             }
362 0 0         if (!defined($self->{'_NoteOn'})) {
363 0           $self->{'_NoteOn'} = [];
364 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
365 0 0         if (ref($event) =~ /::NoteOn$/) {
366 0           push @{$self->{'_NoteOn'}},$event;
  0            
367             }
368             }
369             }
370 0           return $self->{'_NoteOn'};
371             }
372              
373             #==========================================================================
374              
375             =item $array_ref = $Track->note_offs() or $Track->note_offs('refresh');
376              
377             Returns a reference to an array of all NoteOff objects within the track. If called with
378             any parameter the array is refreshed before the reference is returned.
379              
380             =cut
381              
382             sub note_offs {
383 0     0 1   my $self = shift;
384 0 0         if (@_) {
385 0           $self->{'_NoteOff'} = undef;
386             }
387 0 0         if (!defined($self->{'_NoteOff'})) {
388 0           $self->{'_NoteOff'} = [];
389 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
390 0 0         if (ref($event) =~ /::NoteOff$/) {
391 0           push @{$self->{'_NoteOff'}},$event;
  0            
392             }
393             }
394             }
395 0           return $self->{'_NoteOff'};
396             }
397              
398             #==========================================================================
399              
400             =item $array_ref = $Track->control_changes() or $Track->control_changes('refresh');
401              
402             Returns a reference to an array of all ControlChange objects within the track. If called with
403             any parameter the array is refreshed before the reference is returned.
404              
405             =cut
406              
407             sub control_changes {
408 0     0 1   my $self = shift;
409 0 0         if (@_) {
410 0           $self->{'_ControlChange'} = undef;
411             }
412 0 0         if (!defined($self->{'_ControlChange'})) {
413 0           $self->{'_ControlChange'} = [];
414 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
415 0 0         if (ref($event) =~ /::ControlChange$/) {
416 0           push @{$self->{'_ControlChange'}},$event;
  0            
417             }
418             }
419             }
420 0           return $self->{'_ControlChange'};
421             }
422              
423             #==========================================================================
424              
425             =item $array_ref = $Track->program_changes() or $Track->program_changes('refresh');
426              
427             Returns a reference to an array of all ProgramChange objects within the track. If called with
428             any parameter the array is refreshed before the reference is returned.
429              
430             =cut
431              
432             sub program_changes {
433 0     0 1   my $self = shift;
434 0 0         if (@_) {
435 0           $self->{'_ProgramChange'} = undef;
436             }
437 0 0         if (!defined($self->{'_ProgramChange'})) {
438 0           $self->{'_ProgramChange'} = [];
439 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
440 0 0         if (ref($event) =~ /::ProgramChange$/) {
441 0           push @{$self->{'_ProgramChange'}},$event;
  0            
442             }
443             }
444             }
445 0           return $self->{'_ProgramChange'};
446             }
447              
448             #==========================================================================
449              
450             =item $array_ref = $Track->key_aftertouches() or $Track->key_aftertouches('refresh');
451              
452             Returns a reference to an array of all KeyAftertouch objects within the track. If called with
453             any parameter the array is refreshed before the reference is returned.
454              
455             =cut
456              
457             sub key_aftertouches {
458 0     0 1   my $self = shift;
459 0 0         if (@_) {
460 0           $self->{'_KeyAftertouch'} = undef;
461             }
462 0 0         if (!defined($self->{'_KeyAftertouch'})) {
463 0           $self->{'_KeyAftertouch'} = [];
464 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
465 0 0         if (ref($event) =~ /::KeyAftertouch$/) {
466 0           push @{$self->{'_KeyAftertouch'}},$event;
  0            
467             }
468             }
469             }
470 0           return $self->{'_KeyAftertouch'};
471             }
472              
473             #==========================================================================
474              
475             =item $array_ref = $Track->channel_aftertouches() or $Track->channel_aftertouches('refresh');
476              
477             Returns a reference to an array of all ChannelAftertouch objects within the track. If called with
478             any parameter the array is refreshed before the reference is returned.
479              
480             =cut
481              
482             sub channel_aftertouches {
483 0     0 1   my $self = shift;
484 0 0         if (@_) {
485 0           $self->{'_ChannelAftertouch'} = undef;
486             }
487 0 0         if (!defined($self->{'_ChannelAftertouch'})) {
488 0           $self->{'_ChannelAftertouch'} = [];
489 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
490 0 0         if (ref($event) =~ /::ChannelAftertouch$/) {
491 0           push @{$self->{'_ChannelAftertouch'}},$event;
  0            
492             }
493             }
494             }
495 0           return $self->{'_ChannelAftertouch'};
496             }
497              
498             #==========================================================================
499              
500             =item $array_ref = $Track->pitch_bend() or $Track->pitch_bend('refresh');
501              
502             Returns a reference to an array of all PitchBend objects within the track. If called with
503             any parameter the array is refreshed before the reference is returned.
504              
505             =cut
506              
507             sub pitch_bend {
508 0     0 1   my $self = shift;
509 0 0         if (@_) {
510 0           $self->{'_PitchBend'} = undef;
511             }
512 0 0         if (!defined($self->{'_PitchBend'})) {
513 0           $self->{'_PitchBend'} = [];
514 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
515 0 0         if (ref($event) =~ /::Xml::PitchBend$/) {
516 0           push @{$self->{'_PitchBend'}},$event;
  0            
517             }
518             }
519             }
520 0           return $self->{'_PitchBend'};
521             }
522              
523             #==========================================================================
524              
525             =item $array_ref = $Track->sequence_numbers() or $Track->sequence_numbers('refresh');
526              
527             Returns a reference to an array of all SequenceNumber objects within the track. If called with
528             any parameter the array is refreshed before the reference is returned.
529              
530             =cut
531              
532             sub sequence_numbers {
533 0     0 1   my $self = shift;
534 0 0         if (@_) {
535 0           $self->{'_SequenceNumber'} = undef;
536             }
537 0 0         if (!defined($self->{'_SequenceNumber'})) {
538 0           $self->{'_SequenceNumber'} = [];
539 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
540 0 0         if (ref($event) =~ /::SequenceNumber$/) {
541 0           push @{$self->{'_SequenceNumber'}},$event;
  0            
542             }
543             }
544             }
545 0           return $self->{'_SequenceNumber'};
546             }
547              
548             #==========================================================================
549              
550             =item $array_ref = $Track->text_events() or $Track->text_events('refresh');
551              
552             Returns a reference to an array of all TextEvent objects within the track. If called with
553             any parameter the array is refreshed before the reference is returned.
554              
555             =cut
556              
557             sub text_events {
558 0     0 1   my $self = shift;
559 0 0         if (@_) {
560 0           $self->{'_TextEvent'} = undef;
561             }
562 0 0         if (!defined($self->{'_TextEvent'})) {
563 0           $self->{'_TextEvent'} = [];
564 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
565 0 0         if (ref($event) =~ /::TextEvent$/) {
566 0           push @{$self->{'_TextEvent'}},$event;
  0            
567             }
568             }
569             }
570 0           return $self->{'_TextEvent'};
571             }
572              
573             #==========================================================================
574              
575             =item $array_ref = $Track->copyrights() or $Track->copyrights('refresh');
576              
577             Returns a reference to an array of all CopyrightNotice objects within the track. If called
578             with any parameter the array is refreshed before the reference is returned.
579              
580             =cut
581              
582             sub copyrights {
583 0     0 1   my $self = shift;
584 0 0         if (@_) {
585 0           $self->{'_CopyrightNotice'} = undef;
586             }
587 0 0         if (!defined($self->{'_CopyrightNotice'})) {
588 0           $self->{'_CopyrightNotice'} = [];
589 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
590 0 0         if (ref($event) =~ /::CopyrightNotice$/) {
591 0           push @{$self->{'_CopyrightNotice'}},$event;
  0            
592             }
593             }
594             }
595 0           return $self->{'_CopyrightNotice'};
596             }
597              
598             #==========================================================================
599              
600             =item $array_ref = $Track->track_names() or $Track->track_names('refresh');
601              
602             Returns a reference to an array of all TrackName objects within the track. If called with
603             any parameter the array is refreshed before the reference is returned.
604              
605             =cut
606              
607             sub track_names {
608 0     0 1   my $self = shift;
609 0 0         if (@_) {
610 0           $self->{'_TrackName'} = undef;
611             }
612 0 0         if (!defined($self->{'_TrackName'})) {
613 0           $self->{'_TrackName'} = [];
614 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
615 0 0         if (ref($event) =~ /::TrackName$/) {
616 0           push @{$self->{'_TrackName'}},$event;
  0            
617             }
618             }
619             }
620 0           return $self->{'_TrackName'};
621             }
622              
623             #==========================================================================
624              
625             =item $array_ref = $Track->instrument_names() or $Track->instrument_names('refresh');
626              
627             Returns a reference to an array of all InstrumentName objects within the track. If called with
628             any parameter the array is refreshed before the reference is returned.
629              
630             =cut
631              
632             sub instrument_names {
633 0     0 1   my $self = shift;
634 0 0         if (@_) {
635 0           $self->{'_InstrumentName'} = undef;
636             }
637 0 0         if (!defined($self->{'_InstrumentName'})) {
638 0           $self->{'_InstrumentName'} = [];
639 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
640 0 0         if (ref($event) =~ /::InstrumentName$/) {
641 0           push @{$self->{'_InstrumentName'}},$event;
  0            
642             }
643             }
644             }
645 0           return $self->{'_InstrumentName'};
646             }
647              
648             #==========================================================================
649              
650             =item $array_ref = $Track->lyrics() or $Track->lyrics('refresh');
651              
652             Returns a reference to an array of all Lyric objects within the track. If called with
653             any parameter the array is refreshed before the reference is returned.
654              
655             =cut
656              
657             sub lyrics {
658 0     0 1   my $self = shift;
659 0 0         if (@_) {
660 0           $self->{'_Lyric'} = undef;
661             }
662 0 0         if (!defined($self->{'_Lyric'})) {
663 0           $self->{'_Lyric'} = [];
664 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
665 0 0         if (ref($event) =~ /::Lyric$/) {
666 0           push @{$self->{'_Lyric'}},$event;
  0            
667             }
668             }
669             }
670 0           return $self->{'_Lyric'};
671             }
672              
673             #==========================================================================
674              
675             =item $array_ref = $Track->markers() or $Track->markers('refresh');
676              
677             Returns a reference to an array of all Marker objects within the track. If called with
678             any parameter the array is refreshed before the reference is returned.
679              
680             =cut
681              
682             sub markers {
683 0     0 1   my $self = shift;
684 0 0         if (@_) {
685 0           $self->{'_Marker'} = undef;
686             }
687 0 0         if (!defined($self->{'_Marker'})) {
688 0           $self->{'_Marker'} = [];
689 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
690 0 0         if (ref($event) =~ /::Marker$/) {
691 0           push @{$self->{'_Marker'}},$event;
  0            
692             }
693             }
694             }
695 0           return $self->{'_Marker'};
696             }
697              
698             #==========================================================================
699              
700             =item $array_ref = $Track->cue_points() or $Track->cue_points('refresh');
701              
702             Returns a reference to an array of all CuePoint objects within the track. If called with
703             any parameter the array is refreshed before the reference is returned.
704              
705             =cut
706              
707             sub cue_points {
708 0     0 1   my $self = shift;
709 0 0         if (@_) {
710 0           $self->{'_CuePoint'} = undef;
711             }
712 0 0         if (!defined($self->{'_CuePoint'})) {
713 0           $self->{'_CuePoint'} = [];
714 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
715 0 0         if (ref($event) =~ /::CuePoint$/) {
716 0           push @{$self->{'_CuePoint'}},$event;
  0            
717             }
718             }
719             }
720 0           return $self->{'_CuePoint'};
721             }
722              
723             #==========================================================================
724              
725             =item $array_ref = $Track->program_names() or $Track->program_names('refresh');
726              
727             Returns a reference to an array of all ProgramName objects within the track. If called with
728             any parameter the array is refreshed before the reference is returned.
729              
730             =cut
731              
732             sub program_names {
733 0     0 1   my $self = shift;
734 0 0         if (@_) {
735 0           $self->{'_ProgramName'} = undef;
736             }
737 0 0         if (!defined($self->{'_ProgramName'})) {
738 0           $self->{'_ProgramName'} = [];
739 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
740 0 0         if (ref($event) =~ /::ProgramName$/) {
741 0           push @{$self->{'_ProgramName'}},$event;
  0            
742             }
743             }
744             }
745 0           return $self->{'_ProgramName'};
746             }
747              
748             #==========================================================================
749              
750             =item $array_ref = $Track->device_names() or $Track->device_names('refresh');
751              
752             Returns a reference to an array of all DeviceName objects within the track. If called with
753             any parameter the array is refreshed before the reference is returned.
754              
755             =cut
756              
757             sub device_names {
758 0     0 1   my $self = shift;
759 0 0         if (@_) {
760 0           $self->{'_DeviceName'} = undef;
761             }
762 0 0         if (!defined($self->{'_DeviceName'})) {
763 0           $self->{'_DeviceName'} = [];
764 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
765 0 0         if (ref($event) =~ /::DeviceName$/) {
766 0           push @{$self->{'_DeviceName'}},$event;
  0            
767             }
768             }
769             }
770 0           return $self->{'_DeviceName'};
771             }
772              
773             #==========================================================================
774              
775             =item $array_ref = $Track->ports() or $Track->ports('refresh');
776              
777             Returns a reference to an array of all Port objects within the track. If called with
778             any parameter the array is refreshed before the reference is returned.
779              
780             =cut
781              
782             sub ports {
783 0     0 1   my $self = shift;
784 0 0         if (@_) {
785 0           $self->{'_Port'} = undef;
786             }
787 0 0         if (!defined($self->{'_Port'})) {
788 0           $self->{'_Port'} = [];
789 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
790 0 0         if (ref($event) =~ /::Port$/) {
791 0           push @{$self->{'_Port'}},$event;
  0            
792             }
793             }
794             }
795 0           return $self->{'_Port'};
796             }
797              
798             #==========================================================================
799              
800             =item $array_ref = $Track->channel_prefixes() or $Track->channel_prefixes('refresh');
801              
802             Returns a reference to an array of all MidiChannelPrefix objects within the track. If called with
803             any parameter the array is refreshed before the reference is returned.
804              
805             =cut
806              
807             sub channel_prefixes {
808 0     0 1   my $self = shift;
809 0 0         if (@_) {
810 0           $self->{'_MidiChannelPrefix'} = undef;
811             }
812 0 0         if (!defined($self->{'_MidiChannelPrefix'})) {
813 0           $self->{'_MidiChannelPrefix'} = [];
814 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
815 0 0         if (ref($event) =~ /::MidiChannelPrefix$/) {
816 0           push @{$self->{'_MidiChannelPrefix'}},$event;
  0            
817             }
818             }
819             }
820 0           return $self->{'_MidiChannelPrefix'};
821             }
822              
823             #==========================================================================
824              
825             =item $array_ref = $Track->ends_of_tracks() or $Track->ends_of_tracks('refresh');
826              
827             Returns a reference to an array of all EndOfTrack objects within the track. If called with
828             any parameter the array is refreshed before the reference is returned.
829              
830             =cut
831              
832             sub ends_of_tracks {
833 0     0 1   my $self = shift;
834 0 0         if (@_) {
835 0           $self->{'_EndOfTrack'} = undef;
836             }
837 0 0         if (!defined($self->{'_EndOfTrack'})) {
838 0           $self->{'_EndOfTrack'} = [];
839 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
840 0 0         if (ref($event) =~ /::EndOfTrack$/) {
841 0           push @{$self->{'_EndOfTrack'}},$event;
  0            
842             }
843             }
844             }
845 0           return $self->{'_EndOfTrack'};
846             }
847              
848             #==========================================================================
849              
850             =item $array_ref = $Track->set_tempi() or $Track->set_tempi('refresh');
851              
852             Returns a reference to an array of all SetTempo objects within the track. If called with
853             any parameter the array is refreshed before the reference is returned.
854              
855             =cut
856              
857             sub set_tempi {
858 0     0 1   my $self = shift;
859 0 0         if (@_) {
860 0           $self->{'_SetTempo'} = undef;
861             }
862 0 0         if (!defined($self->{'_SetTempo'})) {
863 0           $self->{'_SetTempo'} = [];
864 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
865 0 0         if (ref($event) =~ /::SetTempo$/) {
866 0           push @{$self->{'_SetTempo'}},$event;
  0            
867             }
868             }
869             }
870 0           return $self->{'_SetTempo'};
871             }
872              
873             #==========================================================================
874              
875             =item $array_ref = $Track->smpte_offsets() or $Track->smpte_offsets('refresh');
876              
877             Returns a reference to an array of all SmpteOffset objects within the track. If called with
878             any parameter the array is refreshed before the reference is returned.
879              
880             =cut
881              
882             sub smpte_offsets {
883 0     0 1   my $self = shift;
884 0 0         if (@_) {
885 0           $self->{'_SmpteOffset'} = undef;
886             }
887 0 0         if (!defined($self->{'_SmpteOffset'})) {
888 0           $self->{'_SmpteOffset'} = [];
889 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
890 0 0         if (ref($event) =~ /::SmpteOffset$/) {
891 0           push @{$self->{'_SmpteOffset'}},$event;
  0            
892             }
893             }
894             }
895 0           return $self->{'_SmpteOffset'};
896             }
897              
898             #==========================================================================
899              
900             =item $array_ref = $Track->time_signatures() or $Track->time_signatures('refresh');
901              
902             Returns a reference to an array of all TimeSignature objects within the track. If called with
903             any parameter the array is refreshed before the reference is returned.
904              
905             =cut
906              
907             sub time_signatures {
908 0     0 1   my $self = shift;
909 0 0         if (@_) {
910 0           $self->{'_TimeSignature'} = undef;
911             }
912 0 0         if (!defined($self->{'_TimeSignature'})) {
913 0           $self->{'_TimeSignature'} = [];
914 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
915 0 0         if (ref($event) =~ /::TimeSignature$/) {
916 0           push @{$self->{'_TimeSignature'}},$event;
  0            
917             }
918             }
919             }
920 0           return $self->{'_TimeSignature'};
921             }
922              
923             #==========================================================================
924              
925             =item $array_ref = $Track->key_signatures() or $Track->key_signatures('refresh');
926              
927             Returns a reference to an array of all KeySignature objects within the track. If called with
928             any parameter the array is refreshed before the reference is returned.
929              
930             =cut
931              
932             sub key_signatures {
933 0     0 1   my $self = shift;
934 0 0         if (@_) {
935 0           $self->{'_KeySignature'} = undef;
936             }
937 0 0         if (!defined($self->{'_KeySignature'})) {
938 0           $self->{'_KeySignature'} = [];
939 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
940 0 0         if (ref($event) =~ /::KeySignature$/) {
941 0           push @{$self->{'_KeySignature'}},$event;
  0            
942             }
943             }
944             }
945 0           return $self->{'_KeySignature'};
946             }
947              
948             #==========================================================================
949              
950             =item $array_ref = $Track->sequencer_specifics() or $Track->sequencer_specifics('refresh');
951              
952             Returns a reference to an array of all SequencerSpecific objects within the track. If called with
953             any parameter the array is refreshed before the reference is returned.
954              
955             =cut
956              
957             sub sequencer_specifics {
958 0     0 1   my $self = shift;
959 0 0         if (@_) {
960 0           $self->{'_SequencerSpecific'} = undef;
961             }
962 0 0         if (!defined($self->{'_SequencerSpecific'})) {
963 0           $self->{'_SequencerSpecific'} = [];
964 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
965 0 0         if (ref($event) =~ /::SequencerSpecific$/) {
966 0           push @{$self->{'_SequencerSpecific'}},$event;
  0            
967             }
968             }
969             }
970 0           return $self->{'_SequencerSpecific'};
971             }
972              
973             #==========================================================================
974              
975             =item $array_ref = $Track->meta_events() or $Track->meta_events('refresh');
976              
977             Returns a reference to an array of all Port objects within the track. If called with
978             any parameter the array is refreshed before the reference is returned.
979              
980             =cut
981              
982             sub meta_events {
983 0     0 1   my $self = shift;
984 0 0         if (@_) {
985 0           $self->{'_MetaEvent'} = undef;
986             }
987 0 0         if (!defined($self->{'_MetaEvent'})) {
988 0           $self->{'_MetaEvent'} = [];
989 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
990 0 0         if (ref($event) =~ /::MetaEvent$/) {
991 0           push @{$self->{'_MetaEvent'}},$event;
  0            
992             }
993             }
994             }
995 0           return $self->{'_MetaEvent'};
996             }
997              
998             #==========================================================================
999              
1000             =item $array_ref = $Track->system_exclusives() or $Track->system_exclusives('refresh');
1001              
1002             Returns a reference to an array of all SystemExclusive objects within the track. If called with
1003             any parameter the array is refreshed before the reference is returned.
1004              
1005             =cut
1006              
1007             sub system_exclusives {
1008 0     0 1   my $self = shift;
1009 0 0         if (@_) {
1010 0           $self->{'_SystemExclusive'} = undef;
1011             }
1012 0 0         if (!defined($self->{'_SystemExclusive'})) {
1013 0           $self->{'_SystemExclusive'} = [];
1014 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
1015 0 0         if (ref($event) =~ /::SystemExclusive$/) {
1016 0           push @{$self->{'_SystemExclusive'}},$event;
  0            
1017             }
1018             }
1019             }
1020 0           return $self->{'_SystemExclusive'};
1021             }
1022              
1023             #==========================================================================
1024              
1025             =item $array_ref = $Track->ends_of_exclusives() or $Track->ends_of_exclusives('refresh');
1026              
1027             Returns a reference to an array of all EndOfExclusive objects within the track. If called with
1028             any parameter the array is refreshed before the reference is returned.
1029              
1030             =cut
1031              
1032             sub ends_of_exclusives {
1033 0     0 1   my $self = shift;
1034 0 0         if (@_) {
1035 0           $self->{'_EndOfExclusive'} = undef;
1036             }
1037 0 0         if (!defined($self->{'_EndOfExclusive'})) {
1038 0           $self->{'_EndOfExclusive'} = [];
1039 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
1040 0 0         if (ref($event) =~ /::EndOfExclusive$/) {
1041 0           push @{$self->{'_EndOfExclusive'}},$event;
  0            
1042             }
1043             }
1044             }
1045 0           return $self->{'_EndOfExclusive'};
1046             }
1047              
1048             #==========================================================================
1049              
1050             =item $end = $Track->end() or $Track->end('refresh');
1051              
1052             Returns the absolute time for the end of the track. If called with
1053             any parameter the value is refreshed before it is returned.
1054              
1055             =cut
1056              
1057             sub end {
1058 0     0 1   my $self = shift;
1059 0           my $abs = 0;
1060 0           my $del = 0;
1061              
1062 0 0         if (@_) {
1063 0           $self->{'_End'} = undef;
1064             }
1065 0 0         if (defined($self->{'_End'})) {
1066 0           return $self->{'_End'};
1067             }
1068 0           foreach my $event (@{$self->{'_Events'}}) {
  0            
1069 0 0         if (defined($event->delta())) {
    0          
1070 0           $abs += $event->delta();
1071 0           $event->absolute($abs);
1072             } elsif (defined($event->absolute())) {
1073 0           $abs = $event->absolute();
1074             }
1075             }
1076 0           $self->{'_End'} = $abs;
1077 0           return $self->{'_End'};
1078             }
1079              
1080             #==========================================================================
1081              
1082             =item $Midi_track = $Track->as_midi_track();
1083              
1084             Returns a reference to an array of all objects within the track.
1085              
1086             =cut
1087              
1088             sub as_midi_track {
1089 0     0 1   my $self = shift;
1090              
1091 0           my $Midi_track = MIDI::Track->new();
1092 0           foreach my $evt (@{$self->{'_Events'}}) {
  0            
1093 0           my @midi_event = $evt->as_event();
1094 0           push @{$Midi_track->events_r}, \@midi_event;
  0            
1095             }
1096 0           return $Midi_track;
1097             }
1098              
1099             #==========================================================================
1100              
1101             =item @xml = $Track->as_MidiXML();
1102              
1103             Returns an array of elements formatted according to the MidiXML DTD. These
1104             elements may be assembled by track into entire documents with the following
1105             suggested DOCTYPE declaration:
1106              
1107            
1108             "-//Recordare//DTD MusicXML 0.7 MIDI//EN"
1109             "http://www.musicxml.org/dtds/midixml.dtd">
1110              
1111             =back
1112              
1113             =cut
1114              
1115             sub as_MidiXML {
1116 0     0 1   my $self = shift;
1117 0           my @xml;
1118 0           my @events = @{$self->{'_Events'}};
  0            
1119 0           my $start = '
1120             . " Number=\"$self->{'_Number'}\""
1121             . '>';
1122 0           push @xml, $start;
1123 0           foreach my $evt (@{$self->{'_Events'}}) {
  0            
1124 0           push @xml, $evt->as_MidiXML();
1125             }
1126 0           push @xml, '';
1127 0           @xml;
1128             }
1129              
1130             #==========================================================================
1131              
1132              
1133             return 1;
1134             __END__