Tuesday, May 15, 2012

Sonification - sound of sand - 6

Frequency domain - What we did with volume in the previous post we now do with frequencies. The python program below converts the X- and Y-components of the shape into varying frequencies. The input shapes are the same as in the previous example. You can hear the sound samples here:

Again the sounds are very technical and abstract. I'll leave it like that for the moment. I'm still learning about what I can do. You can see the spectrum of the signal as it appears in Audacity:

It is easy to see that the spectrum now has the shape of the X- and Y- components of the shapes.

Next time I'll try to map the shape to the frequency domain while using the original waveform and not a pure sine signal. To do this I'll have to resample the waveform. This is a bit tricky to program but should give a more interesting signal.

In the meantime I've found a lot of interesting articles about shape sonification. In the future I'll try to do things with the curvature of the shape. And I haven't done anything with the spectral components yet.

from Nsound import *
import math

def convert_chaincode_to_x(c,x):
    if c == 1 or c == 0 or c == 7:
        x = x + 1
        return (x)
    elif ( c == 2 or c == 6):
        x = x
        return (x)
        x = x - 1
        return (x)

def convert_chaincode_to_y(c,y):
    if c == 1 or c == 2 or c == 3:
        y = y + 1
    elif c == 4 or c == 0:
        y = y
        y = y - 1

def sine_duration_frequency(duration, frequency):
    g = Generator(44100.0)
    length = math.ceil(float(duration) * float(frequency))/float(frequency)
    return g.drawSine(length, frequency)

def convert_xy_frequency(xy, minxy, maxxy, minf, maxf):
    r = float(maxf - minf)/float(maxxy - minxy)
    f = (xy - minxy)*r + minf
return (f)

# ==============================
debug1  = False
debug2  = False
debug2a = False
debug3  = True

# read a chaincode .chc file that has been generated by SHAPE
infile = open("C:\\Users\\user\\Documents\\shape\\shape\\tiny_test.chc")
instr = infile.read()
if debug1:
    print instr

# parse the input file - split it into words
inwords = instr.split(' ')
if debug1:
print inwords

# delete anything except the chain code
i = 0
for str in inwords:
    if str.find('0E+0') > -1 :
    i = i + 1
inwords = inwords[i+2:len(inwords)-1]
if debug1:
    print inwords

# fill the x and y buffer with the chaincode values
b_x_chaincode = Buffer()
b_y_chaincode = Buffer()
x = 0
y = 0
for str in inwords:
    c = int(str)
    x = convert_chaincode_to_x(c,x)
    b_x_chaincode << x
    y = convert_chaincode_to_y(c,y)
    b_y_chaincode << y

    if debug2a:
    print c
        print x

if debug2:
    b_x_chaincode.plot("x value from chaincode")
    b_y_chaincode.plot("y value from chaincode")

b_x_chaincode = b_x_chaincode - b_x_chaincode.getMean()
b_y_chaincode = b_y_chaincode - b_y_chaincode.getMean()
# generate a frequency modulated x and y signal
temp = Buffer()
b_x_long = Buffer()
b_y_long = Buffer()

soundpixel_length = 0.02
min_f = 40.0
max_f = 5000.0

min_x = b_x_chaincode.getMin()
max_x = b_x_chaincode.getMax()

if debug3:

for x in b_x_chaincode:
    frequency = convert_xy_frequency(x, min_x, max_x, min_f, max_f)
    b_x_long << sine_duration_frequency(soundpixel_length, frequency)

    if debug3:
        i = i+1
        p = int(len(b_x_chaincode)/4)
        if i%p == 0:
            b = Buffer()
            b = sine_duration_frequency(soundpixel_length, frequency)


min_y = b_y_chaincode.getMin()
max_y = b_y_chaincode.getMax()
for y in b_y_chaincode:
    frequency = convert_xy_frequency(y, min_y, max_y, min_f, max_f)
    b_y_long << sine_duration_frequency(soundpixel_length, frequency)

# code the x and y signal into the left and right channel of an audio stream
# write the audio stream into a .wav file
a = AudioStream(44100.0, 2)
a[0] = b_x_long
a[1] = b_y_long
a.writeWavefile("C:\\Users\\user\\Documents\\shape\\shape\\tiny_test xy_freq_chaincode.wav")

No comments:

Post a Comment