예제 #1
0
def block_mix_wavs(wavpath_a,
                   wavpath_b,
                   out_wavpath,
                   a_gain=1.,
                   b_gain=1.,
                   block_size=4096,
                   mute_left=False):
    '''
    Mix two wav files, applying gains to each
    '''
    wav_a = PySndfile(wavpath_a, 'r')
    wav_b = PySndfile(wavpath_b, 'r')

    out_wav = PySndfile(out_wavpath, 'w', construct_format('wav', 'pcm16'),
                        wav_a.channels(), wav_a.samplerate())

    i = 0
    while i < wav_a.frames():
        if i + block_size > wav_a.frames():
            block_size = wav_a.frames() - i
        x1 = wav_a.read_frames(block_size)
        x2 = wav_b.read_frames(block_size)
        x1[:, :2] *= a_gain
        x2 *= b_gain
        if x1.shape[1] == 3:
            y = np.zeros(x1.shape)
            y[:, 0] = x1[:, 0] + x2
            y[:, 1] = x1[:, 1] + x2
            y[:, 2] = x1[:, 2]
            if mute_left:
                y[:, 0] = 0.0
        else:
            y = x1 + x2
        out_wav.write_frames(y)
        i += block_size
예제 #2
0
def block_process_wav(wavpath, out_wavpath, func, block_size=4096, **args):
    '''
    Mix two wav files, applying gains to each
    '''
    wav = PySndfile(wavpath, 'r')

    out_wav = PySndfile(out_wavpath, 'w', construct_format('wav', 'pcm16'),
                        wav.channels(), wav.samplerate())

    i = 0
    while i < wav.frames():
        if i + block_size > wav.frames():
            block_size = wav.frames() - i
        x = wav.read_frames(block_size)
        y = func(x, **args)
        out_wav.write_frames(y)
        i += block_size
    del out_wav
예제 #3
0
    def __init__(self, fn, sr=None, chns=None, blksz=2**16, dtype=np.float32):
        fnd = False

        if not fnd and (PySndfile is not None):
            try:
                sf = PySndfile(fn, mode='r')
            except IOError:
                pass
            else:
                if (sr is None or sr == sf.samplerate()) and (
                        chns is None or chns == sf.channels()):
                    # no resampling required
                    self.channels = sf.channels()
                    self.samplerate = sf.samplerate()
                    self.frames = sf.frames()

                    self.rdr = sndreader(sf, blksz, dtype=dtype)
                    fnd = True

        if not fnd:
            ffmpeg = findfile('ffmpeg') or findfile('avconv')
            if ffmpeg is not None:
                pipe = sp.Popen([ffmpeg, '-i', fn, '-'],
                                stdin=sp.PIPE,
                                stdout=sp.PIPE,
                                stderr=sp.PIPE)
                fmtout = pipe.stderr.read()
                if (sys.version_info > (3, 0)):
                    fmtout = fmtout.decode()
                m = re.match(
                    r"^(ffmpeg|avconv) version.*Duration: (\d\d:\d\d:\d\d.\d\d),.*Audio: (.+), (\d+) Hz, (.+), (.+), (\d+) kb/s",
                    " ".join(fmtout.split('\n')))
                if m is not None:
                    self.samplerate = int(m.group(4)) if not sr else int(sr)
                    chdef = m.group(5)
                    if chdef.endswith(" channels") and len(chdef.split()) == 2:
                        self.channels = int(chdef.split()[0])
                    else:
                        try:
                            self.channels = {
                                'mono': 1,
                                '1 channels (FL+FR)': 1,
                                'stereo': 2,
                                'hexadecagonal': 16
                            }[chdef] if not chns else chns
                        except:
                            print(f"Channel definition '{chdef}' unknown")
                            raise
                    dur = reduce(lambda x, y: x * 60 + y,
                                 list(map(float,
                                          m.group(2).split(':'))))
                    self.frames = int(
                        dur * self.samplerate
                    )  # that's actually an estimation, because of potential resampling with round-off errors
                    pipe = sp.Popen(
                        [
                            ffmpeg, '-i', fn, '-f', 'f32le', '-acodec',
                            'pcm_f32le', '-ar',
                            str(self.samplerate), '-ac',
                            str(self.channels), '-'
                        ],
                        #                    bufsize=self.samplerate*self.channels*4*50,
                        stdin=sp.PIPE,
                        stdout=sp.PIPE,
                        stderr=sp.PIPE)

                    def rdr():
                        bufsz = (blksz // self.channels) * self.channels * 4
                        while True:
                            data = pipe.stdout.read(bufsz)
                            if len(data) == 0:
                                break
                            data = np.fromstring(data, dtype=dtype)
                            yield data.reshape((-1, self.channels)).T

                    self.rdr = rdr()
                    fnd = True

        if not fnd:
            raise IOError("Format not usable")