Beispiel #1
0
def play_excerpt(input_file, duration=5, use_fade=False, remove_silence=False):
    """Play an excerpt of an audio file.

    Parameters
    ----------
    input_file : str
        Audio file to play.

    duration : float
        Length of excerpt in seconds.

    use_fade : bool
        If true, apply a fade in and fade out.

    remove_silence: bool
        If true, forces entire segment to have sound by removing silence.
    """
    ext = util.fileext(input_file)
    tmp_file = util.temp_file(ext)
    if remove_silence:
        remove_silence(input_file, tmp_file)
    else:
        tmp_file = input_file

    if not use_fade:
        play(tmp_file, end_t=duration)
    else:
        tmp_file2 = util.temp_file(ext)
        fade(tmp_file, tmp_file2, fade_in_time=0.5, fade_out_time=1)
        play(tmp_file2, end_t=duration)
Beispiel #2
0
 def test_trim(self):
     output_file = util.temp_file(formats.WAVE)
     self.assert_(
         sox.trim(input_file=self.input_file,
                  output_file=output_file,
                  start_time=0,
                  end_time=0.1), "Conversion failed.")
Beispiel #3
0
 def test_trim_inplace(self):
     another_file = util.temp_file(formats.WAVE)
     shutil.copy(self.input_file, another_file)
     self.assert_(
         sox.trim(input_file=another_file,
                  output_file=None,
                  start_time=0,
                  end_time=0.1), "Conversion failed.")
     self.assert_(os.path.exists(another_file))
Beispiel #4
0
 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.")
Beispiel #5
0
    def __init__(self, filepath, samplerate=None, channels=None,
                 bytedepth=None, mode="r"):
        """Base class for interfacing with audio files.

        When writing audio files, samplerate, channels, and bytedepth must be
        specified. Otherwise, these parameters may be None when reading to use
        the default values of the audio file.

        Parameters
        ----------
        filepath : str
            Absolute path to a sound file. Does not need to exist (yet).

        samplerate : float, default=None
            Samplerate for the audio file.

        channels : int, default=None
            Number of channels for the audio file.

        bytedepth : int, default=None
            bytedepth (in bytes) of the returned file. For example, CD-quality
            audio has a bytedepth of 2 (16-bit).

        mode : str, default='r'
            Open the file for [r]eading or [w]riting.
        """
        logger.debug(util.classy_print(AudioFile, "Constructor."))
        if not sox.is_valid_file_format(filepath):
            raise ValueError("Cannot handle this filetype: {}"
                             "".format(filepath))
        if mode == "w":
            # TODO: If/raise
            assert samplerate, "Writing audiofiles requires a samplerate."
            assert channels, "Writing audiofiles requires channels."
            assert bytedepth, "Writing audiofiles requires a bytedepth."

        self._filepath = filepath
        self._wave_handle = None
        self._temp_filepath = util.temp_file(formats.WAVE)

        self._mode = mode
        logger.debug(util.classy_print(AudioFile, "Opening wave file."))
        self.__get_handle__(self.filepath, samplerate, channels, bytedepth)
        logger.debug(util.classy_print(AudioFile, "Success!"))
        if self.duration == 0:
            warnings.warn("Caution: You have opened an empty sound file!")
Beispiel #6
0
def convert(input_file,
            output_file,
            samplerate=None,
            channels=None,
            bytedepth=None):
    """Converts one audio file to another on disk.

    Parameters
    ----------
    input_file : str
        Input file to convert.

    output_file : str
        Output file to writer.

    samplerate : float, default=None
        Desired samplerate. If None, defaults to the same as input.

    channels : int, default=None
        Desired channels. If None, defaults to the same as input.

    bytedepth : int, default=None
        Desired bytedepth. If None, defaults to the same as input.

    Returns
    -------
    status : bool
        True on success.
    """
    args = ['sox', '--no-dither', input_file]

    if bytedepth:
        assert bytedepth in [1, 2, 3, 4, 8]
        args += ['-b%d' % (bytedepth * 8)]
    if channels:
        args += ['-c %d' % channels]
    if output_file is None:
        output_file = util.temp_file(formats.WAVE)

    args += [output_file]

    if samplerate:
        args += ['rate', '-I', '%f' % samplerate]

    return _sox(args)
