def audio_data_converter(raw_data: bytes, in_settings: AudioSettings, out_settings: AudioSettings) -> bytes: in_sample_rate = in_settings.sample_rate out_sample_rate = out_settings.sample_rate in_sample_width = in_settings.sample_width out_sample_width = out_settings.sample_width if in_settings.channels != out_settings.channels: raise RuntimeError( 'Can not convert audio data. The number of channels must be the same.' ) if in_sample_rate == out_sample_rate and in_sample_width == out_sample_width: return raw_data # make sure unsigned 8-bit audio (which uses unsigned samples) # is handled like higher sample width audio (which uses signed samples) if in_sample_width == 1: # subtract 128 from every sample to make them act like signed samples raw_data = audioop.bias(raw_data, 1, -128) if in_sample_rate != out_sample_rate: raw_data, _ = audioop.ratecv(raw_data, in_sample_width, in_settings.channels, in_sample_rate, out_sample_rate, None) if in_sample_width != out_sample_width: # we're converting the audio into 24-bit # workaround for https://bugs.python.org/issue12866 if out_sample_width == 3: # convert audio into 32-bit first, which is always supported raw_data = audioop.lin2lin(raw_data, in_sample_width, 4) try: # test whether 24-bit audio is supported # for example, ``audioop`` in Python 3.3 and below don't support # sample width 3, while Python 3.4+ do audioop.bias(b"", 3, 0) except audioop.error: # this version of audioop doesn't support 24-bit audio # (probably Python 3.3 or less) # # since we're in little endian, # we discard the first byte from each 32-bit sample to get a 24-bit sample raw_data = b"".join(raw_data[i + 1:i + 4] for i in range(0, len(raw_data), 4)) else: # 24-bit audio fully supported, we don't need to shim anything raw_data = audioop.lin2lin(raw_data, in_sample_width, out_sample_width) else: raw_data = audioop.lin2lin(raw_data, in_sample_width, out_sample_width) # if the output is 8-bit audio with unsigned samples, # convert the samples we've been treating as signed to unsigned again if out_sample_width == 1: # add 128 to every sample to make them act like unsigned samples again raw_data = audioop.bias(raw_data, 1, 128) return raw_data
def get_raw_data(self, convert_rate=None, convert_width=None): """ Returns a byte string representing the raw frame data for the audio represented by the ``AudioData`` instance. If ``convert_rate`` is specified and the audio sample rate is not ``convert_rate`` Hz, the resulting audio is resampled to match. If ``convert_width`` is specified and the audio samples are not ``convert_width`` bytes each, the resulting audio is converted to match. Writing these bytes directly to a file results in a valid `RAW/PCM audio file <https://en.wikipedia.org/wiki/Raw_audio_format>`__. """ assert convert_rate is None or convert_rate > 0, "Sample rate to convert to must be a positive integer" assert convert_width is None or ( convert_width % 1 == 0 and 1 <= convert_width <= 4 ), "Sample width to convert to must be between 1 and 4 inclusive" raw_data = self.frame_data # make sure unsigned 8-bit audio (which uses unsigned samples) is handled like higher sample width audio # (which uses signed samples) if self.sample_width == 1: raw_data = audioop.bias( raw_data, 1, -128 ) # subtract 128 from every sample to make them act like signed # samples # resample audio at the desired rate if specified if convert_rate is not None and self.sample_rate != convert_rate: raw_data, _ = audioop.ratecv(raw_data, self.sample_width, 1, self.sample_rate, convert_rate, None) # convert samples to desired sample width if specified if convert_width is not None and self.sample_width != convert_width: if convert_width == 3: # we're converting the audio into 24-bit (workaround for https://bugs.python.org/issue12866) raw_data = audioop.lin2lin( raw_data, self.sample_width, 4 ) # convert audio into 32-bit first, which is always supported try: audioop.bias( b"", 3, 0 ) # test whether 24-bit audio is supported (for example, ``audioop`` in Python 3.3 and below don't support sample width 3, while Python 3.4+ do) except audioop.error: # this version of audioop doesn't support 24-bit audio (probably Python 3.3 or less) raw_data = b"".join( raw_data[i + 1:i + 4] for i in range(0, len(raw_data), 4) ) # since we're in little endian, we discard the first byte from each 32-bit sample to get a 24-bit sample else: # 24-bit audio fully supported, we don't need to shim anything raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) else: raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) # if the output is 8-bit audio with unsigned samples, convert the samples we've been treating as signed to unsigned again if convert_width == 1: raw_data = audioop.bias( raw_data, 1, 128 ) # add 128 to every sample to make them act like unsigned samples again return raw_data
def get_raw_data(self, convert_rate=None, convert_width=None): """ 返回一个字节字符串,表示AudioData实例音频的原始帧数据。 如果``convert_rate``已经被指定并且音频采样率不是指定的``convert_rate`` Hz,则重新采样生成的音频以达到匹配。 如果``convert_width``已经被指定并且音频采样不是指定的``convert_width``字节,则转换生成的音频以达到匹配。 将这些字节直接写入文件会生成有效的RAW / PCM音频文件 <https://en.wikipedia.org/wiki/Raw_audio_format>`__. """ #@noter:崔冰 #@description:将采样率和样本宽度都转换成指定数值,获得原始音频数据 #@param string convert_rate:需转换成的采样率 #@param string convert_width:需转换成的样本宽度 #@return 返回一个字节字符串,表示AudioData实例音频的原始帧数据 assert convert_rate is None or convert_rate > 0, "Sample rate to convert to must be a positive integer" #需要转换成的采样率必须是正整数 assert convert_width is None or ( convert_width % 1 == 0 and 1 <= convert_width <= 4 ), "Sample width to convert to must be between 1 and 4 inclusive" #需要转换成的采样宽度必须在1——4之间(包括1和4) raw_data = self.frame_data # 确保无符号的8位音频(使用无符号样本) 被处理为更高采样宽度的音频 (使用有符号样本) if self.sample_width == 1: raw_data = audioop.bias(raw_data, 1, -128) # 从每个样本中减去128,使它们像有符号样本一样 # 若指定了所需采样率,就重采样音频 if convert_rate is not None and self.sample_rate != convert_rate: raw_data, _ = audioop.ratecv(raw_data, self.sample_width, 1, self.sample_rate, convert_rate, None) # 若指定了样本宽度,将样本转换成所需样本宽度, if convert_width is not None and self.sample_width != convert_width: if convert_width == 3: # 将音频转换成24位 (解决方法 https://bugs.python.org/issue12866) raw_data = audioop.lin2lin(raw_data, self.sample_width, 4) # 先把音频转换成32位 try: audioop.bias( b"", 3, 0 ) # 测试一下支不支持24位音频 (例如,Python 3.3及以下的``audioop`` 不支持样本宽度3, 但 Python 3.4+ 可以) except audioop.error: # 这个版本的audioop d不支持24位音频 (可能是Python 3.3 及以下的版本) raw_data = b"".join( raw_data[i + 1:i + 4] for i in range(0, len(raw_data), 4) ) # 由于我们处于小端,因此我们丢弃每个32位采样的第一个字节以获得24位采样 else: # 24位音频完全支持,我们不需要填充任何东西 raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) else: raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) # 如果输出是无符号样本的8位音频,则将我们以前当作有符号样本处理的样本转换为无符号样本 if convert_width == 1: raw_data = audioop.bias(raw_data, 1, 128) # 为每个样本添加128,使其再次像无符号样本一样 return raw_data
def downsample(buf, outrate=16000): """Downsample audio. Required for voice detection. :param buf: Audio data buffer (or path to WAV file). :param int outrate: Output audio sample rate in Hz. :returns: Output buffer. :rtype: BytesIO """ wav = wave.open(buf) inpars = wav.getparams() frames = wav.readframes(inpars.nframes) # Convert to mono if inpars.nchannels == 2: frames = audioop.tomono(frames, inpars.sampwidth, 1, 1) # Convert to 16-bit depth if inpars.sampwidth > 2: frames = audioop.lin2lin(frames, inpars.sampwidth, 2) # Convert frame rate to 16000 Hz frames, _ = audioop.ratecv(frames, 2, 1, inpars.framerate, outrate, None) # Return a BytesIO version of the output outbuf = BytesIO() out = wave.open(outbuf, "w") out.setnchannels(1) out.setsampwidth(2) out.setframerate(outrate) out.writeframes(frames) out.close() outbuf.seek(0) return outbuf
def test_lin2lin(self): # too simple: we test only the size for d1 in data: for d2 in data: got = len(d1) // 3 wtd = len(d2) // 3 self.assertEqual(len(audioop.lin2lin(d1, got, wtd)), len(d2))
def openWavAndConvertDown(self, path): import wave import audioop try: waveInput = wave.open(path, "rb") except: import soundfile data, samplerate = soundfile.read('temp/temp.wav') soundfile.write('temp/temp.wav', data, samplerate, subtype='PCM_16') waveInput = wave.open(path, "rb") converted = waveInput.readframes(waveInput.getnframes()) if waveInput.getframerate() != 8000: converted = audioop.ratecv(converted, waveInput.getsampwidth(), waveInput.getnchannels(), waveInput.getframerate(), 8000, None) converted = converted[0] if waveInput.getnchannels() == 2: converted = audioop.tomono(converted, waveInput.getsampwidth(), 0.5, 0.5) if waveInput.getsampwidth() > 1: converted = audioop.lin2lin(converted, waveInput.getsampwidth(), 1) converted = audioop.bias(converted, 1, 128) waveInput.close() waveOutput = wave.open("temp/temp.wav", "wb") waveOutput.setnchannels(1) waveOutput.setsampwidth(1) waveOutput.setframerate(8000) waveOutput.writeframes(converted) waveOutput.close()
def raw_read(self): """Return some amount of data as a raw audio string""" buf = self.source.raw_read() if buf is None: self.eof = True return None # Convert channels as needed if self.set_channels and self.source.channels() != self.set_channels: if self.set_channels == 1: buf = audioop.tomono(buf, self.source.raw_width(), .5, .5) else: buf = audioop.tostereo(buf, self.source.raw_width(), 1, 1) # Convert sampling rate as needed if self.set_sampling_rate and self.source.sampling_rate() != self.set_sampling_rate: (buf, self.ratecv_state) = audioop.ratecv(buf, self.source.raw_width(), self.channels(), self.source.sampling_rate(), self.set_sampling_rate, self.ratecv_state) if self.set_raw_width and self.source.raw_width() != self.set_raw_width: if self.source.raw_width() == 1 and self.source.has_unsigned_singles(): buf = audioop.bias(buf, 1, -128) buf = audioop.lin2lin(buf, self.source.raw_width(), self.set_raw_width) if self.set_raw_width == 1 and self.source.has_unsigned_singles(): buf = audioop.bias(buf, 1, 128) return buf
def convert_to(self, data: bytes, to_depth: int, to_channels: int, to_rate: int, to_unsigned: bool = False) -> bytes: """Convert audio data.""" dest_width = to_depth // 8 print(to_depth, self._depth) if self._depth != to_depth: if self._depth == 8: data = audioop.bias(data, 1, 128) data = audioop.lin2lin(data, self._width, dest_width) if to_depth == 8: data = audioop(data, 1, 128) if self._unsigned != to_unsigned: data = audioop.bias(data, dest_width, 128) # Make it stereo if self._channels < to_channels: data = audioop.tostereo(data, dest_width, 1, 1) # Make it mono elif self._channels > to_channels: data = audioop.tomono(data, dest_width, 1, 1) # print(dest_width) # Convert the sample rate of the data to the requested rate. if self._rate != to_rate and data: data, self._state = audioop.ratecv(data, dest_width, to_channels, self._rate, to_rate, self._state, 2, 1) return data
def convert_sampwidth(fragment, sampwidth_in, sampwidth_out): """ Convert the sampwidth (byte width) of the input fragment between 1-, 2-, 3-, 4-byte formats. Parameters ---------- fragment : bytes object Specifies the original fragment. sampwidth_in : int Specifies the fragment's original sampwidth. sampwidth_out : int Specifies the fragment's desired sampwidth. Returns ------- bytes """ if sampwidth_in == sampwidth_out: return fragment # In .wav files, 16, 24, and 32 bit samples are signed, 8 bit samples are unsigned. # So when converting from 8 bit wide samples, you need to also subtract 128 from the sample. # Similarly, when converting to 8 bit wide samples, you need to also add 128 to the result. if sampwidth_in == 1: new_fragment = audioop.bias(fragment, 1, -128) else: new_fragment = fragment new_fragment = audioop.lin2lin(new_fragment, sampwidth_in, sampwidth_out) if sampwidth_out == 1: new_fragment = audioop.bias(new_fragment, 1, 128) return new_fragment
def get_raw_data(self, convert_rate = None, convert_width = None): """ Returns a byte string representing the raw frame data for the audio represented by the ``AudioData`` instance. If ``convert_rate`` is specified and the audio sample rate is not ``convert_rate`` Hz, the resulting audio is resampled to match. If ``convert_width`` is specified and the audio samples are not ``convert_width`` bytes each, the resulting audio is converted to match. Writing these bytes directly to a file results in a valid `RAW/PCM audio file <https://en.wikipedia.org/wiki/Raw_audio_format>`__. """ assert convert_rate is None or convert_rate > 0, "Sample rate to convert to must be a positive integer" assert convert_width is None or (convert_width % 1 == 0 and 1 <= convert_width <= 4), "Sample width to convert to must be between 1 and 4 inclusive" raw_data = self.frame_data # make sure unsigned 8-bit audio (which uses unsigned samples) is handled like higher sample width audio (which uses signed samples) if self.sample_width == 1: raw_data = audioop.bias(raw_data, 1, -128) # subtract 128 from every sample to make them act like signed samples # resample audio at the desired rate if specified if convert_rate is not None and self.sample_rate != convert_rate: raw_data, _ = audioop.ratecv(raw_data, self.sample_width, 1, self.sample_rate, convert_rate, None) pass # convert samples to desired byte format if specified if convert_width is not None and self.sample_width != convert_width: raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) # if the output is 8-bit audio with unsigned samples, convert the samples we've been treating as signed to unsigned again if convert_width == 1: raw_data = audioop.bias(raw_data, 1, 128) # add 128 to every sample to make them act like unsigned samples again return raw_data
def test_lin2lin(self): # too simple: we test only the size for d1 in data: for d2 in data: got = len(d1)//3 wtd = len(d2)//3 self.assertEqual(len(audioop.lin2lin(d1, got, wtd)), len(d2))
def coerce_lin(source_aiff, template_obj): '''Read data from source, and convert it to match template's params.''' import audioop frag = source_aiff.read_lin() Ss = source_aiff.stream St = template_obj.stream # Sample width if Ss.getsampwidth() != St.getsampwidth(): print 'coerce sampwidth %i -> %i' %(Ss.getsampwidth(), St.getsampwidth()) frag = audioop.lin2lin(frag, Ss.getsampwidth(), St.getsampwidth()) width = St.getsampwidth() # Channels if Ss.getnchannels() != St.getnchannels(): print 'coerce nchannels %i -> %i' %(Ss.getnchannels(), St.getnchannels()) if Ss.getnchannels()==2 and St.getnchannels()==1: frag = audioop.tomono(frag, width, 0.5, 0.5) elif Ss.getnchannels()==1 and St.getnchannels()==2: frag = audioop.tostereo(frag, width, 1.0, 1.0) else: print "Err: can't match channels" # Frame rate if Ss.getframerate() != St.getframerate(): print 'coerce framerate %i -> %i' %(Ss.getframerate(), St.getframerate()) frag,state = audioop.ratecv( frag, width, St.getnchannels(), Ss.getframerate(), # in rate St.getframerate(), # out rate None, 2,1 ) return frag
def get_raw_data(self, convert_rate=None, convert_width=None): """ Returns a byte string representing the raw frame data for the audio represented by the ``AudioData`` instance. If ``convert_rate`` is specified and the audio sample rate is not ``convert_rate`` Hz, the resulting audio is resampled to match. If ``convert_width`` is specified and the audio samples are not ``convert_width`` bytes each, the resulting audio is converted to match. Writing these bytes directly to a file results in a valid `RAW/PCM audio file <https://en.wikipedia.org/wiki/Raw_audio_format>`__. """ assert convert_rate is None or convert_rate > 0, "Sample rate to convert to must be a positive integer" assert convert_width is None or ( convert_width % 1 == 0 and 2 <= convert_width <= 4 ), "Sample width to convert to must be 2, 3, or 4" raw_data = self.frame_data # resample audio at the desired rate if specified if convert_rate is not None and self.sample_rate != convert_rate: raw_data, _ = audioop.ratecv(raw_data, self.sample_width, 1, self.sample_rate, convert_rate, None) # convert samples to desired byte format if specified if convert_width is not None and self.sample_width != convert_width: raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) return raw_data
def normalize(self) -> 'Sample': """ Normalize the sample, meaning: convert it to the default samplerate, sample width and number of channels. When mixing samples, they should all have the same properties, and this method is ideal to make sure of that. """ if self.__locked: raise RuntimeError("cannot modify a locked sample") self.resample(params.norm_samplerate) if self.samplewidth != params.norm_samplewidth: # Convert to desired sample size. self.__frames = audioop.lin2lin(self.__frames, self.samplewidth, params.norm_samplewidth) self.__samplewidth = params.norm_samplewidth if params.norm_nchannels not in (1, 2): raise ValueError( "norm_nchannels has invalid value, can only be 1 or 2") if self.nchannels == 1 and params.norm_nchannels == 2: # convert to stereo self.__frames = audioop.tostereo(self.__frames, self.samplewidth, 1, 1) self.__nchannels = 2 elif self.nchannels == 2 and params.norm_nchannels == 1: # convert to mono self.__frames = audioop.tomono(self.__frames, self.__samplewidth, 1, 1) self.__nchannels = 1 return self
def testlin2lin(data): # too simple: we test only the size for d1 in data: for d2 in data: got = len(d1)/3 wtd = len(d2)/3 if len(audioop.lin2lin(d1, got, wtd)) <> len(d2): return 0 return 1
def changesampwidth(self, newsampwidth): """ Return frames with the given number of bytes. @param newsampwidth (int) new sample width of the frames. (1 for 8 bits, 2 for 16 bits, 4 for 32 bits) @return converted frames """ return audioop.lin2lin(self.frames, self.sampwidth, newsampwidth)
def get_32bit_frames(self, scale_amplitude=True): """Returns the raw sample frames scaled to 32 bits. See make_32bit method for more info.""" if self.samplewidth == 4: return self.__frames frames = audioop.lin2lin(self.__frames, self.samplewidth, 4) if not scale_amplitude: # we need to scale back the sample amplitude to fit back into 24/16/8 bit range factor = 1.0/2**(8*abs(self.samplewidth-4)) frames = audioop.mul(frames, 4, factor) return frames
def get_raw_data(self, convert_rate=None, convert_width=None): raw_data = self.frame_data # make sure unsigned 8-bit audio (which uses unsigned samples) is handled like higher sample width audio (which uses signed samples) if self.sample_width == 1: raw_data = audioop.bias( raw_data, 1, -128 ) # subtract 128 from every sample to make them act like signed samples # resample audio at the desired rate if specified if convert_rate is not None and self.sample_rate != convert_rate: raw_data, _ = audioop.ratecv(raw_data, self.sample_width, 1, self.sample_rate, convert_rate, None) # convert samples to desired sample width if specified if convert_width is not None and self.sample_width != convert_width: if convert_width == 3: # we're converting the audio into 24-bit (workaround for https://bugs.python.org/issue12866) raw_data = audioop.lin2lin( raw_data, self.sample_width, 4 ) # convert audio into 32-bit first, which is always supported try: audioop.bias( b"", 3, 0 ) # test whether 24-bit audio is supported (for example, ``audioop`` in Python 3.3 and below don't support sample width 3, while Python 3.4+ do) except audioop.error: # this version of audioop doesn't support 24-bit audio (probably Python 3.3 or less) raw_data = b"".join( raw_data[i + 1:i + 4] for i in range(0, len(raw_data), 4) ) # since we're in little endian, we discard the first byte from each 32-bit sample to get a 24-bit sample else: # 24-bit audio fully supported, we don't need to shim anything raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) else: raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) # if the output is 8-bit audio with unsigned samples, convert the samples we've been treating as signed to unsigned again if convert_width == 1: raw_data = audioop.bias( raw_data, 1, 128 ) # add 128 to every sample to make them act like unsigned samples again return raw_data
def get_32bit_frames(self, scale_amplitude=True): """Returns the raw sample frames scaled to 32 bits. See make_32bit method for more info.""" if self.samplewidth == 4: return self.__frames frames = audioop.lin2lin(self.__frames, self.samplewidth, 4) if not scale_amplitude: # we need to scale back the sample amplitude to fit back into 24/16/8 bit range factor = 1.0 / 2**(8 * abs(self.samplewidth - 4)) frames = audioop.mul(frames, 4, factor) return frames
def to_sample_width(self, sampwidth): 'Convert to a new sample width' if self.params.sampwidth == sampwidth: return self if sampwidth not in (1, 2, 3, 4): raise PcmValueError('Illegal sample width: %d' % sampwidth) return self.__class__(self.params, audioop.lin2lin(self.frames, self.params.sampwidth, sampwidth), sampwidth=sampwidth)
def _convert_data(self, data: bytes, to_depth: int, to_channels: int, to_rate: int, to_unsigned: bool = False) -> bytes: """Convert audio data.""" out_width = to_depth // 8 if self._from_float: ldata = audioop.tomono(data, self._width, 1, 0) rdata = audioop.tomono(data, self._width, 0, 1) for mono_data in [ldata, rdata]: float_array = array('f', mono_data) out_array = array('i' if self._out_depth > 16 else 'h') for i in float_array: if i > 1.0: i = 1.0 elif i < -1.0: i = -1.0 out_array.append(round(i * 32767.0)) mono_data = out_array.tobytes() ldata = audioop.tostereo(ldata, self._width, 1, 0) rdata = audioop.tostereo(rdata, self._width, 0, 1) data = audioop.add(ldata, rdata, self._width) if self._to_alaw: data = audioop.lin2alaw(data, self._width) if self._depth != to_depth: data = audioop.lin2lin( data, self._width, out_width ) if self._unsigned != to_unsigned: data = audioop.bias(data, out_width, 128) # Make it stereo if self._channels < to_channels: data = audioop.tostereo(data, out_width, 1, 1) # Make it mono elif self._channels > to_channels: data = audioop.tomono(data, out_width, 1, 1) # Convert the sample rate of the data to the requested rate. if self._rate != to_rate and data: data, self._state = audioop.ratecv( data, out_width, to_channels, self._rate, to_rate, self._state, ) return data
def change_sampwidth(self, new_sampwidth): """Return frames with the given number of bytes. :param new_sampwidth: (int) new sample width of the frames. (1 for 8 bits, 2 for 16 bits, 4 for 32 bits) :returns: (str) converted frames """ if new_sampwidth not in [1, 2, 4]: raise SampleWidthError return audioop.lin2lin(self._frames, self._sampwidth, new_sampwidth)
def changesampwidth(frames, sampwidth, newsampwidth): """ Change the number of bytes used to encode the frames @param frames (string) input frames. @param current sampwidth (int) sample width of the frames. (1 for 8 bits, 2 for 16 bits, 4 for 32 bits) @param newsampwidth (int) new sample width of the frames. (1 for 8 bits, 2 for 16 bits, 4 for 32 bits) @return converted frames """ return audioop.lin2lin(frames, sampwidth, newsampwidth)
def testlin2lin(data): if verbose: print 'lin2lin' # too simple: we test only the size for d1 in data: for d2 in data: got = len(d1)/3 wtd = len(d2)/3 if len(audioop.lin2lin(d1, got, wtd)) != len(d2): return 0 return 1
def change_sampwidth(self, new_sampwidth): """ Return frames with the given number of bytes. :param new_sampwidth: (int) new sample width of the frames. (1 for 8 bits, 2 for 16 bits, 4 for 32 bits) :returns: (str) converted frames """ if new_sampwidth not in [1, 2, 4]: raise SampleWidthError return audioop.lin2lin(self._frames, self._sampwidth, new_sampwidth)
def testlin2lin(data): if verbose: print 'lin2lin' # too simple: we test only the size for d1 in data: for d2 in data: got = len(d1) // 3 wtd = len(d2) // 3 if len(audioop.lin2lin(d1, got, wtd)) != len(d2): return 0 return 1
def write(self, data: bytes) -> int: """Encode and writes str to an ogg file.""" written = 0 if self._from_24: data = audioop.lin2lin(data, 3, self._depth // 8) for data_buffer in slice_buffer(data, self.buffer_size): written += self._vorbis_file.write(self._encode(data_buffer)) return written
def get_raw_data(self, convert_rate = None, convert_width = None): """ Returns a byte string representing the raw frame data for the audio represented by the ``AudioData`` instance. If ``convert_rate`` is specified and the audio sample rate is not ``convert_rate`` Hz, the resulting audio is resampled to match. If ``convert_width`` is specified and the audio samples are not ``convert_width`` bytes each, the resulting audio is converted to match. Writing these bytes directly to a file results in a valid `RAW/PCM audio file <https://en.wikipedia.org/wiki/Raw_audio_format>`__. """ assert convert_rate is None or convert_rate > 0, "Sample rate to convert to must be a positive integer" assert convert_width is None or (convert_width % 1 == 0 and 1 <= convert_width <= 4), "Sample width to convert to must be between 1 and 4 inclusive" raw_data = self.frame_data # make sure unsigned 8-bit audio (which uses unsigned samples) is handled like higher sample width audio (which uses signed samples) if self.sample_width == 1: raw_data = audioop.bias(raw_data, 1, -128) # subtract 128 from every sample to make them act like signed samples # resample audio at the desired rate if specified if convert_rate is not None and self.sample_rate != convert_rate: raw_data, _ = audioop.ratecv(raw_data, self.sample_width, 1, self.sample_rate, convert_rate, None) # convert samples to desired sample width if specified if convert_width is not None and self.sample_width != convert_width: if convert_width == 3: # we're converting the audio into 24-bit (workaround for https://bugs.python.org/issue12866) raw_data = audioop.lin2lin(raw_data, self.sample_width, 4) # convert audio into 32-bit first, which is always supported try: audioop.bias(b"", 3, 0) # test whether 24-bit audio is supported (for example, ``audioop`` in Python 3.3 and below don't support sample width 3, while Python 3.4+ do) except audioop.error: # this version of audioop doesn't support 24-bit audio (probably Python 3.3 or less) raw_data = b"".join(raw_data[i + 1:i + 4] for i in range(0, len(raw_data), 4)) # since we're in little endian, we discard the first byte from each 32-bit sample to get a 24-bit sample else: # 24-bit audio fully supported, we don't need to shim anything raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) else: raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) # if the output is 8-bit audio with unsigned samples, convert the samples we've been treating as signed to unsigned again if convert_width == 1: raw_data = audioop.bias(raw_data, 1, 128) # add 128 to every sample to make them act like unsigned samples again return raw_data
def read(self, size: int = -1) -> bytes: """Convert audio. Convert the samples to the given rate and makes it mono or stereo depending on the channels value. """ data = self._buffer while len(data) < size: temp_data = self._source.read() if not temp_data: if len(data) != 0: data += b'\x00' * (size - len(data)) break if self._source._floatp and not self._floatp: in_array = array('f', temp_data) out_array = array(f"{'h' if self._depth <= 16 else 'i'}") for i in in_array: if i >= 1.0: out_array.append(32767) elif i <= -1.0: out_array.append(-32768) else: out_array.append(math.floor(i * 32768.0)) temp_data = out_array.tobytes() # Convert audio data from source width to self._width. if self._depth != self._source.depth: temp_data = audioop.lin2lin(temp_data, self._source._width, self._width) if self._unsigned != self._source.unsigned: temp_data = audioop.bias(temp_data, self._source._width, 128) # Make it stereo if self._source.channels < self._channels: temp_data = audioop.tostereo(temp_data, self._width, 1, 1) # Make it mono elif self._source.channels > self._channels: temp_data = audioop.tomono(temp_data, self._width, 1, 1) # Convert the sample rate of the data to the requested rate. if self._rate != self._source.rate and temp_data: temp_data, self._state = audioop.ratecv( temp_data, self._width, self._channels, self._source.rate, self._rate, self._state) data += temp_data self._buffer = data[size:] return data[:size]
def convert_wave_data(f_rate,frame_count,sample_width,channels,data): """ Convert wave sample data into pleo format """ if channels==2: data = audioop.tomono(data,sample_width,1,1) data = audioop.mul(data,sample_width,0.97999999999999998) data = audioop.ratecv(data,sample_width,1,f_rate,11025,None,4,4)[0] if sample_width==1: data = audioop.bias(data,1,-128) data = audioop.lin2lin(data,1,2) data = audioop.mul(data,2,(1.0/256)) data = audioop.lin2adpcm(data,2,None)[0] return (11025,frame_count,sample_width,1,data)
def rewrite(): orign=wave.open('hass/asr20181208231910.wav') fms_byte=orign.readframes(orign.getnframes()) orign.close() dest=wave.open('hjwavtest12.wav', 'wb') rebyte = audioop.lin2lin(fms_byte, 1, 2) cvbyte=audioop.ratecv(rebyte, 2, 1, 8000, 16000, None)[0] pdb.set_trace() dest.setnchannels(1) dest.setsampwidth(2) dest.setframerate(16000) dest.writeframes(cvbyte) dest.close()
def _get_audio_data(self, num_bytes): sound = self.sequencer.tick() if sound is None: pyglet.app.exit() return self._mute(sound) sound = [lin2lin(s, 1, self.bytes) for s in sound] output = self._ratecv(sound) output = self._scale(output) output = self._tostereo(output) stereo = mix(output, self.bytes) audio = AudioData(stereo, self.audio_length, self.timestamp, self.tick_time) self.timestamp += self.tick_time return audio
def make_16bit(self, maximize_amplitude=True): """ Convert to 16 bit sample width, usually by using a maximized amplification factor to scale into the full 16 bit range without clipping or overflow. This is used for example to downscale a 32 bits mixed sample back into 16 bit width. """ assert not self.__locked assert self.samplewidth >= 2 if maximize_amplitude: self.amplify_max() if self.samplewidth > 2: self.__frames = audioop.lin2lin(self.__frames, self.samplewidth, 2) self.__samplewidth = 2 return self
def resample(self, data, freq=44100, bits=8, signed=0, channels=1, byteorder=None): "Convert a sample to the mixer's own format." bytes = bits / 8 byteorder = byteorder or sys.byteorder if (freq, bytes, signed, channels, byteorder) == self.parameters: return data # convert to native endianness if byteorder != sys.byteorder: data = byteswap(data, bytes) byteorder = sys.byteorder # convert unsigned -> signed for the next operations if not signed: data = audioop.bias(data, bytes, -(1 << (bytes * 8 - 1))) signed = 1 # convert stereo -> mono while channels > self.channels: assert channels % 2 == 0 data = audioop.tomono(data, bytes, 0.5, 0.5) channels /= 2 # resample to self.freq if freq != self.freq: data, ignored = audioop.ratecv(data, bytes, channels, freq, self.freq, None) freq = self.freq # convert between 8bits and 16bits if bytes != self.bytes: data = audioop.lin2lin(data, bytes, self.bytes) bytes = self.bytes # convert mono -> stereo while channels < self.channels: data = audioop.tostereo(data, bytes, 1.0, 1.0) channels *= 2 # convert signed -> unsigned if not self.signed: data = audioop.bias(data, bytes, 1 << (bytes * 8 - 1)) signed = 0 # convert to mixer endianness if byteorder != self.byteorder: data = byteswap(data, bytes) byteorder = self.byteorder # done if (freq, bytes, signed, channels, byteorder) != self.parameters: raise ValueError, 'sound sample conversion failed' return data
def calculate_max_min(self): self.Sound.write(".temp.wav") S = wave.open(".temp.wav","rb") Length = S.getnframes() BufferLen = Length / self.FragmentFactor Stream = S.readframes(BufferLen) while len(Stream) : Stream = audioop.lin2lin(Stream,2,1) Stream = audioop.tomono(Stream,1,1,-1) min_val, max_val = audioop.minmax(Stream, 1) self.Min_List.append(min_val) self.Max_List.append(max_val) Stream = S.readframes(BufferLen) S.close() os.remove(".temp.wav")
def read(self, frames): data = self.obj.readframes((frames // self.channels)) #data = data[:frames]#Hack don't know why but is returning extra frames if (len(data) == 0): raise EOFError("reached the end") if (self.sw != 2): data = audioop.lin2lin(data, self.sw, 2) if (self.channels == 2): data = audioop.tomono(data, 2, 1, 1) if (self.sf != 16000): data, self.resampler_state = audioop.ratecv( data, 2, 1, self.sf, 16000, self.resampler_state) data = data[: frames] #Hack don't know why but is returning extra frames return data #returns data formatted as 48Khz 16bit mono
def read_data(self, block_samples=1024): """Generates blocks of PCM data found in the file.""" old_width = self._file.getsampwidth() while True: data = self._file.readframes(block_samples) if not data: break # Make sure we have the desired bitdepth and endianness. data = audioop.lin2lin(data, old_width, TARGET_WIDTH) if self._needs_byteswap and self._file.getcomptype() != 'sowt': # Big-endian data. Swap endianness. data = byteswap(data) yield data
def write(self, data: bytes) -> int: """Encode and writes str to an mp3 file.""" # Scale all bit-width data above 16-bit down to 16-bit. if self._from_width: data = audioop.lin2lin(data, self._from_width, self._depth // 8) # Resample all audio data above 44100 down to 44100. if self._rate > 44100: data, self._state = audioop.ratecv(data, self._depth // 8, self._channels, self._rate, 44100, self._state) # Number of samples = bytes / ((bits per sample) / 8) num_samples = len(data) // (self._depth // 8) samples_per_chan = num_samples // self._channels # Create a buffer to hold the encoded data. encoded_data = (_lame.c_ubyte * _lame.LAME_MAXMP3BUFFER)() data_bytes = b'' # Split the data into samples. if self._depth == 16: # Two bytes per sample. data_bytes = array('h', data) elif self._depth == 8: # One byte per sample. data_bytes = array('b', data) # in_buffer_l = (_lame.c_short * samples_per_chan)(*data_bytes[::2]) # in_buffer_r = (_lame.c_short * samples_per_chan)(*data_bytes[1::2]) # bytes_encoded = _lame.lame_encode_buffer(self._global_flags, # in_buffer_l, # in_buffer_r, # samples_per_chan, # encoded_data, # 0) in_buffer = (_lame.c_short * num_samples)(*data_bytes) bytes_encoded = _lame.lame_encode_buffer_interleaved( self._global_flags, in_buffer, samples_per_chan, encoded_data, _lame.sizeof(encoded_data)) # Retrieve the encoded audio data from buffer. out_data = _lame.string_at(encoded_data, bytes_encoded) # Write data to the file. return self._out_file.write(out_data)
def normalize(self): """ Normalize the sample, meaning: convert it to the default samplerate, sample width and number of channels. When mixing samples, they should all have the same properties, and this method is ideal to make sure of that. """ assert not self.__locked self.resample(self.norm_samplerate) if self.samplewidth != self.norm_samplewidth: # Convert to 16 bit sample size. self.__frames = audioop.lin2lin(self.__frames, self.samplewidth, self.norm_samplewidth) self.__samplewidth = self.norm_samplewidth if self.nchannels == 1: # convert to stereo self.__frames = audioop.tostereo(self.__frames, self.samplewidth, 1, 1) self.__nchannels = 2 return self
def read_data(self): pa = PyAudio() stream = pa.open(format=paInt16, channels=1, rate=16000, input=True, frames_per_buffer=1) count = 0 while True: if count >= 2: break print('.' + str(count)) data = stream.read(16000) count += 1 data = audioop.lin2lin(data, pa.get_sample_size(paInt16), TARGET_WIDTH) yield data
def read(self, size=None): """ Convert the samples to the given rate and makes it mono or stereo depending on the channels value. The data is buffered so """ if not audioop: print("audioop not found so returning empty byte") return b'\x00' data = self._buffer while len(data) < size: temp_data = self._source.read() if not temp_data: if len(data) != 0: data += b'\x00' * (size - len(data)) break if self._depth != self._source.depth: temp_data = audioop.lin2lin(temp_data, self._source._width, self._width) if self._unsigned != self._source.unsigned: temp_data = audioop.bias(temp_data, self._source._width, 128) # Make it stereo if self._source.channels < self._channels: temp_data = audioop.tostereo(temp_data, self._width, 1, 1) # Make it mono elif self._source.channels > self._channels: temp_data = audioop.tomono(temp_data, self._width, 1, 1) # Convert the sample rate of the data to the requested rate. if self._rate != self._source.rate and temp_data: temp_data, self._state = audioop.ratecv(temp_data, self._width, self._channels, self._source.rate, self._rate, self._state) data += temp_data self._buffer = data[size:] return data[:size]
def test_lin2lin(self): for w in 1, 2, 4: self.assertEqual(audioop.lin2lin(datas[w], w, w), datas[w]) self.assertEqual(audioop.lin2lin(datas[1], 1, 2), packs[2](0, 0x1200, 0x4500, -0x4500, 0x7F00, -0x8000, -0x100)) self.assertEqual( audioop.lin2lin(datas[1], 1, 4), packs[4](0, 0x12000000, 0x45000000, -0x45000000, 0x7F000000, -0x80000000, -0x1000000), ) self.assertEqual(audioop.lin2lin(datas[2], 2, 1), b"\x00\x12\x45\xba\x7f\x80\xff") self.assertEqual( audioop.lin2lin(datas[2], 2, 4), packs[4](0, 0x12340000, 0x45670000, -0x45670000, 0x7FFF0000, -0x80000000, -0x10000), ) self.assertEqual(audioop.lin2lin(datas[4], 4, 1), b"\x00\x12\x45\xba\x7f\x80\xff") self.assertEqual(audioop.lin2lin(datas[4], 4, 2), packs[2](0, 0x1234, 0x4567, -0x4568, 0x7FFF, -0x8000, -1))
def get_minmax_tag(self): min_list = [] max_list = [] self.write(".temp.wav") Song = wave.open(".temp.wav","rb") NumStream = Song.getnframes() BufferLen = NumStream / self.FragmentFactor Stream = Song.readframes(BufferLen) while len(Stream): Stream = Audio.lin2lin(Stream,2,1) Stream = Audio.tomono(Stream,1,1,-1) min_val, max_val = Audio.minmax(Stream, self.ByteLength) min_list.append(min_val) max_list.append(max_val) Stream = Song.readframes(BufferLen) Song.close() os.remove(".temp.wav") return min_list, max_list
def get_minmax_tag(self): min_list = [] max_list = [] self.write(".temp.wav") Song = wave.open(".temp.wav", "rb") NumStream = Song.getnframes() BufferLen = NumStream / self.FragmentFactor Stream = Song.readframes(BufferLen) while len(Stream): Stream = Audio.lin2lin(Stream, 2, 1) Stream = Audio.tomono(Stream, 1, 1, -1) min_val, max_val = Audio.minmax(Stream, self.ByteLength) min_list.append(min_val) max_list.append(max_val) Stream = Song.readframes(BufferLen) Song.close() os.remove(".temp.wav") return min_list, max_list
def set_sample_width(self, sample_width): if sample_width == self.sample_width: return self data = self._data if self.sample_width == 1: data = audioop.bias(data, 1, -128) if data: data = audioop.lin2lin(data, self.sample_width, sample_width) if sample_width == 1: data = audioop.bias(data, 1, 128) frame_width = self.channels * sample_width return self._spawn(data, overrides={'sample_width': sample_width, 'frame_width': frame_width})
def __init__(self, fp): self.fp = self.module.open(fp, 'rb') p = self.fp.getparams() print p if (p[4] not in self.allowedComp): raise ValueError("Incorrect file format %r"%(p,)) self.comptype = p[4] if p[0] == 2: self._cvt = lambda x,ch=p[1],c=self._cvt: tomono(c(x),ch,0.5,0.5) elif p[0] != 1: raise ValueError("can only handle mono/stereo, not %d"%p[0]) if p[1] != 2: self._cvt = lambda x,ch=p[1],c=self._cvt: lin2lin(c(x),ch,2) self.sampwidth = p[1] if p[2] % 8000 != 0: raise ValueError("sampfreq must be multiple of 8k") self.sampfreq = p[2] if p[2] != 8000: print "rate conversion" self._ratecvt = None self._cvt = lambda x,c=self._cvt: self.rateCvt(c(x))
def read_wav(filename, normalize = 0.5): """ Reads a wave file and return sample rate and mono audio data """ from math import floor # Make header info sys.stderr.write('Openining : ' + filename + '\n\n') wf = wave.open(filename, 'rb') info = "\tWAV file: " + filename + "\n" channels = wf.getnchannels() info += "\tOriginal Channels: " + str(channels) bits = wf.getsampwidth() info += "\tOriginal Bits: " + str(bits*8) + "\n" sr = wf.getframerate() total_samples = wf.getnframes() seconds = float(total_samples)/sr ms_seconds = (seconds - floor(seconds)) * 1000 info += "\tOriginal Size: " + str(total_samples*wf.getsampwidth()) info += " Bytes ( %d" % floor(seconds) info += ":%05.1f" % ms_seconds info += ") seconds \n" info += "\tSample Rate: " + str(sr) + "\n" samples = wf.readframes(total_samples) wf.close() if bits != BITS: # It isn't 16 bits, convert to 16 samples = audioop.lin2lin(samples, bits, BITS) if bits == 1 and min(samples) >= 0: # It's unsigned 8 bits samples = audioop.bias(samples, 2, ssc.MIN ) if channels > 1: samples = audioop.tomono(samples, BITS, 0.75, 0.25) # Normalize at 50% maxsample = audioop.max(samples, BITS) samples = audioop.mul(samples, BITS, MAX * normalize / float(maxsample)) return sr, samples, info
def get_raw_data(self, convert_rate = None, convert_width = None): """ Returns a byte string representing the raw frame data for the audio represented by the ``AudioData`` instance. If ``convert_rate`` is specified and the audio sample rate is not ``convert_rate`` Hz, the resulting audio is resampled to match. If ``convert_width`` is specified and the audio samples are not ``convert_width`` bytes each, the resulting audio is converted to match. Writing these bytes directly to a file results in a valid `RAW/PCM audio file <https://en.wikipedia.org/wiki/Raw_audio_format>`__. """ assert convert_rate is None or convert_rate > 0, "Sample rate to convert to must be a positive integer" assert convert_width is None or (convert_width % 1 == 0 and 2 <= convert_width <= 4), "Sample width to convert to must be 2, 3, or 4" raw_data = self.frame_data # resample audio at the desired rate if specified if convert_rate is not None and self.sample_rate != convert_rate: raw_data, _ = audioop.ratecv(raw_data, self.sample_width, 1, self.sample_rate, convert_rate, None) # convert samples to desired byte format if specified if convert_width is not None and self.sample_width != convert_width: raw_data = audioop.lin2lin(raw_data, self.sample_width, convert_width) return raw_data
def send_voice(self, wav, target, terminated): packet = bytearray() packet.append(self.outgoing_type.value << 5 | target.value) packet.extend(self._encode_varint(self.outgoing_sequence_number)) nchannels, sampwidth, framerate, n, _, _ = wav.getparams() logger.debug('Sending audio: %d channels, %d-bit, %dhz, %d frames', nchannels, sampwidth * 8, framerate, n) for i in range(n): pcm = wav.readframes(1) if sampwidth != 2: pcm = audioop.lin2lin(pcm, sampwidth, 2) if nchannels == 2: pcm = audioop.tomono(pcm, 2, 0.5, 0.5) if framerate != 48000: pcm, _ = audioop.ratecv(pcm, 2, 1, framerate, 48000, None) frame = self.outgoing_codec.encoder.encode(pcm) if self.outgoing_type == self.PacketType.VOICE_OPUS: #packet.extend(self._make_opus_header(frame)) # TODO: figure out opus pass else: packet.extend(self._make_celt_header(frame, True)) if i == n - 1 and terminated: packet.extend(self._make_celt_header(b'', False)) print(packet) self.transport.sendto(bytes(packet)) self.outgoing_sequence_number += 1
def __init__(self, filename, mode='r', depth=16, rate=44100, channels=2, bigendian=False, unsigned=False, **kwargs): """ AllFile(self, filename, mode='r', depth=16, rate=44100, channels=2, bigendian=False, unsigned=False, **kwargs) -> Loads the correct codec for the file and acts as a wrapper providing additional funcionality. """ codec = get_codec(filename, blacklist=[os_basename(__file__)]) self._supported_modes = getattr(codec, '_supported_modes', 'r') source = codec(filename, mode=mode, **kwargs) super(AllFile, self).__init__(filename, mode, source.depth, source.rate, source.channels) self._source = source self._bigendian = bigendian self._unsigned = unsigned self._state = None annotations = getattr(codec.read, '__annotations__') self.read.__annotations__.update(annotations) self._buffer = annotations.get('return', bytes)() self._buffer_size = self._source.buffer_size self._length = self._source.length self._info_dict = self._source._info_dict self.write = self._source.write self._closed = False if self._depth != self._source.depth: self._convert_depth = lambda data: \ audioop.lin2lin(data, self._source._width, self._width) else: self._convert_depth = lambda data: data if self._unsigned != self._source.unsigned: self._convert_unsigned = lambda data: \ audioop.bias(data, self._source._width, 128) else: self._convert_unsigned = lambda data: data # Make it stereo if self._source.channels < self._channels: self._convert_channels = lambda data: audioop.tostereo(data, self._width, 1, 1) # Make it mono elif self._source.channels > self._channels: self._convert_channels = lambda data: audioop.tomono(data, self._width, 1, 1) else: self._convert_channels = lambda data: data # Convert the sample rate of the data to the requested rate. if self._rate != self._source.rate: self._convert_rate = lambda data: audioop.ratecv(data, self._width, self._channels, self._source.rate, self._rate, self._state) else: self._convert_rate = lambda data: (data, self._state) if self._bigendian != self._source.bigendian: self._convert_endian = swap_endian else: self._convert_endian = lambda data: data
def test_lin2lin(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.lin2lin(datas[w], w, w), datas[w]) self.assertEqual(audioop.lin2lin(bytearray(datas[w]), w, w), datas[w]) self.assertEqual(audioop.lin2lin(memoryview(datas[w]), w, w), datas[w]) self.assertEqual(audioop.lin2lin(datas[1], 1, 2), packs[2](0, 0x1200, 0x4500, -0x4500, 0x7F00, -0x8000, -0x100)) self.assertEqual( audioop.lin2lin(datas[1], 1, 3), packs[3](0, 0x120000, 0x450000, -0x450000, 0x7F0000, -0x800000, -0x10000) ) self.assertEqual( audioop.lin2lin(datas[1], 1, 4), packs[4](0, 0x12000000, 0x45000000, -0x45000000, 0x7F000000, -0x80000000, -0x1000000), ) self.assertEqual(audioop.lin2lin(datas[2], 2, 1), b"\x00\x12\x45\xba\x7f\x80\xff") self.assertEqual( audioop.lin2lin(datas[2], 2, 3), packs[3](0, 0x123400, 0x456700, -0x456700, 0x7FFF00, -0x800000, -0x100) ) self.assertEqual( audioop.lin2lin(datas[2], 2, 4), packs[4](0, 0x12340000, 0x45670000, -0x45670000, 0x7FFF0000, -0x80000000, -0x10000), ) self.assertEqual(audioop.lin2lin(datas[3], 3, 1), b"\x00\x12\x45\xba\x7f\x80\xff") self.assertEqual(audioop.lin2lin(datas[3], 3, 2), packs[2](0, 0x1234, 0x4567, -0x4568, 0x7FFF, -0x8000, -1)) self.assertEqual( audioop.lin2lin(datas[3], 3, 4), packs[4](0, 0x12345600, 0x45678900, -0x45678900, 0x7FFFFF00, -0x80000000, -0x100), ) self.assertEqual(audioop.lin2lin(datas[4], 4, 1), b"\x00\x12\x45\xba\x7f\x80\xff") self.assertEqual(audioop.lin2lin(datas[4], 4, 2), packs[2](0, 0x1234, 0x4567, -0x4568, 0x7FFF, -0x8000, -1)) self.assertEqual( audioop.lin2lin(datas[4], 4, 3), packs[3](0, 0x123456, 0x456789, -0x45678A, 0x7FFFFF, -0x800000, -1) )