🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

2851閲覧

pythonでwavファイルを書き出したい

iface

総合スコア42

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/12/23 16:53

編集2020/12/24 03:55

前提・実現したいこと

今回以下のような流れでプログラムをつくっています。
wavファイルを読み込み→FFT→バンドパスフィルタ処理→iFFT→処理後の時間信号がプロットされたか確認→wavファイル書き出し

発生している問題・エラーメッセージ

処理後の時間信号がプロットされたか確認は既にできていて、wavファイルが形としては出力されているのですが、音声が再生されない状態です。出力されたwavファイルの再生時間を確認したところ入力データと一緒でした。
今回こちらのサイトを参照
https://water2litter.net/rum/post/python_scipy_wavfile_write/

追加:
もう一つこちらのサイトを参考にしてもう一つbandpassのプログラムを改良して作ってみました。
http://tacky0612.hatenablog.com/entry/2017/11/28/133103
こちらの場合は、wavファイルが出力されるのですが、再生時間が0秒と書いてあり再生できない状態です。
bandpassの下にソースコードを記載しておきます。

該当のソースコード

bandpass

1import sys 2import scipy.io.wavfile 3from scipy.io.wavfile import write 4from scipy.io.wavfile import read 5from scipy.fftpack import rfft,irfft,fftfreq 6import numpy as np 7import matplotlib.pyplot as plt 8 9#音声ファイル読み込み 10args = sys.argv 11wav_filename = args[1] 12rate, data = scipy.io.wavfile.read(wav_filename) 13 14print(data) 15 16#縦軸(振幅)の配列を作成 17data = data / 32768 18#横軸(時間)の配列を作成  #np.arange(初項, 等差数列の終点, 等差) 19time = np.arange(0, data.shape[0]/rate, 1/rate) 20 21 22#縦軸:dataを高速フーリエ変換する(時間領域から周波数領域に変換する) 23fft_data = np.fft.fft(data) 24#横軸:周波数の取得  #np.fft.fftfreq(データ点数, サンプリング周期) 25freqList = np.fft.fftfreq(data.shape[0], d=1.0/rate) 26 27# 正規化 + 交流成分2倍 28fft_data = fft_data/24000 #サンプル数/2 29#fft_data[0] = fft_data[0]/2 30 31# 配列fft_dataをコピー 32fft_data2 = fft_data.copy() 33 34# bandpass処理 35fft_data2[(freqList < 300)&(freqList > -300)] = 0 #highpass 36fft_data2[(freqList > 3300)|(freqList < -3300)] = 0 #lowpass 37 38# 高速逆フーリエ変換(時間信号に戻す) 39data2 = np.fft.ifft(fft_data2) 40#data2 = np.array(data2,dtype = np.int16) #戻しておかないとすごい音がする 41 42# 振幅を元のスケールに戻す 43data2 = np.real(data2*48000) #N = 16000*3 44 45############################################### 46#### 画像をプロットするプログラムは長いため省略 #### 47############################################### 48 49data.flags.writeable = True 50write('out.wav',rate,data2)

実行例: python ~.py ~.wav
###追加のソースコード

bandpass2