Beispiel #7
0
def soundsc(signal, samplerate):
    """Play a signal as a normalized soundwave.

    Parameters
    ----------
    signal : np.ndarray, shape=(num_samples, num_channels)
        Signal to sonify.

    samplerate : scalar
        Samplerate to use for audio playback.
    """
    tmp_file = util.temp_file(formats.WAVE)
    signal = np.asarray(signal)
    signal *= 0.98 / np.abs(signal).max()
    fileio.write(tmp_file, signal, samplerate)
    try:
        sox.play(tmp_file)
    except KeyboardInterrupt:
        pass
Beispiel #8
0
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)
Beispiel #9
0
def trim(input_file, output_file, start_time, end_time):
    """Excerpt a clip from an audio file, given a start and end time.

    Parameters
    ----------
    input_file : str
        Sound file to trim.

    output_file : str
        File for writing output.

    start_time : float
        Start time of the clip.

    end_time : float
        End time of the clip.

    Returns
    -------
    status : bool
        True on success.
    """
    assert start_time >= 0, "The value for 'start_time' must be positive."
    assert end_time >= 0, "The value for 'end_time' must be positive."
    inplace = not bool(output_file)
    if inplace:
        output_file = util.temp_file(os.path.splitext(input_file)[-1])

    status = _sox([
        'sox', input_file, output_file, 'trim',
        '%0.8f' % start_time,
        '%0.8f' % (end_time - start_time)
    ])
    if inplace:
        os.rename(output_file, input_file)
    return status
Beispiel #10
0
class FileIOTests(unittest.TestCase):
    input_file = util.temp_file(formats.WAVE)
    samplerate = 440
    channels = 1
    bytedepth = 2
    num_repeats = 110
    test_dir = os.path.dirname(__file__)

    def setUp(self):
        "Generate a wave file for testing."
        self.wave_handle = wave.open(self.input_file, mode="w")
        self.wave_handle.setframerate(self.samplerate)
        self.wave_handle.setnchannels(self.channels)
        self.wave_handle.setsampwidth(self.bytedepth)

        # Corresponds to [0.0, 0.5, 0.0, -0.5], or a sine-wave at
        # half-Nyquist. This should sound tonal, for debugging.
        self.wave_handle.writeframes(
            six.b('\x00\x00\x00@\x00\x00\x00\xc0') * self.num_repeats)
        self.wave_handle.close()

    def test_AudioFile_params(self):
        af = fileio.AudioFile(self.input_file, mode='r')
        self.assertEqual(af.samplerate, self.samplerate,
                         "Samplerate mismatch.")
        self.assertEqual(af.channels, self.channels, "Channel mismatch.")
        self.assertEqual(af.bytedepth, self.bytedepth, "Byte depth mismatch.")
        self.assertEqual(af.filepath, self.input_file, "Filepath mismatch.")
        self.assertEqual(af.num_samples, self.num_repeats * 4,
                         "Sample count mismatch.")

    def test_AudioFile_new_params(self):
        new_samplerate = 4000
        new_channels = 2
        new_bytedepth = 1
        af = fileio.AudioFile(self.input_file,
                              samplerate=new_samplerate,
                              channels=new_channels,
                              bytedepth=new_bytedepth,
                              mode='r')
        self.assertEqual(af.samplerate, new_samplerate, "Samplerate mismatch.")
        self.assertEqual(af.channels, new_channels, "Channel mismatch.")
        self.assertEqual(af.bytedepth, new_bytedepth, "Byte depth mismatch.")

    def test_FramedAudioFile_set_framerate(self):
        framerate = 10
        overlap = 0.6
        stride = 40
        af = fileio.FramedAudioFile(self.input_file,
                                    samplerate=400,
                                    framesize=100,
                                    framerate=framerate)
        self.assertEqual(af.framerate, framerate, "Framerate mismatch.")
        self.assertEqual(af.overlap, overlap, "Overlap mismatch.")
        self.assertEqual(af.stride, stride, "Stride mismatch.")

    def test_FramedAudioFile_set_stride(self):
        framerate = 10
        overlap = 0.6
        stride = 40
        af = fileio.FramedAudioFile(self.input_file,
                                    samplerate=400,
                                    framesize=100,
                                    stride=stride)
        self.assertEqual(af.framerate, framerate, "Framerate mismatch.")
        self.assertEqual(af.overlap, overlap, "Overlap mismatch.")
        self.assertEqual(af.stride, stride, "Stride mismatch.")

    def test_FramedAudioFile_set_overlap(self):
        framerate = 10
        overlap = 0.6
        stride = 40
        af = fileio.FramedAudioFile(self.input_file,
                                    samplerate=400,
                                    framesize=100,
                                    overlap=overlap)
        self.assertEqual(af.framerate, framerate, "Framerate mismatch.")
        self.assertEqual(af.overlap, overlap, "Overlap mismatch.")
        self.assertEqual(af.stride, stride, "Stride mismatch.")

    def test_FramedAudioReader_read_center_aligned(self):
        af = fileio.FramedAudioReader(self.input_file,
                                      framesize=8,
                                      alignment='center',
                                      overlap=0.5)
        frame_0 = np.array([0, 0, 0, 0, 0, 0.5, 0, -0.5]).reshape(8, 1)
        frame_n = np.array([0, 0.5, 0, -0.5, 0, 0.5, 0, -0.5]).reshape(8, 1)
        for i, frame_act in enumerate(af):
            err_msg = "Frame-%d mismatch." % i
            if i == 0:
                np.testing.assert_array_equal(frame_act, frame_0, err_msg,
                                              True)
            else:
                np.testing.assert_array_equal(frame_act, frame_n,
                                              "Frame-%d mismatch." % i, True)

    def test_FramedAudioReader_read_left_aligned(self):
        af = fileio.FramedAudioReader(self.input_file,
                                      framesize=8,
                                      alignment='left',
                                      overlap=0.5)
        frame_exp = np.array([0, 0.5, 0, -0.5, 0, 0.5, 0, -0.5]).reshape(8, 1)
        frame_end = np.array([0, 0.5, 0, -0.5, 0, 0, 0, 0]).reshape(8, 1)
        for i, frame_act in enumerate(af):
            err_msg = "Frame-%d mismatch." % i
            if i == (self.num_repeats - 1):
                np.testing.assert_array_equal(frame_act, frame_end, err_msg,
                                              True)
            else:
                np.testing.assert_array_equal(frame_act, frame_exp, err_msg,
                                              True)

    def test_read_real_wave(self):
        wav_file = os.path.join(self.test_dir, 'sample.wav')
        signal, samplerate = fileio.read(wav_file)
        assert len(signal)
        assert samplerate

    def test_read_real_aiff(self):
        aiff_file = os.path.join(self.test_dir, 'sample.aiff')
        signal, samplerate = fileio.read(aiff_file)
        assert len(signal)
        assert samplerate

    def test_write_wave(self):
        wav_file = os.path.join(self.test_dir, 'sample.wav')
        x, fs1 = fileio.read(wav_file)

        tmp = tempfile.NamedTemporaryFile(suffix='.wav')
        fileio.write(tmp.name, x, fs1)
        y, fs2 = fileio.read(tmp.name)
        np.testing.assert_array_almost_equal(x, y)
        assert fs1 == fs2
