Add multiverse support (#19)

Add support for Aviate Audio Multiverse
master
Blackaddr Audio 1 year ago committed by GitHub
parent f70bc3b748
commit 2ad4882ab9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 51
      examples/Delay/AnalogDelayDemo/AnalogDelayDemo.ino
  2. 63
      examples/Delay/AnalogDelayDemoExpansion/AnalogDelayDemoExpansion.ino
  3. 18
      examples/Delay/ExternalDelayDemo/ExternalDelayDemo.ino
  4. 53
      examples/Delay/SoundOnSoundDemo/SoundOnSoundDemo.ino
  5. 62
      examples/Delay/SoundOnSoundExpansionDemo/SoundOnSoundExpansionDemo.ino
  6. 46
      examples/Modulation/TemoloDemo/TemoloDemo.ino
  7. 54
      examples/Modulation/TremoloDemoExpansion/TremoloDemoExpansion.ino
  8. 2
      examples/Tests/DMA_MEM0_test/DMA_MEM0_test.ino
  9. 77
      examples/Tests/DMA_MEM1_test/DMA_MEM1_test.ino
  10. 9
      examples/Tests/Multiverse_BasicDemo/DebugPrintf.h
  11. 285
      examples/Tests/Multiverse_BasicDemo/Multiverse_BasicDemo.ino
  12. 222
      examples/Tests/Multiverse_BasicDemo/PhysicalControls.cpp
  13. 11
      examples/Tests/Multiverse_BasicDemo/PhysicalControls.h
  14. 14
      examples/Tests/TGA_PRO_Basic_Test/PhysicalControls.cpp
  15. 35
      examples/Tests/TGA_PRO_Basic_Test/TGA_PRO_Basic_Test.ino
  16. 21
      examples/Tests/TGA_PRO_Basic_Test/UartTest.cpp
  17. 30
      examples/Tests/TGA_PRO_Basic_Test/spiTest.cpp
  18. 35
      src/BAHardware.h
  19. 16
      src/BAPhysicalControls.h
  20. 14
      src/BATypes.h
  21. 136
      src/DmaSpi.h
  22. 52
      src/LibMemoryManagement.h
  23. 10
      src/common/AudioDelay.cpp
  24. 74
      src/common/BAHardware.cpp
  25. 157
      src/common/ExtMemSlot.cpp
  26. 16
      src/common/ExternalSramManager.cpp
  27. 20
      src/common/ParameterAutomation.cpp
  28. 53
      src/effects/AudioEffectAnalogDelay.cpp
  29. 2
      src/effects/AudioEffectDelayExternal.cpp
  30. 28
      src/effects/AudioEffectRmsMeasure.cpp
  31. 39
      src/effects/AudioEffectSOS.cpp
  32. 38
      src/effects/AudioEffectTremolo.cpp
  33. 9
      src/peripherals/BAAudioControlWM8731.cpp
  34. 14
      src/peripherals/BAPhysicalControls.cpp
  35. 20
      src/peripherals/BASpiMemory.cpp
  36. 43
      src/peripherals/DmaSpi.cpp

@ -1,17 +1,17 @@
/************************************************************************* /*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of * This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board. * the TGA Pro board.
* *
* The latest copy of the BA Guitar library can be obtained from * The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary * https://github.com/Blackaddr/BALibrary
* *
* This example demonstrates teh BAAudioEffectsAnalogDelay effect. It can * This example demonstrates teh BAAudioEffectsAnalogDelay effect. It can
* be controlled using USB MIDI. You can get a free USB MIDI Controller * be controlled using USB MIDI. You can get a free USB MIDI Controller
* appliation at * appliation at
* http://www.blackaddr.com/downloads/BAMidiTester/ * http://www.blackaddr.com/downloads/BAMidiTester/
* or the source code at * or the source code at
* https://github.com/Blackaddr/BAMidiTester * https://github.com/Blackaddr/BAMidiTester
* *
* Even if you don't control the guitar effect with USB MIDI, you must set * 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" * the Arduino IDE USB-Type under Tools to "Serial + MIDI"
*/ */
@ -76,14 +76,16 @@ elapsedMillis timer;
void OnControlChange(byte channel, byte control, byte value) { void OnControlChange(byte channel, byte control, byte value) {
analogDelay.processMidi(channel-1, control, value); analogDelay.processMidi(channel-1, control, value);
#ifdef MIDI_DEBUG #ifdef MIDI_DEBUG
Serial.print("Control Change, ch="); if (Serial) {
Serial.print(channel, DEC); Serial.print("Control Change, ch=");
Serial.print(", control="); Serial.print(channel, DEC);
Serial.print(control, DEC); Serial.print(", control=");
Serial.print(", value="); Serial.print(control, DEC);
Serial.print(value, DEC); Serial.print(", value=");
Serial.println(); Serial.print(value, DEC);
#endif Serial.println();
}
#endif
} }
void setup() { void setup() {
@ -96,7 +98,7 @@ void setup() {
//SPI_MEM0_4M(); // Older REVA and REVB boards came with 4M or 1M //SPI_MEM0_4M(); // Older REVA and REVB boards came with 4M or 1M
//SPI_MEM0_1M(); //SPI_MEM0_1M();
#endif #endif
delay(100); delay(100);
Serial.begin(57600); // Start the serial port Serial.begin(57600); // Start the serial port
@ -107,18 +109,19 @@ void setup() {
delay(5); delay(5);
// Enable the codec // Enable the codec
Serial.println("Enabling codec...\n"); if (Serial) { Serial.println("Enabling codec...\n"); }
codec.enable(); codec.enable();
delay(100); delay(100);
// If using external memory request request memory from the manager // If using external memory request request memory from the manager
// for the slot // for the slot
#ifdef USE_EXT #ifdef USE_EXT
Serial.println("Using EXTERNAL memory"); if (Serial) { Serial.println("Using EXTERNAL memory"); }
// We have to request memory be allocated to our slot. // We have to request memory be allocated to our slot.
externalSram.requestMemory(&delaySlot, 500.0f, MemSelect::MEM0, true); externalSram.requestMemory(&delaySlot, 500.0f, MemSelect::MEM0, true);
delaySlot.clear();
#else #else
Serial.println("Using INTERNAL memory"); if (Serial) { Serial.println("Using INTERNAL memory"); }
#endif #endif
// Setup MIDI // Setup MIDI
@ -126,7 +129,7 @@ void setup() {
MIDI.setHandleControlChange(OnControlChange); MIDI.setHandleControlChange(OnControlChange);
usbMIDI.setHandleControlChange(OnControlChange); usbMIDI.setHandleControlChange(OnControlChange);
// Configure which MIDI CC's will control the effect parameters // Configure which MIDI CC's will control the effect parameters
analogDelay.mapMidiControl(AudioEffectAnalogDelay::BYPASS,16); analogDelay.mapMidiControl(AudioEffectAnalogDelay::BYPASS,16);
analogDelay.mapMidiControl(AudioEffectAnalogDelay::DELAY,20); analogDelay.mapMidiControl(AudioEffectAnalogDelay::DELAY,20);
@ -136,7 +139,7 @@ void setup() {
// Besure to enable the delay. When disabled, audio is is completely blocked // Besure to enable the delay. When disabled, audio is is completely blocked
// to minimize resources to nearly zero. // to minimize resources to nearly zero.
analogDelay.enable(); analogDelay.enable();
// Set some default values. // Set some default values.
// These can be changed by sending MIDI CC messages over the USB using // These can be changed by sending MIDI CC messages over the USB using
@ -162,13 +165,15 @@ void setup() {
void loop() { void loop() {
// usbMIDI.read() needs to be called rapidly from loop(). // usbMIDI.read() needs to be called rapidly from loop().
if (timer > 1000) { if (timer > 1000) {
timer = 0; timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage()); if (Serial) {
Serial.print("% "); Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print(" analogDelay: "); Serial.print(analogDelay.processorUsage()); Serial.print("% ");
Serial.println("%"); Serial.print(" analogDelay: "); Serial.print(analogDelay.processorUsage());
Serial.println("%");
}
} }
MIDI.read(); MIDI.read();

@ -1,24 +1,24 @@
/************************************************************************* /*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of * This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board. * the TGA Pro board.
* *
* The latest copy of the BA Guitar library can be obtained from * The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary * https://github.com/Blackaddr/BALibrary
* *
* This example demonstrates teh BAAudioEffectsAnalogDelay effect. It can * This example demonstrates teh BAAudioEffectsAnalogDelay effect. It can
* be controlled using the Blackaddr Audio "Expansion Control Board". * be controlled using the Blackaddr Audio "Expansion Control Board".
* *
* POT1 (left) controls amount of delay * POT1 (left) controls amount of delay
* POT2 (right) controls amount of feedback * POT2 (right) controls amount of feedback
* POT3 (center) controls the wet/dry mix * POT3 (center) controls the wet/dry mix
* SW1 will enable/bypass the audio effect. LED1 will be on when effect is enabled. * 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 analog filters. LED2 will be on when SW2 is pressed.
* *
* !!! SET POTS TO REASONABLE VALUES BEFORE STARTING TO AVOID SCREECHING FEEDBACK!!!! * !!! SET POTS TO REASONABLE VALUES BEFORE STARTING TO AVOID SCREECHING FEEDBACK!!!!
* - set POT1 (delay) fully counter-clockwise then increase it slowly. * - set POT1 (delay) fully counter-clockwise then increase it slowly.
* - set POT2 (feedback) fully counter-clockwise, then increase it slowly * - set POT2 (feedback) fully counter-clockwise, then increase it slowly
* - set POT3 (wet/dry mix) to half-way at the detent. * - set POT3 (wet/dry mix) to half-way at the detent.
* *
* Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease * Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease
* the headphone volume between values of 0 and 9. * the headphone volume between values of 0 and 9.
*/ */
@ -79,7 +79,7 @@ AudioConnection rightOut(analogDelay,0, i2sOut, 1);
// - LED2 (right) will illuminate when pressing SW2. // - LED2 (right) will illuminate when pressing SW2.
////////////////////////////////////////// //////////////////////////////////////////
// To get the calibration values for your particular board, first run the // To get the calibration values for your particular board, first run the
// BAExpansionCalibrate.ino example and // BAExpansionCalibrate.ino example and
constexpr int potCalibMin = 1; constexpr int potCalibMin = 1;
constexpr int potCalibMax = 1018; constexpr int potCalibMax = 1018;
constexpr bool potSwapDirection = true; constexpr bool potSwapDirection = true;
@ -100,27 +100,27 @@ void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using. TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x); //TGA_PRO_REVB(x);
//TGA_PRO_REVA(x); //TGA_PRO_REVA(x);
#ifdef USE_EXT #ifdef USE_EXT
SPI_MEM0_64M(); // Optional 64Mbit SPI RAM SPI_MEM0_64M(); // Optional 64Mbit SPI RAM
//SPI_MEM0_4M(); // Older REVB and REVA boards offered 1M or 4M //SPI_MEM0_4M(); // Older REVB and REVA boards offered 1M or 4M
//SPI_MEM0_1M(); //SPI_MEM0_1M();
#endif #endif
delay(100); // wait a bit for serial to be available delay(100); // wait a bit for serial to be available
Serial.begin(57600); // Start the serial port Serial.begin(57600); // Start the serial port
delay(100); delay(100);
// Configure the hardware // Configure the hardware
// Setup the controls. The return value is the handle to use when checking for control changes, etc. // Setup the controls. The return value is the handle to use when checking for control changes, etc.
// pushbuttons // pushbuttons
bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control
filterHandle = controls.addSwitch(BA_EXPAND_SW2_PIN); // will be used for stepping through filters filterHandle = controls.addSwitch(BA_EXPAND_SW2_PIN); // will be used for stepping through filters
// pots // pots
delayHandle = controls.addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection); // control the amount of delay delayHandle = controls.addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection); // control the amount of delay
feedbackHandle = controls.addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection); feedbackHandle = controls.addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection);
mixHandle = controls.addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection); mixHandle = controls.addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection);
// leds // leds
led1Handle = controls.addOutput(BA_EXPAND_LED1_PIN); led1Handle = controls.addOutput(BA_EXPAND_LED1_PIN);
led2Handle = controls.addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2 led2Handle = controls.addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2
@ -130,28 +130,29 @@ void setup() {
AudioMemory(128); AudioMemory(128);
// Enable and configure the codec // Enable and configure the codec
Serial.println("Enabling codec...\n"); if (Serial) { Serial.println("Enabling codec...\n"); }
codec.enable(); codec.enable();
codec.setHeadphoneVolume(1.0f); // Max headphone volume codec.setHeadphoneVolume(1.0f); // Max headphone volume
// If using external memory request request memory from the manager // If using external memory request request memory from the manager
// for the slot // for the slot
#ifdef USE_EXT #ifdef USE_EXT
Serial.println("Using EXTERNAL memory"); if (Serial) { Serial.println("Using EXTERNAL memory"); }
// We have to request memory be allocated to our slot. // We have to request memory be allocated to our slot.
externalSram.requestMemory(&delaySlot, 500.0f, MemSelect::MEM0, true); externalSram.requestMemory(&delaySlot, 500.0f, MemSelect::MEM0, true);
delaySlot.clear();
#else #else
Serial.println("Using INTERNAL memory"); if (Serial) { Serial.println("Using INTERNAL memory"); }
#endif #endif
// Besure to enable the delay. When disabled, audio is is completely blocked by the effect // Besure to enable the delay. When disabled, audio is is completely blocked by the effect
// to minimize resource usage to nearly to nearly zero. // to minimize resource usage to nearly to nearly zero.
analogDelay.enable(); analogDelay.enable();
// Set some default values. // Set some default values.
// These can be changed using the controls on the Blackaddr Audio Expansion Board // These can be changed using the controls on the Blackaddr Audio Expansion Board
analogDelay.bypass(false); analogDelay.bypass(false);
controls.setOutput(led1Handle, !analogDelay.isBypass()); // Set the LED when NOT bypassed controls.setOutput(led1Handle, !analogDelay.isBypass()); // Set the LED when NOT bypassed
analogDelay.mix(0.5f); analogDelay.mix(0.5f);
analogDelay.feedback(0.0f); analogDelay.feedback(0.0f);
@ -178,8 +179,8 @@ void loop() {
bool bypass = analogDelay.isBypass(); // get the current state bool bypass = analogDelay.isBypass(); // get the current state
bypass = !bypass; // change it bypass = !bypass; // change it
analogDelay.bypass(bypass); // set the new state analogDelay.bypass(bypass); // set the new state
controls.setOutput(led1Handle, !bypass); // Set the LED when NOT bypassed controls.setOutput(led1Handle, !bypass); // Set the LED when NOT bypassed
Serial.println(String("BYPASS is ") + bypass); if (Serial) { Serial.println(String("BYPASS is ") + bypass); }
} }
// Use SW2 to cycle through the filters // Use SW2 to cycle through the filters
@ -188,27 +189,27 @@ void loop() {
filterIndex = (filterIndex + 1) % 3; // update and potentionall roll the counter 0, 1, 2, 0, 1, 2, ... filterIndex = (filterIndex + 1) % 3; // update and potentionall roll the counter 0, 1, 2, 0, 1, 2, ...
// cast the index between 0 to 2 to the enum class AudioEffectAnalogDelay::Filter // cast the index between 0 to 2 to the enum class AudioEffectAnalogDelay::Filter
analogDelay.setFilter(static_cast<AudioEffectAnalogDelay::Filter>(filterIndex)); // will cycle through 0 to 2 analogDelay.setFilter(static_cast<AudioEffectAnalogDelay::Filter>(filterIndex)); // will cycle through 0 to 2
Serial.println(String("Filter set to ") + filterIndex); if (Serial) { Serial.println(String("Filter set to ") + filterIndex); }
} }
// Use POT1 (left) to control the delay setting // Use POT1 (left) to control the delay setting
if (controls.checkPotValue(delayHandle, potValue)) { if (controls.checkPotValue(delayHandle, potValue)) {
// Pot has changed // Pot has changed
Serial.println(String("New DELAY setting: ") + potValue); if (Serial) { Serial.println(String("New DELAY setting: ") + potValue); }
analogDelay.delayFractionMax(potValue); analogDelay.delayFractionMax(potValue);
} }
// Use POT2 (right) to control the feedback setting // Use POT2 (right) to control the feedback setting
if (controls.checkPotValue(feedbackHandle, potValue)) { if (controls.checkPotValue(feedbackHandle, potValue)) {
// Pot has changed // Pot has changed
Serial.println(String("New FEEDBACK setting: ") + potValue); if (Serial) { Serial.println(String("New FEEDBACK setting: ") + potValue); }
analogDelay.feedback(potValue); analogDelay.feedback(potValue);
} }
// Use POT3 (centre) to control the mix setting // Use POT3 (centre) to control the mix setting
if (controls.checkPotValue(mixHandle, potValue)) { if (controls.checkPotValue(mixHandle, potValue)) {
// Pot has changed // Pot has changed
Serial.println(String("New MIX setting: ") + potValue); if (Serial) { Serial.println(String("New MIX setting: ") + potValue); }
analogDelay.mix(potValue); analogDelay.mix(potValue);
} }
@ -217,11 +218,11 @@ void loop() {
if (Serial.available() > 0) { if (Serial.available() > 0) {
while (Serial.available()) { while (Serial.available()) {
char key = Serial.read(); char key = Serial.read();
if (key == 'u') { if (key == 'u') {
headphoneVolume = (headphoneVolume + 1) % MAX_HEADPHONE_VOL; headphoneVolume = (headphoneVolume + 1) % MAX_HEADPHONE_VOL;
Serial.println(String("Increasing HEADPHONE volume to ") + headphoneVolume); Serial.println(String("Increasing HEADPHONE volume to ") + headphoneVolume);
} }
else if (key == 'd') { else if (key == 'd') {
headphoneVolume = (headphoneVolume - 1) % MAX_HEADPHONE_VOL; headphoneVolume = (headphoneVolume - 1) % MAX_HEADPHONE_VOL;
Serial.println(String("Decreasing HEADPHONE volume to ") + headphoneVolume); Serial.println(String("Decreasing HEADPHONE volume to ") + headphoneVolume);
} }
@ -231,13 +232,15 @@ void loop() {
} }
delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected. delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected.
if (timer > 1000) { if (timer > 1000) {
timer = 0; timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage()); if (Serial) {
Serial.print("% "); Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print(" analogDelay: "); Serial.print(analogDelay.processorUsage()); Serial.print("% ");
Serial.println("%"); Serial.print(" analogDelay: "); Serial.print(analogDelay.processorUsage());
Serial.println("%");
}
} }
} }

@ -1,15 +1,15 @@
/************************************************************************* /*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of * This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board. * the TGA Pro board.
* *
* The latest copy of the BA Guitar library can be obtained from * The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary * https://github.com/Blackaddr/BALibrary
* *
* This demo shows to use the BAAudioEffectDelayExternal audio class * This demo shows to use the BAAudioEffectDelayExternal audio class
* to create long delays using external SPI RAM. * to create long delays using external SPI RAM.
* *
* Eight delay taps are configured from a single SRAM device. * Eight delay taps are configured from a single SRAM device.
* *
*/ */
#include <Audio.h> #include <Audio.h>
#include "BALibrary.h" #include "BALibrary.h"
@ -60,12 +60,12 @@ void setup() {
Serial.begin(57600); Serial.begin(57600);
delay(200); delay(200);
AudioMemory(64); AudioMemory(64);
delay(500); delay(500);
Serial.println(String("Starting...\n")); if (Serial) { Serial.println(String("Starting...\n")); }
delay(100); delay(100);
Serial.println("Enabling codec...\n"); if (Serial) { Serial.println("Enabling codec...\n"); }
codecControl.enable(); codecControl.enable();
delay(100); delay(100);
@ -90,12 +90,12 @@ void setup() {
delayOutMixerB.gain(1, 0.05f); delayOutMixerB.gain(1, 0.05f);
delayOutMixerB.gain(2, 0.025f); delayOutMixerB.gain(2, 0.025f);
delayOutMixerB.gain(3, 0.0125f); delayOutMixerB.gain(3, 0.0125f);
// mix the original signal with the two delay mixers // mix the original signal with the two delay mixers
delayMixer.gain(0, 1.0f); delayMixer.gain(0, 1.0f);
delayMixer.gain(1, 1.0f); delayMixer.gain(1, 1.0f);
delayMixer.gain(2, 1.0f); delayMixer.gain(2, 1.0f);
} }
void loop() { void loop() {

@ -1,21 +1,21 @@
/************************************************************************* /*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of * This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board. * the TGA Pro board.
* *
* The latest copy of the BA Guitar library can be obtained from * The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary * https://github.com/Blackaddr/BALibrary
* *
* THIS DEMO REQUIRES THE EXTERNAL SRAM MEM0 * THIS DEMO REQUIRES THE EXTERNAL SRAM MEM0
* *
* This demo combines MIDI control with the BAAudioEffectSoundOnSound. You can use * This demo combines MIDI control with the BAAudioEffectSoundOnSound. You can use
* the BAMidiTester to control the effect but it's best to use external MIDI footswitch * the BAMidiTester to control the effect but it's best to use external MIDI footswitch
* or the Blackaddr Audio Expansion Control Board. * or the Blackaddr Audio Expansion Control Board.
* *
* User 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 * Afters startup, the effect will spend about 5 seconds clearing the audio delay buffer to prevent
* any startup pops or clicks from propagating. * any startup pops or clicks from propagating.
* *
*/ */
#include <Audio.h> #include <Audio.h>
#include <MIDI.h> #include <MIDI.h>
@ -84,14 +84,16 @@ elapsedMillis timer;
void OnControlChange(byte channel, byte control, byte value) { void OnControlChange(byte channel, byte control, byte value) {
sos.processMidi(channel-1, control, value); sos.processMidi(channel-1, control, value);
#ifdef MIDI_DEBUG #ifdef MIDI_DEBUG
Serial.print("Control Change, ch="); if (Serial) {
Serial.print(channel, DEC); Serial.print("Control Change, ch=");
Serial.print(", control="); Serial.print(channel, DEC);
Serial.print(control, DEC); Serial.print(", control=");
Serial.print(", value="); Serial.print(control, DEC);
Serial.print(value, DEC); Serial.print(", value=");
Serial.println(); Serial.print(value, DEC);
#endif Serial.println();
}
#endif
} }
void setup() { void setup() {
@ -109,20 +111,17 @@ void setup() {
// Disable the codec first // Disable the codec first
codec.disable(); codec.disable();
delay(100);
AudioMemory(128); AudioMemory(128);
delay(5);
SPI_MEM0_1M(); // Configure the SPI memory size SPI_MEM0_1M(); // Configure the SPI memory size
// Enable the codec // Enable the codec
Serial.println("Enabling codec...\n"); if (Serial) { Serial.println("Enabling codec...\n"); }
codec.enable(); codec.enable();
delay(100);
// We have to request memory be allocated to our slot. // We have to request memory be allocated to our slot.
externalSram.requestMemory(&delaySlot, BAHardwareConfig.getSpiMemSizeBytes(MemSelect::MEM0), MemSelect::MEM0, true); externalSram.requestMemory(&delaySlot, BAHardwareConfig.getSpiMemSizeBytes(MemSelect::MEM0), MemSelect::MEM0, true);
//externalSram.requestMemory(&delaySlot, 50.0f, MemSelect::MEM0, true); delaySlot.clear();
// Setup MIDI // Setup MIDI
MIDI.begin(MIDI_CHANNEL_OMNI); MIDI.begin(MIDI_CHANNEL_OMNI);
@ -131,7 +130,7 @@ void setup() {
// Configure the LED to indicate the gate status // Configure the LED to indicate the gate status
sos.setGateLedGpio(USR_LED_ID); sos.setGateLedGpio(USR_LED_ID);
// Configure which MIDI CC's will control the effect parameters // Configure which MIDI CC's will control the effect parameters
//sos.mapMidiControl(AudioEffectSOS::BYPASS,16); //sos.mapMidiControl(AudioEffectSOS::BYPASS,16);
sos.mapMidiControl(AudioEffectSOS::GATE_TRIGGER,16); sos.mapMidiControl(AudioEffectSOS::GATE_TRIGGER,16);
@ -143,7 +142,7 @@ void setup() {
// Besure to enable the delay. When disabled, audio is is completely blocked // Besure to enable the delay. When disabled, audio is is completely blocked
// to minimize resources to nearly zero. // to minimize resources to nearly zero.
sos.enable(); sos.enable();
// Set some default values. // Set some default values.
// These can be changed by sending MIDI CC messages over the USB using // These can be changed by sending MIDI CC messages over the USB using
@ -170,7 +169,7 @@ void setup() {
delay(1000); delay(1000);
sos.clear(); sos.clear();
} }
void loop() { void loop() {
@ -178,10 +177,12 @@ void loop() {
if (timer > 1000) { if (timer > 1000) {
timer = 0; timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage()); if (Serial) {
Serial.print("% "); Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print(" SOS: "); Serial.print(sos.processorUsage()); Serial.print("% ");
Serial.println("%"); Serial.print(" SOS: "); Serial.print(sos.processorUsage());
Serial.println("%");
}
} }
MIDI.read(); MIDI.read();

@ -1,29 +1,29 @@
/************************************************************************* /*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of * This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board. * the TGA Pro board.
* *
* The latest copy of the BA Guitar library can be obtained from * The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary * https://github.com/Blackaddr/BALibrary
* *
* THIS DEMO REQUIRES BOTH THE EXTERNAL SRAM AND EXPANSION BOARD ADD-ONS * THIS DEMO REQUIRES BOTH THE EXTERNAL SRAM AND EXPANSION BOARD ADD-ONS
* *
* This demo combines the Blackaddr Audio Expansion board with the BAAudioEffectSOS, * This demo combines the Blackaddr Audio Expansion board with the BAAudioEffectSOS,
* which provides sound-on-sound. The pushbuttons control the opening of the effect * which provides sound-on-sound. The pushbuttons control the opening of the effect
* gate, as well as clearing the sound being held. * gate, as well as clearing the sound being held.
* *
* The pots control the feedback, as well as the gate opening and close times. * 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 * Afters startup, the effect will spend about 5 seconds clearing the audio delay buffer to prevent
* any startup pops or clicks from propagating. * any startup pops or clicks from propagating.
* *
* POT1 - Gate open time. Middle position (detent) is about 2100 ms. * POT1 - Gate open time. Middle position (detent) is about 2100 ms.
* POT2 - gate close 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 * POT3 - Effect volume. Controls the volume of the SOS effect separate from the normal volume
* SW1 - Strum and hold a chord then push this button. Continue holding the button until the LED1 light goes out. * SW1 - Strum and hold a chord then push this button. Continue holding the button until the LED1 light goes out.
* SW2 - Push this button to clear out the sound circulating in the delay. * SW2 - Push this button to clear out the sound circulating in the delay.
* *
*/ */
#include <Audio.h> #include <Audio.h>
#include "BALibrary.h" #include "BALibrary.h"
#include "BAEffects.h" #include "BAEffects.h"
@ -86,7 +86,7 @@ AudioConnection outputRight(mixer, 0, i2sOut, 1);
// - LED2 (right) will illuminate when pressing SW2. // - LED2 (right) will illuminate when pressing SW2.
////////////////////////////////////////// //////////////////////////////////////////
// To get the calibration values for your particular board, first run the // To get the calibration values for your particular board, first run the
// BAExpansionCalibrate.ino example and // BAExpansionCalibrate.ino example and
constexpr int potCalibMin = 1; constexpr int potCalibMin = 1;
constexpr int potCalibMax = 1018; constexpr int potCalibMax = 1018;
constexpr bool potSwapDirection = true; constexpr bool potSwapDirection = true;
@ -114,7 +114,6 @@ void setup() {
//SPI_MEM0_4M(); // Older REVB / REVA boards offered 1M or 4M //SPI_MEM0_4M(); // Older REVB / REVA boards offered 1M or 4M
//SPI_MEM0_1M(); //SPI_MEM0_1M();
delay(100);
delay(100); // wait a bit for serial to be available delay(100); // wait a bit for serial to be available
Serial.begin(57600); // Start the serial port Serial.begin(57600); // Start the serial port
delay(100); // wait a bit for serial to be available delay(100); // wait a bit for serial to be available
@ -125,8 +124,8 @@ void setup() {
clearHandle = controls.addSwitch(BA_EXPAND_SW2_PIN); // will be used for stepping through filters clearHandle = controls.addSwitch(BA_EXPAND_SW2_PIN); // will be used for stepping through filters
// pots // pots
openHandle = controls.addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection); // control the amount of delay openHandle = controls.addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection); // control the amount of delay
closeHandle = controls.addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection); closeHandle = controls.addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection);
volumeHandle = controls.addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection); volumeHandle = controls.addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection);
// leds // leds
led1Handle = controls.addOutput(BA_EXPAND_LED1_PIN); led1Handle = controls.addOutput(BA_EXPAND_LED1_PIN);
led2Handle = controls.addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2 led2Handle = controls.addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2
@ -136,12 +135,13 @@ void setup() {
AudioMemory(128); AudioMemory(128);
// Enable the codec // Enable the codec
Serial.println("Enabling codec...\n"); if (Serial) { Serial.println("Enabling codec...\n"); }
codec.enable(); codec.enable();
codec.setHeadphoneVolume(1.0f); // Max headphone volume codec.setHeadphoneVolume(1.0f); // Max headphone volume
// We have to request memory be allocated to our slot. // We have to request memory be allocated to our slot.
externalSram.requestMemory(&delaySlot, BAHardwareConfig.getSpiMemSizeBytes(MemSelect::MEM0), MemSelect::MEM0, true); externalSram.requestMemory(&delaySlot, BAHardwareConfig.getSpiMemSizeBytes(MemSelect::MEM0), MemSelect::MEM0, true);
delaySlot.clear();
// Configure the LED to indicate the gate status, this is controlled directly by SOS effect, not by // Configure the LED to indicate the gate status, this is controlled directly by SOS effect, not by
// by BAPhysicalControls // by BAPhysicalControls
@ -149,7 +149,7 @@ void setup() {
// Besure to enable the SOS. 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. // to minimize resources to nearly zero.
sos.enable(); sos.enable();
// Set some default values. // Set some default values.
// These can be changed by sending MIDI CC messages over the USB using // These can be changed by sending MIDI CC messages over the USB using
@ -176,7 +176,7 @@ void setup() {
delay(1000); delay(1000);
sos.clear(); sos.clear();
} }
void loop() { void loop() {
@ -186,35 +186,35 @@ void loop() {
// Check if SW1 has been toggled (pushed) and trigger the gate // Check if SW1 has been toggled (pushed) and trigger the gate
// LED1 will be directly control by the SOS effect, not by BAPhysicalControls // LED1 will be directly control by the SOS effect, not by BAPhysicalControls
if (controls.isSwitchToggled(gateHandle)) { if (controls.isSwitchToggled(gateHandle)) {
sos.trigger(); sos.trigger();
Serial.println("GATE OPEN is triggered"); if (Serial) { Serial.println("GATE OPEN is triggered"); }
} }
// Use SW2 to clear out the SOS delayline // Use SW2 to clear out the SOS delayline
controls.setOutput(led2Handle, controls.getSwitchValue(led2Handle)); controls.setOutput(led2Handle, controls.getSwitchValue(led2Handle));
if (controls.isSwitchToggled(clearHandle)) { if (controls.isSwitchToggled(clearHandle)) {
sos.clear(); sos.clear();
Serial.println("GATE CLEAR is triggered"); if (Serial) { Serial.println("GATE CLEAR is triggered"); }
} }
// Use POT1 (left) to control the OPEN GATE time // Use POT1 (left) to control the OPEN GATE time
if (controls.checkPotValue(openHandle, potValue)) { if (controls.checkPotValue(openHandle, potValue)) {
// Pot has changed // Pot has changed
sos.gateOpenTime(potValue * MAX_GATE_TIME_MS); sos.gateOpenTime(potValue * MAX_GATE_TIME_MS);
Serial.println(String("New OPEN GATE setting (ms): ") + (potValue * MAX_GATE_TIME_MS)); if (Serial) { Serial.println(String("New OPEN GATE setting (ms): ") + (potValue * MAX_GATE_TIME_MS)); }
} }
// Use POT2 (right) to control the CLOSE GATE time // Use POT2 (right) to control the CLOSE GATE time
if (controls.checkPotValue(closeHandle, potValue)) { if (controls.checkPotValue(closeHandle, potValue)) {
// Pot has changed // Pot has changed
sos.gateCloseTime(potValue * MAX_GATE_TIME_MS); sos.gateCloseTime(potValue * MAX_GATE_TIME_MS);
Serial.println(String("New CLOSE GATE setting (ms): ") + (potValue * MAX_GATE_TIME_MS)); if (Serial) { Serial.println(String("New CLOSE GATE setting (ms): ") + (potValue * MAX_GATE_TIME_MS)); }
} }
// Use POT3 (centre) to control the sos effect volume // Use POT3 (centre) to control the sos effect volume
if (controls.checkPotValue(volumeHandle, potValue)) { if (controls.checkPotValue(volumeHandle, potValue)) {
// Pot has changed // Pot has changed
Serial.println(String("New SOS VOLUME setting: ") + potValue); if (Serial) { Serial.println(String("New SOS VOLUME setting: ") + potValue); }
sos.volume(potValue); sos.volume(potValue);
} }
@ -223,11 +223,11 @@ void loop() {
if (Serial.available() > 0) { if (Serial.available() > 0) {
while (Serial.available()) { while (Serial.available()) {
char key = Serial.read(); char key = Serial.read();
if (key == 'u') { if (key == 'u') {
headphoneVolume = (headphoneVolume + 1) % MAX_HEADPHONE_VOL; headphoneVolume = (headphoneVolume + 1) % MAX_HEADPHONE_VOL;
Serial.println(String("Increasing HEADPHONE volume to ") + headphoneVolume); Serial.println(String("Increasing HEADPHONE volume to ") + headphoneVolume);
} }
else if (key == 'd') { else if (key == 'd') {
headphoneVolume = (headphoneVolume - 1) % MAX_HEADPHONE_VOL; headphoneVolume = (headphoneVolume - 1) % MAX_HEADPHONE_VOL;
Serial.println(String("Decreasing HEADPHONE volume to ") + headphoneVolume); Serial.println(String("Decreasing HEADPHONE volume to ") + headphoneVolume);
} }
@ -235,14 +235,16 @@ void loop() {
} }
} }
} }
delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected. delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected.
if (timer > 1000) { if (timer > 1000) {
timer = 0; timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage()); if (Serial) {
Serial.print("% "); Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print(" SOS: "); Serial.print(sos.processorUsage()); Serial.print("% ");
Serial.println("%"); Serial.print(" SOS: "); Serial.print(sos.processorUsage());
Serial.println("%");
}
} }
} }

@ -1,17 +1,17 @@
/************************************************************************* /*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of * This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board. * the TGA Pro board.
* *
* The latest copy of the BA Guitar library can be obtained from * The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary * https://github.com/Blackaddr/BALibrary
* *
* This example demonstrates teh AudioEffectsTremolo effect. It can * This example demonstrates teh AudioEffectsTremolo effect. It can
* be controlled using USB MIDI. You can get a free USB MIDI Controller * be controlled using USB MIDI. You can get a free USB MIDI Controller
* appliation at * appliation at
* http://www.blackaddr.com/downloads/BAMidiTester/ * http://www.blackaddr.com/downloads/BAMidiTester/
* or the source code at * or the source code at
* https://github.com/Blackaddr/BAMidiTester * https://github.com/Blackaddr/BAMidiTester
* *
* Even if you don't control the guitar effect with USB MIDI, you must set * 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" * the Arduino IDE USB-Type under Tools to "Serial + MIDI"
*/ */
@ -57,14 +57,16 @@ elapsedMillis timer;
void OnControlChange(byte channel, byte control, byte value) { void OnControlChange(byte channel, byte control, byte value) {
tremolo.processMidi(channel-1, control, value); tremolo.processMidi(channel-1, control, value);
#ifdef MIDI_DEBUG #ifdef MIDI_DEBUG
Serial.print("Control Change, ch="); if (Serial) {
Serial.print(channel, DEC); Serial.print("Control Change, ch=");
Serial.print(", control="); Serial.print(channel, DEC);
Serial.print(control, DEC); Serial.print(", control=");
Serial.print(", value="); Serial.print(control, DEC);
Serial.print(value, DEC); Serial.print(", value=");
Serial.println(); Serial.print(value, DEC);
#endif Serial.println();
}
#endif
} }
void setup() { void setup() {
@ -72,26 +74,24 @@ void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using. TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x); //TGA_PRO_REVB(x);
//TGA_PRO_REVA(x); //TGA_PRO_REVA(x);
delay(100); delay(100);
Serial.begin(57600); // Start the serial port Serial.begin(57600); // Start the serial port
// Disable the codec first // Disable the codec first
codec.disable(); codec.disable();
delay(100);
AudioMemory(128); AudioMemory(128);
delay(5); delay(5);
// Enable the codec // Enable the codec
Serial.println("Enabling codec...\n"); if (Serial) { Serial.println("Enabling codec...\n"); }
codec.enable(); codec.enable();
delay(100);
// Setup MIDI // Setup MIDI
MIDI.begin(MIDI_CHANNEL_OMNI); MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.setHandleControlChange(OnControlChange); MIDI.setHandleControlChange(OnControlChange);
usbMIDI.setHandleControlChange(OnControlChange); usbMIDI.setHandleControlChange(OnControlChange);
// Configure which MIDI CC's will control the effect parameters // Configure which MIDI CC's will control the effect parameters
tremolo.mapMidiControl(AudioEffectTremolo::BYPASS,16); tremolo.mapMidiControl(AudioEffectTremolo::BYPASS,16);
tremolo.mapMidiControl(AudioEffectTremolo::RATE,20); tremolo.mapMidiControl(AudioEffectTremolo::RATE,20);
@ -100,7 +100,7 @@ void setup() {
// Besure to enable the tremolo. When disabled, audio is is completely blocked // Besure to enable the tremolo. When disabled, audio is is completely blocked
// to minimize resources to nearly zero. // to minimize resources to nearly zero.
tremolo.enable(); tremolo.enable();
// Set some default values. // Set some default values.
// These can be changed by sending MIDI CC messages over the USB using // These can be changed by sending MIDI CC messages over the USB using
@ -121,10 +121,12 @@ void loop() {
if (timer > 1000) { if (timer > 1000) {
timer = 0; timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage()); if (Serial) {
Serial.print("% "); Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print(" tremolo: "); Serial.print(tremolo.processorUsage()); Serial.print("% ");
Serial.println("%"); Serial.print(" tremolo: "); Serial.print(tremolo.processorUsage());
Serial.println("%");
}
} }
MIDI.read(); MIDI.read();

@ -1,21 +1,21 @@
/************************************************************************* /*************************************************************************
* This demo uses the BALibrary library to provide enhanced control of * This demo uses the BALibrary library to provide enhanced control of
* the TGA Pro board. * the TGA Pro board.
* *
* The latest copy of the BA Guitar library can be obtained from * The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary * https://github.com/Blackaddr/BALibrary
* *
* This example demonstrates teh BAAudioEffectsTremolo effect. It can * This example demonstrates teh BAAudioEffectsTremolo effect. It can
* be controlled using the Blackaddr Audio "Expansion Control Board". * be controlled using the Blackaddr Audio "Expansion Control Board".
* *
* POT1 (left) controls the tremolo RATE * POT1 (left) controls the tremolo RATE
* POT2 (right) controls the tremolo DEPTH * POT2 (right) controls the tremolo DEPTH
* POT3 (center) controls the output VOLUME * POT3 (center) controls the output VOLUME
* SW1 will enable/bypass the audio effect. LED1 will be on when effect is enabled. * SW1 will enable/bypass the audio effect. LED1 will be on when effect is enabled.
* SW2 will cycle through the 3 pre-programmed waveforms. NOTE: any waveform other than Sine will cause * 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. * pops/clicks since the waveforms are not bandlimited.
* *
* *
* Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease * Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease
* the headphone volume between values of 0 and 9. * the headphone volume between values of 0 and 9.
*/ */
@ -60,7 +60,7 @@ AudioConnection rightOut(tremolo,0, i2sOut, 1);
// - LED2 (right) will illuminate when pressing SW2. // - LED2 (right) will illuminate when pressing SW2.
////////////////////////////////////////// //////////////////////////////////////////
// To get the calibration values for your particular board, first run the // To get the calibration values for your particular board, first run the
// BAExpansionCalibrate.ino example and // BAExpansionCalibrate.ino example and
constexpr int potCalibMin = 1; constexpr int potCalibMin = 1;
constexpr int potCalibMax = 1018; constexpr int potCalibMax = 1018;
constexpr bool potSwapDirection = true; constexpr bool potSwapDirection = true;
@ -82,7 +82,7 @@ void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using. TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x); //TGA_PRO_REVB(x);
//TGA_PRO_REVA(x); //TGA_PRO_REVA(x);
delay(100); // wait a bit for serial to be available delay(100); // wait a bit for serial to be available
Serial.begin(57600); // Start the serial port Serial.begin(57600); // Start the serial port
delay(100); delay(100);
@ -93,8 +93,8 @@ void setup() {
waveformHandle = controls.addSwitch(BA_EXPAND_SW2_PIN); // will be used for stepping through filters waveformHandle = controls.addSwitch(BA_EXPAND_SW2_PIN); // will be used for stepping through filters
// pots // pots
rateHandle = controls.addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection); // control the amount of delay rateHandle = controls.addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection); // control the amount of delay
depthHandle = controls.addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection); depthHandle = controls.addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection);
volumeHandle = controls.addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection); volumeHandle = controls.addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection);
// leds // leds
led1Handle = controls.addOutput(BA_EXPAND_LED1_PIN); led1Handle = controls.addOutput(BA_EXPAND_LED1_PIN);
led2Handle = controls.addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2 led2Handle = controls.addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2
@ -104,18 +104,18 @@ void setup() {
AudioMemory(128); AudioMemory(128);
// Enable and configure the codec // Enable and configure the codec
Serial.println("Enabling codec...\n"); if (Serial) { Serial.println("Enabling codec...\n"); }
codec.enable(); codec.enable();
codec.setHeadphoneVolume(1.0f); // Max headphone volume codec.setHeadphoneVolume(1.0f); // Max headphone volume
// Besure to enable the tremolo. When disabled, audio is is completely blocked by the effect // Besure to enable the tremolo. When disabled, audio is is completely blocked by the effect
// to minimize resource usage to nearly to nearly zero. // to minimize resource usage to nearly to nearly zero.
tremolo.enable(); tremolo.enable();
// Set some default values. // Set some default values.
// These can be changed using the controls on the Blackaddr Audio Expansion Board // These can be changed using the controls on the Blackaddr Audio Expansion Board
tremolo.bypass(false); tremolo.bypass(false);
controls.setOutput(led1Handle, !tremolo.isBypass()); // Set the LED when NOT bypassed controls.setOutput(led1Handle, !tremolo.isBypass()); // Set the LED when NOT bypassed
tremolo.rate(0.0f); tremolo.rate(0.0f);
tremolo.depth(1.0f); tremolo.depth(1.0f);
@ -140,8 +140,8 @@ void loop() {
bool bypass = tremolo.isBypass(); // get the current state bool bypass = tremolo.isBypass(); // get the current state
bypass = !bypass; // change it bypass = !bypass; // change it
tremolo.bypass(bypass); // set the new state tremolo.bypass(bypass); // set the new state
controls.setOutput(led1Handle, !bypass); // Set the LED when NOT bypassed controls.setOutput(led1Handle, !bypass); // Set the LED when NOT bypassed
Serial.println(String("BYPASS is ") + bypass); if (Serial) { Serial.println(String("BYPASS is ") + bypass); }
} }
// Use SW2 to cycle through the waveforms // Use SW2 to cycle through the waveforms
@ -150,27 +150,27 @@ void loop() {
waveformIndex = (waveformIndex + 1) % static_cast<unsigned>(Waveform::NUM_WAVEFORMS); waveformIndex = (waveformIndex + 1) % static_cast<unsigned>(Waveform::NUM_WAVEFORMS);
// cast the index // cast the index
tremolo.setWaveform(static_cast<Waveform>(waveformIndex)); tremolo.setWaveform(static_cast<Waveform>(waveformIndex));
Serial.println(String("Waveform set to ") + waveformIndex); if (Serial) { Serial.println(String("Waveform set to ") + waveformIndex); }
} }
// Use POT1 (left) to control the rate setting // Use POT1 (left) to control the rate setting
if (controls.checkPotValue(rateHandle, potValue)) { if (controls.checkPotValue(rateHandle, potValue)) {
// Pot has changed // Pot has changed
Serial.println(String("New RATE setting: ") + potValue); if (Serial) { Serial.println(String("New RATE setting: ") + potValue); }
tremolo.rate(potValue); tremolo.rate(potValue);
} }
// Use POT2 (right) to control the depth setting // Use POT2 (right) to control the depth setting
if (controls.checkPotValue(depthHandle, potValue)) { if (controls.checkPotValue(depthHandle, potValue)) {
// Pot has changed // Pot has changed
Serial.println(String("New DEPTH setting: ") + potValue); if (Serial) { Serial.println(String("New DEPTH setting: ") + potValue); }
tremolo.depth(potValue); tremolo.depth(potValue);
} }
// Use POT3 (centre) to control the volume setting // Use POT3 (centre) to control the volume setting
if (controls.checkPotValue(volumeHandle, potValue)) { if (controls.checkPotValue(volumeHandle, potValue)) {
// Pot has changed // Pot has changed
Serial.println(String("New VOLUME setting: ") + potValue); if (Serial) { Serial.println(String("New VOLUME setting: ") + potValue); }
tremolo.volume(potValue); tremolo.volume(potValue);
} }
@ -179,11 +179,11 @@ void loop() {
if (Serial.available() > 0) { if (Serial.available() > 0) {
while (Serial.available()) { while (Serial.available()) {
char key = Serial.read(); char key = Serial.read();
if (key == 'u') { if (key == 'u') {
headphoneVolume = (headphoneVolume + 1) % MAX_HEADPHONE_VOL; headphoneVolume = (headphoneVolume + 1) % MAX_HEADPHONE_VOL;
Serial.println(String("Increasing HEADPHONE volume to ") + headphoneVolume); Serial.println(String("Increasing HEADPHONE volume to ") + headphoneVolume);
} }
else if (key == 'd') { else if (key == 'd') {
headphoneVolume = (headphoneVolume - 1) % MAX_HEADPHONE_VOL; headphoneVolume = (headphoneVolume - 1) % MAX_HEADPHONE_VOL;
Serial.println(String("Decreasing HEADPHONE volume to ") + headphoneVolume); Serial.println(String("Decreasing HEADPHONE volume to ") + headphoneVolume);
} }
@ -193,13 +193,15 @@ void loop() {
} }
delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected. delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected.
if (timer > 1000) { if (timer > 1000) {
timer = 0; timer = 0;
Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage()); if (Serial) {
Serial.print("% "); Serial.print("Processor Usage, Total: "); Serial.print(AudioProcessorUsage());
Serial.print(" tremolo: "); Serial.print(tremolo.processorUsage()); Serial.print("% ");
Serial.println("%"); Serial.print(" tremolo: "); Serial.print(tremolo.processorUsage());
Serial.println("%");
}
} }
} }

@ -72,7 +72,7 @@ void setup() {
SPI_MEM0_1M(); SPI_MEM0_1M();
SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(MemSelect::MEM0); SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(MemSelect::MEM0);
Serial.println("Enabling SPI, testing MEM0"); Serial.printf("Enabling SPI, testing MEM0 up to addres %08X\n\r", SPI_MAX_ADDR);
spiMem0.begin(); spiMem0.begin();
} }

@ -1,16 +1,16 @@
/************************************************************************* /*************************************************************************
* This demo uses the BALibrary to provide enhanced control of * This demo uses the BALibrary to provide enhanced control of
* the TGA Pro board. * the TGA Pro board.
* *
* The latest copy of the BALibrary can be obtained from * The latest copy of the BALibrary can be obtained from
* https://github.com/Blackaddr/BALibrary * https://github.com/Blackaddr/BALibrary
* *
* This demo will perform a DMA memory test on MEM1 attached * This demo will perform a DMA memory test on MEM1 attached
* to SPI1. * to SPI1.
* *
* NOTE: SPI MEM1 can be used by a Teensy 3.5/3.6. * NOTE: SPI MEM1 can be used by a Teensy 3.5/3.6.
* pins. * pins.
* *
*/ */
#include <Wire.h> #include <Wire.h>
#include "BALibrary.h" #include "BALibrary.h"
@ -30,7 +30,6 @@ using namespace BALibrary;
SPISettings memSettings(20000000, MSBFIRST, SPI_MODE0); SPISettings memSettings(20000000, MSBFIRST, SPI_MODE0);
const int cs0pin = SPI1_CS_PIN; const int cs0pin = SPI1_CS_PIN;
BAGpio gpio; // access to User LED
BASpiMemoryDMA spiMem1(SpiDeviceId::SPI_DEVICE1); BASpiMemoryDMA spiMem1(SpiDeviceId::SPI_DEVICE1);
bool compareBuffers(uint8_t *a, uint8_t *b, size_t numBytes) bool compareBuffers(uint8_t *a, uint8_t *b, size_t numBytes)
@ -61,37 +60,35 @@ void setup() {
TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using. TGA_PRO_MKII_REV1(); // Declare the version of the TGA Pro you are using.
//TGA_PRO_REVB(x); //TGA_PRO_REVB(x);
//TGA_PRO_REVA(x); //TGA_PRO_REVA(x);
gpio.begin();
Serial.begin(57600); Serial.begin(57600);
while (!Serial) { yield(); } while (!Serial) { yield(); }
delay(5); delay(5);
SPI_MEM1_1M(); SPI_MEM1_64M();
SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(MemSelect::MEM1); SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(MemSelect::MEM1);
Serial.println("Enabling SPI, testing MEM1"); Serial.printf("Enabling SPI, testing MEM1, max address %08X\n\r", SPI_MAX_ADDR); Serial.flush();
spiMem1.begin(); spiMem1.begin();
} }
bool spi8BitTest(void) { bool spi8BitTest(void) {
size_t spiAddress = 0; size_t spiAddress = 0;
int spiPhase = 0; int spiPhase = 0;
constexpr uint8_t MASK80 = 0xaa; constexpr uint8_t MASK80 = 0xaa;
constexpr uint8_t MASK81 = 0x55; constexpr uint8_t MASK81 = 0x55;
uint8_t src8[DMA_SIZE]; uint8_t src8[DMA_SIZE];
uint8_t dest8[DMA_SIZE]; uint8_t dest8[DMA_SIZE];
// Write to the memory using 8-bit transfers // Write to the memory using 8-bit transfers
Serial.println("\nStarting 8-bit test Write/Read"); Serial.println("\nStarting 8-bit test Write/Read"); Serial.flush();
while (spiPhase < 4) { while (spiPhase < 4) {
spiAddress = 0; spiAddress = 0;
while (spiAddress <= SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer // fill the write data buffer
switch (spiPhase) { switch (spiPhase) {
case 0 : case 0 :
@ -114,15 +111,15 @@ bool spi8BitTest(void) {
src8[i] = ((spiAddress+i) & 0xff) ^ (!MASK81); src8[i] = ((spiAddress+i) & 0xff) ^ (!MASK81);
} }
break; break;
} }
// Send the DMA transfer // Send the DMA transfer
spiMem1.write(spiAddress, src8, DMA_SIZE); spiMem1.write(spiAddress, src8, DMA_SIZE);
// wait until write is done // wait until write is done
while (spiMem1.isWriteBusy()) {} while (spiMem1.isWriteBusy()) {}
spiAddress += DMA_SIZE; spiAddress += DMA_SIZE;
} }
// Read back the data using 8-bit transfers // Read back the data using 8-bit transfers
spiAddress = 0; spiAddress = 0;
while (spiAddress <= SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
@ -149,15 +146,15 @@ bool spi8BitTest(void) {
} }
break; break;
} }
// Read back the DMA data // Read back the DMA data
spiMem1.read(spiAddress, dest8, DMA_SIZE); spiMem1.read(spiAddress, dest8, DMA_SIZE);
// wait until read is done // wait until read is done
while (spiMem1.isReadBusy()) {} while (spiMem1.isReadBusy()) {}
if (!compareBuffers(src8, dest8, DMA_SIZE)) { if (!compareBuffers(src8, dest8, DMA_SIZE)) {
Serial.println(String("ERROR @") + spiAddress); Serial.println(String("ERROR @") + spiAddress);
return false; } // stop the test return false; } // stop the test
spiAddress += DMA_SIZE; spiAddress += DMA_SIZE;
} }
Serial.println(String("Phase ") + spiPhase + String(": 8-bit Write/Read test passed!")); Serial.println(String("Phase ") + spiPhase + String(": 8-bit Write/Read test passed!"));
spiPhase++; spiPhase++;
@ -169,7 +166,7 @@ bool spi8BitTest(void) {
} }
#endif #endif
Serial.println("\nStarting 8-bit test Zero/Read"); Serial.println("\nStarting 8-bit test Zero/Read"); Serial.flush();
// Clear the memory // Clear the memory
spiAddress = 0; spiAddress = 0;
memset(src8, 0, DMA_SIZE); memset(src8, 0, DMA_SIZE);
@ -178,7 +175,7 @@ bool spi8BitTest(void) {
spiMem1.zero(spiAddress, DMA_SIZE); spiMem1.zero(spiAddress, DMA_SIZE);
// wait until write is done // wait until write is done
while (spiMem1.isWriteBusy()) {} while (spiMem1.isWriteBusy()) {}
spiAddress += DMA_SIZE; spiAddress += DMA_SIZE;
} }
// Check the memory is clear // Check the memory is clear
@ -188,8 +185,8 @@ bool spi8BitTest(void) {
spiMem1.read(spiAddress, dest8, DMA_SIZE); spiMem1.read(spiAddress, dest8, DMA_SIZE);
// wait until read is done // wait until read is done
while (spiMem1.isReadBusy()) {} while (spiMem1.isReadBusy()) {}
if (!compareBuffers(src8, dest8, DMA_SIZE)) { return false; } // stop the test if (!compareBuffers(src8, dest8, DMA_SIZE)) { return false; } // stop the test
spiAddress += DMA_SIZE; spiAddress += DMA_SIZE;
} }
Serial.println(String(": 8-bit Zero/Read test passed!")); Serial.println(String(": 8-bit Zero/Read test passed!"));
return true; return true;
@ -201,16 +198,16 @@ bool spi16BitTest(void) {
constexpr uint16_t MASK160 = 0xaaaa; constexpr uint16_t MASK160 = 0xaaaa;
constexpr uint16_t MASK161 = 0x5555; constexpr uint16_t MASK161 = 0x5555;
constexpr int NUM_DATA = DMA_SIZE / sizeof(uint16_t); constexpr int NUM_DATA = DMA_SIZE / sizeof(uint16_t);
uint16_t src16[NUM_DATA]; uint16_t src16[NUM_DATA];
uint16_t dest16[NUM_DATA]; uint16_t dest16[NUM_DATA];
// Write to the memory using 16-bit transfers // Write to the memory using 16-bit transfers
Serial.println("\nStarting 16-bit test"); Serial.println("\nStarting 16-bit test"); Serial.flush();
while (spiPhase < 4) { while (spiPhase < 4) {
spiAddress = 0; spiAddress = 0;
while (spiAddress <= SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer // fill the write data buffer
switch (spiPhase) { switch (spiPhase) {
case 0 : case 0 :
@ -234,14 +231,14 @@ bool spi16BitTest(void) {
} }
break; break;
} }
// Send the DMA transfer // Send the DMA transfer
spiMem1.write16(spiAddress, src16, NUM_DATA); spiMem1.write16(spiAddress, src16, NUM_DATA);
// wait until write is done // wait until write is done
while (spiMem1.isWriteBusy()) {} while (spiMem1.isWriteBusy()) {}
spiAddress += DMA_SIZE; spiAddress += DMA_SIZE;
} }
// Read back the data using 8-bit transfers // Read back the data using 8-bit transfers
spiAddress = 0; spiAddress = 0;
while (spiAddress <= SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
@ -268,15 +265,15 @@ bool spi16BitTest(void) {
} }
break; break;
} }
// Read back the DMA data // Read back the DMA data
spiMem1.read16(spiAddress, dest16, NUM_DATA); spiMem1.read16(spiAddress, dest16, NUM_DATA);
// wait until read is done // wait until read is done
while (spiMem1.isReadBusy()) {} while (spiMem1.isReadBusy()) {}
if (!compareBuffers16(src16, dest16, NUM_DATA)) { if (!compareBuffers16(src16, dest16, NUM_DATA)) {
Serial.print("ERROR @"); Serial.println(spiAddress, HEX); Serial.print("ERROR @"); Serial.println(spiAddress, HEX);
return false; } // stop the test return false; } // stop the test
spiAddress += DMA_SIZE; spiAddress += DMA_SIZE;
} }
Serial.println(String("Phase ") + spiPhase + String(": 16-bit test passed!")); Serial.println(String("Phase ") + spiPhase + String(": 16-bit test passed!"));
spiPhase++; spiPhase++;
@ -287,7 +284,7 @@ bool spi16BitTest(void) {
} }
#endif #endif
Serial.println("\nStarting 16-bit test Zero/Read"); Serial.println("\nStarting 16-bit test Zero/Read"); Serial.flush();
// Clear the memory // Clear the memory
spiAddress = 0; spiAddress = 0;
memset(src16, 0, DMA_SIZE); memset(src16, 0, DMA_SIZE);
@ -296,7 +293,7 @@ bool spi16BitTest(void) {
spiMem1.zero16(spiAddress, NUM_DATA); spiMem1.zero16(spiAddress, NUM_DATA);
// wait until write is done // wait until write is done
while (spiMem1.isWriteBusy()) {} while (spiMem1.isWriteBusy()) {}
spiAddress += DMA_SIZE; spiAddress += DMA_SIZE;
} }
// Check the memory is clear // Check the memory is clear
@ -306,8 +303,8 @@ bool spi16BitTest(void) {
spiMem1.read16(spiAddress, dest16, NUM_DATA); spiMem1.read16(spiAddress, dest16, NUM_DATA);
// wait until read is done // wait until read is done
while (spiMem1.isReadBusy()) {} while (spiMem1.isReadBusy()) {}
if (!compareBuffers16(src16, dest16, NUM_DATA)) { return false; } // stop the test if (!compareBuffers16(src16, dest16, NUM_DATA)) { return false; } // stop the test
spiAddress += DMA_SIZE; spiAddress += DMA_SIZE;
} }
Serial.println(String(": 16-bit Zero/Read test passed!")); Serial.println(String(": 16-bit Zero/Read test passed!"));
return true; return true;

