def test_convert_format(self): output_file = os.path.splitext(self.input_file)[0] + ".aif" self.assert_( sox.convert(input_file=self.input_file, output_file=output_file, samplerate=self.samplerate / 2, channels=self.channels, bytedepth=self.bytedepth), "Conversion to .aif failed.")
def __get_handle__(self, filepath, samplerate, channels, bytedepth): """Get hooks into a wave object for reading or writing. Parameters ---------- filepath : str samplerate : float channels : int bytedepth : int On success, creates an open wave file handle corresponding to filepath, or a tempfile after a successful SoX conversion. Note: This could probably be pulled out into a standalone function, but using class members makes this a little cleaner. Something to consider. """ self._CONVERT = False if self._mode == 'r': try: self._wave_handle = wave.open(filepath, 'r') if bytedepth and self.bytedepth != bytedepth: self._CONVERT = True if samplerate and self.samplerate != samplerate: self._CONVERT = True if channels and self.channels != channels: self._CONVERT = True except wave.Error: self._CONVERT = True if self._CONVERT: # TODO: Catch status, raise on != 0 assert sox.convert(input_file=filepath, output_file=self._temp_filepath, samplerate=samplerate, bytedepth=bytedepth, channels=channels), \ "SoX Conversion failed for '%s'." % filepath self._wave_handle = wave.open(self._temp_filepath, 'r') else: fmt_ext = os.path.splitext(self.filepath)[-1].strip('.') if fmt_ext == formats.WAVE: self._wave_handle = wave.open(self.filepath, self._mode) else: # To write out non-wave files, need a temp wave object first. self._CONVERT = True self._wave_handle = wave.open( self._temp_filepath, self._mode) # Set file parameters # TODO: Encapsulate? self._wave_handle.setframerate(samplerate) self._wave_handle.setsampwidth(bytedepth) self._wave_handle.setnchannels(channels)
def test_convert_samplerate(self): output_file = util.temp_file(formats.WAVE) self.assert_( sox.convert(input_file=self.input_file, output_file=output_file, samplerate=self.samplerate / 2, channels=self.channels, bytedepth=self.bytedepth), "Conversion with different samplerate failed.") wav_handle = wave.open(output_file, mode='r') self.assertEqual(self.samplerate / 2, wav_handle.getframerate(), "Samplerate conversion failed.")
def write(filepath, signal, samplerate=44100, bytedepth=2): """Write an audio signal to disk. Parameters ---------- filepath: str Path to an audio file. signal : np.ndarray, ndim in [1,2] Audio signal to write to disk. samplerate: scalar, or None for file's default Samplerate for the returned audio signal. bytedepth : int, default=2 Number of bytes for the audio signal; must be 2. """ if bytedepth != 2: raise NotImplementedError("Currently only 16-bit audio is supported.") tmp_file = util.temp_file(formats.WAVE) if formats.WAVE == os.path.splitext(filepath)[-1].strip('.'): tmp_file = filepath signal = np.asarray(signal) signal = signal.reshape(-1, 1) if signal.ndim == 1 else signal fp = wave.open(tmp_file, 'w') fp.setnchannels(signal.shape[-1]) fp.setsampwidth(bytedepth) fp.setframerate(samplerate) fp.writeframes(util.array_to_byte_string(signal, bytedepth)) fp.close() if tmp_file != filepath: sox.convert(tmp_file, filepath)
def close(self): """Explicit destructor.""" logging.debug(util.classy_print(AudioFile, "Cleaning up.")) if self._wave_handle: self._wave_handle.close() if self._mode == 'w' and self._CONVERT: logging.debug( util.classy_print(AudioFile, "Conversion required for writing.")) # TODO: Update to if / raise assert sox.convert(input_file=self._temp_filepath, output_file=self.filepath, samplerate=self.samplerate, bytedepth=self.bytedepth, channels=self.channels) if self._temp_filepath and os.path.exists(self._temp_filepath): logging.debug(util.classy_print(AudioFile, "Temporary file deleted.")) os.remove(self._temp_filepath)