File Coverage

blib/lib/Audio/Extract/PCM.pm
Criterion Covered Total %
statement 74 121 61.1
branch 21 56 37.5
condition 5 20 25.0
subroutine 14 19 73.6
pod 6 6 100.0
total 120 222 54.0


line stmt bran cond sub pod time code
1             package Audio::Extract::PCM;
2 3     3   165883 use strict;
  3         13  
  3         129  
3 3     3   16 use warnings;
  3         7  
  3         92  
4 3     3   17 use Carp;
  3         9  
  3         282  
5 3     3   5753 use IO::CaptureOutput qw(qxx);
  3         177529  
  3         232  
6 3     3   6197 use Audio::Extract::PCM::Format;
  3         13  
  3         34  
7 3     3   4547 use Class::Inspector;
  3         21455  
  3         131  
8 3     3   37 use base qw(Exporter);
  3         5  
  3         362  
9              
10 3     3   18 use constant AEP => __PACKAGE__;
  3         6  
  3         3314  
11             our @EXPORT = qw(AEP AEPF);
12              
13             =head1 NAME
14              
15             Audio::Extract::PCM - Extract PCM data from audio files
16              
17             =head1 VERSION
18              
19             Version 0.04_59
20              
21             =cut
22              
23             our $VERSION = '0.04_59';
24              
25              
26             =head1 SYNOPSIS
27              
28             This module's purpose is to extract PCM data from various audio formats. PCM
29             is the format in which you send data to your sound card driver. This module
30             aims to provide a single interface for PCM extraction from various audio
31             formats, compressed and otherwise.
32              
33             The distribution includes some backends which provide access to
34             CPAN's audio decoding modules.
35              
36             Usage example:
37              
38             use Audio::Extract::PCM;
39             my $extractor = Audio::Extract::PCM->new('song.ogg');
40              
41             $extractor->open(endian => 'native', samplesize => 2) or die $extractor->error;
42              
43             warn "Sampling frequency is " . $extractor->format->freq;
44              
45             my $l;
46             while ($l = $extractor->read(my $buf, bytes => 4096)) {
47             print $buf;
48             }
49             die $extractor->error unless defined $l;
50              
51             =head1 METHODS
52              
53             =head2 new
54              
55             Parameters: C
56              
57             Constructs a new object to access the specified file.
58              
59             The extension of the filename will be used to determine which backends open()
60             or pcm() will try.
61              
62             =cut
63              
64             sub new {
65 7     7 1 9124317 my $class = shift;
66 7         63 my ($filename, %args) = @_;
67              
68 7         41 my $this = bless {
69             filename => $filename,
70             }, $class;
71              
72 7         62 my ($ext) = $filename =~ /\.([a-z0-9_]+)\z/i;
73 7 50       34 $ext = '' unless defined $ext;
74              
75 7   50     148 $this->{backends} = {
76             mp3 => [qw( Mad SoX )],
77             ogg => [qw( Vorbis SoX )],
78             wav => [qw( SndFile SoX )],
79             au => [qw( SndFile SoX )],
80             aiff => [qw( SndFile SoX )],
81             }->{lc $ext} || ['SoX'];
82              
83             # Undocumented for now
84 7 50       51 if (exists $args{backends}) {
85 0         0 $this->{backends} = delete $args{backends};
86             }
87 7 100       25 if (exists $args{backend}) {
88 5         21 $this->{backends} = [delete $args{backend}];
89             }
90 7 50       25 if (keys %args) {
91 0         0 croak "Unknown argument: " . join '/', keys %args;
92             }
93              
94 7         26 return $this;
95             }
96              
97              
98             sub _initbackend {
99 16     16   28 my $this = shift;
100 16         28 my ($failed) = @_;
101              
102 16 100       42 if ($failed) {
103              
104 9 50       35 if ($ENV{DEBUG}) {
105 0         0 warn 'Backend '.$this->{backends}[0]." failed\n";
106 0 0       0 if (@{$this->{backends}} > 1) {
  0         0  
107 0         0 warn 'Trying backend '.$this->{backends}[1];
108             }
109             }
110              
111 9         14 shift @{$this->{backends}};
  9         29  
112             }
113 16 100       25 unless (@{$this->{backends}}) {
  16         59  
114 7         25 $this->{error} = 'no suitable backend found';
115 7         194 return ();
116             }
117 9         22 my $backend_short = $this->{backends}[0];
118 9         33 my $backend = join '::', __PACKAGE__, 'Backend', $backend_short;
119              
120 9 50       28 if ($this->_backend_available($backend_short)) {
121 0         0 $this->{backend} = $backend->new(filename => $this->{filename});
122 0         0 return 1;
123             }
124              
125 9         66 return $this->_initbackend('failed');
126             }
127              
128              
129             # =head2 backend_available
130             #
131             # (Class method.)
132             #
133             # Parameter: A backend name, e.g. C<"Mad">.
134             #
135             # Checks whether a specific backend is available on this system. This might load
136             # the backend module.
137             #
138             # Returns true or false.
139             #
140             # =cut
141              
142             # (Pod removed and method made private. I don't like the idea of having public
143             # methods that use string-eval on their parameters.)
144              
145             my %dont_use_backends;
146              
147             sub _backend_available {
148 19     19   194350 my $class = shift;
149 19 50       147 croak('This is a (class) method') unless $class->isa(__PACKAGE__);
150 19 50       174 croak('One parameter expected') unless 1 == @_;
151 19         35 my ($backend_short) = @_;
152              
153             # Better be sure before doing eval and such evil things
154             # (However I hope that you don't pass untrusted strings to this method.)
155 19 50       133 unless ($backend_short =~ /^[A-Z]\w*\z/) {
156 0         0 croak("Bad backend name: $backend_short");
157             }
158            
159 19         61 my $backend = join '::', __PACKAGE__, 'Backend', $backend_short;
160              
161 3     3   43 my $available_ref = do {no strict 'refs'; \${$backend . '::AVAILABLE'}};
  3         17  
  3         3064  
  19         26  
  19         24  
  19         203  
162 19 50       69 return 1 if $$available_ref;
163              
164 19 100 66     166 if (Class::Inspector->installed($backend) && ! $dont_use_backends{$backend}) {
165              
166 6         1070 local $@;
167 6         34 local $SIG{__DIE__};
168              
169             # The AVAILABLE check is done to make sure we avoid the problem
170             # discussed at http://www.perlmonks.org/?node_id=646888
171              
172             # "require" won't fail if %INC has the backend. %INC might have the
173             # backend even though it does not load, maybe because it was already
174             # tried to require in the test suite.
175             # Therefore we have an extra check via the
176             # $Audio::Extract::PCM::Backend::*::AVAILABLE variables. They get set
177             # only if the backend compiles fine.
178              
179 6 50 33     697 if (eval "require $backend; 1" && $$available_ref) {
180 0         0 return 1;
181             }
182 6 50       330 unless ($@ =~ m{^\Q$backend\E - trynext\s}) {
183 0         0 warn;
184             }
185 6         88 $dont_use_backends{$backend} = 1;
186             }
187 19         2187 return 0;
188             }
189              
190              
191             sub _getformat {
192 0     0   0 my $this = shift;
193              
194 0         0 my $format;
195 0 0       0 if (1 == @_) {
196 0         0 $format = $_[0];
197 0 0       0 unless ($format->isa('Audio::Extract::PCM::Format')) {
198 0         0 croak "open's argument is not an Audio::Extract::PCM::Format object";
199             }
200             } else {
201 0         0 $format = Audio::Extract::PCM::Format->new(@_);
202             }
203              
204 0         0 return $format;
205             }
206              
207              
208             =head2 pcm
209              
210             Extracts all pcm data at once.
211              
212             Returns a reference to a string buffer which contains PCM data. The format of
213             these data can be found out using L.
214              
215             On error, an undefined value (or empty list) is returned.
216              
217             Arguments are the same as to L.
218              
219             =cut
220              
221             sub pcm {
222 7     7 1 40 my $this = shift;
223              
224 7 50 33     46 $this->{backend} or $this->_initbackend() or return ();
225              
226             {
227 0         0 my $ret = $this->{backend}->pcm($this->_getformat(@_));
  0         0  
228              
229 0 0 0     0 if ($ret && 'trynext' eq $ret) {
230 0 0       0 $this->_initbackend('failed') or return ();
231 0         0 redo;
232             }
233 0         0 return $this->_backendstatus($ret);
234             }
235             }
236              
237              
238             =head2 open
239              
240             Opens the stream, initializes a backend.
241              
242             =over 8
243              
244             =item Usage
245              
246             $obj->open(
247             freq => 44100,
248             samplesize => 2,
249             channels => 2,
250             endian => 'native',
251             );
252              
253             If there is one single argument, it must be a L
254             object describing the desired format of the extracted PCM data.
255              
256             Otherwise, the supplied arguments will be given to
257             L. See its documentation for details.
258              
259             Note that not all backends support resampling and channel transformation, so if
260             you don't really need 44100 Hz, better don't specify it. You'll probably get
261             the best audio quality if you use the sample rate from the encoded file, which
262             most backends use as default.
263              
264             =item Return value
265              
266             Another L object which describes the actual
267             format of the PCM data. They will be the same values as provided to this
268             method, or some fitting values if no required values were specified. As I
269             said, see L for details.
270              
271             =back
272              
273             =cut
274              
275             sub open {
276 0     0 1 0 my $this = shift;
277              
278 0 0 0     0 $this->{backend} or $this->_initbackend() or return ();
279              
280             {
281 0         0 my $ret = $this->{backend}->open($this->_getformat(@_));
  0         0  
282              
283 0 0 0     0 if ($ret && 'trynext' eq $ret) {
284 0 0       0 $this->_initbackend('failed') or return ();
285 0         0 redo;
286             }
287 0         0 return $this->_backendstatus($ret);
288             }
289             }
290              
291              
292             =head2 read
293              
294             Get decoded PCM samples. Use this only after a successful call to open.
295              
296             =over 8
297              
298             =item Usage
299              
300             $extractor->read(
301             $buffer, # an lvalue
302            
303             append => 1, # Optional: append to buffer
304            
305             # Either a known amount of bytes:
306             bytes => 4096,
307             # or a known amount of time:
308             seconds => 2.5,
309             );
310              
311             The method will read I as many bytes or seconds as specified. Under
312             special circumstances (near the end of file), it may read less.
313              
314             You shouldn't specify both C and C.
315              
316             Maybe I'll get rid of the C option in future releases. And maybe of
317             the I.
318              
319             "Strange" lvalues, like the return value of substr(), are not supported as the
320             C<$buffer> argument (yet?) -- at least for most backends.
321              
322             =item Return value
323              
324             If C were specified, the number of seconds of the read audio data will
325             be returned. Otherwise, the number of read bytes will be returned. On eof, 0
326             will be returned. On error, C will be returned (in scalar context), and
327             the error may be retrieved via error().
328              
329             =back
330              
331             =cut
332              
333             sub read {
334 0     0 1 0 my $this = shift;
335              
336 0         0 my $ret = $this->{backend}->read(@_);
337              
338 0         0 return $this->_backendstatus($ret);
339             }
340              
341              
342             =head2 error
343              
344             Returns the last error that occured for this object.
345              
346             Unfortunately this is often not very readable for computers. For instance, if
347             the file couldn't be opened because it is not there, the various backends have
348             different strings that describe this error.
349              
350             Some of various possible errors:
351              
352             =over 8
353              
354             =item "no suitable backend found"
355              
356             This means that either there is no backend for this file type, or none of the
357             possible backends have their dependencies installed, or none of the possible
358             backends was able to satisfy the PCM format request (i.e. try a less specific
359             format request).
360              
361             =back
362              
363             =cut
364              
365             sub error {
366 7     7 1 57 my $this = shift;
367              
368 7 50       25 if (@_) {
369 0         0 my ($msg) = @_;
370 0         0 return $this->{error} = $msg;
371             }
372              
373 7         51 return $this->{error};
374             }
375              
376              
377             # Give this method the return value of a backend method (or () for definite
378             # failure), then return the return value of this method.
379             #
380             # When the return value is an error, this will set the error descripton from
381             # the backend.
382             sub _backendstatus {
383 0     0     my $this = shift;
384 0           my (@status) = @_;
385              
386 0 0         unless (defined $status[0]) {
387 0           $this->{error} = $this->{backend}->error();
388             }
389              
390 0 0         return @status ? $status[0] : ();
391             }
392              
393              
394             =head2 format
395              
396             Returns a L object which describes the format of
397             the extracted pcm data.
398              
399             You should only call this method after a I call to L or
400             L. If you called L, this method shall return the same format
401             that L has returned.
402              
403             =cut
404              
405             sub format {
406 0     0 1   my $this = shift;
407              
408 0 0         unless ($this->{backend}) {
409 0           croak 'No backend has been initialized. (Call format() only after a successfull call to open() or pcm())';
410             }
411              
412 0           return $this->{backend}->format;
413             }
414              
415              
416             =head1 EXPORTS
417              
418             This module exports the following constants:
419              
420             AEP = "Audio::Extract::PCM"
421             AEPF = "Audio::Extract::PCM::Format"
422              
423             This enables you to write:
424              
425             use Audio::Extract::PCM;
426             my $aep = AEP->new($filename);
427              
428             =head1 SEE ALSO
429              
430             =over 8
431              
432             =item *
433              
434             L - PCM (Pulse-code modulation)
435              
436             =back
437              
438              
439             =head1 DEPENDENCIES
440              
441              
442             Apart from the dependencies that should be automatically installed by CPAN,
443             there are some (optional) other dependencies. It's okay not to install all of
444             them, especially if you don't need all file formats.
445              
446             =over 8
447              
448             =item sox
449              
450             An external audio processing program (should be in the PATH).
451              
452             This is for the SoX backend (L). It will
453             usually be used as a last resort, and it's quite clumsy as it uses an external
454             program, and it doesn't support open/read yet (only pcm()). However, it
455             supports a lot of formats.
456              
457             =item L
458              
459             Used for MP3 decoding (sox supports that too) by
460             L. Please note that as of January 2009,
461             there are some problems with this module (at least with recent perl and gcc
462             versions), and you can find a patch by me at
463             L.
464              
465             L requires the libmad library, and its development headers for
466             compiling.
467              
468             =item L
469              
470             This is used for Ogg/Vorbis decoding (sox supports that too) by
471             L.
472              
473             L requires the vorbis library, and its development
474             headers for compiling.
475              
476             =item L
477              
478             This is a module that supports a wide variety of audio formats and it is used
479             by L.
480              
481             L requires the libsndfile library, and its development headers
482             for compiling.
483              
484             libsndfile had been supporting mainly uncompressed formats for a while, but
485             newer releases seem to support Ogg/Vorbis and FLAC too. At the moment the
486             SndFile backend won't be tried for these formats because my system segfaults.
487             Well, I'm going to make that configurable anyway.
488              
489             About the vorbis support: As I understand it, libsndfile's read function isn't
490             able to return an error status, while libvorbisfile's read function is. As
491             both the Vorbis backend and libsndfile make use of libvorbisfile, you should
492             use the former if you want to have full error control.
493              
494             =back
495              
496              
497             =head1 TODO / PLANS
498              
499             =over 8
500              
501             =item *
502              
503             Maybe I should add functionality for resampling and sample format
504             transformation of the returned PCM data of I backend. Some backends (Mad,
505             SoX) support it, but others don't (Vorbis). The point of the abstract
506             interface is that the user needn't worry about the backends' capabilities, and
507             he shouldn't have to know that he shouldn't try resampling for ogg files.
508              
509             =item *
510              
511             The list (and order) of the backends should be made configurable. For now it's
512             hard-coded, which makes it more or less impossible to write new backend modules
513             without changing this one, however I'm planning to change that.
514              
515             =item *
516              
517             Seeking.
518              
519             =back
520              
521             If you have any good ideas how to implement these todo items, please let me
522             know.
523              
524             =head1 AUTHOR
525              
526             Christoph Bussenius, C<< >>
527              
528             Please include the name of this module in the subject of your emails so they
529             won't get lost in spam.
530              
531             If you find this module useful, I'll be glad if you drop me a note.
532              
533              
534             =head1 COPYRIGHT & LICENSE
535              
536             Copyright 2008 Christoph Bussenius, all rights reserved.
537              
538             This program is free software; you can redistribute it and/or modify it
539             under the same terms as Perl itself.
540              
541              
542             =cut
543              
544             1; # End of Audio::Extract::PCM