Audio Library Examples on Trellis M4

Now that you've got the Arduino IDE setup for the Trellis M4 and the Audio library, we'll make a simple test of the audio system.

First open the Arduinio IDE and create a new sketch by clicking  File > New

Then, copy the code shown below and paste it into the new sketch.

Download: file
/*
  Audio Library on Trellis M4
  Demo of the audio sweep function.
  The user specifies the amplitude,
  start and end frequencies (which can sweep up or down)
  and the length of time of the sweep.
   */

#include <Audio.h>
// Paste your Audio System Design Tool code below this line:


//
 GUItool: end automatically generated code

float t_ampx = 0.05;  // Amplitude
int t_lox = 10;  // Low frequency
int t_hix = 22000;  // High frequency
float t_timex = 10; // Length of time of the sweep in seconds


void setup(void)
{

  Serial.begin(9600);
  //while (!Serial) ;
  delay(3000);

  AudioMemory(6);

  Serial.println("setup done");

  if(!tonesweep1.play(t_ampx,t_lox,t_hix,t_timex)) {
    Serial.println("AudioSynthToneSweep - begin failed");
    while(1);
  }
  // wait for the sweep to end
  while(tonesweep1.isPlaying());

  // and now reverse the sweep
  if(!tonesweep1.play(t_ampx,t_hix,t_lox,t_timex)) {
    Serial.println("AudioSynthToneSweep - begin failed");
    while(1);
  }
  // wait for the sweep to end
  while(tonesweep1.isPlaying());
  Serial.println("Done");
}

void loop(void)
{
}

Tonesweep

 

Create a tonesweep node and a dacs node.

 

Patch the output port of the tonesweep to both inputs of the dacs.

 

Double-click the dacs node to open the rename dialog box.

 

