W E L C O M E

Namaste and Welcome to the "Nuts About Electronics" Blog.

I am an electronics hobbyist based in India. Recently, I rediscovered my childhood passion in tinkering with electronic circuits. I created this blog to share some of my projects, as well as provide some useful information to other hobbyists in India, where many electronic components are hard to find.

Please note that the projects as well as code in this blog are provided "as is", with no guarantees. Working with electricity, electronic components, soldering irons, etc. requires safety precautions - please use your common sense.

Good luck with your projects, and above all, have FUN!

MV

Saturday, August 1, 2009

The Karplus-Strong Algorithm

As part of my ongoing audio projects with Arduino, I was looking for a programmatic way of generating complex sounds. It is simple enough to create a pure tone with a sine wave. But real sounds are complex, with mixtures of overtones or frequencies that rise and fall over time. I recently found an interesting algorithm called "Karplus-Strong string synthesis" which simulates the sound of a plucked string. I wrote a program in Python to explore this algorithm, and I think the sounds produced by this algorithm are just amazing.

First, listen to the 2 samples below, produced by the algorithm:

1. simple.wav
2. ks.wav

Now for the code that produced these:

Here is a simple Python program that generates the sound from a single plucked string, and writes it out to a WAV file.


############################################################
#
# karplus-simple.py
#
# Author: MV (http://electro-nut.blogspot.com/)
#
# Generates a plucked string sound WAV file using the
# Karplus-Strong algorithm. (Simple version.)
#
############################################################
from math import sin, pi
from array import array
from random import random

import wave

# KS params
SR = 44100
f = 220
N = SR/f

# WAV params
NCHANNELS = 1
SWIDTH = 2
FRAME_RATE = 44100
NFRAMES = 44100
NSAMPLES = 44100
# max - 128 for 8-bit, 32767 for 16-bit
MAX_VAL= 32767

# pluck
buf = [random() - 0.5 for i in range(N)]

#init samples
samples = []

# KS - ring buffer
bufSize = len(buf)
for i in range(NSAMPLES):
samples.append(buf[0])
avg = 0.996*0.5*(buf[0] + buf[1])
buf.append(avg)
buf.pop(0)

# samples to 16-bit to string
tmpBuf = [int(x*MAX_VAL) for x in samples]
data = array('h', tmpBuf).tostring()

# write out WAV file
file = wave.open('simple.wav', 'wb')
file.setparams((NCHANNELS, SWIDTH, FRAME_RATE, NFRAMES,
'NONE', 'noncompressed'))
file.writeframes(data)
file.close()


Here is a more object oriented version of the code above, which lets you mix sounds from multiple string plucks.


############################################################
#
# karplus.py
#
# Author: MV (http://electro-nut.blogspot.com/)
#
# Generates a plucked string sound WAV file using the
# Karplus-Strong algorithm.
#
############################################################
from math import sin, pi
from array import array
from random import random
import wave

# KS params
SR = 44100
f = 220

# WAV params
NCHANNELS = 1
SWIDTH = 2
FRAME_RATE = 44100
NFRAMES = 44100
NSAMPLES = 44100*2
# max - 128 for 8-bit, 32767 for 16-bit
MAX_VAL= 32767

class String:
def __init__(self, freq, SR):
self.freq = freq
self.N = SR/freq
# 'pluck' string
def pluck(self):
self.buf = [random() - 0.5 for i in range(self.N)]
# return current sample, increment step
def sample(self):
val = self.buf[0]
avg = 0.996*0.5*(self.buf[0] + self.buf[1])
self.buf.append(avg)
self.buf.pop(0)
return val

str1, str2 = String(196, SR), String(440, SR)

str1.pluck()
str2.pluck()

samples = []

for i in range(NSAMPLES):
sample = str1.sample()
if(i > NSAMPLES/8):
sample += str2.sample()
samples.append(sample)

# samples to 16-bit to string
tmpBuf = [int(x*MAX_VAL) for x in samples]
data = array('h', tmpBuf).tostring()

# write out WAV file
file = wave.open('ks.wav', 'wb')
file.setparams((NCHANNELS, SWIDTH, FRAME_RATE, NFRAMES,
'NONE', 'noncompressed'))
file.writeframes(data)
file.close()



It remains to be seen how I can adapt this to the Arduino. But it has been a fun project!

References

1. You can read details about the algorithm here:

http://en.wikipedia.org/wiki/Karplus-Strong_string_synthesis

2. Here is a programming assignment from Princeton which started me off on this project:

http://www.cs.princeton.edu/courses/archive/spring09/cos126/assignments/guitar.html


2 comments:

Nicolau said...

Very nice!...

Will you continue in your vacation, and implement a whole physically accurate digital waveguide model? :)

How is your Arduino project? Do you plan to make a guitar synthesizer? One idea you might use to make the sound more interesting is synthesizing two or three strings at the same time, with approximate parameters, and sum them all...

David said...

I was just wondering if you had ever gotten this running on the Arduino?