[CM] Python bindings

Todd Ingalls TestCase at asu.edu
Thu Mar 23 11:15:24 PDT 2023

Hello Bill, Everyone

Have found myself having to use python a lot lately and have not been too happy with choice of sound libs I started making bindings for sndlib https://github.com/testcase/pysndlib

There is a lot more to do but just wanted to mention this in case anyone else is working on the same thing or may want to hack this or make recommendations, etc

I used ctypesgen (https://github.com/ctypesgen/ctypesgen) to generate bindings from header files and then have been coding wrapper functions.

I used ctypes for the ffi and also want it to work nicely with numpy. Really want to keep this as simple as possible.

I also focused on trying to be as literal as possible with translation so that it would be easy to port existing examples. This may mean something aren’t pythonic.

It is not exactly fast but was not expecting it to be using python/

Want to also be able to use this in juypter notebooks for teaching sound synthesis next year

Many rough edges and things to be documented. Error handling in non-existent but feel like I at least have some working examples. There is an examples.py file with some simple things just ported from the the simple examples in the docs. Hope to address much of this in coming month or so.

Of course all thanks to Bill for everything . This is really just simple translation of everything you have done. Would be happy to see this folded into main project or  keep is separate for easier maintenance. Whatever is best

To give a sense here is an example with jc-reverb and some simple instrument.

def jc_reverb(lowpass=False, volume=1., amp_env = None):
allpass1 = make_all_pass(-.7, .7, 1051)
allpass2 = make_all_pass(-.7, .7, 337)
allpass3 = make_all_pass(-.7, .7, 113)
comb1 = make_comb(.742, 4799)
comb2 = make_comb(.733, 4999)
comb3 = make_comb(.715, 5399)
comb4 = make_comb(.697, 5801)
chans = Sound.output.mus_channels
length = Sound.reverb.mus_length
filts = [make_delay(seconds2samples(.013))] if chans == 1 else [make_delay(seconds2samples(.013)),make_delay(seconds2samples(.011)) ]
combs = make_comb_bank([comb1, comb2, comb3, comb4])
allpasses = make_all_pass_bank([allpass1,allpass2,allpass3])
if lowpass or amp_env:
flt = make_fir_filter(3, [.25, .5, .25]) if lowpass else None
envA = make_env(amp_env, scaler=volume, duration = length / mus_srate())
if lowpass:
for i in range(length):
out_bank(filts, i, (env(envA) * fir_filter(flt, comb_bank(combs, all_pass(allpasses, ina(i, Sound.reverb))))))
for i in range(length):
out_bank(filts, i, (env(envA) * comb_bank(combs, all_pass_bank(allpasses, ina(i, Sound.reverb)))))
if chans == 1:
gen = filts[0]
for i in range(length):
outa(i, delay(gen), volume * comb_bank(combs, all_pass_bank(allpasses, ina(i, Sound.reverb))))
gen1 = filts[0]
gen2 = filts[1]
for i in range(length):
val = volume * comb_bank(combs, all_pass_bank(allpasses, ina(i, Sound.reverb)))
outa(i, delay(gen1, val))
outb(i, delay(gen2, val))

def blip(beg, dur, freq):
start = seconds2samples(beg)
end = seconds2samples(dur) + start
loc = make_locsig(degree=random.randrange(-90, 90), distance=1., reverb=.7)
cmb = make_comb(0.4, seconds2samples(0.4))
osc = make_oscil(freq)
ampf = make_env([0.0, 0.0, 1.0, 1.0, 2.0, 1.0, 3.0, 0.0], length=4410)
for i in range(start, end):
locsig(loc, i, 0.5 * (comb(cmb, env(ampf) * oscil(osc))))

with Sound("out1.aif", 2, reverb=jc_reverb, reverb_channels=2, play=True):
blip(0, 2, 100)
blip(1, 2, 400)
blip(2, 2, 200)
blip(3, 2, 300)
blip(4, 2, 500)

Todd Ingalls
Associate Director
School of Arts, Media and Engineering

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://cm-mail.stanford.edu/pipermail/cmdist/attachments/20230323/bd4ca55a/attachment-0001.html>

More information about the Cmdist mailing list