Beispiel #11
0
class SoxTests(unittest.TestCase):
    input_file = util.temp_file(formats.WAVE)
    samplerate = 1000
    channels = 1
    bytedepth = 2

    @classmethod
    def setUp(self):
        "Generate a local wave file for testing sox."
        self.wave_handle = wave.open(self.input_file, mode="w")
        self.wave_handle.setframerate(self.samplerate)
        self.wave_handle.setnchannels(self.channels)
        self.wave_handle.setsampwidth(self.bytedepth)

        # Corresponds to [0.0, 0.5, 0.0, -0.5], or a sine-wave at
        # half-Nyquist. This should sound tonal, for debugging.
        self.wave_handle.writeframes(
            six.b("\x00\x00\x00@\x00\x00\x00\xc0") * 200)
        self.wave_handle.close()

    def test_formats(self):
        self.assertEqual(sox.is_valid_file_format("some.wav"), True,
                         "Wav check failed.")
        self.assertEqual(sox.is_valid_file_format("booger"), False,
                         "Extension-less format failed.")
        self.assertEqual(sox.is_valid_file_format("curious.george"), False,
                         "Invalid extension failed.")

    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 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 test_trim(self):
        output_file = util.temp_file(formats.WAVE)
        self.assert_(
            sox.trim(input_file=self.input_file,
                     output_file=output_file,
                     start_time=0,
                     end_time=0.1), "Conversion failed.")

    def test_trim_inplace(self):
        another_file = util.temp_file(formats.WAVE)
        shutil.copy(self.input_file, another_file)
        self.assert_(
            sox.trim(input_file=another_file,
                     output_file=None,
                     start_time=0,
                     end_time=0.1), "Conversion failed.")
        self.assert_(os.path.exists(another_file))

    def test_file_info(self):
        self.assert_(sox.file_info(self.input_file), "File Info failed.")