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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Pygame

Pygameは、ビデオゲームの製作用に設計されたクロスプラットフォームのPythonモジュールセットです。Pythonでコンピューターグラフィックスと音声を扱うためのライブラリが含まれています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

FFmpeg

FFmpegは、動画と音声を交換できるフリーソフトウェアです。UNIX系OSから派生した、MS-DOSから操作するコマンドラインツールです。libavcodecやlibavformat、libswscale、libavfilterなどを含みます。ライセンスは、コンパイルの際のオプションによりLGPLもしくはGPLに決定されます。対応コーデックや使用できるオプションが多く、幅広く利用されています。

Q&A

解決済

2回答

7204閲覧

pythonでwavを再生しつつリアルタイムにスペクトラム(波形)描画をしたい。

dendenmushi

総合スコア98

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Pygame

Pygameは、ビデオゲームの製作用に設計されたクロスプラットフォームのPythonモジュールセットです。Pythonでコンピューターグラフィックスと音声を扱うためのライブラリが含まれています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

FFmpeg

FFmpegは、動画と音声を交換できるフリーソフトウェアです。UNIX系OSから派生した、MS-DOSから操作するコマンドラインツールです。libavcodecやlibavformat、libswscale、libavfilterなどを含みます。ライセンスは、コンパイルの際のオプションによりLGPLもしくはGPLに決定されます。対応コーデックや使用できるオプションが多く、幅広く利用されています。

1グッド

1クリップ

投稿2020/09/06 01:02

前提・実現したいこと

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__()

しかし変わりありませんでした。

気になった点

下の画像の赤枠のところにピンクでかなり細かく上下の表示がされているため、そこだけ表示するようにすれば叶うのかなと思っています。

イメージ説明

知見ある方アドバイス何かありましたら、どうかよろしくお願い致します。

teamikl👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

「Pygameでの描画」とコメントがある部分からの処理を以下のように修正。

  • pygame.display.rectangle(rectangle_list)pygame.display.flipに変更
  • amplitudeSpectrum[i]amplitudeSpectrum[i].astype(int)に変更
  • 2+1+に変更

Python

1 screen.fill((240, 128, 128)) 2 rectangle_list.clear() 3 for i in range(86): 4 rectangle_list.append(pygame.draw.line(screen, (102, 205, 170), (1+i * 10, 350 + amplitudeSpectrum[i].astype(int) * 10), 5 (1+i * 10, 350 - amplitudeSpectrum[i].astype(int) * 10), 4)) 6 pygame.display.flip()

一番の問題は、pygame.display.rectangle(rectangle_list)では「指定した四角形の内部だけを更新する」こと。つまり、前回の描画で四角形(のひとつ)が今回の四角形よりも長かった場合、はみ出る部分の描画が更新されません。これが、「伸びる部分だけが更新されている」ように見える原因。
対策として、今回はpygame.display.flip()で画面全体を更新しています。

ささいな問題は、lineのX座標が始点と終点で1ずれているので、微妙に斜めになっていることと、lineの引数は整数だけしか受け付けなくなる予定なので(毎回その警告がコンソールに出る)、いまのうちに整数化しておくこと。

修正後

投稿2020/09/06 02:32

編集2020/09/06 02:49
Daregada

総合スコア11990

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

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

dendenmushi

2020/09/06 03:00

更新されました。原因詳細理解できました。そしてグラフ確かにずれていました。あとintにastypeする件も重ねて大変ありがとうございました。
Daregada

2020/09/06 03:08

ちなみに、「ピンクのグラフ」は存在せず、斜めに描画されるlineと、それと同じはずの更新範囲が微妙にずれているせいで、画面全体を塗りつぶすピンクがそこだけ見えているのだと思います。
dendenmushi

2020/09/06 03:21

なるほどです。音声波形系は初めてで挑戦中です。ありがとうございました。
guest

0

pygame使ったことないので理屈は分かりませんが、以下のように修正するとそれなりに描画することができました。
rectangle_listにより更新領域を限定していたことにより背景全体の更新ができていなかったのがまずかったように思います。

Python

1 #pygame.display.update(rectangle_list) # ディスプレイ更新 2 pygame.display.update() # ディスプレイ更新

投稿2020/09/06 02:23

can110

総合スコア38341

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

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

dendenmushi

2020/09/06 02:59

確かに更新されました。回答頂きありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問