File Coverage

blib/lib/MIDI/Tools.pm
Criterion Covered Total %
statement 71 71 100.0
branch 30 34 88.2
condition 56 75 74.6
subroutine 9 9 100.0
pod 5 5 100.0
total 171 194 88.1


line stmt bran cond sub pod time code
1             package MIDI::Tools;
2            
3 6     6   59107 use 5.005;
  6         23  
  6         237  
4 6     6   33 use strict;
  6         12  
  6         197  
5 6     6   29 use warnings;
  6         15  
  6         1388  
6            
7             require Exporter;
8 6     6   36 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  6         11  
  6         7466  
9             @ISA = qw(Exporter);
10            
11             # Items to export into callers namespace by default. Note: do not export
12             # names by default without a very good reason. Use EXPORT_OK instead.
13             # Do not simply export all your public functions/methods/constants.
14            
15             # This allows declaration use MIDI::Tools ':all';
16             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
17             # will save memory.
18             %EXPORT_TAGS = ( 'all' => [ qw(note_count note_range note_mean note_limit
19             note_transpose) ] );
20            
21             @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
22            
23             @EXPORT = qw( );
24            
25             $VERSION = '0.02';
26            
27             =head1 NAME
28            
29             MIDI::Tools - Various functions dealing with MIDI Events
30            
31             =head1 SYNOPSIS
32            
33             use MIDI::Tools qw(...);
34            
35             # too much stuff, see below
36            
37             =head1 ABSTRACT
38            
39             MIDI::Tools - Various functions dealing with MIDI events
40            
41             =head1 DESCRIPTION
42            
43             This is a collection of functions evaluating or transforming lists of MIDI
44             events, probably most useful for algorithmic composition. It is designed to
45             be compatible with Sean M. Burke MIDI-Perl suite of modules.
46            
47             =head1 CAVEAT
48            
49             This module is in an early alpha stage of development. Interfaces are not
50             written in stone yet, and stuff needs to be added. Near-future plans include:
51             Dealing with intervals. Dealing with scales (transpose in scale,
52             measure outsideness). Swingifying. Dealing with Chords.
53            
54             =cut
55            
56             =head1 EVALUATING MIDI EVENTS
57            
58             All functions take a reference to a list of MIDI events as parameter and
59             return a scalar or list of results.
60            
61             =head2 $count = note_count($events);
62            
63             Returns number of note_on events (excluding those with a velocity of 0).
64            
65             =cut
66            
67             sub note_count {
68 10     10 1 24 my ($e) = @_;
69            
70 10 100 66     58 return 0 if (!defined $e || !ref $e);
71            
72 8         13 my $count = 0;
73 8         9 foreach (@{$e}) {
  8         17  
74 13         90 $count++
75 18 100 100     47 if (ref $_ && $#{$_} >= 4 && $_->[0] eq 'note_on' && $_->[4] > 0);
      100        
      100        
76             }
77            
78 8         38 return $count;
79             }
80            
81             =head2 ($lowest, $highest) = note_range($events);
82            
83             Returns lowest and highest pitch ocurring in note_on events, or
84             undef if no note_on events occur in $events.
85            
86             =cut
87            
88             sub note_range {
89 10     10 1 101 my ($e) = @_;
90            
91 10 100 66     48 return undef if (!defined $e || !ref $e);
92            
93 8         9 my ($lo, $hi);
94 8         9 foreach (@{$e}) {
  8         14  
95 18 100 100     37 if (ref $_ && $#{$_} >= 4 && $_->[0] eq 'note_on' && $_->[4] > 0) {
  13   100     83  
      100        
96 4 100 66     30 $lo = $_->[3] if (!defined $lo || $_->[3] < $lo);
97 4 50 66     18 $hi = $_->[3] if (!defined $hi || $_->[3] > $hi);
98             }
99             }
100            
101 8 100       36 return undef if (!defined $lo);
102 2         7 return ($lo, $hi);
103             }
104            
105             =head2 ($mean, $stddev) = note_mean($events);
106            
107             Returns mean and standard deviation of pitches in MIDI note_on
108             events.
109            
110             =cut
111            
112             sub note_mean {
113 10     10 1 122 my ($e) = @_;
114            
115 10 100 66     54 return undef if (!defined $e || !ref $e);
116            
117 8         11 my ($count, $sum) = (0, 0);
118 8         11 foreach (@{$e}) {
  8         18  
119 26 100 100     58 if (ref $_ && $#{$_} >= 4 && $_->[0] eq 'note_on' && $_->[4] > 0) {
  21   100     151  
      100        
120 8         10 $count++;
121 8         15 $sum += $_->[3];
122             }
123             }
124            
125 8 100       42 return undef if ($count == 0);
126            
127 2         5 my $avg = $sum / $count;
128 2         3 my $variance = 0;
129 2         2 foreach (@{$e}) {
  2         5  
130 16 100 66     40 if (ref $_ && $#{$_} >= 4 && $_->[0] eq 'note_on' && $_->[4] > 0) {
  16   66     130  
      100        
131 8         23 $variance += ($_->[3] - $avg) * ($_->[3] - $avg);
132             }
133             }
134 2         3 $variance /= $count;
135            
136 2         12 return ($avg, sqrt($variance));
137             }
138            
139             =head1 TRANSFORMING MIDI EVENTS
140            
141             All functions take a reference to a list of MIDI events as parameter and
142             modify the events directly.
143            
144             =head2 note_limit($events, $lowest, $highest);
145            
146             Remove all note_on and note_off events whose pitches lie outside
147             ($lowest .. $highest).
148            
149             =cut
150            
151             sub note_limit {
152 3     3 1 296 my ($e, $lowest, $highest) = @_;
153            
154 3 50 33     15 return undef if (!defined $e || !ref $e);
155 3         4 my $i = 0;
156 3         4 while ($i <= $#{$e}) {
  12         31  
157 9         17 for ($e->[$i]) {
158 9 100 66     21 if (ref $_ && $#{$_} >= 4 && $_->[0] =~ '^note_o(n|ff)$' &&
  9   66     93  
      66        
      66        
159             ($_->[3] < $lowest || $_->[3] > $highest)) {
160 3         4 splice(@{$e}, $i, 1);
  3         12  
161             } else {
162 6         16 $i++;
163             }
164             }
165             }
166            
167             }
168            
169             =head2 note_transpose($events, $semitones);
170            
171             Transpose events by a (positive or negative) number of semitones. Notes will
172             not be transposed below 0 or above 127.
173            
174             =cut
175            
176             sub note_transpose {
177 9     9 1 613 my ($e, $semitones) = @_;
178            
179 9 50 33     38 return undef if (!defined $e || !ref $e);
180            
181 9         15 my ($count, $sum) = (0, 0);
182 9         10 foreach (@{$e}) {
  9         19  
183 9 50 33     25 if (ref $_ && $#{$_} >= 4 && $_->[0] =~ '^note_o(n|ff)$') {
  9   33     72  
184 9         15 $_->[3] += $semitones;
185 9 100       19 $_->[3] = 0 if ($_->[3] < 0);
186 9 100       41 $_->[3] = 127 if ($_->[3] > 127);
187             }
188             }
189             }
190            
191             =head1 SEE ALSO
192            
193             L. L.
194            
195             =head1 AUTHOR
196            
197             Christian Renz, Ecrenz@web42.comE
198            
199             =head1 COPYRIGHT AND LICENSE
200            
201             Copyright 2003 by Christian Renz
202            
203             This library is free software; you can redistribute it and/or modify
204             it under the same terms as Perl itself.
205            
206             =cut
207            
208             1;