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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Q&A

解決済

1回答

1185閲覧

Python2.7 バイナリデータ?を整数型に変えたい

slimat

総合スコア57

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

0グッド

0クリップ

投稿2019/04/03 08:20

編集2019/04/09 02:59

こんにちは。

MacOS Mojave・Python2.7環境でマイクから音を拾って、拾った音をwavファイルに書き込むというプログラムを書こうとしてる途中です。下のコードを実行すると画像のように、dataにはBytes型?のオブジェクトが入っているようなのですけど、その次の行で以下のようなエラーが発生しました。これを適切に整数型に変換してfor文などで要素を一つづつ取り出すなどの処理をしたいのですが、どのように書き直したら上手くいくでしょうか。なお、下記のようにしてpyaudioでは16bitで収録するようにしています。

Python

1stream = audio.open(format=pyaudio.paInt16, # 量子化ビット数16bit 2 channels=int(channel), # チャンネル数 3 rate=int(fs), # サンプリング周波数 4 input=True, # 録音のときは input=True 5 frames_per_buffer=size, # バッファのサイズを設定 6 stream_callback = adCallback) # コールバック関数の設定 7 8print data 9intData = struct.unpack("h", data)

イメージ説明

bash

1Traceback (most recent call last): 2 File "5-4.py", line 103, in <module> 3 wavOut(filename) 4 File "5-4.py", line 23, in wavOut 5 intData = struct.unpack("h", data) 6struct.error: unpack requires a string argument of length 2

下はコード全体です。(古いコード)

Python

1#coding: utf-8 2import pyaudio as pyaudio 3import wave 4import time 5import numpy as np 6import matplotlib.pyplot as plt 7import struct 8 9fs = 16000 # サンプリング周波数 [Hz] 10channel = 1 # チャンネル数 11 12####### wavファイル保存関数 13def wavOut(filename): 14 # 書き出し用オブジェクトの生成(ファイル名の決定) 15 out = wave.Wave_write(filename) 16 17 out.setnchannels(channel) # チャンネル数を設定 18 out.setsampwidth(2) # 量子化ビット数16bits(2byte)を設定 19 out.setframerate(fs) # サンプリング周波数を設定 20 21 print data 22 intData = struct.unpack("h", data) 23 for i in intData: 24 if i > 10000: 25 print i 26 if i < 10000: 27 print u"10000未満:" + i 28 29 # dataを結合してwrite 30 out.writeframes(b''.join(data)) # dataはbytes型 31 out.close() 32 33####### プロット関数 34def plotOut(plot_data): 35 36 plt.clf() 37 plt.ylim(-1*2**15, 2**15) # 上下15bit分を表示 38 plt.plot(plot_data) 39 plt.pause(0.01) # plotして0.01秒pause 40 41####### 録音用コーバック関数(別スレッドで動作) 42def adCallback(in_data, frame_count, time_info, status): 43 # dataに録音バッファ(in_data)を追加 44 data.append(in_data) # in_dataは何型? 45 46 # 代入する前にグローバル変数であることを宣言 47 global buf 48 # 取得した録音バッファ(in_data)をint16に変換 49 buf = np.frombuffer(in_data, dtype="int16") 50 51 return (None, pyaudio.paContinue) 52 53 54####### ここからメイン 55if __name__ == '__main__': 56 # バッファのサイズ 57 size = 2**10 58 audio = pyaudio.PyAudio() 59 # オーディオストリームstreamをopen 60 stream = audio.open(format=pyaudio.paInt16, # 量子化ビット数16bit 61 channels=int(channel), # チャンネル数 62 rate=int(fs), # サンプリング周波数 63 input=True, # 録音のときは input=True 64 frames_per_buffer=size, # バッファのサイズを設定 65 stream_callback = adCallback) # コールバック関数の設定 66 67 # 初期化 68 data = [] 69 buf = [] 70 start_time = '' 71 flag = True 72 73 # 録音の開始 74 stream.start_stream() # 別スレッドで録音を開始 75 print ("Recording.") 76 77 # メインスレッド処理 78 while flag == True: 79 # プロット 80 plotOut(buf) # プロット 81 82 # buf中振幅の絶対値が 10000 を超えたら 83 if np.max(np.absolute(buf)) > 10000: 84 start_time = time.time() # 音圧が10000を超えた時刻を取得 85 print ("Time reset.") # 10000を超えたことをメッセージング 86 flag = False 87 88 while flag == False: # 音圧が10000を超えたら 89 plotOut(buf) 90 if time.time() - start_time > 2: # 録音を停止する 91 print ("Finished.") 92 stream.close() 93 audio.terminate() 94 flag = True 95 96 else: # 停止までの残りの秒数をメッセージング 97 print ("Remaining time [s]: " + str(5 - int(time.time() - start_time))) 98 99 # ファイルに保存 100 filename = "record.wav" # 保存ファイル名 101 print ("Write: " + filename) 102 wavOut(filename) 103

修正したコード(新しいコード)

Python

1#coding: utf-8 2import pyaudio as pyaudio 3import wave 4import time 5import numpy as np 6import matplotlib.pyplot as plt 7import struct 8 9fs = 16000 # サンプリング周波数 [Hz] 10channel = 1 # チャンネル数 11 12####### wavファイル保存関数 13def wavOut(filename): 14 # 書き出し用オブジェクトの生成(ファイル名の決定) 15 out = wave.Wave_write(filename) 16 17 out.setnchannels(channel) # チャンネル数を設定 18 out.setsampwidth(2) # 量子化ビット数16bits(2byte)を設定 19 out.setframerate(fs) # サンプリング周波数を設定 20 21 global packed 22 packed = b''.join(data) 23 print u"type(packed): " + str(type(packed)) # str 24 print packed 25 print type() 26 # intData = struct.unpack("h", packed) 27 28 29 30 for i in intData: 31 if i > 10000: 32 print i 33 if i < 10000: 34 print u"10000未満:" + i 35 36 # dataを結合してwrite 37 out.writeframes(packed) # dataはbytes型 38 out.close() 39 40####### プロット関数 41def plotOut(plot_data): 42 43 plt.clf() 44 plt.ylim(-1*2**15, 2**15) # 上下15bit分を表示 45 plt.plot(plot_data) 46 plt.pause(0.01) # plotして0.01秒pause 47 48####### 録音用コーバック関数(別スレッドで動作) 49def adCallback(in_data, frame_count, time_info, status): 50 51 # print u"type(in_data): " + str(type(in_data)) # str 52 data.append(in_data) # 文字列のリスト型オブジェクト 53 print data # \xb6\xff\xba\xff\xb6\xff\xb7の形の出力が得られる 54 55 # 代入する前にグローバル変数であることを宣言 56 global buf 57 58 # 取得した録音バッファ(in_data)をint16に変換 59 # bufはリスト型なので、リストのインデックス0番にndarrayが入るということ? 60 # 4文字の一つの数字に変換していく 61 buf = np.frombuffer(in_data, dtype="int16") # bufはndarrayで、extendsは使えない。 62 # print u"type(buf): " + str(type(buf)) # 再代入してるからndarrayに変化 63 64 return (None, pyaudio.paContinue) 65 66####### ここからメイン 67if __name__ == '__main__': 68 # バッファのサイズ 69 size = 2**10 70 audio = pyaudio.PyAudio() 71 # オーディオストリームstreamをopen 72 stream = audio.open(format=pyaudio.paInt16, # 量子化ビット数16bit 73 channels=int(channel), # チャンネル数 74 rate=int(fs), # サンプリング周波数 75 input=True, # 録音のときは input=True 76 frames_per_buffer=size, # バッファのサイズを設定 77 stream_callback = adCallback) # コールバック関数の設定 78 79 # 初期化 80 data = [] 81 packed = 1 82 buf = False 83 print u"初期化時はtype(buf): " + str(type(buf)) # list 84 start_time = '' 85 flag = True 86 s = 2 87 88 # 録音の開始 89 stream.start_stream() # 別スレッドで録音を開始 90 print "Recording." 91 92 # メインスレッド処理 93 while flag == True: 94 plotOut(buf) # プロット 95 96 # buf中振幅の絶対値が 10000 を超えたら 97 if np.max(np.absolute(buf)) > 10000: 98 start_time = time.time() # その時刻を取得 99 flag = False # このwhileループを抜け出し 100 101 while flag == False: # そして、このループに入る 102 plotOut(buf) # プロット 103 if time.time() - start_time > s: # 検知してからs秒以上経っていたら 104 print "Finished." 105 stream.close() 106 audio.terminate() 107 flag = True # 録音終了 108 109 else: # 停止までの残りの秒数をメッセージング 110 print "Remaining time [s]: " + str(5 - int(time.time() - start_time)) 111 112 # ファイルに保存 113 filename = "record.wav" # 保存ファイル名 114 print "Write down wav format: " + filename 115 print u"type(data): " + str(type(data)) # list 116 wavOut(filename)

文字化けした出力の画像
イメージ説明

よろしくお願い致します。

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

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

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

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

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

tiitoi

2019/04/03 08:22

バイナリデータをパースするにはバイナリデータがどのようなフォーマットかわからないとできないと思いますよ。
slimat

2019/04/03 08:27

今、質問文を修正したのですが、この情報だと不足でしょうか。
tiitoi

2019/04/03 08:37 編集

data という変数はどのような変数なのでしょうか?
slimat

2019/04/03 08:44

コード全体を追記いたしました。
guest

回答1

0

ベストアンサー

提示コードの動作が確認できないためdataの内容がいまひとつ分かりませんが、struct.unpack("h", data)を利用しているということは、バイト列dataの先頭から2バイトずつ符号有のshortに変換したいということでしょうか。
であれば以下のようなループでできます。
なお、当然ながらdataの長さは2の倍数である必要があります。
参考:7.3. struct --- 文字列データをパックされたバイナリデータとして解釈する

Python

1import struct 2data = 'd\xff\xe5\xff' 3for i in range(0,len(data),2): 4 n = struct.unpack("h", data[i:i+2]) 5 print n[0] 6""" 7-156 8-27 9"""

追記:data変数値の確認表示

Python

1import struct 2data = 'd\xff\xe5\xff' 3 4print len(data) # (13文字ではなく)4 byte 5print type(data)# <type 'str'> 6 7# バイト列をそのまま文字列として出力。 8# ASCIIコードで文字として表現できない部分は文字化けする 9print data # d・ 10 11# バイト列をreprした結果を出力。 12# ASCIIコードで文字として表現できない部分は16進(\x??)表示される 13# (dataの中身は同じバイト列) 14print repr(data) # 'd\xff\xe5\xff' 15 16# バイト列をlist化した結果を出力。 17# repr と同じように16進表示される 18print list(data) # ['d', '\xff', '\xe5', '\xff'] 19 20# リスト型を出力。 21# 各要素はrepr と同じように16進表示される 22data = ['d\xff\xe5\xff'] 23print data # ['d\xff\xe5\xff']

投稿2019/04/05 09:02

編集2019/04/09 07:10
can110

総合スコア38233

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

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

slimat

2019/04/06 08:38

回答有り難うございます。 この辺りのことに関しては初心者なのでうまく伝えれないと思います。あらかじめご了承下さい。 そもそもなのですが、bytes型というのがよく分かっていません。printでターミナルに変数の値を出力した時、文字化けするものがあります。例えば、(古いコードの方では確認済み)adCallback関数内でin_dataをprintすると図のように表示されます(このコメントの投稿時にはアップロードできていません)。一方、"修正したコード"(このコメント投稿後に追記する)のadCallback関数内の "print data # \xb6\xff\xba\xff\xb6\xff\xb7の形の出力が得られる" の部分のprintで出力したものだと、コメント表記の通りにいかにもbytes型?っぽいのが出力されます(私の中ではまともに表示されないものこそがbytes型だと思っているので)。ただ私の中では文字化けしない方もbytes型なのかな?という考えも出てきて混乱しています。 このコードはマイクから拾う時に"format=pyaudio.paInt16"という表記があるので、一つの値に対して16ビットの割当でデータをメモリに書き込んでいると考えています。 少し話がそれるのですが、質問文の、古い方のコードのwavOut内のdata変数‥①の値は"\xb6\xff\xb7..."(bytes型じゃなくて文字列型)のリストになっていました。なので、コメント投稿後に新しいコードを追記したいと思います。新しいコードではdata変数‥①の代わりに、packed変数に、join関数を使って一つの文字列値の"\xb6\xff\xb7..."を代入しました。しかし、packed変数をprintしてみると"\xb6\xff\xb7..."ではなく、文字化けしたものが出力されました。 文字化けするものと、"\xb6\xff\xb7..."ではどちらがbytes型なのでしょうか。
can110

2019/04/08 07:23

まず前提としてpython2にはbyte型はありません。その代わりにstr型が使われます。 そのstr型に格納されているバイト列を文字列とみなすかバイナリとみなすかは利用者にまかされています。 提示コードにおいてpyaudioの仕様、動作は確認していませんが、data変数にはバイナリとしてデータが格納されていると思います。ですのでそのままprint dataすると「文字化けする」のが正解です。 ただ「(bytes型じゃなくて文字列型)のリストになっていました。」という動作が気になります。 修正後の回答コードのように「print list(data)」とすると、そのような表示になりますが。
slimat

2019/04/09 06:56 編集

>str型に格納されているバイト列を文字列とみなすかバイナリとみなすか python2ではbytes型オブジェクトがないとは思いもよりませんでした。 >ただ「(bytes型じゃなくて文字列型)のリストになっていました。」という動作が気になります。 質問文の古い方のスクリプトの、wavOut関数内「print data」の部分の出力は以下のような形をしています。 ['\xff\xb3\xff\xb4\xff\xdb\xff\xd6\xff\xd3\xff\xd5','\xff\xcd\xff\xce\xff\xd3\xff\xcb\xff\xca\xff\','xcd\xff\xcd\xff\xd1\xff\xd6\xff\xde\','xff\xe4\xff\xde\xff\xe5\xff\xe8\xff\xdf\xff','\xdd\xff\xdc\xff\xd9\xff\xd8\xff\xd8\xff\xd9\xff\xda\xff'] 御回答の内容の話なのですが、 >data = 'd\xff\xe5\xff' >print len(data) # (13文字ではなく)4 byte これは、16進数で表されているように思うのですが、それだとxffで1バイト、xe5で1バイト、xffで1バイトなので合計3バイトに思ってしまいます。しかし、なぜ4バイトなのでしょうか。 また、先頭のdは何を表しているのでしょうか。
can110

2019/04/09 07:08

> 質問文の古い方のスクリプトの、wavOut関数内「print data」の部分の出力は以下のような形をしています。 なるほど。この時のdataはリスト型ですね。 リスト型の(各要素の)出力時はrepr結果と同じ出力になるようです。 >~また、先頭のdは何を表しているのでしょうか。 先頭文字「d」は単なる1文字=1バイトデータを表します。よって合計4バイトになります。 ちなみに文字「d」のASCIIコード値は0x64なので\x??表記すると data = '\x64\xff\xe5\xff' と記述でき、同じデータ内容になります。
slimat

2019/04/09 08:42

>先頭文字「d」は単なる1文字=1バイトデータを表します。よって合計4バイトになります。 そういうことなのですか。ありがとうございます。 struct.unpack("h", packed)を実行して、packed変数に代入されているバイト列をunpackしたいのですが、そのコード前でprint repr(packed)したところ、下の出力が得られました(一部)。これだと、フォーマットはhではだめなのでしょうか。print str(len(packed))を実行すると、106496と出力されました。 \x00\x17\x00 \x00!\x00%\x00!\x00\x18\x00\x15\x00\x14\x00\x1d\x00"\x00\'\x00\'\x00(\x00+\x00/\x001\x00-\x00/\x001\x003\x00/\x00.\x007\x004\x00<\x00@\x00=\x00B\x00B\
slimat

2019/04/09 08:45

すみません。一気にunpackしようとしてました。ご回答の通り、forで2バイトずつずらして、やってみます。
slimat

2019/04/09 09:21

今、unpackすることに成功しました。 フォーマットはhでいけました。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問