From 70c45cd160aab2547399cd763328c77e321de064 Mon Sep 17 00:00:00 2001 From: takenori-y Date: Thu, 18 Jan 2024 17:24:08 +0900 Subject: [PATCH] add alaw --- CMakeLists.txt | 4 + doc/main/alaw.rst | 11 ++ doc/main/ialaw.rst | 11 ++ doc/main/iulaw.rst | 2 +- doc/main/ulaw.rst | 2 +- include/SPTK/compression/a_law_compression.h | 96 ++++++++++ include/SPTK/compression/a_law_expansion.h | 96 ++++++++++ src/compression/a_law_compression.cc | 55 ++++++ src/compression/a_law_expansion.cc | 55 ++++++ src/compression/mu_law_compression.cc | 4 +- src/compression/mu_law_expansion.cc | 4 +- src/main/alaw.cc | 174 +++++++++++++++++++ src/main/ialaw.cc | 174 +++++++++++++++++++ src/main/iulaw.cc | 2 +- src/main/ulaw.cc | 2 +- test/test_alaw.bats | 48 +++++ test/test_ialaw.bats | 48 +++++ test/test_iulaw.bats | 7 - test/test_ulaw.bats | 7 - 19 files changed, 780 insertions(+), 22 deletions(-) create mode 100644 doc/main/alaw.rst create mode 100644 doc/main/ialaw.rst create mode 100644 include/SPTK/compression/a_law_compression.h create mode 100644 include/SPTK/compression/a_law_expansion.h create mode 100644 src/compression/a_law_compression.cc create mode 100644 src/compression/a_law_expansion.cc create mode 100644 src/main/alaw.cc create mode 100644 src/main/ialaw.cc create mode 100755 test/test_alaw.bats create mode 100755 test/test_ialaw.bats diff --git a/CMakeLists.txt b/CMakeLists.txt index b5806a83..24e400cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,8 @@ set(CC_SOURCES ${SOURCE_DIR}/check/line_spectral_pairs_stability_check.cc ${SOURCE_DIR}/check/linear_predictive_coefficients_stability_check.cc ${SOURCE_DIR}/check/mlsa_digital_filter_stability_check.cc + ${SOURCE_DIR}/compression/a_law_compression.cc + ${SOURCE_DIR}/compression/a_law_expansion.cc ${SOURCE_DIR}/compression/dynamic_range_compression.cc ${SOURCE_DIR}/compression/huffman_coding.cc ${SOURCE_DIR}/compression/huffman_decoding.cc @@ -262,6 +264,7 @@ set(MAIN_SOURCES ${SOURCE_DIR}/main/acorr.cc ${SOURCE_DIR}/main/acr2csm.cc ${SOURCE_DIR}/main/aeq.cc + ${SOURCE_DIR}/main/alaw.cc ${SOURCE_DIR}/main/amgcep.cc ${SOURCE_DIR}/main/ap.cc ${SOURCE_DIR}/main/average.cc @@ -305,6 +308,7 @@ set(MAIN_SOURCES ${SOURCE_DIR}/main/huffman.cc ${SOURCE_DIR}/main/huffman_decode.cc ${SOURCE_DIR}/main/huffman_encode.cc + ${SOURCE_DIR}/main/ialaw.cc ${SOURCE_DIR}/main/idct.cc ${SOURCE_DIR}/main/ifft.cc ${SOURCE_DIR}/main/ifft2.cc diff --git a/doc/main/alaw.rst b/doc/main/alaw.rst new file mode 100644 index 00000000..f0d2aef4 --- /dev/null +++ b/doc/main/alaw.rst @@ -0,0 +1,11 @@ +.. _alaw: + +alaw +==== + +.. doxygenfile:: alaw.cc + +.. seealso:: :ref:`ialaw` :ref:`ulaw` + +.. doxygenclass:: sptk::ALawCompression + :members: diff --git a/doc/main/ialaw.rst b/doc/main/ialaw.rst new file mode 100644 index 00000000..0cf6717e --- /dev/null +++ b/doc/main/ialaw.rst @@ -0,0 +1,11 @@ +.. _ialaw: + +ialaw +===== + +.. doxygenfile:: ialaw.cc + +.. seealso:: :ref:`alaw` :ref:`iulaw` + +.. doxygenclass:: sptk::ALawExpansion + :members: diff --git a/doc/main/iulaw.rst b/doc/main/iulaw.rst index 1fafa30e..ff2866a3 100644 --- a/doc/main/iulaw.rst +++ b/doc/main/iulaw.rst @@ -5,7 +5,7 @@ iulaw .. doxygenfile:: iulaw.cc -.. seealso:: :ref:`ulaw` +.. seealso:: :ref:`ulaw` :ref:`ialaw` .. doxygenclass:: sptk::MuLawExpansion :members: diff --git a/doc/main/ulaw.rst b/doc/main/ulaw.rst index 671a4b74..2f54eff1 100644 --- a/doc/main/ulaw.rst +++ b/doc/main/ulaw.rst @@ -5,7 +5,7 @@ ulaw .. doxygenfile:: ulaw.cc -.. seealso:: :ref:`iulaw` +.. seealso:: :ref:`iulaw` :ref:`alaw` .. doxygenclass:: sptk::MuLawCompression :members: diff --git a/include/SPTK/compression/a_law_compression.h b/include/SPTK/compression/a_law_compression.h new file mode 100644 index 00000000..ee24cec6 --- /dev/null +++ b/include/SPTK/compression/a_law_compression.h @@ -0,0 +1,96 @@ +// ------------------------------------------------------------------------ // +// Copyright 2021 SPTK Working Group // +// // +// Licensed under the Apache License, Version 2.0 (the "License"); // +// you may not use this file except in compliance with the License. // +// You may obtain a copy of the License at // +// // +// http://www.apache.org/licenses/LICENSE-2.0 // +// // +// Unless required by applicable law or agreed to in writing, software // +// distributed under the License is distributed on an "AS IS" BASIS, // +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // +// See the License for the specific language governing permissions and // +// limitations under the License. // +// ------------------------------------------------------------------------ // + +#ifndef SPTK_COMPRESSION_A_LAW_COMPRESSION_H_ +#define SPTK_COMPRESSION_A_LAW_COMPRESSION_H_ + +#include "SPTK/utils/sptk_utils.h" + +namespace sptk { + +/** + * Nonlinearly compress data based on A-law algorithm. + * + * Given the input data @f$x(n)@f$, the compression is performed as follows: + * @f[ + * y(n) = V \, \mathrm{sgn}(x(n)) \left\{ \begin{array}{ll} + * \frac{A \frac{|x(n)|}{V}}{1 + \log A}, & + * \frac{|x(n)|}{V} < \frac{1}{A} \\ + * \frac{1 + \log(A \frac{|x(n)|}{V})}{1 + \log A}, & + * \frac{|x(n)|}{V} \ge \frac{1}{A} + * \end{array} \right. + * @f] + * where @f$V@f$ is the absolute maximum value of the input data and @f$A@f$ + * is the compression factor, which is typically set to 87.6. + */ +class ALawCompression { + public: + /** + * @param[in] abs_max_value Absolute maximum value. + * @param[in] compression_factor Compression factor, @f$A@f$. + */ + ALawCompression(double abs_max_value, double compression_factor); + + virtual ~ALawCompression() { + } + + /** + * @return Absolute maximum value. + */ + double GetAbsMaxValue() const { + return abs_max_value_; + } + + /** + * @return Compression factor. + */ + double GetCompressionFactor() const { + return compression_factor_; + } + + /** + * @return True if this object is valid. + */ + bool IsValid() const { + return is_valid_; + } + + /** + * @param[in] input Input data. + * @param[out] output Output data. + * @return True on success, false on failure. + */ + bool Run(double input, double* output) const; + + /** + * @param[in,out] input_and_output Input/output data. + * @return True on success, false on failure. + */ + bool Run(double* input_and_output) const; + + private: + const double abs_max_value_; + const double compression_factor_; + const double constant_; + + bool is_valid_; + + DISALLOW_COPY_AND_ASSIGN(ALawCompression); +}; + +} // namespace sptk + +#endif // SPTK_COMPRESSION_A_LAW_COMPRESSION_H_ diff --git a/include/SPTK/compression/a_law_expansion.h b/include/SPTK/compression/a_law_expansion.h new file mode 100644 index 00000000..e43484c4 --- /dev/null +++ b/include/SPTK/compression/a_law_expansion.h @@ -0,0 +1,96 @@ +// ------------------------------------------------------------------------ // +// Copyright 2021 SPTK Working Group // +// // +// Licensed under the Apache License, Version 2.0 (the "License"); // +// you may not use this file except in compliance with the License. // +// You may obtain a copy of the License at // +// // +// http://www.apache.org/licenses/LICENSE-2.0 // +// // +// Unless required by applicable law or agreed to in writing, software // +// distributed under the License is distributed on an "AS IS" BASIS, // +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // +// See the License for the specific language governing permissions and // +// limitations under the License. // +// ------------------------------------------------------------------------ // + +#ifndef SPTK_COMPRESSION_A_LAW_EXPANSION_H_ +#define SPTK_COMPRESSION_A_LAW_EXPANSION_H_ + +#include "SPTK/utils/sptk_utils.h" + +namespace sptk { + +/** + * Nonlinearly decompress data based on A-law algorithm. + * + * Given the input data @f$y(n)@f$, the expansion is performed as follows: + * @f[ + * x(n) = V \, \mathrm{sgn}(y(n)) \left\{ \begin{array}{ll} + * \frac{\frac{|y(n)|}{V}(1 + \log A)}{A}, & + * \frac{|y(n)|}{V} < \frac{1}{1 + \log A} \\ + * \frac{\exp(-1 + \frac{|y(n)|}{V}(1 + \log A))}{A}, & + * \frac{|y(n)|}{V} \ge \frac{1}{1 + \log A} \\ + * \end{array} \right. + * @f] + * where @f$V@f$ is the absolute maximum value of the input data and @f$A@f$ + * is the compression factor, which is typically set to 87.6. + */ +class ALawExpansion { + public: + /** + * @param[in] abs_max_value Absolute maximum value. + * @param[in] compression_factor Compression factor, @f$A@f$. + */ + ALawExpansion(double abs_max_value, double compression_factor); + + virtual ~ALawExpansion() { + } + + /** + * @return Absolute maximum value. + */ + double GetAbsMaxValue() const { + return abs_max_value_; + } + + /** + * @return Compression factor. + */ + double GetCompressionFactor() const { + return compression_factor_; + } + + /** + * @return True if this object is valid. + */ + bool IsValid() const { + return is_valid_; + } + + /** + * @param[in] input Input data. + * @param[out] output Output data. + * @return True on success, false on failure. + */ + bool Run(double input, double* output) const; + + /** + * @param[in,out] input_and_output Input/output data. + * @return True on success, false on failure. + */ + bool Run(double* input_and_output) const; + + private: + const double abs_max_value_; + const double compression_factor_; + const double constant_; + + bool is_valid_; + + DISALLOW_COPY_AND_ASSIGN(ALawExpansion); +}; + +} // namespace sptk + +#endif // SPTK_COMPRESSION_A_LAW_EXPANSION_H_ diff --git a/src/compression/a_law_compression.cc b/src/compression/a_law_compression.cc new file mode 100644 index 00000000..55d93eb3 --- /dev/null +++ b/src/compression/a_law_compression.cc @@ -0,0 +1,55 @@ +// ------------------------------------------------------------------------ // +// Copyright 2021 SPTK Working Group // +// // +// Licensed under the Apache License, Version 2.0 (the "License"); // +// you may not use this file except in compliance with the License. // +// You may obtain a copy of the License at // +// // +// http://www.apache.org/licenses/LICENSE-2.0 // +// // +// Unless required by applicable law or agreed to in writing, software // +// distributed under the License is distributed on an "AS IS" BASIS, // +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // +// See the License for the specific language governing permissions and // +// limitations under the License. // +// ------------------------------------------------------------------------ // + +#include "SPTK/compression/a_law_compression.h" + +#include // std::fabs, std::log + +namespace sptk { + +ALawCompression::ALawCompression(double abs_max_value, + double compression_factor) + : abs_max_value_(abs_max_value), + compression_factor_(compression_factor), + constant_(abs_max_value_ / (1.0 + std::log(compression_factor_))), + is_valid_(true) { + if (abs_max_value_ <= 0.0 || compression_factor_ < 1.0) { + is_valid_ = false; + return; + } +} + +bool ALawCompression::Run(double input, double* output) const { + if (!is_valid_ || NULL == output) { + return false; + } + + const double x(std::fabs(input) / abs_max_value_); + double y(compression_factor_ * x); + if (1.0 / compression_factor_ <= x) { + y = 1.0 + std::log(y); + } + *output = constant_ * sptk::ExtractSign(input) * y; + + return true; +} + +bool ALawCompression::Run(double* input_and_output) const { + if (NULL == input_and_output) return false; + return Run(*input_and_output, input_and_output); +} + +} // namespace sptk diff --git a/src/compression/a_law_expansion.cc b/src/compression/a_law_expansion.cc new file mode 100644 index 00000000..4289e3ef --- /dev/null +++ b/src/compression/a_law_expansion.cc @@ -0,0 +1,55 @@ +// ------------------------------------------------------------------------ // +// Copyright 2021 SPTK Working Group // +// // +// Licensed under the Apache License, Version 2.0 (the "License"); // +// you may not use this file except in compliance with the License. // +// You may obtain a copy of the License at // +// // +// http://www.apache.org/licenses/LICENSE-2.0 // +// // +// Unless required by applicable law or agreed to in writing, software // +// distributed under the License is distributed on an "AS IS" BASIS, // +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // +// See the License for the specific language governing permissions and // +// limitations under the License. // +// ------------------------------------------------------------------------ // + +#include "SPTK/compression/a_law_expansion.h" + +#include // std::exp, std::fabs, std::pow + +namespace sptk { + +ALawExpansion::ALawExpansion(double abs_max_value, double compression_factor) + : abs_max_value_(abs_max_value), + compression_factor_(compression_factor), + constant_(abs_max_value_ / compression_factor_), + is_valid_(true) { + if (abs_max_value_ <= 0.0 || compression_factor_ < 1.0) { + is_valid_ = false; + return; + } +} + +bool ALawExpansion::Run(double input, double* output) const { + if (!is_valid_ || NULL == output) { + return false; + } + + const double x(std::fabs(input) / abs_max_value_); + const double z(1 + std::log(compression_factor_)); + double y(z * x); + if (1.0 / z <= x) { + y = std::exp(y - 1.0); + } + *output = constant_ * sptk::ExtractSign(input) * y; + + return true; +} + +bool ALawExpansion::Run(double* input_and_output) const { + if (NULL == input_and_output) return false; + return Run(*input_and_output, input_and_output); +} + +} // namespace sptk diff --git a/src/compression/mu_law_compression.cc b/src/compression/mu_law_compression.cc index 9cea0850..3454e8ec 100644 --- a/src/compression/mu_law_compression.cc +++ b/src/compression/mu_law_compression.cc @@ -24,7 +24,7 @@ MuLawCompression::MuLawCompression(double abs_max_value, double compression_factor) : abs_max_value_(abs_max_value), compression_factor_(compression_factor), - constant_(1.0 / std::log(1.0 + compression_factor_)), + constant_(abs_max_value_ / std::log(1.0 + compression_factor_)), is_valid_(true) { if (abs_max_value_ <= 0.0 || compression_factor_ <= 0.0) { is_valid_ = false; @@ -38,7 +38,7 @@ bool MuLawCompression::Run(double input, double* output) const { } const double x(std::fabs(input) / abs_max_value_); - *output = (constant_ * abs_max_value_ * sptk::ExtractSign(input) * + *output = (constant_ * sptk::ExtractSign(input) * std::log(1.0 + compression_factor_ * x)); return true; diff --git a/src/compression/mu_law_expansion.cc b/src/compression/mu_law_expansion.cc index 220d5825..cac20baf 100644 --- a/src/compression/mu_law_expansion.cc +++ b/src/compression/mu_law_expansion.cc @@ -23,7 +23,7 @@ namespace sptk { MuLawExpansion::MuLawExpansion(double abs_max_value, double compression_factor) : abs_max_value_(abs_max_value), compression_factor_(compression_factor), - constant_(1.0 / compression_factor_), + constant_(abs_max_value_ / compression_factor_), is_valid_(true) { if (abs_max_value_ <= 0.0 || compression_factor_ <= 0.0) { is_valid_ = false; @@ -37,7 +37,7 @@ bool MuLawExpansion::Run(double input, double* output) const { } const double x(std::fabs(input) / abs_max_value_); - *output = (constant_ * abs_max_value_ * sptk::ExtractSign(input) * + *output = (constant_ * sptk::ExtractSign(input) * (std::pow(1.0 + compression_factor_, x) - 1.0)); return true; diff --git a/src/main/alaw.cc b/src/main/alaw.cc new file mode 100644 index 00000000..3412f0fd --- /dev/null +++ b/src/main/alaw.cc @@ -0,0 +1,174 @@ +// ------------------------------------------------------------------------ // +// Copyright 2021 SPTK Working Group // +// // +// Licensed under the Apache License, Version 2.0 (the "License"); // +// you may not use this file except in compliance with the License. // +// You may obtain a copy of the License at // +// // +// http://www.apache.org/licenses/LICENSE-2.0 // +// // +// Unless required by applicable law or agreed to in writing, software // +// distributed under the License is distributed on an "AS IS" BASIS, // +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // +// See the License for the specific language governing permissions and // +// limitations under the License. // +// ------------------------------------------------------------------------ // + +#include // std::ifstream +#include // std::setw +#include // std::cerr, std::cin, std::cout, std::endl, etc. +#include // std::ostringstream + +#include "GETOPT/ya_getopt.h" +#include "SPTK/compression/a_law_compression.h" +#include "SPTK/utils/sptk_utils.h" + +namespace { + +const double kDefaultAbsMaxValue(32768.0); +const double kDefaultCompressionFactor(87.6); + +void PrintUsage(std::ostream* stream) { + // clang-format off + *stream << std::endl; + *stream << " alaw - A-law pulse code modulation" << std::endl; + *stream << std::endl; + *stream << " usage:" << std::endl; + *stream << " alaw [ options ] [ infile ] > stdout" << std::endl; + *stream << " options:" << std::endl; + *stream << " -v v : absolute maximum of input (double)[" << std::setw(5) << std::right << kDefaultAbsMaxValue << "][ 0.0 < v <= ]" << std::endl; // NOLINT + *stream << " -a a : compression factor (double)[" << std::setw(5) << std::right << kDefaultCompressionFactor << "][ 1.0 <= a <= ]" << std::endl; // NOLINT + *stream << " -h : print this message" << std::endl; + *stream << " infile:" << std::endl; + *stream << " input sequence (double)[stdin]" << std::endl; // NOLINT + *stream << " stdout:" << std::endl; + *stream << " compressed sequence (double)" << std::endl; + *stream << std::endl; + *stream << " SPTK: version " << sptk::kVersion << std::endl; + *stream << std::endl; + // clang-format on +} + +} // namespace + +/** + * @a alaw [ @e option ] [ @e infile ] + * + * - @b -v @e double + * - absolute maximum value of input @f$(0 < V)@f$ + * - @b -a @e double + * - compression factor @f$(1 \le A)@f$ + * - @b infile @e str + * - double-type input data sequence + * - @b stdout + * - double-type compressed data sequence + * + * In the below example, 16-bit data read from @c data.short is compressed to + * 8-bit A-law format. + * + * @code{.sh} + * x2x +sd data.short | alaw | quantize > data.alaw + * @endcode + * + * @param[in] argc Number of arguments. + * @param[in] argv Argument vector. + * @return 0 on success, 1 on failure. + */ +int main(int argc, char* argv[]) { + double abs_max_value(kDefaultAbsMaxValue); + double compression_factor(kDefaultCompressionFactor); + + for (;;) { + const int option_char(getopt_long(argc, argv, "v:a:h", NULL, NULL)); + if (-1 == option_char) break; + + switch (option_char) { + case 'v': { + if (!sptk::ConvertStringToDouble(optarg, &abs_max_value) || + abs_max_value <= 0.0) { + std::ostringstream error_message; + error_message + << "The argument for the -v option must be a positive number"; + sptk::PrintErrorMessage("alaw", error_message); + return 1; + } + break; + } + case 'a': { + if (!sptk::ConvertStringToDouble(optarg, &compression_factor) || + compression_factor < 1.0) { + std::ostringstream error_message; + error_message << "The argument for the -a option must be a number " + << "greater than or equal to one"; + sptk::PrintErrorMessage("alaw", error_message); + return 1; + } + break; + } + case 'h': { + PrintUsage(&std::cout); + return 0; + } + default: { + PrintUsage(&std::cerr); + return 1; + } + } + } + + const int num_input_files(argc - optind); + if (1 < num_input_files) { + std::ostringstream error_message; + error_message << "Too many input files"; + sptk::PrintErrorMessage("alaw", error_message); + return 1; + } + const char* input_file(0 == num_input_files ? NULL : argv[optind]); + + if (!sptk::SetBinaryMode()) { + std::ostringstream error_message; + error_message << "Cannot set translation mode"; + sptk::PrintErrorMessage("alaw", error_message); + return 1; + } + + std::ifstream ifs; + if (NULL != input_file) { + ifs.open(input_file, std::ios::in | std::ios::binary); + if (ifs.fail()) { + std::ostringstream error_message; + error_message << "Cannot open file " << input_file; + sptk::PrintErrorMessage("alaw", error_message); + return 1; + } + } + std::istream& input_stream(ifs.is_open() ? ifs : std::cin); + + sptk::ALawCompression a_law_compression(abs_max_value, compression_factor); + if (!a_law_compression.IsValid()) { + std::ostringstream error_message; + error_message << "Failed to initialize ALawCompression"; + sptk::PrintErrorMessage("alaw", error_message); + return 1; + } + + double data; + + while (sptk::ReadStream(&data, &input_stream)) { + if (!a_law_compression.Run(&data)) { + std::ostringstream error_message; + error_message << "Failed to compress"; + sptk::PrintErrorMessage("alaw", error_message); + return 1; + } + + if (!sptk::WriteStream(data, &std::cout)) { + std::ostringstream error_message; + error_message << "Failed to write compressed data"; + sptk::PrintErrorMessage("alaw", error_message); + return 1; + } + } + + return 0; +} diff --git a/src/main/ialaw.cc b/src/main/ialaw.cc new file mode 100644 index 00000000..69d55a3f --- /dev/null +++ b/src/main/ialaw.cc @@ -0,0 +1,174 @@ +// ------------------------------------------------------------------------ // +// Copyright 2021 SPTK Working Group // +// // +// Licensed under the Apache License, Version 2.0 (the "License"); // +// you may not use this file except in compliance with the License. // +// You may obtain a copy of the License at // +// // +// http://www.apache.org/licenses/LICENSE-2.0 // +// // +// Unless required by applicable law or agreed to in writing, software // +// distributed under the License is distributed on an "AS IS" BASIS, // +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // +// See the License for the specific language governing permissions and // +// limitations under the License. // +// ------------------------------------------------------------------------ // + +#include // std::ifstream +#include // std::setw +#include // std::cerr, std::cin, std::cout, std::endl, etc. +#include // std::ostringstream + +#include "GETOPT/ya_getopt.h" +#include "SPTK/compression/a_law_expansion.h" +#include "SPTK/utils/sptk_utils.h" + +namespace { + +const double kDefaultAbsMaxValue(32768.0); +const double kDefaultCompressionFactor(87.6); + +void PrintUsage(std::ostream* stream) { + // clang-format off + *stream << std::endl; + *stream << " ialaw - inverse A-law pulse code modulation" << std::endl; + *stream << std::endl; + *stream << " usage:" << std::endl; + *stream << " ialaw [ options ] [ infile ] > stdout" << std::endl; + *stream << " options:" << std::endl; + *stream << " -v v : absolute maximum of input (double)[" << std::setw(5) << std::right << kDefaultAbsMaxValue << "][ 0.0 < v <= ]" << std::endl; // NOLINT + *stream << " -a a : compression factor (double)[" << std::setw(5) << std::right << kDefaultCompressionFactor << "][ 1.0 <= a <= ]" << std::endl; // NOLINT + *stream << " -h : print this message" << std::endl; + *stream << " infile:" << std::endl; + *stream << " input sequence (double)[stdin]" << std::endl; // NOLINT + *stream << " stdout:" << std::endl; + *stream << " decompressed sequence (double)" << std::endl; + *stream << std::endl; + *stream << " SPTK: version " << sptk::kVersion << std::endl; + *stream << std::endl; + // clang-format on +} + +} // namespace + +/** + * @a ialaw [ @e option ] [ @e infile ] + * + * - @b -v @e double + * - absolute maximum value of input @f$(0 < V)@f$ + * - @b -a @e double + * - compression factor @f$(1 \le A)@f$ + * - @b infile @e str + * - double-type compressed data sequence + * - @b stdout + * - double-type output data sequence + * + * In the below example, 8-bit compressed and quantized data read from + * @c data.alaw is transformed into raw waveform. + * + * @code{.sh} + * dequantize data.alaw | ialaw > data.raw + * @endcode + * + * @param[in] argc Number of arguments. + * @param[in] argv Argument vector. + * @return 0 on success, 1 on failure. + */ +int main(int argc, char* argv[]) { + double abs_max_value(kDefaultAbsMaxValue); + double compression_factor(kDefaultCompressionFactor); + + for (;;) { + const int option_char(getopt_long(argc, argv, "v:a:h", NULL, NULL)); + if (-1 == option_char) break; + + switch (option_char) { + case 'v': { + if (!sptk::ConvertStringToDouble(optarg, &abs_max_value) || + abs_max_value <= 0.0) { + std::ostringstream error_message; + error_message + << "The argument for the -v option must be a positive number"; + sptk::PrintErrorMessage("ialaw", error_message); + return 1; + } + break; + } + case 'a': { + if (!sptk::ConvertStringToDouble(optarg, &compression_factor) || + compression_factor < 1.0) { + std::ostringstream error_message; + error_message << "The argument for the -a option must be a number " + << "greater than or equal to one"; + sptk::PrintErrorMessage("ialaw", error_message); + return 1; + } + break; + } + case 'h': { + PrintUsage(&std::cout); + return 0; + } + default: { + PrintUsage(&std::cerr); + return 1; + } + } + } + + const int num_input_files(argc - optind); + if (1 < num_input_files) { + std::ostringstream error_message; + error_message << "Too many input files"; + sptk::PrintErrorMessage("ialaw", error_message); + return 1; + } + const char* input_file(0 == num_input_files ? NULL : argv[optind]); + + if (!sptk::SetBinaryMode()) { + std::ostringstream error_message; + error_message << "Cannot set translation mode"; + sptk::PrintErrorMessage("ialaw", error_message); + return 1; + } + + std::ifstream ifs; + if (NULL != input_file) { + ifs.open(input_file, std::ios::in | std::ios::binary); + if (ifs.fail()) { + std::ostringstream error_message; + error_message << "Cannot open file " << input_file; + sptk::PrintErrorMessage("ialaw", error_message); + return 1; + } + } + std::istream& input_stream(ifs.is_open() ? ifs : std::cin); + + sptk::ALawExpansion a_law_expansion(abs_max_value, compression_factor); + if (!a_law_expansion.IsValid()) { + std::ostringstream error_message; + error_message << "Failed to initialize ALawExpansion"; + sptk::PrintErrorMessage("ialaw", error_message); + return 1; + } + + double data; + + while (sptk::ReadStream(&data, &input_stream)) { + if (!a_law_expansion.Run(&data)) { + std::ostringstream error_message; + error_message << "Failed to decompress"; + sptk::PrintErrorMessage("ialaw", error_message); + return 1; + } + + if (!sptk::WriteStream(data, &std::cout)) { + std::ostringstream error_message; + error_message << "Failed to write decompressed data"; + sptk::PrintErrorMessage("ialaw", error_message); + return 1; + } + } + + return 0; +} diff --git a/src/main/iulaw.cc b/src/main/iulaw.cc index c4fb0488..9d35d739 100644 --- a/src/main/iulaw.cc +++ b/src/main/iulaw.cc @@ -37,7 +37,7 @@ void PrintUsage(std::ostream* stream) { *stream << " iulaw [ options ] [ infile ] > stdout" << std::endl; *stream << " options:" << std::endl; *stream << " -v v : absolute maximum of input (double)[" << std::setw(5) << std::right << kDefaultAbsMaxValue << "][ 0.0 < v <= ]" << std::endl; // NOLINT - *stream << " -u u : compression factor ( int)[" << std::setw(5) << std::right << kDefaultCompressionFactor << "][ 0.0 < u <= ]" << std::endl; // NOLINT + *stream << " -u u : compression factor (double)[" << std::setw(5) << std::right << kDefaultCompressionFactor << "][ 0.0 < u <= ]" << std::endl; // NOLINT *stream << " -h : print this message" << std::endl; *stream << " infile:" << std::endl; *stream << " input sequence (double)[stdin]" << std::endl; // NOLINT diff --git a/src/main/ulaw.cc b/src/main/ulaw.cc index e76f2c88..9ceafed0 100644 --- a/src/main/ulaw.cc +++ b/src/main/ulaw.cc @@ -64,7 +64,7 @@ void PrintUsage(std::ostream* stream) { * - double-type compressed data sequence * * In the below example, 16-bit data read from @c data.short is compressed to - * 8-bit ulaw format. + * 8-bit u-law format. * * @code{.sh} * x2x +sd data.short | ulaw | quantize > data.ulaw diff --git a/test/test_alaw.bats b/test/test_alaw.bats new file mode 100755 index 00000000..ec0e6a1d --- /dev/null +++ b/test/test_alaw.bats @@ -0,0 +1,48 @@ +#!/usr/bin/env bats +# ------------------------------------------------------------------------ # +# Copyright 2021 SPTK Working Group # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ------------------------------------------------------------------------ # + +sptk3=tools/sptk/bin +sptk4=bin +tmp=test_alaw + +setup() { + mkdir -p $tmp +} + +teardown() { + rm -rf $tmp +} + +@test "alaw: identity" { + $sptk3/nrand -l 20 > $tmp/1 + $sptk4/alaw -v 4 -a 1 $tmp/1 > $tmp/2 + run $sptk4/aeq $tmp/1 $tmp/2 + [ "$status" -eq 0 ] +} + +@test "alaw: reversibility" { + $sptk3/nrand -l 20 > $tmp/1 + $sptk4/alaw $tmp/1 | $sptk4/ialaw > $tmp/2 + run $sptk4/aeq $tmp/1 $tmp/2 + [ "$status" -eq 0 ] +} + +@test "alaw: valgrind" { + $sptk3/nrand -l 20 > $tmp/1 + run valgrind $sptk4/alaw $tmp/1 + [ "$(echo "${lines[-1]}" | sed -r 's/.*SUMMARY: ([0-9]*) .*/\1/')" -eq 0 ] +} diff --git a/test/test_ialaw.bats b/test/test_ialaw.bats new file mode 100755 index 00000000..4952b12c --- /dev/null +++ b/test/test_ialaw.bats @@ -0,0 +1,48 @@ +#!/usr/bin/env bats +# ------------------------------------------------------------------------ # +# Copyright 2021 SPTK Working Group # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ------------------------------------------------------------------------ # + +sptk3=tools/sptk/bin +sptk4=bin +tmp=test_ialaw + +setup() { + mkdir -p $tmp +} + +teardown() { + rm -rf $tmp +} + +@test "ialaw: identity" { + $sptk3/nrand -l 20 > $tmp/1 + $sptk4/ialaw -v 4 -a 1 $tmp/1 > $tmp/2 + run $sptk4/aeq $tmp/1 $tmp/2 + [ "$status" -eq 0 ] +} + +@test "ialaw: reversibility" { + $sptk3/nrand -l 20 > $tmp/1 + $sptk4/ialaw $tmp/1 | $sptk4/alaw > $tmp/2 + run $sptk4/aeq $tmp/1 $tmp/2 + [ "$status" -eq 0 ] +} + +@test "ialaw: valgrind" { + $sptk3/nrand -l 20 > $tmp/1 + run valgrind $sptk4/ialaw $tmp/1 + [ "$(echo "${lines[-1]}" | sed -r 's/.*SUMMARY: ([0-9]*) .*/\1/')" -eq 0 ] +} diff --git a/test/test_iulaw.bats b/test/test_iulaw.bats index 678e189c..c867430e 100755 --- a/test/test_iulaw.bats +++ b/test/test_iulaw.bats @@ -34,13 +34,6 @@ teardown() { [ "$status" -eq 0 ] } -@test "iulaw: identity" { - $sptk3/nrand -l 20 > $tmp/1 - $sptk4/iulaw -v 4 -u 1e-6 $tmp/1 > $tmp/2 - run $sptk4/aeq $tmp/1 $tmp/2 - [ "$status" -eq 0 ] -} - @test "iulaw: reversibility" { $sptk3/nrand -l 20 > $tmp/1 $sptk4/iulaw $tmp/1 | $sptk4/ulaw > $tmp/2 diff --git a/test/test_ulaw.bats b/test/test_ulaw.bats index 166ecba1..9a8b32f9 100755 --- a/test/test_ulaw.bats +++ b/test/test_ulaw.bats @@ -34,13 +34,6 @@ teardown() { [ "$status" -eq 0 ] } -@test "ulaw: identity" { - $sptk3/nrand -l 20 > $tmp/1 - $sptk4/ulaw -v 4 -u 1e-6 $tmp/1 > $tmp/2 - run $sptk4/aeq $tmp/1 $tmp/2 - [ "$status" -eq 0 ] -} - @test "ulaw: reversibility" { $sptk3/nrand -l 20 > $tmp/1 $sptk4/ulaw $tmp/1 | $sptk4/iulaw > $tmp/2