Pythonでフォルダ内全wavをスペクトログラムに変換してみた

  • このエントリーをはてなブックマークに追加

音声ファイルをスペクトログラム表示することで、音声の周波数・時間・レベルの変化を一度に確認することが可能です。ここではさらにフォルダ内に保存された全wavファイルに対しSTFT計算し、スペクトログラム画像を作成する方法を紹介します。

こんにちは。wat(@watlablog)です。ここではフォルダ内一括処理のスペクトログラム版を紹介します

STFTとスペクトログラム表示のおさらい

STFT/スペクトログラムとは?

STFTShort-Time Fourier Transform : 短時間フーリエ変換)とは、フーリエ変換を応用した計算方法のことで、時系列データを細かく窓(フレーム)で区切ってFFTし、その窓を順次横にずらしながらFFTを繰り返していく解析方法です(下図参考)。

STFTの説明

一方、スペクトログラムとは時間×周波数×振幅レベルという3つの要素で構成された3次元グラフのことで、STFT計算した結果をそのように並べてプロットしたものになります(下図参考)。

spectrogramの例

STFTやスペクトログラムについての詳細な説明、Pythonコードは「Pythonで音のSTFT計算を自作!スペクトログラム表示する方法」に記載しましたので、是非確認してみて下さい!

スペクトログラムの例

当WATLABブログでは、STFT計算とスペクトログラム表示を使ってピアノ音楽の可視化を行った「Pythonでピアノ音楽のスペクトログラムを作ってみた」や、自分の声の声帯振動やフォルマントを確認した「Pythonの音声解析でフォルマントを抽出してみた」で記事を書いていますので、ご興味のある方は是非こちらもご覧ください!

フォルダ一括処理の考え方

上記で紹介した記事は1つの音声ファイルやデータに対して1つのスペクトログラムを作成するコードを書いていました。

プログラムはコンピュータに沢山仕事をさせるのが良いと思いますので、できるだけ自動化させたいですね。

自動化の基本的な考え方に、「フォルダに関連ファイルを全て入れて、その中のファイルを一括で処理する」というものがあります。

当WATLABブログでは「Pythonでフォルダ内の画像を自動一括リサイズする方法」という記事で初めてフォルダ内のファイル一括処理を行いました。

基本的な知識は「フォルダ内のファイルパスを取得する」、「パスをファイル名と拡張子に分ける」、「新規パスを作る」、「作ったパスで保存する」というものがあれば十分と考えます。

今回はwavファイルを任意のフォルダに複数入れた状態でプログラムを実行し、フォルダ内のwavファイルを全てスペクトログラム画像に変換、.png画像を保存フォルダに格納するという処理を書きます。

それでは早速Pythonコードを見てみましょう!

フォルダ内全wavをスペクトログラム画像に変換するPythonコード

準備

まずプログラムを実行する.pyファイルフォルダの直下に、「wav」というフォルダに予めwavファイルを複数置いておきます。

参考までに以下に図として示します。

フォルダ構成

サブプログラム(function.py):STFTの計算に使う関数群

Pythonで音のSTFT計算を自作!スペクトログラム表示する方法」の記事と同様に、STFT計算をするコードは長いので関数ファイルとしてまとめておきます。ここでは「function.py」というファイル名です。

メイン処理(multiple-stft.py)

続いて、メインのファイルを以下に示します。import文で先ほどのfunction.pyを読んでいるのはこれまでと同様ですが、フォルダやファイル処理を行うために、globosも読み込んでいます。

詳細の説明はコード内にコメントを書きましたので参照下さい。

実行結果

以下が実行結果です。spectrogramというフォルダ内にwavファイルと同様の名前の.pngファイルが作成されました。

実行結果

まとめ

本記事では過去のSTFT計算によるスペクトログラム画像の生成をおさらいし、フォルダ内wavファイルに対し一括スペクトログラム処理をしてみました。

このフォルダ内ファイル処理は様々な自動化の基本になりますので、是非応用してみて下さい。

今回は覚えたコードを組み合わせて音声ファイルの自動処理をしてみました!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!

SNSでもご購読できます。