@ -0,0 +1,9 @@
#ifndef DEBUG_PRINTF_H_
#define DEBUG_PRINTF_H_
// Make a safe call to Serial where it checks if the object is valid first. This allows your
// program to work even when no USB serial is connected. Printing to the Serial object when
// no valid connection is present will crash the CPU.
#define DEBUG_PRINT(x) {if (Serial) {x;}}
#endif

@ -0,0 +1,285 @@
/***********************************************************************************
* MULTIVERSE DEMO
*
* This demo program shows how to use BALibrary to access the hardware
* features of the Aviate Audio Multiverse effects processor.
*
* The following are demonstrated in this programming using BALibrary:
* - WM8731 stereo audio codec in master mode (NOTE: not slave mode like TGA Pro
* - Interact with all physical controls
* - Control the 128x64 pixel OLED display (connected to SPI0)
* - Use the 8MB external SRAM (simple memory test)
*
* REQUIREMENTS:
* This demo for Multiverse uses its OLED display which requires several Arduino
* libraries be downloaded first. The SH1106 library is modifed to work with Teensy
* and must be downloaded from the AlgorhythmTechnologies github.
*
* Adafruit_BusIO : https://github.com/adafruit/Adafruit_BusIO
* Adafruit_GFX_Library : https://github.com/adafruit/Adafruit-GFX-Library
* Adafruit_SH1106 : https://github.com/AlgorhythmTechnologies/Adafruit_SH1106
*
*
* USAGE INSTRUCTIONS
* - Use the 'Gain' knob to control the input gain on the codec. See checkPot().
* - Use the 'Level' knob to control output volume with an AudioMixer4 object.
* - Stomp switches S1 and S2 will write status to display, and turn on LED
* - Encoder push-button switches will write status to display when pressed/released
* - Encoder rotary control will adjust a positive/negative count and update display
*/
#include <Audio.h>
#include <SPI.h>
#include "BALibrary.h"
#include "DebugPrintf.h"
#include "PhysicalControls.h"
using namespace BALibrary;
// OLED display stuff
#include "Adafruit_SH1106.h"
#include "Adafruit_GFX.h"
#include "Fonts/FreeSansBold9pt7b.h"
constexpr unsigned SCREEN_WIDTH = 128; // OLED display width, in pixels
constexpr unsigned SCREEN_HEIGHT = 64; // OLED display height, in pixels
Adafruit_SH1106 display(37, 35, 10);
// External SPI RAM
ExternalSramManager sramManager;
ExtMemSlot memSlot;
BASpiMemory spiMem1(SpiDeviceId::SPI_DEVICE1);
unsigned spiAddress = 0;
unsigned spiAddressMax;
unsigned sramStage = 0; // stage 0 is zero, 1 is write, 2 is read
volatile float sramCompletion = 0.0f;
volatile unsigned errorCount = 0;
AudioInputI2Sslave i2sIn;
AudioOutputI2Sslave i2sOut;
AudioMixer4 volumeOut;
// i2sIn --> volumeOut(Mixer) --> i2sOut
AudioConnection patchIn0(i2sIn, 0, volumeOut, 0);
AudioConnection patchIn1(i2sIn, 1, volumeOut, 1);
AudioConnection patchOut0(volumeOut,0, i2sOut, 0);
AudioConnection patchOut1(volumeOut,0, i2sOut, 1);
BAAudioControlWM8731master codec;
elapsedMillis timer;
// Create a control object using the number of switches, pots, encoders and outputs on the
// Multiverse pedal
BAPhysicalControls controls(6, 4, 4, 2); // (SW, POT, ENC, LED)
unsigned loopCounter = 0;
void drawProgressBar(float completion); // declaration
void drawBlackaddrAudio() {
display.setCursor(0, 24); // (x,y)
display.printf(" Blackaddr");
display.setCursor(0, 40); // (x,y)
display.printf(" Audio");
}
void setup() {
codec.disable(); // this will reset the codec
// wait up for the serial to appear for up to 1 second
Serial.begin(57600);
unsigned serialLoopCount = 10;
while (!Serial && (serialLoopCount > 0)) {
delay(100);
serialLoopCount--;
}
MULTIVERSE(); // constants defined in BALibrary become valid only after this call
SPI_MEM1_64M(); // Declare the correct memory size
// Init the display
display.begin(SH1106_SWITCHCAPVCC, SH1106_I2C_ADDRESS, true);
display.clearDisplay();
display.display();
display.setTextColor(WHITE); // Draw white text
display.setFont(&FreeSansBold9pt7b);
drawBlackaddrAudio();
display.display();
configPhysicalControls(&controls, &codec);
// Request a memory slot from the external RAM
size_t numBytes = BAHardwareConfig.getSpiMemSizeBytes(MemSelect::MEM1);
spiAddressMax = BAHardwareConfig.getSpiMemMaxAddr(1)/4; // test the first 25% of memory
bool success = sramManager.requestMemory(&memSlot, numBytes, MemSelect::MEM1, /* no DMA */ false);
if (!success && Serial) { printf("Request for memory slot failed\n\r"); }
// Allocated audio buffers and enable codec
AudioMemory(64);
codec.enable();
delay(100);
// Mixer at full volume
volumeOut.gain(0,1.0f);
volumeOut.gain(1,1.0f);
// flush the pot filters. The analog measurement of the analog pots is averaged (filtered)
// over time, so at startup you will see a bunch of false changes detected as the filter
// settles. We can force this with a few dozen repeated calls.
for (unsigned i=0; i < 50; i++) {
float potValue;
for (unsigned j=0; j < BA_EXPAND_NUM_POT; j++) {
controls.checkPotValue(j, potValue);
}
delay(10);
}
}
void loop() {
// Check all the physical controls for updates
checkPot(0);
checkPot(1);
checkPot(2);
checkPot(3);
checkSwitch(0);
checkSwitch(1);
checkSwitch(2);
checkSwitch(3);
checkSwitch(4);
checkSwitch(5);
checkEncoder(0);
checkEncoder(1);
checkEncoder(2);
checkEncoder(3);
// If the SRAM test is not complete, run the next block
if (sramCompletion < 1.0f) {
nextSpiMemTestBlock();
}
// Adjusting one of the knobs/switches will result in its value being display for
// 2 seconds in the check*() functions.
if (timer > 2000) {
loopCounter++;
display.clearDisplay();
drawBlackaddrAudio();
drawSramProgress(sramCompletion);
display.display();
}
}
// This function will draw on the display which stage the memory test is in, and
// the percentage complete for that stage.
void drawSramProgress(float completion)
{
if (errorCount > 0) { // If errors, print the error count
display.setCursor(0, SCREEN_HEIGHT-1);
display.printf("Errors: %d", errorCount);
return;
}
// Draw the SRAM test progress at the bottom of the screen
display.setCursor(0, SCREEN_HEIGHT-1);
switch(sramStage) {
case 0 : display.printf("0 mem:"); break;
case 1 : display.printf("0 chk:"); break;
case 2 : display.printf("wr mem:"); break;
case 3 : display.printf("rd mem:"); break;
case 4 : // same as default
default: display.printf("Done"); break;
}
display.setCursor(SCREEN_WIDTH*0.63f, SCREEN_HEIGHT-1); // position to lower right corner
display.printf("%0.f%%", 100.0f * completion);
}
// Create a predictable data pattern based on address.
constexpr int mask0 = 0x5555;
constexpr int mask1 = 0xaaaa;
int calcNextData(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);
}
// Process the next block of data in the memory test
void nextSpiMemTestBlock()
{
constexpr unsigned BLOCK_SIZE_BYTES = 256; // transfer 256 bytes (arbitrary) per transaction
constexpr unsigned NUM_BLOCK_WORDS = BLOCK_SIZE_BYTES;
static uint8_t buffer[BLOCK_SIZE_BYTES];
static int16_t buffer16a[NUM_BLOCK_WORDS];
static int16_t buffer16b[NUM_BLOCK_WORDS];
static int maskPhase = 0;
if (sramStage == 0) { // Zero write
// zero the memory
while (spiMem1.isWriteBusy()) {} // wait for DMA write to complete
memSlot.zero(spiAddress, BLOCK_SIZE_BYTES);
spiAddress += BLOCK_SIZE_BYTES;
} else if (sramStage == 1) { // Zero check
memSlot.read(spiAddress, buffer, BLOCK_SIZE_BYTES);
while (spiMem1.isReadBusy()) {} // wait for DMA read results
for (unsigned i=0; i < BLOCK_SIZE_BYTES; i++) {
if (buffer[i] != 0) { errorCount++; }
}
spiAddress += BLOCK_SIZE_BYTES;
}
else if (sramStage == 2) { // write test
// Calculate the data for a block
for (unsigned i=0; i<NUM_BLOCK_WORDS; i++) {
buffer16a[i] = calcNextData(spiAddress+i, 0, 0);
maskPhase = (maskPhase+1) % 2;
}
memSlot.write16(spiAddress, buffer16a, NUM_BLOCK_WORDS);
while (memSlot.isWriteBusy()) {} // wait for DMA write to complete
spiAddress += BLOCK_SIZE_BYTES;
}
else if (sramStage == 3) { // read test
// Calculate the data for a block
for (unsigned i=0; i<NUM_BLOCK_WORDS; i++) {
buffer16a[i] = calcNextData(spiAddress+i, 0, 0);
maskPhase = (maskPhase+1) % 2;
}
memSlot.read16(spiAddress, buffer16b, NUM_BLOCK_WORDS);
while (memSlot.isReadBusy()) {} // wait for DMA read results
for (unsigned i=0; i < NUM_BLOCK_WORDS; i++) {
if (buffer16a[i] != buffer16b[i]) { errorCount++; }
}
spiAddress += BLOCK_SIZE_BYTES;
}
else if (sramStage == 4) {
sramCompletion = 1.0f;
return;
}
if (spiAddress > spiAddressMax && sramStage < 4) {
spiAddress = 0; sramStage++; sramCompletion = 0.0f;
return;
}
sramCompletion = (float)spiAddress / (float)spiAddressMax ;
}

