Basic Usage#
A convenient way to get started with pysndlib is to use the Sound context manager to handle manager a number of details when rendering audio to a file or numpy array.
opening a closing of the main soundfile being written to including giving it a name
setting the samplerate, header type and sample type of the soundfile
scaling of the audio values to a specific range
the following will generate a sound file with two sine waves if will play after rendering using CLM.player clipped is False which means it does not clip the signal at -1 to 1 scaled_to with normalize amplitude to .5 if clipped was True (the default) the signal would be clipped first and then scaled which gives a very different output in this example
import pysndlib.clm as clm
with clm.Sound(play=True, statistics=True, scaled_to=.5, clipped=False):
osc1 = clm.make_oscil(330)
osc2 = clm.make_oscil(500)
for i in range(44100):
clm.outa(i, clm.oscil(osc1) + clm.oscil(osc2))
Here is an example showing writing the same thing to a numpy array and using finalize to call a function to plot the signal
import pysndlib.clm as clm
from matplotlib import pyplot as plt
def plot_mono_arr(arr):
plt.figure(figsize=(6,6))
plt.plot(arr[0], color='gray')
plt.tight_layout()
plt.show()
outarr = np.zeros((1,44100))
with clm.Sound(outarr, statistics=True, scaled_to=.5, clipped=False, finalize=plot_mono_arr):
osc1 = clm.make_oscil(330)
osc2 = clm.make_oscil(500)
for i in range(44100):
clm.outa(i, clm.oscil(osc1) + clm.oscil(osc2))
This is an example of defining a reverb function that is applied after the initial output is rendered. using locsig makes this even easier. to make a reverb you must also use the @clm.clm_reverb decorator
Note clm.default.reverb gets defined within the with Sound context.
@clm.clm_reverb
def bad_mono_rev1(volume=1.):
ap1 = clm.make_all_pass(-.9, .9, 1051)
ap2 = clm.make_all_pass(-.9, .9, 1207)
ap3 = clm.make_all_pass(-.9, .9, 1000)
dly = clm.make_delay(clm.seconds2samples(.011))
length = clm.get_length(clm.default.reverb)
apb = clm.make_all_pass_bank([ap1, ap2, ap3])
for i in range(length):
clm.outa(i, clm.delay(dly, volume * clm.all_pass_bank(apb, clm.ina(i, clm.default.reverb))))
with clm.Sound('ex2.wav', play=True, statistics=True, reverb=bad_mono_rev1(.5)):
osc = clm.make_oscil(500)
e = clm.make_env([0.,0.0, .05, .8, .4, 0.0, 1.0, 0.0], length=22050)
for i in range(44100*2):
val = clm.env(e)*clm.oscil(osc)
clm.outa(i, val*.6)
clm.outa(i, val*.4, clm.default.reverb)
Lastly an example that demonstrates defining functions that can be called in Sound context that uses finalize to plot the output file after the reverb has been applied
from matplotlib import pyplot as plt
def plot_mono_soundfile(filename):
y, _ = file2ndarray(filename)
plt.figure(figsize=(6,6))
plt.plot(y[0], color='gray')
plt.tight_layout()
plt.show()
@clm.clm_reverb
def bad_mono_rev1(volume=1.):
ap1 = clm.make_all_pass(-.9, .9, 1051)
ap2 = clm.make_all_pass(-.9, .9, 1207)
ap3 = clm.make_all_pass(-.9, .9, 1000)
dly = clm.make_delay(clm.seconds2samples(.011))
length = clm.get_length(clm.default.reverb)
apb = clm.make_all_pass_bank([ap1, ap2, ap3])
for i in range(length):
clm.outa(i, clm.delay(dly, volume * clm.all_pass_bank(apb, clm.ina(i, clm.default.reverb))))
def blip(start, dur, freq):
osc = clm.make_oscil(freq)
beg = clm.seconds2samples(start)
end = beg + clm.seconds2samples(dur)
e = clm.make_env([0.,0.0, .05, .8, .4, 0.0, 1.0, 0.0], duration=dur*.5)
for i in range(beg, end):
val = clm.oscil(osc) * env(e)
clm.outa(i, val*.6)
clm.outa(i, val*.4, clm.default.reverb)
with clm.Sound('ex2.wav', play=True, statistics=True, reverb=bad_mono_rev1, finalize=plot_mono_soundfile):
blip(0, 1, 400)
blip(1, 1, 500)
blip(2, 1, 600)
blip(3, 1, 900)
for i in np.arange(4, 6, .333333):
blip(i, .5, 800)