This worked on my computor. Thank you. It will take me sometime to digest the program.
-- regards, Sarma. On Fri, Sep 14, 2012 at 12:33 AM, eryksun <eryk...@gmail.com> wrote: > > I've modified my previous script to add simple polyphonic sound. I > included a basic square wave and a sawtooth wave, plus a random > polyphonic wave. It's the kind of sound you might hear in a cheesy > greeting card. Also, since you're looking to use winsound.PlaySound(), > I changed the byte packing to use a little endian signed short > (int16). I think that's what Windows wave files use. > > My demo below still uses pyaudio, which wraps the cross-platform > PortAudio library. To me it seems like a better solution than relying > on the standard library (e.g. the standard lib uses OSS on Linux; I > don't even have that installed). > > Hopefully it performs OK on your computer. Using NumPy arrays would > speed up the number crunching. > > > import pyaudio > from math import sin, pi > from struct import pack > from random import sample, randrange > > def polywave(freqs, amps, f0, fs): > """create a polyphonic waveform > > freqs: sequence of frequencies (Hz) > amps: sequence of amplitudes > f0: fundamental frequency (Hz) > fs: samples/second > > output is normalized to the range [-1,1]. > """ > N = int(fs / f0) > rad_step = 2 * pi / fs # radians / (Hz * sample) > wave = [0.0] * N > for f, a in zip(freqs, amps): > for n in xrange(N): > wave[n] += a * sin(rad_step * f * n) > maxamp = abs(max(wave, key=lambda x: abs(x))) > return [samp / maxamp for samp in wave] > > def packwave(wave, vol=1, duration=None, fs=None): > """pack a waveform as bytes (int16) > > wave: sample sequence, |mag| <= 1 > vol: optional volume scale, |mag| <= 1 > duration: optional loop time (seconds) > fs: samples/second > > fs is required to set duration. > """ > scale = min(vol * 32767, 32767) > ncycles = 1 > if not (duration is None or fs is None): > ncycles = int(round(1.0 * duration * fs / len(wave))) > data = b''.join(pack('<h', scale * samp) for samp in wave) > return data * ncycles > > def make_square(num, f0, fs): > """generate square wave components > > num: number of harmonics > f0: funamental frequency (Hz) > fs: samples/second > > fs/2 is the upper bound. > """ > stop = min(2*num, int(fs / (2 * f0))) > freqs = [n * f0 for n in xrange(1, stop, 2)] > amps = [1.0 / n for n in xrange(1, stop, 2)] > return freqs, amps > > def make_saw(num, f0, fs): > """generate sawtooth wave components > > num: number of harmonics > f0: funamental frequency (Hz) > fs: samples/second > > fs/2 is the upper bound. > """ > stop = min(num + 1, int(fs / (2 * f0))) > freqs = [n * f0 for n in xrange(1, stop)] > amps = [(-1.0) ** (n + 1) / n for n in xrange(1, stop)] > return freqs, amps > > def make_rand(num, f0, fs): > """generate wave with random harmonics/amplitudes""" > ftop = min(fs // 2, 12000) > nmax = int(ftop / f0) > num = min(num, nmax) > freqs = [n * f0 for n in sample(xrange(1, nmax+1), num)] > amps = [randrange(32768)/32767.0 for n in xrange(num)] > return freqs, amps > > def play(data, stream): > chunks = (data[i:i+1024] for i in xrange(0, len(data), 1024)) > for chunk in chunks: > stream.write(chunk) > > if __name__ == "__main__": > from time import sleep > > fs = 48000 > > p = pyaudio.PyAudio() > stream = p.open( > format=pyaudio.paInt16, > channels=1, > rate=fs, > frames_per_buffer=fs//4, > output=True) > > # http://en.wikipedia.org/wiki/ > # Equal_temperament#Calculating_absolute_frequencies > > note = lambda n: 440 * (2**(1/12.)) ** (-21 + n) > > scale = [note(n) for n in range(12)] > rscale = [note(13-n) for n in range(12)] > vols = [0.2 + 0.05*n for n in range(len(scale))] > rvols = list(reversed(vols)) > > def play_scale(scale, vols, wave_func, master_vol=1): > duration = 0.5 > nharmonics = 30 > for f0, vol in zip(scale, vols): > freqs, amps = wave_func(nharmonics, f0, fs) > wave = polywave(freqs, amps, f0, fs) > data = packwave(wave, master_vol * vol, duration, fs) > play(data, stream) > sleep(0.5) > > play_scale(scale, vols, make_square, 0.5) > play_scale(rscale, rvols, make_saw, 0.5) > play_scale(scale, vols, make_rand, 0.75) > play_scale(rscale, rvols, make_rand, 0.75) > > stream.close() > p.terminate() >
_______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor