前提・実現したいこと
pythonでwavのオーディオスペクトラム描画(波形描画)を行いたい。
環境
windows10
python3.7
参考にしたサイト
pythonで音に合わせて動く波形(オーディオスペクトラム)を作ってみる
行ったこと
①以下から音楽をダウンロードしました。
著作権フリー音源
②ffmpegを導入しました。
ffmpegwindowsインストール参考URL
ⅰ:64bit版 安定 static選択
ⅱ:zipダウンロード
ⅲ:環境変数設定
③mp3形式をwavに変更するためにコマンドプロンプト実行
cmd
1D:\work_folder\music>ffmpeg -i "優しい気持ち.mp3" -vn -ac 2 -ar 44100 -acodec pcm_s16le -f wav "yasasi_output.wav"
④下記該当ソースコードをpythonファイルにて実行(pip install必要です。)
cmd
1pip install soundfile 2pip install pygame
cmd
1D:\work_folder\music>python wav_spect.py
発生している問題・エラーメッセージ
波が常に加算されてしまい上げ下げ表示しない。
緑色の棒グラフがぐんぐん上がっていく。ピンクのグラフは動いている。
該当のソースコード
python
1#!/usr/bin/env python3 2import wave 3import sys 4import pygame 5from pygame.locals import * 6import scipy.fftpack as spfft 7import soundfile as sf 8import pyaudio 9import numpy as np 10import pdb 11# -------------------------------------------------------------------- 12# パラメータ 13# -------------------- 14fn = "yasasi_output.wav" 15# 計算用 16CHUNK = 1024 # pyaudioでストリームにチャンク単位で出力(何故1024かはよく知らない) 17start = 0 # サンプリング開始位置 18N = 1024 # FFTのサンプル数 19SHIFT = 1024 # 窓関数をずらすサンプル数 20hammingWindow = np.hamming(N) # 窓関数 21t = 0 22# -------------------- 23# 描画用 24SCREEN_SIZE = (854, 480) # ディスプレイのサイズ 25rectangle_list = [] 26 27# -------------------- 28# pygame画面初期設定 29pygame.init() 30screen = pygame.display.set_mode(SCREEN_SIZE) 31pygame.display.set_caption("Pygame Audio Visualizer") 32 33 34# -------------------------------------------------------------------- 35# wavファイルを再生しつつ、後に定義する再描画関数redraw()を呼び出す関数 36def play_wav_file(filename): 37 try: 38 wf = wave.open(filename, "r") 39 except FileNotFoundError: # ファイルが存在しなかった場合 40 print("[Error 404] No such file or directory: " + filename) 41 return 0 42 43 # ストリームを開く 44 p = pyaudio.PyAudio() 45 stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), 46 channels=wf.getnchannels(), 47 rate=wf.getframerate(), 48 output=True) 49 50 # 音声を再生 51 data = wf.readframes(CHUNK) 52 while data != '': 53 stream.write(data) 54 data = wf.readframes(CHUNK) 55 redraw() 56 stream.close() 57 p.terminate() 58 59# -------------------------------------------------------------------- 60# 「FFTかけて描画」を繰り返す. 61def redraw(): 62 global start 63 global screen 64 global rectangle_list 65 66 # -------------------- 67 # 対象サンプル点のブロックにFFTをかけて振幅スペクトルを計算する 68 windowedData = hammingWindow * x[start:start + N] # 窓関数をかけたデータブロック 69 X = spfft.fft(windowedData) # FFT 70 amplitudeSpectrum = [np.sqrt(c.real ** 2 + c.imag ** 2) 71 for c in X] # 振幅スペクトル 72 73 # -------------------- 74 # Pygameでの描画 75 76 screen.fill((240, 128, 128)) # 好きな色で初期化する 77 78 rectangle_list.clear() # 四角形リスト初期化 79 80 # スペクトル描画 数値は実行して調整しながら 81 for i in range(86): 82 rectangle_list.append(pygame.draw.line(screen, (102, 205, 170), (1+i * 10, 350 + amplitudeSpectrum[i] * 10), 83 (2+i * 10, 350 - amplitudeSpectrum[i] * 10), 4)) 84 85 86 87 pygame.display.update(rectangle_list) # ディスプレイ更新 88 89 90 start += SHIFT # 窓関数をかける範囲をずらす 91 if start + N > nframes: 92 sys.exit() 93 94 for event in pygame.event.get(): # 終了処理 95 if event.type == QUIT: 96 sys.exit() 97 if event.type == KEYDOWN: 98 if event.key == K_ESCAPE: 99 sys.exit() 100 101# -------------------------------------------------------------------- 102if __name__ == "__main__": 103 104 # -------------------- 105 # wavデータを取得 106 data, fs = sf.read(fn) # dataの形状は(フレーム数×チャンネル数) 107 if data.ndim == 1: 108 x = data # モノラルならそのまま使う 109 if data.ndim == 2: 110 x = data[:, 0] # ステレオならLチャンネルだけに絞って処理することに(Rなら0を1にしてください) 111 112 nframes = x.size # フレーム数取得(FFTで窓関数をずらすときの終了条件に使います) 113 114 # -------------------- 115 # 再生と描画を開始 116 play_wav_file(fn)
試したこと
ディスプレイ更新の下にグラフを初期化するため下記コード追加
python
1 # グラフ初期化 2 rectangle_list = [] 3 amplitudeSpectrum = [] 4 pygame.display.update(rectangle_list) # ディスプレイ更新 5 pygame.display.__init__()
しかし変わりありませんでした。
気になった点
下の画像の赤枠のところにピンクでかなり細かく上下の表示がされているため、そこだけ表示するようにすれば叶うのかなと思っています。
知見ある方アドバイス何かありましたら、どうかよろしくお願い致します。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/09/06 03:00
2020/09/06 03:08
2020/09/06 03:21