ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/PDL-Audio/audio.pd
(Generate patch)

Comparing PDL-Audio/audio.pd (file contents):
Revision 1.5 by root, Tue Dec 28 02:02:59 2004 UTC vs.
Revision 1.9 by root, Tue Nov 8 18:56:06 2005 UTC

1$VERSION = '1.01'; 1$VERSION = '1.1';
2 2
3pp_setversion $VERSION; 3pp_setversion $VERSION;
4pp_beginwrap (); # force error with older PPs 4pp_beginwrap (); # force error with older PPs
5 5
6pp_addpm {At => Top}, <<'EOD'; 6pp_addpm {At => Top}, <<'EOD';
13 use PDL; 13 use PDL;
14 use PDL::Audio; 14 use PDL::Audio;
15 15
16=head1 DESCRIPTION 16=head1 DESCRIPTION
17 17
18Oh well ;) Not much "introductury documentation" has been written yet! See 18Oh well ;) Not much "introductory documentation" has been written yet :(
19my other modules for even worse documentation ;)
20 19
21=head2 NOTATION 20=head2 NOTATION
22 21
23Brackets around parameters indicate that the respective parameter is 22Brackets around parameters indicate that the respective parameter is
24optional and will be replaced with some default value when absent (or 23optional and will be replaced with some default value when absent (or
276 275
277=cut 276=cut
278 277
279sub describe_audio($) { 278sub describe_audio($) {
280 my $pdl = shift; 279 my $pdl = shift;
281 my ($samples, $channels) = $pdl->dims; 280 my ($channels, $samples) = $pdl->dims;
282 my $chan = $channels < 2 ? "mono" : 281 my $chan = $channels < 2 ? "mono" :
283 $channels == 2 ? "stereo" : 282 $channels == 2 ? "stereo" :
284 $channels == 4 ? "quad channel" : 283 $channels == 4 ? "quad channel" :
285 "$channel channel"; 284 "$channels channel";
286 my $desc = "$chan sound with $samples samples"; 285 my $desc = "$chan sound with $samples samples";
287 $desc .= sprintf ", original name \"%s\"", $pdl->path if $pdl->path; 286 $desc .= sprintf ", original name \"%s\"", $pdl->path if $pdl->path;
288 $desc .= sprintf ", type %d (%s)", $pdl->filetype, sound_type_name($pdl->filetype) if $pdl->filetype; 287 $desc .= sprintf ", type %d (%s)", $pdl->filetype, sound_type_name($pdl->filetype) if $pdl->filetype;
289 $desc .= sprintf ", rate %d/s (duration %.2fs)", $pdl->rate, $samples/$pdl->rate if $pdl->rate; 288 $desc .= sprintf ", rate %d/s (duration %.2fs)", $pdl->rate, $samples/$pdl->rate if $pdl->rate;
290 $desc .= sprintf ", format %d (%s)", $pdl->format, sound_format_name($pdl->format) if $pdl->format; 289 $desc .= sprintf ", format %d (%s)", $pdl->format, sound_format_name($pdl->format) if $pdl->format;
291 $desc; 290 $desc
292} 291}
293 292
294=head2 raudio path, [option-hash], option => value, ... 293=head2 raudio path, [option-hash], option => value, ...
295 294
296Reads audio data into the piddle. Options can be anything, most useful values are 295Reads audio data into the piddle. Options can be anything, most useful
297C<filetype>, C<rate>, C<channels> and C<format>. 296values are C<filetype>, C<rate>, C<channels> and C<format>. The returned
297piddle is represents "time" in the outer dimension, and samples in the
298inner (i.e. scalars for mono files, 2-vectors for stereo files):
299
300 [ [left0, right0], [left1, right1], [left2, right2], ...]
298 301
299 # read any file 302 # read any file
300 $pdl = raudio "file.wav"; 303 $pdl = raudio "file.wav";
301 # read a file. if it is a raw file preset values 304 # read a file. if it is a raw file preset values
302 $pdl = raudio "file.raw", filetype => FILE_RAW, rate => 44100, channels => 2; 305 $pdl = raudio "file.raw", filetype => FILE_RAW, rate => 44100, channels => 2;
303 306
304=head2 waudio pdl, [option-hash], option => value, ... 307=head2 waudio pdl, [option-hash], option => value, ...
305 308
306Writes a pdl as a file. The path is taken from the header (or the options), e.g.: 309Writes a pdl as a file. See L<raudio> for options and format. The path and
310other metadata is taken from the header, whcih cna be overwritten using
311options, e.g.:
307 312
308 # write a file, using the header of another piddle 313 # write a file, using the header of another piddle
309 $pdl->waudio($orig_file->gethdr); 314 $pdl->waudio ($orig_file->gethdr);
310 # write pdl as au file, take rate from the header 315 # write pdl as .au file, take rate from the header
311 $pdl->waudio(path => "piddle.au", filetype => FILE_AU, format => FORMAT_16_LINEAR; 316 $pdl->waudio (path => "piddle.au", filetype => FILE_AU, format => FORMAT_16_LINEAR;
312 317
313=cut 318=cut
314 319
315# read a sound file 320# read a sound file
316sub raudio { 321sub raudio {
339 (close_sound_input $fd) >= 0 or barf "$path: ".audio_error_name audio_error; 344 (close_sound_input $fd) >= 0 or barf "$path: ".audio_error_name audio_error;
340 $pdl = $pdl->short->xchg(0,1); 345 $pdl = $pdl->short->xchg(0,1);
341 $pdl = $pdl->clump(2) if $channels == 1; 346 $pdl = $pdl->clump(2) if $channels == 1;
342 $pdl->sever; 347 $pdl->sever;
343 $pdl->sethdr(\%hdr); 348 $pdl->sethdr(\%hdr);
344 $pdl; 349 $pdl
345} 350}
346 351
347sub _audio_make_plain { 352sub _audio_make_plain {
348 my $pdl = shift; 353 my $pdl = shift;
349 if ($pdl->getndims == 1) { 354 if ($pdl->getndims == 1) {
350 ($pdl, 1, $pdl->getdim(0)); 355 ($pdl, 1, $pdl->getdim(0))
351 } else { 356 } else {
352 ($pdl->xchg(0,1)->clump(-1), ($pdl->dims)[1,0]); 357 ($pdl->xchg(0,1)->clump(-1), $pdl->dims)
353 } 358 }
354} 359}
355 360
356sub waudio { 361sub waudio {
357 my $pdl = shift; 362 my $pdl = shift;
362 $hdr{format} ||= FORMAT_16_LINEAR; 367 $hdr{format} ||= FORMAT_16_LINEAR;
363 $hdr{rate} ||= 44100; 368 $hdr{rate} ||= 44100;
364 369
365 ($pdl, $channels, $frames) = _audio_make_plain $pdl->convert(long); 370 ($pdl, $channels, $frames) = _audio_make_plain $pdl->convert(long);
366 371
372 1 <= $channels && $channels <= 2
373 or croak "can only write mono or stereo (one or two channel) files, not $channels channel files";
374
367 my $fd = open_sound_output $hdr{path}, $hdr{rate}, $channels, $hdr{format}, $hdr{filetype}, $hdr{comment}; 375 my $fd = open_sound_output $hdr{path}, $hdr{rate}, $channels, $hdr{format}, $hdr{filetype}, $hdr{comment};
368 $fd >= 0 or barf "$hdr{$path}: ".audio_error_name audio_error; 376 $fd >= 0 or barf "$hdr{$path}: ".audio_error_name audio_error;
369 $pdl->clump(-1)->write_sound($fd, $channels, $frames) 377 $pdl->clump(-1)->write_sound($fd, $channels, $frames)
370 >= 0 or barf "$path: ".audio_error_name audio_error; 378 >= 0 or barf "$path: ".audio_error_name audio_error;
371 (close_sound_output $fd, mus_samples2bytes $hdr{format}, $frames) 379 (close_sound_output $fd, mus_samples2bytes $hdr{format}, $frames * $channels)
372 >= 0 or barf "$hdr{$path}: ".audio_error_name audio_error; 380 >= 0 or barf "$hdr{$path}: ".audio_error_name audio_error;
373} 381}
374 382
375=head2 cut_leading_silence pdl, level 383=head2 cut_leading_silence pdl, level
376 384
391sub cut_leading_silence { 399sub cut_leading_silence {
392 my $pdl = shift; 400 my $pdl = shift;
393 my $level = 1*shift; 401 my $level = 1*shift;
394 my $skip = which (abs($pdl) > $level); 402 my $skip = which (abs($pdl) > $level);
395 $skip = $skip->nelem ? $skip->at(0) : 0; 403 $skip = $skip->nelem ? $skip->at(0) : 0;
396 $pdl->slice("$skip:-1"); 404 $pdl->slice("$skip:-1")
397} 405}
398 406
399sub cut_trailing_silence { 407sub cut_trailing_silence {
400 my $pdl = shift; 408 my $pdl = shift;
401 my $level = 1*shift; 409 my $level = 1*shift;
402 $level = 400000; 410 $level = 400000;
403 my $skip = which (abs($pdl) > $level); 411 my $skip = which (abs($pdl) > $level);
404 $skip = $skip->nelem ? $skip->at(-1) : -1; 412 $skip = $skip->nelem ? $skip->at(-1) : -1;
405 $skip-- if $skip > 0; 413 $skip-- if $skip > 0;
406 $pdl->slice("0:$skip"); 414 $pdl->slice("0:$skip")
407} 415}
408 416
409sub cut_silence { 417sub cut_silence {
410 $_[0]->cut_leading_silence($_[1]) 418 $_[0]->cut_leading_silence($_[1])
411 ->cut_trailing_silence($_[1]); 419 ->cut_trailing_silence($_[1])
412} 420}
413 421
414# have we been a bad boy? 422# have we been a bad boy?
415 423
416for (@METHODS) { 424for (@METHODS) {
753in C<table>, linearly interpolating between successive points of the 761in C<table>, linearly interpolating between successive points of the
754C<waveform>. 762C<waveform>.
755 763
756=head2 partials2waveshape size*, partials, amplitudes, [phase], [fm_mod/] 764=head2 partials2waveshape size*, partials, amplitudes, [phase], [fm_mod/]
757 765
758Take a list (perl list or pdl) of (integer) C<partials> and a list of 766Take a (perl or pdl) list of (integer) C<partials> and a list of
759C<amplitudes> and generate a single wave shape that results by adding 767C<amplitudes> and generate a single wave shape that results by adding
760these partial sines. 768these partial sines.
761 769
762This could (and should) be used by the C<gen_from_table> generator. 770This could (and should) be used by the C<gen_from_table> generator.
763 771
764=head2 gen_from_partials duration*, frequency/, partials, amplitudes, [phase], [fm_mod/] 772=head2 gen_from_partials duration*, frequency/, partials, amplitudes, [phase], [fm_mod/]
765 773
766Take a list (perl list or pdl) of (possibly noninteger) C<partials> and a 774Take a (perl list or pdl) list of (possibly noninteger) C<partials> and a
767list of C<amplitudes> and generate the waveform resulting by summing up 775list of C<amplitudes> and generate the waveform resulting by summing up
768all these partial sines. 776all these partial sines.
769 777
770=cut 778=cut
771 779
1209Calculates the optimal (in the Chebyshev/minimax sense) FIR filter 1217Calculates the optimal (in the Chebyshev/minimax sense) FIR filter
1210impulse response given a set of band edges, the desired reponse on those 1218impulse response given a set of band edges, the desired reponse on those
1211bands, and the weight given to the error in those bands, using the 1219bands, and the weight given to the error in those bands, using the
1212Parks-McClellan exchange algorithm. 1220Parks-McClellan exchange algorithm.
1213 1221
1214The first argument (the one with the funny name) sets the filter 1222The first argument sets the filter size: C<design_remez_fir> returns as
1215size: C<design_remez_fir> returns as many coefficients as specified via 1223many coefficients as specified by this parameter.
1216this parameter.
1217 1224
1218C<bands> is a vector of band edge pairs (start - end), who specify the 1225C<bands> is a vector of band edge pairs (start - end), which specify the
1219start and end of the bands in the filter specification. These must be 1226start and end of the bands in the filter specification. These must be
1220non-overlapping and sorted in increasing order. Only values between C<0> 1227non-overlapping and sorted in increasing order. Only values between C<0>
1221(0 Hz) and C<0.5> (the Nyquist frequency) are allowed. 1228(0 Hz) and C<0.5> (the Nyquist frequency) are allowed.
1222 1229
1223C<des> specifies the desired gain in these bands. 1230C<des> specifies the desired gain in these bands.
1653 1660
1654=head2 spectrum data, [norm], [window], [beta] 1661=head2 spectrum data, [norm], [window], [beta]
1655 1662
1656Returns the spectrum of a given pdl. If C<norm> is absent (or C<undef>), 1663Returns the spectrum of a given pdl. If C<norm> is absent (or C<undef>),
1657it returns the magnitude of the fft of C<data>. When C<norm> == 1 (or 1664it returns the magnitude of the fft of C<data>. When C<norm> == 1 (or
1658C<eq 'NORM'>, in any case), it returns the magnitude, normalized to be 1665C<eq 'NORM'>, case-insensitive), it returns the magnitude, normalized to be
1659between zero and one. If C<norm> == 0 (or C<eq 'dB'>, in any case), then 1666between zero and one. If C<norm> == 0 (or C<eq 'dB'>, case-insensitive), then
1660it returns the magnitude in dB. 1667it returns the magnitude in dB.
1661 1668
1662C<data> is multiplied with C<window> (if not C<undef>) before calculating 1669C<data> is multiplied with C<window> (if not C<undef>) before calculating
1663the fft, and usually contains a window created with C<gen_fft_window> 1670the fft, and usually contains a window created with C<gen_fft_window>
1664(using C<beta>). If C<window> is a string, it is handed over to 1671(using C<beta>). If C<window> is a string, it is handed over to
1891 1898
1892pp_addpm {At => Bot}, <<'EOD'; 1899pp_addpm {At => Bot}, <<'EOD';
1893 1900
1894=head1 AUTHOR 1901=head1 AUTHOR
1895 1902
1896Marc Lehmann <pcg@goof.com>. The ideas were mostly taken from common 1903Marc Lehmann <schmorp@schmorp.de>. The ideas were mostly taken from common
1897lisp music (CLM), by Bill Schottstaedt C<bil@ccrma.stanford.edu>. I also 1904lisp music (CLM), by Bill Schottstaedt C<bil@ccrma.stanford.edu>. I also
1898borrowed many explanations (and references) from the clm docs and some 1905borrowed many explanations (and references) from the clm docs and some
1899code from clm.c. Highly inspiring! 1906code from clm.c. Highly inspiring!
1900 1907
1901=head1 SEE ALSO 1908=head1 SEE ALSO

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines