今までと趣向を変えて、今回は音声を扱ってみました。思いついたのが、瞬間ごとの周波数分布を表示するスペクトログラムを、SenseHATの画面で出してみるというものです。結果が正しいかちょっと怪しいですが…それっぽくは出来たかな?
なお、今回RaspberryPiは表示のみで、画面として使いました。フーリエ変換などはPC側でやっており、その結果(単位時間ごとの周波数分布の配列)をWebSocketでRaspberryPiへ送ります。なぜかというと、RaspberryPiにlibrosaという音声系ライブラリのインストールが出来なかっただけです。。が、今となってはこの表示と処理を分けた構成もアリかなと思えます。
参考:https://jorublog.site/python-voice-analysis/
それにしても、scipyは初めて使いましたが、便利ですねー。
以下は、PC側で実行した解析処理のコードです。最終的に、変数amp_msg
をWebSocketでRaspberryPiへ送ります。
import scipy.io.wavfile
import numpy as np
import librosa
def analyze(filename, timespan=0.001, timerate=0.1):
rate, data = scipy.io.wavfile.read(filename)
data = data / 32768
time = np.arange(0, data.shape[0]/rate, 1/rate)
fft_data = np.abs(np.fft.fft(data))
freqList = np.fft.fftfreq(data.shape[0], d=1.0/rate)
fft_size = 1024
hop_length = int(fft_size / 4)
cols = 8
dBMax = 100
dBMin = -100
tpitch = int(rate*timespan)
timecount = int(len(data)/tpitch)
timecount = int(timecount*timerate)
amp_msg = list()
for f in range(timecount):
tstt = f*tpitch
tend = tstt + tpitch
amplitude = np.abs(librosa.core.stft(data[tstt:tend], n_fft=fft_size, hop_length=hop_length))
log_power = librosa.core.amplitude_to_db(amplitude)
fpitch = int(log_power.size/8)
amp = np.ndarray(cols)
msg = ''
for p in range(cols):
stt = fpitch*p
end = stt + fpitch
freq = np.max(log_power[stt:end])
freq8 = int(np.ceil( (freq-(dBMin))/(dBMax-dBMin)*cols ))
amp[p] = freq8
amp_msg.append(
str(int(amp[0])) + ',' +
str(int(amp[1])) + ',' +
str(int(amp[2])) + ',' +
str(int(amp[3])) + ',' +
str(int(amp[4])) + ',' +
str(int(amp[5])) + ',' +
str(int(amp[6])) + ',' +
str(int(amp[7]))
)
return amp_msg