コメント

  1. 矢嶋慈安 より:

    いつも拝見させて頂いています。現在大学の研究として機械音を測定し、その音をスペクトログラムとして表示、ある一定のグラフ数値から異常ありか、なしかを判別できるようなシステムを目指しこちらのサイトを活用させて頂いています。そんな中でフォルダのパスを入手し展開しているのですが、スペクトログラム表示がされません。エラーもでていなく正常に作動しているのですが、スペクトログラム表示されないため、何か考えられる要因などありましたら教えて頂きたいです。
    また、異常あり、なしをどのようなコードを打てば自動通達できるのか教えて頂けると嬉しいです。

    1. wat より:

      いつもありがとうございます。
      エラーが出ていなく正常に動作しているという事ですが、
      「print(str(i+1) + ‘ done…’) # 計算中がわかるように一応いれとく」
      の下くらいに、
      「print(out_path)」
      と書いて実行し、書かれているout_pathにおかしい所が無いか確認すると良いと思います。
      →そもそもこのprint文が実行されているかどうか、実行されていれば文字列は存在するディレクトリにあるか、という感じです。
       このページのコードはフォルダ内全てのwavをスペクトログラム画像として保存するので、リアルタイム表示はしない仕様です。

      >異常あり、なしをどのようなコードを打てば自動通達できるのか
      これだけだとどのような事を実現したいかはわかりませんが、
      音判定システムでは通常異常音と正常音の特徴をピーク値やオーバーオール値で評価し、ある閾値でOKやNGで判定します。
      複雑な異常音の場合は、最近は機械学習、ディープラーニングのモデルで判定する事が多いようです。
      自動通達は、システムが工場等の場合にはランプを光らせたり音を鳴らしたり…自宅に通達したい場合はメールを送信したり…でしょうか。
      とはいえ、実現したい目的に応じてこの辺は変わると思います。

  2. harrods227 より:

    いつも参考にさせて頂いています。

    このコードにピークを抽出する機能をつけるにはどうすればいいのでしょうか?
    他のページでご紹介頂いているのを見ましたが、組み合わせ方が今ひとつ分かりません。ご教授頂けると嬉しいです。
    以上、よろしくお願いします。

    1. wat より:

      ご訪問ありがとうございます。
      作り方は色々あると思いますが、以下の組み合わせでできそうと思いました。
      そしてピークをマークするだけで良いのか、それとも数値としてファイルに保存したいのかによって構成を組み立てるのが良いと思います。

      ①はじめにdef文でピーク検出関数(以下の記事のfindpeaks, findpeaks_2d)を定義しておく。
      「https://watlab-blog.com/2020/09/29/findpeaks-spectrogram/」

      ②ピーク情報をファイルに保存する場合は、別途def文等で時間、周波数、振幅情報を保存する関数を作っておく。
      (テキストファイルやcsv等。Pandasやnumpyでできそう)

      ②このページのコード「# STFT計算の関数を実行」の次の行で②を実行する。
         ピークを画像の中で図示するだけで良い場合は②を使わず、先ほどの記事の「# ピークを描画する」部分をこのページのコード「# 軸設定する。」の前に記載する。

      という感じでしょうか。
      組み合わせ方の案としてご参考までに!

  3. なたり より:

    以下のエラーがでているのですが、対処法を教えていただけないでしょうか。
    メイン処理の40行目において、
    ValueError: operands could not be broadcast together with shapes (4096,2) (4096,)
    のエラーが出ています。
    これの修正方法を教えていただけると幸いです。

    1. wat より:

      ご訪問ありがとうございます。
      メイン処理40行目というと、stft関数実行部分ですね。もう少し詳しくみると関数のどこで発生しているかの特定ができると思います。
      また、そのエラー自体はshapeの異なるデータに値をマッピングしようとした時に発生するものです。
      (4096, 2)の2が少し気になります。このコードはモノラルのwavを想定したものですが、ステレオで録音されたwavを使っていたりしますか?

      例えばlenやshapeを使ってdataのサイズを見てみる方法等がデバッグとしては良さそうです。

      以上、よろしくお願いいたします。

  4. あああ より:

    はじめまして。いつも参考にさせていただいております。
    質問なのですがこの記事のように.wavファイルではなくスマートフォンで録音した.m4aの音声ファイルでも同じようにスペクトログラムに変換することは可能でしょうか。
    何卒、ご教授いただけますと幸いです。

    1. wat より:

      ご訪問ありがとうございます。
      mp4でも音声を抽出して、横軸時間のデータにすればスペクトログラムに変換することは可能ですよ。

      1. あああ より:

        お返事ありがとうございます。
        この記事にあるプログラムに関してでしたら、どの部分をどのように変換すれば良いでしょうか。
        お手数おかけしますが何卒よろしくお願いします。

        1. wat より:

          こちらも高速化については未検討なので検証できていませんが、スペクトログラムをつくる段階でライブラリを利用するのが最も手軽であると思います。
          以下の記事で紹介しているsignal.spectrogram()を使ってこの記事のコードを書き換えてみれば速くなる可能性があります。
          https://watlab-blog.com/2019/05/19/python-spectrogram/#Scipy%E3%81%AEsignalspectrogram%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F

  5. ゆうや より:

    コメント失礼します.
    現在大学の研究で,こちらのソースコードを参考にスペクトログラム画像の生成コードを実装し,さらに生成速度を上げたいと考えているのですが,何か考えられる方法はないでしょうか?

    1. wat より:

      ご訪問ありがとうございます。
      僕はまだ速度の問題に直面していないのでまだ考えていませんが、
      forループになっていてかつ演算をしている部分は線形代数の知識を使って効率を上げることができそうです。
      てっとり早いのはSciPyのscipy.signal.spectrogramを使うのが良いかもしれません。
      (外部ライブラリは裏でより高速なC++を走らせていたりするので)

      あとはNumbaのJIT(以下記事参考)を使ってコンパイルを試みる…等もありますが、今回のケースに通用して速くなるかは未確認です。
      https://watlab-blog.com/2020/06/14/numba-jit/

      1. ゆうや より:

        一度SciPyの使用を検討してみたいと思います.
        参考にさせて頂きます.
        返信ありがとうございました.

harrods227 へ返信する コメントをキャンセル

*