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 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 test_bias(self): # Note: this test assumes that avg() works d1 = audioop.bias(data[0], 1, 100) d2 = audioop.bias(data[1], 2, 100) d4 = audioop.bias(data[2], 4, 100) self.assertEqual(audioop.avg(d1, 1), 101) self.assertEqual(audioop.avg(d2, 2), 101) self.assertEqual(audioop.avg(d4, 4), 101)
def testbias(data): # Note: this test assumes that avg() works d1 = audioop.bias(data[0], 1, 100) d2 = audioop.bias(data[1], 2, 100) d4 = audioop.bias(data[2], 4, 100) if audioop.avg(d1, 1) <> 101 or \ audioop.avg(d2, 2) <> 101 or \ audioop.avg(d4, 4) <> 101: return 0 return 1
def testbias(data): if verbose: print 'bias' # Note: this test assumes that avg() works d1 = audioop.bias(data[0], 1, 100) d2 = audioop.bias(data[1], 2, 100) d4 = audioop.bias(data[2], 4, 100) if audioop.avg(d1, 1) != 101 or \ audioop.avg(d2, 2) != 101 or \ audioop.avg(d4, 4) != 101: return 0 return 1
def __enter__(self): assert self.stream is None, "This audio source is already inside a context manager" try: # attempt to read the file as WAV self.audio_reader = wave.open(self.filename_or_fileobject, "rb") self.little_endian = True # RIFF WAV is a little-endian format (most ``audioop`` operations assume frames are stored in little-endian form) except wave.Error: try: # attempt to read the file as AIFF self.audio_reader = aifc.open(self.filename_or_fileobject, "rb") self.little_endian = False # AIFF is a big-endian format except aifc.Error: # attempt to read the file as FLAC if hasattr(self.filename_or_fileobject, "read"): flac_data = self.filename_or_fileobject.read() else: with open(self.filename_or_fileobject, "rb") as f: flac_data = f.read() # run the FLAC converter with the FLAC data to get the AIFF data flac_converter = get_flac_converter() process = subprocess.Popen([ flac_converter, "--stdout", "--totally-silent", # put the resulting AIFF file in stdout, and make sure it's not mixed with any program output "--decode", "--force-aiff-format", # decode the FLAC file into an AIFF file "-", # the input FLAC file contents will be given in stdin ], stdin=subprocess.PIPE, stdout=subprocess.PIPE) aiff_data, stderr = process.communicate(flac_data) aiff_file = io.BytesIO(aiff_data) try: self.audio_reader = aifc.open(aiff_file, "rb") except aifc.Error: assert False, "Audio file could not be read as WAV, AIFF, or FLAC; check if file is corrupted" self.little_endian = False # AIFF is a big-endian format assert 1 <= self.audio_reader.getnchannels() <= 2, "Audio must be mono or stereo" self.SAMPLE_WIDTH = self.audio_reader.getsampwidth() # 24-bit audio needs some special handling for old Python versions (workaround for https://bugs.python.org/issue12866) samples_24_bit_pretending_to_be_32_bit = False if self.SAMPLE_WIDTH == 3: # 24-bit audio try: audioop.bias(b"", self.SAMPLE_WIDTH, 0) # test whether this sample width 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) samples_24_bit_pretending_to_be_32_bit = True # while the ``AudioFile`` instance will outwardly appear to be 32-bit, it will actually internally be 24-bit self.SAMPLE_WIDTH = 4 # the ``AudioFile`` instance should present itself as a 32-bit stream now, since we'll be converting into 32-bit on the fly when reading self.SAMPLE_RATE = self.audio_reader.getframerate() self.CHUNK = 4096 self.FRAME_COUNT = self.audio_reader.getnframes() self.DURATION = self.FRAME_COUNT / float(self.SAMPLE_RATE) self.stream = AudioFile.AudioFileStream(self.audio_reader, self.little_endian, samples_24_bit_pretending_to_be_32_bit) return self
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 get_swipe(dev='/dev/audio'): audio = ossaudiodev.open(dev, 'r') audio.setparameters(ossaudiodev.AFMT_S16_LE, 1, 44100) baselines = deque([2**15] * 4) bias = 0 while 1: data, power = get_chunk(audio, bias) baseline = sum(baselines) / len(baselines) * THRESHOLD_FACTOR print power, baseline, power / (baseline or 1) chunks = [] while power > baseline: print power, baseline, power / (baseline or 1), '*' chunks.append(data) data, power = get_chunk(audio, bias) if len(chunks) > 1: data = old_data + ''.join(chunks) + data while audioop.maxpp(data[:3000], 2) < baseline / 2: data = data[1000:] while audioop.maxpp(data[-3000:], 2) < baseline / 2: data = data[:-1000] return audioop.bias(data, 2, -audioop.avg(data, 2)) old_data = data bias = -audioop.avg(data, 2) baselines.popleft() baselines.append(power)
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 bias(self, value): """ Return frames that is the original fragment with a bias added to each sample. Samples wrap around in case of overflow. :param value: (int) the bias which will be applied to each sample. :returns: (str) converted frames """ value = int(value) return audioop.bias(self._frames, self._sampwidth, value)
def bias(self, biasvalue): """ Return frames that is the original fragment with a bias added to each sample. Samples wrap around in case of overflow. @param biasvalue (int) the bias which will be applied to each sample. @return converted frames """ return audioop.bias(self.frames, self.sampwidth, biasvalue)
def bias(self, value): """Return frames that is the original fragment with a bias added to each sample. Samples wrap around in case of overflow. :param value: (int) the bias which will be applied to each sample. :returns: (str) converted frames """ value = int(value) return audioop.bias(self._frames, self._sampwidth, value)
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 bias(fragment, sampwidth, bias): """ Return a fragment that is the original fragment with a bias added to each sample. Samples wrap around in case of overflow. @param fragment (string) input frames. @param sampwidth (int) sample width of the frames. @param bias (int) the bias which will be applied to each sample. @return converted frames """ return audioop.bias(fragment, sampwidth, bias)
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 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 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 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 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 from_file(cls, audio_file, audio_format=wave): ''' Read an audio file. :param audio_file: Path to audio file, or a file-like object :param audio_format: Python module to read audio data, one of wave, aifc, or sunau. ''' with audio_format.open(audio_file, 'rb') as audio: params = audio.getparams() frames = audio.readframes(params.nframes) if audio_format is wave and params.sampwidth == 1: frames = audioop.bias(frames, 1, 0x80) if audio_format is not wave and sys.byteorder == 'little': frames = audioop.byteswap(frames, params.sampwidth) return cls(params, frames)
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 # Perform the scaling and biasing if self.scale != 1.0: buf = audioop.mul(buf, self.source.raw_width(), self.scale) if self.bias != 0: buf = audioop.bias(buf, self.source.raw_width(), self.bias) return buf
def wav2au(data): # Very limited! Assumes a standard 8-bit mono .wav as input import audioop, struct freq, = struct.unpack("<i", data[24:28]) data = data[44:] data = audioop.bias(data, 1, -128) data, ignored = audioop.ratecv(data, 1, 1, freq, 8000, None) data = audioop.lin2ulaw(data, 1) data = struct.pack('>4siiiii8s', '.snd', # header struct.calcsize('>4siiiii8s'), # header size len(data), # data size 1, # encoding 8000, # sample rate 1, # channels 'magic.au') + data return 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 _interpret_wav(x, ch, nb): # Convert the data to a 16-bit sequence. if nb == 1: x = audioop.bias(x, nb, -128) if len(x) % nb != 0: print('length = {}'.format(len(x)), file=sys.stderr) print('width = {}'.format(nb), file=sys.stderr) raise RuntimeError('Not a whole number of frames') x = audioop.lin2lin(x, nb, 2) # Convert the data to a numpy array. scale = 1. / float(1 << 15) fmt = '<i{:d}'.format(2) y = scale * np.frombuffer(x, fmt).astype(np.float32) y = y.reshape((-1, ch)).T return y
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_swipe(): p = pyaudio.PyAudio() stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK) baselines = deque([2**15] * 4) bias = 0 while 1: data, power = get_chunk(stream, bias) baseline = sum(baselines) / len(baselines) * THRESHOLD_FACTOR print power, baseline, power / (baseline or 1) chunks = [] while power > baseline: print power, baseline, power / (baseline or 1), '*' chunks.append(data) data, power = get_chunk(stream, bias) if len(chunks) > 1: data = old_data + ''.join(chunks) + data while audioop.maxpp(data[:3000], 2) < baseline / 2: data = data[1000:] while audioop.maxpp(data[-3000:], 2) < baseline / 2: data = data[:-1000] return audioop.bias(data, 2, -audioop.avg(data, 2)) old_data = data bias = -audioop.avg(data, 2) baselines.popleft() baselines.append(power)
def get_swipe(): p = pyaudio.PyAudio() stream = p.open(format = FORMAT, channels = CHANNELS, rate = RATE, input = True, frames_per_buffer = CHUNK) baselines = deque([2**15] * 4) bias = 0 while 1: data, power = get_chunk(stream, bias) baseline = sum(baselines) / len(baselines) * THRESHOLD_FACTOR print power, baseline, power / (baseline or 1) chunks = [] while power > baseline: print power, baseline, power / (baseline or 1), '*' chunks.append(data) data, power = get_chunk(stream, bias) if len(chunks) > 1: data = old_data + ''.join(chunks) + data while audioop.maxpp(data[:3000], 2) < baseline / 2: data = data[1000:] while audioop.maxpp(data[-3000:], 2) < baseline / 2: data = data[:-1000] return audioop.bias(data, 2, -audioop.avg(data, 2)) old_data = data bias = -audioop.avg(data, 2) baselines.popleft() baselines.append(power)
def test_bias(self): for w in 1, 2, 4: for bias in 0, 1, -1, 127, -128, 0x7FFFFFFF, -0x80000000: self.assertEqual(audioop.bias(b"", w, bias), b"") self.assertEqual(audioop.bias(datas[1], 1, 1), b"\x01\x13\x46\xbc\x80\x81\x00") self.assertEqual(audioop.bias(datas[1], 1, -1), b"\xff\x11\x44\xba\x7e\x7f\xfe") self.assertEqual(audioop.bias(datas[1], 1, 0x7FFFFFFF), b"\xff\x11\x44\xba\x7e\x7f\xfe") self.assertEqual(audioop.bias(datas[1], 1, -0x80000000), datas[1]) self.assertEqual(audioop.bias(datas[2], 2, 1), packs[2](1, 0x1235, 0x4568, -0x4566, -0x8000, -0x7FFF, 0)) self.assertEqual(audioop.bias(datas[2], 2, -1), packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7FFE, 0x7FFF, -2)) self.assertEqual( audioop.bias(datas[2], 2, 0x7FFFFFFF), packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7FFE, 0x7FFF, -2) ) self.assertEqual(audioop.bias(datas[2], 2, -0x80000000), datas[2]) self.assertEqual( audioop.bias(datas[4], 4, 1), packs[4](1, 0x12345679, 0x456789AC, -0x456789AA, -0x80000000, -0x7FFFFFFF, 0) ) self.assertEqual( audioop.bias(datas[4], 4, -1), packs[4](-1, 0x12345677, 0x456789AA, -0x456789AC, 0x7FFFFFFE, 0x7FFFFFFF, -2) ) self.assertEqual( audioop.bias(datas[4], 4, 0x7FFFFFFF), packs[4](0x7FFFFFFF, -0x6DCBA989, -0x3A987656, 0x3A987654, -2, -1, 0x7FFFFFFE), ) self.assertEqual( audioop.bias(datas[4], 4, -0x80000000), packs[4](-0x80000000, -0x6DCBA988, -0x3A987655, 0x3A987655, -1, 0, 0x7FFFFFFF), )
def generate_mouth_data(sample_data, compression, sample_rate, encoding): assert compression in constants.PCM_FORMATS assert encoding in constants.channel_counts assert sample_rate > 0 sample_width = constants.sample_widths[compression] channel_count = constants.channel_counts[encoding] if compression == constants.COMPRESSION_PCM_8_UNSIGNED: # bias by 128 to shift unsigned into signed sample_data = audioop.bias(sample_data, 1, 128) elif sample_width > 1 and compression not in constants.NATIVE_ENDIANNESS_FORMATS: # byteswap samples to system endianness before processing sample_data = audioop.byteswap(sample_data, sample_width) if sample_width == 2: sample_data = memoryview(sample_data).cast("h") elif sample_width == 4: sample_data = memoryview(sample_data).cast("i") # mouth data is sampled at 30Hz, so we divide the audio # sample_rate by that to determine how many samples we must # consider for each fragment. also, since mouth data doesn't # use multiple channels, and the audio samples are interleaved, # we multiply the channel count into the fragment_width. samples_per_mouth_sample = sample_rate / constants.SAMPLE_RATE_MOUTH_DATA fragment_width = int(channel_count * samples_per_mouth_sample + 0.5) # add fragment_width - 1 to round up to next multiple of fragment_width fragment_count = (len(sample_data) + fragment_width - 1) // fragment_width # used to scale the max fragment to the [0, 255] scale of a uint8 scale_to_uint8 = 255 / ((1 << (sample_width * 8 - 1)) - 1) # generate mouth data samples mouth_data = bytearray(fragment_count) for i in range(fragment_count): fragment = sample_data[i * fragment_width:(i + 1) * fragment_width] fragment_avg = sum(map(abs, fragment)) / samples_per_mouth_sample mouth_sample = fragment_avg * scale_to_uint8 if mouth_sample >= 255: mouth_data[i] = 255 else: mouth_data[i] = int(mouth_sample) # shift/scale the mouth samples based on the range of the mouth data mouth_avg = sum(mouth_data) / len(mouth_data) mouth_max = max(mouth_data) mouth_min = max(0, min(255, 2 * mouth_avg - mouth_max)) mouth_range = (mouth_avg + mouth_max) / 2 - mouth_min if mouth_range == 0: # no range in the volume. don't try to scale # or shift, or else we'll divide by zero return bytes(mouth_data) for i in range(len(mouth_data)): mouth_sample = (mouth_data[i] - mouth_min) / mouth_range if mouth_sample >= 1.0: mouth_data[i] = 255 elif mouth_sample <= 0.0: mouth_data[i] = 0 else: mouth_data[i] = int(255 * mouth_sample) return bytes(mouth_data)
def convert_pcm_to_pcm(samples, compression, target_compression, encoding=constants.ENCODING_MONO, target_encoding=constants.ENCODING_MONO, sample_rate=constants.SAMPLE_RATE_22K, target_sample_rate=constants.SAMPLE_RATE_22K): ''' Converts a stream of PCM audio to one with a different compression and/or encoding and/or sample rate. ''' assert compression in constants.PCM_FORMATS assert target_compression in constants.PCM_FORMATS current_width = constants.sample_widths.get(compression, 1) target_width = constants.sample_widths.get(target_compression, 1) if len(samples) % current_width: # ensure samples are a multiple of their width samples = samples[:len(samples) - (len(samples) % current_width)] if compression == constants.COMPRESSION_PCM_8_UNSIGNED: # bias by 128 to shift unsigned into signed samples = audioop.bias(samples, 1, 128) elif current_width > 1 and compression not in constants.NATIVE_ENDIANNESS_FORMATS: # byteswap samples to system endianness before processing samples = audioop.byteswap(samples, current_width) compression = change_pcm_endianness(compression) if current_width != target_width: samples = audioop.lin2lin(samples, current_width, target_width) # change compression to one with the correct sample width compression = change_pcm_width(compression, target_width) # make sure to convert to/from mono/stereo if encoding != target_encoding: if (encoding == constants.ENCODING_MONO and target_encoding == constants.ENCODING_STEREO): samples = audioop.tostereo(samples, target_width, 1, 1) elif (encoding == constants.ENCODING_STEREO and target_encoding == constants.ENCODING_MONO): samples = audioop.tomono(samples, target_width, 0.5, 0.5) else: raise ValueError( "Can only convert between mono and stereo encodings.") encoding = target_encoding # convert sample rate if necessary if sample_rate != target_sample_rate: samples, _ = audioop.ratecv(samples, target_width, constants.channel_counts[encoding], sample_rate, target_sample_rate, None) sample_rate = target_sample_rate if target_compression == constants.COMPRESSION_PCM_8_UNSIGNED: # bias by 128 to shift signed back into unsigned samples = audioop.bias(samples, 1, 128) elif target_width > 1 and (is_big_endian_pcm(compression) != is_big_endian_pcm(target_compression)): # byteswap samples to target endianness samples = audioop.byteswap(samples, target_width) return samples
def parsePCMA(self, packet): data = audioop.alaw2lin(packet.payload, 1) data = audioop.bias(data, 1, 128) self.pmin.write(packet.timestamp, data)
def encodePCMA(self, packet): packet = audioop.bias(packet, 1, -128) packet = audioop.lin2alaw(packet, 1) return packet
def get_chunk(src, bias): data = audioop.bias(src.read(10000), 2, bias) return data, audioop.maxpp(data, 2)
def convert_audio(infile, new_rate=None, freq=None): global verbose # rSound Sample format: # format:2 (0) # wave size:2 (sample size, in pages) # relative pitch:2 # stereo: 2 # sample rate:2 # sound data.... if verbose: print("Input File: {}".format(infile)) rv = bytearray() tr = b"\x01" + bytes(range(1, 256)) # remap 0 -> 1 rv += struct.pack("<10x") # header filled in later src, byteorder, fmt = open_audio(infile) width = src.getsampwidth() channels = src.getnchannels() rate = src.getframerate() bias = 128 swap = width > 1 and sys.byteorder != byteorder if width == 1 and fmt == 'wave': bias = 0 if verbose: print("Input: {} ch, {} Hz, {}-bit, {} ({} frames)".format( channels, rate, width * 8, fmt, src.getnframes())) if channels > 2: raise Exception("{}: Too many channels ({})".format(infile, channels)) cookie = None while True: frames = src.readframes(32) if not frames: break if swap: frames = audioop.byteswap(frames, width) if channels > 1: frames = audioop.tomono(frames, width, 0.5, 0.5) if new_rate: frames, cookie = audioop.ratecv(frames, width, 1, rate, new_rate, cookie) if width != 1: frames = audioop.lin2lin(frames, width, 1) if bias: frames = audioop.bias(frames, 1, bias) frames = frames.translate(tr) rv += frames src.close() # based on system 6 samples, pages rounds down.... pages = (len(rv) - 10) >> 8 hz = new_rate or rate rp = relative_pitch(hz, freq) struct.pack_into( "<HHHHH", rv, 0, 0, # format pages, # wave size in pages rp, 0, # stereo ??? hz # hz ) if verbose: print( "Output: 1 ch, {} Hz, 8-bit, rSoundSample ({} frames, {:.02f} Hz)". format(hz, len(rv) - 10, freq or 261.63)) print() return rv
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
bytes = s_read.getsampwidth() inrate = s_read.getframerate() print('File has ' + str(inchannels) + ' channels,' + str(bytes) + ' bytes per sample and rate ' + str(inrate)) try: print('converting to 16KHz!') converted = audioop.ratecv(data, bytes, inchannels, inrate, 16000, None) if (inchannels == 2): print('converting to mono!') converted = audioop.tomono(converted[0], bytes, 1, 0) if (bytes > 1): print('converting to 8-bit representation!') converted = audioop.lin2lin(converted, bytes, 1) converted = audioop.bias(converted, 1, 128) except: print 'Failed to downsample wav' quit() try: s_read.close() except: print 'Failed to close wav file' quit() ascii = [ord(c) for c in converted] arrayName = fileName.partition(".")[0] cnt = 0 out.write('const uint8_t ')
def test_bias(self): for w in 1, 2, 4: for bias in 0, 1, -1, 127, -128, 0x7fffffff, -0x80000000: self.assertEqual(audioop.bias(b'', w, bias), b'') self.assertEqual(audioop.bias(datas[1], 1, 1), b'\x01\x13\x46\xbc\x80\x81\x00') self.assertEqual(audioop.bias(datas[1], 1, -1), b'\xff\x11\x44\xba\x7e\x7f\xfe') self.assertEqual(audioop.bias(datas[1], 1, 0x7fffffff), b'\xff\x11\x44\xba\x7e\x7f\xfe') self.assertEqual(audioop.bias(datas[1], 1, -0x80000000), datas[1]) self.assertEqual(audioop.bias(datas[2], 2, 1), packs[2](1, 0x1235, 0x4568, -0x4566, -0x8000, -0x7fff, 0)) self.assertEqual(audioop.bias(datas[2], 2, -1), packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7ffe, 0x7fff, -2)) self.assertEqual(audioop.bias(datas[2], 2, 0x7fffffff), packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7ffe, 0x7fff, -2)) self.assertEqual(audioop.bias(datas[2], 2, -0x80000000), datas[2]) self.assertEqual(audioop.bias(datas[4], 4, 1), packs[4](1, 0x12345679, 0x456789ac, -0x456789aa, -0x80000000, -0x7fffffff, 0)) self.assertEqual(audioop.bias(datas[4], 4, -1), packs[4](-1, 0x12345677, 0x456789aa, -0x456789ac, 0x7ffffffe, 0x7fffffff, -2)) self.assertEqual(audioop.bias(datas[4], 4, 0x7fffffff), packs[4](0x7fffffff, -0x6dcba989, -0x3a987656, 0x3a987654, -2, -1, 0x7ffffffe)) self.assertEqual(audioop.bias(datas[4], 4, -0x80000000), packs[4](-0x80000000, -0x6dcba988, -0x3a987655, 0x3a987655, -1, 0, 0x7fffffff))
def bias(self, bias: int) -> 'Sample': """Add a bias constant to each sample value.""" if self.__locked: raise RuntimeError("cannot modify a locked sample") self.__frames = audioop.bias(self.__frames, self.__samplewidth, bias) return self
def __enter__(self): #@noter:崔冰 #@description: 读WAV/AIFF/FLAC格式的音频文件时进行的相关配置,及互相转换格式 assert self.stream is None, "This audio source is already inside a context manager" try: # 读wav格式音频 self.audio_reader = wave.open(self.filename_or_fileobject, "rb") self.little_endian = True # WAV是小端字节序格式 except (wave.Error, EOFError): try: # 读aiff格式音频 self.audio_reader = aifc.open(self.filename_or_fileobject, "rb") self.little_endian = False # AIFF是大端字节序格式 except (aifc.Error, EOFError): # 读FLAC格式音频 if hasattr(self.filename_or_fileobject, "read"): #判断有无有read属性 flac_data = self.filename_or_fileobject.read() else: with open(self.filename_or_fileobject, "rb") as f: flac_data = f.read() # 运行FLAC转换器,把FLAC数据转换成AIFF数据 flac_converter = get_flac_converter() if os.name == "nt": # 在Windows中, 指定该进程将在不显示控制台窗口的情况下启动 startup_info = subprocess.STARTUPINFO() startup_info.dwFlags |= subprocess.STARTF_USESHOWWINDOW # 指定`startup_info`的wShowWindow字段包含一个值 startup_info.wShowWindow = subprocess.SW_HIDE # 指定隐藏控制台窗口 else: startup_info = None # 默认启动信息 process = subprocess.Popen( [ flac_converter, "--stdout", "--totally-silent", #将生成的AIFF文件放入标准输出中,并确保它不与任何程序输出混合 "--decode", "--force-aiff-format", #将FLAC文件解码为AIFF 文件 "-", # 输入的FLAC 文件内容将在标准输入中给出 ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, startupinfo=startup_info) aiff_data, _ = process.communicate(flac_data) aiff_file = io.BytesIO(aiff_data) try: self.audio_reader = aifc.open(aiff_file, "rb") except (aifc.Error, EOFError): raise ValueError( "Audio file could not be read as PCM WAV, AIFF/AIFF-C, or Native FLAC; check if file is corrupted or in another format" ) self.little_endian = False # AIFF是大端字节序格式 assert 1 <= self.audio_reader.getnchannels( ) <= 2, "Audio must be mono or stereo" self.SAMPLE_WIDTH = self.audio_reader.getsampwidth() # 对于旧的Python版本,24位音频需要一些特殊处理 (应变方法:https://bugs.python.org/issue12866) samples_24_bit_pretending_to_be_32_bit = False if self.SAMPLE_WIDTH == 3: # 24位音频 try: audioop.bias(b"", self.SAMPLE_WIDTH, 0) # 测试是否支持此示例宽度 except audioop.error: # 此版本的audioop不支持24位音频 (可能低于Python 3.3) samples_24_bit_pretending_to_be_32_bit = True # 当``AudioFile`` 实例显示是 32位, 它其实是24位 self.SAMPLE_WIDTH = 4 # “AudioFile”实例现在应该呈现为32位数据流,因为我们将在读取时转换为32位 self.SAMPLE_RATE = self.audio_reader.getframerate() self.CHUNK = 4096 self.FRAME_COUNT = self.audio_reader.getnframes() self.DURATION = self.FRAME_COUNT / float(self.SAMPLE_RATE) self.stream = AudioFile.AudioFileStream( self.audio_reader, self.little_endian, samples_24_bit_pretending_to_be_32_bit) return self
def _flip_sign(self): 'Flip between signed and unsigned single byte samples' if self.params.sampwidth != 1: return self return self.__class__(self.params, audioop.bias(self.frames, 1, 0x80))
def __enter__(self): assert self.stream is None, "This audio source is already inside a context manager" try: # attempt to read the file as WAV self.audio_reader = wave.open(self.filename_or_fileobject, "rb") self.little_endian = True # RIFF WAV is a little-endian format (most ``audioop`` operations assume that the frames are stored in little-endian form) except wave.Error: try: # attempt to read the file as AIFF self.audio_reader = aifc.open(self.filename_or_fileobject, "rb") self.little_endian = False # AIFF is a big-endian format except aifc.Error: # attempt to read the file as FLAC if hasattr(self.filename_or_fileobject, "read"): flac_data = self.filename_or_fileobject.read() else: with open(self.filename_or_fileobject, "rb") as f: flac_data = f.read() # run the FLAC converter with the FLAC data to get the AIFF data flac_converter = get_flac_converter() process = subprocess.Popen( [ flac_converter, "--stdout", "--totally-silent", # put the resulting AIFF file in stdout, and make sure it's not mixed with any program output "--decode", "--force-aiff-format", # decode the FLAC file into an AIFF file "-", # the input FLAC file contents will be given in stdin ], stdin=subprocess.PIPE, stdout=subprocess.PIPE) aiff_data, stderr = process.communicate(flac_data) aiff_file = io.BytesIO(aiff_data) try: self.audio_reader = aifc.open(aiff_file, "rb") except aifc.Error: assert False, "Audio file could not be read as WAV, AIFF, or FLAC; check if file is corrupted" self.little_endian = False # AIFF is a big-endian format assert 1 <= self.audio_reader.getnchannels( ) <= 2, "Audio must be mono or stereo" self.SAMPLE_WIDTH = self.audio_reader.getsampwidth() # 24-bit audio needs some special handling for old Python versions (workaround for https://bugs.python.org/issue12866) samples_24_bit_pretending_to_be_32_bit = False if self.SAMPLE_WIDTH == 3: # 24-bit audio try: audioop.bias( b"", self.SAMPLE_WIDTH, 0 ) # test whether this sample width 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) samples_24_bit_pretending_to_be_32_bit = True # while the ``AudioFile`` instance will outwardly appear to be 32-bit, it will actually internally be 24-bit self.SAMPLE_WIDTH = 4 # the ``AudioFile`` instance should present itself as a 32-bit stream now, since we'll be converting into 32-bit on the fly when reading self.SAMPLE_RATE = self.audio_reader.getframerate() self.CHUNK = 4096 self.FRAME_COUNT = self.audio_reader.getnframes() self.DURATION = self.FRAME_COUNT / float(self.SAMPLE_RATE) self.stream = AudioFile.AudioFileStream( self.audio_reader, self.little_endian, samples_24_bit_pretending_to_be_32_bit) return self
def bias(self, bias): """Add a bias constant to each sample value.""" assert not self.__locked self.__frames = audioop.bias(self.__frames, self.__samplewidth, bias) return self
def iter_wave_values(self): """ yield frame numer + volume value from the WAVE file """ typecode = self.get_typecode(self.samplewidth) if log.level >= 5: if self.cfg.AVG_COUNT > 1: # merge samples -> log output in iter_avg_wave_values tlm = None else: tlm = TextLevelMeter(self.max_value, 79) # Use only a read size which is a quare divider of the samplewidth # Otherwise array.array will raise: ValueError: string length not a multiple of item size divider = int(round(float(WAVE_READ_SIZE) / self.samplewidth)) read_size = self.samplewidth * divider if read_size != WAVE_READ_SIZE: log.info("Real use wave read size: %i Bytes" % read_size) get_wave_block_func = functools.partial(self.wavefile.readframes, read_size) skip_count = 0 manually_audioop_bias = self.samplewidth == 1 and audioop is None for frames in iter(get_wave_block_func, ""): if self.samplewidth == 1: if audioop is None: log.warning("use audioop.bias() work-a-round for missing audioop.") else: # 8 bit samples are unsigned, see: # http://docs.python.org/2/library/audioop.html#audioop.lin2lin frames = audioop.bias(frames, 1, 128) try: values = array.array(typecode, frames) except ValueError, err: # e.g.: # ValueError: string length not a multiple of item size # Work-a-round: Skip the last frames of this block frame_count = len(frames) divider = int(math.floor(float(frame_count) / self.samplewidth)) new_count = self.samplewidth * divider frames = frames[:new_count] # skip frames log.error( "Can't make array from %s frames: Value error: %s (Skip %i and use %i frames)" % ( frame_count, err, frame_count - new_count, len(frames) )) values = array.array(typecode, frames) for value in values: self.wave_pos += 1 # Absolute position in the frame stream if manually_audioop_bias: # audioop.bias can't be used. # See: http://hg.python.org/cpython/file/482590320549/Modules/audioop.c#l957 value = value % 0xff - 128 # if abs(value) < self.min_volume: # # log.log(5, "Ignore to lower amplitude") # skip_count += 1 # continue yield (self.wave_pos, value)
def test_bias(self): for w in (1, 2, 3, 4): for bias in (0, 1, -1, 127, -128, 2147483647, -2147483648): self.assertEqual(audioop.bias(b'', w, bias), b'') self.assertEqual(audioop.bias(bytearray(), w, bias), b'') self.assertEqual(audioop.bias(memoryview(b''), w, bias), b'') self.assertEqual(audioop.bias(datas[1], 1, 1), b'\x01\x13F\xbc\x80\x81\x00') self.assertEqual(audioop.bias(datas[1], 1, -1), b'\xff\x11D\xba~\x7f\xfe') self.assertEqual(audioop.bias(datas[1], 1, 2147483647), b'\xff\x11D\xba~\x7f\xfe') self.assertEqual(audioop.bias(datas[1], 1, -2147483648), datas[1]) self.assertEqual(audioop.bias(datas[2], 2, 1), packs[2](1, 4661, 17768, -17766, -32768, -32767, 0)) self.assertEqual(audioop.bias(datas[2], 2, -1), packs[2](-1, 4659, 17766, -17768, 32766, 32767, -2)) self.assertEqual(audioop.bias(datas[2], 2, 2147483647), packs[2](-1, 4659, 17766, -17768, 32766, 32767, -2)) self.assertEqual(audioop.bias(datas[2], 2, -2147483648), datas[2]) self.assertEqual( audioop.bias(datas[3], 3, 1), packs[3](1, 1193047, 4548490, -4548488, -8388608, -8388607, 0)) self.assertEqual( audioop.bias(datas[3], 3, -1), packs[3](-1, 1193045, 4548488, -4548490, 8388606, 8388607, -2)) self.assertEqual( audioop.bias(datas[3], 3, 2147483647), packs[3](-1, 1193045, 4548488, -4548490, 8388606, 8388607, -2)) self.assertEqual(audioop.bias(datas[3], 3, -2147483648), datas[3]) self.assertEqual( audioop.bias(datas[4], 4, 1), packs[4](1, 305419897, 1164413356, -1164413354, -2147483648, -2147483647, 0)) self.assertEqual( audioop.bias(datas[4], 4, -1), packs[4](-1, 305419895, 1164413354, -1164413356, 2147483646, 2147483647, -2)) self.assertEqual( audioop.bias(datas[4], 4, 2147483647), packs[4](2147483647, -1842063753, -983070294, 983070292, -2, -1, 2147483646)) self.assertEqual( audioop.bias(datas[4], 4, -2147483648), packs[4](-2147483648, -1842063752, -983070293, 983070293, -1, 0, 2147483647))
def __init__(self, filename: str, mode: str = 'r', depth: int = 16, rate: int = 44100, channels: int = 2, bigendian: bool = False, unsigned: bool = False, **kwargs): """Loads and play all filetypes supported. Load 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 decompose(swave, framerate, instruments=[tri_string, square_string, sin_string, saw_string]): matches = {} sample_width = 2 total_samples = len(swave) / sample_width block_start = 0 block_end = min(total_samples, block_start + BLOCK_SIZE) next_block = None while block_end - block_start == BLOCK_SIZE: if next_block is None: lblock = swave[block_start * sample_width:block_end * sample_width] else: lblock = next_block if DEBUG_MODE: debug_show_and_play_sample(lblock) noisy_block = False for j in xrange(PEAKS_IN_BLOCK): if next_block is None: peaks, phases = get_peaks_and_phases(lblock) else: peaks = next_peaks phases = next_phases if DEBUG_MODE: debug_display_peaks(peaks) peak = max(peaks) #TODO: normal level detection if peak < 1: print "too quiet." noisy_block = False continue peak_index = peaks.index(peak) phase = phases[peak_index] peaks[peak_index] = 0 next_block = swave[block_end * sample_width:(2 * block_end - block_start) * sample_width] next_peaks, next_phases = get_peaks_and_phases(next_block) next_phase = next_phases[peak_index] phase_delta = next_phase - phase freq_res = float(framerate) / FFT_BLOCK_SIZE base_freq = (peak_index + phase_delta / (2 * math.pi)) * freq_res peak = 1000 periods = int(BLOCK_SIZE * base_freq / framerate) wavelength = int(framerate / base_freq) window_left = max(0, block_start - wavelength / 2) window_right = min(total_samples, block_end + wavelength / 2) window = swave[window_left * sample_width:window_right * sample_width] dc_offset = sum(str_to_list(window)) * sample_width / len(window) window = audioop.bias(window, sample_width, -dc_offset) best_offset = None best_factor = None best_periods = 0 best_freq = base_freq best_rms = audioop.rms(window, sample_width) best_instrument = 0 for p in xrange(1, periods): for inst, wavegen in enumerate(instruments): freq = base_freq pattern = wavegen(framerate, freq, peak, p) offset, factor = audioop.findfit(window, pattern) #window_pattern = window[offset * sample_width:offset * sample_width + len(pattern)] window_pattern = window pattern = complete_silence(pattern, offset, len(window) / sample_width) fitted_pattern = audioop.mul(pattern, sample_width, -factor) applied_pattern = audioop.add(window_pattern, fitted_pattern, sample_width) dc_offset = sum(str_to_list( applied_pattern)) * sample_width / len(applied_pattern) applied_pattern = audioop.bias(applied_pattern, sample_width, -dc_offset) rms = audioop.rms(applied_pattern, sample_width) # if DEBUG_MODE and p > 3: # print "debug: ", p, freq, rms, best_rms, offset # matplotlib.pyplot.plot(str_to_list(window_pattern), 'b') # matplotlib.pyplot.plot(str_to_list(fitted_pattern), 'r') # matplotlib.pyplot.plot(str_to_list(applied_pattern), 'g') # matplotlib.pyplot.show() # matplotlib.pyplot.close() if ((best_rms > 0) and (rms < best_rms * 1.02)) or (best_rms == rms == 0): best_rms = rms best_periods = p best_factor = factor best_offset = offset + window_left best_instrument = inst best_freq = freq print "found: ", best_periods, best_freq, best_rms if not best_freq in matches: matches[best_freq] = [] if best_periods < 3: #block_start = max(best_offset, block_start + 1) #block_end = min(total_samples, block_start + BLOCK_SIZE) block_start = block_end block_end = min(total_samples, block_start + BLOCK_SIZE) noisy_block = True print "too short period" break if not best_factor: print "no waveforms found." continue amp = best_factor * peak wavegen = instruments[best_instrument] print "%5.2f Hz at level %5.2f for %4i periods" % (best_freq, amp, best_periods) matches[best_freq].append( (best_offset, amp, best_periods, best_instrument)) pattern = wavegen(framerate, best_freq, -int(amp), best_periods) complement = complete_silence(pattern, best_offset, total_samples) if DEBUG_MODE: waveout = wave.open("tmp.wav", "wb") waveout.setparams( (2, 2, 44100, 531788, 'NONE', 'not compressed')) outdata = join_stereo(pattern, pattern) waveout.writeframes(outdata) waveout.close() subprocess.Popen( r"C:\Program Files (x86)\Winamp\winamp.exe tmp.wav") matplotlib.pyplot.plot( str_to_list(swave[block_start * sample_width:block_end * sample_width])) matplotlib.pyplot.plot( str_to_list( complement[block_start * sample_width:block_end * sample_width]), 'r') matplotlib.pyplot.show(block=True) matplotlib.pyplot.close() swave = audioop.add(swave, complement, sample_width) if not noisy_block: block_start = block_end block_end = min(total_samples, block_start + BLOCK_SIZE) print block_start, block_end print "block processed." result = audioop.mul(swave, sample_width, 0) for best_freq, notes in matches.iteritems(): for note in notes: offset, amp, periods, best_instrument = note wavegen = instruments[best_instrument] pattern = wavegen(framerate, best_freq, amp, periods) prepared_sample = complete_silence(pattern, offset, len(result) / 2) result = audioop.add(result, prepared_sample, sample_width) return result
def test_bias(self): for w in 1, 2, 3, 4: for bias in 0, 1, -1, 127, -128, 0x7fffffff, -0x80000000: self.assertEqual(audioop.bias(b'', w, bias), b'') self.assertEqual(audioop.bias(bytearray(), w, bias), b'') self.assertEqual(audioop.bias(memoryview(b''), w, bias), b'') self.assertEqual(audioop.bias(datas[1], 1, 1), b'\x01\x13\x46\xbc\x80\x81\x00') self.assertEqual(audioop.bias(datas[1], 1, -1), b'\xff\x11\x44\xba\x7e\x7f\xfe') self.assertEqual(audioop.bias(datas[1], 1, 0x7fffffff), b'\xff\x11\x44\xba\x7e\x7f\xfe') self.assertEqual(audioop.bias(datas[1], 1, -0x80000000), datas[1]) self.assertEqual( audioop.bias(datas[2], 2, 1), packs[2](1, 0x1235, 0x4568, -0x4566, -0x8000, -0x7fff, 0)) self.assertEqual( audioop.bias(datas[2], 2, -1), packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7ffe, 0x7fff, -2)) self.assertEqual( audioop.bias(datas[2], 2, 0x7fffffff), packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7ffe, 0x7fff, -2)) self.assertEqual(audioop.bias(datas[2], 2, -0x80000000), datas[2]) self.assertEqual( audioop.bias(datas[3], 3, 1), packs[3](1, 0x123457, 0x45678a, -0x456788, -0x800000, -0x7fffff, 0)) self.assertEqual( audioop.bias(datas[3], 3, -1), packs[3](-1, 0x123455, 0x456788, -0x45678a, 0x7ffffe, 0x7fffff, -2)) self.assertEqual( audioop.bias(datas[3], 3, 0x7fffffff), packs[3](-1, 0x123455, 0x456788, -0x45678a, 0x7ffffe, 0x7fffff, -2)) self.assertEqual(audioop.bias(datas[3], 3, -0x80000000), datas[3]) self.assertEqual( audioop.bias(datas[4], 4, 1), packs[4](1, 0x12345679, 0x456789ac, -0x456789aa, -0x80000000, -0x7fffffff, 0)) self.assertEqual( audioop.bias(datas[4], 4, -1), packs[4](-1, 0x12345677, 0x456789aa, -0x456789ac, 0x7ffffffe, 0x7fffffff, -2)) self.assertEqual( audioop.bias(datas[4], 4, 0x7fffffff), packs[4](0x7fffffff, -0x6dcba989, -0x3a987656, 0x3a987654, -2, -1, 0x7ffffffe)) self.assertEqual( audioop.bias(datas[4], 4, -0x80000000), packs[4](-0x80000000, -0x6dcba988, -0x3a987655, 0x3a987655, -1, 0, 0x7fffffff))
def __init__(self, filename, pitch=None, rate=None, channel=0, **kwargs): super().__init__(**kwargs) new_rate = rate freq = pitch_to_hz(pitch) if not freq: raise ValueError("Invalid pitch: {}".format(pitch)) # audio conversion verbose = False # if verbose: print("Input File: {}".format(filename)) rv = bytearray() tr = b"\x01" + bytes(range(1, 256)) # remap 0 -> 1 rv += struct.pack("<10x") # header filled in later src, byteorder, fmt = open_audio(filename) width = src.getsampwidth() channels = src.getnchannels() rate = src.getframerate() bias = 128 swap = width > 1 and sys.byteorder != byteorder if width == 1 and fmt == 'wave': bias = 0 if verbose: print("Input: {} ch, {} Hz, {}-bit, {} ({} frames)".format( channels, rate, width * 8, fmt, src.getnframes())) if channels > 2: raise Exception("{}: Too many channels ({})".format( filename, channels)) cookie = None while True: frames = src.readframes(32) if not frames: break if swap: frames = audioop.byteswap(frames, width) if channels > 1: frames = audioop.tomono(frames, width, 0.5, 0.5) if new_rate: frames, cookie = audioop.ratecv(frames, width, 1, rate, new_rate, cookie) if width != 1: frames = audioop.lin2lin(frames, width, 1) if bias: frames = audioop.bias(frames, 1, bias) frames = frames.translate(tr) rv += frames src.close() # based on system 6 samples, pages rounds down.... # probably a bug. pages = (len(rv) - 10 + 255) >> 8 hz = new_rate or rate rp = relative_pitch(hz, freq) struct.pack_into( "<HHHHH", rv, 0, 0, # format pages, # wave size in pages rp, channel, # stereo hz # hz ) self.data = bytes(rv) self.pages = pages self.channel = channel self.relative_pitch = rp self.sample_rate = hz if verbose: print( "Output: 1 ch, {} Hz, 8-bit, rSoundSample ({} frames, {:.02f} Hz)" .format(hz, len(rv) - 10, freq or 261.63)) print()