@ -0,0 +1,222 @@
#include <cmath>
#include "Adafruit_SH1106.h"
#include "BALibrary.h"
#include "DebugPrintf.h"
using namespace BALibrary;
// Declare the externally shared variables from the main .ino
extern Adafruit_SH1106 display;
extern BAAudioControlWM8731master codec;
extern AudioMixer4 volumeOut;
extern elapsedMillis timer;
constexpr int displayRow = 36; // Row to start OLED display updates on
constexpr int potCalibMin = 8;
constexpr int potCalibMax = 1016;
constexpr bool potSwapDirection = true;
constexpr bool encSwapDirection = true;
int pot1Handle= -1, pot2Handle = -1, pot3Handle = -1, pot4Handle = -1;
int sw1Handle = -1, sw2Handle = -1, sw3Handle = -1, sw4Handle = -1, sw5Handle = -1, sw6Handle = -1;
int enc1Handle = -1, enc2Handle = -1, enc3Handle = -1, enc4Handle = -1;
int led1Handle = -1, led2Handle = -1;
BAAudioControlWM8731master *codecPtr = nullptr;
BAPhysicalControls *controlPtr = nullptr;
// Configure and setup the physical controls
void configPhysicalControls(BAPhysicalControls* controls, BAAudioControlWM8731master* codec)
{
// Setup the controls. The return value is the handle to use when checking for control changes, etc.
controlPtr = controls;
codecPtr = codec;
if (!controlPtr) { DEBUG_PRINT(Serial.printf("ERROR: controlPtr is invalid\n\r")); return; }
if (!codecPtr) { DEBUG_PRINT(Serial.printf("ERROR: codecPtr is invalid\n\r")); return; }
// pushbuttons
sw1Handle = controlPtr->addSwitch(BA_EXPAND_SW1_PIN);
sw2Handle = controlPtr->addSwitch(BA_EXPAND_SW2_PIN);
sw3Handle = controlPtr->addSwitch(BA_EXPAND_SW3_PIN);
sw4Handle = controlPtr->addSwitch(BA_EXPAND_SW4_PIN);
sw5Handle = controlPtr->addSwitch(BA_EXPAND_SW5_PIN);
sw6Handle = controlPtr->addSwitch(BA_EXPAND_SW6_PIN);
// pots
pot1Handle = controlPtr->addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection);
pot2Handle = controlPtr->addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection);
pot3Handle = controlPtr->addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection);
pot4Handle = controlPtr->addPot(BA_EXPAND_POT4_PIN, potCalibMin, potCalibMax, potSwapDirection);
// encoders
enc1Handle = controlPtr->addRotary(BA_EXPAND_ENC1_A_PIN, BA_EXPAND_ENC1_B_PIN, encSwapDirection);
enc2Handle = controlPtr->addRotary(BA_EXPAND_ENC2_A_PIN, BA_EXPAND_ENC2_B_PIN, encSwapDirection);
enc3Handle = controlPtr->addRotary(BA_EXPAND_ENC3_A_PIN, BA_EXPAND_ENC3_B_PIN, encSwapDirection);
enc4Handle = controlPtr->addRotary(BA_EXPAND_ENC4_A_PIN, BA_EXPAND_ENC4_B_PIN, encSwapDirection);
// leds
led1Handle = controlPtr->addOutput(BA_EXPAND_LED1_PIN);
led2Handle = controlPtr->addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2
}
void checkPot(unsigned id)
{
float potValue;
unsigned handle;
switch(id) {
case 0 :
handle = pot1Handle;
break;
case 1 :
handle = pot2Handle;
break;
case 2 :
handle = pot3Handle;
break;
case 3 :
handle = pot4Handle;
break;
default :
handle = pot1Handle;
}
if ((handle < 0) || (handle >= controlPtr->getNumPots())) {
DEBUG_PRINT(Serial.printf("ILLEGAL POT HANDLE: %d for id %d\n\r", handle, id));
return;
}
if (controlPtr->checkPotValue(handle, potValue)) {
// Pot has changed
DEBUG_PRINT(Serial.println(String("POT") + id + String(" value: ") + potValue));
timer = 0;
display.clearDisplay();
display.setCursor(0,displayRow);
switch(id) {
case 0 :
{
display.printf("Gain: %0.f\n", potValue * 100.0f);
int gain = static_cast<int>(std::roundf(31.0f * potValue));
codecPtr->setLeftInputGain(gain);
codecPtr->setRightInputGain(gain);
yield(); // give time for i2C transfers to complete
break;
}
case 1 :
{
display.printf("Level: %0.f\n", potValue * 100.0f);
volumeOut.gain(0, potValue);
volumeOut.gain(1, potValue);
break;
}
case 2 : display.printf("Exp T: %0.f\n", potValue * 100.0f); break;
case 3 : display.printf("Exp R: %0.f\n", potValue * 100.0f); break;
}
display.display();
}
}
int checkSwitch(unsigned id, bool getValueOnly=false)
{
unsigned swHandle = -1;
unsigned ledHandle = -1;
switch(id) {
case 0 :
swHandle = sw1Handle;
ledHandle = led1Handle;
break;
case 1 :
swHandle = sw2Handle;
ledHandle = led2Handle;
break;
case 2 :
swHandle = sw3Handle;
break;
case 3 :
swHandle = sw4Handle;
break;
case 4 :
swHandle = sw5Handle;
break;
case 5 :
swHandle = sw6Handle;
break;
default :
swHandle = sw1Handle;
ledHandle = led1Handle;
}
if ((swHandle < 0) || (swHandle >= controlPtr->getNumSwitches())) {
DEBUG_PRINT(Serial.printf("ILLEGAL SWITCH HANDLE: %d for id %d\n\r", swHandle, id); Serial.flush());
return -1;
}
bool switchValue;
bool changed = controlPtr->hasSwitchChanged(swHandle, switchValue);
if (getValueOnly) { return controlPtr->getSwitchValue(swHandle); }
if (changed) {
DEBUG_PRINT(Serial.println(String("Button ") + id + String(" pressed")));
timer = 0;
display.clearDisplay();
display.setCursor(0, displayRow);
switch(id) {
case 0 : display.printf("S1: %d\n", switchValue); break;
case 1 : display.printf("S2: %d\n", switchValue); break;
case 2 : display.printf("EncSw A: %d\n", switchValue); break;
case 3 : display.printf("EncSw B: %d\n", switchValue); break;
case 4 : display.printf("EncSw C: %d\n", switchValue); break;
case 5 : display.printf("EncSw D: %d\n", switchValue); break;
}
display.display();
}
if (swHandle < 2) { // these SWs map to LEDs
bool pressed = controlPtr->isSwitchHeld(swHandle);
controlPtr->setOutput(ledHandle, pressed);
}
return controlPtr->getSwitchValue(swHandle);
}
void checkEncoder(unsigned id)
{
unsigned encHandle;
static int enc1 = 0, enc2 = 0, enc3 = 0, enc4 = 0;
switch(id) {
case 0 :
encHandle = enc1Handle;
break;
case 1 :
encHandle = enc2Handle;
break;
case 2 :
encHandle = enc3Handle;
break;
case 3 :
encHandle = enc4Handle;
break;
default :
encHandle = enc1Handle;
}
if ((encHandle < 0) || (encHandle >= controlPtr->getNumRotary())) {
DEBUG_PRINT(Serial.printf("ILLEGAL ENCODER HANDLE: %d for id %d\n\r", encHandle, id); Serial.flush());
return;
}
int adj= controlPtr->getRotaryAdjustUnit(encHandle);
if (adj != 0) {
DEBUG_PRINT(Serial.printf("Enc %d: %d\n\r", id, adj); Serial.flush());
display.clearDisplay();
display.setCursor(0, displayRow);
switch(id) {
case 0 : enc1 += adj; display.printf("Enc A: %d", enc1); break;
case 1 : enc2 += adj; display.printf("Enc B: %d", enc2); break;
case 2 : enc3 += adj; display.printf("Enc C: %d", enc3); break;
case 3 : enc4 += adj; display.printf("Enc D: %d", enc4); break;
}
display.display();
timer = 0;
}
}

