[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