Skip to content

Commit

Permalink
Merge pull request #8 from tysonlt/stateless
Browse files Browse the repository at this point in the history
Merging
  • Loading branch information
tysonlt authored Feb 23, 2019
2 parents c1fede7 + 26d21ee commit 7aaabe2
Show file tree
Hide file tree
Showing 14 changed files with 103 additions and 58 deletions.
1 change: 0 additions & 1 deletion examples/EffectList/EffectList.ino
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ bool presetRequested = false;

void setup() {

//note that this won't work on a Nano, it uses Serial for MIDI
Serial.begin(9600);
while (!Serial);

Expand Down
2 changes: 1 addition & 1 deletion examples/FineGrainedCallbacks/FineGrainedCallbacks.ino
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ void onSceneName(SceneNumber number, const char *name, const byte length) {
Serial.println(name);
}

//NOTE: only rely on the effects, the reset of the preset is not guaranteed to be complete.
//only rely on the effects, the reset of the preset is not guaranteed to be complete.
void onEffectsReceived(PresetNumber number, AxePreset preset) {

const size_t sz = 25;
Expand Down
1 change: 0 additions & 1 deletion examples/LooperStatus/LooperStatus.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ AxeSystem Axe;

void setup() {

//note that this won't work on a Nano, it uses Serial for MIDI
Serial.begin(9600);

Axe.begin(Serial1);
Expand Down
3 changes: 1 addition & 2 deletions examples/PresetDetails/PresetDetails.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ AxeSystem Axe;

void setup() {

//note that this won't work on a Nano, it uses Serial for MIDI
Serial.begin(9600);
while (!Serial);

Expand All @@ -28,7 +27,7 @@ void onPresetChange(AxePreset preset) {
const size_t sz = 150;
char buf[sz];

//NOTE! Preset/scene names with % in them will not print to debug properly
//Preset/scene names with % in them will not print to debug properly

//AxeSystem has notified that all requested information has arrived!
Serial.println();
Expand Down
5 changes: 2 additions & 3 deletions examples/Refresh/Refresh.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ AxeSystem Axe;

void setup() {

//note that this won't work on a Nano, it uses Serial for MIDI
Serial.begin(9600);
// while (!Serial);

Expand All @@ -15,7 +14,7 @@ void setup() {
Axe.registerPresetChangeCallback(onPresetChange);

//ask for details to be refreshed every 3 seconds
Axe.enableRefresh(3000);
Axe.enableRefresh();

//request current preset
Axe.requestPresetDetails();
Expand All @@ -31,7 +30,7 @@ void onPresetChange(AxePreset preset) {
const size_t sz = 150;
char buf[sz];

//NOTE! Preset/scene names with % in them will not print to debug properly
//Preset/scene names with % in them will not print to debug properly

//AxeSystem has notified that all requested information has arrived!
Serial.print("Preset number: ");
Expand Down
24 changes: 18 additions & 6 deletions examples/SwitchPreset/SwitchPreset.ino
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

AxeSystem Axe;

unsigned long time;

void setup() {
Serial.begin(9600);
Axe.registerPresetChangingCallback(onPresetChanging);
Axe.registerPresetNameCallback(onPresetName);
Axe.begin(Serial1, 4);
time = millis();
//Go to Axe, Setup->MIDI/Remote->Midi Channel=4 to see channel filter in action
//Otherwise, just remove the channel param above and it will default to OMIN
}
Expand All @@ -16,14 +20,22 @@ void loop() {
if (preset >= AxeSystem::MAX_PRESETS) {
preset = 0;
}

Axe.sendPresetChange(preset);
delay(1000);

preset += 11;

if (millis() - time > 1000) {
Axe.sendPresetChange(preset);
preset += 11;
time = millis();
}

Axe.update();

}

void onPresetChanging(PresetNumber preset) {
Serial.println(preset);
Serial.print(preset);
Serial.print(": ");
}

void onPresetName(PresetNumber number, const char *name, const byte length) {
Serial.println(name);
}
7 changes: 7 additions & 0 deletions src/interface/AxePreset.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ class AxePreset {
unsigned getEffectCount() { return _effectCount; }
AxeEffect getEffectAt(const EffectIndex index) { return _effects[index]; }

// Use to determine if the effect list has changed compared to
// another preset. Useful if deciding whether to reprint etc.
bool effectsChanged(AxePreset& preset);

// Determine whether these presets have the same data
bool equals(AxePreset& compare);

// Defaults to 50. If you are running short on ram, lower this to
// truncate the number of effects that will be read from the Axe.
// Don't increase it without changing MAX_EFFECTS as well.
Expand Down
25 changes: 7 additions & 18 deletions src/interface/AxeSystem.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <Arduino.h>
#include "AxeFxControl.h"
#include "private/AxeTypes.h"
#include "AxeLooper.h"
#include "AxeEffect.h"
Expand All @@ -21,12 +22,9 @@ class AxeSystem {

public:

// Declare an instance of this class above your setup() function.
// Optionally register a notification callback, optionally turn on auto-refresh,
// and then just call Axe.update() in the main loop and you are ready to roll.
AxeSystem() {
_looper.setAxeSystem(this);
}
AxeSystem() {
_looper.setAxeSystem(this);
}

// You must call begin with a hardware serial such as Serial1. Optionally set the
// MIDI channel, defaults to OMNI.
Expand All @@ -38,7 +36,7 @@ class AxeSystem {

// Update preset details every millis. Don't refresh if another preset request
// was received within throttle interval.
void enableRefresh(const millis_t millis = 3000, const millis_t throttle = 500);
void enableRefresh(const millis_t millis = 500, const millis_t throttle = 100);

// Remember to call this from loop(). Avoid using delay() anywhere in your code
// for best results.
Expand All @@ -58,9 +56,8 @@ class AxeSystem {
// To get the results back, you should register a callback.
// Call registerPresetChangeCallback() to be notified of preset changes.
//
// Alternatively, you can call getPreset() any time you want, but it will
// not reflect the next preset until isPresetReady() returns true. This
// is not the best way to go. You should register a callback instead.
// Alternatively, you can call getPreset() any time you want, but it is
// not guaranteed to be current. You should register a callback instead.
void requestPresetDetails() { requestPresetName(); }
void requestFirmwareVersion();
void requestTempo();
Expand Down Expand Up @@ -100,14 +97,6 @@ class AxeSystem {
void sendProgramChange(byte value, byte channel);
void sendSysEx(const byte *sysex, const byte length);

// These two methods tell you whether the preset is in the middle of
// changing. (They are just the inverse of each other.) During this time,
// sysex data is being read from the Axe, so the result will still reflect
// the old preset until isPresetReady() returns true, or isPresetChanging()
// returns false. You are better off registering a preset change callback!
bool isPresetReady() { return !_presetChanging; }
bool isPresetChanging() { return _presetChanging; }

// Well is it, or isn't it? As far as we know! This is pretty accurate
// even if you enable/disable the tuner from the front panel.
bool isTunerEngaged() { return _tunerEngaged; }
Expand Down
2 changes: 0 additions & 2 deletions src/interface/private/AxeEffect_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ const static char ASCII_ZERO = 0x30;
friend class AxePreset;
friend class AxeSystem;

AxeEffect() {}

void setAxeSystem(AxeSystem *axe) { _axe = axe; }
void setBypassed(bool bypassed) { _bypassed = bypassed; }
void setChannelCount(byte count) { _numChannels = count; }
Expand Down
28 changes: 28 additions & 0 deletions src/interface/private/AxePreset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@ void AxePreset::setEffects(const AxeEffect effects[], const unsigned count) {
}
}

bool AxePreset::equals(AxePreset& p) {
return
_preset == p._preset &&
_scene == p._scene &&
0 == strcmp(_presetName, p._presetName) &&
0 == strcmp(_sceneName, p._sceneName) &&
!effectsChanged(p);
}

bool AxePreset::effectsChanged(AxePreset& p) {

if (_preset != p._preset ||
_scene != p._scene ||
_effectCount != p._effectCount) {
return true;
}

for (byte i=0; i<_effectCount; i++) {
if (_effects[i]._effectId != p._effects[i]._effectId ||
_effects[i]._bypassed != p._effects[i]._bypassed) {
return true;
}
}

return false;

}

void AxePreset::copyPresetName(char *buffer, size_t max) {
snprintf(buffer, max, _presetName);
}
Expand Down
2 changes: 0 additions & 2 deletions src/interface/private/AxePreset_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

friend class AxeSystem;

AxePreset() {}

// These methods are used by AxeSystem to build the preset.
// You don't need to call them, and you can't.
void setPresetNumber(int number) { _preset = number; }
Expand Down
9 changes: 4 additions & 5 deletions src/interface/private/AxeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

void AxeSystem::update() {

if (!_presetChanging && _refreshRate > 0) {
unsigned long now = millis();
if (now - _lastRefresh > _refreshRate) {
if (_refreshRate > 0) {
if (millis() - _lastRefresh > _refreshRate) {
refresh();
}
}

}
readMidi();

}
Expand Down
51 changes: 35 additions & 16 deletions src/interface/private/AxeSystem_Handlers.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
#include "interface/AxeSystem.h"

void AxeSystem::onPresetChange(const PresetNumber number) {
_presetChanging = true;
_incomingPreset.reset();
_incomingPreset.setPresetNumber(number);
requestPresetName(number);
callPresetChangingCallback(number);
}

void AxeSystem::onSystemExclusive(const byte *sysex, const byte length) {

if (callSysexPluginCallback(sysex, length)) {
return;
}
Expand All @@ -32,6 +31,10 @@ void AxeSystem::onSystemExclusive(const byte *sysex, const byte length) {
}

case SYSEX_REQUEST_PRESET_INFO: {
#ifdef AXE_DEBUG
DEBUGGER.println("SYSEX_REQUEST_PRESET_INFO");
#endif

_lastRefresh = millis();
const byte max = AxePreset::MAX_PRESET_NAME + 1;
const PresetNumber number = midiBytesToInt(sysex[6], sysex[7]);
Expand All @@ -42,8 +45,7 @@ void AxeSystem::onSystemExclusive(const byte *sysex, const byte length) {
_incomingPreset.setPresetName(buffer);
_incomingPreset.copyPresetName(buffer, max); //copy back out in case preset changed it
callPresetNameCallback(number, (const char*) buffer, max);
requestSceneName();
requestEffectDetails();
requestSceneName(); //next item in chain
checkIncomingPreset();
} else {
#ifdef AXE_DEBUG
Expand All @@ -57,15 +59,19 @@ void AxeSystem::onSystemExclusive(const byte *sysex, const byte length) {
}

case SYSEX_REQUEST_SCENE_INFO: {
//TODO during fast changes, can we guarantee this is for current preset?
if (!_incomingPreset.isComplete()) { //TODO is this necessary given guard in preset name case?
#ifdef AXE_DEBUG
DEBUGGER.println("SYSEX_REQUEST_SCENE_INFO");
#endif

if (!_incomingPreset.isComplete()) {
const SceneNumber number = sysex[6] + 1;
const byte max = AxePreset::MAX_SCENE_NAME + 1;
parseName(sysex, length, 7, buffer, max);
_incomingPreset.setSceneNumber(number);
_incomingPreset.setSceneName(buffer);
_incomingPreset.copySceneName(buffer, max); //copy back out in case preset changed it
callSceneNameCallback(number, (const char*) buffer, max);
requestEffectDetails(); //ask here instead of in preset name to avoid filling rx buffer
checkIncomingPreset();
} else {
#ifdef AXE_DEBUG
Expand All @@ -76,8 +82,11 @@ void AxeSystem::onSystemExclusive(const byte *sysex, const byte length) {
}

case SYSEX_REQUEST_SCENE_NUMBER: {
//TODO during fast changes, can we guarantee this is for current preset?
if (!_incomingPreset.isComplete()) { //TODO is this necessary given guard in preset name case?
#ifdef AXE_DEBUG
DEBUGGER.println("SYSEX_REQUEST_SCENE_NUMBER");
#endif

if (!_incomingPreset.isComplete()) {
_incomingPreset.setSceneNumber(sysex[6] + 1);
checkIncomingPreset();
} else {
Expand All @@ -89,8 +98,11 @@ void AxeSystem::onSystemExclusive(const byte *sysex, const byte length) {
}

case SYSEX_EFFECT_DUMP: {
//TODO during fast changes, can we guarantee this is for current preset?
if (!_incomingPreset.isComplete()) { //TODO is this necessary given guard in preset name case?
#ifdef AXE_DEBUG
DEBUGGER.println("SYSEX_EFFECT_DUMP");
#endif

if (!_incomingPreset.isComplete()) {
processEffectDump(sysex, length);
callEffectsReceivedCallback(&_incomingPreset);
checkIncomingPreset();
Expand All @@ -103,6 +115,10 @@ void AxeSystem::onSystemExclusive(const byte *sysex, const byte length) {
}

case SYSEX_REQUEST_FIRMWARE: {
#ifdef AXE_DEBUG
DEBUGGER.println("SYSEX_REQUEST_FIRMWARE");
#endif

_firmwareVersion.major = sysex[6];
_firmwareVersion.minor = sysex[7];
_usbVersion.major = sysex[9];
Expand All @@ -112,6 +128,10 @@ void AxeSystem::onSystemExclusive(const byte *sysex, const byte length) {
}

case SYSEX_REQUEST_TEMPO: {
#ifdef AXE_DEBUG
DEBUGGER.println("SYSEX_REQUEST_TEMPO");
#endif

byte newTempo = (byte) midiBytesToInt(sysex[6], sysex[7]);
if (newTempo != _tempo) {
_tempo = newTempo;
Expand Down Expand Up @@ -175,11 +195,10 @@ bool AxeSystem::isRequestedPreset(const PresetNumber number) {
}

void AxeSystem::checkIncomingPreset() {
if (_incomingPreset.isComplete()) {
_presetChanging = false;
_preset = _incomingPreset;
callPresetChangeCallback(&_preset);
}
if (_incomingPreset.isComplete() && !_preset.equals(_incomingPreset)) {
_preset = _incomingPreset;
callPresetChangeCallback(&_preset);
}
}

// TODO: need to prioritise which effects are shown in order
Expand All @@ -206,7 +225,7 @@ void AxeSystem::processEffectDump(const byte *sysex, const byte length) {
effect.setChannel(channel);
effect.setChannelCount(numChannels);

//NOTE assumes preset number has already been received
//assumes preset number has already been received
if (callEffectFilterCallback(_incomingPreset.getPresetNumber(), effect)) {
effects[count++] = effect;
}
Expand Down
Loading

0 comments on commit 7aaabe2

Please sign in to comment.