From dc5e8b9fd698ab69e6d752a89b2adc12107b27ec Mon Sep 17 00:00:00 2001 From: takenori-y Date: Mon, 31 Aug 2020 21:23:39 +0900 Subject: [PATCH] update ifft --- doc/Doxyfile | 2 + doc/cmd/ifft.rst | 7 ++ include/SPTK/math/fast_fourier_transform.h | 6 ++ .../math/inverse_fast_fourier_transform.h | 66 +++++++++++++--- .../math/real_valued_fast_fourier_transform.h | 5 ++ ...al_valued_inverse_fast_fourier_transform.h | 5 ++ ...ast_fourier_transform_cepstral_analysis.cc | 4 +- src/analyzer/mel_cepstral_analysis.cc | 4 +- .../mel_generalized_cepstral_analysis.cc | 6 +- src/converter/cepstrum_to_autocorrelation.cc | 2 +- ...o_negative_derivative_of_phase_spectrum.cc | 2 +- .../filter_coefficients_to_spectrum.cc | 2 +- ...erivative_of_phase_spectrum_to_cepstrum.cc | 2 +- src/main/ifft.cc | 75 ++++++++++++------ src/math/fast_fourier_transform.cc | 4 + src/math/fourier_transform.cc | 2 +- src/math/inverse_fast_fourier_transform.cc | 46 +++++------ .../real_valued_fast_fourier_transform.cc | 6 +- ...l_valued_inverse_fast_fourier_transform.cc | 10 ++- .../two_dimensional_fast_fourier_transform.cc | 2 +- ...ast_fourier_transform_for_real_sequence.cc | 4 +- ...ensional_inverse_fast_fourier_transform.cc | 2 +- .../mlsa_digital_filter_stability_check.cc | 9 +-- test/test_ifft.bats | 78 +++++++++++++++++++ 24 files changed, 268 insertions(+), 83 deletions(-) create mode 100644 doc/cmd/ifft.rst create mode 100644 test/test_ifft.bats diff --git a/doc/Doxyfile b/doc/Doxyfile index 88385109..56fc74bf 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -853,6 +853,7 @@ INPUT = \ ../include/SPTK/filter/all_zero_digital_filter.h \ ../include/SPTK/math/fast_fourier_transform.h \ ../include/SPTK/math/frequency_transform.h \ + ../include/SPTK/math/inverse_fast_fourier_transform.h \ ../include/SPTK/math/real_valued_fast_fourier_transform.h \ ../include/SPTK/math/real_valued_inverse_fast_fourier_transform.h \ ../include/SPTK/normalizer/generalized_cepstrum_gain_normalization.h \ @@ -863,6 +864,7 @@ INPUT = \ ../src/main/fftr.cc \ ../src/main/freqt.cc \ ../src/main/gnorm.cc \ + ../src/main/ifft.cc \ ../src/main/ignorm.cc \ ../src/main/iulaw.cc \ ../src/main/mc2b.cc \ diff --git a/doc/cmd/ifft.rst b/doc/cmd/ifft.rst new file mode 100644 index 00000000..b0aa5fff --- /dev/null +++ b/doc/cmd/ifft.rst @@ -0,0 +1,7 @@ +ifft +==== + +.. doxygenfile:: ifft.cc + +.. doxygenclass:: sptk::InverseFastFourierTransform + :members: diff --git a/include/SPTK/math/fast_fourier_transform.h b/include/SPTK/math/fast_fourier_transform.h index 8b1233af..4fd6160b 100644 --- a/include/SPTK/math/fast_fourier_transform.h +++ b/include/SPTK/math/fast_fourier_transform.h @@ -73,6 +73,11 @@ namespace sptk { */ class FastFourierTransform { public: + /** + * @param[in] fft_length FFT length, \f$L\f$. + */ + explicit FastFourierTransform(int fft_length); + /** * @param[in] num_order Order of input, \f$M\f$. * @param[in] fft_length FFT length, \f$L\f$. @@ -114,6 +119,7 @@ class FastFourierTransform { const std::vector& imag_part_input, std::vector* real_part_output, std::vector* imag_part_output) const; + /** * @param[in,out] real_part Real part. * @param[in,out] imag_part Imaginary part. diff --git a/include/SPTK/math/inverse_fast_fourier_transform.h b/include/SPTK/math/inverse_fast_fourier_transform.h index b16a3653..fe690782 100644 --- a/include/SPTK/math/inverse_fast_fourier_transform.h +++ b/include/SPTK/math/inverse_fast_fourier_transform.h @@ -8,7 +8,7 @@ // Interdisciplinary Graduate School of // // Science and Engineering // // // -// 1996-2019 Nagoya Institute of Technology // +// 1996-2020 Nagoya Institute of Technology // // Department of Computer Science // // // // All rights reserved. // @@ -52,40 +52,86 @@ namespace sptk { +/** + * Calculate inverse DFT of complex-valued input data. + * + * The input is \f$M\f$-th order complex-valued data: + * \f[ + * \begin{array}{cccc} + * \mathrm{Re}(x(0)), & \mathrm{Re}(x(1)), & \ldots, & \mathrm{Re}(x(M)), \\ + * \mathrm{Im}(x(0)), & \mathrm{Im}(x(1)), & \ldots, & \mathrm{Im}(x(M)), + * \end{array} + * \f] + * The outputs are + * \f[ + * \begin{array}{cccc} + * \mathrm{Re}(X(0)), & \mathrm{Re}(X(1)), & \ldots, & \mathrm{Re}(X(L-1)), \\ + * \mathrm{Im}(X(0)), & \mathrm{Im}(X(1)), & \ldots, & \mathrm{Im}(X(L-1)), + * \end{array} + * \f] + * where \f$L\f$ is the FFT length and \f$X\f$ is the complex-valued inverse FFT + * sequence of \f$x\f$. + */ class InverseFastFourierTransform { public: - // + /** + * @param[in] fft_length FFT length, \f$L\f$. + */ + explicit InverseFastFourierTransform(int fft_length); + + /** + * @param[in] num_order Order of input, \f$M\f$. + * @param[in] fft_length FFT length, \f$L\f$. + */ InverseFastFourierTransform(int num_order, int fft_length); - // virtual ~InverseFastFourierTransform() { } + /** + * @return Order of input. + */ int GetNumOrder() const { return fast_fourier_transform_.GetNumOrder(); } - // + /** + * @return FFT length. + */ int GetFftLength() const { return fast_fourier_transform_.GetFftLength(); } - // + /** + * @return True if this obejct is valid. + */ bool IsValid() const { return fast_fourier_transform_.IsValid(); } - // + /** + * @param[in] real_part_input \f$M\f$-th order real part of input. + * @param[in] imag_part_input \f$M\f$-th order imaginary part of input. + * @param[out] real_part_output Real part of output. + * @param[out] imag_part_output Imaginary part of output. + * @return True on success, false on failure. + */ bool Run(const std::vector& real_part_input, - const std::vector& imaginary_part_input, + const std::vector& imag_part_input, std::vector* real_part_output, - std::vector* imaginary_part_output) const; + std::vector* imag_part_output) const; + + /** + * @param[in,out] real_part Real part. + * @param[in,out] imag_part Imaginary part. + * @return True on success, false on failure. + */ + bool Run(std::vector* real_part, + std::vector* imag_part) const; private: - // const FastFourierTransform fast_fourier_transform_; - // DISALLOW_COPY_AND_ASSIGN(InverseFastFourierTransform); }; diff --git a/include/SPTK/math/real_valued_fast_fourier_transform.h b/include/SPTK/math/real_valued_fast_fourier_transform.h index 8755db8b..128f3513 100644 --- a/include/SPTK/math/real_valued_fast_fourier_transform.h +++ b/include/SPTK/math/real_valued_fast_fourier_transform.h @@ -92,6 +92,11 @@ class RealValuedFastFourierTransform { DISALLOW_COPY_AND_ASSIGN(Buffer); }; + /** + * @param[in] fft_length FFT length, \f$L\f$. + */ + explicit RealValuedFastFourierTransform(int fft_length); + /** * @param[in] num_order Order of input, \f$M\f$. * @param[in] fft_length FFT length, \f$L\f$. diff --git a/include/SPTK/math/real_valued_inverse_fast_fourier_transform.h b/include/SPTK/math/real_valued_inverse_fast_fourier_transform.h index c0b8b751..a77871a8 100644 --- a/include/SPTK/math/real_valued_inverse_fast_fourier_transform.h +++ b/include/SPTK/math/real_valued_inverse_fast_fourier_transform.h @@ -78,6 +78,11 @@ class RealValuedInverseFastFourierTransform { DISALLOW_COPY_AND_ASSIGN(Buffer); }; + /** + * @param[in] fft_length FFT length, \f$L\f$. + */ + explicit RealValuedInverseFastFourierTransform(int fft_length); + /** * @param[in] num_order Order of input, \f$M\f$. * @param[in] fft_length FFT length, \f$L\f$. diff --git a/src/analyzer/fast_fourier_transform_cepstral_analysis.cc b/src/analyzer/fast_fourier_transform_cepstral_analysis.cc index 8e3d1835..9506a1a2 100644 --- a/src/analyzer/fast_fourier_transform_cepstral_analysis.cc +++ b/src/analyzer/fast_fourier_transform_cepstral_analysis.cc @@ -54,8 +54,8 @@ FastFourierTransformCepstralAnalysis::FastFourierTransformCepstralAnalysis( : num_order_(num_order), num_iteration_(num_iteration), acceleration_factor_(acceleration_factor), - fast_fourier_transform_(fft_length - 1, fft_length), - inverse_fast_fourier_transform_(fft_length - 1, fft_length), + fast_fourier_transform_(fft_length), + inverse_fast_fourier_transform_(fft_length), is_valid_(true) { if (num_order_ < 0 || fft_length < 2 * num_order_ || num_iteration_ <= 0 || acceleration_factor_ < 0.0 || !fast_fourier_transform_.IsValid() || diff --git a/src/analyzer/mel_cepstral_analysis.cc b/src/analyzer/mel_cepstral_analysis.cc index 425fdad8..aca39d77 100644 --- a/src/analyzer/mel_cepstral_analysis.cc +++ b/src/analyzer/mel_cepstral_analysis.cc @@ -102,8 +102,8 @@ MelCepstralAnalysis::MelCepstralAnalysis(int fft_length, int num_order, alpha_(alpha), num_iteration_(num_iteration), convergence_threshold_(convergence_threshold), - fourier_transform_(fft_length_ - 1, fft_length_), - inverse_fourier_transform_(fft_length_ - 1, fft_length_), + fourier_transform_(fft_length_), + inverse_fourier_transform_(fft_length_), frequency_transform_(fft_length_ / 2, num_order_, alpha_), inverse_frequency_transform_(num_order_, fft_length_ / 2, -alpha_), toeplitz_plus_hankel_system_solver_(num_order_, true), diff --git a/src/analyzer/mel_generalized_cepstral_analysis.cc b/src/analyzer/mel_generalized_cepstral_analysis.cc index 7a172876..1afc9132 100644 --- a/src/analyzer/mel_generalized_cepstral_analysis.cc +++ b/src/analyzer/mel_generalized_cepstral_analysis.cc @@ -139,9 +139,9 @@ MelGeneralizedCepstralAnalysis::MelGeneralizedCepstralAnalysis( gamma_(gamma), num_iteration_(num_iteration), convergence_threshold_(convergence_threshold), - fourier_transform_(fft_length_ - 1, fft_length_), - inverse_fourier_transform_(fft_length_ - 1, fft_length_), - complex_valued_inverse_fourier_transform_(fft_length_ - 1, fft_length_), + fourier_transform_(fft_length_), + inverse_fourier_transform_(fft_length_), + complex_valued_inverse_fourier_transform_(fft_length_), toeplitz_plus_hankel_system_solver_(num_order_ - 1, true), generalized_cepstrum_gain_normalization_(num_order_, gamma_), generalized_cepstrum_inverse_gain_normalization_gamma_minus_one_( diff --git a/src/converter/cepstrum_to_autocorrelation.cc b/src/converter/cepstrum_to_autocorrelation.cc index 86980722..f071fdbf 100644 --- a/src/converter/cepstrum_to_autocorrelation.cc +++ b/src/converter/cepstrum_to_autocorrelation.cc @@ -56,7 +56,7 @@ CepstrumToAutocorrelation::CepstrumToAutocorrelation(int num_input_order, int fft_length) : num_input_order_(num_input_order), num_output_order_(num_output_order), - fast_fourier_transform_(fft_length - 1, fft_length), + fast_fourier_transform_(fft_length), is_valid_(true) { if (num_input_order_ < 0 || num_output_order_ < 0 || fft_length <= num_input_order_ || fft_length <= num_output_order_ || diff --git a/src/converter/cepstrum_to_negative_derivative_of_phase_spectrum.cc b/src/converter/cepstrum_to_negative_derivative_of_phase_spectrum.cc index 3a026b66..64a31af0 100644 --- a/src/converter/cepstrum_to_negative_derivative_of_phase_spectrum.cc +++ b/src/converter/cepstrum_to_negative_derivative_of_phase_spectrum.cc @@ -52,7 +52,7 @@ namespace sptk { CepstrumToNegativeDerivativeOfPhaseSpectrum:: CepstrumToNegativeDerivativeOfPhaseSpectrum(int num_order, int fft_length) : num_order_(num_order), - fast_fourier_transform_(fft_length - 1, fft_length), + fast_fourier_transform_(fft_length), is_valid_(true) { if (num_order_ < 0 || fft_length < 2 * num_order_ || !fast_fourier_transform_.IsValid()) { diff --git a/src/converter/filter_coefficients_to_spectrum.cc b/src/converter/filter_coefficients_to_spectrum.cc index 5295a664..93f16a58 100644 --- a/src/converter/filter_coefficients_to_spectrum.cc +++ b/src/converter/filter_coefficients_to_spectrum.cc @@ -62,7 +62,7 @@ FilterCoefficientsToSpectrum::FilterCoefficientsToSpectrum( output_format_(output_format), epsilon_for_calculating_logarithms_(epsilon_for_calculating_logarithms), relative_floor_in_decibels_(relative_floor_in_decibels), - fast_fourier_transform_(fft_length_ - 1, fft_length_), + fast_fourier_transform_(fft_length_), is_valid_(true) { if (num_numerator_order_ < 0 || num_denominator_order_ < 0 || fft_length_ <= num_numerator_order_ || diff --git a/src/converter/negative_derivative_of_phase_spectrum_to_cepstrum.cc b/src/converter/negative_derivative_of_phase_spectrum_to_cepstrum.cc index 4db81dfc..4f1f009a 100644 --- a/src/converter/negative_derivative_of_phase_spectrum_to_cepstrum.cc +++ b/src/converter/negative_derivative_of_phase_spectrum_to_cepstrum.cc @@ -52,7 +52,7 @@ namespace sptk { NegativeDerivativeOfPhaseSpectrumToCepstrum:: NegativeDerivativeOfPhaseSpectrumToCepstrum(int fft_length, int num_order) : num_order_(num_order), - fast_fourier_transform_(fft_length - 1, fft_length), + fast_fourier_transform_(fft_length), is_valid_(true) { if (num_order_ < 0 || fft_length < 2 * num_order_ || !fast_fourier_transform_.IsValid()) { diff --git a/src/main/ifft.cc b/src/main/ifft.cc index a32e279c..fd1b47f1 100644 --- a/src/main/ifft.cc +++ b/src/main/ifft.cc @@ -8,7 +8,7 @@ // Interdisciplinary Graduate School of // // Science and Engineering // // // -// 1996-2019 Nagoya Institute of Technology // +// 1996-2020 Nagoya Institute of Technology // // Department of Computer Science // // // // All rights reserved. // @@ -43,6 +43,7 @@ // ----------------------------------------------------------------- // #include // getopt_long + #include // std::ifstream #include // std::setw #include // std::cerr, std::cin, std::cout, std::endl, etc. @@ -55,21 +56,22 @@ namespace { enum InputFormats { - kInputRealAndImaginaryParts = 0, + kInputRealAndImagParts = 0, kInputRealPart, + kInputImagPart, kNumInputFormats }; enum OutputFormats { - kOutputRealAndImaginaryParts = 0, + kOutputRealAndImagParts = 0, kOutputRealPart, - kOutputImaginaryPart, + kOutputImagPart, kNumOutputFormats }; const int kDefaultFftLength(256); -const InputFormats kDefaultInputFormat(kInputRealAndImaginaryParts); -const OutputFormats kDefaultOutputFormat(kOutputRealAndImaginaryParts); +const InputFormats kDefaultInputFormat(kInputRealAndImagParts); +const OutputFormats kDefaultOutputFormat(kOutputRealAndImagParts); void PrintUsage(std::ostream* stream) { // clang-format off @@ -79,10 +81,11 @@ void PrintUsage(std::ostream* stream) { *stream << " usage:" << std::endl; *stream << " ifft [ options ] [ infile ] > stdout" << std::endl; *stream << " options:" << std::endl; - *stream << " -l l : FFT length ( int)[" << std::setw(5) << std::right << kDefaultFftLength << "][ 0 < l <= ]" << std::endl; // NOLINT + *stream << " -l l : FFT length ( int)[" << std::setw(5) << std::right << kDefaultFftLength << "][ 1 <= l <= ]" << std::endl; // NOLINT *stream << " -q q : input format ( int)[" << std::setw(5) << std::right << kDefaultInputFormat << "][ 0 <= q <= 1 ]" << std::endl; // NOLINT *stream << " 0 (real and imaginary parts)" << std::endl; *stream << " 1 (real part)" << std::endl; + *stream << " 2 (imaginary part)" << std::endl; *stream << " -o o : output format ( int)[" << std::setw(5) << std::right << kDefaultOutputFormat << "][ 0 <= o <= 2 ]" << std::endl; // NOLINT *stream << " 0 (real and imaginary parts)" << std::endl; *stream << " 1 (real part)" << std::endl; @@ -102,6 +105,30 @@ void PrintUsage(std::ostream* stream) { } // namespace +/** + * \a ifft [ \e option ] [ \e infile ] + * + * - \b -l \e int + * - FFT length \f$(1 \le L)\f$ + * - \b -q \e int + * - input format + * \arg \c 0 real and imaginary parts + * \arg \c 1 real part + * \arg \c 2 imaginary part + * - \b -o \e int + * - output format + * \arg \c 0 real and imaginary parts + * \arg \c 1 real part + * \arg \c 2 imaginary part + * - \b infile \e str + * - double-type data sequence + * - \b stdout + * - double-type inverse FFT sequence + * + * @param[in] argc Number of arguments. + * @param[in] argv Argument vector. + * @return 0 on success, 1 on false. + */ int main(int argc, char* argv[]) { int fft_length(kDefaultFftLength); InputFormats input_format(kDefaultInputFormat); @@ -162,7 +189,6 @@ int main(int argc, char* argv[]) { } } - // get input file const int num_input_files(argc - optind); if (1 < num_input_files) { std::ostringstream error_message; @@ -172,7 +198,6 @@ int main(int argc, char* argv[]) { } const char* input_file(0 == num_input_files ? NULL : argv[optind]); - // open stream std::ifstream ifs; ifs.open(input_file, std::ios::in | std::ios::binary); if (ifs.fail() && NULL != input_file) { @@ -183,9 +208,7 @@ int main(int argc, char* argv[]) { } std::istream& input_stream(ifs.fail() ? std::cin : ifs); - // prepare for inverse fast Fourier transform - sptk::InverseFastFourierTransform inverse_fast_fourier_transform( - fft_length - 1, fft_length); + sptk::InverseFastFourierTransform inverse_fast_fourier_transform(fft_length); if (!inverse_fast_fourier_transform.IsValid()) { std::ostringstream error_message; error_message << "FFT length must be a power of 2"; @@ -198,14 +221,20 @@ int main(int argc, char* argv[]) { std::vector output_x(fft_length); std::vector output_y(fft_length); - while ((kInputRealAndImaginaryParts == input_format && - sptk::ReadStream(false, 0, 0, fft_length, &input_x, &input_stream, - NULL) && - sptk::ReadStream(false, 0, 0, fft_length, &input_y, &input_stream, - NULL)) || - (kInputRealPart == input_format && - sptk::ReadStream(false, 0, 0, fft_length, &input_x, &input_stream, - NULL))) { + for (;;) { + if ((kInputRealAndImagParts == input_format || + kInputRealPart == input_format) && + !sptk::ReadStream(false, 0, 0, fft_length, &input_x, &input_stream, + NULL)) { + break; + } + if ((kInputRealAndImagParts == input_format || + kInputImagPart == input_format) && + !sptk::ReadStream(false, 0, 0, fft_length, &input_y, &input_stream, + NULL)) { + break; + } + if (!inverse_fast_fourier_transform.Run(input_x, input_y, &output_x, &output_y)) { std::ostringstream error_message; @@ -214,7 +243,7 @@ int main(int argc, char* argv[]) { return 1; } - if ((kOutputRealAndImaginaryParts == output_format || + if ((kOutputRealAndImagParts == output_format || kOutputRealPart == output_format) && !sptk::WriteStream(0, fft_length, output_x, &std::cout, NULL)) { std::ostringstream error_message; @@ -223,8 +252,8 @@ int main(int argc, char* argv[]) { return 1; } - if ((kOutputRealAndImaginaryParts == output_format || - kOutputImaginaryPart == output_format) && + if ((kOutputRealAndImagParts == output_format || + kOutputImagPart == output_format) && !sptk::WriteStream(0, fft_length, output_y, &std::cout, NULL)) { std::ostringstream error_message; error_message << "Failed to write imaginary parts"; diff --git a/src/math/fast_fourier_transform.cc b/src/math/fast_fourier_transform.cc index 93fbe85c..b2df21a8 100644 --- a/src/math/fast_fourier_transform.cc +++ b/src/math/fast_fourier_transform.cc @@ -50,6 +50,10 @@ namespace sptk { +FastFourierTransform::FastFourierTransform(int fft_length) + : FastFourierTransform(fft_length - 1, fft_length) { +} + FastFourierTransform::FastFourierTransform(int num_order, int fft_length) : num_order_(num_order), fft_length_(fft_length), diff --git a/src/math/fourier_transform.cc b/src/math/fourier_transform.cc index 82816490..b7cdec74 100644 --- a/src/math/fourier_transform.cc +++ b/src/math/fourier_transform.cc @@ -53,7 +53,7 @@ class FastFourierTransformWrapper : public sptk::FourierTransform::FourierTransformInterface { public: explicit FastFourierTransformWrapper(int fft_length) - : fast_fourier_tranform_(fft_length - 1, fft_length) { + : fast_fourier_tranform_(fft_length) { } virtual ~FastFourierTransformWrapper() { } diff --git a/src/math/inverse_fast_fourier_transform.cc b/src/math/inverse_fast_fourier_transform.cc index 1599ca08..43939187 100644 --- a/src/math/inverse_fast_fourier_transform.cc +++ b/src/math/inverse_fast_fourier_transform.cc @@ -8,7 +8,7 @@ // Interdisciplinary Graduate School of // // Science and Engineering // // // -// 1996-2019 Nagoya Institute of Technology // +// 1996-2020 Nagoya Institute of Technology // // Department of Computer Science // // // // All rights reserved. // @@ -44,12 +44,14 @@ #include "SPTK/math/inverse_fast_fourier_transform.h" -#include // std::transform -#include // std::size_t -#include // std::bind1st, std::multiplies +#include // std::transform namespace sptk { +InverseFastFourierTransform::InverseFastFourierTransform(int fft_length) + : InverseFastFourierTransform(fft_length - 1, fft_length) { +} + InverseFastFourierTransform::InverseFastFourierTransform(int num_order, int fft_length) : fast_fourier_transform_(num_order, fft_length) { @@ -57,36 +59,30 @@ InverseFastFourierTransform::InverseFastFourierTransform(int num_order, bool InverseFastFourierTransform::Run( const std::vector& real_part_input, - const std::vector& imaginary_part_input, + const std::vector& imag_part_input, std::vector* real_part_output, - std::vector* imaginary_part_output) const { - // check inputs - if (!fast_fourier_transform_.IsValid() || - real_part_input.size() != - static_cast(fast_fourier_transform_.GetNumOrder() + 1) || - imaginary_part_input.size() != - static_cast(fast_fourier_transform_.GetNumOrder() + 1) || - NULL == real_part_output || NULL == imaginary_part_output) { - return false; - } - - if (!fast_fourier_transform_.Run(imaginary_part_input, real_part_input, - imaginary_part_output, real_part_output)) { + std::vector* imag_part_output) const { + if (!fast_fourier_transform_.Run(imag_part_input, real_part_input, + imag_part_output, real_part_output)) { return false; } const int fft_length(fast_fourier_transform_.GetFftLength()); - const double inverse_fft_length(1.0 / fft_length); + const double z(1.0 / fft_length); std::transform(real_part_output->begin(), real_part_output->begin() + fft_length, - real_part_output->begin(), - std::bind1st(std::multiplies(), inverse_fft_length)); - std::transform(imaginary_part_output->begin(), - imaginary_part_output->begin() + fft_length, - imaginary_part_output->begin(), - std::bind1st(std::multiplies(), inverse_fft_length)); + real_part_output->begin(), [z](double x) { return x * z; }); + std::transform(imag_part_output->begin(), + imag_part_output->begin() + fft_length, + imag_part_output->begin(), [z](double x) { return x * z; }); return true; } +bool InverseFastFourierTransform::Run(std::vector* real_part, + std::vector* imag_part) const { + if (NULL == real_part || NULL == imag_part) return false; + return Run(*real_part, *imag_part, real_part, imag_part); +} + } // namespace sptk diff --git a/src/math/real_valued_fast_fourier_transform.cc b/src/math/real_valued_fast_fourier_transform.cc index 7079a10f..e26cb00b 100644 --- a/src/math/real_valued_fast_fourier_transform.cc +++ b/src/math/real_valued_fast_fourier_transform.cc @@ -50,12 +50,16 @@ namespace sptk { +RealValuedFastFourierTransform::RealValuedFastFourierTransform(int fft_length) + : RealValuedFastFourierTransform(fft_length - 1, fft_length) { +} + RealValuedFastFourierTransform::RealValuedFastFourierTransform(int num_order, int fft_length) : num_order_(num_order), fft_length_(fft_length), half_fft_length_(fft_length_ / 2), - fast_fourier_transform_(half_fft_length_ - 1, half_fft_length_), + fast_fourier_transform_(half_fft_length_), is_valid_(true) { if (num_order_ < 0 || fft_length_ <= num_order_ || !IsPowerOfTwo(fft_length_) || !fast_fourier_transform_.IsValid()) { diff --git a/src/math/real_valued_inverse_fast_fourier_transform.cc b/src/math/real_valued_inverse_fast_fourier_transform.cc index 19196fc0..4722ea64 100644 --- a/src/math/real_valued_inverse_fast_fourier_transform.cc +++ b/src/math/real_valued_inverse_fast_fourier_transform.cc @@ -44,12 +44,15 @@ #include "SPTK/math/real_valued_inverse_fast_fourier_transform.h" -#include // std::transform -#include // std::size_t -#include // std::bind1st, std::multiplies +#include // std::transform namespace sptk { +RealValuedInverseFastFourierTransform::RealValuedInverseFastFourierTransform( + int fft_length) + : RealValuedInverseFastFourierTransform(fft_length - 1, fft_length) { +} + RealValuedInverseFastFourierTransform::RealValuedInverseFastFourierTransform( int num_order, int fft_length) : fast_fourier_transform_(num_order, fft_length) { @@ -85,6 +88,7 @@ bool RealValuedInverseFastFourierTransform::Run( bool RealValuedInverseFastFourierTransform::Run( std::vector* real_part, std::vector* imag_part, RealValuedInverseFastFourierTransform::Buffer* buffer) const { + if (NULL == real_part) return false; return Run(*real_part, real_part, imag_part, buffer); } diff --git a/src/math/two_dimensional_fast_fourier_transform.cc b/src/math/two_dimensional_fast_fourier_transform.cc index 3e98a6db..881c2d7e 100644 --- a/src/math/two_dimensional_fast_fourier_transform.cc +++ b/src/math/two_dimensional_fast_fourier_transform.cc @@ -54,7 +54,7 @@ TwoDimensionalFastFourierTransform::TwoDimensionalFastFourierTransform( : num_row_(num_row), num_column_(num_column), fft_length_(fft_length), - fast_fourier_transform_(fft_length_ - 1, fft_length_), + fast_fourier_transform_(fft_length_), is_valid_(true) { if (num_row_ <= 0 || fft_length_ < num_row_ || num_column_ <= 0 || fft_length < num_column_ || !fast_fourier_transform_.IsValid()) { diff --git a/src/math/two_dimensional_fast_fourier_transform_for_real_sequence.cc b/src/math/two_dimensional_fast_fourier_transform_for_real_sequence.cc index 2fa9f49d..8008bade 100644 --- a/src/math/two_dimensional_fast_fourier_transform_for_real_sequence.cc +++ b/src/math/two_dimensional_fast_fourier_transform_for_real_sequence.cc @@ -56,8 +56,8 @@ TwoDimensionalFastFourierTransformForRealSequence:: : num_row_(num_row), num_column_(num_column), fft_length_(fft_length), - fast_fourier_transform_(fft_length_ - 1, fft_length_), - fast_fourier_transform_for_real_sequence_(fft_length_ - 1, fft_length_), + fast_fourier_transform_(fft_length_), + fast_fourier_transform_for_real_sequence_(fft_length_), is_valid_(true) { if (num_row_ <= 0 || fft_length_ < num_row_ || num_column_ <= 0 || fft_length < num_column_ || !fast_fourier_transform_.IsValid() || diff --git a/src/math/two_dimensional_inverse_fast_fourier_transform.cc b/src/math/two_dimensional_inverse_fast_fourier_transform.cc index 5cd37ae1..0c52fa7e 100644 --- a/src/math/two_dimensional_inverse_fast_fourier_transform.cc +++ b/src/math/two_dimensional_inverse_fast_fourier_transform.cc @@ -55,7 +55,7 @@ TwoDimensionalInverseFastFourierTransform:: : num_row_(num_row), num_column_(num_column), fft_length_(fft_length), - inverse_fast_fourier_transform_(fft_length_ - 1, fft_length_), + inverse_fast_fourier_transform_(fft_length_), is_valid_(true) { if (num_row_ <= 0 || fft_length_ < num_row_ || num_column_ <= 0 || fft_length < num_column_ || !inverse_fast_fourier_transform_.IsValid()) { diff --git a/src/utils/mlsa_digital_filter_stability_check.cc b/src/utils/mlsa_digital_filter_stability_check.cc index 3604aa66..f8c2444a 100644 --- a/src/utils/mlsa_digital_filter_stability_check.cc +++ b/src/utils/mlsa_digital_filter_stability_check.cc @@ -59,11 +59,10 @@ MlsaDigitalFilterStabilityCheck::MlsaDigitalFilterStabilityCheck( threshold_(threshold), fast_mode_(fast_mode), modification_type_(modification_type), - fourier_transform_(fast_mode ? NULL : new RealValuedFastFourierTransform( - fft_length - 1, fft_length)), - inverse_fourier_transform_(fast_mode ? NULL - : new InverseFastFourierTransform( - fft_length - 1, fft_length)), + fourier_transform_( + fast_mode ? NULL : new RealValuedFastFourierTransform(fft_length)), + inverse_fourier_transform_( + fast_mode ? NULL : new InverseFastFourierTransform(fft_length)), is_valid_(true) { if (num_order_ < 0 || !sptk::IsValidAlpha(alpha) || threshold_ <= 0.0) { is_valid_ = false; diff --git a/test/test_ifft.bats b/test/test_ifft.bats new file mode 100644 index 00000000..91863df6 --- /dev/null +++ b/test/test_ifft.bats @@ -0,0 +1,78 @@ +#!/usr/bin/env bats +# ----------------------------------------------------------------- # +# The Speech Signal Processing Toolkit (SPTK) # +# developed by SPTK Working Group # +# http://sp-tk.sourceforge.net/ # +# ----------------------------------------------------------------- # +# # +# Copyright (c) 1984-2007 Tokyo Institute of Technology # +# Interdisciplinary Graduate School of # +# Science and Engineering # +# # +# 1996-2020 Nagoya Institute of Technology # +# Department of Computer Science # +# # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or # +# without modification, are permitted provided that the following # +# conditions are met: # +# # +# - Redistributions of source code must retain the above copyright # +# notice, this list of conditions and the following disclaimer. # +# - Redistributions in binary form must reproduce the above # +# copyright notice, this list of conditions and the following # +# disclaimer in the documentation and/or other materials provided # +# with the distribution. # +# - Neither the name of the SPTK working group nor the names of its # +# contributors may be used to endorse or promote products derived # +# from this software without specific prior written permission. # +# # +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS # +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # +# POSSIBILITY OF SUCH DAMAGE. # +# ----------------------------------------------------------------- # + +sptk3=tools/sptk/bin +sptk4=bin + +setup() { + mkdir -p tmp +} + +teardown() { + rm -rf tmp +} + +@test "ifft: compatibility" { + ary=("" "-R" "-I") + for o in `seq 0 2`; do + $sptk3/nrand -l 16 | $sptk3/ifft -l 8 ${ary[$o]} > tmp/1 + $sptk3/nrand -l 16 | $sptk4/ifft -l 8 -o $o > tmp/2 + run $sptk4/aeq tmp/1 tmp/2 + [ "$status" -eq 0 ] + done +} + +@test "ifft: reversiblity" { + $sptk3/nrand -l 16 > tmp/1 + $sptk4/ifft -l 8 tmp/1 | $sptk4/fft -l 8 > tmp/2 + run $sptk4/aeq tmp/1 tmp/2 + [ "$status" -eq 0 ] +} + +@test "ifft: valgrind" { + $sptk3/nrand -l 16 > tmp/1 + run valgrind $sptk4/ifft -l 8 tmp/1 > /dev/null + [ $(echo "${lines[-1]}" | sed -r 's/.*SUMMARY: ([0-9]*) .*/\1/') -eq 0 ] +}