[Tutor] Musical note on python
D.V.N.Sarma డి.వి.ఎన్.శర్మ
dvnsarma at gmail.com
Fri Sep 14 02:49:41 CEST 2012
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 <eryksun at 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()
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20120914/8a90b63f/attachment-0001.html>
More information about the Tutor
mailing list