Maker.io main logo

How to use Adafruit’s Neotrellis as a Soundboard

2019-10-31 | By Evan Browning

License: See Original Project

Getting Started

I began this project by reading documentation for the NeoTrellis. I decided to program the project in the CircuitPython language with the Mu editor.

Getting programs to run:

1. Install Mu. This is an open source editor that will allow you to write code to the NeoTrellis and easily communicate with it.

2. Download the latest version of CircuitPython for the NeoTrellis and drag this .uf2 file to your desktop.

3. Connect the NeoTrellis to your computer. A new external drive called CIRCUITPY should show up in your computer’s file system as shown below. If CIRCUITPY does not show up, see the next step.

CIRCUITPY_1

4. If CIRCUITPY shows up, skip this step. Double click the reset button on the bottom of the NeoTrellis using a thin object such as a pen or screwdriver. The button is in a small hole in the case underneath the NeoTrellis as shown in the picture below. A drive called “TREM4BOOT” should show up on your computer. Drag the .uf2 file (from step 2) into this drive. TRELM4BOOT should disappear and then CIRCUITPY should show up.

Reset_Button_2

drag_file_3

5. Open Mu. A popup window should ask you what mode you want. Select “Adafruit CircuitPython” and click OK. If this popup doesn’t show up, click “Mode” in the upper left corner and then select “Adafruit CircuitPython.”

Select_Mode_4

MU_5

6. Copy and paste the example code below into Mu. All gray highlighted text is a comment.

Copy Code
import time	#library for the time function

while True: #main loop
print("Hello World!") #say “Hello World!”
time.sleep(1) #delay for reading serial output

7. Double click on the “untitled*” tab near the upper left corner. A save as screen will pop up.

untitled_7

8. Save the file as “code.py” to CIRCUITPY. If your computer says that this file is already in CIRCUITPY, click replace. This is how you tell the NeoTrellis to run your program, so you will be replacing code.py every time you run a different program on the NeoTrellis.

codepy_8

9. Click on “Serial” at the top of the window to open the serial monitor to see if the program is working. A series of “Hello World!” statements should appear at the bottom of the screen.

Serial_9

Notes:

  • Since the file “code.py” is how you run programs on the NeoTrellis, if you want to save copies of multiple programs, you can rename them and save them to your computer.
  • If problems arise, reset the NeoTrellis. You may have to drag the .uf2 file back into TREM4BOOT.

Default Drum machine

This example program will help to make sure that you can hear audio from the NeoTrellis.

1. Download the files for a drum machine example program (neotrellis_m4_default_files) and unzip them.

2. Connect the NeoTrellis to either speakers or headphones with volume adjustment using the 3.5mm headphone jack. The NeoTrellis does not have volume adjustment, so start with a low volume.

3. Connect the NeoTrellis to the computer and drag the drum machine files to the CIRCUITPY drive. If CIRCUITPY does not show up, see the above section “Getting Programs to Run”.

4. After a startup lightshow, a white line of pixels should sweep across the board every few seconds. Touching a button will keep it lit until it is pressed again. When the white line reaches a lit button, the drum voice for that button will play. Each color is a different voice.

Installing Libraries

Because CircuitPython has some very useful libraries, it is a good idea to install some of them.

1. Check to see if CIRCUITPY has a folder called “lib”. If not, create a new folder, name it lib, and drag it into CIRCUITPY. This folder is where libraries will go.

2. Download the Adafruit CircuitPython Trellis M4 library. Click “clone or download” and then “Download Zip” to download the files. Unzip the file by double clicking on it. A folder called “Adafruit_CircuitPython_TrellisM4-master“ should open. Drag this folder into the lib folder. This library is specifically for the NeoTrellis.

3. Download the latest CircuitPython Library Bundle. Click on “adafruit-circuitpython-bundle-4.x-mpy-20190606.zip” to download the files. Unzip the file by double clicking on it. A folder called “adafruit-circuitpython-bundle-4.x-mpy-20190606” should show up. Open this folder, and then open the “lib” folder that is inside of it. Drag the contents of this “lib” into the “lib” folder of CIRCUITPY.

Lighting things up

