On Thu, 17 Jun 2010 23:44:28 +0400
Louigi Verona <louigi.ver...@gmail.com> wrote:

> Hello Simon!
> I am interested - how do you achieve phasing on Linux? Using what tools?
> 
> --
> Louigi Verona
> http://www.louigiverona.ru
> 

Check this out.. you will need python and numpy.

Simon.
#!/usr/bin/env python

import sys
from math import sqrt

import wave
import numpy

scalar = numpy.float32

SAMPLERATE = 44100

def read_wave(filename):

    w = wave.open(filename)

    chunks = []
    count = 0
    while 1:
        chunk = w.readframes(4096)
        if not chunk:
            break
        count += len(chunk)
        chunks.append(chunk)

    a = numpy.empty(count, numpy.float32)
    i = 0
    for chunk in chunks:

        b = numpy.fromstring(chunk, numpy.int16)
        n = len(b)
        a[i:i+n] = b
        i += n

    assert i == count/2

    x0, x1 = a.min(), a.max()
    assert x0<x1
    a = a / (x1-x0)

    return a



def normalize(a, volume=1.):
    print "peak-to-peak: %.2f" % (a.max()-a.min())
    assert 0. <= volume <= 1.
    if a.max() - a.min() > 1e-8:
        #centre = (a.max() + a.min()) / 2
        #a -= centre
        a *= float(volume) * 32767 / (a.max() - a.min()) 
    else:
        print " *** quiet array"
    return a.astype(numpy.int16)



def write_wave(filename, a, samplerate=SAMPLERATE):

    assert len(a.shape)==1 or a.shape[1] in (1, 2), "odd shape = %r"%(a.shape,)
    channels = 1 if len(a.shape)==1 else a.shape[1]
    print "write_wave", filename, 'channels=', channels

    a = normalize(a)

    f = wave.open(filename, 'w')
    f.setnchannels(channels)
    f.setsampwidth(2)
    f.setframerate(samplerate)
    f.writeframesraw(a.tostring())
    f.close()


_window_cache = {}
def window(a, d_idx=None, attack=100, decay=100):
    #print "window", len(a), d_idx, attack, decay
    if d_idx is None:
        d_idx = len(a)
    key = (d_idx, attack, decay)
    w = _window_cache.get(key)
    if w is None:
        w = numpy.empty(d_idx, dtype=scalar)
        w[:] = 1.
        for idx in range(attack):
            w[int(idx)] = 1.*idx/float(attack)
        for idx in range(decay):
            w[int(d_idx - idx-1)] = 1.*idx/float(decay) # ramp up
        _window_cache[key] = w

    a = a[0 : d_idx]
    a = a*w
    return a



def paint(a, b, idx0, idx1=None):

    if idx1 is None:
        idx1 = len(b)

    idx0 = int(idx0)
    idx1 = int(idx1)
    adx0, adx1 = idx0, idx0+idx1
    bdx0, bdx1 = 0, idx1
    try:
        a[adx0 : adx1] += b[bdx0 : bdx1]
    except ValueError:
        print "paint: ValueError"
        pass



    

def main(source, target, stacks=10, dt=0.1, cycles=30):

    a = read_wave(source)

    N = len(a) * cycles
    A = numpy.zeros((N,), scalar) # use (N, 2) for stereo output
    dn = dt * SAMPLERATE
    bs = [a[:len(a) - dn*i] for i in range(stacks)]
    for b in bs:
        idx = 0
        while idx + len(b) < len(A):
            b = window(b)
            paint(A[:], b, idx)
            idx += len(b)

    #a = A[len(a):] # skip the first cycle...
    A[:len(a)] /= sqrt(cycles) # attenuate the first cycle...

    write_wave(target, A)





if __name__ == "__main__":

    if not sys.argv[1:]:
        print "USAGE:\n\tphaser.py source.wav target.wav\n"
    else:
    
        source = sys.argv[1]
        target = sys.argv[2]
    
        main(source, target)




_______________________________________________
Linux-audio-dev mailing list
Linux-audio-dev@lists.linuxaudio.org
http://lists.linuxaudio.org/listinfo/linux-audio-dev

Reply via email to