Update to support TGA Pro MKII (#14)

* Cleanup and fix issue with DMA transfers on T4 (#13)

* Fix issue with max delay on external memory in AudioEffectAnalogDelay

* Cleanup of tremolo and analog delay effects

* Improved potentiometer getValue() function

* Updated and tested examples with T4.0
pull/18/head
Blackaddr Audio 3 years ago committed by GitHub
parent 6f20a52ce7
commit 8bb56adfd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 54
      examples/Basic/BA0_HelloAudioWorld/BA0_HelloAudioWorld.ino
  2. 29
      examples/Basic/BA1_DelayAndReverb/BA1_DelayAndReverb.ino
  3. 106
      examples/Basic/BA1_TGA_Pro_NOMEM_demo/BA1_TGA_Pro_NOMEM_demo.ino
  4. 209
      examples/Basic/BA2_TGA_Pro_1MEM/BA2_TGA_Pro_1MEM.ino
  5. 271
      examples/Basic/BA3_TGA_Pro_2MEM/BA3_TGA_Pro_2MEM.ino
  6. 94
      examples/Delay/AnalogDelayDemo/AnalogDelayDemo.ino
  7. 40
      examples/Delay/AnalogDelayDemoExpansion/AnalogDelayDemoExpansion.ino
  8. 12
      examples/Delay/ExternalDelayDemo/ExternalDelayDemo.ino
  9. 99
      examples/Delay/SoundOnSoundDemo/SoundOnSoundDemo.ino
  10. 53
      examples/Delay/SoundOnSoundExpansionDemo/SoundOnSoundExpansionDemo.ino
  11. 85
      examples/Modulation/TemoloDemo/TemoloDemo.ino
  12. 43
      examples/Modulation/TremoloDemoExpansion/TremoloDemoExpansion.ino
  13. 9
      examples/Tests/BAExpansionCalibrate/BAExpansionCalibrate.ino
  14. 5
      examples/Tests/MeasureNoise/MeasureNoise.ino
  15. 0
      examples/Tests/TGA_PRO_Basic_Test/PhysicalControls.cpp
  16. 62
      examples/Tests/TGA_PRO_Basic_Test/TGA_PRO_Basic_Test.ino
  17. 0
      examples/Tests/TGA_PRO_Basic_Test/UartTest.cpp
  18. 0
      examples/Tests/TGA_PRO_Basic_Test/spiTest.cpp
  19. 5
      src/BAGpio.h
  20. 231
      src/BAHardware.h
  21. 6
      src/BALibrary.h
  22. 7
      src/common/AudioDelay.cpp
  23. 264
      src/common/BAHardware.cpp
  24. 6
      src/common/ExtMemSlot.cpp
  25. 121
      src/effects/AudioEffectAnalogDelay.cpp
  26. 22
      src/effects/AudioEffectSOS.cpp
  27. 15
      src/effects/AudioEffectTremolo.cpp
  28. 51
      src/peripherals/BAGpio.cpp
  29. 19
      src/peripherals/BAPhysicalControls.cpp
  30. 80
      src/peripherals/BASpiMemory.cpp

@ -0,0 +1,54 @@
/*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board.
*
* The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary
*
* This demo provides a very simple pass-through, clean audio example.
* This can be used to double checking everything is hooked up and working correctly.
*
* This example also demonstrates the bare minimum code necessary to pass audio
* through the TGA Pro:
* - BAAudioControlWM8731 to enable and control the CODEC
* - AudioInputI2S to receive input audio from the CODEC (it's ADC)
* - AudioOutputI2S to send output audio to the CODEC (it's DAC)
*
*/
#include <Audio.h>
#include "BALibrary.h"
using namespace BALibrary; // This prevents us having to put BALibrary:: in front of all the Blackaddr Audio components
BAAudioControlWM8731 codecControl;
AudioInputI2S i2sIn;
AudioOutputI2S i2sOut;
// Audio Connections: name(channel)
// - Setup a mono signal chain, send the mono signal to both output channels in case you are using headphone
// i2sIn(0) --> i2sOut(0)
// i2sIn(1) --> i2sOut(1)
AudioConnection patch0(i2sIn, 0, i2sOut, 0); // connect the cab filter to the output.
AudioConnection patch1(i2sIn, 0, i2sOut, 1); // connect the cab filter to the output.
void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
delay(5); // wait a few ms to make sure the GTA Pro is fully powered up
AudioMemory(48); // Provide an arbitrarily large number of audio buffers (48 blocks) for the effects (delays use a lot more than others)
// If the codec was already powered up (due to reboot) power it down first
codecControl.disable();
delay(100);
codecControl.enable();
delay(100);
}
void loop() {
// The audio flows automatically through the Teensy Audio Library
}

@ -7,7 +7,12 @@
*
* This demo provides an example guitar tone consisting of some slap-back delay,
* followed by a reverb and a low-pass cabinet filter.
*
* This example uses very simple versions of these effects in the PJRC Audio
* Library to make it a bit easier to learn how all this stuff works. More advanced
* and better sounding effects are available from the Teensy Audio community.
*
* A mild cab filter is used in case you are using headphones.
*/
#include <Wire.h>
#include <Audio.h>
@ -28,28 +33,39 @@ AudioMixer4 mixer; // Used to mix the original dry with the wet (ef
AudioFilterBiquad cabFilter; // We'll want something to cut out the highs and smooth the tone, just like a guitar cab.
// Audio Connections
// Audio Connections: name(channel)
// - Setup a mono signal chain, send the mono signal to both output channels
// - The reverb effect doesn't mix the dry signal, so we'll do that ourselves with the mixer effect.
// - We need to reduce the gain into the reverb to prevent it's filters clipping
// - mix the wet and the dry together, then send to a cabFilter then to the output.
// i2sIn(0) --> mixer(0)
// i2sIn(0) --> delayModule(0) --> gainModule(0) --> reverb(0) --> mixer(1)
// mixer(0) --> cabFilter(0) --> i2sOut(1)
AudioConnection patchIn(i2sIn,0, delayModule, 0); // route the input to the delay
AudioConnection patch2(delayModule,0, gainModule, 0); // send the delay to the gain module
AudioConnection patch2b(gainModule, 0, reverb, 0); // then to the reverb
AudioConnection patch2b(gainModule, 0, reverb, 0); // then to the reverb
AudioConnection patch1(i2sIn,0, mixer,0); // mixer input 0 is our original dry signal
AudioConnection patch1(i2sIn,0, mixer,0); // mixer input 0 is our original dry signal
AudioConnection patch3(reverb, 0, mixer, 1); // mixer input 1 is our wet
AudioConnection patch4(mixer, 0, cabFilter, 0); // mixer outpt to the cabinet filter
AudioConnection patch5(cabFilter, 0, i2sOut, 0); // connect the cab filter to the output.
AudioConnection patch5(cabFilter, 0, i2sOut, 0); // connect the cab filter to the output.
AudioConnection patch5b(cabFilter, 0, i2sOut, 1); // connect the cab filter to the output.
void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
delay(5); // wait a few ms to make sure the GTA Pro is fully powered up
AudioMemory(48);
AudioMemory(48); // Provide an arbitrarily large number of audio buffers (48 blocks) for the effects (delays use a lot more than others)
// If the codec was already powered up (due to reboot) power itd own first
// If the codec was already powered up (due to reboot) power it down first
codecControl.disable();
delay(100);
codecControl.enable();
@ -73,4 +89,3 @@ void loop() {
// The audio flows automatically through the Teensy Audio Library
}

@ -1,106 +0,0 @@
/*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board.
*
* The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary
*
* This demo will provide an audio passthrough, as well as exercise the
* MIDI interface.
*
*/
#include <Wire.h>
#include <Audio.h>
#include <MIDI.h>
#include "BALibrary.h"
MIDI_CREATE_DEFAULT_INSTANCE();
using namespace midi;
using namespace BALibrary;
AudioInputI2S i2sIn;
AudioOutputI2S i2sOut;
// Audio Thru Connection
AudioConnection patch0(i2sIn,0, i2sOut, 0);
AudioConnection patch1(i2sIn,1, i2sOut, 1);
BAAudioControlWM8731 codecControl;
BAGpio gpio; // access to User LED
unsigned long t=0;
void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(57600);
delay(5);
while (!Serial) { yield(); }
// If the codec was already powered up (due to reboot) power itd own first
codecControl.disable();
delay(100);
AudioMemory(24);
Serial.println("Enabling codec...\n");
codecControl.enable();
delay(100);
}
void loop() {
///////////////////////////////////////////////////////////////////////
// MIDI TESTING
// Connect a loopback cable between the MIDI IN and MIDI OUT on the
// GTA Pro. This test code will periodically send MIDI events which
// will loop back and get printed in the Serial Monitor.
///////////////////////////////////////////////////////////////////////
DataByte note, velocity, channel, d1, d2;
// Send MIDI OUT
int cc, val=0xA, channelSend = 1;
for (cc=32; cc<40; cc++) {
MIDI.sendControlChange(cc, val, channelSend); val++; channelSend++;
delay(100);
MIDI.sendNoteOn(10, 100, channelSend);
delay(100);
}
if (MIDI.read()) { // Is there a MIDI message incoming ?
MidiType type = MIDI.getType();
Serial.println(String("MIDI IS WORKING!!!"));
switch (type) {
case NoteOn:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
if (velocity > 0) {
Serial.println(String("Note On: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
} else {
Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
}
break;
case NoteOff:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
break;
default:
d1 = MIDI.getData1();
d2 = MIDI.getData2();
Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
}
t = millis();
}
if (millis() - t > 10000) {
t += 10000;
Serial.println("(no MIDI activity, check cables)");
}
// Toggle the USR LED state
gpio.toggleLed();
}

@ -1,209 +0,0 @@
/*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board.
*
* The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary
*
* This demo will provide an audio passthrough, as well as exercise the
* MIDI interface.
*
* It will also peform a sweep of SPI MEM0.
*
* NOTE: SPI MEM0 can be used by a Teensy 3.1/3.2/3.5/3.6.
* pins.
*
*/
#include <Wire.h>
#include <Audio.h>
#include <MIDI.h>
#include "BALibrary.h"
MIDI_CREATE_DEFAULT_INSTANCE();
using namespace midi;
using namespace BALibrary;
AudioInputI2S i2sIn;
AudioOutputI2S i2sOut;
// Audio Thru Connection
AudioConnection patch0(i2sIn,0, i2sOut, 0);
AudioConnection patch1(i2sIn,1, i2sOut, 1);
BAAudioControlWM8731 codecControl;
BAGpio gpio; // access to User LED
BASpiMemory spiMem0(SpiDeviceId::SPI_DEVICE0);
unsigned long t=0;
// SPI stuff
unsigned spiAddress0 = 0;
uint16_t spiData0 = 0xABCD;
int spiErrorCount0 = 0;
constexpr int mask0 = 0x5555;
constexpr int mask1 = 0xaaaa;
int maskPhase = 0;
int loopPhase = 0;
void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(57600);
while (!Serial) { yield(); }
delay(5);
SPI_MEM0_1M(); // Set the Spi memory size to 1Mbit
// If the codec was already powered up (due to reboot) power itd own first
codecControl.disable();
delay(100);
AudioMemory(24);
Serial.println("Sketch: Enabling codec...\n");
codecControl.enable();
delay(100);
Serial.println("Enabling SPI");
spiMem0.begin();
}
int calcData(int spiAddress, int loopPhase, int maskPhase)
{
int data;
int phase = ((loopPhase << 1) + maskPhase) & 0x3;
switch(phase)
{
case 0 :
data = spiAddress ^ mask0;
break;
case 1:
data = spiAddress ^ mask1;
break;
case 2:
data = ~spiAddress ^ mask0;
break;
case 3:
data = ~spiAddress ^ mask1;
}
return (data & 0xffff);
}
void loop() {
//////////////////////////////////////////////////////////////////
// Write test data to the SPI Memory 0
//////////////////////////////////////////////////////////////////
maskPhase = 0;
for (spiAddress0=0; spiAddress0 <= BAHardwareConfig.getSpiMemMaxAddr(0); spiAddress0=spiAddress0+2) {
if ((spiAddress0 % 32768) == 0) {
//Serial.print("Writing to ");
//Serial.println(spiAddress0, HEX);
}
spiData0 = calcData(spiAddress0, loopPhase, maskPhase);
spiMem0.write16(spiAddress0, spiData0);
maskPhase = (maskPhase+1) % 2;
}
Serial.println("SPI0 writing DONE!");
///////////////////////////////////////////////////////////////////
// Read back from the SPI Memory 0
///////////////////////////////////////////////////////////////////
spiErrorCount0 = 0;
spiAddress0 = 0;
maskPhase = 0;
for (spiAddress0=0; spiAddress0 <= BAHardwareConfig.getSpiMemMaxAddr(0); spiAddress0=spiAddress0+2) {
if ((spiAddress0 % 32768) == 0) {
// Serial.print("Reading ");
// Serial.print(spiAddress0, HEX);
}
spiData0 = calcData(spiAddress0, loopPhase, maskPhase);
int data = spiMem0.read16(spiAddress0);
if (data != spiData0) {
spiErrorCount0++;
Serial.println("");
Serial.print("ERROR MEM0: (expected) (actual):");
Serial.print(spiData0, HEX); Serial.print(":");
Serial.print(data, HEX);
delay(100);
}
maskPhase = (maskPhase+1) % 2;
if ((spiAddress0 % 32768) == 0) {
// Serial.print(", data = ");
// Serial.println(data, HEX);
// Serial.println(String(" loopPhase: ") + loopPhase + String(" maskPhase: ") + maskPhase);
}
// Break out of test once the error count reaches 10
if (spiErrorCount0 > 10) { break; }
}
if (spiErrorCount0 == 0) { Serial.println("SPI0 TEST PASSED!!!"); }
loopPhase = (loopPhase+1) % 2;
///////////////////////////////////////////////////////////////////////
// MIDI TESTING
// Connect a loopback cable between the MIDI IN and MIDI OUT on the
// GTA Pro. This test code will periodically send MIDI events which
// will loop back and get printed in the Serial Monitor.
///////////////////////////////////////////////////////////////////////
DataByte note, velocity, channel, d1, d2;
// Send MIDI OUT
int cc, val=0xA, channelSend = 1;
for (cc=32; cc<40; cc++) {
MIDI.sendControlChange(cc, val, channelSend); val++; channelSend++;
delay(100);
MIDI.sendNoteOn(10, 100, channelSend);
delay(100);
}
if (MIDI.read()) { // Is there a MIDI message incoming ?
MidiType type = MIDI.getType();
Serial.println(String("MIDI IS WORKING!!!"));
switch (type) {
case NoteOn:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
if (velocity > 0) {
Serial.println(String("Note On: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
} else {
Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
}
break;
case NoteOff:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
break;
default:
d1 = MIDI.getData1();
d2 = MIDI.getData2();
Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
}
t = millis();
}
if (millis() - t > 10000) {
t += 10000;
Serial.println("(no MIDI activity, check cables)");
}
// Toggle the USR LED state
gpio.toggleLed();
}

@ -1,271 +0,0 @@
/*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board.
*
* The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary
*
* This demo will provide an audio passthrough, as well as exercise the
* MIDI interface.
*
* It will also peform a sweep of SPI MEM0 and MEM1.
*
* NOTE: SPI MEM0 can be used by a Teensy 3.1/3.2/3.5/3.6. SPI MEM1
* can only be used by a Teensy 3.5/3.6 since it is mapped to the extended
* pins.
*
*/
#include <Wire.h>
#include <Audio.h>
#include <MIDI.h>
#include "BALibrary.h"
MIDI_CREATE_DEFAULT_INSTANCE();
using namespace midi;
using namespace BALibrary;
AudioInputI2S i2sIn;
AudioOutputI2S i2sOut;
// Audio Thru Connection
AudioConnection patch0(i2sIn,0, i2sOut, 0);
AudioConnection patch1(i2sIn,1, i2sOut, 1);
BAAudioControlWM8731 codecControl;
BAGpio gpio; // access to User LED
BASpiMemory spiMem0(SpiDeviceId::SPI_DEVICE0);
BASpiMemory spiMem1(SpiDeviceId::SPI_DEVICE1);
unsigned long t=0;
// SPI stuff
int spiAddress0 = 0;
uint16_t spiData0 = 0xABCD;
int spiErrorCount0 = 0;
int spiAddress1 = 0;
uint16_t spiData1 = 0xDCBA;
int spiErrorCount1 = 0;
constexpr int mask0 = 0x5555;
constexpr int mask1 = 0xaaaa;
int maskPhase = 0;
int loopPhase = 0;
void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(57600);
while (!Serial) { yield(); }
delay(5);
// Set the SPI memory sizes
SPI_MEM0_1M();
SPI_MEM1_1M();
// If the codec was already powered up (due to reboot) power itd own first
codecControl.disable();
delay(100);
AudioMemory(24);
Serial.println("Sketch: Enabling codec...\n");
codecControl.enable();
delay(100);
Serial.println("Enabling SPI");
spiMem0.begin();
spiMem1.begin();
}
int calcData(int spiAddress, int loopPhase, int maskPhase)
{
int data;
int phase = ((loopPhase << 1) + maskPhase) & 0x3;
switch(phase)
{
case 0 :
data = spiAddress ^ mask0;
break;
case 1:
data = spiAddress ^ mask1;
break;
case 2:
data = ~spiAddress ^ mask0;
break;
case 3:
data = ~spiAddress ^ mask1;
}
return (data & 0xffff);
}
void loop() {
//////////////////////////////////////////////////////////////////
// Write test data to the SPI Memory 0
//////////////////////////////////////////////////////////////////
maskPhase = 0;
for (spiAddress0=0; spiAddress0 <= BAHardwareConfig.getSpiMemMaxAddr(0); spiAddress0=spiAddress0+2) {
if ((spiAddress0 % 32768) == 0) {
//Serial.print("Writing to ");
//Serial.println(spiAddress0, HEX);
}
spiData0 = calcData(spiAddress0, loopPhase, maskPhase);
spiMem0.write16(spiAddress0, spiData0);
maskPhase = (maskPhase+1) % 2;
}
Serial.println("SPI0 writing DONE!");
///////////////////////////////////////////////////////////////////
// Read back from the SPI Memory 0
///////////////////////////////////////////////////////////////////
spiErrorCount0 = 0;
spiAddress0 = 0;
maskPhase = 0;
for (spiAddress0=0; spiAddress0 <= BAHardwareConfig.getSpiMemMaxAddr(0); spiAddress0=spiAddress0+2) {
if ((spiAddress0 % 32768) == 0) {
// Serial.print("Reading ");
// Serial.print(spiAddress0, HEX);
}
spiData0 = calcData(spiAddress0, loopPhase, maskPhase);
int data = spiMem0.read16(spiAddress0);
if (data != spiData0) {
spiErrorCount0++;
Serial.println("");
Serial.print("ERROR MEM0: (expected) (actual):");
Serial.print(spiData0, HEX); Serial.print(":");
Serial.print(data, HEX);
delay(100);
}
maskPhase = (maskPhase+1) % 2;
if ((spiAddress0 % 32768) == 0) {
// Serial.print(", data = ");
// Serial.println(data, HEX);
// Serial.println(String(" loopPhase: ") + loopPhase + String(" maskPhase: ") + maskPhase);
}
// Break out of test once the error count reaches 10
if (spiErrorCount0 > 10) { break; }
}
if (spiErrorCount0 == 0) { Serial.println("SPI0 TEST PASSED!!!"); }
//////////////////////////////////////////////////////////////////
// Write test data to the SPI Memory 1
//////////////////////////////////////////////////////////////////
maskPhase = 0;
for (spiAddress1=0; spiAddress1 <= BAHardwareConfig.getSpiMemMaxAddr(1); spiAddress1+=2) {
if ((spiAddress1 % 32768) == 0) {
//Serial.print("Writing to ");
//Serial.println(spiAddress1, HEX);
}
spiData1 = calcData(spiAddress1, loopPhase, maskPhase);
spiMem1.write16(spiAddress1, spiData1);
maskPhase = (maskPhase+1) % 2;
}
Serial.println("SPI1 writing DONE!");
///////////////////////////////////////////////////////////////////
// Read back from the SPI Memory 1
///////////////////////////////////////////////////////////////////
spiErrorCount1 = 0;
spiAddress1 = 0;
maskPhase = 0;
for (spiAddress1=0; spiAddress1 <= BAHardwareConfig.getSpiMemMaxAddr(1); spiAddress1+=2) {
if ((spiAddress1 % 32768) == 0) {
//Serial.print("Reading ");
//Serial.print(spiAddress1, HEX);
}
spiData1 = calcData(spiAddress1, loopPhase, maskPhase);
uint16_t data = spiMem1.read16(spiAddress1);
if (data != spiData1) {
spiErrorCount1++;
Serial.println("");
Serial.print("ERROR MEM1: (expected) (actual):");
Serial.print(spiData1, HEX); Serial.print(":");
Serial.println(data, HEX);
delay(100);
}
maskPhase = (maskPhase+1) % 2;
if ((spiAddress1 % 32768) == 0) {
//Serial.print(", data = ");
//Serial.println(data, HEX);
}
// Break out of test once the error count reaches 10
if (spiErrorCount1 > 10) { break; }
}
if (spiErrorCount1 == 0) { Serial.println("SPI1 TEST PASSED!!!"); }
loopPhase = (loopPhase+1) % 2;
///////////////////////////////////////////////////////////////////////
// MIDI TESTING
// Connect a loopback cable between the MIDI IN and MIDI OUT on the
// GTA Pro. This test code will periodically send MIDI events which
// will loop back and get printed in the Serial Monitor.
///////////////////////////////////////////////////////////////////////
DataByte note, velocity, channel, d1, d2;
// Send MIDI OUT
int cc, val=0xA, channelSend = 1;
for (cc=32; cc<40; cc++) {
MIDI.sendControlChange(cc, val, channelSend); val++; channelSend++;
delay(100);
MIDI.sendNoteOn(10, 100, channelSend);
delay(100);
}
if (MIDI.read()) { // Is there a MIDI message incoming ?
MidiType type = MIDI.getType();
Serial.println(String("MIDI IS WORKING!!!"));
switch (type) {
case NoteOn:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
if (velocity > 0) {
Serial.println(String("Note On: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
} else {
Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
}
break;
case NoteOff:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
break;
default:
d1 = MIDI.getData1();
d2 = MIDI.getData2();
Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
}
t = millis();
}
if (millis() - t > 10000) {
t += 10000;
Serial.println("(no MIDI activity, check cables)");
}
// Toggle the USR LED state
gpio.toggleLed();
}

@ -15,11 +15,14 @@
* Even if you don't control the guitar effect with USB MIDI, you must set
* the Arduino IDE USB-Type under Tools to "Serial + MIDI"
*/
#include <MIDI.h>
#include <Audio.h>
#include <MIDI.h>
#include "BALibrary.h"
#include "BAEffects.h"
using namespace midi;
MIDI_CREATE_DEFAULT_INSTANCE();
using namespace BAEffects;
using namespace BALibrary;
@ -31,6 +34,7 @@ BAAudioControlWM8731 codec;
// YOU MUST USE TEENSYDUINO 1.41 or greater
// YOU MUST COMPILE THIS DEMO USING Serial + Midi
//#define USE_CAB_FILTER // uncomment this line to add a simple low-pass filter to simulate a cabinet if you are going straight to headphones
//#define USE_EXT // uncomment this line to use External MEM0
#define MIDI_DEBUG // uncomment to see raw MIDI info in terminal
@ -53,18 +57,45 @@ AudioEffectAnalogDelay analogDelay(200.0f); // max delay of 200 ms or internal.
// If you use external SPI memory you can get up to 1485.0f ms of delay!
#endif
#if defined(USE_CAB_FILTER)
AudioFilterBiquad cabFilter; // We'll want something to cut out the highs and smooth the tone, just like a guitar cab.
#endif
// Simply connect the input to the delay, and the output
// to both i2s channels
AudioConnection input(i2sIn,0, analogDelay,0);
#if defined(USE_CAB_FILTER)
AudioConnection delayOut(analogDelay, 0, cabFilter, 0);
AudioConnection leftOut(cabFilter,0, i2sOut, 0);
AudioConnection rightOut(cabFilter,0, i2sOut, 1);
#else
AudioConnection leftOut(analogDelay,0, i2sOut, 0);
AudioConnection rightOut(analogDelay,0, i2sOut, 1);
#endif
elapsedMillis timer;
int loopCount = 0;
void OnControlChange(byte channel, byte control, byte value) {
analogDelay.processMidi(channel-1, control, value);
#ifdef MIDI_DEBUG
Serial.print("Control Change, ch=");
Serial.print(channel, DEC);
Serial.print(", control=");
Serial.print(control, DEC);
Serial.print(", value=");
Serial.print(value, DEC);
Serial.println();
#endif
}
void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
#ifdef USE_EXT
SPI_MEM0_4M();
//SPI_MEM0_1M(); // use this line instead of you have the older 1Mbit memory
#endif
delay(100);
Serial.begin(57600); // Start the serial port
@ -82,7 +113,6 @@ void setup() {
// If using external memory request request memory from the manager
// for the slot
#ifdef USE_EXT
SPI_MEM0_1M();
Serial.println("Using EXTERNAL memory");
// We have to request memory be allocated to our slot.
externalSram.requestMemory(&delaySlot, 500.0f, MemSelect::MEM0, true);
@ -90,6 +120,12 @@ void setup() {
Serial.println("Using INTERNAL memory");
#endif
// Setup MIDI
MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.setHandleControlChange(OnControlChange);
usbMIDI.setHandleControlChange(OnControlChange);
// Configure which MIDI CC's will control the effect parameters
analogDelay.mapMidiControl(AudioEffectAnalogDelay::BYPASS,16);
analogDelay.mapMidiControl(AudioEffectAnalogDelay::DELAY,20);
@ -116,53 +152,25 @@ void setup() {
//analogDelay.setFilter(AudioEffectAnalogDelay::Filter::WARM); // A warm filter with a smooth frequency rolloff above 2Khz
//analogDelay.setFilter(AudioEffectAnalogDelay::Filter::DARK); // A very dark filter, with a sharp rolloff above 1Khz
// Setup 2-stages of LPF, cutoff 4500 Hz, Q-factor 0.7071 (a 'normal' Q-factor)
#if defined(USE_CAB_FILTER)
// Guitar cabinet: Setup 2-stages of LPF, cutoff 4500 Hz, Q-factor 0.7071 (a 'normal' Q-factor)
cabFilter.setLowpass(0, 4500, .7071);
cabFilter.setLowpass(1, 4500, .7071);
}
void OnControlChange(byte channel, byte control, byte value) {
analogDelay.processMidi(channel, control, value);
#ifdef MIDI_DEBUG
Serial.print("Control Change, ch=");
Serial.print(channel, DEC);
Serial.print(", control=");
Serial.print(control, DEC);
Serial.print(", value=");
Serial.print(value, DEC);
Serial.println();
#endif
#endif
}
void loop() {
// usbMIDI.read() needs to be called rapidly from loop(). When
// each MIDI messages arrives, it return true. The message must
// be fully processed before usbMIDI.read() is called again.
if (loopCount % 524288 == 0) {
// usbMIDI.read() needs to be called rapidly from loop().
if (timer > 1000) {
timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print("% ");
Serial.print(" analogDelay: "); Serial.print(analogDelay.processorUsage());
Serial.println("%");
}
loopCount++;
// check for new MIDI from USB
if (usbMIDI.read()) {
// this code entered only if new MIDI received
byte type, channel, data1, data2, cable;
type = usbMIDI.getType(); // which MIDI message, 128-255
channel = usbMIDI.getChannel(); // which MIDI channel, 1-16
data1 = usbMIDI.getData1(); // first data byte of message, 0-127
data2 = usbMIDI.getData2(); // second data byte of message, 0-127
Serial.println(String("Received a MIDI message on channel ") + channel);
if (type == MidiType::ControlChange) {
// if type is 3, it's a CC MIDI Message
// Note: the Arduino MIDI library encodes channels as 1-16 instead
// of 0 to 15 as it should, so we must subtract one.
OnControlChange(channel-1, data1, data2);
}
}
MIDI.read();
usbMIDI.read();
}

@ -28,12 +28,13 @@
using namespace BAEffects;
using namespace BALibrary;
//#define USE_CAB_FILTER // uncomment this line to add a simple low-pass filter to simulate a cabinet if you are going straight to headphones
//#define USE_EXT // uncomment this line to use External MEM0
AudioInputI2S i2sIn;
AudioOutputI2S i2sOut;
BAAudioControlWM8731 codec;
//#define USE_EXT // uncomment this line to use External MEM0
#ifdef USE_EXT
// If using external SPI memory, we will instantiate a SRAM
// manager and create an external memory slot to use as the memory
@ -53,15 +54,19 @@ AudioEffectAnalogDelay analogDelay(200.0f); // set the max delay of 200 ms.
// If you use external SPI memory you can get up to 1485.0f ms of delay!
#endif
#if defined(USE_CAB_FILTER)
AudioFilterBiquad cabFilter; // We'll want something to cut out the highs and smooth the tone, just like a guitar cab.
#endif
// Simply connect the input to the delay, and the output
// to both i2s channels
AudioConnection input(i2sIn,0, analogDelay,0);
#if defined(USE_CAB_FILTER)
AudioConnection delayOut(analogDelay, 0, cabFilter, 0);
AudioConnection leftOut(cabFilter,0, i2sOut, 0);
AudioConnection rightOut(cabFilter,0, i2sOut, 1);
#else
AudioConnection leftOut(analogDelay,0, i2sOut, 0);
AudioConnection rightOut(analogDelay,0, i2sOut, 1);
#endif
//////////////////////////////////////////
// SETUP PHYSICAL CONTROLS
@ -83,7 +88,7 @@ constexpr bool potSwapDirection = true;
// Blackaddr Audio Expansion Board.
BAPhysicalControls controls(BA_EXPAND_NUM_SW, BA_EXPAND_NUM_POT, BA_EXPAND_NUM_ENC, BA_EXPAND_NUM_LED);
int loopCount = 0;
elapsedMillis timer;
unsigned filterIndex = 0; // variable for storing which analog filter we're currently using.
constexpr unsigned MAX_HEADPHONE_VOL = 10;
unsigned headphoneVolume = 8; // control headphone volume from 0 to 10.
@ -92,13 +97,21 @@ unsigned headphoneVolume = 8; // control headphone volume from 0 to 10.
int bypassHandle, filterHandle, delayHandle, feedbackHandle, mixHandle, led1Handle, led2Handle; // Handles for the various controls
void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
#ifdef USE_EXT
SPI_MEM0_4M();
//SPI_MEM0_1M(); // use this line instead of you have the older 1Mbit memory
#endif
delay(100); // wait a bit for serial to be available
Serial.begin(57600); // Start the serial port
delay(100);
// Configure the hardware
SPI_MEM0_1M();
// Setup the controls. The return value is the handle to use when checking for control changes, etc.
// pushbuttons
bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control
@ -137,6 +150,7 @@ void setup() {
// Set some default values.
// These can be changed using the controls on the Blackaddr Audio Expansion Board
analogDelay.bypass(false);
controls.setOutput(led1Handle, !analogDelay.isBypass()); // Set the LED when NOT bypassed
analogDelay.mix(0.5f);
analogDelay.feedback(0.0f);
@ -147,9 +161,11 @@ void setup() {
//analogDelay.setFilter(AudioEffectAnalogDelay::Filter::WARM); // A warm filter with a smooth frequency rolloff above 2Khz
//analogDelay.setFilter(AudioEffectAnalogDelay::Filter::DARK); // A very dark filter, with a sharp rolloff above 1Khz
#if defined(USE_CAB_FILTER)
// Guitar cabinet: Setup 2-stages of LPF, cutoff 4500 Hz, Q-factor 0.7071 (a 'normal' Q-factor)
cabFilter.setLowpass(0, 4500, .7071);
cabFilter.setLowpass(1, 4500, .7071);
#endif
}
void loop() {
@ -213,14 +229,14 @@ void loop() {
}
}
// Use the loopCounter to roughly measure human timescales. Every few seconds, print the CPU usage
// to the serial port. About 500,000 loops!
if (loopCount % 524288 == 0) {
delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected.
if (timer > 1000) {
timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print("% ");
Serial.print(" analogDelay: "); Serial.print(analogDelay.processorUsage());
Serial.println("%");
}
loopCount++;
}

@ -49,17 +49,21 @@ AudioConnection outputRight(delayMixer, 0, i2sOut, 1);
void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
SPI_MEM0_4M();
//SPI_MEM0_1M(); // use this line instead of you have the older 1Mbit memory
Serial.begin(57600);
while(!Serial) { yield(); }
delay(200);
AudioMemory(64);
delay(500);
Serial.println(String("Starting...\n"));
delay(100);
SPI_MEM0_1M(); // set the SPI MEM0 memory size
// SPI_MEM1_1M(); // set the MEM1 memory aize
Serial.println("Enabling codec...\n");
codecControl.enable();
delay(100);

@ -11,32 +11,29 @@
* the BAMidiTester to control the effect but it's best to use external MIDI footswitch
* or the Blackaddr Audio Expansion Control Board.
*
* Use must set the Arduino IDE USB-Type to "Serial + MIDI" in the Tools menu.
* User must set the Arduino IDE USB-Type to "Serial + MIDI" in the Tools menu.
*
* Afters startup, the effect will spend about 5 seconds clearing the audio delay buffer to prevent
* any startup pops or clicks from propagating.
*
*/
#include <Wire.h>
#include <Audio.h>
#include <MIDI.h>
#include <SPI.h>
#include "BALibrary.h"
#include "BAEffects.h"
#include <midi_UsbTransport.h>
static const unsigned sUsbTransportBufferSize = 16;
typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;
UsbTransport sUsbTransport;
MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, uMIDI);
/// IMPORTANT /////
// YOU MUST USE TEENSYDUINO 1.41 or greater
// YOU MUST COMPILE THIS DEMO USING Serial + Midi
//#define USE_CAB_FILTER // uncomment this line to add a simple low-pass filter to simulate a cabinet if you are going straight to headphones
#define MIDI_DEBUG
MIDI_CREATE_DEFAULT_INSTANCE();
using namespace midi;
MIDI_CREATE_DEFAULT_INSTANCE();
using namespace BAEffects;
#define MIDI_DEBUG
using namespace BALibrary;
AudioInputI2S i2sIn;
@ -54,9 +51,12 @@ AudioEffectSOS sos(&delaySlot);
AudioEffectDelay delayModule; // we'll add a little slapback echo
AudioMixer4 gainModule; // This will be used simply to reduce the gain before the reverb
AudioEffectReverb reverb; // Add a bit of 'verb to our tone
AudioFilterBiquad cabFilter; // We'll want something to cut out the highs and smooth the tone, just like a guitar cab.
AudioMixer4 mixer;
#if defined(USE_CAB_FILTER)
AudioFilterBiquad cabFilter; // We'll want something to cut out the highs and smooth the tone, just like a guitar cab.
#endif
// Connect the input
AudioConnection inputToSos(i2sIn, 0, sos, 0);
AudioConnection inputToSolo(i2sIn, 0, delayModule, 0);
@ -69,13 +69,17 @@ AudioConnection inputToReverb(gainModule, 0, reverb, 0);
AudioConnection mixer0input(i2sIn, 0, mixer, 0); // SOLO Dry Channel
AudioConnection mixer1input(reverb, 0, mixer, 1); // SOLO Wet Channel
AudioConnection mixer2input(sos, 0, mixer, 2); // SOS Channel
AudioConnection inputToCab(mixer, 0, cabFilter, 0);
// CODEC Outputs
#if defined(USE_CAB_FILTER)
AudioConnection inputToCab(mixer, 0, cabFilter, 0);
AudioConnection outputLeft(cabFilter, 0, i2sOut, 0);
AudioConnection outputRight(cabFilter, 0, i2sOut, 1);
#else
AudioConnection outputLeft(mixer, 0, i2sOut, 0);
AudioConnection outputRight(mixer, 0, i2sOut, 1);
#endif
int loopCount = 0;
elapsedMillis timer;
void OnControlChange(byte channel, byte control, byte value) {
sos.processMidi(channel-1, control, value);
@ -92,7 +96,14 @@ void OnControlChange(byte channel, byte control, byte value) {
void setup() {
delay(100);
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
SPI_MEM0_4M();
//SPI_MEM0_1M(); // use this line instead of you have the older 1Mbit memory
delay(100);
Serial.begin(57600); // Start the serial port
// Disable the codec first
@ -115,20 +126,19 @@ delay(100);
// Setup MIDI
MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.setHandleControlChange(OnControlChange);
uMIDI.begin(MIDI_CHANNEL_OMNI);
uMIDI.setHandleControlChange(OnControlChange);
usbMIDI.setHandleControlChange(OnControlChange);
// Configure the LED to indicate the gate status
sos.setGateLedGpio(USR_LED_ID);
// Configure which MIDI CC's will control the effect parameters
sos.mapMidiControl(AudioEffectSOS::BYPASS,16);
sos.mapMidiControl(AudioEffectSOS::CLEAR_FEEDBACK_TRIGGER,22);
sos.mapMidiControl(AudioEffectSOS::GATE_TRIGGER,23);
//sos.mapMidiControl(AudioEffectSOS::BYPASS,16);
sos.mapMidiControl(AudioEffectSOS::GATE_TRIGGER,16);
sos.mapMidiControl(AudioEffectSOS::CLEAR_FEEDBACK_TRIGGER,17);
sos.mapMidiControl(AudioEffectSOS::GATE_OPEN_TIME,20);
sos.mapMidiControl(AudioEffectSOS::GATE_CLOSE_TIME,21);
sos.mapMidiControl(AudioEffectSOS::FEEDBACK,24);
sos.mapMidiControl(AudioEffectSOS::VOLUME,17);
sos.mapMidiControl(AudioEffectSOS::VOLUME,22);
//sos.mapMidiControl(AudioEffectSOS::FEEDBACK,24);
// Besure to enable the delay. When disabled, audio is is completely blocked
// to minimize resources to nearly zero.
@ -146,51 +156,34 @@ delay(100);
gainModule.gain(0, 0.25); // the reverb unit clips easily if the input is too high
delayModule.delay(0, 50.0f); // 50 ms slapback delay
#if defined(USE_CAB_FILTER)
// Setup 2-stages of LPF, cutoff 4500 Hz, Q-factor 0.7071 (a 'normal' Q-factor)
cabFilter.setLowpass(0, 4500, .7071);
cabFilter.setLowpass(1, 4500, .7071);
#endif
// Setup the Mixer
mixer.gain(0, 0.5f); // SOLO Dry gain
mixer.gain(1, 0.5f); // SOLO Wet gain
mixer.gain(1, 1.0f); // SOS gain
delay(1000);
sos.clear();
}
void loop() {
// usbMIDI.read() needs to be called rapidly from loop(). When
// each MIDI messages arrives, it return true. The message must
// be fully processed before usbMIDI.read() is called again.
// usbMIDI.read() needs to be called rapidly from loop().
if (loopCount % 524288 == 0) {
if (timer > 1000) {
timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print("% ");
Serial.print(" sos: "); Serial.print(sos.processorUsage());
Serial.print(" SOS: "); Serial.print(sos.processorUsage());
Serial.println("%");
}
loopCount++;
MIDI.read();
uMIDI.read();
// // check for new MIDI from USB
// if (usbMIDI.read()) {
// // this code entered only if new MIDI received
// byte type, channel, data1, data2, cable;
// type = usbMIDI.getType(); // which MIDI message, 128-255
// channel = usbMIDI.getChannel(); // which MIDI channel, 1-16
// data1 = usbMIDI.getData1(); // first data byte of message, 0-127
// data2 = usbMIDI.getData2(); // second data byte of message, 0-127
// Serial.println(String("Received a MIDI message on channel ") + channel);
//
// if (type == MidiType::ControlChange) {
// // if type is 3, it's a CC MIDI Message
// // Note: the Arduino MIDI library encodes channels as 1-16 instead
// // of 0 to 15 as it should, so we must subtract one.
// OnControlChange(channel-1, data1, data2);
// }
// }
usbMIDI.read();
}

@ -13,6 +13,9 @@
*
* The pots control the feedback, as well as the gate opening and close times.
*
* Afters startup, the effect will spend about 5 seconds clearing the audio delay buffer to prevent
* any startup pops or clicks from propagating.
*
* POT1 - Gate open time. Middle position (detent) is about 2100 ms.
* POT2 - gate close time. Middle position (detent) is about 2100 ms.
* POT3 - Effect volume. Controls the volume of the SOS effect separate from the normal volume
@ -20,12 +23,15 @@
* SW2 - Push this button to clear out the sound circulating in the delay.
*
*/
#include <Audio.h>
#include "BALibrary.h"
#include "BAEffects.h"
using namespace BAEffects;
using namespace BALibrary;
//#define USE_CAB_FILTER // uncomment this line to add a simple low-pass filter to simulate a cabinet if you are going straight to headphones
AudioInputI2S i2sIn;
AudioOutputI2S i2sOut;
BAAudioControlWM8731 codec;
@ -41,9 +47,12 @@ AudioEffectSOS sos(&delaySlot);
AudioEffectDelay delayModule; // we'll add a little slapback echo
AudioMixer4 gainModule; // This will be used simply to reduce the gain before the reverb
AudioEffectReverb reverb; // Add a bit of 'verb to our tone
AudioFilterBiquad cabFilter; // We'll want something to cut out the highs and smooth the tone, just like a guitar cab.
AudioMixer4 mixer;
#if defined(USE_CAB_FILTER)
AudioFilterBiquad cabFilter; // We'll want something to cut out the highs and smooth the tone, just like a guitar cab.
#endif
// Connect the input
AudioConnection inputToSos(i2sIn, 0, sos, 0);
AudioConnection inputToSolo(i2sIn, 0, delayModule, 0);
@ -56,11 +65,15 @@ AudioConnection inputToReverb(gainModule, 0, reverb, 0);
AudioConnection mixer0input(i2sIn, 0, mixer, 0); // SOLO Dry Channel
AudioConnection mixer1input(reverb, 0, mixer, 1); // SOLO Wet Channel
AudioConnection mixer2input(sos, 0, mixer, 2); // SOS Channel
AudioConnection inputToCab(mixer, 0, cabFilter, 0);
// CODEC Outputs
#if defined(USE_CAB_FILTER)
AudioConnection inputToCab(mixer, 0, cabFilter, 0);
AudioConnection outputLeft(cabFilter, 0, i2sOut, 0);
AudioConnection outputRight(cabFilter, 0, i2sOut, 1);
#else
AudioConnection outputLeft(mixer, 0, i2sOut, 0);
AudioConnection outputRight(mixer, 0, i2sOut, 1);
#endif
//////////////////////////////////////////
// SETUP PHYSICAL CONTROLS
@ -82,7 +95,7 @@ constexpr bool potSwapDirection = true;
// Blackaddr Audio Expansion Board.
BAPhysicalControls controls(BA_EXPAND_NUM_SW, BA_EXPAND_NUM_POT, BA_EXPAND_NUM_ENC, BA_EXPAND_NUM_LED);
int loopCount = 0;
elapsedMillis timer;
constexpr unsigned MAX_HEADPHONE_VOL = 10;
unsigned headphoneVolume = MAX_HEADPHONE_VOL; // control headphone volume from 0 to 10.
constexpr float MAX_GATE_TIME_MS = 4000.0f; // set maximum gate time of 4 seconds.
@ -93,11 +106,17 @@ int gateHandle, clearHandle, openHandle, closeHandle, volumeHandle, led1Handle,
void setup() {
delay(100);
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
SPI_MEM0_4M();
//SPI_MEM0_1M(); // use this line instead of you have the older 1Mbit memory
delay(100);
delay(100); // wait a bit for serial to be available
Serial.begin(57600); // Start the serial port
delay(100); // wait a bit for serial to be available
BAHardwareConfig.set(MemSelect::MEM0, SPI_MEMORY_1M);
// Setup the controls. The return value is the handle to use when checking for control changes, etc.
// pushbuttons
@ -115,9 +134,6 @@ delay(100);
codec.disable();
AudioMemory(128);
TGA_PRO_EXPAND_REV2(); // Set the expansion board revision
SPI_MEM0_1M(); // set the Spi memory size
// Enable the codec
Serial.println("Enabling codec...\n");
codec.enable();
@ -130,7 +146,7 @@ delay(100);
// by BAPhysicalControls
sos.setGateLedGpio(BA_EXPAND_LED1_PIN);
// Besure to enable the delay. When disabled, audio is is completely blocked
// Besure to enable the SOS. When disabled, audio is is completely blocked
// to minimize resources to nearly zero.
sos.enable();
@ -146,19 +162,22 @@ delay(100);
gainModule.gain(0, 0.25); // the reverb unit clips easily if the input is too high
delayModule.delay(0, 50.0f); // 50 ms slapback delay
#if defined(USE_CAB_FILTER)
// Setup 2-stages of LPF, cutoff 4500 Hz, Q-factor 0.7071 (a 'normal' Q-factor)
cabFilter.setLowpass(0, 4500, .7071);
cabFilter.setLowpass(1, 4500, .7071);
#endif
// Setup the Mixer
mixer.gain(0, 0.5f); // SOLO Dry gain
mixer.gain(1, 0.5f); // SOLO Wet gain
mixer.gain(1, 1.0f); // SOS gain
delay(1000);
sos.clear();
}
void loop() {
float potValue;
@ -215,12 +234,14 @@ void loop() {
}
}
}
if (loopCount % 524288 == 0) {
delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected.
if (timer > 1000) {
timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print("% ");
Serial.print(" sos: "); Serial.print(sos.processorUsage());
Serial.print(" SOS: "); Serial.print(sos.processorUsage());
Serial.println("%");
}
loopCount++;
}

@ -20,6 +20,8 @@
#include "BAEffects.h"
using namespace midi;
MIDI_CREATE_DEFAULT_INSTANCE();
using namespace BAEffects;
using namespace BALibrary;
@ -31,22 +33,46 @@ BAAudioControlWM8731 codec;
// YOU MUST USE TEENSYDUINO 1.41 or greater
// YOU MUST COMPILE THIS DEMO USING Serial + Midi
//#define USE_CAB_FILTER // uncomment this line to add a simple low-pass filter to simulate a cabinet if you are going straight to headphones
#define MIDI_DEBUG // uncomment to see raw MIDI info in terminal
AudioEffectTremolo tremolo;
#if defined(USE_CAB_FILTER)
AudioFilterBiquad cabFilter; // We'll want something to cut out the highs and smooth the tone, just like a guitar cab.
#endif
// Simply connect the input to the tremolo, and the output
// to both i2s channels
AudioConnection input(i2sIn,0, tremolo,0);
AudioConnection tremoloOut(tremolo, 0, cabFilter, 0);
#if defined(USE_CAB_FILTER)
AudioConnection tremOut(tremolo, 0, cabFilter, 0);
AudioConnection leftOut(cabFilter,0, i2sOut, 0);
AudioConnection rightOut(cabFilter,0, i2sOut, 1);
#else
AudioConnection leftOut(tremolo,0, i2sOut, 0);
AudioConnection rightOut(tremolo,0, i2sOut, 1);
#endif
elapsedMillis timer;
int loopCount = 0;
void OnControlChange(byte channel, byte control, byte value) {
tremolo.processMidi(channel-1, control, value);
#ifdef MIDI_DEBUG
Serial.print("Control Change, ch=");
Serial.print(channel, DEC);
Serial.print(", control=");
Serial.print(control, DEC);
Serial.print(", value=");
Serial.print(value, DEC);
Serial.println();
#endif
}
void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
delay(100);
Serial.begin(57600); // Start the serial port
@ -61,6 +87,11 @@ void setup() {
codec.enable();
delay(100);
// Setup MIDI
MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.setHandleControlChange(OnControlChange);
usbMIDI.setHandleControlChange(OnControlChange);
// Configure which MIDI CC's will control the effect parameters
tremolo.mapMidiControl(AudioEffectTremolo::BYPASS,16);
tremolo.mapMidiControl(AudioEffectTremolo::RATE,20);
@ -78,53 +109,25 @@ void setup() {
tremolo.bypass(false);
tremolo.depth(0.5f); // 50% depth modulation
// Setup 2-stages of LPF, cutoff 4500 Hz, Q-factor 0.7071 (a 'normal' Q-factor)
#if defined(USE_CAB_FILTER)
// Guitar cabinet: Setup 2-stages of LPF, cutoff 4500 Hz, Q-factor 0.7071 (a 'normal' Q-factor)
cabFilter.setLowpass(0, 4500, .7071);
cabFilter.setLowpass(1, 4500, .7071);
}
void OnControlChange(byte channel, byte control, byte value) {
tremolo.processMidi(channel, control, value);
#ifdef MIDI_DEBUG
Serial.print("Control Change, ch=");
Serial.print(channel, DEC);
Serial.print(", control=");
Serial.print(control, DEC);
Serial.print(", value=");
Serial.print(value, DEC);
Serial.println();
#endif
#endif
}
void loop() {
// usbMIDI.read() needs to be called rapidly from loop(). When
// each MIDI messages arrives, it return true. The message must
// be fully processed before usbMIDI.read() is called again.
// usbMIDI.read() needs to be called rapidly from loop().
if (loopCount % 524288 == 0) {
if (timer > 1000) {
timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print("% ");
Serial.print(" tremolo: "); Serial.print(tremolo.processorUsage());
Serial.println("%");
}
loopCount++;
// check for new MIDI from USB
if (usbMIDI.read()) {
// this code entered only if new MIDI received
byte type, channel, data1, data2, cable;
type = usbMIDI.getType(); // which MIDI message, 128-255
channel = usbMIDI.getChannel(); // which MIDI channel, 1-16
data1 = usbMIDI.getData1(); // first data byte of message, 0-127
data2 = usbMIDI.getData2(); // second data byte of message, 0-127
Serial.println(String("Received a MIDI message on channel ") + channel);
if (type == MidiType::ControlChange) {
// if type is 3, it's a CC MIDI Message
// Note: the Arduino MIDI library encodes channels as 1-16 instead
// of 0 to 15 as it should, so we must subtract one.
OnControlChange(channel-1, data1, data2);
}
}
MIDI.read();
usbMIDI.read();
}

@ -8,11 +8,12 @@
* This example demonstrates teh BAAudioEffectsTremolo effect. It can
* be controlled using the Blackaddr Audio "Expansion Control Board".
*
* POT1 (left) controls amount of delay
* POT2 (right) controls amount of feedback
* POT3 (center) controls the wet/dry mix
* POT1 (left) controls the tremolo RATE
* POT2 (right) controls the tremolo DEPTH
* POT3 (center) controls the output VOLUME
* SW1 will enable/bypass the audio effect. LED1 will be on when effect is enabled.
* SW2 will cycle through the 3 pre-programmed analog filters. LED2 will be on when SW2 is pressed.
* SW2 will cycle through the 3 pre-programmed waveforms. NOTE: any waveform other than Sine will cause
* pops/clicks since the waveforms are not bandlimited.
*
*
* Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease
@ -25,20 +26,27 @@
using namespace BAEffects;
using namespace BALibrary;
//#define USE_CAB_FILTER // uncomment this line to add a simple low-pass filter to simulate a cabinet if you are going straight to headphones
AudioInputI2S i2sIn;
AudioOutputI2S i2sOut;
BAAudioControlWM8731 codec;
AudioEffectTremolo tremolo;
#if defined(USE_CAB_FILTER)
AudioFilterBiquad cabFilter; // We'll want something to cut out the highs and smooth the tone, just like a guitar cab.
#endif
// Simply connect the input to the delay, and the output
// to both i2s channels
AudioConnection input(i2sIn,0, tremolo,0);
AudioConnection delayOut(tremolo, 0, cabFilter, 0);
#if defined(USE_CAB_FILTER)
AudioConnection tremOut(tremolo, 0, cabFilter, 0);
AudioConnection leftOut(cabFilter,0, i2sOut, 0);
AudioConnection rightOut(cabFilter,0, i2sOut, 1);
#else
AudioConnection leftOut(tremolo,0, i2sOut, 0);
AudioConnection rightOut(tremolo,0, i2sOut, 1);
#endif
//////////////////////////////////////////
@ -61,7 +69,8 @@ constexpr bool potSwapDirection = true;
// Blackaddr Audio Expansion Board.
BAPhysicalControls controls(BA_EXPAND_NUM_SW, BA_EXPAND_NUM_POT, BA_EXPAND_NUM_ENC, BA_EXPAND_NUM_LED);
int loopCount = 0;
elapsedMillis timer;
unsigned waveformIndex = 0; // variable for storing which analog filter we're currently using.
constexpr unsigned MAX_HEADPHONE_VOL = 10;
unsigned headphoneVolume = 8; // control headphone volume from 0 to 10.
@ -70,12 +79,14 @@ unsigned headphoneVolume = 8; // control headphone volume from 0 to 10.
int bypassHandle, waveformHandle, rateHandle, depthHandle, volumeHandle, led1Handle, led2Handle; // Handles for the various controls
void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
delay(100); // wait a bit for serial to be available
Serial.begin(57600); // Start the serial port
delay(100);
TGA_PRO_EXPAND_REV2(); // Configure the expansion board revision
// Setup the controls. The return value is the handle to use when checking for control changes, etc.
// pushbuttons
bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control
@ -104,6 +115,7 @@ void setup() {
// Set some default values.
// These can be changed using the controls on the Blackaddr Audio Expansion Board
tremolo.bypass(false);
controls.setOutput(led1Handle, !tremolo.isBypass()); // Set the LED when NOT bypassed
tremolo.rate(0.0f);
tremolo.depth(1.0f);
@ -112,9 +124,11 @@ void setup() {
// These are commented out, in this example we'll use SW2 to cycle through the different filters
//tremolo.setWaveform(Waveform::SINE); // The default waveform
#if defined(USE_CAB_FILTER)
// Guitar cabinet: Setup 2-stages of LPF, cutoff 4500 Hz, Q-factor 0.7071 (a 'normal' Q-factor)
cabFilter.setLowpass(0, 4500, .7071);
cabFilter.setLowpass(1, 4500, .7071);
#endif
}
void loop() {
@ -178,15 +192,14 @@ void loop() {
}
}
// Use the loopCounter to roughly measure human timescales. Every few seconds, print the CPU usage
// to the serial port. About 500,000 loops!
//if (loopCount % 524288 == 0) {
if (loopCount % 25000 == 0) {
delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected.
if (timer > 1000) {
timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print("% ");
Serial.print(" tremolo: "); Serial.print(tremolo.processorUsage());
Serial.println("%");
}
loopCount++;
}

@ -8,6 +8,10 @@
* This program can be used to find out the calibration values for each of your POTs
* on the Blackaddr Audio Expansion Control Board.
*
* Normally the default values used in the BALibrary are appropriate for the Expansion
* Control Board, however you an use this program as a reference for calibrating pots
* in a custom design.
*
* USE THE ARDUINO SERIAL MONITOR TO PERFORM THE CALIBRATION
*
* When prompted turn the appropriate POT in the specified direction and
@ -24,8 +28,11 @@ void setup() {
delay(100);
Serial.begin(57600);
delay(500); // long delay to wait for Serial to init
Serial.flush();
TGA_PRO_EXPAND_REV2(); // Set the expansion board revision
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
// put your setup code here, to run once:
Serial.println("Calibrating POT1");

@ -15,6 +15,8 @@
* be useful for frequency detection but is not appropriate for when sound quality is desired as
* the modulation of the filter will result in audible artifacts.
*
* ALLOW THE TEST TO RUN THROUGH SEVERAL CYCLE of toggling the HPF so the CODEC can calibrate correctly.
*
*/
#include <Wire.h>
#include <Audio.h>
@ -39,6 +41,9 @@ AudioConnection patchOutL(rmsModule, 0, i2sOut, 0); // connect the cab filt
AudioConnection patchOutR(rmsModule, 0, i2sOut, 1); // connect the cab filter to the output.
void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
delay(5); // wait a few ms to make sure the GTA Pro is fully powered up
AudioMemory(48);

@ -7,7 +7,6 @@
* - Audio INPUT and OUTPUT JACKS
* - Midi INPUT and Midi OUTPUT jacks
* - MEM0 (if installed)
* - MEM1 (if installed)
* - User LED
*
* This will also test the Expansion Control Board (if installed):
@ -42,9 +41,9 @@
*
*/
//#define RUN_MIDI_TEST // Uncomment this line to run the MIDI test.
//#define RUN_MEMO_TEST // Uncomment this line to run the MEM0 test.
//#define RUN_MEM1_TEST // (Teensy 3.5/3/6 only!) Uncomment this line to run the MEM1 test.
//#define RUN_MIDI_TEST // Uncomment this line to run a MIDI test. You must connect a MIDI cable as a loopback between the MIDI input and output jacks.
//#define RUN_MEMO_TEST // Uncomment this line if you purchased the option SPI RAM.
//#define RUN_EXP_TEST // Uncomment if you purchased the Expansion Control Board
#include <Audio.h>
#include "BALibrary.h"
@ -61,6 +60,8 @@ AudioConnection patch1(i2sIn,1, i2sOut, 1);
BAAudioControlWM8731 codec;
BAGpio gpio; // access to User LED
elapsedMillis timer;
#if defined(RUN_MEMO_TEST)
BASpiMemoryDMA spiMem0(SpiDeviceId::SPI_DEVICE0);
#endif
@ -71,30 +72,38 @@ BASpiMemoryDMA spiMem1(SpiDeviceId::SPI_DEVICE1);
// Create a control object using the number of switches, pots, encoders and outputs on the
// Blackaddr Audio Expansion Board.
#ifdef RUN_EXP_TEST
BAPhysicalControls controls(BA_EXPAND_NUM_SW, BA_EXPAND_NUM_POT, BA_EXPAND_NUM_ENC, BA_EXPAND_NUM_LED);
void configPhysicalControls(BAPhysicalControls &controls, BAAudioControlWM8731 &codec);
void checkPot(unsigned id);
void checkSwitch(unsigned id);
#endif
bool spiTest(BASpiMemory *mem, int id); // returns true if passed
bool uartTest(); // returns true if passed
unsigned loopCounter = 0;
void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x);
//TGA_PRO_REVA(x);
Serial.begin(57600);
while (!Serial) { yield(); }
//while (!Serial) { yield(); }
delay(500);
// Disable the audio codec first
codec.disable();
delay(100);
AudioMemory(128);
AudioMemory(64);
codec.enable();
codec.setHeadphoneVolume(0.8f); // Set headphone volume
#if defined(RUN_EXP_TEST)
configPhysicalControls(controls, codec);
TGA_PRO_EXPAND_REV2(); // Macro to declare expansion board revision
Serial.println("Now monitoring for input from Expansion Control Board");
#endif
// Run the initial Midi connectivity and SPI memory tests.
#if defined(RUN_MIDI_TEST)
@ -102,33 +111,28 @@ void setup() {
#endif
#if defined(RUN_MEMO_TEST)
SPI_MEM0_1M();
//SPI_MEM0_4M();
SPI_MEM0_4M(); // Declare the correct memory size
// SPI_MEM0_1M(); // older boards only had 1M memories
spiMem0.begin(); delay(10);
if (spiTest(&spiMem0, 0)) { Serial.println("SPI0 testing PASSED!");}
#endif
#if defined(RUN_MEM1_TEST) && !defined(__IMXRT1062__)
SPI_MEM1_1M();
//SPI_MEM1_4M();
spiMem1.begin(); delay(10);
if (spiTest(&spiMem1, 1)) { Serial.println("SPI1 testing PASSED!");}
#endif
Serial.println("Now monitoring for input from Expansion Control Board");
}
void loop() {
checkPot(0);
checkPot(1);
checkPot(2);
checkSwitch(0);
checkSwitch(1);
delay(20);
#if defined(RUN_EXP_TEST)
checkPot(0);
checkPot(1);
checkPot(2);
checkSwitch(0);
checkSwitch(1);
#endif
delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected.
loopCounter++;
if ((loopCounter % 100) == 0) {
gpio.toggleLed();
if (timer > 1000) {
timer = 0;
gpio.toggleLed(); // toggle the user LED every 1 second
}
}

@ -67,6 +67,11 @@ public:
/// @returns the new stage of the user LED.
int toggleLed();
/// Convert the GPIO enum to the underlying logical pin number
/// @param gpio the enum value to convert
/// @returns the logical pin number for the GPIO
uint8_t enumToPinNumber(GPIO gpio);
private:
uint8_t m_ledState;
};

@ -20,8 +20,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifndef __BALIBRARY_BAHARDWARE_H
#define __BALIBRARY_BAHARDWARE_H
#ifndef BALIBRARY_BAHARDWARE_H_
#define BALIBRARY_BAHARDWARE_H_
#include <Arduino.h>
#include <cstdint>
@ -32,30 +32,29 @@
*****************************************************************************/
namespace BALibrary {
// In your Arudino .ino file, use #defines for your TGA Pro revision and options
// to correctly configure your hardware
#define TGA_PRO_REVA(x) BALibrary::BAHardwareConfig.m_tgaBoard = TgaBoard::REV_A ///< Macro for specifying REV A of the TGA Pro
#define TGA_PRO_REVB(x) BALibrary::BAHardwareConfig.m_tgaBoard = TgaBoard::REV_B ///< Macro for specifying REV B of the TGA Pro
#define TGA_PRO_EXPAND_REV2(x) BALibrary::BAHardwareConfig.m_expansionBoard = ExpansionBoard::REV_2 ///< Macro for specifying REV 2 of the Expansion Board
#define SPI_MEM0_1M(x) BALibrary::BAHardwareConfig.m_spiMem0 = SPI_MEMORY_1M ///< Macro for specifying MEM0 is 1Mbit
#define SPI_MEM0_4M(x) BALibrary::BAHardwareConfig.m_spiMem0 = SPI_MEMORY_4M ///< Macro for specifying MEM1 is 4Mbit
#define SPI_MEM1_1M(x) BALibrary::BAHardwareConfig.m_spiMem1 = SPI_MEMORY_1M ///< Macro for specifying MEM0 is 1Mbit
#define SPI_MEM1_4M(x) BALibrary::BAHardwareConfig.m_spiMem1 = SPI_MEMORY_4M ///< Macro for specifying MEM1 is 1Mbit
/******************************************************************************
* Hardware Configuration
*****************************************************************************/
/// enum to specify the TGA Board revision
enum class TgaBoard : unsigned {
REV_A = 0, ///< indicates using REV A of the TGA Pro
REV_B ///< indicates using REV B of the TGA Pro
REV_B, ///< indicates using REV B of the TGA Pro
MKII_REV1, ///< indicates using MKII, Rev 1 of the TGA Pro
AVALON
};
/// enum to specify the TGA Board revision
enum class TeensyProcessor : unsigned {
TEENSY3 = 0, ///< indicates using REV A of the TGA Pro
TEENSY4, ///< indicates using REV B of the TGA Pro
};
/// enum to specify the TGA Pro Expansion Board revision
enum class ExpansionBoard : unsigned {
NO_EXPANSION = 0, ///< default, indicates no expansion board is present
REV_1, ///< indicates using REV 1 of the Expansion Board
REV_2 ///< indicates using REV 2 of the Expansion Board
REV_2, ///< indicates using REV 2 of the Expansion Board
REV_3 ///< indicates using REV 3 of the Expansion Board (MKII Series)
};
/// enum to specify SPI memory dize
@ -66,6 +65,7 @@ enum class SpiMemorySize : unsigned {
};
constexpr unsigned NUM_MEM_SLOTS = 2; ///< The TGA Pro has two SPI ports for memory
/// enum to specify MEM0 or MEM1
enum MemSelect : unsigned {
MEM0 = 0, ///< SPI RAM MEM0
@ -108,6 +108,22 @@ enum class SpiDeviceId : unsigned {
SPI_DEVICE1 = 1 ///< Arduino SPI1 device
};
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO {
GPIO0 = 0,
GPIO1 = 1,
GPIO2 = 2,
GPIO3 = 3,
GPIO4 = 4,
GPIO5 = 5,
GPIO6 = 6,
GPIO7 = 7,
TP1 = 8,
TP2 = 9
};
/**************************************************************************//**
* BAHardware is a global object that holds hardware configuration options for
* board revisions and ordering options. It is created automatically, and only
@ -116,7 +132,7 @@ enum class SpiDeviceId : unsigned {
*****************************************************************************/
class BAHardware {
public:
BAHardware() = default; ///< default constructor
BAHardware(); ///< default constructor
/// sets the TGA Pro board revision
/// @param tgaBoard enum to specify board revision
@ -126,6 +142,10 @@ public:
/// @returns enum for the board revision
TgaBoard getTgaBoard(void);
/// get the configured Teensy Processor
/// @returns enum for the processor
TeensyProcessor getTeensyProcessor();
/// sets the Expansion board revision
/// @param expansionBoard enum to specify the expansion board revision
void set(ExpansionBoard expansionBoard);
@ -163,75 +183,75 @@ public:
/// @returns the last valid address location in the memory
size_t getSpiMemMaxAddr (unsigned memIndex);
TgaBoard m_tgaBoard = TgaBoard::REV_B; ///< stores the configured TGA Pro revision
ExpansionBoard m_expansionBoard = ExpansionBoard::NO_EXPANSION; ///< stores the configured Expansion Board revision
SpiMemoryDefinition m_spiMem0 = SPI_MEMORY_NONE; ///< stores the definition for MEM0
SpiMemoryDefinition m_spiMem1 = SPI_MEMORY_NONE; ///< stores the definition for MEM1
TgaBoard m_tgaBoard = TgaBoard::MKII_REV1; ///< stores the configured TGA Pro revision
TeensyProcessor m_teensyProcessor = TeensyProcessor::TEENSY4; ///< store the processor in use
ExpansionBoard m_expansionBoard = ExpansionBoard::NO_EXPANSION; ///< stores the configured Expansion Board revision
SpiMemoryDefinition m_spiMem0 = SPI_MEMORY_NONE; ///< stores the definition for MEM0
SpiMemoryDefinition m_spiMem1 = SPI_MEMORY_NONE; ///< stores the definition for MEM1
};
extern BAHardware BAHardwareConfig; ///< external definition of global configuration class object
/**************************************************************************//**
* Teensy 3.6/3.5 Hardware Pinout
*****************************************************************************/
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) // T3.6 or T3.5
constexpr uint8_t USR_LED_ID = 16; ///< Teensy IO number for the user LED.
// In your Arudino .ino file, use #defines for your TGA Pro revision and options
// to correctly configure your hardware
#define TGA_PRO_REVA(x) BALibrary::BAHardwareConfig.set(TgaBoard::REV_A) ///< Macro for specifying REV A of the TGA Pro
#define TGA_PRO_REVB(x) BALibrary::BAHardwareConfig.set(TgaBoard::REV_B) ///< Macro for specifying REV B of the TGA Pro
#define TGA_PRO_MKII_REV1(x) BALibrary::BAHardwareConfig.set(TgaBoard::MKII_REV1) ///< Macro for specifying REV B of the TGA Pro
#define TGA_PRO_EXPAND_REV2(x) BALibrary::BAHardwareConfig.setExpansionBoard(ExpansionBoard::REV_2) ///< Macro for specifying REV 2 of the Expansion Board
#define TGA_PRO_EXPAND_REV3(x) BALibrary::BAHardwareConfig.setExpansionBoard(ExpansionBoard::REV_3) ///< Macro for specifying REV 2 of the Expansion Board
#define SPI_MEM0_1M(x) BALibrary::BAHardwareConfig.set(MEM0, SPI_MEMORY_1M) ///< Macro for specifying MEM0 is 1Mbit
#define SPI_MEM0_4M(x) BALibrary::BAHardwareConfig.set(MEM0, SPI_MEMORY_4M) ///< Macro for specifying MEM1 is 4Mbit
#define SPI_MEM1_1M(x) BALibrary::BAHardwareConfig.set(MEM1, SPI_MEMORY_1M) ///< Macro for specifying MEM0 is 1Mbit
#define SPI_MEM1_4M(x) BALibrary::BAHardwareConfig.set(MEM1, SPI_MEMORY_4M) ///< Macro for specifying MEM1 is 1Mbit
extern uint8_t USR_LED_ID; ///< Teensy IO number for the user LED.
extern unsigned BA_EXPAND_NUM_POT;
extern unsigned BA_EXPAND_NUM_SW;
extern unsigned BA_EXPAND_NUM_LED;
extern unsigned BA_EXPAND_NUM_ENC;
extern uint8_t BA_EXPAND_POT1_PIN; // 14_A0_TX3_SPDIFOUT
extern uint8_t BA_EXPAND_POT2_PIN; // 15_A1_RX3_SPDIFIN
extern uint8_t BA_EXPAND_POT3_PIN; // 16_A2_RX4_SCL1
extern uint8_t BA_EXPAND_SW1_PIN; // 2_OUT2
extern uint8_t BA_EXPAND_SW2_PIN; // 3_LRCLK2
extern uint8_t BA_EXPAND_LED1_PIN; // 4_BLCK2
extern uint8_t BA_EXPAND_LED2_PIN; // 5_IN2
extern uint8_t GPIO0;
extern uint8_t GPIO1;
extern uint8_t GPIO2;
extern uint8_t GPIO3;
extern uint8_t GPIO4;
extern uint8_t GPIO5;
extern uint8_t GPIO6;
extern uint8_t GPIO7;
extern uint8_t TP1;
extern uint8_t TP2;
// SPI0 and SPI1 pinouts
constexpr uint8_t SPI0_SCK_PIN = 14;
constexpr uint8_t SPI0_CS_PIN = 15;
constexpr uint8_t SPI0_MISO_PIN = 8;
constexpr uint8_t SPI0_MOSI_PIN = 7;
extern uint8_t SPI0_SCK_PIN;
extern uint8_t SPI0_CS_PIN;
extern uint8_t SPI0_MISO_PIN;
extern uint8_t SPI0_MOSI_PIN;
#define SPI1_AVAILABLE
constexpr uint8_t SPI1_SCK_PIN = 20;
constexpr uint8_t SPI1_CS_PIN = 31;
constexpr uint8_t SPI1_MISO_PIN = 5;
constexpr uint8_t SPI1_MOSI_PIN = 21;
extern uint8_t SPI1_SCK_PIN;
extern uint8_t SPI1_CS_PIN;
extern uint8_t SPI1_MISO_PIN;
extern uint8_t SPI1_MOSI_PIN;
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO : uint8_t {
GPIO0 = 2,
GPIO1 = 3,
GPIO2 = 4,
GPIO3 = 6,
GPIO4 = 12,
GPIO5 = 32,
GPIO6 = 27,
GPIO7 = 28,
TP1 = 34,
TP2 = 33
};
#if defined(ARDUINO_TEENSY41) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
#define SPI1_AVAILABLE
#endif
/**************************************************************************//**
* Teensy 4.0 Hardware Settings
*****************************************************************************/
#elif defined(__IMXRT1062__) // T4.0
constexpr uint8_t USR_LED_ID = 2; ///< Teensy IO number for the user LED.
// SPI0 pinouts
constexpr uint8_t SPI0_SCK_PIN = 13;
constexpr uint8_t SPI0_CS_PIN = 10;
constexpr uint8_t SPI0_MISO_PIN = 12;
constexpr uint8_t SPI0_MOSI_PIN = 11;
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO : uint8_t {
GPIO0 = 3,
GPIO1 = 4,
GPIO2 = 5,
GPIO3 = 6,
GPIO4 = 17,
GPIO5 = 16,
GPIO6 = 15,
GPIO7 = 14,
TP1 = 9,
TP2 = 22
};
#if defined(__IMXRT1062__) // T4.0
#define SCL_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_00
#define SDA_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_01
@ -242,75 +262,10 @@ constexpr uint32_t SCL_SDA_PAD_CFG = 0xF808;
#define LRCLK_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_11
#define DAC_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_B1_01
constexpr uint32_t I2S_PAD_CFG = 0x0008;
/**************************************************************************//**
* DEFAULT Teensy 3.2 Hardware Settings
*****************************************************************************/
#else
constexpr uint8_t USR_LED_ID = 16; ///< Teensy IO number for the user LED.
// SPI0 and SPI1 pinouts
constexpr uint8_t SPI0_SCK_PIN = 14;
constexpr uint8_t SPI0_CS_PIN = 15;
constexpr uint8_t SPI0_MISO_PIN = 8;
constexpr uint8_t SPI0_MOSI_PIN = 7;
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO : uint8_t {
GPIO0 = 2,
GPIO1 = 3,
GPIO2 = 4,
GPIO3 = 6,
GPIO4 = 12,
GPIO5 = 32,
GPIO6 = 27,
GPIO7 = 28,
TP1 = 34,
TP2 = 33
};
#endif
/**************************************************************************//**
* Blackaddr Audio Expansion Board Pin Configuration
*****************************************************************************/
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) // T3.6 or T3.5
// Teensy 3.6 Pinout
constexpr unsigned BA_EXPAND_NUM_POT = 3;
constexpr unsigned BA_EXPAND_NUM_SW = 2;
constexpr unsigned BA_EXPAND_NUM_LED = 2;
constexpr unsigned BA_EXPAND_NUM_ENC = 0;
constexpr uint8_t BA_EXPAND_POT1_PIN = A16; // 35_A16_PWM
constexpr uint8_t BA_EXPAND_POT2_PIN = A17; // 36_A17_PWM
constexpr uint8_t BA_EXPAND_POT3_PIN = A18; // 37_SCL1_A18_PWM
constexpr uint8_t BA_EXPAND_SW1_PIN = 2; // 2)PWM
constexpr uint8_t BA_EXPAND_SW2_PIN = 3; // 3_SCL2_PWM
constexpr uint8_t BA_EXPAND_LED1_PIN = 4; // 4_SDA2_PWM
constexpr uint8_t BA_EXPAND_LED2_PIN = 6; // 6_PWM
#elif defined(__IMXRT1062__)
// Teensy 4.0 pinout
constexpr unsigned BA_EXPAND_NUM_POT = 3;
constexpr unsigned BA_EXPAND_NUM_SW = 2;
constexpr unsigned BA_EXPAND_NUM_LED = 2;
constexpr unsigned BA_EXPAND_NUM_ENC = 0;
constexpr uint8_t BA_EXPAND_POT1_PIN = A0; // 14_A0_TX3_SPDIFOUT
constexpr uint8_t BA_EXPAND_POT2_PIN = A1; // 15_A1_RX3_SPDIFIN
constexpr uint8_t BA_EXPAND_POT3_PIN = A2; // 16_A2_RX4_SCL1
constexpr uint8_t BA_EXPAND_SW1_PIN = 3; // 3_LRCLK2
constexpr uint8_t BA_EXPAND_SW2_PIN = 4; // 4_BCLK2
constexpr uint8_t BA_EXPAND_LED1_PIN = 5; // 5_IN2
constexpr uint8_t BA_EXPAND_LED2_PIN = 6; // 6_OUT1D
#else
#warning Your processor is not yet supported in BALibrary
#endif
} // namespace BALibrary
#endif /* __BALIBRARY_BAHARDWARE_H */
#endif /* BALIBRARY_BAHARDWARE_H_ */

@ -17,8 +17,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __BALIBRARY_H
#define __BALIBRARY_H
#ifndef BALIBRARY_H_
#define BALIBRARY_H_
#include "BAHardware.h" // contains the Blackaddr hardware board definitions
@ -31,4 +31,4 @@
#include "BAGpio.h"
#include "BAPhysicalControls.h"
#endif /* __BALIBRARY_H */
#endif /* BALIBRARY_H_ */

@ -87,7 +87,6 @@ audio_block_t* AudioDelay::addBlock(audio_block_t *block)
setSpiDmaCopyBuffer();
#endif
// this causes pops
m_slot->writeAdvance16(block->data, AUDIO_BLOCK_SAMPLES);
}
blockToRelease = block;
@ -115,7 +114,10 @@ size_t AudioDelay::getMaxDelaySamples()
bool AudioDelay::getSamples(audio_block_t *dest, size_t offsetSamples, size_t numSamples)
{
return m_getSamples(dest->data, offsetSamples, numSamples);
if (!dest) { return false; }
else {
return m_getSamples(dest->data, offsetSamples, numSamples);
}
}
bool AudioDelay::getSamples(int16_t *dest, size_t offsetSamples, size_t numSamples)
@ -221,6 +223,7 @@ bool AudioDelay::interpolateDelay(int16_t *extendedSourceBuffer, int16_t *destBu
bool AudioDelay::setSpiDmaCopyBuffer(void)
{
bool returnValue = false;
if (m_slot->isUseDma()) {
// For DMA use on T4.0 we need this kluge
BASpiMemoryDMA * spiDma = static_cast<BASpiMemoryDMA*>(m_slot->getSpiMemoryHandle());

@ -23,15 +23,277 @@ namespace BALibrary {
BAHardware BAHardwareConfig; // create the global configuration struct
////////////////////////////////////////////////////////////////////////////////
// DEFAULT SETTINGS - modified appropriate when user calls BAHardware:set()
// Default settings are currently for TGA PRO MKII & Teensy 4
////////////////////////////////////////////////////////////////////////////////
uint8_t USR_LED_ID = 6; ///< Teensy IO number for the user LED.
unsigned BA_EXPAND_NUM_POT = 3;
unsigned BA_EXPAND_NUM_SW = 2;
unsigned BA_EXPAND_NUM_LED = 2;
unsigned BA_EXPAND_NUM_ENC = 0;
uint8_t BA_EXPAND_POT1_PIN = A0; // 14_A0_TX3_SPDIFOUT
uint8_t BA_EXPAND_POT2_PIN = A1; // 15_A1_RX3_SPDIFIN
uint8_t BA_EXPAND_POT3_PIN = A2; // 16_A2_RX4_SCL1
uint8_t BA_EXPAND_SW1_PIN = 2; // 2_OUT2
uint8_t BA_EXPAND_SW2_PIN = 3; // 3_LRCLK2
uint8_t BA_EXPAND_LED1_PIN = 4; // 4_BLCK2
uint8_t BA_EXPAND_LED2_PIN = 5; // 5_IN2
uint8_t GPIO0 = 2;
uint8_t GPIO1 = 3;
uint8_t GPIO2 = 4;
uint8_t GPIO3 = 5;
uint8_t GPIO4 = 255; // Not available on MKII
uint8_t GPIO5 = 16;
uint8_t GPIO6 = 15;
uint8_t GPIO7 = 14;
uint8_t TP1 = 9;
uint8_t TP2 = 22;
// SPI0
uint8_t SPI0_SCK_PIN = 13;
uint8_t SPI0_CS_PIN = 10;
uint8_t SPI0_MISO_PIN = 12;
uint8_t SPI0_MOSI_PIN = 11;
// SPI1 is only available on user breakout board for MKII/T4
uint8_t SPI1_SCK_PIN = 27;
uint8_t SPI1_CS_PIN = 38;
uint8_t SPI1_MISO_PIN = 39;
uint8_t SPI1_MOSI_PIN = 26;
BAHardware::BAHardware()
{
#if defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY40) // T4.X
m_teensyProcessor = TeensyProcessor::TEENSY4;
#elif defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__)
m_teensyProcessor = TeensyProcessor::TEENSY3;
#else
#error "Only Teensy 4.1, 4.0, 3.6, 3.5, 3.2 are supported"
#endif
}
void BAHardware::set(TgaBoard tgaBoard)
{
m_tgaBoard = tgaBoard;
m_tgaBoard = tgaBoard;
////////////////////////////////////////////////////////////////////////////
// MKII //
////////////////////////////////////////////////////////////////////////////
#if defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY40) // T4.X
if (tgaBoard == TgaBoard::MKII_REV1) {
// No change from defaults
}
#endif
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__) // T3.6 or T3.5 or T3.2
if (tgaBoard == TgaBoard::MKII_REV1) {
// Uses TEENSY_ADAPTER_T3
USR_LED_ID = 16;
BA_EXPAND_POT1_PIN = A16; // 14_A0_TX3_SPDIFOUT
BA_EXPAND_POT2_PIN = A17; // 15_A1_RX3_SPDIFIN
BA_EXPAND_POT3_PIN = A18; // 16_A2_RX4_SCL1
BA_EXPAND_SW1_PIN = 2; // 2_OUT2
BA_EXPAND_SW2_PIN = 3; // 3_LRCLK2
BA_EXPAND_LED1_PIN = 4; // 4_BLCK2
BA_EXPAND_LED2_PIN = 6; // 5_IN2
GPIO0 = 2;
GPIO1 = 3;
GPIO2 = 4;
GPIO3 = 6;
GPIO4 = 255; // Not available on MKII
GPIO5 = 37;
GPIO6 = 36;
GPIO7 = 35;
TP1 = 34;
TP2 = 33;
SPI0_SCK_PIN = 14;
SPI0_CS_PIN = 15;
SPI0_MISO_PIN = 8;
SPI0_MOSI_PIN = 7;
SPI1_SCK_PIN = 20;
SPI1_CS_PIN = 31;
SPI1_MISO_PIN = 5;
SPI1_MOSI_PIN = 21;
}
#endif
////////////////////////////////////////////////////////////////////////////
// REVB (Original TGA Pro) //
////////////////////////////////////////////////////////////////////////////
#if defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY40) // T4.X
if (tgaBoard == TgaBoard::REV_B) {
// Uses TGA_T4_ADAPTER board
USR_LED_ID = 2;
BA_EXPAND_POT1_PIN = A0; // 14_A0_TX3_SPDIFOUT
BA_EXPAND_POT2_PIN = A1; // 15_A1_RX3_SPDIFIN
BA_EXPAND_POT3_PIN = A2; // 16_A2_RX4_SCL1
BA_EXPAND_SW1_PIN = 3; // 2_OUT2
BA_EXPAND_SW2_PIN = 4; // 3_LRCLK2
BA_EXPAND_LED1_PIN = 5; // 4_BLCK2
BA_EXPAND_LED2_PIN = 6; // 5_IN2
GPIO0 = 3;
GPIO1 = 4;
GPIO2 = 5;
GPIO3 = 6;
GPIO4 = 17;
GPIO5 = 16;
GPIO6 = 15;
GPIO7 = 14;
TP1 = 9;
TP2 = 255; // Not available
SPI0_SCK_PIN = 13;
SPI0_CS_PIN = 10;
SPI0_MISO_PIN = 12;
SPI0_MOSI_PIN = 11;
}
#endif
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__) // T3.6 or T3.5 or T3.2
if (tgaBoard == TgaBoard::REV_B) {
USR_LED_ID = 16;
BA_EXPAND_POT1_PIN = A16; // 14_A0_TX3_SPDIFOUT
BA_EXPAND_POT2_PIN = A17; // 15_A1_RX3_SPDIFIN
BA_EXPAND_POT3_PIN = A18; // 16_A2_RX4_SCL1
BA_EXPAND_SW1_PIN = 2; // 2_OUT2
BA_EXPAND_SW2_PIN = 3; // 3_LRCLK2
BA_EXPAND_LED1_PIN = 4; // 4_BLCK2
BA_EXPAND_LED2_PIN = 6; // 5_IN2
GPIO0 = 2;
GPIO1 = 3;
GPIO2 = 4;
GPIO3 = 6;
GPIO4 = 38;
GPIO5 = 37;
GPIO6 = 36;
GPIO7 = 35;
TP1 = 34;
TP2 = 33;
SPI0_SCK_PIN = 14;
SPI0_CS_PIN = 15;
SPI0_MISO_PIN = 8;
SPI0_MOSI_PIN = 7;
SPI1_SCK_PIN = 20;
SPI1_CS_PIN = 31;
SPI1_MISO_PIN = 5;
SPI1_MOSI_PIN = 21;
}
#endif
////////////////////////////////////////////////////////////////////////////
// REVA (Original TGA Pro) //
////////////////////////////////////////////////////////////////////////////
#if defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY40) // T4.X
if (tgaBoard == TgaBoard::REV_A) {
// Uses TGA_T4_ADAPTER board
USR_LED_ID = 2;
GPIO0 = 3;
GPIO1 = 4;
GPIO2 = 5;
GPIO3 = 6;
GPIO4 = 17;
GPIO5 = 16;
GPIO6 = 15;
GPIO7 = 14;
TP1 = 9;
TP2 = 255; // Not available
SPI0_SCK_PIN = 13;
SPI0_CS_PIN = 10;
SPI0_MISO_PIN = 12;
SPI0_MOSI_PIN = 11;
}
#endif
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__) // T3.6 or T3.5 or T3.2
if (tgaBoard == TgaBoard::REV_A) {
// REVA did not support Expansion board
USR_LED_ID = 16;
GPIO0 = 2;
GPIO1 = 3;
GPIO2 = 4;
GPIO3 = 6;
GPIO4 = 12;
GPIO5 = 32;
GPIO6 = 27;
GPIO7 = 29;
TP1 = 34;
TP2 = 33;
SPI0_SCK_PIN = 14;
SPI0_CS_PIN = 15;
SPI0_MISO_PIN = 8;
SPI0_MOSI_PIN = 7;
SPI1_SCK_PIN = 20;
SPI1_CS_PIN = 31;
SPI1_MISO_PIN = 5;
SPI1_MOSI_PIN = 21;
}
#endif
////////////////////////////////////////////////////////////////////////////
// Avalon //
////////////////////////////////////////////////////////////////////////////
#if defined(ARDUINO_TEENSY41) // T4.X
if (tgaBoard == TgaBoard::AVALON) {
BA_EXPAND_NUM_POT = 2;
BA_EXPAND_NUM_SW = 6;
BA_EXPAND_NUM_LED = 2;
BA_EXPAND_NUM_ENC = 4;
BA_EXPAND_POT1_PIN = A0;
BA_EXPAND_POT2_PIN = A1;
BA_EXPAND_POT3_PIN = A13;
BA_EXPAND_SW1_PIN = 17;
BA_EXPAND_SW2_PIN = 16;
BA_EXPAND_LED1_PIN = 22;
BA_EXPAND_LED2_PIN = 32;
SPI0_SCK_PIN = 13;
SPI0_CS_PIN = 10;
SPI0_MISO_PIN = 12;
SPI0_MOSI_PIN = 11;
}
#endif
}
TgaBoard BAHardware::getTgaBoard(void)
{
return m_tgaBoard;
}
TeensyProcessor BAHardware::getTeensyProcessor(void)
{
return m_teensyProcessor;
}
void BAHardware::set(ExpansionBoard expansionBoard)
{
m_expansionBoard = expansionBoard;

@ -144,11 +144,17 @@ bool ExtMemSlot::writeAdvance16(int16_t *src, size_t numWords)
// this write will wrap the memory slot
size_t wrBytes = m_end - m_currentWrPosition + 1;
size_t wrDataNum = wrBytes >> 1; // divide by two to get the number of data
m_spi->write16(m_currentWrPosition, reinterpret_cast<uint16_t*>(src), wrDataNum);
size_t remainingData = numWords - wrDataNum;
m_spi->write16(m_start, reinterpret_cast<uint16_t*>(src + wrDataNum), remainingData); // write remaining bytes are start
m_currentWrPosition = m_start + (remainingData*sizeof(int16_t));
}
// If a write transaction landed exactly on the end of the memory, the next position must be
// manually put back to the start
if (m_currentWrPosition > m_end) { m_currentWrPosition = m_start; }
return true;
}

@ -36,7 +36,9 @@ AudioEffectAnalogDelay::AudioEffectAnalogDelay(ExtMemSlot *slot)
: AudioStream(1, m_inputQueueArray)
{
m_memory = new AudioDelay(slot);
m_maxDelaySamples = (slot->size() / sizeof(int16_t));
// the delay cannot be exactly equal to the slot size, you need at least one sample so the wr/rd are not on top of each other.
m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES;
m_externalMemory = true;
m_constructFilter();
}
@ -77,50 +79,52 @@ void AudioEffectAnalogDelay::setFilter(Filter filter)
void AudioEffectAnalogDelay::update(void)
{
audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples
// Check is block is disabled
if (m_enable == false) {
// do not transmit or process any audio, return as quickly as possible.
if (inputAudioBlock) release(inputAudioBlock);
// release all held memory resources
if (m_previousBlock) {
release(m_previousBlock); m_previousBlock = nullptr;
}
if (!m_externalMemory) {
// when using internal memory we have to release all references in the ring buffer
while (m_memory->getRingBuffer()->size() > 0) {
audio_block_t *releaseBlock = m_memory->getRingBuffer()->front();
m_memory->getRingBuffer()->pop_front();
if (releaseBlock) release(releaseBlock);
}
}
return;
}
// Check is block is bypassed, if so either transmit input directly or create silence
if (m_bypass == true) {
// transmit the input directly
if (!inputAudioBlock) {
// create silence
inputAudioBlock = allocate();
if (!inputAudioBlock) { return; } // failed to allocate
else {
clearAudioBlock(inputAudioBlock);
}
}
transmit(inputAudioBlock, 0);
release(inputAudioBlock);
return;
}
// Check is block is disabled
if (m_enable == false) {
// release all held memory resources
if (m_previousBlock) {
release(m_previousBlock); m_previousBlock = nullptr;
}
if (!m_externalMemory) {
// when using internal memory we have to release all references in the ring buffer
while (m_memory->getRingBuffer()->size() > 0) {
audio_block_t *releaseBlock = m_memory->getRingBuffer()->front();
m_memory->getRingBuffer()->pop_front();
if (releaseBlock) release(releaseBlock);
}
}
return;
}
audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples
// Check is block is bypassed, if so either transmit input directly or create silence
if ((m_bypass == true) || (!inputAudioBlock)) {
// transmit the input directly
if (!inputAudioBlock) {
// create silence
inputAudioBlock = allocate();
if (!inputAudioBlock) { return; } // failed to allocate
else {
clearAudioBlock(inputAudioBlock);
}
}
transmit(inputAudioBlock, 0);
release(inputAudioBlock);
return;
}
// Otherwise perform normal processing
// In order to make use of the SPI DMA, we need to request the read from memory first,
// then do other processing while it fills in the back.
audio_block_t *blockToOutput = nullptr; // this will hold the output audio
blockToOutput = allocate();
if (!blockToOutput) return; // skip this update cycle due to failure
if (!blockToOutput) {
transmit(inputAudioBlock, 0);
release(inputAudioBlock);
return; // skip this update cycle due to failure
}
// get the data. If using external memory with DMA, this won't be filled until
// later.
@ -162,21 +166,17 @@ void AudioEffectAnalogDelay::delay(float milliseconds)
{
size_t delaySamples = calcAudioSamples(milliseconds);
if (delaySamples > m_memory->getMaxDelaySamples()) {
// this exceeds max delay value, limit it.
delaySamples = m_memory->getMaxDelaySamples();
}
if (!m_memory) { Serial.println("delay(): m_memory is not valid"); }
if (!m_memory) { Serial.println("delay(): m_memory is not valid"); return; }
if (!m_externalMemory) {
// internal memory
m_maxDelaySamples = m_memory->getMaxDelaySamples();
//QueuePosition queuePosition = calcQueuePosition(milliseconds);
//Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset);
} else {
// external memory
//Serial.println(String("CONFIG: delay:") + delaySamples);
ExtMemSlot *slot = m_memory->getSlot();
m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES;
if (!slot) { Serial.println("ERROR: slot ptr is not valid"); }
if (!slot->isEnabled()) {
@ -185,6 +185,10 @@ void AudioEffectAnalogDelay::delay(float milliseconds)
}
}
if (delaySamples > m_maxDelaySamples) {
// this exceeds max delay value, limit it.
delaySamples = m_maxDelaySamples;
}
m_delaySamples = delaySamples;
}
@ -194,43 +198,52 @@ void AudioEffectAnalogDelay::delay(size_t delaySamples)
if (!m_externalMemory) {
// internal memory
m_maxDelaySamples = m_memory->getMaxDelaySamples();
//QueuePosition queuePosition = calcQueuePosition(delaySamples);
//Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset);
} else {
// external memory
//Serial.println(String("CONFIG: delay:") + delaySamples);
ExtMemSlot *slot = m_memory->getSlot();
m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES;
if (!slot->isEnabled()) {
slot->enable();
}
}
m_delaySamples = delaySamples;
if (delaySamples > m_maxDelaySamples) {
// this exceeds max delay value, limit it.
delaySamples = m_maxDelaySamples;
}
m_delaySamples = delaySamples;
}
void AudioEffectAnalogDelay::delayFractionMax(float delayFraction)
{
size_t delaySamples = static_cast<size_t>(static_cast<float>(m_memory->getMaxDelaySamples()) * delayFraction);
if (delaySamples > m_memory->getMaxDelaySamples()) {
// this exceeds max delay value, limit it.
delaySamples = m_memory->getMaxDelaySamples();
}
if (!m_memory) { Serial.println("delay(): m_memory is not valid"); }
if (!m_externalMemory) {
// internal memory
m_maxDelaySamples = m_memory->getMaxDelaySamples();
//QueuePosition queuePosition = calcQueuePosition(delaySamples);
//Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset);
} else {
// external memory
//Serial.println(String("CONFIG: delay:") + delaySamples);
ExtMemSlot *slot = m_memory->getSlot();
m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES;
if (!slot->isEnabled()) {
slot->enable();
}
}
m_delaySamples = delaySamples;
if (delaySamples > m_maxDelaySamples) {
// this exceeds max delay value, limit it.
delaySamples = m_maxDelaySamples;
}
m_delaySamples = delaySamples;
}
void AudioEffectAnalogDelay::m_preProcessing(audio_block_t *out, audio_block_t *dry, audio_block_t *wet)
@ -268,8 +281,8 @@ void AudioEffectAnalogDelay::processMidi(int channel, int control, int value)
if ((m_midiConfig[DELAY][MIDI_CHANNEL] == channel) &&
(m_midiConfig[DELAY][MIDI_CONTROL] == control)) {
// Delay
if (m_externalMemory) { m_maxDelaySamples = m_memory->getSlot()->size() / sizeof(int16_t); }
size_t delayVal = (size_t)(val * (float)m_maxDelaySamples);
if (m_externalMemory) { m_maxDelaySamples = (m_memory->getSlot()->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES; }
size_t delayVal = (size_t)(val * (float)(m_maxDelaySamples));
delay(delayVal);
Serial.println(String("AudioEffectAnalogDelay::delay (ms): ") + calcAudioTimeMs(delayVal)
+ String(" (samples): ") + delayVal + String(" out of ") + m_maxDelaySamples);

@ -62,28 +62,25 @@ void AudioEffectSOS::enable(void)
if (m_externalMemory) {
// Because we hold the previous output buffer for an update cycle, the maximum delay is actually
// 1 audio block mess then the max delay returnable from the memory.
m_maxDelaySamples = m_memory->getMaxDelaySamples();
m_maxDelaySamples = m_memory->getMaxDelaySamples() - AUDIO_BLOCK_SAMPLES;
Serial.println(String("SOS Enabled with delay length ") + m_maxDelaySamples + String(" samples"));
}
m_delaySamples = m_maxDelaySamples;
m_inputGateAuto.setupParameter(GATE_OPEN_STAGE, 0.0f, 1.0f, 1000.0f, ParameterAutomation<float>::Function::EXPONENTIAL);
m_inputGateAuto.setupParameter(GATE_HOLD_STAGE, 1.0f, 1.0f, m_maxDelaySamples, ParameterAutomation<float>::Function::HOLD);
m_inputGateAuto.setupParameter(GATE_HOLD_STAGE, 1.0f, 1.0f, m_delaySamples, ParameterAutomation<float>::Function::HOLD);
m_inputGateAuto.setupParameter(GATE_CLOSE_STAGE, 1.0f, 0.0f, 1000.0f, ParameterAutomation<float>::Function::EXPONENTIAL);
m_clearFeedbackAuto.setupParameter(GATE_OPEN_STAGE, 1.0f, 0.0f, 1000.0f, ParameterAutomation<float>::Function::EXPONENTIAL);
m_clearFeedbackAuto.setupParameter(GATE_HOLD_STAGE, 0.0f, 0.0f, m_maxDelaySamples, ParameterAutomation<float>::Function::HOLD);
m_clearFeedbackAuto.setupParameter(GATE_HOLD_STAGE, 0.0f, 0.0f, m_delaySamples, ParameterAutomation<float>::Function::HOLD);
m_clearFeedbackAuto.setupParameter(GATE_CLOSE_STAGE, 0.0f, 1.0f, 1000.0f, ParameterAutomation<float>::Function::EXPONENTIAL);
}
void AudioEffectSOS::update(void)
{
audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples
// Check is block is disabled
if (m_enable == false) {
// do not transmit or process any audio, return as quickly as possible.
if (inputAudioBlock) release(inputAudioBlock);
// release all held memory resources
if (m_previousBlock) {
release(m_previousBlock); m_previousBlock = nullptr;
@ -99,6 +96,8 @@ void AudioEffectSOS::update(void)
return;
}
audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples
// Check is block is bypassed, if so either transmit input directly or create silence
if ( (m_bypass == true) || (!inputAudioBlock) ) {
// transmit the input directly
@ -138,11 +137,7 @@ void AudioEffectSOS::update(void)
// mix the input with the feedback path in the pre-processing stage
m_preProcessing(preProcessed, inputAudioBlock, m_previousBlock);
// consider doing the BBD post processing here to use up more time while waiting
// for the read data to come back
audio_block_t *blockToRelease = m_memory->addBlock(preProcessed);
//audio_block_t *blockToRelease = m_memory->addBlock(inputAudioBlock);
//Serial.println("Done adding new block");
// BACK TO OUTPUT PROCESSING
@ -158,15 +153,14 @@ void AudioEffectSOS::update(void)
release(inputAudioBlock);
if (m_previousBlock)
release(m_previousBlock);
if (m_previousBlock) { release(m_previousBlock); }
m_previousBlock = blockToOutput;
if (m_blockToRelease == m_previousBlock) {
Serial.println("ERROR: POINTER COLLISION");
}
if (m_blockToRelease) release(m_blockToRelease);
if (m_blockToRelease) { release(m_blockToRelease); }
m_blockToRelease = blockToRelease;
}
@ -176,14 +170,12 @@ void AudioEffectSOS::gateOpenTime(float milliseconds)
// TODO - change the paramter automation to an automation sequence
m_openTimeMs = milliseconds;
m_inputGateAuto.setupParameter(GATE_OPEN_STAGE, 0.0f, 1.0f, m_openTimeMs, ParameterAutomation<float>::Function::EXPONENTIAL);
//m_clearFeedbackAuto.setupParameter(GATE_OPEN_STAGE, 1.0f, 0.0f, m_openTimeMs, ParameterAutomation<float>::Function::EXPONENTIAL);
}
void AudioEffectSOS::gateCloseTime(float milliseconds)
{
m_closeTimeMs = milliseconds;
m_inputGateAuto.setupParameter(GATE_CLOSE_STAGE, 1.0f, 0.0f, m_closeTimeMs, ParameterAutomation<float>::Function::EXPONENTIAL);
//m_clearFeedbackAuto.setupParameter(GATE_CLOSE_STAGE, 0.0f, 1.0f, m_closeTimeMs, ParameterAutomation<float>::Function::EXPONENTIAL);
}
////////////////////////////////////////////////////////////////////////

@ -28,17 +28,16 @@ AudioEffectTremolo::~AudioEffectTremolo()
void AudioEffectTremolo::update(void)
{
audio_block_t *inputAudioBlock = receiveWritable(); // get the next block of input samples
// Check is block is disabled
if (m_enable == false) {
// do not transmit or process any audio, return as quickly as possible.
return;
}
// Check is block is disabled
if (m_enable == false) {
// do not transmit or process any audio, return as quickly as possible.
if (inputAudioBlock) release(inputAudioBlock);
return;
}
audio_block_t *inputAudioBlock = receiveWritable(); // get the next block of input samples
// Check is block is bypassed, if so either transmit input directly or create silence
if (m_bypass == true) {
if ((m_bypass == true) || (!inputAudioBlock)) {
// transmit the input directly
if (!inputAudioBlock) {
// create silence

@ -26,18 +26,18 @@ namespace BALibrary {
BAGpio::BAGpio()
{
// Set all GPIOs to input
pinMode(static_cast<uint8_t>(GPIO::GPIO0), INPUT);
pinMode(static_cast<uint8_t>(GPIO::GPIO1), INPUT);
pinMode(static_cast<uint8_t>(GPIO::GPIO2), INPUT);
pinMode(static_cast<uint8_t>(GPIO::GPIO3), INPUT);
pinMode(static_cast<uint8_t>(GPIO::GPIO4), INPUT);
pinMode(static_cast<uint8_t>(GPIO::GPIO5), INPUT);
pinMode(static_cast<uint8_t>(GPIO::GPIO6), INPUT);
pinMode(static_cast<uint8_t>(GPIO::GPIO7), INPUT);
pinMode(static_cast<uint8_t>(GPIO::TP1), INPUT);
pinMode(static_cast<uint8_t>(GPIO::TP2), INPUT);
pinMode(GPIO0, INPUT);
pinMode(GPIO1, INPUT);
pinMode(GPIO2, INPUT);
pinMode(GPIO3, INPUT);
pinMode(GPIO4, INPUT);
pinMode(GPIO5, INPUT);
pinMode(GPIO6, INPUT);
pinMode(GPIO7, INPUT);
pinMode(TP1, INPUT);
pinMode(TP2, INPUT);
// Set the LED ot ouput
// Set the LED to ouput
pinMode(USR_LED_ID, OUTPUT);
clearLed(); // turn off the LED
@ -49,21 +49,21 @@ BAGpio::~BAGpio()
void BAGpio::setGPIODirection(GPIO gpioId, int direction)
{
pinMode(static_cast<uint8_t>(gpioId), direction);
pinMode(enumToPinNumber(gpioId), direction);
}
void BAGpio::setGPIO(GPIO gpioId)
{
digitalWrite(static_cast<uint8_t>(gpioId), 0x1);
digitalWrite(enumToPinNumber(gpioId), 0x1);
}
void BAGpio::clearGPIO(GPIO gpioId)
{
digitalWrite(static_cast<uint8_t>(gpioId), 0);
digitalWrite(enumToPinNumber(gpioId), 0);
}
int BAGpio::toggleGPIO(GPIO gpioId)
{
int data = digitalRead(static_cast<uint8_t>(gpioId));
digitalWrite(static_cast<uint8_t>(gpioId), ~data);
int data = digitalRead(enumToPinNumber(gpioId));
digitalWrite(enumToPinNumber(gpioId), ~data);
return ~data;
}
@ -84,5 +84,24 @@ int BAGpio::toggleLed()
return m_ledState;
}
uint8_t enumToPinNumber(GPIO gpio)
{
uint8_t pinNumber;
switch(gpio) {
case GPIO::GPIO0 : pinNumber = GPIO0; break;
case GPIO::GPIO1 : pinNumber = GPIO1; break;
case GPIO::GPIO2 : pinNumber = GPIO2; break;
case GPIO::GPIO3 : pinNumber = GPIO3; break;
case GPIO::GPIO4 : pinNumber = GPIO4; break;
case GPIO::GPIO5 : pinNumber = GPIO5; break;
case GPIO::GPIO6 : pinNumber = GPIO6; break;
case GPIO::GPIO7 : pinNumber = GPIO7; break;
case GPIO::TP1 : pinNumber = TP1; break;
case GPIO::TP2 : pinNumber = TP2; break;
default : pinNumber = 0; break;
}
return pinNumber;
}
} /* namespace BALibrary */

@ -265,12 +265,22 @@ bool Potentiometer::getValue(float &value) {
return false;
}
}
m_lastValidValue = m_lastValue;
// Convert the integer reading to a float value range 0.0 to 1.0f
if (valFilter < m_minCalibrationThresholded) { value = 0.0f; }
else if (valFilter > m_maxCalibrationThresholded) { value = 1.0f; }
if (valFilter < m_minCalibrationThresholded) {
m_lastValue = m_minCalibrationThresholded;
if (m_lastValidValue == m_minCalibrationThresholded) { return false; }
m_lastValidValue = m_lastValue;
value = 0.0f;
}
else if (valFilter > m_maxCalibrationThresholded) {
m_lastValue = m_maxCalibrationThresholded;
if (m_lastValidValue == m_maxCalibrationThresholded) { return false; }
m_lastValidValue = m_lastValue;
value = 1.0f;
}
else {
m_lastValidValue = m_lastValue;
value = static_cast<float>(valFilter - m_minCalibrationThresholded) / static_cast<float>(m_rangeThresholded);
}
@ -319,6 +329,9 @@ void Potentiometer::setChangeThreshold(float changeThreshold)
Potentiometer::Calib Potentiometer::calibrate(uint8_t pin) {
Calib calib;
// Flush the serial port input buffer
while (Serial.available() > 0) {}
Serial.print("Calibration pin "); Serial.println(pin);
Serial.println("Move the pot fully counter-clockwise to the minimum setting and press any key then ENTER");
while (true) {

@ -24,19 +24,19 @@
namespace BALibrary {
// MEM0 Settings
constexpr int SPI_CS_MEM0 = SPI0_CS_PIN;
constexpr int SPI_MOSI_MEM0 = SPI0_MOSI_PIN;
constexpr int SPI_MISO_MEM0 = SPI0_MISO_PIN;
constexpr int SPI_SCK_MEM0 = SPI0_SCK_PIN;
#if defined(SPI1_AVAILABLE)
// MEM1 Settings
constexpr int SPI_CS_MEM1 = SPI1_CS_PIN;
constexpr int SPI_MOSI_MEM1 = SPI1_MOSI_PIN;
constexpr int SPI_MISO_MEM1 = SPI1_MISO_PIN;
constexpr int SPI_SCK_MEM1 = SPI1_SCK_PIN;
#endif
//// MEM0 Settings
//int SPI_CS_MEM0 = SPI0_CS_PIN;
//int SPI_MOSI_MEM0 = SPI0_MOSI_PIN;
//int SPI_MISO_MEM0 = SPI0_MISO_PIN;
//int SPI_SCK_MEM0 = SPI0_SCK_PIN;
//
//#if defined(SPI1_AVAILABLE)
//// MEM1 Settings
//int SPI_CS_MEM1 = SPI1_CS_PIN;
//int SPI_MOSI_MEM1 = SPI1_MOSI_PIN;
//int SPI_MISO_MEM1 = SPI1_MISO_PIN;
//int SPI_SCK_MEM1 = SPI1_SCK_PIN;
//#endif
// SPI Constants
constexpr int SPI_WRITE_MODE_REG = 0x1;
@ -73,22 +73,22 @@ void BASpiMemory::begin()
{
switch (m_memDeviceId) {
case SpiDeviceId::SPI_DEVICE0 :
m_csPin = SPI_CS_MEM0;
m_csPin = SPI0_CS_PIN;
m_spi = &SPI;
m_spi->setMOSI(SPI_MOSI_MEM0);
m_spi->setMISO(SPI_MISO_MEM0);
m_spi->setSCK(SPI_SCK_MEM0);
m_spi->setMOSI(SPI0_MOSI_PIN);
m_spi->setMISO(SPI0_MISO_PIN);
m_spi->setSCK(SPI0_SCK_PIN);
m_spi->begin();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
break;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case SpiDeviceId::SPI_DEVICE1 :
m_csPin = SPI_CS_MEM1;
m_csPin = SPI1_CS_PIN;
m_spi = &SPI1;
m_spi->setMOSI(SPI_MOSI_MEM1);
m_spi->setMISO(SPI_MISO_MEM1);
m_spi->setSCK(SPI_SCK_MEM1);
m_spi->setMOSI(SPI1_MOSI_PIN);
m_spi->setMISO(SPI1_MISO_PIN);
m_spi->setSCK(SPI1_SCK_PIN);
m_spi->begin();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM1).DIE_BOUNDARY;
break;
@ -367,17 +367,17 @@ BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId)
int cs;
switch (memDeviceId) {
case SpiDeviceId::SPI_DEVICE0 :
cs = SPI_CS_MEM0;
cs = SPI0_CS_PIN;
m_cs = new ActiveLowChipSelect(cs, m_settings);
break;
#if defined(__MK66FX1M0__)
case SpiDeviceId::SPI_DEVICE1 :
cs = SPI_CS_MEM1;
cs = SPI1_CS_PIN;
m_cs = new ActiveLowChipSelect1(cs, m_settings);
break;
#endif
default :
cs = SPI_CS_MEM0;
cs = SPI0_CS_PIN;
}
// add 4 bytes to buffer for SPI CMD and 3 bytes of address
@ -393,17 +393,17 @@ BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId, uint32_t speedHz)
int cs;
switch (memDeviceId) {
case SpiDeviceId::SPI_DEVICE0 :
cs = SPI_CS_MEM0;
cs = SPI0_CS_PIN;
m_cs = new ActiveLowChipSelect(cs, m_settings);
break;
#if defined(__MK66FX1M0__)
case SpiDeviceId::SPI_DEVICE1 :
cs = SPI_CS_MEM1;
cs = SPI1_CS_PIN;
m_cs = new ActiveLowChipSelect1(cs, m_settings);
break;
#endif
default :
cs = SPI_CS_MEM0;
cs = SPI0_CS_PIN;
}
m_txCommandBuffer = new uint8_t[CMD_ADDRESS_SIZE];
@ -433,11 +433,11 @@ void BASpiMemoryDMA::begin(void)
{
switch (m_memDeviceId) {
case SpiDeviceId::SPI_DEVICE0 :
m_csPin = SPI_CS_MEM0;
m_csPin = SPI0_CS_PIN;
m_spi = &SPI;
m_spi->setMOSI(SPI_MOSI_MEM0);
m_spi->setMISO(SPI_MISO_MEM0);
m_spi->setSCK(SPI_SCK_MEM0);
m_spi->setMOSI(SPI0_MOSI_PIN);
m_spi->setMISO(SPI0_MISO_PIN);
m_spi->setSCK(SPI0_SCK_PIN);
m_spi->begin();
m_spiDma = new DmaSpiGeneric();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
@ -445,11 +445,11 @@ void BASpiMemoryDMA::begin(void)
#if defined(__MK66FX1M0__) // DMA on SPI1 is only supported on T3.6
case SpiDeviceId::SPI_DEVICE1 :
m_csPin = SPI_CS_MEM1;
m_csPin = SPI1_CS_PIN;
m_spi = &SPI1;
m_spi->setMOSI(SPI_MOSI_MEM1);
m_spi->setMISO(SPI_MISO_MEM1);
m_spi->setSCK(SPI_SCK_MEM1);
m_spi->setMOSI(SPI1_MOSI_PIN);
m_spi->setMISO(SPI1_MISO_PIN);
m_spi->setSCK(SPI1_SCK_PIN);
m_spi->begin();
m_spiDma = new DmaSpiGeneric(1);
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM1).DIE_BOUNDARY;
@ -478,6 +478,8 @@ void BASpiMemoryDMA::write(size_t address, uint8_t *src, size_t numBytes)
size_t nextAddress = address;
uint8_t *intermediateBuffer = nullptr;
while ( m_txTransfer[1].busy() || m_txTransfer[0].busy()) { yield(); } // wait until not busy
// Check for intermediate buffer use
if (m_dmaCopyBufferSize) {
// copy to the intermediate buffer;
@ -487,8 +489,6 @@ void BASpiMemoryDMA::write(size_t address, uint8_t *src, size_t numBytes)
while (bytesRemaining > 0) {
m_txXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_txTransfer[1].busy() || m_txTransfer[0].busy()) { yield(); } // wait until not busy
m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer);
m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS);
m_spiDma->registerTransfer(m_txTransfer[1]);
@ -559,14 +559,13 @@ void BASpiMemoryDMA::read(size_t address, uint8_t *dest, size_t numBytes)
}
while (bytesRemaining > 0) {
m_rxXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_rxTransfer[1].busy() || m_rxTransfer[0].busy()) { yield(); }
m_rxXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
m_setSpiCmdAddr(SPI_READ_CMD, nextAddress, m_rxCommandBuffer);
while ( m_rxTransfer[1].busy() || m_rxTransfer[0].busy()) { yield(); }
m_rxTransfer[1] = DmaSpi::Transfer(m_rxCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS);
m_spiDma->registerTransfer(m_rxTransfer[1]);
while ( m_rxTransfer[0].busy() || m_rxTransfer[1].busy()) { yield(); }
m_rxTransfer[0] = DmaSpi::Transfer(nullptr, m_rxXferCount, destPtr, 0, m_cs, TransferType::NO_START_CS, nullptr, intermediateBuffer);
m_spiDma->registerTransfer(m_rxTransfer[0]);
@ -615,7 +614,6 @@ bool BASpiMemoryDMA::setDmaCopyBufferSize(size_t numBytes)
m_dmaReadCopyBuffer = (volatile uint8_t*)dma_aligned_malloc(MEM_ALIGNED_ALLOC, numBytes);
if (!m_dmaReadCopyBuffer) {
// allocate failed
m_dmaCopyBufferSize = 0;
return false;
}

Loading…
Cancel
Save