Search code examples
pythonaudiomp3frequency

Python library for playing fixed-frequency sound


I have a mosquito problem in my house. This wouldn't usually concern a programmers' community; However, I've seen some devices that claim to deter these nasty creatures by playing a 17Khz tone. I would like to do this using my laptop.

One method would be creating an MP3 with a a single, fixed-frequency tone (This can easily done by audacity), opening it with a python library and playing it repeatedly.

The second would be playing a sound using the computer built-in speaker. I'm looking for something similar to QBasic Sound:

SOUND 17000, 100

Is there a python library for that?


Solution

  • 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 division
    import math
    
    from pyaudio import PyAudio # sudo apt-get install python{,3}-pyaudio
    
    try:
        from itertools import izip
    except ImportError: # Python 3
        izip = zip
        xrange = range
    
    def 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.