diff --git a/mindspore/ccsrc/minddata/dataset/api/audio.cc b/mindspore/ccsrc/minddata/dataset/api/audio.cc index 312f1bb9af..562b674f11 100755 --- a/mindspore/ccsrc/minddata/dataset/api/audio.cc +++ b/mindspore/ccsrc/minddata/dataset/api/audio.cc @@ -25,6 +25,7 @@ #include "minddata/dataset/audio/ir/kernels/bass_biquad_ir.h" #include "minddata/dataset/audio/ir/kernels/complex_norm_ir.h" #include "minddata/dataset/audio/ir/kernels/contrast_ir.h" +#include "minddata/dataset/audio/ir/kernels/deemph_biquad_ir.h" #include "minddata/dataset/audio/ir/kernels/frequency_masking_ir.h" #include "minddata/dataset/audio/ir/kernels/highpass_biquad_ir.h" #include "minddata/dataset/audio/ir/kernels/lowpass_biquad_ir.h" @@ -162,6 +163,18 @@ std::shared_ptr Contrast::Parse() { return std::make_shared(data_->enhancement_amount_); } +// DeemphBiquad Transform Operation. +struct DeemphBiquad::Data { + explicit Data(int32_t sample_rate) : sample_rate_(sample_rate) {} + int32_t sample_rate_; +}; + +DeemphBiquad::DeemphBiquad(int32_t sample_rate) : data_(std::make_shared(sample_rate)) {} + +std::shared_ptr DeemphBiquad::Parse() { + return std::make_shared(data_->sample_rate_); +} + // FrequencyMasking Transform Operation. struct FrequencyMasking::Data { Data(bool iid_masks, int32_t frequency_mask_param, int32_t mask_start, float mask_value) diff --git a/mindspore/ccsrc/minddata/dataset/api/python/bindings/dataset/audio/kernels/ir/bindings.cc b/mindspore/ccsrc/minddata/dataset/api/python/bindings/dataset/audio/kernels/ir/bindings.cc index e1093eb9c6..a576d2be23 100644 --- a/mindspore/ccsrc/minddata/dataset/api/python/bindings/dataset/audio/kernels/ir/bindings.cc +++ b/mindspore/ccsrc/minddata/dataset/api/python/bindings/dataset/audio/kernels/ir/bindings.cc @@ -29,6 +29,7 @@ #include "minddata/dataset/audio/ir/kernels/bass_biquad_ir.h" #include "minddata/dataset/audio/ir/kernels/complex_norm_ir.h" #include "minddata/dataset/audio/ir/kernels/contrast_ir.h" +#include "minddata/dataset/audio/ir/kernels/deemph_biquad_ir.h" #include "minddata/dataset/audio/ir/kernels/frequency_masking_ir.h" #include "minddata/dataset/audio/ir/kernels/highpass_biquad_ir.h" #include "minddata/dataset/audio/ir/kernels/lowpass_biquad_ir.h" @@ -144,6 +145,17 @@ PYBIND_REGISTER(ContrastOperation, 1, ([](const py::module *m) { })); })); +PYBIND_REGISTER( + DeemphBiquadOperation, 1, ([](const py::module *m) { + (void)py::class_>( + *m, "DeemphBiquadOperation") + .def(py::init([](int32_t sample_rate) { + auto deemph_biquad = std::make_shared(sample_rate); + THROW_IF_ERROR(deemph_biquad->ValidateParams()); + return deemph_biquad; + })); + })); + PYBIND_REGISTER( FrequencyMaskingOperation, 1, ([](const py::module *m) { (void) diff --git a/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/CMakeLists.txt b/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/CMakeLists.txt index 00a709e545..83264e7ca1 100755 --- a/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/CMakeLists.txt +++ b/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(audio-ir-kernels OBJECT bass_biquad_ir.cc complex_norm_ir.cc contrast_ir.cc + deemph_biquad_ir.cc frequency_masking_ir.cc highpass_biquad_ir.cc lowpass_biquad_ir.cc diff --git a/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/deemph_biquad_ir.cc b/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/deemph_biquad_ir.cc new file mode 100644 index 0000000000..dee1a3585f --- /dev/null +++ b/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/deemph_biquad_ir.cc @@ -0,0 +1,51 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * 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 "minddata/dataset/audio/ir/kernels/deemph_biquad_ir.h" + +#include "minddata/dataset/audio/ir/validators.h" +#include "minddata/dataset/audio/kernels/deemph_biquad_op.h" + +namespace mindspore { +namespace dataset { +namespace audio { +// DeemphBiquadOperation +DeemphBiquadOperation::DeemphBiquadOperation(int32_t sample_rate) : sample_rate_(sample_rate) {} + +Status DeemphBiquadOperation::ValidateParams() { + if ((sample_rate_ != 44100 && sample_rate_ != 48000)) { + std::string err_msg = + "DeemphBiquad: sample_rate should be 44100 (hz) or 48000 (hz), but got: " + std::to_string(sample_rate_); + MS_LOG(ERROR) << err_msg; + return Status(StatusCode::kMDSyntaxError, __LINE__, __FILE__, err_msg); + } + return Status::OK(); +} + +std::shared_ptr DeemphBiquadOperation::Build() { + std::shared_ptr tensor_op = std::make_shared(sample_rate_); + return tensor_op; +} + +Status DeemphBiquadOperation::to_json(nlohmann::json *out_json) { + nlohmann::json args; + args["sample_rate"] = sample_rate_; + *out_json = args; + return Status::OK(); +} +} // namespace audio +} // namespace dataset +} // namespace mindspore diff --git a/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/deemph_biquad_ir.h b/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/deemph_biquad_ir.h new file mode 100644 index 0000000000..ffbbb4c27b --- /dev/null +++ b/mindspore/ccsrc/minddata/dataset/audio/ir/kernels/deemph_biquad_ir.h @@ -0,0 +1,57 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * 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 MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_DEEMPH_BIQUAD_IR_H_ +#define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_DEEMPH_BIQUAD_IR_H_ + +#include +#include +#include + +#include "include/api/status.h" +#include "minddata/dataset/include/dataset/constants.h" +#include "minddata/dataset/include/dataset/transforms.h" +#include "minddata/dataset/kernels/ir/tensor_operation.h" + +namespace mindspore { +namespace dataset { + +namespace audio { + +constexpr char kDeemphBiquadOperation[] = "DeemphBiquad"; + +class DeemphBiquadOperation : public TensorOperation { + public: + explicit DeemphBiquadOperation(int32_t sample_rate); + + ~DeemphBiquadOperation() = default; + + std::shared_ptr Build() override; + + Status ValidateParams() override; + + std::string Name() const override { return kDeemphBiquadOperation; } + + Status to_json(nlohmann::json *out_json) override; + + private: + int32_t sample_rate_; +}; +} // namespace audio + +} // namespace dataset +} // namespace mindspore +#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_DEEMPH_BIQUAD_IR_H_ diff --git a/mindspore/ccsrc/minddata/dataset/audio/kernels/CMakeLists.txt b/mindspore/ccsrc/minddata/dataset/audio/kernels/CMakeLists.txt index 7a7078d625..06785b3ffb 100644 --- a/mindspore/ccsrc/minddata/dataset/audio/kernels/CMakeLists.txt +++ b/mindspore/ccsrc/minddata/dataset/audio/kernels/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(audio-kernels OBJECT bass_biquad_op.cc complex_norm_op.cc contrast_op.cc + deemph_biquad_op.cc frequency_masking_op.cc highpass_biquad_op.cc lowpass_biquad_op.cc diff --git a/mindspore/ccsrc/minddata/dataset/audio/kernels/deemph_biquad_op.cc b/mindspore/ccsrc/minddata/dataset/audio/kernels/deemph_biquad_op.cc new file mode 100644 index 0000000000..4e64db7bfa --- /dev/null +++ b/mindspore/ccsrc/minddata/dataset/audio/kernels/deemph_biquad_op.cc @@ -0,0 +1,72 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * 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 "minddata/dataset/audio/kernels/deemph_biquad_op.h" + +#include "minddata/dataset/audio/kernels/audio_utils.h" +#include "minddata/dataset/util/status.h" + +namespace mindspore { +namespace dataset { +Status DeemphBiquadOp::Compute(const std::shared_ptr &input, std::shared_ptr *output) { + IO_CHECK(input, output); + TensorShape input_shape = input->shape(); + CHECK_FAIL_RETURN_UNEXPECTED(input_shape.Size() > 0, "DeemphBiquad: input tensor is not in shape of <..., time>."); + CHECK_FAIL_RETURN_UNEXPECTED(input->type() == DataType(DataType::DE_FLOAT32) || + input->type() == DataType(DataType::DE_FLOAT16) || + input->type() == DataType(DataType::DE_FLOAT64), + "DeemphBiquad: input tensor type should be float, but got: " + input->type().ToString()); + int32_t central_freq = 0; + double width_slope = 0.0; + double gain = 0.0; + // central_freq, width_slope and gain value reference sox values + if (sample_rate_ == 44100) { + central_freq = 5283; + width_slope = 0.4845; + gain = -9.477; + } else if (sample_rate_ == 48000) { + central_freq = 5356; + width_slope = 0.479; + gain = -9.62; + } + + double w0 = 2 * PI * central_freq / sample_rate_; + double A = exp(gain / 40 * log(10)); + double alpha = sin(w0) / 2 * sqrt((A + 1 / A) * (1 / width_slope - 1) + 2); + + // temp1, temp2, temp3 are the intermediate variable used to solve for a and b. + double temp1 = 2 * sqrt(A) * alpha; + double temp2 = (A - 1) * cos(w0); + double temp3 = (A + 1) * cos(w0); + + double b0 = A * ((A + 1) + temp2 + temp1); + double b1 = -2 * A * ((A - 1) + temp3); + double b2 = A * ((A + 1) + temp2 - temp1); + double a0 = (A + 1) - temp2 + temp1; + double a1 = 2 * ((A - 1) - temp3); + double a2 = (A + 1) - temp2 - temp1; + if (input->type() == DataType(DataType::DE_FLOAT32)) { + return Biquad(input, output, static_cast(b0), static_cast(b1), static_cast(b2), + static_cast(a0), static_cast(a1), static_cast(a2)); + } else if (input->type() == DataType(DataType::DE_FLOAT64)) { + return Biquad(input, output, static_cast(b0), static_cast(b1), static_cast(b2), + static_cast(a0), static_cast(a1), static_cast(a2)); + } else { + return Biquad(input, output, static_cast(b0), static_cast(b1), static_cast(b2), + static_cast(a0), static_cast(a1), static_cast(a2)); + } +} +} // namespace dataset +} // namespace mindspore diff --git a/mindspore/ccsrc/minddata/dataset/audio/kernels/deemph_biquad_op.h b/mindspore/ccsrc/minddata/dataset/audio/kernels/deemph_biquad_op.h new file mode 100644 index 0000000000..1e830c02f2 --- /dev/null +++ b/mindspore/ccsrc/minddata/dataset/audio/kernels/deemph_biquad_op.h @@ -0,0 +1,46 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * 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 MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_DEEMPH_BIQUAD_OP_H_ +#define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_DEEMPH_BIQUAD_OP_H_ + +#include +#include +#include + +#include "minddata/dataset/core/tensor.h" +#include "minddata/dataset/kernels/tensor_op.h" +#include "minddata/dataset/util/status.h" + +namespace mindspore { +namespace dataset { +class DeemphBiquadOp : public TensorOp { + public: + explicit DeemphBiquadOp(int32_t sample_rate) : sample_rate_(sample_rate) {} + + ~DeemphBiquadOp() override = default; + + void Print(std::ostream &out) const override { out << Name() << ": sample_rate: " << sample_rate_ << std::endl; } + + Status Compute(const std::shared_ptr &input, std::shared_ptr *output) override; + + std::string Name() const override { return kDeemphBiquadOp; } + + private: + int32_t sample_rate_; +}; +} // namespace dataset +} // namespace mindspore +#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_DEEMPH_BIQUAD_OP_H_ diff --git a/mindspore/ccsrc/minddata/dataset/include/dataset/audio.h b/mindspore/ccsrc/minddata/dataset/include/dataset/audio.h index 72d42e997e..53decaa973 100755 --- a/mindspore/ccsrc/minddata/dataset/include/dataset/audio.h +++ b/mindspore/ccsrc/minddata/dataset/include/dataset/audio.h @@ -230,6 +230,25 @@ class Contrast final : public TensorTransform { std::shared_ptr data_; }; +/// \brief Design two-pole deemph filter. Similar to SoX implementation. +class DeemphBiquad final : public TensorTransform { + public: + /// \param[in] sample_rate Sampling rate of the waveform, the value can only be 44100 (Hz) or 48000(hz). + explicit DeemphBiquad(int32_t sample_rate); + + /// \brief Destructor. + ~DeemphBiquad() = default; + + protected: + /// \brief Function to convert TensorTransform object into a TensorOperation object. + /// \return Shared pointer to TensorOperation object. + std::shared_ptr Parse() override; + + private: + struct Data; + std::shared_ptr data_; +}; + /// \brief FrequencyMasking TensorTransform. /// \notes Apply masking to a spectrogram in the frequency domain. class FrequencyMasking final : public TensorTransform { diff --git a/mindspore/ccsrc/minddata/dataset/kernels/tensor_op.h b/mindspore/ccsrc/minddata/dataset/kernels/tensor_op.h index 629f6fa51c..58157c7721 100644 --- a/mindspore/ccsrc/minddata/dataset/kernels/tensor_op.h +++ b/mindspore/ccsrc/minddata/dataset/kernels/tensor_op.h @@ -148,6 +148,7 @@ constexpr char kBandrejectBiquadOp[] = "BandrejectBiquadOp"; constexpr char kBassBiquadOp[] = "BassBiquadOp"; constexpr char kComplexNormOp[] = "ComplexNormOp"; constexpr char kContrastOp[] = "ContrastOp"; +constexpr char kDeemphBiquadOp[] = "DeemphBiquadOp"; constexpr char kFrequencyMaskingOp[] = "FrequencyMaskingOp"; constexpr char kHighpassBiquadOp[] = "HighpassBiquadOp"; constexpr char kLowpassBiquadOp[] = "LowpassBiquadOp"; diff --git a/mindspore/dataset/audio/transforms.py b/mindspore/dataset/audio/transforms.py index e220f17352..2ba419d38f 100755 --- a/mindspore/dataset/audio/transforms.py +++ b/mindspore/dataset/audio/transforms.py @@ -25,7 +25,7 @@ import mindspore._c_dataengine as cde from ..transforms.c_transforms import TensorOperation from .utils import ScaleType from .validators import check_allpass_biquad, check_amplitude_to_db, check_band_biquad, check_bandpass_biquad, \ - check_bandreject_biquad, check_bass_biquad, check_complex_norm, check_contrast, \ + check_bandreject_biquad, check_bass_biquad, check_complex_norm, check_contrast, check_deemph_biquad, \ check_highpass_biquad, check_lowpass_biquad, check_masking, check_time_stretch @@ -294,6 +294,30 @@ class Contrast(AudioTensorOperation): return cde.ContrastOperation(self.enhancement_amount) +class DeemphBiquad(AudioTensorOperation): + """ + Design two-pole deemph filter for audio waveform of dimension of (..., time). + + Args: + Sample_rate (int): sampling rate of the waveform, e.g. 44100 (Hz), + the value must be 44100 or 48000. + + Examples: + >>> import numpy as np + >>> + >>> waveform = np.array([[2.716064453125e-03, 6.34765625e-03], [9.246826171875e-03, 1.0894775390625e-02]]) + >>> numpy_slices_dataset = ds.NumpySlicesDataset(data=waveform, column_names=["audio"]) + >>> transforms = [audio.DeemphBiquad(44100)] + >>> numpy_slices_dataset = numpy_slices_dataset.map(operations=transforms, input_columns=["audio"]) + """ + @check_deemph_biquad + def __init__(self, sample_rate): + self.sample_rate = sample_rate + + def parse(self): + return cde.DeemphBiquadOperation(self.sample_rate) + + class FrequencyMasking(AudioTensorOperation): """ Apply masking to a spectrogram in the frequency domain. diff --git a/mindspore/dataset/audio/validators.py b/mindspore/dataset/audio/validators.py index 3902c27eae..b65969558c 100755 --- a/mindspore/dataset/audio/validators.py +++ b/mindspore/dataset/audio/validators.py @@ -201,6 +201,20 @@ def check_contrast(method): return new_method +def check_deemph_biquad(method): + """Wrapper method to check the parameters of CutMixBatch.""" + + @wraps(method) + def new_method(self, *args, **kwargs): + [sample_rate], _ = parse_user_args(method, *args, **kwargs) + type_check(sample_rate, (int,), "sample_rate") + if sample_rate not in (44100, 48000): + raise ValueError("Input sample_rate should be 44100 or 48000, but got {0}.".format(sample_rate)) + return method(self, *args, **kwargs) + + return new_method + + def check_lowpass_biquad(method): """Wrapper method to check the parameters of LowpassBiquad.""" diff --git a/tests/ut/cpp/dataset/c_api_audio_a_to_q_test.cc b/tests/ut/cpp/dataset/c_api_audio_a_to_q_test.cc index d6a3f89f3c..6a06051e48 100644 --- a/tests/ut/cpp/dataset/c_api_audio_a_to_q_test.cc +++ b/tests/ut/cpp/dataset/c_api_audio_a_to_q_test.cc @@ -729,6 +729,64 @@ TEST_F(MindDataTestPipeline, TestContrastParamCheck) { EXPECT_EQ(iter02, nullptr); } +TEST_F(MindDataTestPipeline, TestDeemphBiquadPipeline) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestDeemphBiquadPipeline."; + // Original waveform + std::shared_ptr schema = Schema(); + ASSERT_OK(schema->add_column("inputData", mindspore::DataType::kNumberTypeFloat32, {2, 200})); + std::shared_ptr ds = RandomData(50, schema); + EXPECT_NE(ds, nullptr); + + ds = ds->SetNumWorkers(4); + EXPECT_NE(ds, nullptr); + + auto DeemphBiquadOp = audio::DeemphBiquad(44100); + + ds = ds->Map({DeemphBiquadOp}); + EXPECT_NE(ds, nullptr); + + // Filtered waveform by deemphbiquad + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(ds, nullptr); + + std::unordered_map row; + ASSERT_OK(iter->GetNextRow(&row)); + + std::vector expected = {2, 200}; + + int i = 0; + while (row.size() != 0) { + auto col = row["inputData"]; + ASSERT_EQ(col.Shape(), expected); + ASSERT_EQ(col.Shape().size(), 2); + ASSERT_EQ(col.DataType(), mindspore::DataType::kNumberTypeFloat32); + ASSERT_OK(iter->GetNextRow(&row)); + i++; + } + EXPECT_EQ(i, 50); + + iter->Stop(); +} + +TEST_F(MindDataTestPipeline, TestDeemphBiquadWrongArgs) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestDeemphBiquadWrongArgs."; + std::shared_ptr schema = Schema(); + // Original waveform + ASSERT_OK(schema->add_column("inputData", mindspore::DataType::kNumberTypeFloat32, {2, 2})); + std::shared_ptr ds = RandomData(50, schema); + std::shared_ptr ds01; + EXPECT_NE(ds, nullptr); + + // Check sample_rate + MS_LOG(INFO) << "Sample_rate_ is zero."; + auto deemph_biquad_op_01 = audio::DeemphBiquad(0); + ds01 = ds->Map({deemph_biquad_op_01}); + EXPECT_NE(ds01, nullptr); + + std::shared_ptr iter01 = ds01->CreateIterator(); + EXPECT_EQ(iter01, nullptr); +} + TEST_F(MindDataTestPipeline, TestHighpassBiquadSuccess) { MS_LOG(INFO) << "Doing MindDataTestPipeline-TestHighpassBiquadSuccess."; diff --git a/tests/ut/cpp/dataset/execute_test.cc b/tests/ut/cpp/dataset/execute_test.cc index ed6964f990..2634c43c25 100644 --- a/tests/ut/cpp/dataset/execute_test.cc +++ b/tests/ut/cpp/dataset/execute_test.cc @@ -734,6 +734,39 @@ TEST_F(MindDataTestExecute, TestContrastWithWrongArg) { EXPECT_FALSE(s01.IsOk()); } +TEST_F(MindDataTestExecute, TestDeemphBiquadWithEager) { + MS_LOG(INFO) << "Doing MindDataTestExecute-TestDeemphBiquadWithEager"; + // Original waveform + std::vector labels = { + 2.716064453125000000e-03, 6.347656250000000000e-03, 9.246826171875000000e-03, 1.089477539062500000e-02, + 1.138305664062500000e-02, 1.156616210937500000e-02, 1.394653320312500000e-02, 1.550292968750000000e-02, + 1.614379882812500000e-02, 1.840209960937500000e-02, 1.718139648437500000e-02, 1.599121093750000000e-02, + 1.647949218750000000e-02, 1.510620117187500000e-02, 1.385498046875000000e-02, 1.345825195312500000e-02, + 1.419067382812500000e-02, 1.284790039062500000e-02, 1.052856445312500000e-02, 9.368896484375000000e-03}; + std::shared_ptr input; + ASSERT_OK(Tensor::CreateFromVector(labels, TensorShape({2, 10}), &input)); + auto input_02 = mindspore::MSTensor(std::make_shared(input)); + std::shared_ptr deemph_biquad_01 = std::make_shared(44100); + mindspore::dataset::Execute Transform01({deemph_biquad_01}); + // Filtered waveform by deemphbiquad + Status s01 = Transform01(input_02, &input_02); + EXPECT_TRUE(s01.IsOk()); +} + +TEST_F(MindDataTestExecute, TestDeemphBiquadWithWrongArg) { + MS_LOG(INFO) << "Doing MindDataTestExecute-TestDeemphBiquadWithWrongArg."; + std::vector labels = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6}; + std::shared_ptr input; + ASSERT_OK(Tensor::CreateFromVector(labels, TensorShape({1, 6}), &input)); + auto input_02 = mindspore::MSTensor(std::make_shared(input)); + // Check sample_rate + MS_LOG(INFO) << "sample_rate is zero."; + std::shared_ptr deemph_biquad_op = std::make_shared(0); + mindspore::dataset::Execute Transform01({deemph_biquad_op}); + Status s01 = Transform01(input_02, &input_02); + EXPECT_FALSE(s01.IsOk()); +} + TEST_F(MindDataTestExecute, TestHighpassBiquadEager) { MS_LOG(INFO) << "Doing MindDataTestExecute-TestHighpassBiquadEager."; int sample_rate = 44100; diff --git a/tests/ut/python/dataset/test_deemph_biquad.py b/tests/ut/python/dataset/test_deemph_biquad.py new file mode 100644 index 0000000000..f3826224f9 --- /dev/null +++ b/tests/ut/python/dataset/test_deemph_biquad.py @@ -0,0 +1,85 @@ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================== +import numpy as np +import pytest + +import mindspore.dataset as ds +import mindspore.dataset.audio.transforms as audio +from mindspore import log as logger + + +def count_unequal_element(data_expected, data_me, rtol, atol): + assert data_expected.shape == data_me.shape + total_count = len(data_expected.flatten()) + error = np.abs(data_expected - data_me) + greater = np.greater(error, atol + np.abs(data_expected) * rtol) + loss_count = np.count_nonzero(greater) + assert (loss_count / total_count) < rtol, \ + "\ndata_expected_std:{0}\ndata_me_error:{1}\nloss:{2}". \ + format(data_expected[greater], data_me[greater], error[greater]) + + +def test_func_deemph_biquad_eager(): + """ mindspore eager mode normal testcase:deemph_biquad op""" + # Original waveform + waveform = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype=np.float64) + # Expect waveform + expect_waveform = np.array([[0.04603508, 0.11216372, 0.19070681], + [0.18414031, 0.31054966, 0.42633607]], dtype=np.float64) + deemph_biquad_op = audio.DeemphBiquad(44100) + # Filtered waveform by deemphbiquad + output = deemph_biquad_op(waveform) + count_unequal_element(expect_waveform, output, 0.0001, 0.0001) + + +def test_func_deemph_biquad_pipeline(): + """ mindspore pipeline mode normal testcase:deemph_biquad op""" + # Original waveform + waveform = np.array([[0.2, 0.2, 0.3], [0.4, 0.5, 0.7]], dtype=np.float64) + # Expect waveform + expect_waveform = np.array([[0.0895, 0.1279, 0.1972], + [0.1791, 0.3006, 0.4583]], dtype=np.float64) + dataset = ds.NumpySlicesDataset(waveform, ["audio"], shuffle=False) + deemph_biquad_op = audio.DeemphBiquad(48000) + # Filtered waveform by deemphbiquad + dataset = dataset.map(input_columns=["audio"], operations=deemph_biquad_op, num_parallel_workers=8) + i = 0 + for data in dataset.create_dict_iterator(output_numpy=True): + count_unequal_element(expect_waveform[i, :], data['audio'], 0.0001, 0.0001) + i += 1 + + +def test_invalid_input_all(): + waveform = np.random.rand(2, 1000) + def test_invalid_input(test_name, sample_rate, error, error_msg): + logger.info("Test DeemphBiquad with bad input: {0}".format(test_name)) + with pytest.raises(error) as error_info: + audio.DeemphBiquad(sample_rate)(waveform) + assert error_msg in str(error_info.value) + + test_invalid_input("invalid sample_rate parameter type as a float", 44100.5, TypeError, + "Argument sample_rate with value 44100.5 is not of type []," + + " but got .") + test_invalid_input("invalid sample_rate parameter type as a String", "44100", TypeError, + "Argument sample_rate with value 44100 is not of type []," + + " but got .") + test_invalid_input("invalid sample_rate parameter value", 45000, ValueError, + "Input sample_rate should be 44100 or 48000, but got 45000.") + + +if __name__ == '__main__': + test_func_deemph_biquad_eager() + test_func_deemph_biquad_pipeline() + test_invalid_input_all()