|
| 1 | +# NeoTrellis Soundbox Remix - CircuitPython |
| 2 | +# Noe and Pedro Ruiz, code by Mike Barela |
| 3 | +# for Adafruit Industries, MIT License |
| 4 | + |
| 5 | +import time |
| 6 | +import os |
| 7 | +import random |
| 8 | +import board |
| 9 | +from board import SCL, SDA |
| 10 | +import digitalio |
| 11 | +import busio |
| 12 | +import audioio |
| 13 | +import adafruit_rgbled |
| 14 | +from adafruit_neotrellis.neotrellis import NeoTrellis |
| 15 | +import adafruit_lis3dh |
| 16 | + |
| 17 | +# Color definitions |
| 18 | +OFF = (0, 0, 0) |
| 19 | +RED = (25, 0, 0) |
| 20 | +YELLOW = (25, 15, 0) |
| 21 | +GREEN = (0, 25, 0) |
| 22 | +CYAN = (0, 25, 25) |
| 23 | +BLUE = (0, 0, 25) |
| 24 | +PURPLE = (18, 0, 25) |
| 25 | +WHITE = (127, 127, 127) |
| 26 | + |
| 27 | +# Create the i2c object for the trellis |
| 28 | +# If you get an error, your PropMaker Shield needs to be snappped on |
| 29 | +i2c_bus = busio.I2C(SCL, SDA) |
| 30 | + |
| 31 | +# Create the trellis |
| 32 | +trellis = NeoTrellis(i2c_bus) |
| 33 | + |
| 34 | +print("NeoTrellis created") |
| 35 | + |
| 36 | +# Enable PWR Pin to enable NeoPixels, audio amplifier and RGB LED |
| 37 | +# See https://learn.adafruit.com/adafruit-prop-maker-featherwing/pinouts |
| 38 | +enable = digitalio.DigitalInOut(board.D10) |
| 39 | +enable.direction = digitalio.Direction.OUTPUT |
| 40 | +enable.value = True |
| 41 | + |
| 42 | +# Set up RGB for switch RGB LED |
| 43 | +RED_LED = board.D11 |
| 44 | +GREEN_LED = board.D12 |
| 45 | +BLUE_LED = board.D13 |
| 46 | +led = adafruit_rgbled.RGBLED(RED_LED, GREEN_LED, BLUE_LED) |
| 47 | +led.color = GREEN |
| 48 | + |
| 49 | +# Enable button use on PropMaker Wing Switch input |
| 50 | +push_switch = digitalio.DigitalInOut(board.D9) |
| 51 | +push_switch.switch_to_input(pull=digitalio.Pull.UP) |
| 52 | + |
| 53 | +# Set up Accelerometer on I2C bus |
| 54 | +int1 = digitalio.DigitalInOut(board.D5) |
| 55 | +accel = adafruit_lis3dh.LIS3DH_I2C(i2c_bus, int1=int1) |
| 56 | +# See https://circuitpython.readthedocs.io/projects/lis3dh/en/ |
| 57 | +# latest/api.html for adjusting settings for the accelerometer |
| 58 | +accel.range = adafruit_lis3dh.RANGE_4_G |
| 59 | +# accel.set_tap(1, 80) # Single tap, second value is sensitivity |
| 60 | + |
| 61 | +# Set up playing audio on A0 and interruptable playing |
| 62 | +myaudio = audioio.AudioOut(board.A0) |
| 63 | +audio_file = None |
| 64 | + |
| 65 | +def play_file(audio_filename): |
| 66 | + global audio_file # pylint: disable=global-statement |
| 67 | + if myaudio.playing: |
| 68 | + myaudio.stop() |
| 69 | + if audio_file: |
| 70 | + audio_file.close() |
| 71 | + audio_file = open("/sounds/"+audio_filename, "rb") |
| 72 | + wav = audioio.WaveFile(audio_file) |
| 73 | + print("Playing "+audio_filename+".") |
| 74 | + myaudio.play(wav) |
| 75 | + |
| 76 | +# Process wav files in the flash drive sounds directory |
| 77 | +wavefiles = [file for file in os.listdir("/sounds/") |
| 78 | + if (file.endswith(".wav") and not file.startswith("._"))] |
| 79 | +if len(wavefiles) < 1: |
| 80 | + print("No wav files found in sounds directory") |
| 81 | +else: |
| 82 | + print("Audio files found: ", wavefiles) |
| 83 | + |
| 84 | +PUSH_COLOR = GREEN |
| 85 | +ANIM_COLOR = WHITE |
| 86 | + |
| 87 | +COLORS = ["RED", "YELLOW", "GREEN", "CYAN", "BLUE", "PURPLE", "WHITE"] |
| 88 | +COLOR_TUPLES = [RED, YELLOW, GREEN, CYAN, BLUE, PURPLE, WHITE] |
| 89 | + |
| 90 | +buttons = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] |
| 91 | +button_colors = [OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, |
| 92 | + OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF] |
| 93 | +shuffled_colors = list(button_colors) |
| 94 | +Shuffled = False |
| 95 | + |
| 96 | +# Time to process the filenames using the special file name syntax |
| 97 | +# Currently nn-color-name.wav where nn = 2 digit number 0 to 15 |
| 98 | +# color is lower or upper case color name from above and |
| 99 | +# name can be anything. BUT these all must be separated by a "-" |
| 100 | +# Example 02-blue-firetruck.wav is valid. Note leading 0 for 0 to 9 |
| 101 | +wavnames = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""] |
| 102 | +shuffled_names = list(wavnames) # Duplicate list, wavnames is our reference |
| 103 | +shuffled = False |
| 104 | +for soundfile in wavefiles: |
| 105 | + print("Processing "+soundfile) |
| 106 | + pos = int(soundfile[0:2]) |
| 107 | + if pos >= 0 and pos < 16: # Valid filenames start with 00 to 15 |
| 108 | + wavnames[pos] = soundfile # Store soundfile in proper index |
| 109 | + shuffled_names[pos] = soundfile |
| 110 | + skip = soundfile[3:].find('-') + 3 |
| 111 | + user_color = soundfile[3:skip].upper() # Detect file color |
| 112 | + print("For file "+soundfile+", color is "+user_color+".") |
| 113 | + file_color = COLOR_TUPLES[COLORS.index(user_color)] |
| 114 | + button_colors[pos] = file_color |
| 115 | + shuffled_colors[pos] = file_color |
| 116 | + else: |
| 117 | + print("Filenames must start with a number from 00 to 15 - "+soundfile) |
| 118 | + |
| 119 | +# this will be called when button events are received |
| 120 | +def blink(event): |
| 121 | + # turn the LED on when a rising edge is detected |
| 122 | + if event.edge == NeoTrellis.EDGE_RISING: # Trellis button pushed |
| 123 | + print("Button "+str(event.number)+" pushed") |
| 124 | + if event.number > 15: |
| 125 | + print("Event number out of range: ", event.number) |
| 126 | + trellis.pixels[event.number] = WHITE |
| 127 | + if shuffled_names[event.number] != "": |
| 128 | + play_file(shuffled_names[event.number]) |
| 129 | + |
| 130 | + # turn the LED off when a rising edge is detected (button released) |
| 131 | + elif event.edge == NeoTrellis.EDGE_FALLING: |
| 132 | + trellis.pixels[event.number] = shuffled_colors[event.number] |
| 133 | + |
| 134 | +for i in range(16): |
| 135 | + # activate rising edge events on all keys |
| 136 | + trellis.activate_key(i, NeoTrellis.EDGE_RISING) |
| 137 | + # activate falling edge events on all keysshuff |
| 138 | + trellis.activate_key(i, NeoTrellis.EDGE_FALLING) |
| 139 | + # set all keys to trigger the blink callback |
| 140 | + trellis.callbacks[i] = blink |
| 141 | + |
| 142 | + # cycle the LEDs on startup |
| 143 | + trellis.pixels[i] = ANIM_COLOR |
| 144 | + time.sleep(.05) |
| 145 | + |
| 146 | +# On start, set the pixels on trellis to the file name colors chosen |
| 147 | +for i in range(16): |
| 148 | + trellis.pixels[i] = shuffled_colors[i] |
| 149 | + time.sleep(.05) |
| 150 | + |
| 151 | +while True: |
| 152 | + # call the sync function call any triggered callbacks |
| 153 | + trellis.sync() |
| 154 | + |
| 155 | + # Check push switch, reset trellis buttons randomization if pressed |
| 156 | + if not push_switch.value: |
| 157 | + myaudio.stop() # Stop any audio playing |
| 158 | + print("RGB Switch Push - reset shuffle if needed") |
| 159 | + shuffled_names = list(wavnames) # Reset with clean lists |
| 160 | + shuffled_colors = list(button_colors) |
| 161 | + for i in range(16): |
| 162 | + trellis.pixels[i] = shuffled_colors[i] |
| 163 | + time.sleep(.05) |
| 164 | + Shuffled = False |
| 165 | + led.color = GREEN |
| 166 | + # Check accelerometer |
| 167 | + if accel.shake(shake_threshold=15): # Change shake(val) to tapped |
| 168 | + myaudio.stop() # Stop any audio playing |
| 169 | + print("Unit Tapped - shuffle sound files to random buttons") |
| 170 | + shuffled_names = list(wavnames) # Copy lists |
| 171 | + shuffled_colors = list(button_colors) |
| 172 | + for i in range(len(wavnames)): # Do the shuffling |
| 173 | + random_i = random.randrange(len(wavnames)) |
| 174 | + # Swap current name with a random slot |
| 175 | + name = shuffled_names[random_i] |
| 176 | + shuffled_names[random_i] = shuffled_names[i] |
| 177 | + shuffled_names[i] = name |
| 178 | + number = shuffled_colors[random_i] |
| 179 | + shuffled_colors[random_i] = shuffled_colors[i] |
| 180 | + shuffled_colors[i] = number |
| 181 | + for i in range(16): |
| 182 | + trellis.pixels[i] = shuffled_colors[i] |
| 183 | + time.sleep(.05) |
| 184 | + print(shuffled_names) |
| 185 | + print(shuffled_colors) |
| 186 | + shuffled = True |
| 187 | + led.color = RED |
| 188 | + # the trellis can only be read every 17 milliseconds or so |
| 189 | + time.sleep(.019) |
0 commit comments