The documentation for the NeoTrellis library contained information for the following functions that deal with handling button presses and lighting up the board.

  • pressed_keys - A list of tuples of currently pressed button coordinates.
  • pixels - Provides a two-dimensional grid representation of the NeoPixels on the NeoTrellis M4.
  • pixels.fill - Colors all the NeoPixels a given color.
  • pixels.brightness - The overall brightness of the pixels. Must be a number between 0 and 1, which represents a percentage, i.e. 0.3 is 30%.
  • pixels.width - The width of the NeoPixel grid. When rotation is 0 or 180, the width is 8. When rotation is 90 or 270, the width is 4.
  • pixels.height - The height of the NeoPixel grid. When rotation is 0 or 180, the height is 4. When rotation is 90 or 270, the height is 8.

Using the functions pixels and pixels.brightness, I began lighting up buttons by defining the location and colors for 4 buttons. The code is shown below.

Copy Code
import time
import adafruit_trellism4 #import NeoTrellis Library

trellis = adafruit_trellism4.TrellisM4Express()

trellis.pixels.brightness = (0.2)

buttons = [ (0, 0), #button 1
(7, 0), #button 2
(0, 3), #button 3
(7, 3)] #button 4

colors = [ (179, 0, 255), #button 1
(0, 255, 0), #button 2
(0, 0, 255), #button 3
(255, 255, 0) ] #button 4

def ColorButtons(): #function to set button colors
for i in range(len(buttons)):
trellis.pixels[buttons[i]] = colors[i]


while True: #main loop
ColorButtons()

colored_10

Above the four buttons are colored

Next, I added some code to detect when a button was pressed. This tests to see if a button is pressed by seeing if the pressed_keys function contains information. If no keys are pressed, pressed_keys will be empty, which makes the variable pressed false. When keys are pressed, pressed will be True and the NeoTrellis will say “a button is being pressed” in the serial monitor.

Copy Code
while True: #main loop
pressed = list(trellis.pressed_keys)

if pressed:
print("a button is being pressed")
else:
print("a button is not being pressed")
ColorButtons()
time.sleep(0.1) #delay for reading serial monitor

Next, I added a function that checks to see which button is being pressed. Using a loop, the function tests to see if the button coordinate it was given matches any of the defined button coordinates. If the button is not found, the button will return False. This goes above the main loop.

Copy Code
def Location(val):
found = False
for i in range(len(buttons)):
if val == buttons[i]:
found = i + 1
return found

The location function is implemented below, using the variable place to keep track of what button was pressed.

Copy Code
while True: #main while loop
pressed = list(trellis.pressed_keys)

if pressed:
print("a button is being pressed")
place = Location(pressed[0])
if place:
print("button ", place, " is being pressed")
trellis.pixels[buttons[place - 1]] = (255, 255, 255)
else:
print("a button is not being pressed")
ColorButtons()
time.sleep(0.1) #delay for reading serial monitor

Next, I added an if statement to see if the pushed button is one of the defined buttons that is intended to play audio. If it is, the code will try to play the audio at the bottom under “if valid:”

Copy Code
valid = False

while True: #main loop
pressed = list(trellis.pressed_keys)

if pressed:
place = Location(pressed[0])
if place:
print("button ", place, " is being pressed")
trellis.pixels[buttons[place - 1]] = (255, 255, 255)
valid = True
else:
print("an invalid button is being pressed")
valid = False
else:
print("a button is not being pressed")
valid = False
ColorButtons()

if valid:
#play the associated audio for the pushed button
pass
time.sleep(0.1) #delay for reading serial monitor

Audio

For the audio portion of this program, I used the drum machine example to make the audio play for each button by renaming the VOICES array used in the example, but the rest of the code is directly copied. Below is the setup for the audio that goes above the main loop.

Copy Code
import board
import busio
import audioio
from wave_parsing import parse_wav

#beginning of audio setup
VOICES = ["Button_1.wav", #button 1
"Button_2.wav", #button 2
"Button_3.wav", #button 3
"Button_4.wav"] #button 4

#Parse the first file to figure out what format its in
wave_format = parse_wav(VOICES[0])
print(wave_format)

