File Coverage

blib/lib/MIDI/Util.pm
Criterion Covered Total %
statement 105 106 99.0
branch 34 38 89.4
condition 2 4 50.0
subroutine 14 14 100.0
pod 7 7 100.0
total 162 169 95.8


line stmt bran cond sub pod time code
1             package MIDI::Util;
2             our $AUTHORITY = 'cpan:GENE';
3              
4             # ABSTRACT: MIDI Utilities
5              
6             our $VERSION = '0.1002';
7              
8 1     1   639 use strict;
  1         1  
  1         25  
9 1     1   4 use warnings;
  1         2  
  1         20  
10              
11 1     1   364 use MIDI ();
  1         10466  
  1         23  
12 1     1   529 use MIDI::Simple ();
  1         6636  
  1         26  
13 1     1   362 use Music::Tempo qw(bpm_to_ms);
  1         406  
  1         50  
14 1     1   6 use Exporter 'import';
  1         1  
  1         40  
15              
16             our @EXPORT = qw(
17             midi_dump
18             midi_format
19             set_chan_patch
20             set_time_signature
21             setup_score
22             dura_size
23             ticks
24             );
25              
26 1     1   4 use constant TICKS => 96;
  1         3  
  1         1088  
27              
28              
29             sub setup_score {
30 1     1 1 571 my %args = (
31             lead_in => 4,
32             volume => 120,
33             bpm => 100,
34             channel => 0,
35             patch => 0,
36             octave => 4,
37             signature => '4/4',
38             @_,
39             );
40              
41 1         6 my $score = MIDI::Simple->new_score();
42              
43 1         84 set_time_signature($score, $args{signature});
44              
45 1         19 $score->set_tempo( bpm_to_ms($args{bpm}) * 1000 );
46              
47 1         22 $score->Channel(9);
48 1         17 $score->n( 'qn', 42 ) for 1 .. $args{lead_in};
49              
50 1         533 $score->Volume($args{volume});
51 1         8 $score->Channel($args{channel});
52 1         9 $score->Octave($args{octave});
53 1         31 $score->patch_change( $args{channel}, $args{patch} );
54              
55 1         20 return $score;
56             }
57              
58              
59             sub set_chan_patch {
60 1     1 1 3288 my ( $score, $channel, $patch ) = @_;
61              
62 1   50     3 $channel //= 0;
63              
64 1 50       5 $score->patch_change( $channel, $patch )
65             if defined $patch;
66              
67 1         17 $score->noop( 'c' . $channel );
68             }
69              
70              
71             sub midi_dump {
72 15     15 1 6874 my ($key) = @_;
73              
74 15 100       102 if ( lc $key eq 'volume' ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
75             return [
76 10         20 map { "$_ => $MIDI::Simple::Volume{$_}" }
77 1         5 sort { $MIDI::Simple::Volume{$a} <=> $MIDI::Simple::Volume{$b} }
  24         29  
78             keys %MIDI::Simple::Volume
79             ];
80             }
81             elsif ( lc $key eq 'length' ) {
82             return [
83 20         55 map { "$_ => $MIDI::Simple::Length{$_}" }
84 1         6 sort { $MIDI::Simple::Length{$a} <=> $MIDI::Simple::Length{$b} }
  66         72  
85             keys %MIDI::Simple::Length
86             ];
87             }
88             elsif ( lc $key eq 'ticks' ) {
89             return [
90 20         50 map { "$_ => " . $MIDI::Simple::Length{$_} * TICKS }
91 1         6 sort { $MIDI::Simple::Length{$a} <=> $MIDI::Simple::Length{$b} }
  66         68  
92             keys %MIDI::Simple::Length
93             ];
94             }
95             elsif ( lc $key eq 'note' ) {
96             return [
97 27         45 map { "$_ => $MIDI::Simple::Note{$_}" }
98 1         6 sort { $MIDI::Simple::Note{$a} <=> $MIDI::Simple::Note{$b} }
  98         99  
99             keys %MIDI::Simple::Note
100             ];
101             }
102             elsif ( lc $key eq 'note2number' ) {
103             return [
104 128         187 map { "$_ => $MIDI::note2number{$_}" }
105 1         20 sort { $MIDI::note2number{$a} <=> $MIDI::note2number{$b} }
  728         729  
106             keys %MIDI::note2number
107             ];
108             }
109             elsif ( lc $key eq 'number2note' ) {
110             return [
111 128         199 map { "$_ => $MIDI::number2note{$_}" }
112 1         17 sort { $a <=> $b }
  739         674  
113             keys %MIDI::number2note
114             ];
115             }
116             elsif ( lc $key eq 'patch2number' ) {
117             return [
118 128         196 map { "$_ => $MIDI::patch2number{$_}" }
119 1         17 sort { $MIDI::patch2number{$a} <=> $MIDI::patch2number{$b} }
  737         738  
120             keys %MIDI::patch2number
121             ];
122             }
123             elsif ( lc $key eq 'number2patch' ) {
124             return [
125 128         193 map { "$_ => $MIDI::number2patch{$_}" }
126 1         15 sort { $a <=> $b }
  731         673  
127             keys %MIDI::number2patch
128             ];
129             }
130             elsif ( lc $key eq 'notenum2percussion' ) {
131             return [
132 47         74 map { "$_ => $MIDI::notenum2percussion{$_}" }
133 1         7 sort { $a <=> $b }
  207         192  
134             keys %MIDI::notenum2percussion
135             ];
136             }
137             elsif ( lc $key eq 'percussion2notenum' ) {
138             return [
139 47         73 map { "$_ => $MIDI::percussion2notenum{$_}" }
140 1         10 sort { $MIDI::percussion2notenum{$a} <=> $MIDI::percussion2notenum{$b} }
  202         208  
141             keys %MIDI::percussion2notenum
142             ];
143             }
144             elsif ( lc $key eq 'all_events' ) {
145 1         5 return \@MIDI::Event::All_events;
146             }
147             elsif ( lc $key eq 'midi_events' ) {
148 1         3 return \@MIDI::Event::MIDI_events;
149             }
150             elsif ( lc $key eq 'meta_events' ) {
151 1         3 return \@MIDI::Event::Meta_events;
152             }
153             elsif ( lc $key eq 'text_events' ) {
154 1         3 return \@MIDI::Event::Text_events;
155             }
156             elsif ( lc $key eq 'nontext_meta_events' ) {
157 1         3 return \@MIDI::Event::Nontext_meta_events;
158             }
159             else {
160 0         0 return [];
161             }
162             }
163              
164              
165             sub midi_format {
166 1     1 1 415 my (@notes) = @_;
167 1         2 my @formatted;
168 1         2 for my $note (@notes) {
169 4         5 $note =~ s/C##/D/;
170 4         3 $note =~ s/D##/E/;
171 4         5 $note =~ s/F##/G/;
172 4         4 $note =~ s/G##/A/;
173              
174 4         5 $note =~ s/Dbb/C/;
175 4         4 $note =~ s/Ebb/D/;
176 4         4 $note =~ s/Abb/G/;
177 4         3 $note =~ s/Bbb/A/;
178              
179 4         5 $note =~ s/E#/F/;
180 4         5 $note =~ s/B#/C/;
181              
182 4         3 $note =~ s/Cb/B/;
183 4         5 $note =~ s/Fb/E/;
184              
185 4         5 $note =~ s/#/s/;
186 4         5 $note =~ s/b/f/;
187              
188 4         7 push @formatted, $note;
189             }
190 1         3 return @formatted;
191             }
192              
193              
194             sub set_time_signature {
195 1     1 1 2 my ($score, $signature) = @_;
196 1         3 my ($beats, $divisions) = split /\//, $signature;
197 1 50       7 $score->time_signature(
    50          
198             $beats,
199             ($divisions == 8 ? 3 : 2),
200             ($divisions == 8 ? 24 : 18 ),
201             8
202             );
203             }
204              
205              
206             sub dura_size {
207 4     4 1 509 my ($duration, $ppqn) = @_;
208 4   50     38 $ppqn ||= TICKS;
209 4         6 my $size = 0;
210 4 100       15 if ($duration =~ /^d(\d+)$/) {
211 2         23 $size = sprintf '%0.f', $1 / $ppqn;
212             }
213             else {
214 2         3 $size = $MIDI::Simple::Length{$duration};
215             }
216 4         14 return $size;
217             }
218              
219              
220             sub ticks {
221 1     1 1 2 my ($score) = @_;
222 1         2 return ${ $score->{Tempo} };
  1         4  
223             }
224              
225             1;
226              
227             __END__