@ -0,0 +1,11 @@
#ifndef PHYSICAL_CONTROLS_H_
#define PHYSICAL_CONTROLS_H_
#include "BALibrary.h"
void configPhysicalControls(BALibrary::BAPhysicalControls* controls, BALibrary::BAAudioControlWM8731master* codec);
void checkPot(unsigned id);
int checkSwitch(unsigned id, bool getValueOnly=false);
void checkEncoder(unsigned id);
#endif

@ -12,14 +12,14 @@ BAPhysicalControls *controlPtr = nullptr;
void configPhysicalControls(BAPhysicalControls &controls, BAAudioControlWM8731 &codec) void configPhysicalControls(BAPhysicalControls &controls, BAAudioControlWM8731 &codec)
{ {
// Setup the controls. The return value is the handle to use when checking for control changes, etc. // Setup the controls. The return value is the handle to use when checking for control changes, etc.
// pushbuttons // pushbuttons
sw1Handle = controls.addSwitch(BA_EXPAND_SW1_PIN); sw1Handle = controls.addSwitch(BA_EXPAND_SW1_PIN);
sw2Handle = controls.addSwitch(BA_EXPAND_SW2_PIN); sw2Handle = controls.addSwitch(BA_EXPAND_SW2_PIN);
// pots // pots
pot1Handle = controls.addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection); pot1Handle = controls.addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection);
pot2Handle = controls.addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection); pot2Handle = controls.addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection);
pot3Handle = controls.addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection); pot3Handle = controls.addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection);
// leds // leds
led1Handle = controls.addOutput(BA_EXPAND_LED1_PIN); led1Handle = controls.addOutput(BA_EXPAND_LED1_PIN);
led2Handle = controls.addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2 led2Handle = controls.addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2
@ -45,12 +45,12 @@ void checkPot(unsigned id)
default : default :
handle = pot1Handle; handle = pot1Handle;
} }
if (controlPtr->checkPotValue(handle, potValue)) { if (controlPtr->checkPotValue(handle, potValue)) {
// Pot has changed // Pot has changed
codecPtr->setHeadphoneVolume(potValue); codecPtr->setHeadphoneVolume(potValue);
Serial.println(String("POT") + id + String(" value: ") + potValue); if (Serial) { Serial.println(String("POT") + id + String(" value: ") + potValue); }
} }
} }
void checkSwitch(unsigned id) void checkSwitch(unsigned id)
@ -72,7 +72,7 @@ void checkSwitch(unsigned id)
} }
if (controlPtr->isSwitchToggled(swHandle)) { if (controlPtr->isSwitchToggled(swHandle)) {
Serial.println(String("Button ") + id + String(" pressed")); if (Serial) { Serial.println(String("Button ") + id + String(" pressed")); }
} }
bool pressed = controlPtr->isSwitchHeld(swHandle); bool pressed = controlPtr->isSwitchHeld(swHandle);