1import numpy as np 2import sys 3from scipy.fftpack import rfft,irfft,fftfreq 4import wave 5import matplotlib.pyplot as plt 6 7# ファイルを読み出し 8args = sys.argv 9wav_filename = args[1] 10wf = wave.open(wav_filename,"r") 11 12rate = wf.getframerate() 13nframes = wf.getnframes() 14width = wf.getsampwidth() 15 16amp = (2**8) ** width / 2 #??? 17data = wf.readframes(nframes) #frameの読み込み 18wf.close() 19data = np.frombuffer(data,'int16') # intに変換 20data = data / amp # 振幅正規化(-1~1) 21 22# make time axis 23time = np.arange(0, nframes/rate, 1.0/rate) 24 25fft_data = np.fft.fft(data) 26freq = np.fft.fftfreq(nframes,1.0/rate) 27 28#正規化 29fft_data = fft_data/(nframes/2) 30 31#配列fft_dataをコピー 32fft_data2 = fft_data.copy() 33 34# bandpass処理 35fft_data2[(freq < 300)&(freq > -300)] = 0 #highpass 36fft_data2[(freq > 3300)|(freq < -3300)] = 0 #lowpass 37 38# 高速逆フーリエ変換(時間信号に戻す) 39data2 = np.fft.ifft(fft_data2) 40#data2 = np.array(data2,'int16') 41 42# 振幅を元のスケールに戻す 43data2 = np.real(data2*nframes) 44 45############################################### 46#### 画像をプロットするプログラムは長いため省略 #### 47############################################### 48 49###ファイル書き込み### 50write_wave = wave.open("1.wav","wb") 51write_wave.setparams(wf.getparams()) 52write_wave.writeframes(data2) 53write_wave.close() 54

試したこと

サイトの通り読み込んだデータは書き込み禁止らしいので、

data.flags.writeable = True

を追加した。

補足情報(FW/ツールのバージョンなど)

anaconda3を使用

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jbpb0

2020/12/23 22:55

> write('out.wav',rate,data) data2じゃなくて、data?
iface

2020/12/24 03:40

回答ありがとうございます。 すいません、data2だと思います。 しかし、data2に直しても結果は一緒でした。
jbpb0

2020/12/24 04:30

rate, data = scipy.io.wavfile.read(wav_filename) の直後に print(np.max(data)) print(np.min(data)) を追加して実行した結果と、コードの最後に print(np.max(data2)) print(np.min(data2)) を追加して実行した結果を比べると、全然違いますよね 前者は整数、後者は浮動小数点だし、桁も全然違います そこを合わせないと(もともとのdataに合わせる)いけないのではないですかね
jbpb0

2020/12/24 04:32

data = data / 32768 をやる前の、元々のdataの型と大きさ(桁)に合わせる
iface

2020/12/24 04:53

dataとdata2のサイズの比較は以前したのですが、やはりそこが問題なのですね。 data: Max:23973 min:-28157 data2: Max:0.982835678912711 min:-1.1392373711083272 元々のdataの型と大きさに合わせるというのは、型をint型にして、data2のサイズを10^4倍させればよいということですか。
jbpb0

2020/12/24 06:16 編集

コード内のあちこちで正規化と称して何か掛けたり割ったりしてますけど、下記をやれば分かりますが、fft→ifftをしたら値は元に戻るので、ifftして最終的に音声に戻して利用するのが前提なら、そういうこと(正規化)は要らないんですよ rate, data = scipy.io.wavfile.read(wav_filename) fft_data = np.fft.fft(data) fft_data2 = fft_data.copy() data2 = np.fft.ifft(fft_data2) data2ri = data2.real.astype(np.int16) print(np.max(data)) print(np.min(data)) print(np.max(data2)) print(np.min(data2)) print(np.max(data2ri)) print(np.min(data2ri)) なので、桁が合わないからまた何か掛けて辻褄を合わせるとかするのではなく、そもそも不要な掛け算とか割り算とかしてるところを全部消して、wavに書き込む前に複素数の実部だけにしてから型をint16にして書き込めばいいんじゃないですかね
iface

2020/12/25 04:35

ありがとうございます。wavファイルもちゃんと出力されて動作確認も行えました。 正規化がどのような動作をしているのか詳しく把握していなかったのですごく勉強になります。
guest

回答1

0

自己解決

dataとdata2のサイズのMax,minを比較してみると下記のようになった。

data
Max:23973
min:-28157

data2:
Max:0.982835678912711
min:-1.1392373711083272

data2は浮動小数点で実数に直す必要があったため、時間信号に戻す際にint型に戻す必要があった。

data2 = np.fft.ifft(fft_data2) data2ri = data2.real.astype(np.int16)

投稿2020/12/25 04:46

iface

総合スコア42

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問