Python library for playing fixed-frequency sound Python library for playing fixed-frequency sound python python

Python library for playing fixed-frequency sound


PyAudiere is a simple cross-platform solution for the problem:

>>> import audiere>>> d = audiere.open_device()>>> t = d.create_tone(17000) # 17 KHz>>> t.play() # non-blocking call>>> import time>>> time.sleep(5)>>> t.stop()

pyaudiere.org is gone. The site and binary installers for Python 2 (debian, windows) are available via the wayback machine e.g., here's source code pyaudiere-0.2.tar.gz.

To support both Python 2 and 3 on Linux, Windows, OSX, pyaudio module could be used instead:

#!/usr/bin/env python"""Play a fixed frequency sound."""from __future__ import divisionimport mathfrom pyaudio import PyAudio # sudo apt-get install python{,3}-pyaudiotry:    from itertools import izipexcept ImportError: # Python 3    izip = zip    xrange = rangedef sine_tone(frequency, duration, volume=1, sample_rate=22050):    n_samples = int(sample_rate * duration)    restframes = n_samples % sample_rate    p = PyAudio()    stream = p.open(format=p.get_format_from_width(1), # 8bit                    channels=1, # mono                    rate=sample_rate,                    output=True)    s = lambda t: volume * math.sin(2 * math.pi * frequency * t / sample_rate)    samples = (int(s(t) * 0x7f + 0x80) for t in xrange(n_samples))    for buf in izip(*[samples]*sample_rate): # write several samples at a time        stream.write(bytes(bytearray(buf)))    # fill remainder of frameset with silence    stream.write(b'\x80' * restframes)    stream.stop_stream()    stream.close()    p.terminate()

Example:

sine_tone(    # see http://www.phy.mtu.edu/~suits/notefreqs.html    frequency=440.00, # Hz, waves per second A4    duration=3.21, # seconds to play sound    volume=.01, # 0..1 how loud it is    # see http://en.wikipedia.org/wiki/Bit_rate#Audio    sample_rate=22050 # number of samples per second)

It is a modified (to support Python 3) version of this AskUbuntu answer.


The module winsound is included with Python, so there are no external libraries to install, and it should do what you want (and not much else).

 import winsound winsound.Beep(17000, 100)

It's very simple and easy, though is only available for Windows.

But:
A complete answer to this question should note that although this method will produce a sound, it will not deter mosquitoes. It's already been tested: see here and here


I'm putting my code in here as it helps a programmer gain clarity over how the code works. Explanation is in the code itself:

#!/usr/bin/env python3import pyaudioimport structimport mathFORMAT = pyaudio.paInt16CHANNELS = 2RATE = 44100p = pyaudio.PyAudio()def data_for_freq(frequency: float, time: float = None):    """get frames for a fixed frequency for a specified time or    number of frames, if frame_count is specified, the specified    time is ignored"""    frame_count = int(RATE * time)    remainder_frames = frame_count % RATE    wavedata = []    for i in range(frame_count):        a = RATE / frequency  # number of frames per wave        b = i / a        # explanation for b        # considering one wave, what part of the wave should this be        # if we graph the sine wave in a        # displacement vs i graph for the particle        # where 0 is the beginning of the sine wave and        # 1 the end of the sine wave        # which part is "i" is denoted by b        # for clarity you might use        # though this is redundant since math.sin is a looping function        # b = b - int(b)        c = b * (2 * math.pi)        # explanation for c        # now we map b to between 0 and 2*math.PI        # since 0 - 2*PI, 2*PI - 4*PI, ...        # are the repeating domains of the sin wave (so the decimal values will        # also be mapped accordingly,        # and the integral values will be multiplied        # by 2*PI and since sin(n*2*PI) is zero where n is an integer)        d = math.sin(c) * 32767        e = int(d)        wavedata.append(e)    for i in range(remainder_frames):        wavedata.append(0)    number_of_bytes = str(len(wavedata))      wavedata = struct.pack(number_of_bytes + 'h', *wavedata)    return wavedatadef play(frequency: float, time: float):    """    play a frequency for a fixed time!    """    frames = data_for_freq(frequency, time)    stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, output=True)    stream.write(frames)    stream.stop_stream()    stream.close()if __name__ == "__main__":    play(400, 1)