code.py
  1  # SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries
  2  #
  3  # SPDX-License-Identifier: MIT
  4  
  5  # Lucio 2020
  6  # Feather M4 + Propmaker + amps + lots of neopixels
  7  import board
  8  import busio
  9  from digitalio import DigitalInOut, Direction, Pull
 10  import audioio
 11  import audiomixer
 12  import audiomp3
 13  import adafruit_lis3dh
 14  import neopixel
 15  from adafruit_led_animation.animation.solid import Solid
 16  from adafruit_led_animation.animation.comet import Comet
 17  from adafruit_led_animation.animation.pulse import Pulse
 18  from adafruit_led_animation.helper import PixelSubset
 19  from adafruit_led_animation.group import AnimationGroup
 20  from adafruit_led_animation.color import RED, ORANGE, WHITE
 21  
 22  ORANGE_DIM = 0x801400  # half value version
 23  RED_DIM = 0x800000
 24  
 25  #  ---Set Volume Max Here---
 26  VOLUME_MULT = 0.65  # 1 = full volume, 0.1 is very quiet, 0 is muted
 27  
 28  #  ---SWITCH/BUTTON SETUP---
 29  mode_switch = DigitalInOut(board.D9)
 30  mode_switch.switch_to_input(pull=Pull.UP)
 31  mode_state = mode_switch.value
 32  trig_button = DigitalInOut(board.A4)
 33  trig_button.switch_to_input(pull=Pull.UP)
 34  alt_button = DigitalInOut(board.A5)
 35  alt_button.switch_to_input(pull=Pull.UP)
 36  
 37  #  ---ACCELEROMETER SETUP---
 38  # Set up accelerometer on I2C bus, 4G range:
 39  i2c = busio.I2C(board.SCL, board.SDA)
 40  int1 = DigitalInOut(board.D6)
 41  accel = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=int1)
 42  
 43  #  ---SPEAKER SETUP---
 44  enable = DigitalInOut(board.D10)
 45  enable.direction = Direction.OUTPUT
 46  enable.value = True
 47  # Set up speakers and mixer. Stereo files, where music has empty right channel, FX empty left
 48  speaker = audioio.AudioOut(board.A0, right_channel=board.A1)
 49  mixer = audiomixer.Mixer(channel_count=2, buffer_size=2304, sample_rate=22050)
 50  
 51  #  ---NEOPIXEL SETUP---
 52  pixel_pin = board.D5
 53  pixel_num = 154
 54  pixels = neopixel.NeoPixel(
 55      pixel_pin, pixel_num, brightness=0.6, auto_write=False, pixel_order=neopixel.GRBW
 56  )
 57  # ^ change pixel_order depending on RGB vs. RGBW pixels
 58  
 59  
 60  #  ---Pixel Map---
 61  #  this is the physical order in which the strips are plugged
 62  pixel_stripA = PixelSubset(pixels, 0, 18)  # 18 pixel strip
 63  pixel_stripB = PixelSubset(pixels, 18, 36)  # 18 pixel strip
 64  pixel_jewel = PixelSubset(pixels, 36, 43)  # 7 pixel jewel
 65  pixel_ringsAll = PixelSubset(pixels, 43, 151)  # all of the rings
 66  #  or use rings individually:
 67  # pixel_ringA = PixelSubset(pixels, 43, 59)  # 16 pixel ring
 68  # pixel_ringB = PixelSubset(pixels, 59, 75)  # 16 pixel ring
 69  # pixel_ringC = PixelSubset(pixels, 75, 91)  # 16 pixel ring
 70  # pixel_ringD = PixelSubset(pixels, 91, 151)  # 60 pixel ring
 71  
 72  #  ---BPM---
 73  BPM = 128
 74  BEAT = 60 / BPM  # quarter note beat
 75  b16TH = BEAT / 4  # 16TH note
 76  b64TH = BEAT / 16  # sixty-fourth
 77  
 78  #  ---Anim Setup---
 79  # heal color mode
 80  # Pulse 'speed' = smoothness
 81  pulse_rings_m0 = Pulse(pixel_ringsAll, speed=0.01, color=ORANGE, period=BEAT)
 82  pulse_jewel_m0 = Pulse(pixel_jewel, speed=0.01, color=ORANGE, period=BEAT)
 83  comet_stripA_m0 = Comet(
 84      pixel_stripA, speed=b64TH, color=ORANGE, tail_length=9, bounce=False
 85  )
 86  comet_stripB_m0 = Comet(
 87      pixel_stripB, speed=b64TH, color=ORANGE, tail_length=9, bounce=False
 88  )
 89  
 90  # speed color mode
 91  pulse_rings_m1 = Pulse(pixel_ringsAll, speed=0.02, color=RED, period=BEAT / 2)
 92  pulse_jewel_m1 = Pulse(pixel_jewel, speed=0.02, color=RED, period=BEAT / 2)
 93  comet_stripA_m1 = Comet(
 94      pixel_stripA, speed=b64TH, color=RED, tail_length=9, bounce=False
 95  )
 96  comet_stripB_m1 = Comet(
 97      pixel_stripB, speed=b64TH, color=RED, tail_length=9, bounce=False
 98  )
 99  
