最近使用 Python 的 Struct Unpack 时出现问题
Problem with using Python's Struct Unpack Recently
在 Python 脚本中,我使用以下命令录制了一些音频:
import subprocess
import wave
self.rec_args =['arecord', '--device=pulse', '-f', 'cd', '-t', '/home/USER/audioFile.wav')]
self.rec = subprocess.Popen(self.rec_args, shell=False)
然后我打开文件:
self.wave_file = wave.open('/home/USER/audioFile.wav', 'rb')
并获取通道数 (2) 和采样率 (44100):
self.num_channels, self.sample_rate = self.getWaveParameters(self.wave_file)
然后我可以使用 getWaveIntegers 的代码来获取声音的振幅:
wi = self.getWaveIntegers(self.wave_file, self.sample_rate, self.num_channels, 0, 20)
其中 clipStart = 0,然后要分析的样本长度 = 20 秒。
########################################
def getWaveIntegers(self, stream, sample_rate, num_channels, clipStart, timeLength):
#
# stream = the already opened wave file to navigate through
# clipStart = the starting position of the clip in the wave file
# timeLength = the length of time of the clip to take from the wave file
# set start of clip
startPosition = sample_rate * clipStart # converts clipStart time to samplewidth
stream.setpos(startPosition) # set the starting position in the wave file
# length of clip
clipLength = sample_rate*timeLength*num_channels # timeLength in terms of channels and sample rate ####?
clipData = stream.readframes(sample_rate*timeLength) # the clip of the wave file starting at startPosition for time in sample_rate
integer_data = wave.struct.unpack("%dh"%(clipLength), clipData)
channels = [ [] for time in range(num_channels) ]
for index, value in enumerate(integer_data):
bucket = index % num_channels
channels[bucket].append(value)
del clipData
# keep only left? channel
sampleChannel = []
for c in range(0, len(channels[0]):
sampleChannel.append(abs(int(channels[0][c]/100)))
return sampleChannel
########################################
def getWaveParameters(self, stream):
#
num_channels = stream.getnchannels()
sample_rate = stream.getframerate()
sample_width = stream.getsampwidth()
num_frames = stream.getnframes()
raw_data = stream.readframes( num_frames ) # Returns byte data
total_samples = num_frames * num_channels
if sample_width == 1:
fmt = "%iB" % total_samples # read unsigned chars
elif sample_width == 2:
fmt = "%ih" % total_samples # read signed 2 byte shorts
else:
raise ValueError("Only supports 8 and 16 bit audio formats.")
return num_channels, sample_rate#, sample_width, num_frames, total_samples, fmt # do not need these values for this code
########################################
直到最近,它一直正常工作。
我现在收到以下错误:
Traceback (most recent call last):
File "myfile.py", line 167, in getWaveIntegers
integer_data = wave.struct.unpack("%dh"%(clipLength), clipData)
struct.error: unpack requires a buffer of 3528000 bytes
有些文件的clipLength好像是:1764000字节(刚好是错误的3528000字节的一半)
我注意到在过去几天里各种 Python 库更新到以下版本:
Python 3.6:amd64 (3.6.8-1~18.04.3, 3.6.9-1~18.04)
我尝试了 https://docs.python.org/3.6/library/struct.html
中提供的示例
>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
当我在我的系统(Python 3.6.9(默认,2019 年 11 月 7 日,10:44:02)和 linux 上的 [GCC 8.3.0] 上执行此操作时:
>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x01\x00\x02\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'
长度是示例中长度的两倍。有:
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
我收到错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
struct.error: unpack requires a buffer of 16 bytes
但当我这样做时:
>>> unpack('hhl', b'\x01\x00\x02\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00')
(1, 2, 3)
我答对了。
我是不是做了什么奇怪的事情,或者是 Python 更新中的错误。老实说,我并不完全理解 struct 命令。非常感谢您阅读像我这样的吹毛求疵的post!
约翰
如上所述,我无法找出 struct unpack 的问题,所以我围绕它进行了编程并使用了 numpy。所以 getWaveIntegers 的代码应该是:
########################################
import numpy
def getWaveIntegers(self, stream, sample_rate, num_channels, clipStart, timeLength):
#
# stream = the already opened wave file to navigate through
# clipStart = the starting position of the clip in the wave file
# timeLength = the length of time of the clip to take from the wave file
# set start of clip
startPosition = sample_rate * clipStart # converts clipStart time to samplewidth
stream.setpos(startPosition) # set the starting position in the wave file
# length of clip
clipLength = sample_rate*timeLength*num_channels # timeLength in terms of channels and sample rate ####?
clipData = stream.readframes(sample_rate*timeLength) # the clip of the wave file starting at startPosition for time in sample_rate
signal = numpy.fromstring(clipData, "Int16")
#
result = numpy.fromstring(clipData, dtype=numpy.int16)
chunk_length = int(len(result) / num_channels)
assert chunk_length == int(chunk_length)
result = numpy.reshape(result, (chunk_length, num_channels))
# keep only left channel and only 10 samples per second
leftChannel = []
for c in range(0, len(result[:, 0]), 50):
leftChannel.append(abs(int(result[:, 0][c]/100))) # the absolute value of the integer of the frequency divided by 100 (for diagramatic purposes)
return leftChannel
########################################
我希望这对以后的人有所帮助。
在 Python 脚本中,我使用以下命令录制了一些音频:
import subprocess
import wave
self.rec_args =['arecord', '--device=pulse', '-f', 'cd', '-t', '/home/USER/audioFile.wav')]
self.rec = subprocess.Popen(self.rec_args, shell=False)
然后我打开文件:
self.wave_file = wave.open('/home/USER/audioFile.wav', 'rb')
并获取通道数 (2) 和采样率 (44100):
self.num_channels, self.sample_rate = self.getWaveParameters(self.wave_file)
然后我可以使用 getWaveIntegers 的代码来获取声音的振幅:
wi = self.getWaveIntegers(self.wave_file, self.sample_rate, self.num_channels, 0, 20)
其中 clipStart = 0,然后要分析的样本长度 = 20 秒。
########################################
def getWaveIntegers(self, stream, sample_rate, num_channels, clipStart, timeLength):
#
# stream = the already opened wave file to navigate through
# clipStart = the starting position of the clip in the wave file
# timeLength = the length of time of the clip to take from the wave file
# set start of clip
startPosition = sample_rate * clipStart # converts clipStart time to samplewidth
stream.setpos(startPosition) # set the starting position in the wave file
# length of clip
clipLength = sample_rate*timeLength*num_channels # timeLength in terms of channels and sample rate ####?
clipData = stream.readframes(sample_rate*timeLength) # the clip of the wave file starting at startPosition for time in sample_rate
integer_data = wave.struct.unpack("%dh"%(clipLength), clipData)
channels = [ [] for time in range(num_channels) ]
for index, value in enumerate(integer_data):
bucket = index % num_channels
channels[bucket].append(value)
del clipData
# keep only left? channel
sampleChannel = []
for c in range(0, len(channels[0]):
sampleChannel.append(abs(int(channels[0][c]/100)))
return sampleChannel
########################################
def getWaveParameters(self, stream):
#
num_channels = stream.getnchannels()
sample_rate = stream.getframerate()
sample_width = stream.getsampwidth()
num_frames = stream.getnframes()
raw_data = stream.readframes( num_frames ) # Returns byte data
total_samples = num_frames * num_channels
if sample_width == 1:
fmt = "%iB" % total_samples # read unsigned chars
elif sample_width == 2:
fmt = "%ih" % total_samples # read signed 2 byte shorts
else:
raise ValueError("Only supports 8 and 16 bit audio formats.")
return num_channels, sample_rate#, sample_width, num_frames, total_samples, fmt # do not need these values for this code
########################################
直到最近,它一直正常工作。 我现在收到以下错误:
Traceback (most recent call last):
File "myfile.py", line 167, in getWaveIntegers
integer_data = wave.struct.unpack("%dh"%(clipLength), clipData)
struct.error: unpack requires a buffer of 3528000 bytes
有些文件的clipLength好像是:1764000字节(刚好是错误的3528000字节的一半)
我注意到在过去几天里各种 Python 库更新到以下版本: Python 3.6:amd64 (3.6.8-1~18.04.3, 3.6.9-1~18.04)
我尝试了 https://docs.python.org/3.6/library/struct.html
中提供的示例>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
当我在我的系统(Python 3.6.9(默认,2019 年 11 月 7 日,10:44:02)和 linux 上的 [GCC 8.3.0] 上执行此操作时:
>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x01\x00\x02\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'
长度是示例中长度的两倍。有:
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
我收到错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
struct.error: unpack requires a buffer of 16 bytes
但当我这样做时:
>>> unpack('hhl', b'\x01\x00\x02\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00')
(1, 2, 3)
我答对了。
我是不是做了什么奇怪的事情,或者是 Python 更新中的错误。老实说,我并不完全理解 struct 命令。非常感谢您阅读像我这样的吹毛求疵的post! 约翰
如上所述,我无法找出 struct unpack 的问题,所以我围绕它进行了编程并使用了 numpy。所以 getWaveIntegers 的代码应该是:
########################################
import numpy
def getWaveIntegers(self, stream, sample_rate, num_channels, clipStart, timeLength):
#
# stream = the already opened wave file to navigate through
# clipStart = the starting position of the clip in the wave file
# timeLength = the length of time of the clip to take from the wave file
# set start of clip
startPosition = sample_rate * clipStart # converts clipStart time to samplewidth
stream.setpos(startPosition) # set the starting position in the wave file
# length of clip
clipLength = sample_rate*timeLength*num_channels # timeLength in terms of channels and sample rate ####?
clipData = stream.readframes(sample_rate*timeLength) # the clip of the wave file starting at startPosition for time in sample_rate
signal = numpy.fromstring(clipData, "Int16")
#
result = numpy.fromstring(clipData, dtype=numpy.int16)
chunk_length = int(len(result) / num_channels)
assert chunk_length == int(chunk_length)
result = numpy.reshape(result, (chunk_length, num_channels))
# keep only left channel and only 10 samples per second
leftChannel = []
for c in range(0, len(result[:, 0]), 50):
leftChannel.append(abs(int(result[:, 0][c]/100))) # the absolute value of the integer of the frequency divided by 100 (for diagramatic purposes)
return leftChannel
########################################
我希望这对以后的人有所帮助。