695 lines
14 KiB
C++
695 lines
14 KiB
C++
#include <Arduino.h>
|
|
|
|
#include "editor-modes.h"
|
|
#include "editor.h"
|
|
#include "panel-scanner.h"
|
|
#include "player.h"
|
|
#include "pattern.h"
|
|
|
|
extern PanelScanner theScanner;
|
|
extern Player thePlayer;
|
|
extern Pattern thePattern;
|
|
extern Editor theEditor;
|
|
|
|
// Local definitions
|
|
|
|
|
|
static const int32_t PATTERN_SEL_INDICATOR = 0x10;
|
|
static const int32_t PATTERN_CHAIN_INDICATOR = 0x11;
|
|
static const int32_t STEP_EDIT_INDICATOR = 0x12;
|
|
static const int32_t STEP_ACCENT_INDICATOR = 0x13;
|
|
static const int32_t VOICE_SEL_INDICATOR = 0x14;
|
|
static const int32_t MUTE_SEL_INDICATOR = 0x15;
|
|
static const int32_t UTILITY_SEL_INDICATOR = 0x16;
|
|
static const int32_t PLAY_INDICATOR = 0x17;
|
|
/*
|
|
static const int32_t PATTERN_SEL_INDICATOR = 0x17;
|
|
static const int32_t PATTERN_CHAIN_INDICATOR = 0x16;
|
|
static const int32_t STEP_EDIT_INDICATOR = 0x15;
|
|
static const int32_t STEP_ACCENT_INDICATOR = 0x14;
|
|
static const int32_t VOICE_SEL_INDICATOR = 0x13;
|
|
static const int32_t MUTE_SEL_INDICATOR = 0x12;
|
|
static const int32_t UTILITY_SEL_INDICATOR = 0x11;
|
|
static const int32_t PLAY_INDICATOR = 0x10;
|
|
*/
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// common implementation because chain display
|
|
// is used by chain and patt sel modes.
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void doChainLeds()
|
|
{
|
|
if(thePlayer.chainIsActive())
|
|
{
|
|
theScanner.clearAllBlinkingLEDs();
|
|
|
|
for(uint32_t i = 0; i < Pattern::NUM_PATTERNS; i++)
|
|
{
|
|
theScanner.setBlinkingLED(i, thePlayer.checkChainMembership(i));
|
|
}
|
|
// blinking overrides background, so
|
|
// to mark current pattern, unset blinking,
|
|
// set background
|
|
theScanner.clearBlinkingLED(thePattern.getCurrentPattern());
|
|
theScanner.setBackgroundLED(thePattern.getCurrentPattern());
|
|
}
|
|
}
|
|
|
|
static void doPlayingLed()
|
|
{
|
|
theScanner.clearAllOverlayLEDs();
|
|
|
|
if(thePlayer.isPlaying())
|
|
{
|
|
theScanner.setOverlayLED(thePlayer.getCurrentStep());
|
|
theScanner.setBackgroundLED(PLAY_INDICATOR);
|
|
}
|
|
else
|
|
{
|
|
theScanner.clearBackgroundLED(PLAY_INDICATOR);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//////// Base Class
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// constructor...
|
|
pvEditorMode::pvEditorMode()
|
|
{
|
|
}
|
|
|
|
// Common handling for the start/stop key
|
|
void pvEditorMode::HandlePlayButton(bool pressed)
|
|
{
|
|
Serial.write("Play/Pause");
|
|
if(pressed )
|
|
{
|
|
if(thePlayer.isPlaying())
|
|
{
|
|
thePlayer.stop();
|
|
}
|
|
else
|
|
{
|
|
thePlayer.start();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//////// Step Editor
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
StepEdit::StepEdit(): pvEditorMode()
|
|
{
|
|
//current_voice = 0;
|
|
|
|
}
|
|
|
|
void StepEdit::HandleKey(uint32_t keynum, bool pressed)
|
|
{
|
|
bool setting;
|
|
|
|
if (keynum == PLAY_INDICATOR) //start/stop key
|
|
{
|
|
HandlePlayButton(pressed);
|
|
}
|
|
else if((keynum >= 0) && (keynum <= 15))
|
|
{
|
|
if(pressed)
|
|
{
|
|
setting = thePattern.toggleBit(keynum);
|
|
|
|
// If we're clearing a bit, lose it's accent, too.
|
|
if(!setting)
|
|
{
|
|
if(thePattern.getAccentBit(keynum))
|
|
thePattern.toggleAccentBit(keynum);
|
|
}
|
|
|
|
setLEDs(true);
|
|
}
|
|
}
|
|
else if(keynum == VOICE_SEL_INDICATOR) // voice select mode
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_VOICE_SEL);
|
|
}
|
|
}
|
|
else if(keynum == STEP_ACCENT_INDICATOR) // voice select mode
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_STEP_ACCENT);
|
|
}
|
|
}
|
|
|
|
else if(keynum == MUTE_SEL_INDICATOR)
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_MUTE_SEL);
|
|
}
|
|
}
|
|
else if(keynum == PATTERN_SEL_INDICATOR) // pattern select mode
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_PATT_SEL);
|
|
}
|
|
}
|
|
else if(keynum == UTILITY_SEL_INDICATOR)
|
|
{
|
|
if(pressed)// && (!thePlayer.isPlaying()))
|
|
{
|
|
theEditor.setMode(Editor::eMODE_UTILITY);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
else// other, unmapped keys, just show they work.
|
|
{
|
|
theScanner.setBackgroundLED(keynum, pressed);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
void StepEdit::setLEDs(bool entry)
|
|
{
|
|
// Initialize LEDs
|
|
if(entry)
|
|
{
|
|
doPlayingLed();
|
|
|
|
theScanner.setBackgroundLED(STEP_EDIT_INDICATOR);
|
|
|
|
for(uint32_t i = 0; i < Pattern::PATTERN_LEN; i++)
|
|
{
|
|
theScanner.setBackgroundLED(i, thePattern.getVoiceBit(i));
|
|
}
|
|
}
|
|
else // on exit
|
|
{
|
|
theScanner.clearAllHalfLEDs();
|
|
theScanner.clearAllBackgroundLEDs();
|
|
theScanner.clearAllBlinkingLEDs();
|
|
}
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//////// Accent Editor
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
StepAccent::StepAccent(): pvEditorMode()
|
|
{
|
|
//current_voice = 0;
|
|
|
|
}
|
|
|
|
void StepAccent::HandleKey(uint32_t keynum, bool pressed)
|
|
{
|
|
bool setting;
|
|
Serial.write("Step Accent");
|
|
|
|
if(keynum == STEP_ACCENT_INDICATOR)
|
|
{
|
|
if(!pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_STEP_EDIT);
|
|
}
|
|
}
|
|
else if (keynum == PLAY_INDICATOR) //start/stop key
|
|
{
|
|
HandlePlayButton(pressed);
|
|
}
|
|
else if((keynum >= 0) && (keynum <= 15))
|
|
{
|
|
if(pressed)
|
|
{
|
|
setting = thePattern.toggleAccentBit(keynum);
|
|
|
|
// If we just added an accent, but note isn't triggered, trigger it.
|
|
// Likewise, if we cleared and accent, clear the trigger.
|
|
// Don't leave stranded accents, because they're an ugly surprise later...
|
|
if( (setting && !thePattern.getVoiceBit(keynum) ) ||
|
|
(!setting && thePattern.getVoiceBit(keynum)))
|
|
{
|
|
thePattern.toggleBit(keynum);
|
|
}
|
|
|
|
setLEDs(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void StepAccent::setLEDs(bool entry)
|
|
{
|
|
// Initialize LEDs
|
|
if(entry)
|
|
{
|
|
doPlayingLed();
|
|
|
|
theScanner.setBackgroundLED(STEP_ACCENT_INDICATOR);
|
|
|
|
for(uint32_t i = 0; i < Pattern::PATTERN_LEN; i++)
|
|
{
|
|
theScanner.setBackgroundLED(i, thePattern.getAccentBit(i));
|
|
theScanner.setHalfLED(i, thePattern.getVoiceBit(i));
|
|
}
|
|
}
|
|
else // on exit
|
|
{
|
|
theScanner.clearAllHalfLEDs();
|
|
theScanner.clearAllBackgroundLEDs();
|
|
theScanner.clearAllBlinkingLEDs();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//////// Voice Selector
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
VoiceSelect::VoiceSelect(): pvEditorMode()
|
|
{
|
|
|
|
}
|
|
|
|
void VoiceSelect::HandleKey(uint32_t keynum, bool pressed)
|
|
{
|
|
Serial.write("Voice select");
|
|
|
|
if(keynum == VOICE_SEL_INDICATOR) // voice select mode
|
|
{
|
|
if(!pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_STEP_EDIT);
|
|
}
|
|
}
|
|
else if (keynum == PLAY_INDICATOR) //start/stop key
|
|
{
|
|
HandlePlayButton(pressed);
|
|
}
|
|
else if((keynum >= 0) && (keynum <= 10))
|
|
{
|
|
// TBD - more voices means accept more input
|
|
if(pressed)
|
|
{
|
|
thePattern.setCurrentVoice(keynum);
|
|
setLEDs(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void VoiceSelect::setLEDs(bool entry)
|
|
{
|
|
uint32_t bitnum;
|
|
|
|
if(entry)
|
|
{
|
|
theScanner.clearAllBackgroundLEDs();
|
|
|
|
doPlayingLed();
|
|
|
|
// Mode indication
|
|
theScanner.setBackgroundLED(VOICE_SEL_INDICATOR);
|
|
|
|
// Present voice indication
|
|
bitnum = thePattern.getCurrentVoice();
|
|
theScanner.setBackgroundLED(bitnum);
|
|
}
|
|
else
|
|
{
|
|
theScanner.clearAllBackgroundLEDs();
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//////// Mute Selector
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
MuteSelect::MuteSelect(): pvEditorMode()
|
|
{
|
|
|
|
}
|
|
|
|
void MuteSelect::HandleKey(uint32_t keynum, bool pressed)
|
|
{
|
|
// bool setting;
|
|
Serial.write("Mute select");
|
|
|
|
if(keynum == STEP_EDIT_INDICATOR) // voice select mode
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_STEP_EDIT);
|
|
}
|
|
}
|
|
else if(keynum == PATTERN_SEL_INDICATOR) // pattern select mode
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_PATT_SEL);
|
|
}
|
|
}
|
|
else if (keynum == PLAY_INDICATOR) //start/stop key
|
|
{
|
|
HandlePlayButton(pressed);
|
|
}
|
|
else if(keynum == UTILITY_SEL_INDICATOR)
|
|
{
|
|
if(pressed)// && (!thePlayer.isPlaying()))
|
|
{
|
|
theEditor.setMode(Editor::eMODE_UTILITY);
|
|
}
|
|
}
|
|
|
|
else if((keynum >= 0) && (keynum <= 10))
|
|
{
|
|
if(pressed)
|
|
{
|
|
bool setting;
|
|
setting = thePlayer.toggleMuteBit(keynum);
|
|
setLEDs(true);
|
|
if (setting == true) {};
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void MuteSelect::setLEDs(bool entry)
|
|
{
|
|
if(entry)
|
|
{
|
|
doPlayingLed();
|
|
|
|
// set mode indicator
|
|
theScanner.setBackgroundLED(MUTE_SEL_INDICATOR);
|
|
|
|
// and display data on editor buttons
|
|
for(uint32_t i = 0; i < 12; i++)
|
|
{
|
|
theScanner.setBackgroundLED(i, thePlayer.getMuteBit(i));
|
|
// blinking overrides background
|
|
theScanner.setBlinkingLED(i, thePlayer.getPendingMuteBit(i));
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
theScanner.clearAllBackgroundLEDs();
|
|
theScanner.clearAllBlinkingLEDs();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//////// Pattern Selector
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
PatternSelect::PatternSelect()
|
|
{
|
|
|
|
}
|
|
|
|
void PatternSelect::HandleKey(uint32_t keynum, bool pressed)
|
|
{
|
|
Serial.write("Pattern select");
|
|
|
|
if(keynum == STEP_EDIT_INDICATOR)
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_STEP_EDIT);
|
|
}
|
|
}
|
|
else if(keynum == MUTE_SEL_INDICATOR)
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_MUTE_SEL);
|
|
}
|
|
}
|
|
else if(keynum == UTILITY_SEL_INDICATOR)
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_UTILITY);
|
|
}
|
|
}
|
|
else if(keynum == PATTERN_CHAIN_INDICATOR)
|
|
{
|
|
if(pressed)
|
|
{
|
|
thePlayer.initChain();
|
|
theEditor.setMode(Editor::eMODE_CHAIN_EDIT);
|
|
}
|
|
}
|
|
else if (keynum == PLAY_INDICATOR) //start/stop key
|
|
{
|
|
HandlePlayButton(pressed);
|
|
}
|
|
else if((keynum >= 0) && (keynum <= 15))
|
|
{
|
|
if(pressed)
|
|
{
|
|
// if there was a chain, end it
|
|
if(thePlayer.chainIsActive())
|
|
{
|
|
thePlayer.initChain();
|
|
}
|
|
|
|
thePlayer.setNextPattern(keynum);
|
|
setLEDs(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PatternSelect::setLEDs(bool entry)
|
|
{
|
|
int32_t pending;
|
|
|
|
if(entry)
|
|
{
|
|
theScanner.clearAllBackgroundLEDs();
|
|
theScanner.clearAllBlinkingLEDs();
|
|
|
|
doPlayingLed();
|
|
|
|
// set mode indicator
|
|
theScanner.setBackgroundLED(PATTERN_SEL_INDICATOR);
|
|
|
|
if(!thePlayer.chainIsActive())
|
|
{
|
|
theScanner.setBackgroundLED(thePattern.getCurrentPattern());
|
|
pending = thePlayer.getPendingPattern();
|
|
if(pending != -1)
|
|
{
|
|
theScanner.setBlinkingLED(pending);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
doChainLeds();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
theScanner.clearAllBackgroundLEDs();
|
|
theScanner.clearAllBlinkingLEDs();
|
|
}
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//////// Chain Editor
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ChainEdit::ChainEdit()
|
|
{
|
|
|
|
}
|
|
|
|
void ChainEdit::HandleKey(uint32_t keynum, bool pressed)
|
|
{
|
|
Serial.write("Chain editor");
|
|
|
|
if(keynum == PATTERN_CHAIN_INDICATOR)
|
|
{
|
|
if(!pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_PATT_SEL);
|
|
}
|
|
}
|
|
else if(keynum == PLAY_INDICATOR) //start/stop key
|
|
{
|
|
HandlePlayButton(pressed);
|
|
}
|
|
else if((keynum >= 0) && (keynum <= 15))
|
|
{
|
|
if(pressed)
|
|
{
|
|
thePlayer.addToChain(keynum);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChainEdit::setLEDs(bool entry)
|
|
{
|
|
if(entry)
|
|
{
|
|
doPlayingLed();
|
|
|
|
doChainLeds();
|
|
|
|
// set mode indicator
|
|
theScanner.setBackgroundLED(PATTERN_CHAIN_INDICATOR);
|
|
}
|
|
else
|
|
{
|
|
theScanner.clearAllBackgroundLEDs();
|
|
theScanner.clearAllBlinkingLEDs();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//////// Utility mode
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
UtilityMode::UtilityMode(): pvEditorMode()
|
|
{
|
|
|
|
}
|
|
|
|
void UtilityMode::HandleKey(uint32_t keynum, bool pressed)
|
|
{
|
|
Serial.write("Utility mode");
|
|
|
|
if(keynum == STEP_EDIT_INDICATOR) // voice select mode
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_STEP_EDIT);
|
|
}
|
|
}
|
|
else if(keynum == MUTE_SEL_INDICATOR)
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_MUTE_SEL);
|
|
}
|
|
}
|
|
else if(keynum == PATTERN_SEL_INDICATOR) // pattern select mode
|
|
{
|
|
if(pressed)
|
|
{
|
|
theEditor.setMode(Editor::eMODE_PATT_SEL);
|
|
}
|
|
}
|
|
else if (keynum == PLAY_INDICATOR) //start/stop key
|
|
{
|
|
HandlePlayButton(pressed);
|
|
}
|
|
else if((keynum >= 0) && (keynum <= 15))
|
|
{
|
|
doUtilMode(keynum, pressed);
|
|
|
|
}
|
|
}
|
|
|
|
void UtilityMode::setLEDs(bool entry)
|
|
{
|
|
//uint32_t bitnum;
|
|
|
|
if(entry)
|
|
{
|
|
doPlayingLed();
|
|
|
|
// Mode indication
|
|
theScanner.setBackgroundLED(UTILITY_SEL_INDICATOR);
|
|
|
|
// Present data indication
|
|
theScanner.setBackgroundLED(0x2, thePlayer.getSwing());
|
|
}
|
|
else
|
|
{
|
|
theScanner.clearAllBackgroundLEDs();
|
|
}
|
|
}
|
|
|
|
void UtilityMode::doUtilMode(uint32_t keynum, bool pressed)
|
|
{
|
|
bool playing = thePlayer.isPlaying();
|
|
|
|
if(!pressed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch(keynum)
|
|
{
|
|
case 0:
|
|
{
|
|
if(!playing)
|
|
{
|
|
thePattern.clearCurrentPattern();
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
{
|
|
if(!playing)
|
|
{
|
|
thePattern.randomizeCurrentPattern();
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
thePlayer.toggleSwing();
|
|
setLEDs(true);
|
|
}
|
|
break;
|
|
case 14:
|
|
{
|
|
if(!playing)
|
|
{
|
|
delay(100);
|
|
|
|
thePattern.writeToCard();
|
|
|
|
delay(100);
|
|
}
|
|
}
|
|
break;
|
|
case 15:
|
|
{
|
|
if(!playing)
|
|
{
|
|
delay(100);
|
|
|
|
thePattern.readFromCard();
|
|
|
|
delay(100);
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|