1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
#!/usr/bin/python
# TODO: When the distance goes beyound the wave file length the IR tail migth click or even disapear on silence. Solution compute the maximum delay and add it to all the waves.
# sudo apt-get install python-numpy
# sudo apt-get install sox
import os
import sys
import numpy
import math
import cmath
import normalizeAndWav
def readDatFile(filename) :
wavefile = file(filename, "r")
return [ float(sample) for time, sample in [ line.split() for line in wavefile.readlines() if line[0]!=";"]]
def writeDatFile(filename, samples) :
result = []
result += ["; Sample Rate 44100\n"]
result += ["; Channels 1\n"]
result += [ "%.11g %.11g\n"%(timeInSamples/44100., sample) for timeInSamples, sample in zip( range(0, len(samples)), samples) ]
wavefile = file(filename, "w")
wavefile.writelines(result)
def shiftSamples(audio, deltaSamples) :
if deltaSamples == 0 : return
if deltaSamples > 0 :
audio[deltaSamples:] = audio[:-deltaSamples]
audio[0:deltaSamples] = 0
else:
deltaSamples = abs(deltaSamples) # make it positive
audio[0:-deltaSamples] = audio[deltaSamples:]
audio[-deltaSamples:] = 0
# Configurable parameters. (TODO make them arguments with sane defaults)
setting = 2
if setting == 1:
NX = 10
NY = 10
sizeX = 2. #meters
sizeY = 2. #meters
recordingDistance = .524263 #meters
xs = NX/2.
ys = NY/2.
elif setting == 2:
NX = 10
NY = 10
sizeX = 12. #meters
sizeY = 12. #meters
recordingDistance = 7 #meters
xs = NX/2.
ys = NY/2.
elif setting == 3: #offline 1 - guitar
NX = 20
NY = 20
sizeX = 12. #meters
sizeY = 12. #meters
recordingDistance = 6 #meters
xs = NX/2.
ys = NY/8.
elif setting == 4: #offline 2 - cajon
NX = 20
NY = 20
sizeX = 12. #meters
sizeY = 12. #meters
recordingDistance = 6 #meters
xs = NX/2.
ys = 7*NY/8.
elif setting == 5: #offline 2 - bailaora
NX = 20
NY = 20
sizeX = 12. #meters
sizeY = 12. #meters
recordingDistance = 6 #meters
xs = 3*NX/4.
ys = 0
else:
assert False, "bad setting"
databasePrefix = "carneltest"
wavSourcePrefix = "wavs/CarnelTest"
print "Usage: ", sys.argv[0], "wav-source-prefix database-prefix"
print "Example: ", sys.argv[0], "wavs/CarnelShort carnelshort"
if len(sys.argv)==3:
wavSourcePrefix = sys.argv[1]
databasePrefix = sys.argv[2]
databaseDir = databasePrefix+"Database"
print "wavSourcePrefix:", wavSourcePrefix
print "databaseDir:", databaseDir
recordingAzimut = 0 #radians
recordedFilesPattern = databasePrefix+"%s.dat"
filepattern = databaseDir+"/%s_emissor_%i-%i-%i_receptor_%i-%i-%i.dat"
print "creating database dir: ", databaseDir
os.system("mkdir -p %s" % databaseDir)
for suffix in ("P","X","Y"):
os.system("sox %s%s.wav %s%s.dat"%(wavSourcePrefix,suffix,databasePrefix,suffix) )
print "Loading recorded impulse responses..."
recordedComponents = dict( [
( suffix, numpy.array(readDatFile(recordedFilesPattern % suffix)) )
for suffix in ("P", "X", "Y") ] )
scale = complex(sizeX/NX, sizeY/NY)
minDistance = min(scale.real, scale.imag)
for xt in range(NX) :
for yt in range(NY) :
gridWayToSource = (complex(xs, ys) - complex(xt, yt))
wayToSource = complex(gridWayToSource.real*scale.real, gridWayToSource.imag*scale.imag)
distanceToSource = abs(wayToSource) or minDistance
azimuthToSource = math.atan2(wayToSource.real, wayToSource.imag)
distanceFactor = recordingDistance/distanceToSource
azimuthRotation = azimuthToSource - recordingAzimut
deltaSamples = int((distanceToSource - recordingDistance)*44100/340)
print distanceToSource, wayToSource, deltaSamples
assert(deltaSamples >= -2000)
P,X,Y = [distanceFactor * component for component in
[recordedComponents[c] for c in ["P","X","Y"] ] ]
for component in P,X,Y:
shiftSamples(component, deltaSamples)
X, Y = \
(X * math.cos(azimuthRotation) + Y * math.sin(azimuthRotation),
-X * math.sin(azimuthRotation) + Y * math.cos(azimuthRotation))
print "Writing data...", xt, yt
#continue
writeDatFile(filepattern % ("p", 0,0,0, xt,yt,0) , P)
writeDatFile(filepattern % ("vx", 0,0,0, xt,yt,0) , X)
writeDatFile(filepattern % ("vy", 0,0,0, xt,yt,0) , Y)
print
print "\n== Normalize and convert to wav ==\n"
normalizeAndWav.processDir(databaseDir)
|