Source code for rainbowhat.buzzer

from threading import Timer

try:
    import RPi.GPIO as GPIO
except ImportError:
    raise ImportError("This library requires the RPi.GPIO module\nInstall with: sudo pip install RPi.GPIO")


BUZZER = 13

_timeout = None

_is_setup = False

pwm = None

def setup():
    global _is_setup, pwm

    if _is_setup:
        return

    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    GPIO.setup(BUZZER, GPIO.OUT)

    # Set up the PWM and then set the pin to input
    # to prevent the signal from being output.
    # Since starting/stopping PWM causes a segfault,
    # this is the only way to manage the buzzer.

    pwm = GPIO.PWM(BUZZER, 1)
    GPIO.setup(BUZZER, GPIO.IN)
    pwm.start(50)

    _is_setup = True

def note(frequency, duration=1.0):
    """Play a single note.

    :param frequency: Musical frequency in hertz
    :param duration: Optional duration in seconds, use None to sustain note

    """

    global _timeout

    setup()

    if frequency <= 0:
        raise ValueError("Frequency must be > 0")

    if duration is not None and duration <= 0:
        raise ValueError("Duration must be > 0")

    clear_timeout()

    pwm.ChangeFrequency(frequency)
    GPIO.setup(BUZZER, GPIO.OUT)    

    if duration is not None and duration > 0:
        _timeout = Timer(duration, stop)
        _timeout.start()

def midi_note(note_number, duration=1.0):
    """Play a single note by MIDI note number.

    Converts a MIDI note number into a frequency and plays it. A5 is 69.

    :param note_number: MIDI note number of note
    :param duration: Optional duration in seconds, use None to sustain note

    """

    freq = (2**((note_number-69.0)/12)) * 440

    note(freq, duration)

def clear_timeout():
    """Clear any note timeout set.

    Will cause any pending playing note to be sustained.

    """

    global _timeout

    if _timeout is not None:
        _timeout.cancel()
        _timeout = None

def stop():
    """Stop buzzer.

    Immediately silences the buzzer.

    """

    clear_timeout()

    GPIO.setup(BUZZER, GPIO.IN)