質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

88.93%

フォルダ内のwavファイルを一括してフーリエ変換し、値をCSV出力したい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 185

karita

score 15

現状

jupyter notebookでフォルダ内のwavファイルを一括して読込まではできたと思うのですが、
フーリエ変換して、振幅スペクトルの値をCSV出力する際、
1行目に各wavファイル名と同じ番号が来て、2行目以降から該当する値が来るように一括処理する方法が分からない状態です。
CSVの内容を下のイメージのようにしたいです。

CSVイメージ:

1列目      2列目      3列目
1行目  001(.wav),   002,      003,  ・・・
2行目 [001のデータ],[002のデータ],[003のデータ],・・・
↓       ↓        ↓

ご教授お願いいたします。

該当コード

import glob #globモジュールを宣言
import wave
import struct
from scipy import fromstring, int32
import numpy as np
from pylab import *
%matplotlib inline

for file in glob.glob("*.wav"):
    wavfile = open(file, "rb")#サンプルwavファイル
    wr = wave.open(wavfile, "rb") #wavファイルの読み込み
    ch = wr.getnchannels() # モノラルなら1,ステレオなら2
    width = wr.getsampwidth() # サンプル長(1byte=8bit)
    fr = wr.getframerate() #サンプリンググレート(サンプリング周波数)
    fn = wr.getnframes() # 全体のオーディオフレーム数(全データ点数)⇒サンプリング周波数で割れば時間

    N = 22050 #サンプリングレート"fr"の半分の値
    span =4 #フーリエ変換の回数

    print(wavfile)
    print('サンプル数',N)
    print('チャンネル', ch)
    print('サンプル長(bytes)', width)
    print('サンプリンググレート', fr)
    print('全オーディオフレーム数', fn)
    print('サンプル時間',fn/fr,'秒')
    print('N*span時間', 1.0 * N * span / fr, '秒')

    origin = wr.readframes(wr.getnframes()) #メソッドreadframes(n)でnデータ点数を読み込む、ここでは全データ点数の読み込み
    data = origin[:N * span * ch * width] #"origin"から要素の範囲[ ]を指定
    wr.close()

    print('現配列長', len(origin)) #"origin"の要素数
    print('サンプル配列長: ', len(data)) #"data"の要素数

    X = np.frombuffer(data, dtype="int16")#"data"をバイナリ表記から16bitsの整数数列に変換

    # ステレオ前提、左右音に分ける ※モノラルは単に1つおきにデータを読みこむため、必要ない工程 
    left = X[::2] #"0から2番目おき"に要素を得る
    right = X[1::2] #"1から2番目おき"に要素を得る

    print(X)
    print(len(X))
    print(left)
    print(len(left))
    print(right)
    print(len(right))

    #各サンプル区間ごとの周波数分布を配列で返してきます
    def fourier (x, n, w): #x:データ成分、n:個数、w:次元
        K = []
        for i in range(0, w-2): 
            sample = x[i * n:( i + 1) * n] #i~(i+1)番目の要素を得る
            partial = np.fft.fft(sample) #"sample"をフーリエ変換
            K.append(partial) #"K"に"partial"を追加

        return K

    #周波数分布をもとに、実空間での波形を生成しています
    def inverse_fourier (k):
        ret = []
        for sample in k:
            inv = np.fft.ifft(sample) #"sample"を逆フーリエ変換
            ret.extend(inv.real) #"inv.real"を"ret"に追加

        print (len(sample))
        return ret

    Kl = fourier(left, N, span)
    Kr = fourier(right, N, span)
    #周波数リスト
    freqlist = np.fft.fftfreq(N, d=1/fr)
    #振幅スペクトル #実部と虚部を取り出すには、".real" と ".imag" を使用
    #kl[1]は要素数2以上必要⇒spanは4以上
    amp = [np.sqrt(c.real ** 2 + c.imag ** 2) for c in Kl[1]] 
    plot(freqlist, amp, marker= 'o', linestyle='-') #周波数リスト、振幅スペクトル、点、線スタイル
    axis([0, 25000, 0, 100000])

    amp = [np.sqrt(c.real ** 2 + c.imag ** 2) for c in Kr[1]]
    plot(freqlist, amp, marker= 'o', linestyle='-')

    np.savetxt("amp.csv",amp, fmt="%.0f",delimiter=",",header=wavfile)

    print('==============================================================================================================================')

<_io.BufferedReader name='0.wav'>
サンプル数 22050
チャンネル 2
サンプル長(bytes) 3
サンプリンググレート 96000
全オーディオフレーム数 2559658
サンプル時間 26.663104166666667 秒
N*span時間 0.91875 秒
現配列長 15357948
サンプル配列長:  529200
[30738 10747     2 ... 28859 -8178    -1]
264600
[30738     2  6908 ... 28683     0 -8178]
132300
[10747 28925     1 ... 17165 28859    -1]
132300


TypeError                                 Traceback (most recent call last)
<ipython-input-16-38d1c0e7f858> in <module>
79     plot(freqlist, amp, marker= 'o', linestyle='-')
80 
---> 81     np.savetxt("amp.csv",amp, fmt="%.0f",delimiter=",",header=wavfile)
82 
83     print('==============================================================================================================================')

D:\ProgramData\Anaconda3\lib\site-packages\numpy\lib\npyio.py in savetxt(fname, X, fmt, delimiter, newline, header, footer, comments, encoding)
1413             raise ValueError('invalid fmt: %r' % (fmt,))
1414 
-> 1415         if len(header) > 0:
1416             header = header.replace('\n', '\n' + comments)
1417             fh.write(comments + header + newline)

TypeError: object of type '_io.BufferedReader' has no len()

やってみたこと

np.savetxtでCSV出力を試みました。
1行目にwavファイル名が来るように"header=wavfile"としたところ、上記のエラーとなりました。

補足情報

python3.7.4 windows10

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

根本的な問題として、提示コードではforループ毎に同じamp.csvに書込みしているので最後の内容しか書き込めていません。
まずは以下のように別ファイルに書き込むようにしてみてはいかがでしょうか?

import glob #globモジュールを宣言
import os
import numpy as np

for i, file in enumerate(glob.glob("*.wav")):
    # 出力CSVファイル名
    csv_path = os.path.splitext(os.path.basename(file))[0] + '.csv'    # 元のファイル名をそのままつける場合
    csv_path = f'{i+1:03}' + '.csv'    # 単に連番でいい場合
    :
    np.savetxt( csv_path, amp, fmt="%.0f",delimiter=",")


なお、データを縦方向(列毎)に持たせるのはあまりよろしくないかと思います。
一般的には横方向(行毎)に持たせるほうがのちのデータ分析が楽です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/07 11:06

    ご回答ありがとうございます。
    おかげさまで、出力データが上書きされていたことが分かりました。
    当初と少し違った方法ですが、こちらの方法の方が素人の私には扱いやすいと思われますので、使わせていただきたいと思います。

    キャンセル

0

ドキュメントをみると、headerにはstrを入れないといけないようです。今回、ファイルを入れてエラーになっているのではないでしょうか。
numpy.savetxt

一括で列名を入れる場合、numpyですとheadre="001(.wav),002003,..."という文字列を作って指定してあげないといけません。pandasのto_csvのほうがcolumnsが出力されるので楽かもしれませんね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る