Some short Python examples to illustrate basic use of the getZ and absZ methods, the DetectorCache, the OnsetDetector and the FrequencyShifter.
Simple Example
''' Simple example to read in a file, create a DetectorBank with two octaves
of detectors and plot the abs(z) values.
'''
import numpy as np
import scipy.io.wavfile
from detectorbank import DetectorBank
import matplotlib.pyplot as plt
sr, audio = scipy.io.wavfile.read('file.wav')
if audio.dtype == 'int16':
audio = audio / 2**15
f = np.array(list(440 * 2**(k/12) for k in range(-12, 13)))
bandwidth = np.zeros(len(f))
det_char = np.array(list(zip(f, bandwidth)))
method = DetectorBank.runge_kutta
f_norm = DetectorBank.freq_unnormalized
a_norm = DetectorBank.amp_normalized
damping = 0.0001
gain = 25
det =
DetectorBank(sr, audio.astype(np.float32), 4, det_char,
method|f_norm|a_norm, damping, gain)
z = np.zeros((len(f),len(audio)), dtype=np.complex128)
det.getZ(z)
r = np.zeros(z.shape)
m = det.absZ(r, z)
print('Max: {}'.format(m))
t = np.linspace(0, r.shape[1]/sr, r.shape[1])
for k in range(r.shape[0]):
line, = plt.plot(t,r[k])
plt.show()
Using the DetectorCache
The previous example required all of the z values to be kept in RAM. For long audio files and/or many detectors, this is impractical. The DetectorCache enables you to store a number of short segments of abs(z) values. If you request a value not currently in the cache, old segments will be deleted and new ones created until the requested sample is reached. This means the DetectorCache can only go forwards: once a segment has been deleted, attempting to access values from it will cause an exception to be thrown. (For more information, please see SlidingBuffer.)
''' DetectorCache example: create a DetectorBank and use a DetectorCache to
access abs(z) values on demand.
'''
import numpy as np
import scipy.io.wavfile
from detectorbank import DetectorBank, Producer, DetectorCache
sr, audio = scipy.io.wavfile.read('file.wav')
if audio.dtype == 'int16':
audio = audio / 2**15
f = np.array(list(440 * 2 ** (k/12) for k in range(-5,5)))
bandwidth = np.zeros(len(f))
bandwidth[2] = 7
det_char = np.array(list(zip(f, bandwidth)))
method = DetectorBank.runge_kutta
f_norm = DetectorBank.freq_unnormalized
a_norm = DetectorBank.amp_normalized
damping = 0.0001
gain = 25
det =
DetectorBank(sr, audio.astype(np.float32), 0, det_char,
method|f_norm|a_norm, damping, gain)
p = Producer(det)
cache = DetectorCache(p, 2, sr)
result = cache[5,0]
print(result)
result = cache[7,100000]
print(result)
try:
result = cache[3,1000]
except IndexError as err:
print('Attempting to access a value from a discarded segment throws an exception:')
print('IndexError: {}'.format(err))
Saving and Loading DetectorBank Profiles
The DetectorBank has a facility to save itself, so it can be reloaded, instead of constructing a new DetectorBank with the same parameters.
import numpy as np
from detectorbank import DetectorBank
f = np.array(list(440 * 2**(k/12) for k in range(-48, 40)))
bandwidth = np.zeros(len(f))
det_char = np.array(list(zip(f, bandwidth)))
sr = 48000
method = DetectorBank.runge_kutta
f_norm = DetectorBank.freq_unnormalized
a_norm = DetectorBank.amp_normalized
damping = 0.0001
gain = 25
det =
DetectorBank(sr, np.zeros(1).astype(np.float32), 0, det_char,
method|f_norm|a_norm, damping, gain)
det.saveProfile('88 key piano, RK4, f un, a nrm')
This profile can then be loaded into a new program thus:
sr, audio = scipy.io.wavfile.read('file.wav')
if audio.dtype == 'int16':
audio = audio / 2**15
det = db.DetectorBank('88 key piano, RK4, f un, a nrm', audio.astype(np.float32))
Using the FrequencyShifter
This package also contains a FrequencyShifter. You probably won't need to use it in conjunction with a DetectorBank (it will be applied automatically, if necessary), but it may be useful in other applications, so here's a short usage example. (Full explantion of the operation of the FrequencyShifter can be found here.)
''' FrequencyShifter example: create a sine tone at a given frequency, then
modulate it and plot the power spectral density of both signals.
'''
import numpy as np
from detectorbank import FrequencyShifter
import matplotlib.pyplot as plt
sr = 48000
f0 = 10000
f_shift = -7000
t = np.linspace(0, 2*np.pi*f0, sr)
signal = np.sin(t)
signal = signal.astype(np.float32)
shifted = np.zeros(signal.shape, dtype=np.float32)
fs.shift(f_shift, shifted)
f, (ax1, ax2) = plt.subplots(2, sharex=True)
ax1.psd(signal, Fs=sr)
ax1.set_xlim(xmax=sr//2)
ax1.set_ylim(-120, -20)
ax1.set_xlabel('')
ax1.set_ylabel('dB/Hz')
ax2.psd(shifted, Fs=sr)
ax2.set_xlim(xmax=sr//2)
ax2.set_ylim(-120, -20)
ax2.set_ylabel('dB/Hz')
plt.show()