This Python module defines a Waveform class with methods sinewave and noise. Sinewave generates a specified frequency and noise generates samples with specified standard deviation. The constructor requires the duration for both methods to be specified. Class variables are the sampling rate and the number of channels. The packed strings and the signal and noise lists are available. main() adds these and uses Bandpass (from bpf_class - Kaiser window response above) to filter the unpacked samples, using lfilter from audioop. Audio before and after filtering is played and recorded to file.
#!/usr/bin/python
import wave, struct, math, audioop
from alsaaudio import *
import signal, sys, getopt
from numpy.random import normal
from scipy.signal import lfilter
from bpf_class import Bandpass
class Waveform:
" Waveform Class Generates different waveforms with duration (Sec) length "
def __init__(self, duration):
self.rate = 8000 # frame rate
self.channels = 1 # mono stereo etc
self.frames = int(duration * self.rate) # number of samples (2 bytes)
# sound card device initialization (alsa module)
self.out = PCM(type=PCM_PLAYBACK, mode=PCM_NONBLOCK, card='default')
# parameters
self.out.setchannels(self.channels)
self.out.setrate(self.rate)
# Signed 16 bit samples for each channel (Little Endian byte order)
self.out.setformat(PCM_FORMAT_S16_LE) # how sound card interprets data
self.out.setperiodsize(self.frames)
def sinewave(self, frequency):
self.frequency = frequency
# note sinewave peak is limited to magnitude 0.1
sig = [ 0.1 * math.sin( 2.0*math.pi*self.frequency*x/self.rate ) for x in range(self.frames)]
# The scale factor for 16bit resolution
scale = ( 2**16 - 1 )/2.0
# Scale the signal list
self.sig_16 = [ int(scale*x) for x in sig ]
self.sinewave=struct.pack('<'+self.channels*self.frames*'h',*self.sig_16)
# note above 'h' not 'l' (c type short, python integer 2) for 16 bit samples
# with l, self.dit packed into (long) integer size=4
# self.out.write(self.sinewave) # plays the sound in self.sinewave
def noise(self, sigma):
self.sigma = sigma # Standard deviation
mu = 0 # mean
noise = normal(mu, sigma, self.frames)
scale = ( 2**16 - 1 )/2.0
# Scale the noise list
self.noise_scaled = [ int(scale*x) for x in noise ]
self.noiseout=struct.pack('<'+self.channels*self.frames*'h',*self.noise_scaled)
# note above 'h' not 'l' (c type short, python integer 2) for 16 bit samples
# with l, self.dit packed into (long) integer size=4
# self.out.write(self.noiseout) # plays the sound in self.noiseout
#-------------------------------------------------------------------------------------------
def main():
mysound1 = Waveform(10)
mysound1.rate = 6000 # 6k samples per sec
a=mysound1.noise(0.2) # noise with 0.2 std dev
b=mysound1.sinewave(720)# sinewave freq 720
# add coded noise and sinewave samples
c=audioop.add(mysound1.noiseout, mysound1.sinewave, 2)
mysound1.out.write(c) # play unfiltered signal
# Now add the noise and sinewave samples before structured packing
d = [sum(pair) for pair in zip(mysound1.noise_scaled, mysound1.sig_16,)]
d[:] = [x*0.5 for x in d] # attenuate (each sample) by 6dB
bpf700hz = Bandpass() # create 700 hz bpf
# Use lfilter to filter test signal with Bandpass filter.
filtered_d = lfilter(bpf700hz.taps, 1.0, d)
# Pack the filtered sinewave and noise
mysound1.filterout=struct.pack('<'+mysound1.channels*mysound1.frames*'h',*filtered_d)
# Play the filtered sound
mysound1.out.write(mysound1.filterout)
# open file and write filtered sound to it.
f = open('out.raw', 'wb')
f.write(mysound1.filterout)
# to play file :~/python/audio$ python playbacktest.py out.raw
if __name__ == '__main__':
main()
Comments