1 | $VERSION = '1.01'; |
1 | $VERSION = '1.011'; |
2 | |
2 | |
3 | pp_setversion $VERSION; |
3 | pp_setversion $VERSION; |
4 | pp_beginwrap (); # force error with older PPs |
4 | pp_beginwrap (); # force error with older PPs |
5 | |
5 | |
6 | pp_addpm {At => Top}, <<'EOD'; |
6 | pp_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 | |
18 | Oh well ;) Not much "introductury documentation" has been written yet! See |
18 | Oh well ;) Not much "introductory documentation" has been written yet :( |
19 | my other modules for even worse documentation ;) |
|
|
20 | |
19 | |
21 | =head2 NOTATION |
20 | =head2 NOTATION |
22 | |
21 | |
23 | Brackets around parameters indicate that the respective parameter is |
22 | Brackets around parameters indicate that the respective parameter is |
24 | optional and will be replaced with some default value when absent (or |
23 | optional and will be replaced with some default value when absent (or |
… | |
… | |
753 | in C<table>, linearly interpolating between successive points of the |
752 | in C<table>, linearly interpolating between successive points of the |
754 | C<waveform>. |
753 | C<waveform>. |
755 | |
754 | |
756 | =head2 partials2waveshape size*, partials, amplitudes, [phase], [fm_mod/] |
755 | =head2 partials2waveshape size*, partials, amplitudes, [phase], [fm_mod/] |
757 | |
756 | |
758 | Take a list (perl list or pdl) of (integer) C<partials> and a list of |
757 | Take a (perl or pdl) list of (integer) C<partials> and a list of |
759 | C<amplitudes> and generate a single wave shape that results by adding |
758 | C<amplitudes> and generate a single wave shape that results by adding |
760 | these partial sines. |
759 | these partial sines. |
761 | |
760 | |
762 | This could (and should) be used by the C<gen_from_table> generator. |
761 | This could (and should) be used by the C<gen_from_table> generator. |
763 | |
762 | |
764 | =head2 gen_from_partials duration*, frequency/, partials, amplitudes, [phase], [fm_mod/] |
763 | =head2 gen_from_partials duration*, frequency/, partials, amplitudes, [phase], [fm_mod/] |
765 | |
764 | |
766 | Take a list (perl list or pdl) of (possibly noninteger) C<partials> and a |
765 | Take a (perl list or pdl) list of (possibly noninteger) C<partials> and a |
767 | list of C<amplitudes> and generate the waveform resulting by summing up |
766 | list of C<amplitudes> and generate the waveform resulting by summing up |
768 | all these partial sines. |
767 | all these partial sines. |
769 | |
768 | |
770 | =cut |
769 | =cut |
771 | |
770 | |
… | |
… | |
1209 | Calculates the optimal (in the Chebyshev/minimax sense) FIR filter |
1208 | Calculates the optimal (in the Chebyshev/minimax sense) FIR filter |
1210 | impulse response given a set of band edges, the desired reponse on those |
1209 | impulse response given a set of band edges, the desired reponse on those |
1211 | bands, and the weight given to the error in those bands, using the |
1210 | bands, and the weight given to the error in those bands, using the |
1212 | Parks-McClellan exchange algorithm. |
1211 | Parks-McClellan exchange algorithm. |
1213 | |
1212 | |
1214 | The first argument (the one with the funny name) sets the filter |
1213 | The first argument sets the filter size: C<design_remez_fir> returns as |
1215 | size: C<design_remez_fir> returns as many coefficients as specified via |
1214 | many coefficients as specified by this parameter. |
1216 | this parameter. |
|
|
1217 | |
1215 | |
1218 | C<bands> is a vector of band edge pairs (start - end), who specify the |
1216 | C<bands> is a vector of band edge pairs (start - end), which specify the |
1219 | start and end of the bands in the filter specification. These must be |
1217 | start and end of the bands in the filter specification. These must be |
1220 | non-overlapping and sorted in increasing order. Only values between C<0> |
1218 | non-overlapping and sorted in increasing order. Only values between C<0> |
1221 | (0 Hz) and C<0.5> (the Nyquist frequency) are allowed. |
1219 | (0 Hz) and C<0.5> (the Nyquist frequency) are allowed. |
1222 | |
1220 | |
1223 | C<des> specifies the desired gain in these bands. |
1221 | C<des> specifies the desired gain in these bands. |
… | |
… | |
1500 | $beta = 2.5 unless defined $beta; |
1498 | $beta = 2.5 unless defined $beta; |
1501 | |
1499 | |
1502 | $size = $size->getdim(0) if ref $size; |
1500 | $size = $size->getdim(0) if ref $size; |
1503 | $size > 2 or barf "fft window size too small"; |
1501 | $size > 2 or barf "fft window size too small"; |
1504 | |
1502 | |
1505 | my $midn = $size >> 1; |
1503 | my $midn = $size >> 1; |
1506 | my $midm1 = ($size-1) >> 1; |
1504 | my $midm1 = ($size-1) >> 1; |
1507 | my $midp1 = ($size+1) >> 1; |
1505 | my $midp1 = ($size+1) >> 1; |
1508 | my $dur = zeroes $size; |
1506 | my $dur = zeroes $size; |
1509 | my $sf = ($size-1)/$size; |
1507 | my $sf = ($size-1)/$size; |
1510 | %fft_window = ( |
1508 | %fft_window = ( |
1511 | RECTANGULAR => sub { |
1509 | RECTANGULAR => sub { |
1512 | $dur->ones |
1510 | $dur->ones |
1513 | }, |
1511 | }, |
… | |
… | |
1653 | |
1651 | |
1654 | =head2 spectrum data, [norm], [window], [beta] |
1652 | =head2 spectrum data, [norm], [window], [beta] |
1655 | |
1653 | |
1656 | Returns the spectrum of a given pdl. If C<norm> is absent (or C<undef>), |
1654 | Returns the spectrum of a given pdl. If C<norm> is absent (or C<undef>), |
1657 | it returns the magnitude of the fft of C<data>. When C<norm> == 1 (or |
1655 | it returns the magnitude of the fft of C<data>. When C<norm> == 1 (or |
1658 | C<eq 'NORM'>, in any case), it returns the magnitude, normalized to be |
1656 | C<eq 'NORM'>, case-insensitive), it returns the magnitude, normalized to be |
1659 | between zero and one. If C<norm> == 0 (or C<eq 'dB'>, in any case), then |
1657 | between zero and one. If C<norm> == 0 (or C<eq 'dB'>, case-insensitive), then |
1660 | it returns the magnitude in dB. |
1658 | it returns the magnitude in dB. |
1661 | |
1659 | |
1662 | C<data> is multiplied with C<window> (if not C<undef>) before calculating |
1660 | C<data> is multiplied with C<window> (if not C<undef>) before calculating |
1663 | the fft, and usually contains a window created with C<gen_fft_window> |
1661 | the 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 |
1662 | (using C<beta>). If C<window> is a string, it is handed over to |
… | |
… | |
1671 | |
1669 | |
1672 | sub spectrum { |
1670 | sub spectrum { |
1673 | my ($data, $norm, $window, $beta) = @_; |
1671 | my ($data, $norm, $window, $beta) = @_; |
1674 | my $len; |
1672 | my $len; |
1675 | if (defined $window) { |
1673 | if (defined $window) { |
1676 | $window = gen_fft_window ($data->getdim(0), $window, $beta) unless ref $window; |
1674 | $window = gen_fft_window ($data->getdim (0), $window, $beta) unless ref $window; |
1677 | $data = $data * $window; |
1675 | $data = $data * $window; |
1678 | $len = $window->getdim(0); |
1676 | $len = $window->getdim (0); |
1679 | } else { |
1677 | } else { |
1680 | $len = $data->getdim(0); |
1678 | $len = $data->getdim (0); |
1681 | } |
1679 | } |
1682 | $data = rfft ($data->slice("0:".($len-1))->sever)->slice(",0:".int($len/2))->Cr2p->slice("(0)"); |
1680 | $data = rfft ( |
|
|
1681 | $data->slice ("0:" . ($len - 1)) |
|
|
1682 | ->sever |
|
|
1683 | ) |
|
|
1684 | ->slice (",0:" . int ($len / 2)) |
|
|
1685 | ->PDL::Complex::Cr2p |
|
|
1686 | ->slice ("(0)"); |
1683 | if ($norm == 1 || lc $norm eq "norm") { |
1687 | if ($norm == 1 || lc $norm eq "norm") { |
1684 | $data / max $data; |
1688 | $data / max $data; |
1685 | } elsif (($norm =~ /^[.0]+$/) || (lc $norm eq "db")) { |
1689 | } elsif (($norm =~ /^[.0]+$/) || (lc $norm eq "db")) { |
1686 | log (1e-37 + $data / max $data) * (20 / log 10); |
1690 | log (1e-37 + $data / max $data) * (20 / log 10); |
1687 | } else { |
1691 | } else { |
… | |
… | |
1885 | |
1889 | |
1886 | pp_addpm {At => Bot}, <<'EOD'; |
1890 | pp_addpm {At => Bot}, <<'EOD'; |
1887 | |
1891 | |
1888 | =head1 AUTHOR |
1892 | =head1 AUTHOR |
1889 | |
1893 | |
1890 | Marc Lehmann <pcg@goof.com>. The ideas were mostly taken from common |
1894 | Marc Lehmann <schmorp@schmorp.de>. The ideas were mostly taken from common |
1891 | lisp music (CLM), by Bill Schottstaedt C<bil@ccrma.stanford.edu>. I also |
1895 | lisp music (CLM), by Bill Schottstaedt C<bil@ccrma.stanford.edu>. I also |
1892 | borrowed many explanations (and references) from the clm docs and some |
1896 | borrowed many explanations (and references) from the clm docs and some |
1893 | code from clm.c. Highly inspiring! |
1897 | code from clm.c. Highly inspiring! |
1894 | |
1898 | |
1895 | =head1 SEE ALSO |
1899 | =head1 SEE ALSO |