@ -1,44 +1,44 @@
/************************************************************************* /*************************************************************************
* This demo is used for manufacturing testing on the TGA Pro Expansion * This demo is used for manufacturing testing on the TGA Pro Expansion
* Control Board. * Control Board.
* *
* This will test the following on the TGA Pro: * This will test the following on the TGA Pro:
* *
* - Audio INPUT and OUTPUT JACKS * - Audio INPUT and OUTPUT JACKS
* - Midi INPUT and Midi OUTPUT jacks * - Midi INPUT and Midi OUTPUT jacks
* - MEM0 (if installed) * - MEM0 (if installed)
* - User LED * - User LED
* *
* This will also test the Expansion Control Board (if installed): * This will also test the Expansion Control Board (if installed):
* *
* - three POT knobs * - three POT knobs
* - two pushbutton SWitches * - two pushbutton SWitches
* - two LEDs * - two LEDs
* - headphone output * - headphone output
* *
* SETUP INSTRUCTIONS: * SETUP INSTRUCTIONS:
* *
* 1) Connect an audio source to AUDIO INPUT. * 1) Connect an audio source to AUDIO INPUT.
* 2) Connect AUDIO OUTPUT to amp, stereo, headphone amplifier, etc. * 2) Connect AUDIO OUTPUT to amp, stereo, headphone amplifier, etc.
* 3) if testing the MIDI ports, connect a MIDI cable between MIDI INPUT and MIDI OUTPUT * 3) if testing the MIDI ports, connect a MIDI cable between MIDI INPUT and MIDI OUTPUT
* 4) comment out any tests you want to skip * 4) comment out any tests you want to skip
* 5) Compile and run the demo on your Teensy with TGA Pro. * 5) Compile and run the demo on your Teensy with TGA Pro.
* 6) Launch the Arduino Serial Monitor to see results. * 6) Launch the Arduino Serial Monitor to see results.
* *
* TESTING INSTRUCTIONS: * TESTING INSTRUCTIONS:
* *
* 1) Check the Serial Monitor for the results of the MIDI testing, and external memory testing. * 1) Check the Serial Monitor for the results of the MIDI testing, and external memory testing.
* 2) Confirm that the audio sent to the INPUT is coming out the OUTPUT. * 2) Confirm that the audio sent to the INPUT is coming out the OUTPUT.
* 3) Confirm the User LED is blinking every 1 or 2 seconds * 3) Confirm the User LED is blinking every 1 or 2 seconds
* *
* If using the Expansion Control Board: * If using the Expansion Control Board:
* *
* 1) Try pushing the pushbuttons. When pushed, they should turn on their corresponding LED. * 1) Try pushing the pushbuttons. When pushed, they should turn on their corresponding LED.
* 2) Try turn each of the knobs one at a time. They should adjust the volume. * 2) Try turn each of the knobs one at a time. They should adjust the volume.
* *
* The latest copy of the BA Guitar library can be obtained from * The latest copy of the BA Guitar library can be obtained from
* https://github.com/Blackaddr/BALibrary * https://github.com/Blackaddr/BALibrary
* *
*/ */
//#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_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.
@ -93,7 +93,6 @@ void setup() {
gpio.begin(); gpio.begin();
Serial.begin(57600); Serial.begin(57600);
//while (!Serial) { yield(); }
delay(500); delay(500);
// Disable the audio codec first // Disable the audio codec first
@ -104,20 +103,20 @@ void setup() {
codec.setHeadphoneVolume(0.8f); // Set headphone volume codec.setHeadphoneVolume(0.8f); // Set headphone volume
#if defined(RUN_EXP_TEST) #if defined(RUN_EXP_TEST)
configPhysicalControls(controls, codec); configPhysicalControls(controls, codec);
Serial.println("Now monitoring for input from Expansion Control Board"); if (Serial) { Serial.println("Now monitoring for input from Expansion Control Board"); }
#endif #endif
// Run the initial Midi connectivity and SPI memory tests. // Run the initial Midi connectivity and SPI memory tests.
#if defined(RUN_MIDI_TEST) #if defined(RUN_MIDI_TEST)
if (uartTest()) { Serial.println("MIDI Ports testing PASSED!"); } if (uartTest()) { if (Serial) Serial.println("MIDI Ports testing PASSED!"); }
#endif #endif
#if defined(RUN_MEMO_TEST) #if defined(RUN_MEMO_TEST)
SPI_MEM0_64M(); // declare the 64Mbit optional PSI memory SPI_MEM0_64M(); // declare the 64Mbit optional PSI memory
//SPI_MEM0_4M(); // REVB and REVA came with 4M or 1M //SPI_MEM0_4M(); // REVB and REVA came with 4M or 1M
// SPI_MEM0_1M(); // SPI_MEM0_1M();
spiMem0.begin(); delay(10); spiMem0.begin(); delay(10);
if (spiTest(&spiMem0, 0)) { Serial.println("SPI0 testing PASSED!");} if (spiTest(&spiMem0, 0)) { if (Serial) Serial.println("SPI0 testing PASSED!");}
#endif #endif
} }
@ -132,7 +131,7 @@ void loop() {
#endif #endif
delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected. delay(20); // Without some minimal delay here it will be difficult for the pots/switch changes to be detected.
loopCounter++; loopCounter++;
if (timer > 1000) { if (timer > 1000) {
timer = 0; timer = 0;

@ -4,7 +4,7 @@
using namespace BALibrary; using namespace BALibrary;
constexpr unsigned MIDI_RATE = 31250; constexpr unsigned MIDI_RATE = 31250;
constexpr unsigned HIGH_RATE = 230400; constexpr unsigned HIGH_RATE = 230400;
constexpr unsigned TEST_TIME = 5; // 5 second test each constexpr unsigned TEST_TIME = 5; // 5 second test each
static unsigned baudRate = MIDI_RATE; // start with low speed static unsigned baudRate = MIDI_RATE; // start with low speed
@ -19,14 +19,15 @@ bool uartTest(void)
{ {
Serial1.begin(baudRate, SERIAL_8N1); Serial1.begin(baudRate, SERIAL_8N1);
delay(100); delay(100);
while(!Serial) {} if (!Serial) { return false; } // skip uart test if Serial not connected
Serial.println(String("\nRunning MIDI Port speed test at ") + baudRate); Serial.println(String("\nRunning MIDI Port speed test at ") + baudRate);
// write the first data // write the first data
Serial1.write(writeData); Serial1.write(writeData);
while(!testFailed && !testDone) { while(!testFailed && !testDone) {
if (loopCounter >= (baudRate/4)) { // the divisor determines how long the test runs for if (loopCounter >= (baudRate/4)) { // the divisor determines how long the test runs for
// next test // next test
switch (testPhase) { switch (testPhase) {
@ -38,13 +39,13 @@ bool uartTest(void)
} }
if (errorCount == 0) { Serial.println("TEST PASSED!"); } if (errorCount == 0) { Serial.println("TEST PASSED!"); }
else { else {
Serial.println("MIDI PORT TEST FAILED!"); Serial.println("MIDI PORT TEST FAILED!");
} }
errorCount = 0; errorCount = 0;
testPhase++; testPhase++;
loopCounter = 0; loopCounter = 0;
if (!testDone) { if (!testDone) {
Serial.println(String("\nRunning MIDI Port speed test at ") + baudRate); Serial.println(String("\nRunning MIDI Port speed test at ") + baudRate);
Serial1.begin(baudRate, SERIAL_8N1); Serial1.begin(baudRate, SERIAL_8N1);
@ -53,24 +54,24 @@ bool uartTest(void)
Serial.println("MIDI PORT TEST DONE!\n"); Serial.println("MIDI PORT TEST DONE!\n");
} }
} }
// Wait for read data // Wait for read data
if (Serial1.available()) { if (Serial1.available()) {
uint8_t readData= Serial1.read(); uint8_t readData= Serial1.read();
if (readData != writeData) { if (readData != writeData) {
Serial.println(String("MIDI ERROR: readData = ") + readData + String(" writeData = ") + writeData); Serial.println(String("MIDI ERROR: readData = ") + readData + String(" writeData = ") + writeData);
errorCount++; errorCount++;
} }
if ((loopCounter % (baudRate/64)) == 0) { // the divisor determines how often the period is printed if ((loopCounter % (baudRate/64)) == 0) { // the divisor determines how often the period is printed
Serial.print("."); Serial.flush(); Serial.print("."); Serial.flush();
} }
if (errorCount > 16) { if (errorCount > 16) {
Serial.println("Halting test"); Serial.println("Halting test");
testFailed = true; testFailed = true;
} }
loopCounter++; loopCounter++;
writeData++; writeData++;
Serial1.write(writeData); Serial1.write(writeData);

@ -32,13 +32,14 @@ int calcData(int spiAddress, int loopPhase, int maskPhase)
break; break;
case 3: case 3:
data = ~spiAddress ^ mask1; data = ~spiAddress ^ mask1;
} }
return (data & 0xffff); return (data & 0xffff);
} }
bool spiTest(BASpiMemory *mem, int id) bool spiTest(BASpiMemory *mem, int id)
{ {
if (!Serial) { return false; } // Skip test if Serial not connected
int spiAddress = 0; int spiAddress = 0;
int spiErrorCount = 0; int spiErrorCount = 0;
@ -47,7 +48,7 @@ bool spiTest(BASpiMemory *mem, int id)
uint16_t memBlock[NUM_BLOCK_WORDS]; uint16_t memBlock[NUM_BLOCK_WORDS];
uint16_t goldData[NUM_BLOCK_WORDS]; uint16_t goldData[NUM_BLOCK_WORDS];
SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(0); // assume for this test both memories are the same size so use MEM0 SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(MemSelect::MEM0); // assume for this test both memories are the same size so use MEM0
const size_t SPI_MEM_SIZE_BYTES = BAHardwareConfig.getSpiMemSizeBytes(id); const size_t SPI_MEM_SIZE_BYTES = BAHardwareConfig.getSpiMemSizeBytes(id);
Serial.println(String("Starting SPI MEM Test of ") + SPI_MEM_SIZE_BYTES + String(" bytes")); Serial.println(String("Starting SPI MEM Test of ") + SPI_MEM_SIZE_BYTES + String(" bytes"));
@ -55,9 +56,9 @@ bool spiTest(BASpiMemory *mem, int id)
for (int cnt = 0; cnt < NUM_TESTS; cnt++) { for (int cnt = 0; cnt < NUM_TESTS; cnt++) {
// Zero check // Zero check
mem->zero16(0, SPI_MEM_SIZE_BYTES / sizeof(uint16_t)); mem->zero16(0, SPI_MEM_SIZE_BYTES / sizeof(uint16_t));
while (mem->isWriteBusy()) {} while (mem->isWriteBusy()) {}
for (spiAddress = 0; spiAddress <= SPI_MAX_ADDR; spiAddress += NUM_BLOCK_WORDS*sizeof(uint16_t)) { for (spiAddress = 0; spiAddress <= SPI_MAX_ADDR; spiAddress += NUM_BLOCK_WORDS*sizeof(uint16_t)) {
mem->read16(spiAddress, memBlock, NUM_BLOCK_WORDS); mem->read16(spiAddress, memBlock, NUM_BLOCK_WORDS);
while (mem->isReadBusy()) {} while (mem->isReadBusy()) {}
@ -69,15 +70,20 @@ bool spiTest(BASpiMemory *mem, int id)
} }
if (spiErrorCount >= 10) break; if (spiErrorCount >= 10) break;
} }
//if (spiErrorCount == 0) { Serial.println(String("SPI MEMORY(") + cnt + String("): Zero test PASSED!")); } if (spiErrorCount == 0) { Serial.println(String("SPI MEMORY(") + cnt + String("): Zero test PASSED!")); }
if (spiErrorCount == 0) { Serial.print("."); Serial.flush(); } if (spiErrorCount == 0) { Serial.print("."); Serial.flush(); }
if (spiErrorCount > 0) { Serial.println(String("SPI MEMORY(") + cnt + String("): Zero test FAILED, error count = ") + spiErrorCount); return false;} if (spiErrorCount > 0) {
//Serial.println(String("SPI MEMORY(") + cnt + String("): Zero test FAILED, error count = ") + spiErrorCount); return false;
Serial.printf("SPI MEMORY: test %d Zero test FAILED, error count:%d, final address:0x%08X\n\r",
cnt, spiErrorCount, spiAddress);
return false;
}
// Write all test data to the memory // Write all test data to the memory
maskPhase = 0; maskPhase = 0;
for (spiAddress = 0; spiAddress <= SPI_MAX_ADDR; spiAddress += NUM_BLOCK_WORDS*sizeof(uint16_t)) { for (spiAddress = 0; spiAddress <= SPI_MAX_ADDR; spiAddress += NUM_BLOCK_WORDS*sizeof(uint16_t)) {
// Calculate the data for a block // Calculate the data for a block
for (int i=0; i<NUM_BLOCK_WORDS; i++) { for (int i=0; i<NUM_BLOCK_WORDS; i++) {
memBlock[i] = calcData(spiAddress+i, loopPhase, maskPhase); memBlock[i] = calcData(spiAddress+i, loopPhase, maskPhase);
@ -93,8 +99,8 @@ bool spiTest(BASpiMemory *mem, int id)
maskPhase = 0; maskPhase = 0;
for (spiAddress = 0; spiAddress <= SPI_MAX_ADDR; spiAddress += NUM_BLOCK_WORDS*sizeof(uint16_t)) { for (spiAddress = 0; spiAddress <= SPI_MAX_ADDR; spiAddress += NUM_BLOCK_WORDS*sizeof(uint16_t)) {
mem->read16(spiAddress, memBlock, NUM_BLOCK_WORDS); mem->read16(spiAddress, memBlock, NUM_BLOCK_WORDS);
// Calculate the golden data for a block // Calculate the golden data for a block
for (int i=0; i<NUM_BLOCK_WORDS; i++) { for (int i=0; i<NUM_BLOCK_WORDS; i++) {
goldData[i] = calcData(spiAddress+i, loopPhase, maskPhase); goldData[i] = calcData(spiAddress+i, loopPhase, maskPhase);
@ -107,7 +113,7 @@ bool spiTest(BASpiMemory *mem, int id)
Serial.println(String("ERROR@ ") + i + String(": ") + goldData[i] + String("!=") + memBlock[i]); Serial.println(String("ERROR@ ") + i + String(": ") + goldData[i] + String("!=") + memBlock[i]);
spiErrorCount++; spiErrorCount++;
if (spiErrorCount >= 10) break; if (spiErrorCount >= 10) break;
} }
#ifdef SANITY_CHECK #ifdef SANITY_CHECK
else { else {
if ((spiAddress == 0) && (i<10) && (cnt == 0) ){ if ((spiAddress == 0) && (i<10) && (cnt == 0) ){

@ -40,7 +40,7 @@ enum class TgaBoard : unsigned {
REV_A = 0, ///< indicates using REV A of the TGA Pro 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 MKII_REV1, ///< indicates using MKII, Rev 1 of the TGA Pro
AVALON MULTIVERSE ///< indicates using the Aviate Audio Multiverse
}; };
/// enum to specify the TGA Board revision /// enum to specify the TGA Board revision
@ -54,7 +54,8 @@ enum class ExpansionBoard : unsigned {
NO_EXPANSION = 0, ///< default, indicates no expansion board is present NO_EXPANSION = 0, ///< default, indicates no expansion board is present
REV_1, ///< indicates using REV 1 of the Expansion Board 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) REV_3, ///< indicates using REV 3 of the Expansion Board (MKII Series)
MULTIVERSE ///< indicates using the Aviate Audio Multiverse for controls
}; };
/// enum to specify SPI memory dize /// enum to specify SPI memory dize
@ -204,9 +205,12 @@ extern BAHardware BAHardwareConfig; ///< external definition of global configura
#define TGA_PRO_REVA(x) BALibrary::BAHardwareConfig.set(TgaBoard::REV_A) ///< Macro for specifying REV A of the TGA Pro #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_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_MKII_REV1(x) BALibrary::BAHardwareConfig.set(TgaBoard::MKII_REV1) ///< Macro for specifying REV B of the TGA Pro
#define MULTIVERSE(x) BALibrary::BAHardwareConfig.set(TgaBoard::MULTIVERSE) ///< 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_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 TGA_PRO_EXPAND_REV3(x) BALibrary::BAHardwareConfig.setExpansionBoard(ExpansionBoard::REV_3) ///< Macro for specifying REV 2 of the Expansion Board
#define MULTIVERSE_EXPAND(x) BALibrary::BAHardwareConfig.setExpansionBoard(ExpansionBoard::MULTIVERSE) ///< Macro for specifying Multiverse
#define SPI_MEM0_1M(x) BALibrary::BAHardwareConfig.set(MEM0, SPI_MEMORY_1M) ///< Macro for specifying MEM0 is 1Mbit #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 MEM0 is 4Mbit #define SPI_MEM0_4M(x) BALibrary::BAHardwareConfig.set(MEM0, SPI_MEMORY_4M) ///< Macro for specifying MEM0 is 4Mbit
@ -228,9 +232,32 @@ 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_SW1_PIN; // 2_OUT2
extern uint8_t BA_EXPAND_SW2_PIN; // 3_LRCLK2 extern uint8_t BA_EXPAND_SW2_PIN; // 3_LRCLK2
extern uint8_t BA_EXPAND_LED1_PIN; // 4_BLCK2 extern uint8_t BA_EXPAND_LED1_PIN; // 4_BLCK2
extern uint8_t BA_EXPAND_LED2_PIN; // 5_IN2 extern uint8_t BA_EXPAND_LED2_PIN; // 5_IN2
// Only used on Aviate Audio Multiverse
// START Multiverse definitions
extern uint8_t BA_EXPAND_POT4_PIN;
extern uint8_t BA_EXPAND_POT5_PIN;
extern uint8_t BA_EXPAND_POT6_PIN;
extern uint8_t BA_EXPAND_SW3_PIN;
extern uint8_t BA_EXPAND_SW4_PIN;
extern uint8_t BA_EXPAND_SW5_PIN;
extern uint8_t BA_EXPAND_SW6_PIN;
extern uint8_t BA_EXPAND_ENC1_A_PIN;
extern uint8_t BA_EXPAND_ENC1_B_PIN;
extern uint8_t BA_EXPAND_ENC2_A_PIN;
extern uint8_t BA_EXPAND_ENC2_B_PIN;
extern uint8_t BA_EXPAND_ENC3_A_PIN;
extern uint8_t BA_EXPAND_ENC3_B_PIN;
extern uint8_t BA_EXPAND_ENC4_A_PIN;
extern uint8_t BA_EXPAND_ENC4_B_PIN;
// END Multiverse defintiions
extern uint8_t GPIO0; extern uint8_t GPIO0;
extern uint8_t GPIO1; extern uint8_t GPIO1;
extern uint8_t GPIO2; extern uint8_t GPIO2;
@ -253,12 +280,12 @@ extern uint8_t SPI1_CS_PIN;
extern uint8_t SPI1_MISO_PIN; extern uint8_t SPI1_MISO_PIN;
extern uint8_t SPI1_MOSI_PIN; extern uint8_t SPI1_MOSI_PIN;
#if defined(ARDUINO_TEENSY41) || defined(__MK66FX1M0__) || defined(__MK64FX512__) #if defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
#define SPI1_AVAILABLE #define SPI1_AVAILABLE
#endif #endif
/**************************************************************************//** /**************************************************************************//**
* Teensy 4.0 Hardware Settings * Teensy 4.X Hardware Settings
*****************************************************************************/ *****************************************************************************/
#if defined(__IMXRT1062__) // T4.0 #if defined(__IMXRT1062__) // T4.0

@ -238,18 +238,30 @@ public:
/// @returns the index in the encoder vector the new encoder was placed at. /// @returns the index in the encoder vector the new encoder was placed at.
unsigned addRotary(uint8_t pin1, uint8_t pin2, bool swapDirection = false, int divider = 1); unsigned addRotary(uint8_t pin1, uint8_t pin2, bool swapDirection = false, int divider = 1);
/// Get the number of registered rotary encoders
/// @returns the number of encoders registered
unsigned getNumRotary();
/// add a switch to the controls /// add a switch to the controls
/// @param pin the pin number connected to the switch /// @param pin the pin number connected to the switch
/// @param intervalMilliseconds, optional, specifies the filtering time to debounce a switch /// @param intervalMilliseconds, optional, specifies the filtering time to debounce a switch
/// @returns the index in the switch vector the new switch was placed at. /// @returns the index in the switch vector the new switch was placed at.
unsigned addSwitch(uint8_t pin, unsigned long intervalMilliseconds = 10); unsigned addSwitch(uint8_t pin, unsigned long intervalMilliseconds = 10);
/// Get the number of registered switches
/// @returns the number of switches registered
unsigned getNumSwitches();
/// add a pot to the controls /// add a pot to the controls
/// @param pin the pin number connected to the wiper of the pot /// @param pin the pin number connected to the wiper of the pot
/// @param minCalibration the value corresponding to lowest pot setting /// @param minCalibration the value corresponding to lowest pot setting
/// @param maxCalibration the value corresponding to the highest pot setting /// @param maxCalibration the value corresponding to the highest pot setting
unsigned addPot(uint8_t pin, unsigned minCalibration, unsigned maxCalibration); unsigned addPot(uint8_t pin, unsigned minCalibration, unsigned maxCalibration);
/// Get the number of registered pots
/// @returns the number of pots registered
unsigned getNumPots();
/// add a pot to the controls /// add a pot to the controls
/// @param pin the pin number connected to the wiper of the pot /// @param pin the pin number connected to the wiper of the pot
/// @param minCalibration the value corresponding to lowest pot setting /// @param minCalibration the value corresponding to lowest pot setting
@ -263,6 +275,10 @@ public:
/// @returns a handle (unsigned) to the added output. Use this to access the output. /// @returns a handle (unsigned) to the added output. Use this to access the output.
unsigned addOutput(uint8_t pin); unsigned addOutput(uint8_t pin);
/// Get the number of registered outputs
/// @returns the number of outputs registered
unsigned getNumOutputs();
/// Set the output specified by the provided handle /// Set the output specified by the provided handle
/// @param handle the handle that was provided previously by calling addOutput() /// @param handle the handle that was provided previously by calling addOutput()
/// @param val the value to set the output. 0 is low, not zero is high. /// @param val the value to set the output. 0 is low, not zero is high.

@ -49,10 +49,10 @@ public:
/// returns 0 if success, otherwise error /// returns 0 if success, otherwise error
int push_back(T element) { int push_back(T element) {
//Serial.println(String("RingBuffer::push_back...") + m_head + String(":") + m_tail + String(":") + m_size); //if (Serial) { Serial.println(String("RingBuffer::push_back...") + m_head + String(":") + m_tail + String(":") + m_size); }
if ( (m_head == m_tail) && (m_size > 0) ) { if ( (m_head == m_tail) && (m_size > 0) ) {
// overflow // overflow
Serial.println("RingBuffer::push_back: overflow"); if (Serial) { Serial.println("RingBuffer::push_back: overflow"); }
return -1; return -1;
} }
@ -73,7 +73,7 @@ public:
if (m_size == 0) { if (m_size == 0) {
// buffer is empty // buffer is empty
//Serial.println("RingBuffer::pop_front: buffer is empty\n"); // if (Serial) { Serial.println("RingBuffer::pop_front: buffer is empty\n"); }
return -1; return -1;
} }
if (m_tail < m_maxSize-1) { if (m_tail < m_maxSize-1) {
@ -82,7 +82,7 @@ public:
m_tail = 0; m_tail = 0;
} }
m_size--; m_size--;
//Serial.println(String("RingBuffer::pop_front: ") + m_head + String(":") + m_tail + String(":") + m_size); // if (Serial) { Serial.println(String("RingBuffer::pop_front: ") + m_head + String(":") + m_tail + String(":") + m_size); }
return 0; return 0;
} }
@ -141,8 +141,10 @@ public:
/// DEBUG: Prints the status of the Ringbuffer. NOte using this much printing will usually cause audio glitches /// DEBUG: Prints the status of the Ringbuffer. NOte using this much printing will usually cause audio glitches
void print() const { void print() const {
for (int idx=0; idx<m_maxSize; idx++) { for (int idx=0; idx<m_maxSize; idx++) {
Serial.print(idx + String(" address: ")); Serial.print((uint32_t)m_buffer[idx], HEX); if (Serial) {
Serial.print(" data: "); Serial.println((uint32_t)m_buffer[idx]->data, HEX); Serial.print(idx + String(" address: ")); Serial.print((uint32_t)m_buffer[idx], HEX);
Serial.print(" data: "); Serial.println((uint32_t)m_buffer[idx]->data, HEX);
}
} }
} }
private: private:

@ -58,8 +58,8 @@ class DummyChipSelect : public AbstractChipSelect
**/ **/
class DebugChipSelect : public AbstractChipSelect class DebugChipSelect : public AbstractChipSelect
{ {
void select(TransferType transferType = TransferType::NORMAL) override {Serial.println("Debug CS: select()");} void select(TransferType transferType = TransferType::NORMAL) override { if (Serial) Serial.println("Debug CS: select()");}
void deselect(TransferType transferType = TransferType::NORMAL) override {Serial.println("Debug CS: deselect()");} void deselect(TransferType transferType = TransferType::NORMAL) override { if (Serial) Serial.println("Debug CS: deselect()");}
}; };
/** \brief An active low chip select class. This also configures the given pin. /** \brief An active low chip select class. This also configures the given pin.
@ -114,7 +114,7 @@ class ActiveLowChipSelect : public AbstractChipSelect
}; };
#if defined(__MK66FX1M0__) #if defined(__MK66FX1M0__) || (defined(__IMXRT1062__) && (defined(ARDUINO_TEENSY_MICROMOD) || defined(ARDUINO_TEENSY41)))
class ActiveLowChipSelect1 : public AbstractChipSelect class ActiveLowChipSelect1 : public AbstractChipSelect
{ {
public: public:
@ -154,12 +154,12 @@ class ActiveLowChipSelect1 : public AbstractChipSelect
const SPISettings settings_; const SPISettings settings_;
}; };
#endif #endif // defined(__MK66FX1M0__) || (defined(__IMXRT1062__) && defined(ARDUINO_TEENSY_MICROMOD))
#if defined(DEBUG_DMASPI) #if defined(DEBUG_DMASPI)
#define DMASPI_PRINT(x) do {Serial.printf x ; Serial.flush();} while (0); #define DMASPI_PRINT(x) do { if (Serial) { Serial.printf x ; Serial.flush();} } while (0);
#else #else
#define DMASPI_PRINT(x) do {} while (0); #define DMASPI_PRINT(x) do {} while (0);
#endif #endif
@ -712,15 +712,17 @@ typename AbstractDmaSpi<DMASPI_INSTANCE, SPICLASS, m_Spi>::Transfer* volatile Ab
template<typename DMASPI_INSTANCE, typename SPICLASS, SPICLASS& m_Spi> template<typename DMASPI_INSTANCE, typename SPICLASS, SPICLASS& m_Spi>
volatile uint8_t AbstractDmaSpi<DMASPI_INSTANCE, SPICLASS, m_Spi>::m_devNull = 0; volatile uint8_t AbstractDmaSpi<DMASPI_INSTANCE, SPICLASS, m_Spi>::m_devNull = 0;
//void dump_dma(DMAChannel *dmabc) // void dump_dma(DMAChannel *dmabc)
//{ // {
// Serial.printf("%x %x:", (uint32_t)dmabc, (uint32_t)dmabc->TCD); // if (Serial) {
// // Serial.printf("%x %x:", (uint32_t)dmabc, (uint32_t)dmabc->TCD);
// Serial.printf("SA:%x SO:%d AT:%x NB:%x SL:%d DA:%x DO: %d CI:%x DL:%x CS:%x BI:%x\n", (uint32_t)dmabc->TCD->SADDR,
// dmabc->TCD->SOFF, dmabc->TCD->ATTR, dmabc->TCD->NBYTES, dmabc->TCD->SLAST, (uint32_t)dmabc->TCD->DADDR, // Serial.printf("SA:%x SO:%d AT:%x NB:%x SL:%d DA:%x DO: %d CI:%x DL:%x CS:%x BI:%x\n", (uint32_t)dmabc->TCD->SADDR,
// dmabc->TCD->DOFF, dmabc->TCD->CITER, dmabc->TCD->DLASTSGA, dmabc->TCD->CSR, dmabc->TCD->BITER); // dmabc->TCD->SOFF, dmabc->TCD->ATTR, dmabc->TCD->NBYTES, dmabc->TCD->SLAST, (uint32_t)dmabc->TCD->DADDR,
// Serial.flush(); // dmabc->TCD->DOFF, dmabc->TCD->CITER, dmabc->TCD->DLASTSGA, dmabc->TCD->CSR, dmabc->TCD->BITER);
//} // Serial.flush();
// }
// }
#if defined(__IMXRT1062__) // T4.0 #if defined(__IMXRT1062__) // T4.0
@ -764,37 +766,8 @@ public:
IMXRT_LPSPI4_S.DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; //enable DMA on both TX and RX IMXRT_LPSPI4_S.DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; //enable DMA on both TX and RX
IMXRT_LPSPI4_S.SR = 0x3f00; // clear out all of the other status... IMXRT_LPSPI4_S.SR = 0x3f00; // clear out all of the other status...
// if (m_pCurrentTransfer->m_pSource) {
// arm_dcache_flush((void *)m_pCurrentTransfer->m_pSource, m_pCurrentTransfer->m_transferCount);
// }
} }
// static void pre_cs_impl()
// {
//
// //LPSPI4_PARAM = LPSPI4_PARAM;
// //LPSPI4_PARAM = 0x0404;
// //DMASPI_PRINT(("!!!!!!!!!!!!!!!!!!!!!PARAM reg is %08X\n", LPSPI4_PARAM));
// txChannel_()->TCD->ATTR_SRC = 0; //Make sure set for 8 bit mode...
// txChannel_()->TCD->SLAST = 0; // Finish with it pointing to next location
// rxChannel_()->TCD->ATTR_DST = 0; //Make sure set for 8 bit mode...
// rxChannel_()->TCD->DLASTSGA = 0;
//
// //DMASPI_PRINT(("STATUS SR reg is %08X\n", LPSPI4_SR));
// if (LPSPI4_SR & 0x1800) {
// DMASPI_PRINT(("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ERROR SR reg is %08X\n", LPSPI4_SR));
// }
// LPSPI4_SR = 0x3f00; // clear various error and status flags
// DMASPI_PRINT(("********************************************CHECK SR reg is %08X\n", LPSPI4_SR));
//
// LPSPI4_TCR = (LPSPI4_TCR & ~(LPSPI_TCR_FRAMESZ(31))) | LPSPI_TCR_FRAMESZ(7); // Set the FRAMESZ to 7 for 8-bit frame size
// LPSPI4_FCR = 0; // set watermarks to zero, this ensures ready flag is set whenever fifo is not empty
//
// LPSPI4_CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; //enable module and reset both FIFOs
// LPSPI4_DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; // enable DMA on both TX and RX
// }
static void post_cs_impl() static void post_cs_impl()
{ {
rxChannel_()->enable(); rxChannel_()->enable();
@ -810,23 +783,76 @@ public:
IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; // actually clear both... IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; // actually clear both...
IMXRT_LPSPI4_S.SR = 0x3f00; // clear out all of the other status... IMXRT_LPSPI4_S.SR = 0x3f00; // clear out all of the other status...
// if (m_pCurrentTransfer->m_pDest) {
// arm_dcache_delete((void *)m_pCurrentTransfer->m_pDest, m_pCurrentTransfer->m_transferCount);
// }
} }
// static void post_finishCurrentTransfer_impl() private:
// { };
// //LPSPI4_FCR = LPSPI_FCR_TXWATER(15); // restore FSR status extern DmaSpi0 DMASPI0;
// LPSPI4_DER = 0; // DMA no longer doing TX or RX
// LPSPI4_CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; //enable module and reset both FIFOs #if (defined(__IMXRT1062__) && (defined(ARDUINO_TEENSY_MICROMOD) || defined (ARDUINO_TEENSY41)))
// LPSPI4_SR = 0x3f00; // clear out all the other statuses // On T4.X, SPI1 is LPSPI3
// }
class DmaSpi1 : public AbstractDmaSpi<DmaSpi1, SPIClass, SPI1>
{
public:
static void begin_setup_txChannel_impl()
{
txChannel_()->disable();
txChannel_()->destination((volatile uint8_t&)IMXRT_LPSPI3_S.TDR);
txChannel_()->disableOnCompletion();
txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI3_TX);
}
static void begin_setup_rxChannel_impl()
{
rxChannel_()->disable();
rxChannel_()->source((volatile uint8_t&)IMXRT_LPSPI3_S.RDR); // POPR is the receive fifo register for the SPI
rxChannel_()->disableOnCompletion();
rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI3_RX); // The DMA RX id for MT66 is 14
rxChannel_()->attachInterrupt(rxIsr_);
rxChannel_()->interruptAtCompletion();
}
static void pre_cs_impl()
{
if (LPSPI3_SR & 0x1800) {
DMASPI_PRINT(("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ERROR SR reg is %08X\n\r", LPSPI3_SR));
}
DMASPI_PRINT(("********************************************CHECK SR reg is %08X\n\r", LPSPI3_SR));
IMXRT_LPSPI3_S.TCR = (IMXRT_LPSPI3_S.TCR & ~(LPSPI_TCR_FRAMESZ(31))) | LPSPI_TCR_FRAMESZ(7);
IMXRT_LPSPI3_S.FCR = 0;
IMXRT_LPSPI3_S.CR = LPSPI_CR_MEN; // I had to add the enable otherwise it wont' work
// Lets try to output the first byte to make sure that we are in 8 bit mode...
IMXRT_LPSPI3_S.DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; //enable DMA on both TX and RX
IMXRT_LPSPI3_S.SR = 0x3f00; // clear out all of the other status...
}
static void post_cs_impl()
{
rxChannel_()->enable();
txChannel_()->enable();
DMASPI_PRINT(("Done post_cs_impl()\n\r"));
}
static void post_finishCurrentTransfer_impl()
{
IMXRT_LPSPI3_S.FCR = LPSPI_FCR_TXWATER(15); // _spi_fcr_save; // restore the FSR status...
IMXRT_LPSPI3_S.DER = 0; // DMA no longer doing TX (or RX)
IMXRT_LPSPI3_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; // actually clear both...
IMXRT_LPSPI3_S.SR = 0x3f00; // clear out all of the other status...
}
private: private:
}; };
extern DmaSpi1 DMASPI1;
extern DmaSpi0 DMASPI0; #endif // (defined(__IMXRT1062__) && defined(ARDUINO_TEENSY_MICROMOD))
#elif defined(KINETISK) #elif defined(KINETISK)
@ -1050,7 +1076,7 @@ public:
// { // {
// DMASPI_PRINT(("%s: %x %x %x %x \n", sz, p[0], p[1], p[2], p[3])); // DMASPI_PRINT(("%s: %x %x %x %x \n", sz, p[0], p[1], p[2], p[3]));
// } // }
static void post_cs_impl() static void post_cs_impl()
{ {
DMASPI_PRINT(("post_cs S C1 C2: %x %x %x\n", SPI1_S, SPI1_C1, SPI1_C2)); DMASPI_PRINT(("post_cs S C1 C2: %x %x %x\n", SPI1_S, SPI1_C1, SPI1_C2));

@ -80,6 +80,55 @@ public:
/// @returns the read position value /// @returns the read position value
size_t getReadPosition() const { return m_currentRdPosition-m_start; } size_t getReadPosition() const { return m_currentRdPosition-m_start; }
/* Byte-based transfers */
/// Write a block of zeros (8-bit) to the memory at the specified offset
/// @param offsetBytes offset in 8-bit bytes from start of slot
/// @param numBytes number of 8-bit bytes to transfer
/// @returns true on success, else false on error
bool zero(size_t offsetBytes, size_t numBytes);
/// Write a block of 8-bit data to the memory at the specified offset
/// @param offsetBytes offset in 8-bit bytes from start of slot
/// @param src pointer to start of block of 16-bit data
/// @param numBytes number of 8-bit bytes to transfer
/// @returns true on success, else false on error
bool write(size_t offsetBytes, uint8_t *src, size_t numBytes);
/// Read a block of 8-bit data from the memory at the specified location
/// @param offsetBytes offset in 8-bit bytes from start of slot
/// @param dest pointer to destination for the read data
/// @param numBytes number of 8-bit bytes to transfer
/// @returns true on success, else false on error
bool read(size_t offsetBytes, uint8_t *dest, size_t numBytes);
/// Write a block of 16-bit data zeros in circular operation
/// @param numBytes number of 16-bit words to transfer
/// @returns true on success, else false on error
bool zeroAdvance(size_t numBytes);
/// Write a single 16-bit data to the next location in circular operation
/// @param data the 16-bit word to transfer
/// @returns true on success, else false on error
bool writeAdvance(uint8_t data); // write just one data
/// Write a block of 16-bit data from the specified location in circular operation
/// @param src pointer to the start of the block of data to write to memory
/// @param numBytes number of 16-bit words to transfer
/// @returns true on success, else false on error
bool writeAdvance(uint8_t *src, size_t numBytes);
/// Read the next byte in memory during circular operation
/// @returns the next 8-bit data word in memory
uint8_t readAdvance();
/// Read the next block of numWords during circular operation
/// @details, dest is ignored when using DMA
/// @param dest pointer to the destination of the read.
/// @param numBytes number of 16-bit words to transfer
/// @returns true on success, else false on error
bool readAdvance(uint8_t *dest, size_t numBytes);
/// Write a block of 16-bit data to the memory at the specified offset /// Write a block of 16-bit data to the memory at the specified offset
/// @param offsetWords offset in 16-bit words from start of slot /// @param offsetWords offset in 16-bit words from start of slot
/// @param src pointer to start of block of 16-bit data /// @param src pointer to start of block of 16-bit data
@ -100,11 +149,12 @@ public:
/// @returns true on success, else false on error /// @returns true on success, else false on error
bool read16(size_t offsetWords, int16_t *dest, size_t numWords); bool read16(size_t offsetWords, int16_t *dest, size_t numWords);
/* 16-bit data transfers */
/// Read the next in memory during circular operation /// Read the next in memory during circular operation
/// @returns the next 16-bit data word in memory /// @returns the next 16-bit data word in memory
uint16_t readAdvance16(); uint16_t readAdvance16();
/// Read the next block of numWords during circular operation /// Read the next block of numWords during circular operation
/// @details, dest is ignored when using DMA /// @details, dest is ignored when using DMA
/// @param dest pointer to the destination of the read. /// @param dest pointer to the destination of the read.

@ -76,7 +76,9 @@ audio_block_t* AudioDelay::addBlock(audio_block_t *block)
} else { } else {
// EXTERNAL memory // EXTERNAL memory
if (!m_slot) { Serial.println("addBlock(): m_slot is not valid"); } if (!m_slot) {
if (Serial) { Serial.println("addBlock(): m_slot is not valid"); }
}
if (block) { if (block) {
@ -128,7 +130,7 @@ bool AudioDelay::getSamples(int16_t *dest, size_t offsetSamples, size_t numSampl
bool AudioDelay::m_getSamples(int16_t *dest, size_t offsetSamples, size_t numSamples) bool AudioDelay::m_getSamples(int16_t *dest, size_t offsetSamples, size_t numSamples)
{ {
if (!dest) { if (!dest) {
Serial.println("getSamples(): dest is invalid"); if (Serial) { Serial.println("getSamples(): dest is invalid"); }
return false; return false;
} }
@ -196,8 +198,8 @@ bool AudioDelay::m_getSamples(int16_t *dest, size_t offsetSamples, size_t numSam
return true; return true;
} else { } else {
// numSamples is > than total slot size // numSamples is > than total slot size
Serial.println("getSamples(): ERROR numSamples > total slot size"); if (Serial) { Serial.println("getSamples(): ERROR numSamples > total slot size"); }
Serial.println(numSamples + String(" > ") + m_slot->size()); if (Serial) { Serial.println(numSamples + String(" > ") + m_slot->size()); }
return false; return false;
} }
} }

@ -40,6 +40,7 @@ uint8_t BA_EXPAND_POT3_PIN = A2; // 16_A2_RX4_SCL1
uint8_t BA_EXPAND_SW1_PIN = 2; // 2_OUT2 uint8_t BA_EXPAND_SW1_PIN = 2; // 2_OUT2
uint8_t BA_EXPAND_SW2_PIN = 3; // 3_LRCLK2 uint8_t BA_EXPAND_SW2_PIN = 3; // 3_LRCLK2
uint8_t BA_EXPAND_LED1_PIN = 4; // 4_BLCK2 uint8_t BA_EXPAND_LED1_PIN = 4; // 4_BLCK2
uint8_t BA_EXPAND_LED2_PIN = 5; // 5_IN2 uint8_t BA_EXPAND_LED2_PIN = 5; // 5_IN2
@ -66,6 +67,27 @@ uint8_t SPI1_CS_PIN = 38;
uint8_t SPI1_MISO_PIN = 39; uint8_t SPI1_MISO_PIN = 39;
uint8_t SPI1_MOSI_PIN = 26; uint8_t SPI1_MOSI_PIN = 26;
// The following pins are only used on Multiverse
// They have dummy default values
uint8_t BA_EXPAND_POT4_PIN = A0;
uint8_t BA_EXPAND_POT5_PIN = A0;
uint8_t BA_EXPAND_POT6_PIN = A0;
uint8_t BA_EXPAND_SW3_PIN = 0;
uint8_t BA_EXPAND_SW4_PIN = 0;
uint8_t BA_EXPAND_SW5_PIN = 0;
uint8_t BA_EXPAND_SW6_PIN = 0;
uint8_t BA_EXPAND_ENC1_A_PIN = 0;
uint8_t BA_EXPAND_ENC1_B_PIN = 0;
uint8_t BA_EXPAND_ENC2_A_PIN = 0;
uint8_t BA_EXPAND_ENC2_B_PIN = 0;
uint8_t BA_EXPAND_ENC3_A_PIN = 0;
uint8_t BA_EXPAND_ENC3_B_PIN = 0;
uint8_t BA_EXPAND_ENC4_A_PIN = 0;
uint8_t BA_EXPAND_ENC4_B_PIN = 0;
BAHardware::BAHardware() BAHardware::BAHardware()
{ {
#if defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY_MICROMOD) // T4.X #if defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY_MICROMOD) // T4.X
@ -88,6 +110,7 @@ void BAHardware::set(TgaBoard tgaBoard)
if (tgaBoard == TgaBoard::MKII_REV1) { if (tgaBoard == TgaBoard::MKII_REV1) {
// No change from defaults // No change from defaults
} }
return;
#endif #endif
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__) // T3.6 or T3.5 or T3.2 #if defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__) // T3.6 or T3.5 or T3.2
@ -126,6 +149,7 @@ void BAHardware::set(TgaBoard tgaBoard)
SPI1_MISO_PIN = 5; SPI1_MISO_PIN = 5;
SPI1_MOSI_PIN = 21; SPI1_MOSI_PIN = 21;
} }
return;
#endif #endif
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -162,6 +186,7 @@ void BAHardware::set(TgaBoard tgaBoard)
SPI0_MISO_PIN = 12; SPI0_MISO_PIN = 12;
SPI0_MOSI_PIN = 11; SPI0_MOSI_PIN = 11;
} }
return;
#endif #endif
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__) // T3.6 or T3.5 or T3.2 #if defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__) // T3.6 or T3.5 or T3.2
@ -199,6 +224,7 @@ void BAHardware::set(TgaBoard tgaBoard)
SPI1_MISO_PIN = 5; SPI1_MISO_PIN = 5;
SPI1_MOSI_PIN = 21; SPI1_MOSI_PIN = 21;
} }
return;
#endif #endif
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -226,6 +252,7 @@ void BAHardware::set(TgaBoard tgaBoard)
SPI0_MISO_PIN = 12; SPI0_MISO_PIN = 12;
SPI0_MOSI_PIN = 11; SPI0_MOSI_PIN = 11;
} }
return;
#endif #endif
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__) // T3.6 or T3.5 or T3.2 #if defined(__MK66FX1M0__) || defined(__MK64FX512__) || defined(__MK20DX256__) // T3.6 or T3.5 or T3.2
@ -255,32 +282,57 @@ void BAHardware::set(TgaBoard tgaBoard)
SPI1_MISO_PIN = 5; SPI1_MISO_PIN = 5;
SPI1_MOSI_PIN = 21; SPI1_MOSI_PIN = 21;
} }
return;
#endif #endif
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Avalon // // MULTIVERSE //
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
#if defined(ARDUINO_TEENSY41) // T4.X #if defined(ARDUINO_TEENSY_MICROMOD)
if (tgaBoard == TgaBoard::AVALON) { if (tgaBoard == TgaBoard::MULTIVERSE) {
BA_EXPAND_NUM_POT = 2; BA_EXPAND_NUM_POT = 4;
BA_EXPAND_NUM_SW = 6; BA_EXPAND_NUM_SW = 6;
BA_EXPAND_NUM_LED = 2; BA_EXPAND_NUM_LED = 2;
BA_EXPAND_NUM_ENC = 4; BA_EXPAND_NUM_ENC = 4;
BA_EXPAND_POT1_PIN = A0; BA_EXPAND_POT1_PIN = A8;
BA_EXPAND_POT2_PIN = A1; BA_EXPAND_POT2_PIN = A0;
BA_EXPAND_POT3_PIN = A13; BA_EXPAND_POT3_PIN = A2;
BA_EXPAND_POT4_PIN = A3;
BA_EXPAND_SW1_PIN = 6;
BA_EXPAND_SW2_PIN = 34;
BA_EXPAND_SW3_PIN = 45;
BA_EXPAND_SW4_PIN = 32;
BA_EXPAND_SW5_PIN = 41;
BA_EXPAND_SW6_PIN = 40;
BA_EXPAND_SW1_PIN = 17; BA_EXPAND_ENC1_A_PIN = 33;
BA_EXPAND_SW2_PIN = 16; BA_EXPAND_ENC1_B_PIN = 2;
BA_EXPAND_LED1_PIN = 22;
BA_EXPAND_LED2_PIN = 32; BA_EXPAND_ENC2_A_PIN = 31;
BA_EXPAND_ENC2_B_PIN = 36;
BA_EXPAND_ENC3_A_PIN = 5;
BA_EXPAND_ENC3_B_PIN = 4;
BA_EXPAND_ENC4_A_PIN = 3;
BA_EXPAND_ENC4_B_PIN = 30;
BA_EXPAND_LED1_PIN = 9;
BA_EXPAND_LED2_PIN = 42;
SPI0_SCK_PIN = 13; SPI0_SCK_PIN = 13;
SPI0_CS_PIN = 10; SPI0_CS_PIN = 10;
SPI0_MISO_PIN = 12; SPI0_MISO_PIN = 12;
SPI0_MOSI_PIN = 11; SPI0_MOSI_PIN = 11;
SPI1_SCK_PIN = 27;
SPI1_CS_PIN = 43;
SPI1_MISO_PIN = 1;
SPI1_MOSI_PIN = 26;
} }
return;
#endif #endif
} }

@ -31,7 +31,7 @@ namespace BALibrary {
bool ExtMemSlot::clear() bool ExtMemSlot::clear()
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
m_spi->zero16(m_start, m_size); m_spi->zero(m_start, m_size);
return true; return true;
} }
@ -43,13 +43,25 @@ bool ExtMemSlot::setWritePosition(size_t offsetBytes)
} else { return false; } } else { return false; }
} }
bool ExtMemSlot::write16(size_t offsetWords, int16_t *src, size_t numWords) bool ExtMemSlot::setReadPosition(size_t offsetBytes)
{
if (m_start + offsetBytes <= m_end) {
m_currentRdPosition = m_start + offsetBytes;
return true;
} else {
return false;
}
}
/////////////////////////////////////////////////////////////////////////
// BYTE BASED TRANSFERS
/////////////////////////////////////////////////////////////////////////
bool ExtMemSlot::zero(size_t offsetBytes, size_t numBytes)
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
size_t writeStart = m_start + sizeof(int16_t)*offsetWords; // 2x because int16 is two bytes per data size_t writeStart = m_start + offsetBytes;
size_t numBytes = sizeof(int16_t)*numWords;
if ((writeStart + numBytes-1) <= m_end) { if ((writeStart + numBytes-1) <= m_end) {
m_spi->write16(writeStart, reinterpret_cast<uint16_t*>(src), numWords); // cast audio data to uint m_spi->zero(writeStart, numBytes); // cast audio data to uint
return true; return true;
} else { } else {
// this would go past the end of the memory slot, do not perform the write // this would go past the end of the memory slot, do not perform the write
@ -57,16 +69,138 @@ bool ExtMemSlot::write16(size_t offsetWords, int16_t *src, size_t numWords)
} }
} }
bool ExtMemSlot::setReadPosition(size_t offsetBytes) bool ExtMemSlot::write(size_t offsetBytes, uint8_t *src, size_t numBytes)
{ {
if (m_start + offsetBytes <= m_end) { if (!m_valid) { return false; }
m_currentRdPosition = m_start + offsetBytes; size_t writeStart = m_start + offsetBytes;
if ((writeStart + numBytes-1) <= m_end) {
m_spi->write(writeStart, src, numBytes); // cast audio data to uint
return true;
} else {
// this would go past the end of the memory slot, do not perform the write
return false;
}
}
bool ExtMemSlot::read(size_t offsetBytes, uint8_t *dest, size_t numBytes)
{
if (!dest) return false; // invalid destination
size_t readOffset = m_start + offsetBytes;
if ((readOffset + numBytes-1) <= m_end) {
m_spi->read(readOffset, dest, numBytes);
return true;
} else {
// this would go past the end of the memory slot, do not perform the read
return false;
}
}
bool ExtMemSlot::zeroAdvance(size_t numBytes)
{
if (!m_valid) { return false; }
if (m_currentWrPosition + numBytes-1 <= m_end) {
// entire block fits in memory slot without wrapping
m_spi->zero(m_currentWrPosition, numBytes); // cast audio data to uint.
m_currentWrPosition += numBytes;
} else {
// this write will wrap the memory slot
size_t wrBytes = m_end - m_currentWrPosition + 1;
m_spi->zero(m_currentWrPosition, wrBytes);
size_t remainingBytes = numBytes - wrBytes; // calculate the remaining bytes
m_spi->zero(m_start, remainingBytes); // write remaining bytes are start
m_currentWrPosition = m_start + remainingBytes;
}
return true;
}
bool ExtMemSlot::writeAdvance(uint8_t data)
{
if (!m_valid) { return false; }
m_spi->write(m_currentWrPosition, static_cast<uint8_t>(data));
if (m_currentWrPosition < m_end-1) {
m_currentWrPosition++; // wrote two bytes
} else {
m_currentWrPosition = m_start;
}
return true;
}
bool ExtMemSlot::writeAdvance(uint8_t *src, size_t numBytes)
{
if (!m_valid) { return false; }
if (m_currentWrPosition + numBytes-1 <= m_end) {
// entire block fits in memory slot without wrapping
m_spi->write(m_currentWrPosition, reinterpret_cast<uint8_t*>(src), numBytes); // cast audio data to uint.
m_currentWrPosition += numBytes;
} else {
// this write will wrap the memory slot
size_t wrBytes = m_end - m_currentWrPosition + 1;
m_spi->write(m_currentWrPosition, src, wrBytes);
size_t remainingData = numBytes - wrBytes;
m_spi->write(m_start, src + wrBytes, remainingData); // write remaining bytes are start
m_currentWrPosition = m_start + remainingData;
}
return true;
}
/// Read the next in memory during circular operation
/// @returns the next 8-bit data word in memory
uint8_t ExtMemSlot::readAdvance() {
uint8_t val = m_spi->read(m_currentRdPosition);
if (m_currentRdPosition < m_end-1) {
m_currentRdPosition ++; // position is in bytes and we read two
} else {
m_currentRdPosition = m_start;
}
return val;
}
bool ExtMemSlot::readAdvance(uint8_t *dest, size_t numBytes)
{
if (!m_valid) { return false; }
if (m_currentRdPosition + numBytes-1 <= m_end) {
// entire block fits in memory slot without wrapping
m_spi->read(m_currentRdPosition, dest, numBytes); // cast audio data to uint.
m_currentRdPosition += numBytes;
} else {
// this read will wrap the memory slot
size_t rdBytes = m_end - m_currentRdPosition + 1;
m_spi->read(m_currentRdPosition, dest, rdBytes);
size_t remainingData = numBytes - rdBytes;
m_spi->read(m_start, (dest + rdBytes), remainingData); // write remaining bytes are start
m_currentRdPosition = m_start + remainingData;
}
return true;
}
/////////////////////////////////////////////////////////////////////////
// 16-BIT BASED TRANSFERS
/////////////////////////////////////////////////////////////////////////
bool ExtMemSlot::write16(size_t offsetWords, int16_t *src, size_t numWords)
{
if (!m_valid) { return false; }
size_t writeStart = m_start + sizeof(int16_t)*offsetWords; // 2x because int16 is two bytes per data
size_t numBytes = sizeof(int16_t)*numWords;
if ((writeStart + numBytes-1) <= m_end) {
m_spi->write16(writeStart, reinterpret_cast<uint16_t*>(src), numWords); // cast audio data to uint
return true; return true;
} else { } else {
// this would go past the end of the memory slot, do not perform the write
return false; return false;
} }
} }
bool ExtMemSlot::zero16(size_t offsetWords, size_t numWords) bool ExtMemSlot::zero16(size_t offsetWords, size_t numWords)
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
@ -198,12 +332,12 @@ bool ExtMemSlot::writeAdvance16(int16_t data)
bool ExtMemSlot::enable() const bool ExtMemSlot::enable() const
{ {
if (m_spi) { if (m_spi) {
Serial.println("ExtMemSlot::enable()"); if (Serial) { Serial.println("ExtMemSlot::enable()"); }
m_spi->begin(); m_spi->begin();
return true; return true;
} }
else { else {
Serial.println("ExtMemSlot m_spi is nullptr"); if (Serial) { Serial.println("ExtMemSlot m_spi is nullptr"); }
return false; return false;
} }
} }
@ -231,10 +365,11 @@ bool ExtMemSlot::isReadBusy() const
void ExtMemSlot::printStatus(void) const void ExtMemSlot::printStatus(void) const
{ {
Serial.println(String("valid:") + m_valid + String(" m_start:") + m_start + \ if (Serial) { Serial.println(String("valid:") + m_valid + String(" m_start:") + m_start + \
String(" m_end:") + m_end + String(" m_currentWrPosition: ") + m_currentWrPosition + \ String(" m_end:") + m_end + String(" m_currentWrPosition: ") + m_currentWrPosition + \
String(" m_currentRdPosition: ") + m_currentRdPosition + \ String(" m_currentRdPosition: ") + m_currentRdPosition + \
String(" m_size:") + m_size); String(" m_size:") + m_size);
}
} }
} }

