第6章ではRaspberry Piを音声利用します.
Raspberry Piには音声出力端子(3.5mmステレオミニジャック)がありますので普通のミニプラグ付きヘッドホンなどからステレオ音声を出力できます.この章では,音楽ファイルをpythonプログラムで出力します.また,Waveファイルのしくみを説明します.そして,音声データを数式で作成して,そのまま音声出力します.
ここでは,MP3ファイルをpythonプログラムで読み込み,そのデータを音声出力します.音声データを再生/停止する基本的なプログラムです.GPIOを利用してボタンから操作します.
以下の手順でpythonプログラムを作成して,音声を再生しましょう.
リスト 1. s_test.py
001 import time, signal, sys
002 import pygame.mixer
003
004 alarm_music = "test1.mp3"
005 play_volume = 100
006
007 pygame.mixer.init()
008 pygame.mixer.music.load( alarm_music )
009 pygame.mixer.music.set_volume( play_volume/100 )
010
011 pygame.mixer.music.play(loops=0)
012 while True:
013 if(pygame.mixer.music.get_busy()!=True):
014 break
015 time.sleep( 0.2 )
016 pygame.mixer.music.stop()
017
$ wget http://icrus.org/raspi/test0.mp3 ↵
$ wget http://icrus.org/raspi/test1.mp3 ↵
$ amixer cset numid=3 1 ↵
(HDMIに戻すとき)$ amixer cset numid=3 2 ↵
$ python s_test.py ↵
mp3音声ファイルは再生できましたか?自分の好みのmp3ファイルをカレンとディレクトリに置き,s_test.pyの音声ファイル名を変更して再生してみましょう.
次にGPIOを使って,ブレッドボード上のスイッチで音声ファイルの再生を制御してみましょう.
リスト 2. s_gpio.py
001 import time, signal, sys
002 import RPi.GPIO as GPIO
003 import pygame.mixer
004
005 alarm_music = "test1.mp3"
006 play_volume = 100
007 switch_pin = 4
008 out_pin = 17
009
010 GPIO.cleanup()
011 GPIO.setmode( GPIO.BCM )
012 GPIO.setup( switch_pin, GPIO.IN )
013 GPIO.setup( out_pin, GPIO.OUT )
014
015 pygame.mixer.init()
016 pygame.mixer.music.load( alarm_music )
017 pygame.mixer.music.set_volume( play_volume/100 )
018
019 pygame.mixer.music.play(-1)
020 b_play=True
021 while True:
022 if b_play==True:
023 GPIO.output( out_pin, GPIO.HIGH )
024 else:
025 GPIO.output( out_pin, GPIO.LOW )
026
027 if GPIO.input( switch_pin ) == GPIO.HIGH:
028 if b_play==True:
029 pygame.mixer.music.pause()
030 b_play=False
031 else:
032 pygame.mixer.music.unpause()
033 b_play=True
034 time.sleep(0.2)
035 time.sleep( 0.1 )
036
図1 再生制御回路図
$ python s_gpio.py ↵
mp3音声ファイルは再生停止はできましたかできましたか?以下に示すURLを参考にすると,いろいろな,命令を実行できます.スイッチを追加して,頭から再生するボタン(など)を作ってみてください.
<参考URL>
http://westplain.sakuraweb.com/translate/pygame/Music.cgi
Waveファイル(拡張子wav)には圧縮なしの音データが入っています.mp3ファイル等は1/10~1/20のデータ圧縮が行われており,伸張した場合,特性の劣化が起こりますが,WAVEファイルは録音時そのままのデータを記録します.よって,数式などにより簡単に好みの波形を出力できます.ではWAVEファイルを作成してみましょう.
次にpythonプログラムを使って,WAVEファイルを作ってみましょう.
リスト 3. s_wave.py
010 # coding: utf-8
020 import numpy as np # 数値計算拡張モジュール
030 import wave # WAVEファイル処理モジュール
040 import struct # 構造体モジュール
050
060 # Cosine wave
070 def create_wave( A, f0, fs, t ): # A 振幅, f0 周波数, fs サンプリング周波数, t 時間[s]
080 point = np.arange( 0, fs*t ) # 数列 0~fs*t-1
090 cos_wave = A * np.cos( 2*np.pi*f0*(point)/fs ) # cos()による数列
100 cos_wave = [ int(x * 32767.0) for x in cos_wave ] # 符号付き16ビットの整数列にする(WAVEのデータ)
110 wave_data = struct.pack( "h"*len(cos_wave), *cos_wave )
120 w = wave.Wave_write( "440Hz.wav" )
130 p = (1, 2, fs, len(wave_data), 'NONE', 'not compressed')
140 w.setparams( p )
150 w.writeframes( wave_data )
160 w.close()
170
180 print( len(point), len(cos_wave) )
190
200 A = 1
210 fs = 44100
220 f0 = 440
230 seconds = 10
240 create_wave( A, f0, fs, seconds )
$ python s_wave.py ↵
$ aplay 440Hz.wave ↵
440Hzの正弦波が再生されます.この音はよく調律に使われるA4の音(「ラ」)です
pythonプログラムを使って,ステレオ仕様のWAVEファイルを作ってみましょう.
リスト 4. s_wave_st.py
010 # coding: utf-8
020 import numpy as np # 数値計算拡張モジュール
030 import wave # WAVEファイル処理モジュール
040 import struct # 構造体モジュール
050
060 # Cosine wave
070 def create_wave( A, f0, fs, t ): # A 振幅, f0 周波数, fs サンプリング周波数, t 時間[s]
080 point = np.arange( 0, fs*t ) # 数列 0~fs*t-1
090 cos_wave0 = A * np.cos( 2*np.pi*f0 *(point)/fs ) # cos()による数列
100 cos_wave1 = A * np.cos( 2*np.pi*f0/2*(point)/fs ) # cos()による数列
110
120 cos_wave = [0]*len(cos_wave0)*2
130 for i in range(len(cos_wave0)):
140 cos_wave[i*2] = cos_wave0[i]
150 cos_wave[i*2+1] = cos_wave1[i]
160
170 cos_wave = [ int(x * 32767.0) for x in cos_wave ] # 符号付き16ビットの整数列にする(WAVEのデータ)
180
190 wave_data = struct.pack( "h"*len(cos_wave), *cos_wave )
200 w = wave.Wave_write( "st440Hz.wav" )
210 p = (2, 2, fs, len(cos_wave), 'NONE', 'not compressed')
220 #チャンネル数,
230 #サンプルサイズ(バイト), サンプリング周波数, フレーム数,
240 #圧縮形式, 圧縮形式を人に判読可能な形 'NONE'に対して'not compressed'
250 w.setparams( p )
260 w.writeframes( wave_data )
270 w.close()
280
290 print( len(point), len(cos_wave) )
300
310
320 # main #########################
330 A = 1
340 fs = 44100
350 f0 = 440
360 seconds = 5
370 create_wave( A, f0, fs, seconds )
$ python s_wave_st.py ↵
$ aplay st440Hz.wave ↵
440Hzの正弦波(左)と,220Hzの音(右)が同時に再生されます
<参考URL>
https://qiita.com/kinaonao/items/c3f2ef224878fbd232f5
次にWAVEデータを作成しつつ,オーディオデバイスを直接操り,音声を出力します.
$ sudo apt-get install python-pyaudio python3-pyaudio ↵
リスト 5 test_pyaudio.py
001 #coding: utf-8
002 import wave
003 import pyaudio
004
005 def printWaveInfo(wf):
006 """WAVEファイルの情報を取得"""
007 print "チャンネル数:", wf.getnchannels()
008 print "サンプル幅:", wf.getsampwidth()
009 print "サンプリング周波数:", wf.getframerate()
010 print "フレーム数:", wf.getnframes()
011 print "パラメータ:", wf.getparams()
012 print "長さ(秒):", float(wf.getnframes()) / wf.getframerate()
013
014 if __name__ == '__main__':
015 wf = wave.open("440Hz.wav", "r")
016
017 printWaveInfo(wf)
018
019 # ストリームを開く
020 p = pyaudio.PyAudio()
021 stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
022 channels=wf.getnchannels(),
023 rate=wf.getframerate(),
024 output=True)
025
026 # チャンク単位でストリームに出力し音声を再生
027 chunk = 1024
028 data = wf.readframes(chunk)
029 while data != '':
030 stream.write(data)
031 data = wf.readframes(chunk)
032 stream.close()
033 p.terminate()
$ python test_pyaudio.py ↵
結果 音が途切れと途切れになり,現状で対策は見つかっていません.
<参考サイト>http://home.a00.itscom.net/hatada/ssp/pyaudio01.html
本来は,プログラム中のdataに手を加え音を加工する予定でしたがそこまで行けませんでした.結論,Raspberry PiでpyAudioがうまく動きませんでした.少し時間をかけてトライする必要がありそうです.または,OSバージョンのためかも知れません.pyAudioの項については,パソコン上のLinuxで試してみることをお勧めします.時間があれば,C言語で直接デバイスをたたく方法もあるかも知れませんが,OSやアプリのバージョンアップを待った方が早そうです.それよりも,音声出力を使って,独自にラズパイ的なGPIOなどを使ったアプリケーションを作ったほうがいいかもしれません.時間があれば今日動かなかった,これらについても研究してください.
音データを作成しつつ,オーディオデバイスを直接操り,音声を出力します.
$ sudo apt-get install libasound2-dev libesd0 ↵
$ wget http://icrus.org/raspi/alsa_test1.c ↵
$ wget http://icrus.org/raspi/sinewave.c ↵
$ gcc alsa_test1.c -lasound -lm -o alsa_test1 ↵
$ ./alsa_test1 ↵
$ wget http://icrus.org/raspi/alsa_test2.c ↵
$ gcc alsa_test2.c -lasound -lm -o alsa_test2 ↵
$ ./alsa_test2 default off st440Hz.wav ↵
pythonを利用するときも,このCプログラムをラップして呼び出せるようにすると,pythonプログラム中で音データを作成して,デバイスに音出力できるようになります.
<参考サイト/文献>コンピュータ搭載! Linuxオーディオの作り方 CQ出版社刊 2018年1月 https://shop.cqpub.co.jp/hanbai/books/47/47071.html (ダウロードファイルがサイトに有)(第9章 Linux用超定番サウンドI/Oライブラリ ALSA入門)
<その他参考サイト>
http://home.a00.itscom.net/hatada/ssp/pyaudio01.html
PyAudio入門
https://qiita.com/Nyanpy/items/cb4ea8dc4dc01fe56918#2pyaudio
pythonで音楽再生する方法
http://takeshid.hatenadiary.jp/entry/2016/01/10/153503
PyAudioの基本メモ2 音声入出力
https://qiita.com/Nyanpy/items/cb4ea8dc4dc01fe56918
Raspberry Piで音楽(wav/mp3)ファイルを再生する方法 python編
IT女子のラズベリーパイ入門奮闘記
http://deviceplus.jp/hobby/raspberrypi_entry_012/
https://ja.stackoverflow.com/questions/23655/raspberry-pi%E3%81%A7pyaudio%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6wave%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8C%E6%AD%A3%E5%B8%B8%E3%81%AB%E9%B3%B4%E3%82%89%E3%81%AA%E3%81%84
Raspberry PiでPyAudioを使ってwaveファイルが正常に鳴らない
足立工科大学情報通信工学科 2017年11月28日(火)
更新2020,12,16(水)