226 lines
6.6 KiB
Python
Executable file
226 lines
6.6 KiB
Python
Executable file
# SPDX-FileCopyrightText: 2020 Erin St Blaine for Adafruit Industries
|
|
# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""
|
|
Bottle Piano with Capacitive Touch
|
|
Adafruit invests time and resources providing this open source code.
|
|
Please support Adafruit and open source hardware by purchasing
|
|
products from Adafruit!
|
|
Written by Melissa LeBlanc, Erin St Blaine & Limor Fried for Adafruit Industries
|
|
Copyright (c) 2019-2020 Adafruit Industries
|
|
Licensed under the MIT license.
|
|
All text above must be included in any redistribution.
|
|
"""
|
|
|
|
import time
|
|
import digitalio
|
|
import board
|
|
import neopixel
|
|
import busio
|
|
import adafruit_mpr121
|
|
from audiocore import WaveFile
|
|
from audiopwmio import PWMAudioOut as AudioOut
|
|
from adafruit_led_animation.animation.rainbow import Rainbow
|
|
from adafruit_led_animation.animation.rainbowchase import RainbowChase
|
|
from adafruit_led_animation.animation.chase import Chase
|
|
from adafruit_led_animation.animation.rainbowcomet import RainbowComet
|
|
from adafruit_led_animation.sequence import AnimationSequence
|
|
from adafruit_led_animation.color import (
|
|
BLACK,
|
|
RED,
|
|
ORANGE,
|
|
YELLOW,
|
|
GREEN,
|
|
BLUE,
|
|
MAGENTA,
|
|
PURPLE,
|
|
AMBER,
|
|
TEAL,
|
|
)
|
|
from adafruit_debouncer import Debouncer
|
|
|
|
# pylint: disable=global-statement
|
|
|
|
# NeoPixel strip setup -- set your total number of pixels here -----------------
|
|
PIXEL_NUM = 200
|
|
pixel_pin = board.A1
|
|
pixels = neopixel.NeoPixel(pixel_pin, PIXEL_NUM, brightness=1, auto_write=False)
|
|
LAST_BUTTON = None
|
|
|
|
'''
|
|
Customize your light strip for individual notes. Each line represents a bottle.
|
|
Change the numbers to reflect the first and last pixel in each ring. You can also
|
|
change the colors assigned to each bottle here.
|
|
'''
|
|
|
|
bottle_lights = (
|
|
(0, 10, RED),
|
|
(15, 30, ORANGE),
|
|
(31, 52, AMBER),
|
|
(53, 72, YELLOW),
|
|
(77, 96, GREEN),
|
|
(98, 119, TEAL),
|
|
(120, 145, BLUE),
|
|
(150, 173, PURPLE),
|
|
(180, 200, MAGENTA),
|
|
)
|
|
|
|
# Cap touch board setup ------------------------------------------------------
|
|
i2c = busio.I2C(board.SCL, board.SDA)
|
|
mpr121 = adafruit_mpr121.MPR121(i2c)
|
|
|
|
# Demo MODE LED Animations ------------------------------------------------------
|
|
rainbow = Rainbow(pixels, speed=0, period=10, name="rainbow", step=1)
|
|
rainbow_chase = RainbowChase(pixels, speed=0, size=5, spacing=10)
|
|
chase = Chase(pixels, speed=0.1, color=RED, size=1, spacing=6)
|
|
rainbow_comet = RainbowComet(pixels, speed=0.01, tail_length=60, bounce=True)
|
|
|
|
# Animation Sequence Playlist -- rearrange to change the order of animations
|
|
|
|
animations = AnimationSequence(
|
|
rainbow_chase,
|
|
chase,
|
|
rainbow_comet,
|
|
auto_clear=True,
|
|
auto_reset=True,
|
|
)
|
|
|
|
def go_dark():
|
|
'''set all pixels to black'''
|
|
pixels.fill(BLACK)
|
|
pixels.show()
|
|
|
|
|
|
# Debouncer ------------------------------------------------------
|
|
|
|
buttons = [Debouncer(mpr121[i]) for i in range(12)]
|
|
|
|
|
|
# Audio Setup ------------------------------------------------------
|
|
|
|
spkr_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
|
|
spkr_enable.direction = digitalio.Direction.OUTPUT
|
|
spkr_enable.value = True
|
|
|
|
audio = AudioOut(board.SPEAKER)
|
|
|
|
tracks = (
|
|
WaveFile(open("sounds/F2.wav", "rb")), # 0
|
|
WaveFile(open("sounds/G2.wav", "rb")), # 1
|
|
WaveFile(open("sounds/A2.wav", "rb")), # 2
|
|
WaveFile(open("sounds/Bb2.wav", "rb")), # 3
|
|
WaveFile(open("sounds/C2.wav", "rb")), # 4
|
|
WaveFile(open("sounds/D3.wav", "rb")), # 5
|
|
WaveFile(open("sounds/E3.wav", "rb")), # 6
|
|
WaveFile(open("sounds/F3.wav", "rb")), # 7
|
|
WaveFile(open("sounds/F1.wav", "rb")), # 7
|
|
WaveFile(open("sounds/G1.wav", "rb")), # 8
|
|
WaveFile(open("sounds/A1.wav", "rb")), # 9
|
|
WaveFile(open("sounds/Bb1.wav", "rb")), # 10
|
|
WaveFile(open("sounds/C1.wav", "rb")), # 11
|
|
WaveFile(open("sounds/D2.wav", "rb")), # 12
|
|
WaveFile(open("sounds/E2.wav", "rb")), # 13
|
|
WaveFile(open("sounds/F2.wav", "rb")), # 13
|
|
)
|
|
|
|
# Add or change song track names here. They will play in the order listed.
|
|
demo_tracks = (
|
|
WaveFile(open("sounds/undersea.wav", "rb")),
|
|
WaveFile(open("sounds/tequila.wav", "rb")),
|
|
WaveFile(open("sounds/lion.wav", "rb")),
|
|
)
|
|
|
|
MODE = 0 # Initial mode = OFF
|
|
SONG = 0
|
|
|
|
|
|
|
|
|
|
def light_up(bottle):
|
|
'''light up the bottles'''
|
|
lights = bottle_lights[bottle]
|
|
for pixel_id in range(lights[0], lights[1]):
|
|
pixels[pixel_id] = lights[2]
|
|
|
|
|
|
def play_bottle(bottle_id, is_octave):
|
|
''' play audio tracks and light up bottles'''
|
|
global MODE
|
|
go_dark()
|
|
light_up(bottle_id)
|
|
if is_octave:
|
|
audio.play(tracks[bottle_id + 7]) # Start playing sound
|
|
light_up(8)
|
|
else:
|
|
audio.play(tracks[bottle_id]) # Start playing sound
|
|
pixels.show()
|
|
MODE = 2
|
|
|
|
|
|
def check_buttons(touched):
|
|
''' check to see if buttons have been pressed'''
|
|
global MODE, LAST_BUTTON
|
|
octave = touched[11]
|
|
off = touched[9]
|
|
if octave:
|
|
light_up(8)
|
|
for pad in range(1, 9):
|
|
if LAST_BUTTON is not None and not touched[LAST_BUTTON]:
|
|
LAST_BUTTON = None
|
|
if pad != LAST_BUTTON and touched[pad]:
|
|
LAST_BUTTON = pad
|
|
play_bottle(pad - 1, octave)
|
|
if off:
|
|
MODE = 9
|
|
go_dark()
|
|
if touched[10]:
|
|
go_dark()
|
|
audio.play(demo_tracks[SONG])
|
|
while audio.playing:
|
|
animations.animate()
|
|
|
|
MODE = 3
|
|
|
|
|
|
while True:
|
|
# Idle mode: Play a Rainbow animation when nothing's being touched
|
|
if MODE == 0:
|
|
pixels.brightness = 0.3 #rainbow mode is much brighter than the other modes, so adjust here
|
|
rainbow.animate()
|
|
for button in buttons:
|
|
button.update()
|
|
check_buttons(mpr121.touched_pins)
|
|
time.sleep(0.1)
|
|
for i in range(12):
|
|
if buttons[i].fell:
|
|
MODE = 1
|
|
# If not idle mode
|
|
if MODE >= 1:
|
|
pixels.brightness = 1
|
|
check_buttons(mpr121.touched_pins)
|
|
time.sleep(0.1)
|
|
if MODE == 2: # mode 2 is individual notes
|
|
if audio.playing:
|
|
pixels.show()
|
|
while audio.playing:
|
|
check_buttons(mpr121.touched_pins)
|
|
time.sleep(0.07)
|
|
else:
|
|
MODE = 0 # Return to idle mode
|
|
if MODE == 3:
|
|
SONG = SONG + 1
|
|
animations.next()
|
|
if SONG == 3:
|
|
MODE = 0
|
|
SONG = 0
|
|
|
|
else:
|
|
MODE = 0 # Return to idle mode
|
|
if MODE == 9: # MODE 9 is "off" mode, listening for a new button press to wake up.
|
|
# for button in buttons:
|
|
# button.update()
|
|
for i in range(12):
|
|
if buttons[i].fell:
|
|
MODE = 1
|