@ -68,7 +68,7 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALi
if (!m_configured) { m_configure(); } if (!m_configured) { m_configure(); }
if (m_memConfig[mem].totalAvailable >= sizeBytes) { if (m_memConfig[mem].totalAvailable >= sizeBytes) {
Serial.println(String("Configuring a slot for mem ") + mem); if (Serial) Serial.printf("Configuring mem %d, for size %d, available %d\n\r", (unsigned)mem, sizeBytes, m_memConfig[mem].totalAvailable);
// there is enough available memory for this request // there is enough available memory for this request
slot->m_start = m_memConfig[mem].nextAvailable; slot->m_start = m_memConfig[mem].nextAvailable;
slot->m_end = slot->m_start + sizeBytes -1; slot->m_end = slot->m_start + sizeBytes -1;
@ -78,15 +78,18 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALi
if (!m_memConfig[mem].m_spi) { if (!m_memConfig[mem].m_spi) {
if (useDma) { if (useDma) {
if (Serial) { Serial.printf("Creating S for id %d\n\r", (int)mem);}
m_memConfig[mem].m_spi = new BALibrary::BASpiMemoryDMA(static_cast<BALibrary::SpiDeviceId>(mem)); m_memConfig[mem].m_spi = new BALibrary::BASpiMemoryDMA(static_cast<BALibrary::SpiDeviceId>(mem));
slot->m_useDma = true; slot->m_useDma = true;
} else { } else {
if (Serial) { Serial.printf("Creating BASpiMemory for id %d\n\r", (int)mem);}
m_memConfig[mem].m_spi = new BALibrary::BASpiMemory(static_cast<BALibrary::SpiDeviceId>(mem)); m_memConfig[mem].m_spi = new BALibrary::BASpiMemory(static_cast<BALibrary::SpiDeviceId>(mem));
slot->m_useDma = false; slot->m_useDma = false;
} }
if (!m_memConfig[mem].m_spi) { if (!m_memConfig[mem].m_spi) {
if (Serial) { Serial.printf("Failed to create SPI for id %d\n\r", (int)mem);}
} else { } else {
Serial.println("Calling spi begin()"); if (Serial) { Serial.println("Calling spi begin()"); }
m_memConfig[mem].m_spi->begin(); m_memConfig[mem].m_spi->begin();
} }
} }
@ -97,15 +100,14 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALi
m_memConfig[mem].totalAvailable -= sizeBytes; m_memConfig[mem].totalAvailable -= sizeBytes;
slot->m_valid = true; slot->m_valid = true;
if (!slot->isEnabled()) { slot->enable(); } if (!slot->isEnabled()) { slot->enable(); }
Serial.println("Clear the memory\n"); Serial.flush(); // Note: we no longer auto-clear the slot (on purpose)
slot->clear(); if (Serial) { Serial.println("Done Request memory\n"); Serial.flush(); }
Serial.println("Done Request memory\n"); Serial.flush();
return true; return true;
} else { } else {
// there is not enough memory available for the request // there is not enough memory available for the request
Serial.println(String("ExternalSramManager::requestMemory(): Insufficient memory in slot, request/available: ") if (Serial) { Serial.println(String("ExternalSramManager::requestMemory(): Insufficient memory in slot, request/available: ")
+ sizeBytes + String(" : ") + sizeBytes + String(" : ")
+ m_memConfig[mem].totalAvailable); + m_memConfig[mem].totalAvailable); }
return false; return false;
} }
} }

