

「スペクトラルノイズ除去による雑音除去」  
<https://www.ai-shift.co.jp/techblog/1305>

のサイトから、ノイズ部分と音源分離後の音声データを書き込んだ後に  
音声を再生したいと思っています。プログラム上だとSound Envelopがノイズ部分、  
recovered_signalが音源分離後の音声？のはずです。この2つをwavファイルにすればできると思うのですがその方法を教えてほしいです。

下記のソースコードは、webサイトのプログラムを一部書き加えてあります。

[code]

    !pip install librosa
    
    import numpy as np
    from scipy.ndimage import maximum_filter1d
    
    def envelope(y, rate, threshold):
        """
        Args:
            - y: 信号データ
            - rate: サンプリング周波数
            - threshold: 雑音判断するしきい値
        Returns:
            - mask: 振幅がしきい値以上か否か
            - y_mean: Sound Envelop
        """
        y_mean = maximum_filter1d(np.abs(y), mode="constant", size=rate//20)
        mask = [mean > threshold for mean in y_mean]
        return mask, y_mean
    
    import librosa
    
    
    n_fft=2048  # STFTカラム間の音声フレーム数
    hop_length=512  # STFTカラム間の音声フレーム数
    win_length=2048  # ウィンドウサイズ
    n_std_thresh=1.5  # 信号とみなされるために、ノイズの平均値よりも大きい標準偏差（各周波数レベルでの平均値のdB）が何個あるかのしきい値
    
    def _stft(y, n_fft, hop_length, win_length):
        return librosa.stft(y=y, n_fft=n_fft, hop_length=hop_length, win_length=win_length)
    
    def _amp_to_db(x):
        return librosa.core.amplitude_to_db(x, ref=1.0, amin=1e-20, top_db=80.0)
    
    
    
    sample_rate= 32000
    
    # 音声ファイルの読み込み
    #noise_clip = open(r"C:\Users\1818067\birdvoice.wav")
    
    path=r'C:\Users\1818067\birdvoice.wav'
    sig, _ = librosa.load(path, sr=sample_rate)
    
    # ノイズデータ取得
    mask, noise_clip = envelope(sig, sample_rate, threshold=0.03)
    
    
    
    
    noise_stft = _stft(noise_clip, n_fft, hop_length, win_length)
    noise_stft_db = _amp_to_db(np.abs(noise_stft))  # dBに変換する
    
    mean_freq_noise = np.mean(noise_stft_db, axis=1)
    std_freq_noise = np.std(noise_stft_db, axis=1)
    noise_thresh = mean_freq_noise + std_freq_noise * n_std_thresh
    
    import librosa
    from envelop import envelope
    import scipy
    
    
    n_grad_freq = 2  # マスクで平滑化する周波数チャンネルの数
    n_grad_time = 4  # マスクを使って滑らかにする時間チャンネル数
    prop_decrease = 1.0  # ノイズをどの程度減らすか
    
    
    #data = open(r'C:\Users\1818067\birdvoice.wav')
    #audio_clip = envelope(data).envelop
    
    sample_rate= 32000
    
    # 音声ファイルの読み込み
    #noise_clip = open(r"C:\Users\1818067\birdvoice.wav")
    
    path=r'C:\Users\1818067\birdvoice.wav'
    sig, _ = librosa.load(path, sr=sample_rate)
    
    # ノイズデータ取得
    audio_clip, rate = librosa.load('birdvoice.wav')
    
    
    # 音源もSTFTで特徴量抽出する
    sig_stft = _stft(audio_clip, n_fft, hop_length, win_length)
    sig_stft_db = _amp_to_db(np.abs(sig_stft))
    
    # 時間と頻度でマスクの平滑化フィルターを作成
    smoothing_filter = np.outer(
            np.concatenate(
                [
                    np.linspace(0, 1, n_grad_freq + 1, endpoint=False),
                    np.linspace(1, 0, n_grad_freq + 2),
                ]
            )[1:-1],
            np.concatenate(
                [
                    np.linspace(0, 1, n_grad_time + 1, endpoint=False),
                    np.linspace(1, 0, n_grad_time + 2),
                ]
            )[1:-1],
        )
    smoothing_filter = smoothing_filter / np.sum(smoothing_filter)
    
    # 時間と周波数のしきい値の計算
    db_thresh = np.repeat(
            np.reshape(noise_thresh, [1, len(mean_freq_noise)]),
            np.shape(sig_stft_db)[1],
            axis=0,
        ).T
    sig_mask = sig_stft_db < db_thresh
    sig_mask = scipy.signal.fftconvolve(sig_mask, smoothing_filter, mode="same")
    sig_mask = sig_mask * prop_decrease
    
    mask_gain_dB = np.min(_amp_to_db(np.abs(sig_stft)))
    
    def _db_to_amp(x,):
        return librosa.core.db_to_amplitude(x, ref=1.0)
    
    sig_stft_db_masked = (
            sig_stft_db * (1 - sig_mask)
            + np.ones(np.shape(mask_gain_dB)) * mask_gain_dB * sig_mask
    )
    
    def _istft(y, hop_length, win_length):
        return librosa.istft(y, hop_length, win_length)
    
    sig_imag_masked = np.imag(sig_stft) * (1 - sig_mask)
    sig_stft_amp = (_db_to_amp(sig_stft_db_masked) * np.sign(sig_stft)) + (1j * sig_imag_masked)
    
    recovered_signal = _istft(sig_stft_amp, hop_length, win_length)
    
[/code]


CC BY-SA 4.0
2021-10-13T05:54:56.640
83065
2023-04-26T03:05:55.697
2022-04-20T11:13:38.313
3060
48401
question
python python3
「スペクトラルノイズ除去による雑音除去」による音声再生


以下のような感じで`librosa`の最近の版にはファイル出力機能そのものが無く、`soundfile`という別のパッケージでやってくださいと記述されています。

librosa 0.7.2  
[librosa.output.write_wav(path, y, sr,
norm=False)](https://librosa.org/doc/0.7.2/generated/librosa.output.write_wav.html#librosa.output.write_wav)

> This function is deprecated in librosa 0.7.0. It will be removed in 0.8.
> Usage of `write_wav` should be replaced by `soundfile.write`.

librosa 0.8.1  
[Write out audio files](https://librosa.org/doc/latest/ioformats.html#write-
out-audio-files)

> [PySoundFile](https://pysoundfile.readthedocs.io/en/latest/) provides output
> functionality that can be used directly with numpy array audio buffers:

SoundFile  
[soundfile.write(file, data, samplerate, subtype=None, endian=None,
format=None,
closefd=True)](https://pysoundfile.readthedocs.io/en/latest/#soundfile.write)

> Examples  
>  Write 10 frames of random data to a new file:
[code]

>     >>> import numpy as np
>     >>> import soundfile as sf
>     >>> sf.write('stereo_file.wav', np.random.randn(10, 2), 44100, 'PCM_24')
>  
[/code]

他の参考記事：  
[librosaにおける16-bitでのWAV書き出し](https://www.wizard-notes.com/entry/music-
analysis/librosa-wav-write-16-bit)

* * *

なので例えば`recovered_signal`をファイルにするには以下のようにすれば良いでしょう。

[code]

    import soundfile as sf
    
    sf.write('clearvoice.wav', recovered_signal, 22050, subtype='PCM_16')
    
[/code]

* * *

そしてwavファイルを再生するには、こちらの記事に記載されているどれかを使えば良いでしょう。  
[Pythonでサウンドを扱う](https://qiita.com/hisshi00/items/62c555095b8ff15f9dd2)

例えば上記記事で最初に記載されている`playsound`なら、以前の質問にあったように最新版だとエラーになるので、  
[playsoundを使って音声を再生しようとするとエラーが発生する](https://ja.stackoverflow.com/q/82738/26370)

一つ前の版をインストールしておいて、

[code]

    pip install -U playsound==1.2.2
    
[/code]

以下のように呼び出せば良いと思われます。

[code]

    from playsound import playsound
    
    playsound('clearvoice.wav')
    
[/code]


CC BY-SA 4.0
2021-10-13T10:39:47.607
83073
2021-10-13T10:39:47.607
26370
83065
answer


実行するとcannot import name 'envelope' from 'envelop'となるのですが  
修正後のコードを見せていただけないのでしょうか？


CC BY-SA 4.0
2022-06-21T09:29:02.620
89504
2022-06-21T09:29:02.620
53170
83065
answer