# mk_sin_wave.py
import numpy as np
sample_rate = 8000# サンプリングレート(samples/seconds)
frequency=1000 # 単位 Hz
seconds = 0.2 # 生成時間(秒)
CHANK = 1024
# 1KHzの波形を生成-----------------------
# n=1つのCHANKに必要な1KH波形の数=sample_rateHzの周期の1つのCHANK当たりの時間 ÷ frequency Hzの周期
n = (1/sample_rate)*CHANK/(1/frequency)
print( f"1つのCHANK(={CHANK})に必要な{frequency}Hz波形の数={n}")
dx = 2* np.pi*n / (CHANK)
a=0x07fff * np.sin(np.arange(0, sample_rate * seconds, dx))
a=a.astype(np.int16)
print(a, a.shape)
import matplotlib.pyplot as plt
plt.plot(a)
plt.show()
barray = a.tobytes()
print("生成バイナリのbyte数", len(barray))
def save_wave_file( barray, path="test.wav"):
''' barray の16bitリトルエンディアンバイト列から、未圧縮でpathのサウンドファイルを作る'''
import wave
wavefile = wave.open(path, 'wb') # waveファイルをバイナリ保存用として開く。
wavefile.setnchannels(1) # モノラル(単一の音信号)
wavefile.setsampwidth(2) # 2byteのデータ群と録音する指定
wavefile.setframerate(sample_rate) # サンプリングレート
wavefile.writeframes(barray) # 上記で設定した属性で、ファイルに出力
wavefile.close()
save_wave_file( barray) # ファイル生成
def print_inf_wave_file( path="test.wav"):
import wave
wavefile = wave.open(path, mode='rb')
print(f"-----{path}ファイルの情報-----")
print('type: ', type(wavefile))
print('チャンネル数:', wavefile.getnchannels()) # モノラルなら1,ステレオなら2
print('サンプル幅:', wavefile.getsampwidth()) # バイト数 (1byte=8bit)
print('サンプリング周波数:', wavefile.getframerate()) # CDは44100Hz
print('フレーム数:', wavefile.getnframes()) # サンプリング周波数で割れば時間
params=wavefile.getparams()# 上記+αのパラメータクラスを返す
print('パラメータ',type(params) ,":", params)
print_inf_wave_file() # ファイル情報の確認
1つのCHANK(=1024)に必要な1000Hz波形の数=128.0 [ 0 23169 32767 ... 23169 0 -23169] (2038,) 生成バイナリのbyte数 4076 -----test.wavファイルの情報----- type:チャンネル数: 1 サンプル幅: 2 サンプリング周波数: 8000 フレーム数: 2038 パラメータ : _wave_params(nchannels=1, sampwidth=2, framerate=8000, nframes=2038, comptype='NONE', compname='not compressed')
C:\Windows\system32>pip install pyaudio
Collecting pyaudio
Downloading PyAudio-0.2.11-cp36-cp36m-win_amd64.whl (52kB)
100% |????????????????????????????????| 61kB 3.4MB/s
Installing collected packages: pyaudio
Successfully installed pyaudio-0.2.11
C:\Windows\system32>
import sys
import time
import _thread # Python3では、「_thread」を使う
import pyaudio
import wave
key_code = 0 #キーが押されたらキーデータがセット
def input_key(): # スレッドで実行予定のキー入力関数
print("キー入力待機")
c = sys.stdin.read(1) # 1文字入力
global key_code
key_code = c
# 新しいスレッドを開始して、input_keyを実行させ、そのIDを返します。
thread_id = _thread.start_new_thread(input_key, ())
FORMAT = pyaudio.paInt16 # 2byteのデータ群と録音する指定
CHUNK=1024 # 1回のinput で 1024個のデータを録音(サイズは1024 × 2 byteのバイナリ)
RATE=44100
CHANNELS=1
audio=pyaudio.PyAudio()
stream=audio.open(format = FORMAT,
channels = CHANNELS,
rate = RATE,
frames_per_buffer = CHUNK,
input = True,
output = True) # inputとoutputを同時にTrueにする
print("録音スタート")
frames = []
while key_code == 0:
input = stream.read(CHUNK) # 録音データを取得 (CHUNK×2byte のバイナリ)
frames.append(input) # 録音されたバイナリデータを配列の最後の要素として追加している。
output = stream.write(input)
stream.stop_stream()
stream.close()
audio.terminate()
print("録音ストップ")
wavefile = wave.open("test.wav", 'wb') # waveファイルをバイナリ保存用として開く。
wavefile.setnchannels(CHANNELS)
wavefile.setsampwidth(audio.get_sample_size(FORMAT))
wavefile.setframerate(RATE)
wavefile.writeframes(b''.join(frames)) # 上記で設定した属性で、ファイルに出力
wavefile.close()
# グラフの描画
import numpy as np
def array_16_from_chunk(frames, chunkSize=1028, bigFlag=False): # チャンクのバイナリの配列から1次 16bit整数に変換
a = []
for i in range(len(frames)):
# a += array_16_from_binary(frames[i], bigFlag ) #2バイト、リトルエンディアンで変換と同じ処理
a += np.frombuffer(frames[i], dtype="int16").tolist() # 上記と同じ結果が得られるnumpyのメソッド
return a
import matplotlib.pyplot as plt
a = array_16_from_chunk(frames, True) # バイナリの配列から、int のリストに変換
plt.plot(np.arange(len(a)), np.array(a), label='サウンド波形')
plt.show()
import pyaudio # 録音や再生に使う
import wave # waveファイル読み取り用
CHUNK = 1024
filename="test.wav"
wavefile = wave.open(filename, 'rb') # waveファイルを読み取りでバイナリオープン
audio = pyaudio.PyAudio()
sampwidth = wavefile.getsampwidth() #サンプル幅
print("sampwidth:", sampwidth)
format=audio.get_format_from_width(sampwidth) # ストリームを読み書きするときのデータ型
print("format:", format) # ステレオかモノラルかの選択 1でモノラル 2でステレオ
channels=wavefile.getnchannels() # ステレオかモノラルかの選択 1でモノラル 2でステレオ
print("channels:", channels)
rate=wavefile.getframerate() # サンプル周波数
print("ramerate:", rate)
stream = audio.open(format=format,channels=channels,rate=rate,output=True)
# 上記は、引数で指定する順番が定義と違うので、引数名を指定して実行させている。
num=0; # チャンクのカウント
data = wavefile.readframes(CHUNK) # 1024個読み取り
while len(data) > 0:
num += 1
stream.write(data) # ストリームへの書き込みで、これで音が出力される。
data = wavefile.readframes(CHUNK) # ファイルから1024個*2個の
print("チャンク数",num)
stream.stop_stream()
stream.close()
audio.terminate()