Rename the node "audioOutput" and then press the "OK" button (hitting Enter on the keyboard doesn't work for me)

 

Next, press the Export button to generate the source code snippet. Since the tool was designed for use with the Teensy, some of the library imports listed at the top of the code aren't necessary for use with the Trellis M4. So, only select and copy the section surrounded by the // GUItool: lines.

Next, head back to the Arduino IDE and paste the code into the section at the top where indicated.

Save this sketch as ToneSweep_TrellisM4.ino

This is what the final sketch looks like after adding the Audio GUI code:

/*
  Audio Library on Trellis M4
  Demo of the audio sweep function.
  The user specifies the amplitude,
  start and end frequencies (which can sweep up or down)
  and the length of time of the sweep.
   */

#include <Audio.h>
// Paste your Audio System Design Tool code below this line:
// GUItool: begin automatically generated code
AudioSynthToneSweep      tonesweep1;     //xy=531.0833129882812,166.08334350585938
AudioOutputAnalogStereo  audioOutput;          //xy=727.0833129882812,166.08334350585938
AudioConnection          patchCord1(tonesweep1, 0, audioOutput, 0);
AudioConnection          patchCord2(tonesweep1, 0, audioOutput, 1);
// GUItool: end automatically generated code

float t_ampx = 0.05;  // Amplitude
int t_lox = 10;  // Low frequency
int t_hix = 22000;  // High frequency
float t_timex = 10; // Length of time of the sweep in seconds


void setup(void) {

  Serial.begin(9600);
  //while (!Serial) ;
  delay(3000);

  AudioMemory(6);

  Serial.println("setup done");

  if(!tonesweep1.play(t_ampx,t_lox,t_hix,t_timex)) {
    Serial.println("AudioSynthToneSweep - begin failed");
    while(1);
  }
  // wait for the sweep to end
  while(tonesweep1.isPlaying());

  // and now reverse the sweep
  if(!tonesweep1.play(t_ampx,t_hix,t_lox,t_timex)) {
    Serial.println("AudioSynthToneSweep - begin failed");
    while(1);
  }
  // wait for the sweep to end
  while(tonesweep1.isPlaying());
  Serial.println("Done");
}

void loop(void){
}

Now, it's time to upload the code to your Trellis M4 and test it out! First, make sure you have headphones or speakers plugged into the Trellis M4.

Next, plug the Trellis M4 into your computer with the USB cable (make sure it's a data cable, not an evil power-only cable!)

Bootloader Mode

 

Now, we'll put the Trellis M4 into "bootloader" mode. In this mode it will be ready to receive the Arduino upload. Use a thin, pointed object such as a headphone plug or chopstick to double-click the reset button on the back side of the board.

 

Once you have double-clicked the reset button, the indicator LED will turn green. (You'll notice a new USB drive appear on your computer named TRELM4BOOT, this is the bootloader USB storage built right into the Trellis M4. We don't need to use this for our Arduino sketch upload.) It is now ready to receive the Arduino upload.

In Arduino, select the Trellis M4 board from the Tools > Board: menu item

 

Choose the proper port from the Tools > Port menu item as shown

 

Now, compile and upload the code to the Trellis M4 by clicking Sketch > Upload

 

You will hear a long upward and then downward tone sweep. Success!

Waveform Pitch

You can make a simple patch that swaps the tone sweep for a waveform node in the Audio System Design Tool in order to test the Trellis M4 hardware while playing a sound. The buttons will light up and the accelerometer tilt will bend the pitch (frequency) of the waveform oscillator

First, copy and save this code as a new Arduino sketch.

Download: file
// Trellis M4 Audio Workshop
// shows how to alter pitch with accelerometer
// Waveform Mod

#include <Audio.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL343.h>
#include "Adafruit_NeoTrellisM4.h"
#include <elapsedMillis.h>

Adafruit_ADXL343 accel = Adafruit_ADXL343(123, &Wire1);

// The NeoTrellisM4 object is a keypad and neopixel strip subclass
// that does things like auto-update the NeoPixels and stuff!
Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4();
// Paste your Audio System Design Tool code below this line:




//

// GUItool: begin automatically generated code
//AudioSynthWaveform       waveform1;      //xy=592.7221984863281,187.38888549804688
//AudioOutputAnalogStereo  audioOutput;          //xy=777.0833129882812,189.08334350585938
//AudioConnection          patchCord1(waveform1, 0, audioOutput, 0);
//AudioConnection          patchCord2(waveform1, 0, audioOutput, 1);
// GUItool: end automatically generated code


int xbend = 64;
int ybend = 64;
int last_xbend = 64;
int last_ybend = 64;

int count=1;

void setup() {
  trellis.begin();
  trellis.show();  // Initialize w all pixels off
  trellis.setBrightness(255);

  if(!accel.begin()) {
  Serial.println("No accelerometer found");
  while(1);
}
  AudioMemory(10);
  // Initialize processor and memory measurements
  AudioProcessorUsageMaxReset();
  AudioMemoryUsageMaxReset();
  Serial.begin(115200);
  waveform1.begin(WAVEFORM_SAWTOOTH);
  delay(1000);
}


void loop() {
  waveform1.frequency(110 + (ybend * 2));
  waveform1.amplitude(0.05);
  wait(5);
}

void wait(unsigned int milliseconds){
  elapsedMillis msec=0;
  while (msec <= milliseconds){
    trellis.tick();
    while(trellis.available()) {
      keypadEvent e = trellis.read();
      Serial.print((int)e.bit.KEY);
      int keyindex = e.bit.KEY;
      if(e.bit.EVENT == KEY_JUST_PRESSED){
        Serial.println(" pressed");
        trellis.setPixelColor(keyindex, Wheel(keyindex * 255 / 32)); // rainbow!
        }
      else if(e.bit.EVENT == KEY_JUST_RELEASED){
        Serial.println(" released");
        trellis.setPixelColor(keyindex, 0);
        }
     }

   // Check for accelerometer
    sensors_event_t event;
    accel.getEvent(&event);

    //check if it's been moved a decent amount
    if (abs(event.acceleration.x) < 2.0) {  // 2.0 m/s^2
    // don't make any bend unless they've really started moving it
     xbend = 64;
   }
    else {
      if (event.acceleration.x > 0) {
      xbend = ofMap(event.acceleration.x, 2.0, 10.0, 63, 0, true);  // 2 ~ 10 m/s^2 is upward bend
    }
    else {
        xbend = ofMap(event.acceleration.x, -2.0, -10.0, 64, 127, true);  // -2 ~ -10 m/s^2 is downward bend
      }
    }
    if (xbend != last_xbend) {
      Serial.print("X mod: "); Serial.println(xbend);
      last_xbend = xbend;
    }

    if (abs(event.acceleration.y) < 2.0) {  // 2.0 m/s^2
     ybend = 64;
   }
    else {
      if (event.acceleration.y > 0) {
      ybend = ofMap(event.acceleration.y, 2.0, 10.0, 63, 0, true);  // 2 ~ 10 m/s^2 is upward bend
    }
    else {
        ybend = ofMap(event.acceleration.y, -2.0, -10.0, 64, 127, true);  // -2 ~ -10 m/s^2 is downward bend
      }
    }
    if (ybend != last_ybend) {
      Serial.print("Y mod: "); Serial.println(ybend);
      last_ybend = ybend;
    }
  }
}


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return Adafruit_NeoPixel::Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return Adafruit_NeoPixel::Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return Adafruit_NeoPixel::Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

// floating point map
float ofMap(float value, float inputMin, float inputMax, float outputMin, float outputMax, bool clamp) {
    float outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin);

    if (clamp) {
      if (outputMax < outputMin) {
        if (outVal < outputMax)  outVal = outputMax;
        else if (outVal > outputMin)  outVal = outputMin;
      } else {
        if (outVal > outputMax) outVal = outputMax;
        else if (outVal < outputMin)  outVal = outputMin;
      }
    }
    return outVal;

}

You can see that we're now using some of the built in NeoTrellis M4 library functions to read buttons, light the button NeoPixels, and read the accelerometer.

We've got some helper functions to make this easier, such as the Wheel function for picking colors, and the ofMap function to map the accelerometer values from floating point numbers to integers.

Waveform

The key elements of the Audio library code here are: waveform1.begin(WAVEFORM_SAWTOOTH); which initializes the waveform1 node as a sawtooth waveform in the setup().

Then, in order to adjust the pitch of the waveform interactively, we'll make a waveform1.frequency() call in the main loop() and give it a value of 110 + a value mapped to the accelerometer reading on the y-axis, which looks like this: waveform1.frequency(110 + (ybend * 2));

The Info panel in the Audio System Design Tool shows us the different functions available:

Functions

begin(waveform);

Configure the waveform type to create.

begin(level, frequency, waveform);

Output a waveform, and set the amplitude and frequency.

frequency(freq);

Change the frequency.

amplitude(level);

Change the amplitude. Set to 0 to turn the signal off.

offset(level);

Add a DC offset, from -1.0 to +1.0. Useful for generating waveforms to use as control or modulation signals.

phase(angle);

Cause the generated waveform to jump to a specific point within its cycle. Angle is from 0 to 360 degrees. When multiple objects are configured, AudioNoInterrupts() should be used to guarantee all new settings take effect together.

pulseWidth(amount);

Change the width (duty cycle) of the pulse.

arbitraryWaveform(array, maxFreq);

Configure the waveform to be used with WAVEFORM_ARBITRARY. Array must be an array of 256 samples. Currently, the data is used without any filtering, which can cause aliasing with frequencies above 172 Hz. For higher frequency output, you must bandwidth limit your waveform data. Someday, "maxFreq" will be used to do this automatically.

Notes

Supported Waveforms:

  • WAVEFORM_SINE
  • WAVEFORM_SAWTOOTH
  • WAVEFORM_SAWTOOTH_REVERSE
  • WAVEFORM_SQUARE
  • WAVEFORM_TRIANGLE
  • WAVEFORM_TRIANGLE_VARIABLE
  • WAVEFORM_ARBITRARY
  • WAVEFORM_PULSE
  • WAVEFORM_SAMPLE_HOLD

Waveform to Audio Output

In the Audio System Design Tool, create a waveform node and connect it to a dacs node renamed to "audioOutput", then copy the GUI code snippet.

Paste the code snippet into your Arduino sketch and save it as Waveform_Mode_TrellisM4.ino

Upload the code to your board. Now, you'll be able to bend the pitch by tilting the NeoTrellis, and the buttons will light up when pressed.

This is what the final sketch looks like after adding the Audio GUI code:

// Trellis M4 Audio Workshop
// shows how to alter pitch with accelerometer
// Waveform Mod

#include <Audio.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL343.h>
#include "Adafruit_NeoTrellisM4.h"
#include <elapsedMillis.h>

Adafruit_ADXL343 accel = Adafruit_ADXL343(123, &Wire1);

// The NeoTrellisM4 object is a keypad and neopixel strip subclass
// that does things like auto-update the NeoPixels and stuff!
Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4();
// Paste your Audio System Design Tool code below this line:
// GUItool: begin automatically generated code
AudioSynthWaveform       waveform1;      //xy=592.7221984863281,187.38888549804688
AudioOutputAnalogStereo  audioOutput;          //xy=777.0833129882812,189.08334350585938
AudioConnection          patchCord1(waveform1, 0, audioOutput, 0);
AudioConnection          patchCord2(waveform1, 0, audioOutput, 1);
// GUItool: end automatically generated code


int xbend = 64;
int ybend = 64;
int last_xbend = 64;
int last_ybend = 64;

int count=1;

void setup() {
  trellis.begin();
  trellis.show();  // Initialize w all pixels off
  trellis.setBrightness(255);

  if(!accel.begin()) {
  Serial.println("No accelerometer found");
  while(1);
}
  AudioMemory(10);
  // Initialize processor and memory measurements
  AudioProcessorUsageMaxReset();
  AudioMemoryUsageMaxReset();
  Serial.begin(115200);
  waveform1.begin(WAVEFORM_SAWTOOTH);
  delay(1000);
}


void loop() {
  waveform1.frequency(110 + (ybend * 2));
  waveform1.amplitude(0.05);
  wait(5);
}

void wait(unsigned int milliseconds){
  elapsedMillis msec=0;
  while (msec <= milliseconds){
    trellis.tick();
    while(trellis.available()) {
      keypadEvent e = trellis.read();
      Serial.print((int)e.bit.KEY);
      int keyindex = e.bit.KEY;
      if(e.bit.EVENT == KEY_JUST_PRESSED){
        Serial.println(" pressed");
        trellis.setPixelColor(keyindex, Wheel(keyindex * 255 / 32)); // rainbow!
        }
      else if(e.bit.EVENT == KEY_JUST_RELEASED){
        Serial.println(" released");
        trellis.setPixelColor(keyindex, 0);
        }
     }

   // Check for accelerometer
    sensors_event_t event;
    accel.getEvent(&event);

    //check if it's been moved a decent amount
    if (abs(event.acceleration.x) < 2.0) {  // 2.0 m/s^2
    // don't make any bend unless they've really started moving it
     xbend = 64;
   }
    else {
      if (event.acceleration.x > 0) {
      xbend = ofMap(event.acceleration.x, 2.0, 10.0, 63, 0, true);  // 2 ~ 10 m/s^2 is upward bend
    }
    else {
        xbend = ofMap(event.acceleration.x, -2.0, -10.0, 64, 127, true);  // -2 ~ -10 m/s^2 is downward bend
      }
    }
    if (xbend != last_xbend) {
      Serial.print("X mod: "); Serial.println(xbend);
      last_xbend = xbend;
    }

    if (abs(event.acceleration.y) < 2.0) {  // 2.0 m/s^2
     ybend = 64;
   }
    else {
      if (event.acceleration.y > 0) {
      ybend = ofMap(event.acceleration.y, 2.0, 10.0, 63, 0, true);  // 2 ~ 10 m/s^2 is upward bend
    }
    else {
        ybend = ofMap(event.acceleration.y, -2.0, -10.0, 64, 127, true);  // -2 ~ -10 m/s^2 is downward bend
      }
    }
    if (ybend != last_ybend) {
      Serial.print("Y mod: "); Serial.println(ybend);
      last_ybend = ybend;
    }
  }
}


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return Adafruit_NeoPixel::Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return Adafruit_NeoPixel::Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return Adafruit_NeoPixel::Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

// floating point map
float ofMap(float value, float inputMin, float inputMax, float outputMin, float outputMax, bool clamp) {
    float outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin);

    if (clamp) {
      if (outputMax < outputMin) {
        if (outVal < outputMax)  outVal = outputMax;
        else if (outVal > outputMin)  outVal = outputMin;
      } else {
        if (outVal > outputMax) outVal = outputMax;
        else if (outVal < outputMin)  outVal = outputMin;
      }
    }
    return outVal;

}

You can also open the Arduino Serial Monitor to see the print statements of the accelerometer readings and button presses. This is very useful for troubleshooting!

First, re-select the TrellisM4 in the Tools > Port menu (a new port is often assigned after upload), then open the serial monitor by clicking Tools > Serial Monitor

Next, we'll create a more sophisticated, four voice polyphonic synthesizer.

This guide was first published on Dec 18, 2018. It was last updated on Dec 18, 2018. This page (Audio Library Examples on Trellis M4) was last updated on Oct 20, 2019.