@ -134,9 +134,9 @@ T ParameterAutomation<T>::getNextValue()
} else { } else {
returnValue = m_startValue - (m_scaleY*value); returnValue = m_startValue - (m_scaleY*value);
} }
// Serial.println(String("Start/End values: ") + m_startValue + String(":") + m_endValue); // if (Serial) { Serial.println(String("Start/End values: ") + m_startValue + String(":") + m_endValue); }
//Serial.print("Parameter m_currentValueX is "); Serial.println(m_currentValueX, 6); // if (Serial) { Serial.print("Parameter m_currentValueX is "); Serial.println(m_currentValueX, 6); }
//Serial.print("Parameter returnValue is "); Serial.println(returnValue, 6); // if (Serial) { Serial.print("Parameter returnValue is "); Serial.println(returnValue, 6); }
return returnValue; return returnValue;
} }
@ -175,7 +175,7 @@ ParameterAutomationSequence<T>::~ParameterAutomationSequence()
template <class T> template <class T>
void ParameterAutomationSequence<T>::setupParameter(int index, T startValue, T endValue, size_t durationSamples, typename ParameterAutomation<T>::Function function) void ParameterAutomationSequence<T>::setupParameter(int index, T startValue, T endValue, size_t durationSamples, typename ParameterAutomation<T>::Function function)
{ {
Serial.println(String("setupParameter() called with samples: ") + durationSamples); if (Serial) { Serial.println(String("setupParameter() called with samples: ") + durationSamples); }
m_paramArray[index]->reconfigure(startValue, endValue, durationSamples, function); m_paramArray[index]->reconfigure(startValue, endValue, durationSamples, function);
m_currentIndex = 0; m_currentIndex = 0;
} }
@ -183,7 +183,7 @@ void ParameterAutomationSequence<T>::setupParameter(int index, T startValue, T e
template <class T> template <class T>
void ParameterAutomationSequence<T>::setupParameter(int index, T startValue, T endValue, float durationMilliseconds, typename ParameterAutomation<T>::Function function) void ParameterAutomationSequence<T>::setupParameter(int index, T startValue, T endValue, float durationMilliseconds, typename ParameterAutomation<T>::Function function)
{ {
Serial.print(String("setupParameter() called with time: ")); Serial.println(durationMilliseconds, 6); if (Serial) { Serial.print(String("setupParameter() called with time: ")); Serial.println(durationMilliseconds, 6); }
m_paramArray[index]->reconfigure(startValue, endValue, durationMilliseconds, function); m_paramArray[index]->reconfigure(startValue, endValue, durationMilliseconds, function);
m_currentIndex = 0; m_currentIndex = 0;
} }
@ -194,7 +194,7 @@ void ParameterAutomationSequence<T>::trigger(void)
m_currentIndex = 0; m_currentIndex = 0;
m_paramArray[0]->trigger(); m_paramArray[0]->trigger();
m_running = true; m_running = true;
//Serial.println("ParameterAutomationSequence<T>::trigger() called"); // if (Serial) { Serial.println("ParameterAutomationSequence<T>::trigger() called"); }
} }
template <class T> template <class T>
@ -204,17 +204,17 @@ T ParameterAutomationSequence<T>::getNextValue()
T nextValue = m_paramArray[m_currentIndex]->getNextValue(); T nextValue = m_paramArray[m_currentIndex]->getNextValue();
if (m_running) { if (m_running) {
//Serial.println(String("ParameterAutomationSequence<T>::getNextValue() is ") + nextValue // if (Serial) { Serial.println(String("ParameterAutomationSequence<T>::getNextValue() is ") + nextValue
// + String(" from stage ") + m_currentIndex); // + String(" from stage ") + m_currentIndex); }
// If current stage is done, trigger the next // If current stage is done, trigger the next
if (m_paramArray[m_currentIndex]->isFinished()) { if (m_paramArray[m_currentIndex]->isFinished()) {
Serial.println(String("Finished stage ") + m_currentIndex); if (Serial) { Serial.println(String("Finished stage ") + m_currentIndex); }
m_currentIndex++; m_currentIndex++;
if (m_currentIndex >= m_numStages) { if (m_currentIndex >= m_numStages) {
// Last stage already finished // Last stage already finished
Serial.println("Last stage finished"); if (Serial) { Serial.println("Last stage finished"); }
m_running = false; m_running = false;
m_currentIndex = 0; m_currentIndex = 0;
} else { } else {

@ -3,7 +3,20 @@
* *
* Created on: Jan 7, 2018 * Created on: Jan 7, 2018
* Author: slascos * Author: slascos
*/ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <new> #include <new>
#include "AudioEffectAnalogDelayFilters.h" #include "AudioEffectAnalogDelayFilters.h"
#include "AudioEffectAnalogDelay.h" #include "AudioEffectAnalogDelay.h"
@ -166,22 +179,26 @@ void AudioEffectAnalogDelay::delay(float milliseconds)
{ {
size_t delaySamples = calcAudioSamples(milliseconds); size_t delaySamples = calcAudioSamples(milliseconds);
if (!m_memory) { Serial.println("delay(): m_memory is not valid"); return; } if (!m_memory) {
if (Serial) { Serial.println("delay(): m_memory is not valid"); return; }
}
if (!m_externalMemory) { if (!m_externalMemory) {
// internal memory // internal memory
m_maxDelaySamples = m_memory->getMaxDelaySamples(); m_maxDelaySamples = m_memory->getMaxDelaySamples();
//QueuePosition queuePosition = calcQueuePosition(milliseconds); //QueuePosition queuePosition = calcQueuePosition(milliseconds);
//Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); // if (Serial) { Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); }
} else { } else {
// external memory // external memory
ExtMemSlot *slot = m_memory->getSlot(); ExtMemSlot *slot = m_memory->getSlot();
m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES; m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES;
if (!slot) { Serial.println("ERROR: slot ptr is not valid"); } if (!slot) {
if (Serial) { Serial.println("ERROR: slot ptr is not valid"); }
}
if (!slot->isEnabled()) { if (!slot->isEnabled()) {
slot->enable(); slot->enable();
Serial.println("WEIRD: slot was not enabled"); if (Serial) { Serial.println("WEIRD: slot was not enabled"); }
} }
} }
@ -194,16 +211,16 @@ void AudioEffectAnalogDelay::delay(float milliseconds)
void AudioEffectAnalogDelay::delay(size_t delaySamples) void AudioEffectAnalogDelay::delay(size_t delaySamples)
{ {
if (!m_memory) { Serial.println("delay(): m_memory is not valid"); } if (!m_memory) { if (Serial) Serial.println("delay(): m_memory is not valid"); }
if (!m_externalMemory) { if (!m_externalMemory) {
// internal memory // internal memory
m_maxDelaySamples = m_memory->getMaxDelaySamples(); m_maxDelaySamples = m_memory->getMaxDelaySamples();
//QueuePosition queuePosition = calcQueuePosition(delaySamples); //QueuePosition queuePosition = calcQueuePosition(delaySamples);
//Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); // if (Serial) { Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); }
} else { } else {
// external memory // external memory
//Serial.println(String("CONFIG: delay:") + delaySamples); // if (Serial) { Serial.println(String("CONFIG: delay:") + delaySamples); }
ExtMemSlot *slot = m_memory->getSlot(); ExtMemSlot *slot = m_memory->getSlot();
m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES; m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES;
if (!slot->isEnabled()) { if (!slot->isEnabled()) {
@ -222,16 +239,16 @@ void AudioEffectAnalogDelay::delayFractionMax(float delayFraction)
{ {
size_t delaySamples = static_cast<size_t>(static_cast<float>(m_memory->getMaxDelaySamples()) * delayFraction); size_t delaySamples = static_cast<size_t>(static_cast<float>(m_memory->getMaxDelaySamples()) * delayFraction);
if (!m_memory) { Serial.println("delay(): m_memory is not valid"); } if (!m_memory) { if (Serial) Serial.println("delay(): m_memory is not valid"); }
if (!m_externalMemory) { if (!m_externalMemory) {
// internal memory // internal memory
m_maxDelaySamples = m_memory->getMaxDelaySamples(); m_maxDelaySamples = m_memory->getMaxDelaySamples();
//QueuePosition queuePosition = calcQueuePosition(delaySamples); //QueuePosition queuePosition = calcQueuePosition(delaySamples);
//Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); // if (Serial) { Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); }
} else { } else {
// external memory // external memory
//Serial.println(String("CONFIG: delay:") + delaySamples); // if (Serial) { Serial.println(String("CONFIG: delay:") + delaySamples); }
ExtMemSlot *slot = m_memory->getSlot(); ExtMemSlot *slot = m_memory->getSlot();
m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES; m_maxDelaySamples = (slot->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES;
if (!slot->isEnabled()) { if (!slot->isEnabled()) {
@ -284,23 +301,23 @@ void AudioEffectAnalogDelay::processMidi(int channel, int control, int value)
if (m_externalMemory) { m_maxDelaySamples = (m_memory->getSlot()->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES; } if (m_externalMemory) { m_maxDelaySamples = (m_memory->getSlot()->size() / sizeof(int16_t))-AUDIO_BLOCK_SAMPLES; }
size_t delayVal = (size_t)(val * (float)(m_maxDelaySamples)); size_t delayVal = (size_t)(val * (float)(m_maxDelaySamples));
delay(delayVal); delay(delayVal);
Serial.println(String("AudioEffectAnalogDelay::delay (ms): ") + calcAudioTimeMs(delayVal) if (Serial) { Serial.println(String("AudioEffectAnalogDelay::delay (ms): ") + calcAudioTimeMs(delayVal)
+ String(" (samples): ") + delayVal + String(" out of ") + m_maxDelaySamples); + String(" (samples): ") + delayVal + String(" out of ") + m_maxDelaySamples); }
return; return;
} }
if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) && if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) &&
(m_midiConfig[BYPASS][MIDI_CONTROL] == control)) { (m_midiConfig[BYPASS][MIDI_CONTROL] == control)) {
// Bypass // Bypass
if (value >= 65) { bypass(false); Serial.println(String("AudioEffectAnalogDelay::not bypassed -> ON") + value); } if (value >= 65) { bypass(false); if (Serial) Serial.println(String("AudioEffectAnalogDelay::not bypassed -> ON") + value); }
else { bypass(true); Serial.println(String("AudioEffectAnalogDelay::bypassed -> OFF") + value); } else { bypass(true); if (Serial) Serial.println(String("AudioEffectAnalogDelay::bypassed -> OFF") + value); }
return; return;
} }
if ((m_midiConfig[FEEDBACK][MIDI_CHANNEL] == channel) && if ((m_midiConfig[FEEDBACK][MIDI_CHANNEL] == channel) &&
(m_midiConfig[FEEDBACK][MIDI_CONTROL] == control)) { (m_midiConfig[FEEDBACK][MIDI_CONTROL] == control)) {
// Feedback // Feedback
Serial.println(String("AudioEffectAnalogDelay::feedback: ") + 100*val + String("%")); if (Serial) { Serial.println(String("AudioEffectAnalogDelay::feedback: ") + 100*val + String("%")); }
feedback(val); feedback(val);
return; return;
} }
@ -308,7 +325,7 @@ void AudioEffectAnalogDelay::processMidi(int channel, int control, int value)
if ((m_midiConfig[MIX][MIDI_CHANNEL] == channel) && if ((m_midiConfig[MIX][MIDI_CHANNEL] == channel) &&
(m_midiConfig[MIX][MIDI_CONTROL] == control)) { (m_midiConfig[MIX][MIDI_CONTROL] == control)) {
// Mix // Mix
Serial.println(String("AudioEffectAnalogDelay::mix: Dry: ") + 100*(1-val) + String("% Wet: ") + 100*val ); if (Serial) { Serial.println(String("AudioEffectAnalogDelay::mix: Dry: ") + 100*(1-val) + String("% Wet: ") + 100*val ); }
mix(val); mix(val);
return; return;
} }
@ -316,7 +333,7 @@ void AudioEffectAnalogDelay::processMidi(int channel, int control, int value)
if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) && if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) &&
(m_midiConfig[VOLUME][MIDI_CONTROL] == control)) { (m_midiConfig[VOLUME][MIDI_CONTROL] == control)) {
// Volume // Volume
Serial.println(String("AudioEffectAnalogDelay::volume: ") + 100*val + String("%")); if (Serial) { Serial.println(String("AudioEffectAnalogDelay::volume: ") + 100*val + String("%")); }
volume(val); volume(val);
return; return;
} }

@ -67,7 +67,7 @@ void BAAudioEffectDelayExternal::delay(uint8_t channel, float milliseconds) {
unsigned mask = m_activeMask; unsigned mask = m_activeMask;
if (m_activeMask == 0) m_startUsingSPI(m_spiChannel); if (m_activeMask == 0) m_startUsingSPI(m_spiChannel);
m_activeMask = mask | (1<<channel); m_activeMask = mask | (1<<channel);
Serial.print("DelayLengthInt: "); Serial.println(m_requestedDelayLength); if (Serial) { Serial.print("DelayLengthInt: "); Serial.println(m_requestedDelayLength); }
} }
void BAAudioEffectDelayExternal::disable(uint8_t channel) { void BAAudioEffectDelayExternal::disable(uint8_t channel) {

@ -3,7 +3,20 @@
* *
* Created on: March 7, 2020 * Created on: March 7, 2020
* Author: slascos * Author: slascos
*/ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <arm_math.h> #include <arm_math.h>
#include "BALibrary.h" #include "BALibrary.h"
#include "AudioEffectRmsMeasure.h" #include "AudioEffectRmsMeasure.h"
@ -64,8 +77,7 @@ void AudioEffectRmsMeasure::update(void)
for (int i=0; i<AUDIO_BLOCK_SAMPLES; i++) { for (int i=0; i<AUDIO_BLOCK_SAMPLES; i++) {
dotProduct += ((int64_t)inputAudioBlock->data[i] * (int64_t)inputAudioBlock->data[i]); dotProduct += ((int64_t)inputAudioBlock->data[i] * (int64_t)inputAudioBlock->data[i]);
if (dotProduct < 0) { if (dotProduct < 0) {
Serial.println("DOT ERROR!"); if (Serial) { Serial.println("DOT ERROR!"); Serial.println(inputAudioBlock->data[i], HEX); }
Serial.println(inputAudioBlock->data[i], HEX);
} }
} }
m_sum += (int64_t)(dotProduct); m_sum += (int64_t)(dotProduct);
@ -80,11 +92,13 @@ void AudioEffectRmsMeasure::update(void)
// dbfs = 20*log10(abs(rmsFigure)/32768.0f); // dbfs = 20*log10(abs(rmsFigure)/32768.0f);
m_dbfs = 20.0f * log10(m_rms/32768.0f); m_dbfs = 20.0f * log10(m_rms/32768.0f);
Serial.print("Accumulator: "); Serial.println((int)(m_sum >> 32), HEX); if (Serial) {
Serial.print("RAW RMS: "); Serial.println(m_rms); Serial.print("Accumulator: "); Serial.println((int)(m_sum >> 32), HEX);
Serial.print("RAW RMS: "); Serial.println(m_rms);
Serial.print("AudioEffectRmsMeasure: the RMS figure is "); Serial.print(m_dbfs); Serial.print("AudioEffectRmsMeasure: the RMS figure is "); Serial.print(m_dbfs);
Serial.print(" dBFS over "); Serial.print(m_accumulatorCount); Serial.println(" audio blocks"); Serial.print(" dBFS over "); Serial.print(m_accumulatorCount); Serial.println(" audio blocks");
}
m_sum = 0; m_sum = 0;
m_accumulatorCount = 0; m_accumulatorCount = 0;

@ -3,7 +3,20 @@
* *
* Created on: Apr 14, 2018 * Created on: Apr 14, 2018
* Author: blackaddr * Author: blackaddr
*/ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AudioEffectSOS.h" #include "AudioEffectSOS.h"
#include "LibBasicFunctions.h" #include "LibBasicFunctions.h"
@ -63,7 +76,7 @@ void AudioEffectSOS::enable(void)
// Because we hold the previous output buffer for an update cycle, the maximum delay is actually // 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. // 1 audio block mess then the max delay returnable from the memory.
m_maxDelaySamples = m_memory->getMaxDelaySamples() - AUDIO_BLOCK_SAMPLES; m_maxDelaySamples = m_memory->getMaxDelaySamples() - AUDIO_BLOCK_SAMPLES;
Serial.println(String("SOS Enabled with delay length ") + m_maxDelaySamples + String(" samples")); if (Serial) { Serial.println(String("SOS Enabled with delay length ") + m_maxDelaySamples + String(" samples")); }
} }
m_delaySamples = m_maxDelaySamples; m_delaySamples = m_maxDelaySamples;
m_inputGateAuto.setupParameter(GATE_OPEN_STAGE, 0.0f, 1.0f, 1000.0f, ParameterAutomation<float>::Function::EXPONENTIAL); m_inputGateAuto.setupParameter(GATE_OPEN_STAGE, 0.0f, 1.0f, 1000.0f, ParameterAutomation<float>::Function::EXPONENTIAL);
@ -126,8 +139,8 @@ void AudioEffectSOS::update(void)
// get the data. If using external memory with DMA, this won't be filled until // get the data. If using external memory with DMA, this won't be filled until
// later. // later.
m_memory->getSamples(blockToOutput, m_delaySamples); m_memory->getSamples(blockToOutput, m_delaySamples);
//Serial.println(String("Delay samples:") + m_delaySamples); // if (Serial) { Serial.println(String("Delay samples:") + m_delaySamples); }
//Serial.println(String("Use dma: ") + m_memory->getSlot()->isUseDma()); // if (Serial) { Serial.println(String("Use dma: ") + m_memory->getSlot()->isUseDma()); }
// If using DMA, we need something else to do while that read executes, so // If using DMA, we need something else to do while that read executes, so
// move on to input preprocessing // move on to input preprocessing
@ -157,7 +170,7 @@ void AudioEffectSOS::update(void)
m_previousBlock = blockToOutput; m_previousBlock = blockToOutput;
if (m_blockToRelease == m_previousBlock) { if (m_blockToRelease == m_previousBlock) {
Serial.println("ERROR: POINTER COLLISION"); if (Serial) { Serial.println("ERROR: POINTER COLLISION"); }
} }
if (m_blockToRelease) { release(m_blockToRelease); } if (m_blockToRelease) { release(m_blockToRelease); }
@ -190,7 +203,7 @@ void AudioEffectSOS::processMidi(int channel, int control, int value)
(m_midiConfig[GATE_OPEN_TIME][MIDI_CONTROL] == control)) { (m_midiConfig[GATE_OPEN_TIME][MIDI_CONTROL] == control)) {
// Gate Open Time // Gate Open Time
gateOpenTime(val * MAX_GATE_OPEN_TIME_MS); gateOpenTime(val * MAX_GATE_OPEN_TIME_MS);
Serial.println(String("AudioEffectSOS::gate open time (ms): ") + m_openTimeMs); if (Serial) { Serial.println(String("AudioEffectSOS::gate open time (ms): ") + m_openTimeMs); }
return; return;
} }
@ -198,14 +211,14 @@ void AudioEffectSOS::processMidi(int channel, int control, int value)
(m_midiConfig[GATE_CLOSE_TIME][MIDI_CONTROL] == control)) { (m_midiConfig[GATE_CLOSE_TIME][MIDI_CONTROL] == control)) {
// Gate Close Time // Gate Close Time
gateCloseTime(val * MAX_GATE_CLOSE_TIME_MS); gateCloseTime(val * MAX_GATE_CLOSE_TIME_MS);
Serial.println(String("AudioEffectSOS::gate close time (ms): ") + m_closeTimeMs); if (Serial) { Serial.println(String("AudioEffectSOS::gate close time (ms): ") + m_closeTimeMs); }
return; return;
} }
if ((m_midiConfig[FEEDBACK][MIDI_CHANNEL] == channel) && if ((m_midiConfig[FEEDBACK][MIDI_CHANNEL] == channel) &&
(m_midiConfig[FEEDBACK][MIDI_CONTROL] == control)) { (m_midiConfig[FEEDBACK][MIDI_CONTROL] == control)) {
// Feedback // Feedback
Serial.println(String("AudioEffectSOS::feedback: ") + 100*val + String("%")); if (Serial) { Serial.println(String("AudioEffectSOS::feedback: ") + 100*val + String("%")); }
feedback(val); feedback(val);
return; return;
} }
@ -213,7 +226,7 @@ void AudioEffectSOS::processMidi(int channel, int control, int value)
if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) && if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) &&
(m_midiConfig[VOLUME][MIDI_CONTROL] == control)) { (m_midiConfig[VOLUME][MIDI_CONTROL] == control)) {
// Volume // Volume
Serial.println(String("AudioEffectSOS::volume: ") + 100*val + String("%")); if (Serial) { Serial.println(String("AudioEffectSOS::volume: ") + 100*val + String("%")); }
volume(val); volume(val);
return; return;
} }
@ -221,15 +234,15 @@ void AudioEffectSOS::processMidi(int channel, int control, int value)
if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) && if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) &&
(m_midiConfig[BYPASS][MIDI_CONTROL] == control)) { (m_midiConfig[BYPASS][MIDI_CONTROL] == control)) {
// Bypass // Bypass
if (value >= 65) { bypass(false); Serial.println(String("AudioEffectSOS::not bypassed -> ON") + value); } if (value >= 65) { bypass(false); if (Serial) Serial.println(String("AudioEffectSOS::not bypassed -> ON") + value); }
else { bypass(true); Serial.println(String("AudioEffectSOS::bypassed -> OFF") + value); } else { bypass(true); if (Serial) Serial.println(String("AudioEffectSOS::bypassed -> OFF") + value); }
return; return;
} }
if ((m_midiConfig[GATE_TRIGGER][MIDI_CHANNEL] == channel) && if ((m_midiConfig[GATE_TRIGGER][MIDI_CHANNEL] == channel) &&
(m_midiConfig[GATE_TRIGGER][MIDI_CONTROL] == control)) { (m_midiConfig[GATE_TRIGGER][MIDI_CONTROL] == control)) {
// The gate is triggered by any value // The gate is triggered by any value
Serial.println(String("AudioEffectSOS::Gate Triggered!")); if (Serial) { Serial.println(String("AudioEffectSOS::Gate Triggered!")); }
m_inputGateAuto.trigger(); m_inputGateAuto.trigger();
return; return;
} }
@ -237,7 +250,7 @@ void AudioEffectSOS::processMidi(int channel, int control, int value)
if ((m_midiConfig[CLEAR_FEEDBACK_TRIGGER][MIDI_CHANNEL] == channel) && if ((m_midiConfig[CLEAR_FEEDBACK_TRIGGER][MIDI_CHANNEL] == channel) &&
(m_midiConfig[CLEAR_FEEDBACK_TRIGGER][MIDI_CONTROL] == control)) { (m_midiConfig[CLEAR_FEEDBACK_TRIGGER][MIDI_CONTROL] == control)) {
// The gate is triggered by any value // The gate is triggered by any value
Serial.println(String("AudioEffectSOS::Clear feedback Triggered!")); if (Serial) { Serial.println(String("AudioEffectSOS::Clear feedback Triggered!")); }
m_clearFeedbackAuto.trigger(); m_clearFeedbackAuto.trigger();
return; return;
} }

