forked from huawei/mindspore2022
!26244 [assistant][ops] Add new data PhaseVocoder
Merge pull request !26244 from TR-nbu/PhaseVocoder
This commit is contained in:
commit
2b82ba1e49
|
|
@ -45,6 +45,7 @@
|
|||
#include "minddata/dataset/audio/ir/kernels/mu_law_decoding_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/mu_law_encoding_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/overdrive_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/phase_vocoder_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/phaser_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/riaa_biquad_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/sliding_window_cmn_ir.h"
|
||||
|
|
@ -583,6 +584,26 @@ std::shared_ptr<TensorOperation> Phaser::Parse() {
|
|||
data_->decay_, data_->mod_speed_, data_->sinusoidal_);
|
||||
}
|
||||
|
||||
// PhaseVocoder Transofrm Operation.
|
||||
struct PhaseVocoder::Data {
|
||||
Data(float rate, const MSTensor &phase_advance) : rate_(rate), phase_advance_(phase_advance) {}
|
||||
float rate_;
|
||||
MSTensor phase_advance_;
|
||||
};
|
||||
|
||||
PhaseVocoder::PhaseVocoder(float rate, const MSTensor &phase_advance)
|
||||
: data_(std::make_shared<Data>(rate, phase_advance)) {}
|
||||
|
||||
std::shared_ptr<TensorOperation> PhaseVocoder::Parse() {
|
||||
std::shared_ptr<Tensor> phase_advance;
|
||||
Status rc = Tensor::CreateFromMSTensor(data_->phase_advance_, &phase_advance);
|
||||
if (rc.IsError()) {
|
||||
MS_LOG(ERROR) << "Error creating phase_vocoder constant tensor." << rc;
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<PhaseVocoderOperation>(data_->rate_, phase_advance);
|
||||
}
|
||||
|
||||
// RiaaBiquad Transform Operation.
|
||||
struct RiaaBiquad::Data {
|
||||
explicit Data(int32_t sample_rate) : sample_rate_(sample_rate) {}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "minddata/dataset/audio/ir/kernels/mu_law_decoding_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/mu_law_encoding_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/overdrive_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/phase_vocoder_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/phaser_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/riaa_biquad_ir.h"
|
||||
#include "minddata/dataset/audio/ir/kernels/sliding_window_cmn_ir.h"
|
||||
|
|
@ -432,6 +433,17 @@ PYBIND_REGISTER(PhaserOperation, 1, ([](const py::module *m) {
|
|||
}));
|
||||
}));
|
||||
|
||||
PYBIND_REGISTER(
|
||||
PhaseVocoderOperation, 1, ([](const py::module *m) {
|
||||
(void)py::class_<audio::PhaseVocoderOperation, TensorOperation, std::shared_ptr<audio::PhaseVocoderOperation>>(
|
||||
*m, "PhaseVocoderOperation")
|
||||
.def(py::init([](float rate, const std::shared_ptr<Tensor> &phase_advance) {
|
||||
auto phase_vocoder = std::make_shared<audio::PhaseVocoderOperation>(rate, phase_advance);
|
||||
THROW_IF_ERROR(phase_vocoder->ValidateParams());
|
||||
return phase_vocoder;
|
||||
}));
|
||||
}));
|
||||
|
||||
PYBIND_REGISTER(
|
||||
RiaaBiquadOperation, 1, ([](const py::module *m) {
|
||||
(void)py::class_<audio::RiaaBiquadOperation, TensorOperation, std::shared_ptr<audio::RiaaBiquadOperation>>(
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ add_library(audio-ir-kernels OBJECT
|
|||
mu_law_decoding_ir.cc
|
||||
mu_law_encoding_ir.cc
|
||||
overdrive_ir.cc
|
||||
phase_vocoder_ir.cc
|
||||
phaser_ir.cc
|
||||
riaa_biquad_ir.cc
|
||||
sliding_window_cmn_ir.cc
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* Copyright 2022 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/phase_vocoder_ir.h"
|
||||
|
||||
#include "minddata/dataset/audio/ir/validators.h"
|
||||
#include "minddata/dataset/audio/kernels/phase_vocoder_op.h"
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
namespace audio {
|
||||
PhaseVocoderOperation::PhaseVocoderOperation(float rate, const std::shared_ptr<Tensor> &phase_advance)
|
||||
: rate_(rate), phase_advance_(phase_advance) {}
|
||||
|
||||
PhaseVocoderOperation::~PhaseVocoderOperation() = default;
|
||||
|
||||
Status PhaseVocoderOperation::ValidateParams() {
|
||||
const int kPhaseAdvanceRank = 2;
|
||||
const int kLastDim = -1;
|
||||
const int kLastDimSize = 1;
|
||||
RETURN_IF_NOT_OK(ValidateFloatScalarPositive("PhaseVocoder", "rate", rate_));
|
||||
CHECK_FAIL_RETURN_SYNTAX_ERROR(
|
||||
phase_advance_->Rank() == kPhaseAdvanceRank && phase_advance_->shape()[kLastDim] == kLastDimSize,
|
||||
"PhaseVocoder: invalid parameter, 'phase_advance' should be in shape of <freq, 1>.");
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::string PhaseVocoderOperation::Name() const { return kPhaseVocoderOperation; }
|
||||
|
||||
std::shared_ptr<TensorOp> PhaseVocoderOperation::Build() {
|
||||
std::shared_ptr<PhaseVocoderOp> tensor_op = std::make_shared<PhaseVocoderOp>(rate_, phase_advance_);
|
||||
return tensor_op;
|
||||
}
|
||||
|
||||
Status PhaseVocoderOperation::to_json(nlohmann::json *out_json) {
|
||||
nlohmann::json args;
|
||||
args["rate"] = rate_;
|
||||
RETURN_IF_NOT_OK(phase_advance_->to_json(&args));
|
||||
*out_json = args;
|
||||
return Status::OK();
|
||||
}
|
||||
} // namespace audio
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* Copyright 2022 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_PHASE_VOCODER_IR_H_
|
||||
#define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_PHASE_VOCODER_IR_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "include/api/status.h"
|
||||
#include "minddata/dataset/kernels/ir/tensor_operation.h"
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
namespace audio {
|
||||
constexpr char kPhaseVocoderOperation[] = "PhaseVocoder";
|
||||
|
||||
class PhaseVocoderOperation : public TensorOperation {
|
||||
public:
|
||||
PhaseVocoderOperation(float rate, const std::shared_ptr<Tensor> &phase_advance);
|
||||
|
||||
~PhaseVocoderOperation();
|
||||
|
||||
std::shared_ptr<TensorOp> Build() override;
|
||||
|
||||
Status ValidateParams() override;
|
||||
|
||||
std::string Name() const override;
|
||||
|
||||
Status to_json(nlohmann::json *out_json) override;
|
||||
|
||||
private:
|
||||
float rate_;
|
||||
std::shared_ptr<Tensor> phase_advance_;
|
||||
};
|
||||
} // namespace audio
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_PHASE_VOCODER_IR_H_
|
||||
|
|
@ -32,6 +32,7 @@ add_library(audio-kernels OBJECT
|
|||
mu_law_decoding_op.cc
|
||||
mu_law_encoding_op.cc
|
||||
overdrive_op.cc
|
||||
phase_vocoder_op.cc
|
||||
phaser_op.cc
|
||||
riaa_biquad_op.cc
|
||||
sliding_window_cmn_op.cc
|
||||
|
|
|
|||
|
|
@ -475,6 +475,29 @@ Status TimeStretch(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor>
|
|||
return Status::OK();
|
||||
}
|
||||
|
||||
Status PhaseVocoder(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, float rate,
|
||||
const std::shared_ptr<Tensor> &phase_advance) {
|
||||
const int32_t kFrequencePosInComplex = -3;
|
||||
RETURN_IF_NOT_OK(ValidateTensorShape("PhaseVocoder", input->shape().Size() > kDefaultAudioDim && input->IsComplex(),
|
||||
"<..., freq, num_frame, complex=2>"));
|
||||
RETURN_IF_NOT_OK(ValidateTensorNumeric("PhaseVocoder", input));
|
||||
RETURN_IF_NOT_OK(ValidateEqual("PhaseVocoder", "first dimension of 'phase_advance'", phase_advance->shape()[0],
|
||||
"freq dimension length of input tensor", input->shape()[kFrequencePosInComplex]));
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(phase_advance->type() == input->type(),
|
||||
"PhaseVocoder: invalid parameter, data type of phase_advance should be equal to data "
|
||||
"type of input tensor, but got: data type of phase_advance " +
|
||||
phase_advance->type().ToString() + " while data type of input tensor " +
|
||||
input->type().ToString() + ".");
|
||||
std::shared_ptr<Tensor> input_tensor;
|
||||
if (input->type().value() != DataType::DE_FLOAT64) {
|
||||
RETURN_IF_NOT_OK(TypeCast(input, &input_tensor, DataType(DataType::DE_FLOAT32)));
|
||||
RETURN_IF_NOT_OK(TimeStretch<float>(input_tensor, output, rate, phase_advance));
|
||||
} else {
|
||||
RETURN_IF_NOT_OK(TimeStretch<double>(input, output, rate, phase_advance));
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status Dct(std::shared_ptr<Tensor> *output, int n_mfcc, int n_mels, NormMode norm) {
|
||||
TensorShape dct_shape({n_mels, n_mfcc});
|
||||
Tensor::CreateEmpty(dct_shape, DataType(DataType::DE_FLOAT32), output);
|
||||
|
|
|
|||
|
|
@ -445,6 +445,15 @@ Status SpectralCentroid(const std::shared_ptr<Tensor> &input, std::shared_ptr<Te
|
|||
Status TimeStretch(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, float rate, float hop_length,
|
||||
float n_freq);
|
||||
|
||||
/// \brief Stretch STFT in time at a given rate, without changing the pitch.
|
||||
/// \param[in] input Tensor of shape <..., freq, time, 2>.
|
||||
/// \param[in] output Tensor of shape <..., freq, ceil(time/rate), 2>.
|
||||
/// \param[in] rate Speed-up factor.
|
||||
/// \param[in] phase_advance Expected phase advance in each bin in shape of (freq, 1).
|
||||
/// \return Status code.
|
||||
Status PhaseVocoder(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, float rate,
|
||||
const std::shared_ptr<Tensor> &phase_advance);
|
||||
|
||||
/// \brief Apply a mask along axis.
|
||||
/// \param input: Tensor of shape <..., freq, time>.
|
||||
/// \param output: Tensor of shape <..., freq, time>.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Copyright 2022 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/phase_vocoder_op.h"
|
||||
|
||||
#include "minddata/dataset/audio/kernels/audio_utils.h"
|
||||
#include "minddata/dataset/kernels/data/data_utils.h"
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
Status PhaseVocoderOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
|
||||
IO_CHECK(input, output);
|
||||
return PhaseVocoder(input, output, rate_, phase_advance_);
|
||||
}
|
||||
|
||||
Status PhaseVocoderOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
|
||||
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
|
||||
outputs.clear();
|
||||
const int32_t kTimePos = -2;
|
||||
const int32_t kComplexDimSize = 2;
|
||||
for (auto s : inputs) {
|
||||
std::vector<dsize_t> s_vec = s.AsVector();
|
||||
s_vec.pop_back();
|
||||
s_vec.pop_back();
|
||||
s_vec.push_back(std::ceil(s[kTimePos] / rate_));
|
||||
s_vec.push_back(kComplexDimSize);
|
||||
outputs.emplace_back(TensorShape(s_vec));
|
||||
}
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(!outputs.empty(), "PhaseVocoder: invalid shape of input tensor.");
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status PhaseVocoderOp::OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) {
|
||||
RETURN_IF_NOT_OK(TensorOp::OutputType(inputs, outputs));
|
||||
RETURN_IF_NOT_OK(
|
||||
ValidateTensorType("PhaseVocoder", inputs[0].IsNumeric(), "[int, float, double]", inputs[0].ToString()));
|
||||
if (inputs[0] == DataType(DataType::DE_FLOAT64)) {
|
||||
outputs[0] = DataType(DataType::DE_FLOAT64);
|
||||
} else {
|
||||
outputs[0] = DataType(DataType::DE_FLOAT32);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* Copyright 2022 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_PHASE_VOCODER_OP_H_
|
||||
#define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_PHASE_VOCODER_OP_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "minddata/dataset/core/tensor.h"
|
||||
#include "minddata/dataset/kernels/tensor_op.h"
|
||||
#include "minddata/dataset/util/status.h"
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
class PhaseVocoderOp : public TensorOp {
|
||||
public:
|
||||
/// \brief Constructor.
|
||||
/// \param[in] rate Speed-up factor.
|
||||
/// \param[in] phase_advance Expected phase advance in each bin in shape of (freq, 1).
|
||||
PhaseVocoderOp(float rate, const std::shared_ptr<Tensor> &phase_advance)
|
||||
: rate_(rate), phase_advance_(phase_advance) {}
|
||||
|
||||
~PhaseVocoderOp() override = default;
|
||||
|
||||
Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override;
|
||||
|
||||
std::string Name() const override { return kPhaseVocoderOp; }
|
||||
|
||||
Status OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) override;
|
||||
|
||||
Status OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) override;
|
||||
|
||||
private:
|
||||
float rate_;
|
||||
std::shared_ptr<Tensor> phase_advance_;
|
||||
};
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_PHASE_VOCODER_OP_H_
|
||||
|
|
@ -751,6 +751,28 @@ class MS_API Phaser final : public TensorTransform {
|
|||
std::shared_ptr<Data> data_;
|
||||
};
|
||||
|
||||
/// \brief PhaseVocoder TensorTransform
|
||||
/// \notes Given a STFT tensor, speed up in time without modifying pitch by factor of rate.
|
||||
class MS_API PhaseVocoder final : public TensorTransform {
|
||||
public:
|
||||
/// \brief Constructor.
|
||||
/// \param[in] rate Speed-up factor.
|
||||
/// \param[in] phase_advance Expected phase advance in each bin in shape of (freq, 1).
|
||||
PhaseVocoder(float rate, const MSTensor &phase_advance);
|
||||
|
||||
/// \brief Destructor.
|
||||
~PhaseVocoder() = default;
|
||||
|
||||
protected:
|
||||
/// \brief Function to convert TensorTransform object into a TensorOperation object.
|
||||
/// \return Shared pointer to TensorOperation object.
|
||||
std::shared_ptr<TensorOperation> Parse() override;
|
||||
|
||||
private:
|
||||
struct Data;
|
||||
std::shared_ptr<Data> data_;
|
||||
};
|
||||
|
||||
/// \brief Apply RIAA vinyl playback equalization.
|
||||
class MS_API RiaaBiquad final : public TensorTransform {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ constexpr char kMuLawDecodingOp[] = "MuLawDecodingOp";
|
|||
constexpr char kMuLawEncodingOp[] = "MuLawEncodingOp";
|
||||
constexpr char kOverdriveOp[] = "OverdriveOp";
|
||||
constexpr char kPhaserOp[] = "PhaserOp";
|
||||
constexpr char kPhaseVocoderOp[] = "PhaseVocoderOp";
|
||||
constexpr char kRiaaBiquadOp[] = "RiaaBiquadOp";
|
||||
constexpr char kSlidingWindowCmnOp[] = "SlidingWindowCmnOp";
|
||||
constexpr char kSpectralCentroidOp[] = "SpectralCentroidOp";
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ from .validators import check_allpass_biquad, check_amplitude_to_db, check_band_
|
|||
check_contrast, check_db_to_amplitude, check_dc_shift, check_deemph_biquad, check_detect_pitch_frequency, \
|
||||
check_dither, check_equalizer_biquad, check_fade, check_flanger, check_gain, check_highpass_biquad, \
|
||||
check_lfilter, check_lowpass_biquad, check_magphase, check_masking, check_mel_scale, check_mu_law_coding, \
|
||||
check_overdrive, check_phaser, check_riaa_biquad, check_sliding_window_cmn, check_spectral_centroid, \
|
||||
check_spectrogram, check_time_stretch, check_treble_biquad, check_vol
|
||||
check_overdrive, check_phase_vocoder, check_phaser, check_riaa_biquad, check_sliding_window_cmn, \
|
||||
check_spectral_centroid, check_spectrogram, check_time_stretch, check_treble_biquad, check_vol
|
||||
|
||||
|
||||
class AudioTensorOperation(TensorOperation):
|
||||
|
|
@ -1114,6 +1114,33 @@ class Phaser(AudioTensorOperation):
|
|||
self.delay_ms, self.decay, self.mod_speed, self.sinusoidal)
|
||||
|
||||
|
||||
class PhaseVocoder(AudioTensorOperation):
|
||||
"""
|
||||
Given a STFT tensor, speed up in time without modifying pitch by a factor of rate.
|
||||
|
||||
Args:
|
||||
rate (float): Speed-up factor.
|
||||
phase_advance (numpy.ndarray): Expected phase advance in each bin in shape of (freq, 1).
|
||||
|
||||
Examples:
|
||||
>>> import numpy as np
|
||||
>>>
|
||||
>>> waveform = np.random.randn(2, 44, 10, 2)
|
||||
>>> numpy_slices_dataset = ds.NumpySlicesDataset(data=waveform, column_names=["audio"])
|
||||
>>> phase_advance = np.random.randn(44, 1)
|
||||
>>> transforms = [audio.PhaseVocoder(rate=2, phase_advance=phase_advance)]
|
||||
>>> numpy_slices_dataset = numpy_slices_dataset.map(operations=transforms, input_columns=["audio"])
|
||||
"""
|
||||
|
||||
@check_phase_vocoder
|
||||
def __init__(self, rate, phase_advance):
|
||||
self.rate = rate
|
||||
self.phase_advance = cde.Tensor(phase_advance)
|
||||
|
||||
def parse(self):
|
||||
return cde.PhaseVocoderOperation(self.rate, self.phase_advance)
|
||||
|
||||
|
||||
class RiaaBiquad(AudioTensorOperation):
|
||||
"""
|
||||
Apply RIAA vinyl playback equalization. Similar to SoX implementation.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ Validators for TensorOps.
|
|||
|
||||
from functools import wraps
|
||||
|
||||
import numpy as np
|
||||
|
||||
from mindspore.dataset.core.validator_helpers import check_float32, check_float32_not_zero, check_int32, \
|
||||
check_int32_not_zero, check_list_same_size, check_non_negative_float32, check_non_negative_int32, \
|
||||
check_pos_float32, check_pos_int32, check_value, INT32_MAX, parse_user_args, type_check
|
||||
|
|
@ -721,3 +723,17 @@ def check_spectral_centroid(method):
|
|||
return method(self, *args, **kwargs)
|
||||
|
||||
return new_method
|
||||
|
||||
|
||||
def check_phase_vocoder(method):
|
||||
"""Wrapper method to check the parameters of PhaseVocoder."""
|
||||
|
||||
@wraps(method)
|
||||
def new_method(self, *args, **kwargs):
|
||||
[rate, phase_advance], _ = parse_user_args(method, *args, **kwargs)
|
||||
type_check(rate, (int, float), "rate")
|
||||
check_pos_float32(rate, "rate")
|
||||
type_check(phase_advance, (np.ndarray,), "phase_advance")
|
||||
return method(self, *args, **kwargs)
|
||||
|
||||
return new_method
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2021 Huawei Technologies Co., Ltd
|
||||
* Copyright 2021-2022 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.
|
||||
|
|
@ -2245,3 +2245,99 @@ TEST_F(MindDataTestPipeline, TestMelScaleWrongArgs) {
|
|||
iter = ds->CreateIterator();
|
||||
EXPECT_EQ(iter, nullptr);
|
||||
}
|
||||
|
||||
/// Feature: PhaseVocoder
|
||||
/// Description: test PhaseVocoder in pipeline mode
|
||||
/// Expectation: the data is processed successfully
|
||||
TEST_F(MindDataTestPipeline, TestPhaseVocoderPipeline) {
|
||||
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestPhaseVocoderPipeline.";
|
||||
std::shared_ptr<SchemaObj> schema = Schema();
|
||||
|
||||
int freq = 1025;
|
||||
int hop_length = 512;
|
||||
ASSERT_OK(schema->add_column("waveform", mindspore::DataType::kNumberTypeFloat32, {2, freq, 30, 2}));
|
||||
|
||||
std::vector<float> phase_advance;
|
||||
float tpnum = 0;
|
||||
float step = (1.0 * M_PI * hop_length / (freq - 1));
|
||||
for (int i = 0; i < freq; i++) {
|
||||
phase_advance.push_back(tpnum);
|
||||
tpnum += step;
|
||||
}
|
||||
|
||||
std::shared_ptr<Dataset> ds = RandomData(5, schema);
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
ds = ds->SetNumWorkers(4);
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
std::shared_ptr<Tensor> phase_advance_tensor;
|
||||
Tensor::CreateFromVector(phase_advance, TensorShape({1025, 1}), &phase_advance_tensor);
|
||||
auto input_ms = mindspore::MSTensor(std::make_shared<mindspore::dataset::DETensor>(phase_advance_tensor));
|
||||
|
||||
float rate = 1.3;
|
||||
auto PhaseVocoder = audio::PhaseVocoder(rate, input_ms);
|
||||
|
||||
ds = ds->Map({PhaseVocoder});
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
std::shared_ptr<Iterator> iter = ds->CreateIterator();
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
std::unordered_map<std::string, mindspore::MSTensor> row;
|
||||
ASSERT_OK(iter->GetNextRow(&row));
|
||||
|
||||
std::vector<int64_t> expected = {2, 1025, 24, 2};
|
||||
|
||||
int i = 0;
|
||||
while (row.size() != 0) {
|
||||
auto col = row["waveform"];
|
||||
ASSERT_EQ(col.Shape(), expected);
|
||||
ASSERT_EQ(col.Shape().size(), 4);
|
||||
ASSERT_EQ(col.DataType(), mindspore::DataType::kNumberTypeFloat32);
|
||||
ASSERT_OK(iter->GetNextRow(&row));
|
||||
i++;
|
||||
}
|
||||
EXPECT_EQ(i, 5);
|
||||
|
||||
iter->Stop();
|
||||
}
|
||||
|
||||
/// Feature: PhaseVocoder
|
||||
/// Description: test PhaseVocoder with wrong input
|
||||
/// Expectation: Throw exception as expected.
|
||||
TEST_F(MindDataTestPipeline, TestPhaseVocoderWrongArgs) {
|
||||
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestPhaseVocoderWrongArgs.";
|
||||
std::shared_ptr<SchemaObj> schema = Schema();
|
||||
|
||||
int freq = 1025;
|
||||
int hop_length = 512;
|
||||
ASSERT_OK(schema->add_column("waveform", mindspore::DataType::kNumberTypeFloat32, {2, freq, 30, 2}));
|
||||
|
||||
std::vector<float> phase_advance;
|
||||
float tpnum = 0;
|
||||
float step = (1.0 * M_PI * hop_length / (freq - 1));
|
||||
for (int i = 0; i < freq; i++) {
|
||||
phase_advance.push_back(tpnum);
|
||||
tpnum += step;
|
||||
}
|
||||
|
||||
std::shared_ptr<Tensor> phase_advance_tensor;
|
||||
Tensor::CreateFromVector(phase_advance, TensorShape({1025, 1}), &phase_advance_tensor);
|
||||
auto input_ms = mindspore::MSTensor(std::make_shared<mindspore::dataset::DETensor>(phase_advance_tensor));
|
||||
|
||||
std::shared_ptr<Dataset> ds = RandomData(50, schema);
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
ds = ds->SetNumWorkers(4);
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
float rate = -2.0;
|
||||
auto PhaseVocoder = audio::PhaseVocoder(rate, input_ms);
|
||||
|
||||
ds = ds->Map({PhaseVocoder});
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
std::shared_ptr<Iterator> iter = ds->CreateIterator();
|
||||
EXPECT_EQ(iter, nullptr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2161,6 +2161,32 @@ TEST_F(MindDataTestExecute, TestDBToAmplitudeWithEager) {
|
|||
EXPECT_TRUE(s01.IsOk());
|
||||
}
|
||||
|
||||
/// Feature: PhaseVocoder
|
||||
/// Description: test PhaseVocoder in eager mode
|
||||
/// Expectation: the data is processed successfully
|
||||
TEST_F(MindDataTestExecute, TestPhaseVocoderEager) {
|
||||
MS_LOG(INFO) << "Doing MindDataTestExecute-TestPhaseVocoderEager.";
|
||||
// testing
|
||||
std::shared_ptr<Tensor> input_tensor, input_phase_advance_tensor;
|
||||
Tensor::CreateFromVector(
|
||||
std::vector<float>({0.1468, -1.1094, 0.0525, -0.3742, -0.7729, -0.7138, 0.3253, 0.0419, 0.8433, -0.5313,
|
||||
-0.0988, -0.0927, -0.7071, -0.7740, -1.1087, -1.1925, -1.2749, -0.0862, 0.0693, 0.2937,
|
||||
0.1676, 0.2356, 2.7333, 2.5171, 0.8055, 0.7380, -0.4437, -0.7257, -0.7154, 0.1801,
|
||||
-1.9323, 1.8184, 0.8196, 0.1371, -0.0677, -2.2315, 0.0662, -0.0071, -0.8639, 0.6215,
|
||||
-0.5144, 0.8373, -0.1072, 0.6184, 0.1985, -0.7692, -0.5879, -0.0029, 0.0676, -0.5520}),
|
||||
TensorShape({1, 5, 5, 2}), &input_tensor);
|
||||
auto input_tensor_ms = mindspore::MSTensor(std::make_shared<mindspore::dataset::DETensor>(input_tensor));
|
||||
float rate = 2;
|
||||
std::vector<float> phase_advance{0.0000, 1.5708, 3.1416, 4.7124, 6.2832};
|
||||
Tensor::CreateFromVector(phase_advance, TensorShape({5, 1}), &input_phase_advance_tensor);
|
||||
auto phase_advance_ms =
|
||||
mindspore::MSTensor(std::make_shared<mindspore::dataset::DETensor>(input_phase_advance_tensor));
|
||||
std::shared_ptr<TensorTransform> pv = std::make_shared<audio::PhaseVocoder>(rate, phase_advance_ms);
|
||||
mindspore::dataset::Execute transform({pv});
|
||||
Status status = transform(input_tensor_ms, &input_tensor_ms);
|
||||
EXPECT_TRUE(status.IsOk());
|
||||
}
|
||||
|
||||
/// Feature: SlidingWindowCmn
|
||||
/// Description: test basic function of SlidingWindowCmn
|
||||
/// Expectation: get correct number of data
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
# Copyright 2022 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 gen(shape):
|
||||
np.random.seed(0)
|
||||
data = np.random.random(shape)
|
||||
yield (np.array(data, dtype=np.float32),)
|
||||
|
||||
|
||||
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 allclose_nparray(data_expected, data_me, rtol, atol, equal_nan=True):
|
||||
if np.any(np.isnan(data_expected)):
|
||||
assert np.allclose(data_me, data_expected, rtol, atol, equal_nan=equal_nan)
|
||||
elif not np.allclose(data_me, data_expected, rtol, atol, equal_nan=equal_nan):
|
||||
count_unequal_element(data_expected, data_me, rtol, atol)
|
||||
|
||||
|
||||
def test_phase_vocoder_compare():
|
||||
"""
|
||||
Feature: PhaseVocoder
|
||||
Description: mindspore eager mode checking precision
|
||||
Expectation: the returned result is as expected
|
||||
"""
|
||||
indata_0 = np.array([[[[0.43189, 2.3049924],
|
||||
[-0.01202229, 0.9176453],
|
||||
[-0.6258611, 0.66475236],
|
||||
[0.13541847, 1.2829605],
|
||||
[0.9725325, 1.1669061]],
|
||||
[[-0.35001752, -1.0989336],
|
||||
[-1.4930767, 0.86829656],
|
||||
[0.3355314, -0.41216415],
|
||||
[-1.1828239, 1.0075365],
|
||||
[-0.19343425, 0.38364533]]]]).astype('float32')
|
||||
indata_1 = np.array([[[[0.43189, 2.3049924],
|
||||
[-0.01202229, 0.9176453],
|
||||
[-0.6258611, 0.66475236],
|
||||
[0.13541847, 1.2829605],
|
||||
[0.9725325, 1.1669061]],
|
||||
[[-0.35001752, -1.0989336],
|
||||
[-1.4930767, 0.86829656],
|
||||
[0.3355314, -0.41216415],
|
||||
[-1.1828239, 1.0075365],
|
||||
[-0.19343425, 0.38364533]]]]).astype('float64')
|
||||
rate = 2.
|
||||
phase_advance_0 = np.array([[0.0000], [3.9270]]).astype('float32')
|
||||
op_0 = audio.PhaseVocoder(rate, phase_advance_0)
|
||||
phase_advance_1 = np.array([[0.0000], [3.9270]]).astype('float64')
|
||||
op_1 = audio.PhaseVocoder(rate, phase_advance_1)
|
||||
outdata_0 = op_0(indata_0)
|
||||
outdata_1 = op_1(indata_1)
|
||||
stand_outdata = np.array([[[[0.43189007, 2.3049924],
|
||||
[-0.01196056, 0.9129374],
|
||||
[1.1385509, 1.00558]],
|
||||
[[-0.35001755, -1.0989336],
|
||||
[-0.4594292, 0.26718047],
|
||||
[0.404371, -0.14520557]]]]).astype('float32')
|
||||
allclose_nparray(outdata_0, stand_outdata, 0.0001, 0.0001)
|
||||
allclose_nparray(outdata_1, stand_outdata, 0.0001, 0.0001)
|
||||
|
||||
|
||||
def test_phase_vocoder_eager():
|
||||
"""
|
||||
Feature: PhaseVocoder
|
||||
Description: mindspore eager mode with normal testcase
|
||||
Expectation: the returned result is as expected
|
||||
"""
|
||||
logger.info("test PhaseVocoder op in eager mode")
|
||||
stft = next(gen([10, 10, 10, 2]))[0]
|
||||
out_put = audio.PhaseVocoder(1.3, np.random.randn(10, 1).astype('float32'))(stft)
|
||||
assert out_put.shape == (10, 10, 8, 2)
|
||||
|
||||
|
||||
def test_phase_vocoder_pipeline():
|
||||
"""
|
||||
Feature: PhaseVocoder
|
||||
Description: mindspore pipeline mode with normal testcase
|
||||
Expectation: the returned result is as expected
|
||||
"""
|
||||
logger.info("test PhaseVocoder op in pipeline mode")
|
||||
|
||||
generator = gen([32, 33, 333, 2])
|
||||
data1 = ds.GeneratorDataset(source=generator, column_names=["input"])
|
||||
|
||||
transforms = [audio.PhaseVocoder(0.8, np.random.randn(33, 1).astype('float32'))]
|
||||
data1 = data1.map(operations=transforms, input_columns=["input"])
|
||||
|
||||
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
|
||||
out_put = item["input"]
|
||||
assert out_put.shape == (32, 33, 417, 2)
|
||||
|
||||
|
||||
def test_phase_vocoder_invalid_input():
|
||||
"""
|
||||
Feature: PhaseVocoder
|
||||
Description: mindspore eager mode with invalid input
|
||||
Expectation: the returned result is as expected
|
||||
"""
|
||||
def test_invalid_param(test_name, rate, phase_advance, error, error_msg):
|
||||
logger.info("Test PhaseVocoder with wrong params: {0}".format(test_name))
|
||||
with pytest.raises(error) as error_info:
|
||||
_ = audio.PhaseVocoder(rate, phase_advance)
|
||||
assert error_msg in str(error_info.value)
|
||||
|
||||
def test_invalid_input(test_name, spec, rate, phase_advance, error, error_msg):
|
||||
logger.info("Test PhaseVocoder with wrong params: {0}".format(test_name))
|
||||
with pytest.raises(error) as error_info:
|
||||
_ = audio.PhaseVocoder(rate, phase_advance)(spec)
|
||||
assert error_msg in str(error_info.value)
|
||||
|
||||
test_invalid_param("invalid phase_advance", 2, None, TypeError,
|
||||
"Argument phase_advance with value None is not of type")
|
||||
test_invalid_param("invalid phase_advance", 0, np.random.randn(4, 1), ValueError,
|
||||
"Input rate is not within the required interval of (0, 16777216].")
|
||||
spec = next(gen([1, 2, 2]))[0]
|
||||
test_invalid_input("invalid phase_advance", spec, 1.23, np.random.randn(4), RuntimeError,
|
||||
"PhaseVocoder: invalid parameter, 'phase_advance' should be in shape of <freq, 1>.")
|
||||
test_invalid_input("invalid phase_advance", spec, 1.1, np.random.randn(4, 4, 1), RuntimeError,
|
||||
"PhaseVocoder: invalid parameter, 'phase_advance' should be in shape of <freq, 1>.")
|
||||
test_invalid_input("invalid input tensor", spec, 2, np.random.randn(3, 1), RuntimeError,
|
||||
"PhaseVocoder: invalid parameter, 'first dimension of 'phase_advance'' should be equal")
|
||||
input_tensor = np.random.randn(4, 4, 2).astype('float32')
|
||||
input_phase_advance = np.random.randn(4, 1).astype('float64')
|
||||
test_invalid_input("invalid input tensor", input_tensor, 2, input_phase_advance, RuntimeError,
|
||||
"PhaseVocoder: invalid parameter, data type of phase_advance should be equal to data")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_phase_vocoder_compare()
|
||||
test_phase_vocoder_eager()
|
||||
test_phase_vocoder_pipeline()
|
||||
test_phase_vocoder_invalid_input()
|
||||
Loading…
Reference in New Issue