code.py
  1  # SPDX-FileCopyrightText: 2020 Erin St Blaine for Adafruit Industries
  2  # SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
  3  #
  4  # SPDX-License-Identifier: MIT
  5  
  6  """
  7  Bottle Piano with Capacitive Touch
  8  Adafruit invests time and resources providing this open source code.
  9  Please support Adafruit and open source hardware by purchasing
 10  products from Adafruit!
 11  Written by Melissa LeBlanc, Erin St Blaine & Limor Fried for Adafruit Industries
 12  Copyright (c) 2019-2020 Adafruit Industries
 13  Licensed under the MIT license.
 14  All text above must be included in any redistribution.
 15  """
 16  
 17  import time
 18  import digitalio
 19  import board
 20  import neopixel
 21  import busio
 22  import adafruit_mpr121
 23  from audiocore import WaveFile
 24  from audiopwmio import PWMAudioOut as AudioOut
 25  from adafruit_led_animation.animation.rainbow import Rainbow
 26  from adafruit_led_animation.animation.rainbowchase import RainbowChase
 27  from adafruit_led_animation.animation.chase import Chase
 28  from adafruit_led_animation.animation.rainbowcomet import RainbowComet
 29  from adafruit_led_animation.sequence import AnimationSequence
 30  from adafruit_led_animation.color import (
 31      BLACK,
 32      RED,
 33      ORANGE,
 34      YELLOW,
 35      GREEN,
 36      BLUE,
 37      MAGENTA,
 38      PURPLE,
 39      AMBER,
 40      TEAL,
 41  )
 42  from adafruit_debouncer import Debouncer
 43  
 44  # pylint: disable=global-statement
 45  
 46  # NeoPixel strip setup -- set your total number of pixels here  -----------------
 47  PIXEL_NUM = 200
 48  pixel_pin = board.A1
 49  pixels = neopixel.NeoPixel(pixel_pin, PIXEL_NUM, brightness=1, auto_write=False)
 50  LAST_BUTTON = None
 51  
 52  '''
 53  Customize your light strip for individual notes. Each line represents a bottle.
 54  Change the numbers to reflect the first and last pixel in each ring. You can also
 55  change the colors assigned to each bottle here.
 56  '''
 57  
 58  bottle_lights = (
 59      (0, 10, RED),
 60      (15, 30, ORANGE),
 61      (31, 52, AMBER),
 62      (53, 72, YELLOW),
 63      (77, 96, GREEN),
 64      (98, 119, TEAL),
 65      (120, 145, BLUE),
 66      (150, 173, PURPLE),
 67      (180, 200, MAGENTA),
 68  )
 69  
 70  # Cap touch board setup   ------------------------------------------------------
 71  i2c = busio.I2C(board.SCL, board.SDA)
 72  mpr121 = adafruit_mpr121.MPR121(i2c)
 73  
 74  # Demo MODE LED Animations  ------------------------------------------------------
 75  rainbow = Rainbow(pixels, speed=0, period=10, name="rainbow", step=1)
 76  rainbow_chase = RainbowChase(pixels, speed=0, size=5, spacing=10)
 77  chase = Chase(pixels, speed=0.1, color=RED, size=1, spacing=6)
 78  rainbow_comet = RainbowComet(pixels, speed=0.01, tail_length=60, bounce=True)
 79  
 80  # Animation Sequence Playlist -- rearrange to change the order of animations
 81  
 82  animations = AnimationSequence(
 83      rainbow_chase,
 84      chase,
 85      rainbow_comet,
 86      auto_clear=True,
 87      auto_reset=True,
 88  )
 89  
 90  def go_dark():
 91      '''set all pixels to black'''
 92      pixels.fill(BLACK)
 93      pixels.show()
 94  
 95  
 96  # Debouncer ------------------------------------------------------
 97  
 98  buttons = [Debouncer(mpr121[i]) for i in range(12)]
 99  