import numpy as np
import wave
wavefile = wave.open("test.wav", "r")
nframes = wavefile.getnframes() # フレーム数(データの個数)
print("nframes:" , nframes) # 実行例: nframes: 88064
framerate = wavefile.getframerate() # フレームレート(1秒間のデータ出力数)
print("framerate:", framerate) # 実行例: framerate: 44100
buffer = wavefile.readframes(nframes) # ファイルからの読み取り(読み取りフレーム数)で、ファイルからバイナリのデータ部を読み取り、返す。
wavefile.close() # ファイルを閉じる
# print(buffer) # b'\xbe\xff-\xfeS・・・・・・・\xb6\xfd\x9a\xfdx\xfd'のようなバイナリで得られる。
y1 = np.frombuffer(buffer, dtype="int16") # bufferのバイナリが、16bit整数(リトルエンディアン)である前提で、1次numpyの配列に変換
print(y1) # 実行例: [ -66 -467 -941 ..., -586 -614 -648]
print("type:",type(y1)) # 実行例: type: <class 'numpy.ndarray'>
print("type:",type(y1[0])) # 実行例: type: <class 'numpy.int16'>
print(len(y1), '数' ) # 88064 数
y1 = np.delete(y1, range(0,26000)) # 先頭 26000個のデータを削除
y1 = np.delete(y1, range( len(y1)-32000,len(y1) ) ) # 後ろ 32000個のデータを削除
print(y1) # 先頭 26000個のデータを削除
max = y1.max()
min = y1.min()
print("max:", max ,"min:", min )
raise_y=1 # 倍率算出
if max >= abs(min):
raise_y = 32767 / max
else :
raise_y = abs(32767 / min)
y1 = y1 * raise_y # フルスケールを使う倍率変換
y1 = y1.astype(np.int16)
import matplotlib.pyplot as plt
t1 = np.arange(0, len(y1)) / float(framerate) # プロットのx軸用データ生成
plt.plot(t1, y1, 'r')
plt.xlabel('Time [sec]')
plt.show()
# numpy の配列を wave モジュールを使って wav ファイルに保存
w = wave.Wave_write("output.wav")
w.setnchannels(1) # チャンネル数
w.setsampwidth(2) # サンプル(量子化)サイズで、16bitなら2(バイト)。
w.setframerate(44100) # チャンネル数
w.writeframes(y1) # 保存するnumpy の配列
w.close()
一定時間だけ録音して、framesの配列に記憶したバイナリー記憶します。
numb=100 で、このチャンクの操作回数だけ録音です。
その後に、それを再生します。
'''
一定時間だけ録音して、framesの配列に記憶したバイナリー記憶します。
numb=100 で、このチャンクの操作回数だけ録音です。
その後に、それを再生します。
'''
import pyaudio # 録音や再生に使う
audio = pyaudio.PyAudio()
FORMAT = pyaudio.paInt16 # 2byteのデータ群と録音する指定
CHUNK=1024 # 1回のinput で 1024個のデータを録音(サイズは1024 × 2 byteのバイナリ)
RATE=32000
CHANNELS=1
stream=audio.open(format = FORMAT,
channels = CHANNELS,
rate = RATE,
frames_per_buffer = CHUNK,
input = True,
output = True) # inputとoutputを同時にTrueにする
numb=100 # チャンクの操作回数
print("録音スタート", int( (1/RATE) *CHUNK*numb*1000), "ミリ秒")
frames = []
for idx in range(numb):
d = stream.read(CHUNK) # 録音データを取得 (CHUNK×2byte のバイナリ)
frames.append(d) # 録音されたバイナリデータを配列の最後の要素として追加している。
# 次のコードを有効にすると上記録音の代わりにサイン波形の音を埋め込む
'''
import math
import numpy as np
frames = []
for idx in range(100):
dx = np.pi/16
a = (0x1ff * np.sin(np.arange(0, dx * 1024, dx))).astype(np.int16)+0x1ff
#from plotting import plotting
#plotting(np.arange(1024),a, True)
#exit()
d = a.tobytes()
frames.append(d)
'''
input("Enter で再生します。>>>")
idx=0 # チャンクのカウント
while idx < len(frames):
stream.write(frames[idx]) # ストリームへの書き込みで、これで音が出力される。
idx += 1
stream.stop_stream()
stream.close()
audio.terminate()
上記コメントは、録音のサイン波の生成データで記憶域を埋める処理です。 サウンドデータ生成の手法参考になるでしょう。
サウンドの待ち行列と、再生スレッドを作っています。
mainでは確認用で、1KHzのsin波の音を、待ち行列に入れて再生しています。再生終了前でEnterでスレッドを終えることができます。
解像度(ビットレート)は、pyaudio.paInt16の指定により、16bit符号付きデータです
sample_rate を変更しても、1KHzのsin波を作っているので、聞き比べ可能です。
音が鳴る長さはsample_rate を変更すると、音が鳴る期間が変わります。(forの繰り返し数で変更できます)
play_sin.py
import numpy as np
import threading
from collections import deque
from time import sleep
import pyaudio
# 再生関連関数定義 ---------------ここから
audio = pyaudio.PyAudio()
# サンプリングレート(1秒間で何個のデータを使うかの値)の指定
sample_rate = 48000 # 映像業界の音の標準(DVD)
sample_rate = 44100 # 音楽業界の標準(CD-DA)
sample_rate = 32000 # FMステレオ放送中継
sample_rate = 16000 # 高音質IP電話など
sample_rate = 8000 # 電話(ISDNなど)
stream=audio.open(format = pyaudio.paInt16, # 2byteのデータ群と録音する指定
channels = 1,
rate = sample_rate, # サンプリングレート(1秒間で何個のデータを使うかの値)
frames_per_buffer = 1024,#1回の処理で使うサイズは1024 × 2 =2048byte
input = False, #録音は使わない
output = True) # 再生をTrueにする
queue = deque() #再生待ち行列
lock = threading.Lock() # Lockモジュール生成
def set_data(data):# 再生データをキューにセットする。
lock.acquire() # 排他制御開始
queue.append(data)
lock.release() # 排他制御解除
flag_playing = True
def playing():# 再生スレッド関数
while flag_playing:
if len(queue) == 0:
sleep(0.0001)
continue
lock.acquire() # 排他制御開始
data=queue.popleft()
lock.release() # 排他制御解除
stream.write(data) # ストリームへの書き込みで、これで音が出力される。
#print(data)
# 再生関連関数定義 ---------------ここまで
snd_id = threading.Thread(target=playing) #再生部分を別スレッドにする
snd_id.start() #再生スレッドをスタート
# 1KHzの波形を生成して鳴らす-----------------------
# n=1CHANKに必要な1KH波形の数=sample_rateHzの周期の1CHANK当たりの時間 ÷ 1KHの周期
n = (1/sample_rate)*1024/(1/1000)
print( "1CHANKに必要な1KH波形の数=", n)
dx = 2* np.pi*n / (1024)
a=0x1ff * np.sin(np.arange(0, dx * 1024, dx))
a=a.astype(np.int16) + 0x1ff
print(a, a.shape)
import matplotlib.pyplot as plt
plt.plot(a)
plt.show()
d = a.tobytes()
print(d, len(d))
for idx in range(10):
set_data(d) # sin波のバイナリーデータ1CHANK分をキューに入れる(それが再生される)
input("終了 Wait Enter>>>")
flag_playing = False
参考: https://people.csail.mit.edu/hubert/pyaudio/docs/#class-stream