@ -3,7 +3,21 @@
* *
* Created on: Jan 7, 2018 * Created on: Jan 7, 2018
* Author: slascos * Author: slascos
*/ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cmath> // std::roundf #include <cmath> // std::roundf
#include "AudioEffectTremolo.h" #include "AudioEffectTremolo.h"
@ -62,16 +76,6 @@ void AudioEffectTremolo::update(void)
float sample = std::roundf(mod[i] * (float)inputAudioBlock->data[i]); float sample = std::roundf(mod[i] * (float)inputAudioBlock->data[i]);
inputAudioBlock->data[i] = (int16_t)sample; inputAudioBlock->data[i] = (int16_t)sample;
} }
//Serial.println(String("mod: ") + mod[0]);
//float mod = (m_osc.getNext()+1.0f)/2.0f; // value between -1.0 and +1.0f
//float modVolume = (1.0f - m_depth) + mod*m_depth; // value between 0 to depth
//float finalVolume = m_volume * modVolume;
// Set the output volume
//gainAdjust(inputAudioBlock, inputAudioBlock, finalVolume, 1);
transmit(inputAudioBlock); transmit(inputAudioBlock);
release(inputAudioBlock); release(inputAudioBlock);
@ -97,8 +101,8 @@ void AudioEffectTremolo::processMidi(int channel, int control, int value)
if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) && if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) &&
(m_midiConfig[BYPASS][MIDI_CONTROL] == control)) { (m_midiConfig[BYPASS][MIDI_CONTROL] == control)) {
// Bypass // Bypass
if (value >= 65) { bypass(false); Serial.println(String("AudioEffectTremolo::not bypassed -> ON") + value); } if (value >= 65) { bypass(false); if (Serial) Serial.println(String("AudioEffectTremolo::not bypassed -> ON") + value); }
else { bypass(true); Serial.println(String("AudioEffectTremolo::bypassed -> OFF") + value); } else { bypass(true); if (Serial) Serial.println(String("AudioEffectTremolo::bypassed -> OFF") + value); }
return; return;
} }
@ -106,7 +110,7 @@ void AudioEffectTremolo::processMidi(int channel, int control, int value)
(m_midiConfig[RATE][MIDI_CONTROL] == control)) { (m_midiConfig[RATE][MIDI_CONTROL] == control)) {
// Rate // Rate
rate(val); rate(val);
Serial.println(String("AudioEffectTremolo::rate: ") + m_rate); if (Serial) { Serial.println(String("AudioEffectTremolo::rate: ") + m_rate); }
return; return;
} }
@ -114,7 +118,7 @@ void AudioEffectTremolo::processMidi(int channel, int control, int value)
(m_midiConfig[DEPTH][MIDI_CONTROL] == control)) { (m_midiConfig[DEPTH][MIDI_CONTROL] == control)) {
// Depth // Depth
depth(val); depth(val);
Serial.println(String("AudioEffectTremolo::depth: ") + m_depth); if (Serial) { Serial.println(String("AudioEffectTremolo::depth: ") + m_depth); }
return; return;
} }
@ -133,14 +137,14 @@ void AudioEffectTremolo::processMidi(int channel, int control, int value)
m_waveform = Waveform::RANDOM; m_waveform = Waveform::RANDOM;
} }
Serial.println(String("AudioEffectTremolo::waveform: ") + static_cast<unsigned>(m_waveform)); if (Serial) { Serial.println(String("AudioEffectTremolo::waveform: ") + static_cast<unsigned>(m_waveform)); }
return; return;
} }
if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) && if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) &&
(m_midiConfig[VOLUME][MIDI_CONTROL] == control)) { (m_midiConfig[VOLUME][MIDI_CONTROL] == control)) {
// Volume // Volume
Serial.println(String("AudioEffectTremolo::volume: ") + 100*val + String("%")); if (Serial) { Serial.println(String("AudioEffectTremolo::volume: ") + 100*val + String("%")); }
volume(val); volume(val);
return; return;
} }

@ -136,7 +136,7 @@ BAAudioControlWM8731::~BAAudioControlWM8731()
// Powerdown and disable the codec // Powerdown and disable the codec
void BAAudioControlWM8731::disable(void) void BAAudioControlWM8731::disable(void)
{ {
//Serial.println("Disabling codec"); // if (Serial) { Serial.println("Disabling codec"); }
if (m_wireStarted == false) { if (m_wireStarted == false) {
Wire.begin(); Wire.begin();
m_wireStarted = true; m_wireStarted = true;
@ -161,7 +161,7 @@ void BAAudioControlWM8731::enable(void)
disable(); // disable first in case it was already powered up disable(); // disable first in case it was already powered up
//Serial.println("Enabling codec"); // if (Serial) { Serial.println("Enabling codec"); }
if (m_wireStarted == false) { if (m_wireStarted == false) {
Wire.begin(); Wire.begin();
m_wireStarted = true; m_wireStarted = true;
@ -398,10 +398,9 @@ bool BAAudioControlWM8731::write(unsigned int reg, unsigned int val)
Wire.write(val & 0xFF); Wire.write(val & 0xFF);
byte error = Wire.endTransmission(); byte error = Wire.endTransmission();
if (error) { if (error) {
Serial.println(String("Wire::Error: ") + error + String(" retrying...")); if (Serial) { Serial.println(String("Wire::Error: ") + error + String(" retrying...")); }
} else { } else {
done = true; done = true;
//Serial.println("Wire::SUCCESS!");
} }
} }
@ -427,7 +426,7 @@ void BAAudioControlWM8731master::enable(void)
disable(); // disable first in case it was already powered up disable(); // disable first in case it was already powered up
//Serial.println("Enabling codec"); // if (Serial) { Serial.println("Enabling codec"); }
if (m_wireStarted == false) { if (m_wireStarted == false) {
Wire.begin(); Wire.begin();
m_wireStarted = true; m_wireStarted = true;

@ -22,11 +22,11 @@
// These calls must be define in order to get vector to work on arduino // These calls must be define in order to get vector to work on arduino
namespace std { namespace std {
void __throw_bad_alloc() { void __throw_bad_alloc() {
Serial.println("Unable to allocate memory"); if (Serial) { Serial.println("Unable to allocate memory"); }
abort(); abort();
} }
void __throw_length_error( char const*e ) { void __throw_length_error( char const*e ) {
Serial.print("Length Error :"); Serial.println(e); if (Serial) { Serial.print("Length Error :"); Serial.println(e); }
abort(); abort();
} }
} }
@ -56,6 +56,8 @@ unsigned BAPhysicalControls::addRotary(uint8_t pin1, uint8_t pin2, bool swapDire
return m_encoders.size()-1; return m_encoders.size()-1;
} }
unsigned BAPhysicalControls::getNumRotary() { return m_encoders.size(); }
unsigned BAPhysicalControls::addSwitch(uint8_t pin, unsigned long intervalMilliseconds) { unsigned BAPhysicalControls::addSwitch(uint8_t pin, unsigned long intervalMilliseconds) {
m_switches.emplace_back(); m_switches.emplace_back();
m_switches.back().attach(pin); m_switches.back().attach(pin);
@ -64,6 +66,8 @@ unsigned BAPhysicalControls::addSwitch(uint8_t pin, unsigned long intervalMillis
return m_switches.size()-1; return m_switches.size()-1;
} }
unsigned BAPhysicalControls::getNumSwitches() { return m_switches.size(); }
unsigned BAPhysicalControls::addPot(uint8_t pin, unsigned minCalibration, unsigned maxCalibration) { unsigned BAPhysicalControls::addPot(uint8_t pin, unsigned minCalibration, unsigned maxCalibration) {
m_pots.emplace_back(pin, minCalibration, maxCalibration); m_pots.emplace_back(pin, minCalibration, maxCalibration);
pinMode(pin, INPUT); pinMode(pin, INPUT);
@ -76,12 +80,16 @@ unsigned BAPhysicalControls::addPot(uint8_t pin, unsigned minCalibration, unsign
return m_pots.size()-1; return m_pots.size()-1;
} }
unsigned BAPhysicalControls::getNumPots() { return m_pots.size(); }
unsigned BAPhysicalControls::addOutput(uint8_t pin) { unsigned BAPhysicalControls::addOutput(uint8_t pin) {
m_outputs.emplace_back(pin); m_outputs.emplace_back(pin);
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
return m_outputs.size()-1; return m_outputs.size()-1;
} }
unsigned BAPhysicalControls::getNumOutputs() { return m_outputs.size(); }
void BAPhysicalControls::setOutput(unsigned handle, int val) { void BAPhysicalControls::setOutput(unsigned handle, int val) {
if (handle >= m_outputs.size()) { return; } if (handle >= m_outputs.size()) { return; }
m_outputs[handle].set(val); m_outputs[handle].set(val);
@ -329,6 +337,8 @@ void Potentiometer::setChangeThreshold(float changeThreshold)
Potentiometer::Calib Potentiometer::calibrate(uint8_t pin) { Potentiometer::Calib Potentiometer::calibrate(uint8_t pin) {
Calib calib; Calib calib;
if (!Serial) { return calib; } // this function REQUIRES Serial port connection
// Flush the serial port input buffer // Flush the serial port input buffer
while (Serial.available() > 0) {} while (Serial.available() > 0) {}

@ -24,20 +24,6 @@
namespace BALibrary { namespace BALibrary {
//// 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 // SPI Constants
constexpr int SPI_WRITE_MODE_REG = 0x1; constexpr int SPI_WRITE_MODE_REG = 0x1;
constexpr int SPI_WRITE_CMD = 0x2; constexpr int SPI_WRITE_CMD = 0x2;
@ -82,7 +68,7 @@ void BASpiMemory::begin()
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY; m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
break; break;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) #if defined(ARDUINO_TEENSY_MICROMOD) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
case SpiDeviceId::SPI_DEVICE1 : case SpiDeviceId::SPI_DEVICE1 :
m_csPin = SPI1_CS_PIN; m_csPin = SPI1_CS_PIN;
m_spi = &SPI1; m_spi = &SPI1;
@ -401,7 +387,7 @@ void BASpiMemoryDMA::begin(void)
cs = SPI0_CS_PIN; cs = SPI0_CS_PIN;
m_cs = new ActiveLowChipSelect(cs, m_settings); m_cs = new ActiveLowChipSelect(cs, m_settings);
break; break;
#if defined(__MK66FX1M0__) #if defined(ARDUINO_TEENSY_MICROMOD) || defined(__MK66FX1M0__)
case SpiDeviceId::SPI_DEVICE1 : case SpiDeviceId::SPI_DEVICE1 :
cs = SPI1_CS_PIN; cs = SPI1_CS_PIN;
m_cs = new ActiveLowChipSelect1(cs, m_settings); m_cs = new ActiveLowChipSelect1(cs, m_settings);
@ -430,7 +416,7 @@ void BASpiMemoryDMA::begin(void)
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY; m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
break; break;
#if defined(__MK66FX1M0__) // DMA on SPI1 is only supported on T3.6 #if defined(ARDUINO_TEENSY_MICROMOD) || defined(__MK66FX1M0__) // DMA on SPI1 is only supported on T3.6 or Micromod
case SpiDeviceId::SPI_DEVICE1 : case SpiDeviceId::SPI_DEVICE1 :
m_csPin = SPI1_CS_PIN; m_csPin = SPI1_CS_PIN;
m_spi = &SPI1; m_spi = &SPI1;

@ -1,15 +1,38 @@
/*
* DmaSpi.cpp
*
* Created on: Jan 7, 2018
* Author: slascos
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DmaSpi.h" #include "DmaSpi.h"
#if defined(__IMXRT1062__) // T4.0 #if defined(__IMXRT1062__) // T4.X
DmaSpi0 DMASPI0; DmaSpi0 DMASPI0;
#if defined(ARDUINO_TEENSY_MICROMOD) || defined (ARDUINO_TEENSY41)
DmaSpi1 DMASPI1;
#endif
#elif defined(KINETISK) #elif defined(KINETISK)
DmaSpi0 DMASPI0; DmaSpi0 DMASPI0;
#if defined(__MK66FX1M0__) #if defined(__MK66FX1M0__)
DmaSpi1 DMASPI1; DmaSpi1 DMASPI1;
//DmaSpi2 DMASPI2; //DmaSpi2 DMASPI2;
#endif #endif
#elif defined (KINETISL) #elif defined (KINETISL)
DmaSpi0 DMASPI0; DmaSpi0 DMASPI0;
DmaSpi1 DMASPI1; DmaSpi1 DMASPI1;
#else #else
#endif // defined #endif // defined

Loading…
Cancel
Save