100  
101  # Audio Setup ------------------------------------------------------
102  
103  spkr_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
104  spkr_enable.direction = digitalio.Direction.OUTPUT
105  spkr_enable.value = True
106  
107  audio = AudioOut(board.SPEAKER)
108  
109  tracks = (
110      WaveFile(open("sounds/F2.wav", "rb")),  # 0
111      WaveFile(open("sounds/G2.wav", "rb")),  # 1
112      WaveFile(open("sounds/A2.wav", "rb")),  # 2
113      WaveFile(open("sounds/Bb2.wav", "rb")),  # 3
114      WaveFile(open("sounds/C2.wav", "rb")),  # 4
115      WaveFile(open("sounds/D3.wav", "rb")),  # 5
116      WaveFile(open("sounds/E3.wav", "rb")),  # 6
117      WaveFile(open("sounds/F3.wav", "rb")),  # 7
118      WaveFile(open("sounds/F1.wav", "rb")),  # 7
119      WaveFile(open("sounds/G1.wav", "rb")),  # 8
120      WaveFile(open("sounds/A1.wav", "rb")),  # 9
121      WaveFile(open("sounds/Bb1.wav", "rb")),  # 10
122      WaveFile(open("sounds/C1.wav", "rb")),  # 11
123      WaveFile(open("sounds/D2.wav", "rb")),  # 12
124      WaveFile(open("sounds/E2.wav", "rb")),  # 13
125      WaveFile(open("sounds/F2.wav", "rb")),  # 13
126  )
127  
128  # Add or change song track names here. They will play in the order listed.
129  demo_tracks = (
130      WaveFile(open("sounds/undersea.wav", "rb")),
131      WaveFile(open("sounds/tequila.wav", "rb")),
132      WaveFile(open("sounds/lion.wav", "rb")),
133  )
134  
135  MODE = 0  # Initial mode = OFF
136  SONG = 0
137  
138  
139  
140  
141  def light_up(bottle):
142      '''light up the bottles'''
143      lights = bottle_lights[bottle]
144      for pixel_id in range(lights[0], lights[1]):
145          pixels[pixel_id] = lights[2]
146  
147  
148  def play_bottle(bottle_id, is_octave):
149      ''' play audio tracks and light up bottles'''
150      global MODE
151      go_dark()
152      light_up(bottle_id)
153      if is_octave:
154          audio.play(tracks[bottle_id + 7])  # Start playing sound
155          light_up(8)
156      else:
157          audio.play(tracks[bottle_id])  # Start playing sound
158      pixels.show()
159      MODE = 2
160  
161  
162  def check_buttons(touched):
163      ''' check to see if buttons have been pressed'''
164      global MODE, LAST_BUTTON
165      octave = touched[11]
166      off = touched[9]
167      if octave:
168          light_up(8)
169      for pad in range(1, 9):
170          if LAST_BUTTON is not None and not touched[LAST_BUTTON]:
171              LAST_BUTTON = None
172          if pad != LAST_BUTTON and touched[pad]:
173              LAST_BUTTON = pad
174              play_bottle(pad - 1, octave)
175      if off:
176          MODE = 9
177          go_dark()
178      if touched[10]:
179          go_dark()
180          audio.play(demo_tracks[SONG])
181          while audio.playing:
182              animations.animate()
183  
184          MODE = 3
185  
186  
187  while True:
188      # Idle mode: Play a Rainbow animation when nothing's being touched
189      if MODE == 0:
190          pixels.brightness = 0.3  #rainbow mode is much brighter than the other modes, so adjust here
191          rainbow.animate()
192          for button in buttons:
193              button.update()
194          check_buttons(mpr121.touched_pins)
195          time.sleep(0.1)
196          for i in range(12):
197              if buttons[i].fell:
198                  MODE = 1
199      # If not idle mode
200      if MODE >= 1:
201          pixels.brightness = 1
202          check_buttons(mpr121.touched_pins)
203          time.sleep(0.1)
204          if MODE == 2:  # mode 2 is individual notes
205              if audio.playing:
206                  pixels.show()
207                  while audio.playing:
208                      check_buttons(mpr121.touched_pins)
209                      time.sleep(0.07)
210              else:
211                  MODE = 0  # Return to idle mode
212          if MODE == 3:
213              SONG = SONG + 1
214              animations.next()
215              if SONG == 3:
216                  MODE = 0
217                  SONG = 0
218  
219              else:
220                  MODE = 0  # Return to idle mode
221          if MODE == 9:  # MODE 9 is "off" mode, listening for a new button press to wake up.
222  #             for button in buttons:
223  #                 button.update()
224              for i in range(12):
225                  if buttons[i].fell:
226                      MODE = 1