# Audio playback object - we'll go with either mono or stereo depending on
# what we see in the first file
if wave_format['channels'] == 1:
audio = audioio.AudioOut(board.A1)
elif wave_format['channels'] == 2:
audio = audioio.AudioOut(board.A1, right_channel=board.A0)
else:
raise RuntimeError("Must be mono or stereo waves!")
mixer = audioio.Mixer(voice_count=len(VOICES),
sample_rate=wave_format['sample_rate'],
channel_count=wave_format['channels'],
bits_per_sample=16, samples_signed=True)
audio.play(mixer)

samples = []

Next, I added code to the main loop that plays the audio for each button. This is very similar to the code from the drum machine example.

Copy Code
while True: #main loop
pressed = list(trellis.pressed_keys)

if pressed:
place = Location(pressed[0])
if place:
print("button ", place, " is being pressed")
trellis.pixels[buttons[place - 1]] = (255, 255, 255)
valid = True
else:
print("an invalid button is being pressed")
valid = False
else:
print("a button is not being pressed")
valid = False
ColorButtons()

if valid:
print("Valid")

# play the sound
wave_file = open(VOICES[place-1], "rb")
sample = audioio.WaveFile(wave_file)
mixer.play(sample, voice=0)

while mixer.playing:
print("Playing Sound")
time.sleep(0.1)
ColorButtons()
time.sleep(0.1)

Lastly, I added a feature that changes the audio being played if a different button is pressed before the audio is finished for the button that was previously pressed.

Copy Code
if valid:
print("Valid")

# play the sound
wave_file = open(VOICES[place-1], "rb")
sample = audioio.WaveFile(wave_file)
mixer.play(sample, voice=0)

while mixer.playing:
print("Playing Sound")
time.sleep(0.1)

#check to see if a different button was pressed
pressed = list(trellis.pressed_keys)
if pressed:
new_place = Location(pressed[0])
if (new_place != place) or (new_place == False):
print("Different Button Pressed")
break
ColorButtons()

The Final Code

Below, the entire program is shown.

Copy Code
import time
import adafruit_trellism4 #import NeoTrellis Library
import board
import busio
import audioio
from wave_parsing import parse_wav

trellis = adafruit_trellism4.TrellisM4Express()


####### Change the code below #######
trellis.pixels.brightness = (0.2)

buttons = [ (0, 0), #button 1
(7, 0), #button 2
(0, 3), #button 3
(7, 3)] #button 4

colors = [ (179, 0, 255), #button 1
(0, 255, 0), #button 2
(0, 0, 255), #button 3
(255, 255, 0) ] #button 4

#begining of audio setup
VOICES = ["Button_1.wav", #button 1
"Button_2.wav", #button 2
"Button_3.wav", #button 3
"Button_4.wav"] #button 4
####### Change the code above #######


#Parse the first file to figure out what format it is in
wave_format = parse_wav(VOICES[0])
print(wave_format)

# Audio playback object - we'll go with either mono or stereo depending on
# what we see in the first file
if wave_format['channels'] == 1:
audio = audioio.AudioOut(board.A1)
elif wave_format['channels'] == 2:
audio = audioio.AudioOut(board.A1, right_channel=board.A0)
else:
raise RuntimeError("Must be mono or stereo waves!")
mixer = audioio.Mixer(voice_count=len(VOICES), sample_rate=wave_format['sample_rate'],
channel_count=wave_format['channels'],
bits_per_sample=16, samples_signed=True)
audio.play(mixer)

samples = []


def ColorButtons(): #function to set button colors
for i in range(len(buttons)):
trellis.pixels[buttons[i]] = colors[i]


def Location(val):
found = False
for i in range(len(buttons)):
if val == buttons[i]:
found = i + 1
return found



valid = False

while True: #main loop
pressed = list(trellis.pressed_keys)

if pressed:
place = Location(pressed[0])
if place:
print("button ", place, " is being pressed")
trellis.pixels[buttons[place - 1]] = (255, 255, 255)
valid = True
else:
print("an invalid button is being pressed")
valid = False
else:
print("a button is not being pressed")
valid = False
ColorButtons()

if valid:
print("Valid")

#play the sound
wave_file = open(VOICES[place-1], "rb")
sample = audioio.WaveFile(wave_file)
mixer.play(sample, voice=0)

while mixer.playing:
print("Playing Sound")
time.sleep(0.1)

#check to see if a different button was pressed
pressed = list(trellis.pressed_keys)
if pressed:
new_place = Location(pressed[0])
if (new_place != place) or (new_place == False):
print("Different Button Pressed")
break #exit the while to end audio
ColorButtons()
time.sleep(0.1)

playing_11

Although difficult to see, the image above is showing that the top right button is white,

meaning that the audio for the button is currently playing.

Creating Audio Files

To be played on the NeoTrellis, audio files must be 16-bit PCM WAV files sampled at 22,050 Hz and must either all be stereo, or all be mono.

One way to obtain and convert audio files is to use an open source program called Audacity. You can use existing audio files such as something recorded with a smartphone or you can record directly on Audacity.

1. Install Audacity.

2. Skip this section if you already have audio on your computer that is ready to be converted. If you don’t, you can also record directly on audacity.

a. Start by opening audacity. Click the record button as shown below. A new project will open.

record_12

b. You can now record yourself talking. When finished, click the stop button.

stop_13

c. You can play back your audio by clicking the back button and then clicking play.

buttons_14

d. If you would like to re-record something, click the X to start a new recording.

re-record_15

3. If you have audio ready to go, drag the first audio file into the audacity window. They must be converted one at a time.

4. Because your audio must be mono, check to see if you have one or two blue waveforms. If your audio has just one waveform, skip this step.

waves_16

If you have two blue waveforms, click on “tracks” in the top of the window, and then click “Mix Stereo down to Mono”.

mix_17

5. Ensure that the audio is 16-bit by clicking on the file name. Scroll down to “Format” and check to see that 16-bit PCM is highlighted.

PCM_18

6. Set the sample rate to 22,050 Hz by clicking below “Project Rate (Hz)” in the lower left corner.

rate_19

7. Export the audio by going to “File” at the top. Go to export and then Export as WAV. and then export audio.

export_20

8. Save the file to CIRCUITPY, or anywhere else you would like. You can name the audio whatever you like, but try to keep it short. The name has to be 32 characters or less. Click OK when the screen for optional metadata shows up.

Save_21

9. If you didn’t save your audio to CIRCUITPY, then drag them in. You can now change the code to play these files on the NeoTrellis as show in the section below.

Customizing the soundboard

The portion of the final code shown below is designed to be changed for future uses. It is near the top of the code.

code_22

1. Brightness: The brightness of the buttons is controlled by the function below. If you want a different brightness value, change the highlighted value below to be anywhere from 0 to 1, where 1 is the maximum setting.

code_23

2. Buttons: Each button has a coordinate pair enclosed in parentheses as shown in the first image below. The coordinate pairs are relative to the upper left corner button when the board is oriented with the USB facing away from you. This layout is shown in the second picture below. The list of the ordered pairs below is known as an array because each coordinate is separated by a comma, and each coordinate is enclosed by brackets. To add more buttons, list their coordinates in this array. Be sure to have an opening and closing bracket.

button_code_24

board_25

3. Colors: the color for each button is defined below. The color scheme uses additive synthesis with the three primary colors of red, green, and blue, known as RGB. Each value of red green and blue can be integers from 0 to 255, where 0 is off and 255 is mamximum. Each button color is defined by the three values seperated by commas and enclosed by parenthese. For example, in the highlighted portion below for button 1, the red value is 179, green is off, and blue is maximum. To add more colors, list their RGB values in this array.

4. Again, this is an array similar to the buttons section above.

code_26

5. Audio files: The audio files that you want to play must be 16-bit 22,050 Hz WAV files. See the “Converting Audio” section above. Drag your audio files into CIRCUITPY if you haven’t already. List the name of each audio file that you want to use in the array as shown below. Be sure to include the .wav extension.

code_27

Improvements

One problem that I did not address for this project is what to do if a user wishes to end the audio. The best way to fix this would be to record a short audio clip such as “audio ended”. This would work well for applications where the main audio files are long and may need to be stopped before they are finished playing.

制造商零件编号 4020
ADAFRUIT NEOTRELLIS M4 WITH ENCL
Adafruit Industries LLC
Add all DigiKey Parts to Cart
TechForum

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.

Visit TechForum