100  solid_white = Solid(pixel_ringsAll, color=WHITE)
101  
102  # ---Anim Modes---
103  vu_strip_animations_mode0 = AnimationGroup(comet_stripA_m0, comet_stripB_m0, sync=True)
104  vu_strip_animations_mode1 = AnimationGroup(comet_stripA_m1, comet_stripB_m1, sync=True)
105  
106  #  ---Audio Setup---
107  if mode_state:
108      BGM = "/lucio/bgmheal.mp3"
109  else:
110      BGM = "/lucio/bgmspeed.mp3"
111  sample0 = audiomp3.MP3Decoder(open(BGM, "rb"))
112  FX = "/lucio/shoot.mp3"
113  sample1 = audiomp3.MP3Decoder(open(FX, "rb"))
114  speaker.play(mixer)
115  mixer.voice[0].play(sample0, loop=True)
116  mixer.voice[0].level = 0.3 * VOLUME_MULT
117  mixer.voice[1].level = 0.7 * VOLUME_MULT
118  
119  
120  while True:
121      if mode_state:  # heal mode on startup
122          vu_strip_animations_mode0.animate()
123          pulse_rings_m0.animate()
124          pulse_jewel_m0.animate()
125      else:  # speed mode on startup
126          vu_strip_animations_mode1.animate()
127          pulse_rings_m1.animate()
128          pulse_jewel_m1.animate()
129  
130      # Change modes
131      if mode_switch.value:
132          if mode_state == 0:  # state has changed, toggle it
133              BGM = "/lucio/bgmheal.mp3"
134              sample0.file = open(BGM, "rb")
135              mixer.voice[0].play(sample0, loop=True)
136              vu_strip_animations_mode0.animate()
137              pulse_rings_m0.animate()
138              pulse_jewel_m0.animate()
139              mode_state = 1
140      else:
141          if mode_state == 1:
142              BGM = "/lucio/bgmspeed.mp3"
143              sample0.file = open(BGM, "rb")
144              mixer.voice[0].play(sample0, loop=True)
145              vu_strip_animations_mode1.animate()
146              pulse_rings_m1.animate()
147              pulse_jewel_m1.animate()
148              mode_state = 0
149  
150      x, _, _ = accel.acceleration  # get accelerometer values
151  
152      if not mixer.voice[1].playing:
153          if not trig_button.value:  # trigger squeezed
154              FX_sample = "/lucio/shoot.mp3"
155              sample1.file = open(FX_sample, "rb")
156              mixer.voice[1].play(sample1)
157              if mode_state:
158                  solid_white.animate()
159              else:
160                  solid_white.animate()
161  
162          if not alt_button.value:  # alt trigger squeezed
163              FX_sample = "/lucio/alt_shoot.mp3"
164              sample1.file = open(FX_sample, "rb")
165              mixer.voice[1].play(sample1)
166              if mode_state:
167                  solid_white.animate()
168              else:
169                  solid_white.animate()
170  
171          if accel.acceleration.x > 8:  # reload
172              FX_sample = "/lucio/reload.mp3"
173              sample1.file = open(FX_sample, "rb")
174              mixer.voice[1].play(sample1)
175              if mode_state:
176                  solid_white.animate()
177              else:
178                  solid_white.animate()
179  
180          if accel.acceleration.x < -8:  # Ultimate
181              FX_sample = "/lucio/ultimate.mp3"
182              sample1.file = open(FX_sample, "rb")
183              mixer.voice[1].play(sample1)
184              if mode_state:
185                  solid_white.animate()
186              else:
187                  solid_white.animate()