From 365ebe3af3c4fe00f84453205697a6a9630118dc Mon Sep 17 00:00:00 2001 From: Len Date: Wed, 10 Apr 2024 10:37:21 -0400 Subject: [PATCH] Envelope2 firmware changes (#63) Lengthened attack, decay, and release times (especially in logarithmic mode), and cleaned up the code a bit. --- .../firmware/Envelope2/Envelope2.ino | 2092 +++++++++-------- .../Envelope2/firmware/Envelope2/TimedTask.h | 106 +- .../Envelope2/firmware/Envelope2/numtables.h | 882 +++---- .../MakeLookupTables/MakeLookupTables.cpp | 25 +- .../MakeLookupTables/MakeLookupTables.vcxproj | 350 +-- 5 files changed, 1730 insertions(+), 1725 deletions(-) diff --git a/modules/Envelope2/firmware/Envelope2/Envelope2.ino b/modules/Envelope2/firmware/Envelope2/Envelope2.ino index 87c3f289..7c20de21 100644 --- a/modules/Envelope2/firmware/Envelope2/Envelope2.ino +++ b/modules/Envelope2/firmware/Envelope2/Envelope2.ino @@ -1,1043 +1,1049 @@ -/* -Firmware for Envelope2 Eurorack module - -Copyright 2022 Len Popp - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include "TimedTask.h" - -// -// Misc Definitions -// - -// Debugging flags -//#define DEBUG -#ifdef DEBUG -#define DEBUG_ERROR_COUNTER -//#define DUMMY_READS -#define DEBUG_FAKE_GATES -//#define DEBUG_ENV_DUMP -#define DEBUG_ENV_OUTPUT -//#define DEBUG_TIME_TEST -#define DEBUG_WATCHDOG -#else // !DEBUG -#define DEBUG_ERROR_COUNTER -#define DEBUG_WATCHDOG -#endif - -#define INLINE __attribute__((always_inline)) - -// Macros to access flash program memory. -#define PMEMB(addr) pgm_read_byte_near(addr) -#define PMEMW(addr) pgm_read_word_near(addr) -#define PMEMD(addr) pgm_read_dword_near(addr) - -// Macros to manipulate bits in control registers. -// setBit(), clrBit() can be used as efficient substitutes for digitalWrite(). -#define setBit(xPORT, xBIT) xPORT |= (1 << (xBIT)) -#define setBits(xPORT, xBITS, xMASK) xPORT = (xPORT & ~(xMASK)) | (xBITS) -#define clrBit(xPORT, xBIT) xPORT &= (~(1 << (xBIT))) - -#ifdef DEBUG_TIME_TEST -volatile unsigned long counterTimeTest = 0; -#endif -#ifdef DEBUG_ERROR_COUNTER -volatile unsigned long counterErrors = 0; -#endif - -// Word32 is a 32-bit word whose individual bytes can be accessed for efficiency. -struct Word32 -{ - union - { - uint32_t dw; - struct - { - uint8_t b0; - uint8_t b1; - uint8_t b2; - uint8_t b3; - }; - }; - Word32() { } - Word32(uint32_t dw) { this->dw = dw; } -}; - -// -// Data tables -// - -#include "numtables.h" - -// -// I/O Definitions -// - -// For some I/O pins we define both the Arduino pin number and the chip register & bit -// so that we can access the pin directly for efficiency in time-critical code. - -// Lin/Log switch inputs -const byte pinSwLogLin1 = 4; -const byte pinSwLogLin2 = 7; - -// Gate inputs (also used as interrupts) -const byte pinGate1 = 2; -const byte pinGate2 = 3; - -// LED PWM outputs -const byte pinLED1 = 5; // The LED is on a Timer0 PWM pin (output) -const byte pinLED2 = 6; // The LED is on a Timer0 PWM pin (output) - -// ADC channel selection -const byte pinChannelSel = 9; -#ifdef CHANNEL_SEL_2_PINS // if a second switch control is needed, e.g. for CD4016/4066 -const byte pinChannelSel2 = 10; -#endif - -void initIOPins() -{ - pinMode(pinGate1, INPUT); - pinMode(pinGate2, INPUT); - pinMode(pinSwLogLin1, INPUT_PULLUP); - pinMode(pinSwLogLin2, INPUT_PULLUP); - pinMode(pinLED1, OUTPUT); - pinMode(pinLED2, OUTPUT); - pinMode(pinChannelSel, OUTPUT); -#ifdef CHANNEL_SEL_2_PINS // if a second switch control is needed, e.g. for CD4016/4066 - pinMode(pinChannelSel2, OUTPUT); -#endif - analogReference(DEFAULT); -} - -#ifdef DUMMY_READS -int dummyDigitalRead(byte pin) -{ - int n; - switch (pin) { - case pinSwLogLin1: - case pinSwLogLin2: - n = HIGH; // linear envelope - break; - //case pinGate1: - //case pinGate2: - // n = digitalRead(pin); // really read a gate signal - // break; - default: - n = LOW; - break; - } - return n; -} -#endif - -int readDigitalPin(byte pin) -{ - int w; -#ifdef DUMMY_READS - w = dummyDigitalRead(pin); -#else - w = digitalRead(pin); -#endif - return w; -} - -#ifdef DUMMY_READS -unsigned dummyAnalogRead(byte pin) -{ - unsigned w; - switch (pin) { - case 4: - w = 512; // 50% sustain - break; - default: - w = 621; // 0.5s A, D, R - break; - } - return w; -} -#endif - -unsigned readADCPin(byte pin) -{ - unsigned w; -#ifdef DUMMY_READS - w = dummyAnalogRead(pin); -#else - w = analogRead(pin); -#endif - return w; -} - -uint32_t readTimeInput(byte pin) -{ - // Read an A, D or R knob and return the corresponding timer increment value. - unsigned w = readADCPin(pin); - if (w > cTimeInputMapTable) - w = cTimeInputMapTable; - return PMEMD(TimeInputMapTable + w); // TimeInputMapTable[w]; -} - -unsigned readSustainInput(byte pin) -{ - // Read a Sustain knob and return the corresponding sustain value. - unsigned w = readADCPin(pin); - // Sustain range is zero to 4095. - if (w >= 1023) - w = 4095; - else - w <<= 2; - return w; -} - -// -// Envelope Implementation -// - -class ADSREnvelope -{ -public: - ADSREnvelope(byte pinA, byte pinD, byte pinS, byte pinR, byte pinL, byte pinG); - - bool IsLooping() const { return fLoop; } - word CurrentOutput() const { return wCurOut; } - - void ReadControls(); - void HandleGateInterrupt(); - void GateStart(); - void GateStop(); - void Increment(); - -private: - // Parameters - uint32_t dwIncrAttack; // per-tick increment for attack - uint32_t dwIncrDecay; // per-tick increment for decay - word wSustain; // sustain level 0-4095 - uint32_t dwIncrRelease; // per-tick increment for release - bool fLogarithmic; // true = logarithmic, false = linear - bool fLoop; // true = loop mode NOTE: not supported - - // Envelope states/phases - typedef enum { - stateOff, stateAttack, stateDecay, stateSustain, stateRelease - } ADSRState; - - // Current state - ADSRState state; // current envelope phase/state - Word32 dwCurPos; // current position in the envelope curve (24 bits) - word wCurOut; // current output level 0-4095 - word wOutOffset; // output offset, used in decay phase - - static const word wOutputRange = 4096; - static const uint32_t dwPosRange = ((uint32_t)wOutputRange) << 12; - - // Input pins - // Analog - const byte pinAttack; - const byte pinDecay; - const byte pinSustain; - const byte pinRelease; - // Digital - const byte pinLogLin; - const byte pinGate; - -private: - void InitAttack(); - void IncrementAttack(); - void InitDecay(); - void IncrementDecay(); - void InitSustain(); - void UpdateSustain(); - void InitRelease(); - void IncrementRelease(); - void StopEnvelope(); - static word LookupAttackValue(word wValue); - static word InterpolateAttackValue(word wValue); - static word LookupDecayValue(word wValue); - static word InterpolateDecayValue(word wValue); - -// Debugging functions -public: -#ifdef DEBUG_ENV_DUMP - void Dump(); -#endif -#ifdef DEBUG_ENV_OUTPUT - void DebugOut(); - bool fDisplayOn; - unsigned long tStart; -#endif -}; - -ADSREnvelope::ADSREnvelope(byte pinA, byte pinD, byte pinS, byte pinR, byte pinL, byte pinG) - : dwIncrAttack(512), - dwIncrDecay(512), - wSustain(1000), - dwIncrRelease(512), - fLogarithmic(false), - fLoop(false), - state(stateOff), - dwCurPos(0), - wCurOut(0), - wOutOffset(0), - pinAttack(pinA), - pinDecay(pinD), - pinSustain(pinS), - pinRelease(pinR), - pinLogLin(pinL), - pinGate(pinG) -#ifdef DEBUG_ENV_OUTPUT - ,fDisplayOn(false), - tStart(0) -#endif -{ -} - -void ADSREnvelope::ReadControls() -{ - // NOTE: The correct channel must be selected in the ADC switch - // before calling this function. - dwIncrAttack = readTimeInput(pinAttack); - dwIncrDecay = readTimeInput(pinDecay); - wSustain = readSustainInput(pinSustain); - dwIncrRelease = readTimeInput(pinRelease); - fLogarithmic = (readDigitalPin(pinLogLin) == LOW); -} - -void ADSREnvelope::HandleGateInterrupt() -{ - if (readDigitalPin(pinGate) == HIGH) - GateStart(); - else - GateStop(); -} - -void ADSREnvelope::GateStart() -{ - // Gate signal has gone high - Start the envelope! - InitAttack(); -} - -void ADSREnvelope::GateStop() -{ - // Gate signal has gone low - Transition to Release state. - // If the envelope isn't currently in an appropriate state, do nothing. - if (state != stateOff && state != stateRelease) { - InitRelease(); - } -} - -void ADSREnvelope::Increment() -{ - switch (state) { - case stateAttack: - IncrementAttack(); - break; - case stateDecay: - IncrementDecay(); - break; - case stateSustain: - UpdateSustain(); - break; - case stateRelease: - IncrementRelease(); - break; - case stateOff: - default: - // do nothing - break; - } -} - -void ADSREnvelope::InitAttack() -{ - // Attack starts from the current output value, even if not zero. - //wCurOut = wCurOut; - // If starting from a non-zero value, initialize dwCurPos so that it runs the - // last part of the attack not the first. That simplifies the Increment() code - // and gives a nicer logarithmic curve. - word w = wCurOut; - if (fLogarithmic) { - // Log curve - w = LookupAttackValue(w) << 2; - } - dwCurPos.dw = ((uint32_t)w) << 12; - wOutOffset = 0; - state = stateAttack; -} - -void ADSREnvelope::IncrementAttack() -{ - dwCurPos.dw += dwIncrAttack; - if (dwCurPos.b3 != 0) { //if (dwCurPos.dw > dwPosRange) - // finished this phase of the envelope - InitDecay(); - } else { - word w = ((uint32_t)dwCurPos.dw) >> 12; - if (fLogarithmic) { - // Convert to a logarithmic curve - w = InterpolateAttackValue(w); - } - wCurOut = w; // w - wOutOffset but wOutOffset is 0 - } -} - -void ADSREnvelope::InitDecay() -{ - // Decay should always start from the maximum output value (otherwise the decay - // phase wouldn't have started yet). - wCurOut = wOutputRange - 1; // max output value - // Initialize dwCurPos so that it runs the last part of the decay curve not the first. - // That simplifies the Increment() code and gives a nicer logarithmic curve. - word w = wSustain; - if (fLogarithmic) { - // Log curve - w = LookupDecayValue(w) << 2; - } - dwCurPos.dw = ((uint32_t)w) << 12; - wOutOffset = wSustain; - state = stateDecay; -} - -void ADSREnvelope::IncrementDecay() -{ - dwCurPos.dw += dwIncrDecay; - if (dwCurPos.b3 != 0) { //if (dwCurPos.dw > dwPosRange) - // finished this phase of the envelope - if (fLoop) { - // Loop mode: No sustain phase, continue right on to release - InitRelease(); - } else { - // Normal mode: Start sustain phase - InitSustain(); - } - } else { - word w = ((uint32_t)dwCurPos.dw) >> 12; - if (fLogarithmic) { - // Convert to a logarithmic curve - w = InterpolateDecayValue(w); - } - wCurOut = wOutputRange - 1 - w + wOutOffset; - } -} - -void ADSREnvelope::InitSustain() -{ - wCurOut = wSustain; - dwCurPos.dw = 0; - state = stateSustain; -} - -void ADSREnvelope::UpdateSustain() -{ - // Update the current sustain level, in case the knob setting has changed. - wCurOut = wSustain; -} - -void ADSREnvelope::InitRelease() -{ - // Release starts from the current output value, even if it's not the sustain value. - //wCurOut = wCurOut; - // Initialize dwCurPos so that it runs the last part of the decay curve not the first. - // That simplifies the Increment() code and gives a nicer logarithmic curve. - word w = wOutputRange - 1 - wCurOut; - if (fLogarithmic) { - // Log curve - w = LookupDecayValue(w) << 2; - } - dwCurPos.dw = ((uint32_t)w) << 12; - wOutOffset = 0; - state = stateRelease; -} - -void ADSREnvelope::IncrementRelease() -{ - dwCurPos.dw += dwIncrRelease; - if (dwCurPos.b3 != 0) { //if (dwCurPos.dw > dwPosRange) - // finished this phase of the envelope - if (fLoop) { - // Loop mode: Restart the envelope immediately. - wCurOut = 0; - InitAttack(); - } else { - // Normal mode: Just stop enveloping. - StopEnvelope(); - } - } else { - word w = (((uint32_t)dwCurPos.dw) >> 12); - if (fLogarithmic) { - // Convert to a logarithmic curve - w = InterpolateDecayValue(w); - } - wCurOut = wOutputRange - 1 - w; - } -} - -void ADSREnvelope::StopEnvelope() -{ - state = stateOff; - dwCurPos = 0; - wCurOut = 0; -} - -/* - * LookupAttackValue - * Look up wValue in the attack curve table and return the index of the closest (equal or greater) value. - * This is to initialize the attack portion of the envelope when it's not starting from zero. - */ -word ADSREnvelope::LookupAttackValue(word wValue) -{ - if (wValue == 0) { - // must be handled specially - return 0; - } else { - word iLo = 0; - word iHi = cLogAttackMapTable - 1; - if (wValue < PMEMW(LogAttackMapTable + iHi)) { // just in case wValue is out of range - while (iHi - iLo > 1) { - word iNew = (iLo + iHi) >> 1; - word wNew = PMEMW(LogAttackMapTable + iNew); // LogAttackMapTable[iNew] - if (wNew >= wValue) - iHi = iNew; - else - iLo = iNew; - } - } - return iHi; - } -} - -/* - * InterpolateAttackValue - * Convert wValue to a logarithmic value with table lookup and interpolation. - */ -word ADSREnvelope::InterpolateAttackValue(word wValue) -{ - // Log curve - Table lookup with interpolation using the bottom 2 bits of wValue - word* pw = LogAttackMapTable + (wValue >> 2); - word w0 = PMEMW(pw); // LogAttackMapTable[(wValue >> 2)] - word w1 = PMEMW(pw+1); // LogAttackMapTable[(wValue >> 2)+1] - word wOut = w0; - word wT = (wValue & 1) ? w1 : w0; - wOut = (wOut + wT) >> 1; - wT = (wValue & 2) ? w1 : w0; - wOut = (wOut + wT) >> 1; - return wOut; -} - -/* - * LookupDecayValue - * Look up wValue in the decay/release curve table and return the index of the closest (equal or greater) value. - * This is to initialize the decay & release portions of the envelope starting from any value. - */ -word ADSREnvelope::LookupDecayValue(word wValue) -{ - if (wValue == 0) { - // must be handled specially - return 0; - } else { - word iLo = 0; - word iHi = cLogDecayMapTable - 1; - if (wValue < PMEMW(LogDecayMapTable + iHi)) { // just in case wValue is out of range - while (iHi - iLo > 1) { - word iNew = (iLo + iHi) >> 1; - word wNew = PMEMW(LogDecayMapTable + iNew); // LogDecayMapTable[iNew] - if (wNew >= wValue) - iHi = iNew; - else - iLo = iNew; - } - } - return iHi; - } -} - -/* - * InterpolateDecayValue - * Convert wValue to a logarithmic value with table lookup and interpolation. - */ -word ADSREnvelope::InterpolateDecayValue(word wValue) -{ - // Log curve - Table lookup with interpolation using the bottom 2 bits of wValue - word* pw = LogDecayMapTable + (wValue >> 2); - word w0 = PMEMW(pw); // LogDecayMapTable[(wValue >> 2)] - word w1 = PMEMW(pw+1); // LogDecayMapTable[(wValue >> 2)+1] - word wOut = w0; - word wT = (wValue & 1) ? w1 : w0; - wOut = (wOut + wT) >> 1; - wT = (wValue & 2) ? w1 : w0; - wOut = (wOut + wT) >> 1; - return wOut; -} - -#ifdef DEBUG_ENV_DUMP -void ADSREnvelope::Dump() -{ - Serial.print("ADSR pins="); Serial.print(pinAttack); Serial.print(' '); Serial.print(pinDecay); Serial.print(' '); Serial.print(pinSustain); Serial.print(' '); Serial.print(pinRelease); - Serial.print(" state="); Serial.println(state); - Serial.print("Log="); Serial.print(fLogarithmic); - Serial.print(" Attack="); Serial.print(dwIncrAttack); - Serial.print(" Decay="); Serial.print(dwIncrDecay); - Serial.print(" Sustain="); Serial.print(wSustain); - Serial.print(" Release="); Serial.println(dwIncrRelease); - Serial.print("CurPos="); Serial.print(dwCurPos.dw); Serial.print(" index="); Serial.println(dwCurPos.dw >> 14); - Serial.print("CurOut="); Serial.print(wCurOut); Serial.print(" Offset="); Serial.println(wOutOffset); - Serial.print("OutputRange="); Serial.print(wOutputRange); Serial.print(" PosRange="); Serial.println(dwPosRange); -} -#endif - -#ifdef DEBUG_ENV_OUTPUT -const byte cchStars = 64; -char szDebug[cchStars+1]; -char achStars[cchStars+1] = "****************************************************************"; - -void ADSREnvelope::DebugOut() -{ - word w = wCurOut; - if (!fDisplayOn) { - if (w > 0) { - fDisplayOn = true; - tStart = millis(); - } - } else { - byte bValue = (w >> 6); - if (bValue > cchStars) { - Serial.print("?? "); Serial.print(w); - } else { - memcpy(szDebug, achStars, bValue); - szDebug[bValue] = 0; - Serial.print(szDebug); - } - Serial.println(); - if (w == 0) { - fDisplayOn = false; -#ifdef DEBUG_ENV_DUMP - Serial.print("time: "); Serial.println(millis() - tStart); - Dump(); -#endif - } - } -} -#endif // DEBUG_ENV_OUTPUT - -volatile ADSREnvelope envelope1(0, 1, 4, 5, pinSwLogLin1, pinGate1); - -volatile ADSREnvelope envelope2(2, 3, 4, 5, pinSwLogLin2, pinGate2); - -// -// SPI Interface to DACs -// - -const SPISettings settings(20000000, MSBFIRST, SPI_MODE0); - -const byte pinCS1 = 10; // SPI chip-select for DAC 1 (output) -const byte pinBitCS1 = 2; -//const byte pinCS2 = 10; // SPI chip-select for DAC 2 (output) -//const byte pinBitCS2 = 2; -// All the CS lines are on the same port, to simplify the code. -#define pinPortCS PORTB - -// MCP482x DAC -const byte pinLDAC = 8; // DAC LDAC signal (output) -#define pinPortLDAC PORTB -const byte pinBitLDAC = 0; -// SPI commands -const byte bitDACAB = 15; // 0 = unit A, 1 = unit B -const byte bDACUnitA = 0; -const byte bDACUnitB = 1; -const byte bitDACGain = 13; // 0 = 2x, 1 = 1x -const byte bitDACShutdown = 12; // active low -const word wDACCmdDefault = ((0 << bitDACGain) | (1 << bitDACShutdown)); - -void initSPI() -{ - // SPI setup - pinMode(pinLDAC, OUTPUT); - digitalWrite(pinLDAC, LOW); - pinMode(pinCS1, OUTPUT); - digitalWrite(pinCS1, HIGH); - //pinMode(pinCS2, OUTPUT); - //digitalWrite(pinCS2, HIGH); - SPI.begin(); - // SPI settings don't change so beginTransaction() is only called once to save time. - SPI.beginTransaction(settings); -} - -void SPISendToDAC(word wNum, byte pinBitCS, byte bDACUnit) -{ - // Send an SPI command word to the MCP4821/4822 DAC - word wSPIData = wDACCmdDefault | ((word)bDACUnit << bitDACAB) | wNum; - //SPI.beginTransaction(settings); // moved to setup() - not necessary to do this every time - clrBit(pinPortCS, pinBitCS); //digitalWrite(pinCS, LOW); - SPI.transfer16(wSPIData); - setBit(pinPortCS, pinBitCS); //digitalWrite(pinCS, HIGH); - //SPI.endTransaction(); // don't do this every time -} - -// -// Timer Interrupt Handler -// - -// Timer interrupt settings -// freqTimer, compareTimer, bitsTimerPrescaler must all be set to match -const word freqTimer = 20000; // 24000; // 25000; // 31250; // timer interrupt frequency -const word compareTimer = 799; // 666; // 639; // 511; // compare value for timer interrupts -const byte bitsTimerPrescaler = 0b001; // /1 timer clock prescaler -const byte maskTimerPrescaler = 0b111; // bit mask for setting the prescaler - -void initTimerInterrupt() -{ - // Set Timer1 interrupt frequency. - cli(); - TCCR1A = 0; - TCCR1B = 0; - setBit(TCCR1B, WGM12); // mode = CTC with OCR1A - // The prescaler and compare values must be set to match freqTimer. - setBits(TCCR1B, bitsTimerPrescaler, maskTimerPrescaler); - OCR1A = compareTimer; - setBit(TIMSK1, OCIE1A); // enable timer compare interrupt - TCNT1 = 0; // initialize counter value - sei(); -} - -/* - * Timer1 Interrupt Handler - * This is where the envelopes are calculated and output. - */ -ISR(TIMER1_COMPA_vect) -{ -#ifdef DEBUG_TIME_TEST - counterTimeTest++; -#endif - - // Output the current envelope voltages to the DACs. - // Inhibit the DAC outputs and set them all at once. - setBit(pinPortLDAC, pinBitLDAC); //digitalWrite(pinLDAC, HIGH); - // Send the data to the DAC chips via SPI. - // Note that envelope 1 is output on DAC channel B and envelope 2 is on channel A. - SPISendToDAC(envelope1.CurrentOutput(), pinBitCS1, bDACUnitB); // send to DAC 1 unit B - SPISendToDAC(envelope2.CurrentOutput(), pinBitCS1, bDACUnitA); // send to DAC 1 unit A - //SPISendToDAC(wOut3, pinBitCS2, bDACUnitA); // send to DAC 2 - // Latch the DAC outputs. - clrBit(pinPortLDAC, pinBitLDAC); //digitalWrite(pinLDAC, LOW); - - // Increment the envelope states. - envelope1.Increment(); - envelope2.Increment(); -} - -// -// Gate Interrupt Handlers -// - -void initGateInterrupts() -{ - // Enable external interrupts INT0 & INT1 to be triggered by gate inputs - cli(); - setBits(EICRA, 0b0101, 0b1111); // both interrupts triggered by any change on pin - setBits(EIMSK, 0b11, 0b11); // both interrupts enabled - sei(); -} - -ISR(INT0_vect) -{ - envelope1.HandleGateInterrupt(); -} - - -ISR(INT1_vect) -{ - envelope2.HandleGateInterrupt(); -} - -// -// TaskBlinkLeds - Blink the indicator LEDs -// - -class TaskBlinkLeds : public TimedTask -{ -public: - static const unsigned dtBlinkLEDs = 3; - - TaskBlinkLeds() : TimedTask(dtBlinkLEDs) {} - - void Task(unsigned long tNow) - { - blinkLED(pinLED1, envelope1.CurrentOutput()); - blinkLED(pinLED2, envelope2.CurrentOutput()); - } - - static void blinkLED(byte pin, word wValue) - { - // wValue is a 12-bit DAC output value - byte b = wValue >> 4; - // Light curve mapping to make the LED look nicer. - // LEDMapTable entries are in progmem - byte* addr = LEDMapTable + b; - b = PMEMB(addr); // LEDMapTable[index]; - analogWrite(pin, b); - } -}; - -TaskBlinkLeds taskBlinkLEDs; - -// -// TaskReadControls - Read the front panel controls -// - -class TaskReadControls : public TimedTask -{ -public: - static const unsigned dtReadControls = 50; - - TaskReadControls() : TimedTask(dtReadControls) {} - - void Task(unsigned long tNow) - { - // Read the front-panel controls for each of the envelopes. - // Note that some ADC pins are shared via a CD4016 switch - // so the appropriate channel must be selected before reading. -#ifdef CHANNEL_SEL_2_PINS // if a second switch control is needed, e.g. for CD4016/4066 - digitalWrite(pinChannelSel2, LOW); -#endif - digitalWrite(pinChannelSel, HIGH); - envelope1.ReadControls(); - digitalWrite(pinChannelSel, LOW); -#ifdef CHANNEL_SEL_2_PINS // if a second switch control is needed, e.g. for CD4016/4066 - digitalWrite(pinChannelSel2, HIGH); -#endif - envelope2.ReadControls(); - } -}; - -TaskReadControls taskReadControls; - -#ifdef DEBUG_WATCHDOG - -// -// TaskWatchdog - Task to keep an eye on processor load -// - -class TaskWatchdog : public TimedTask -{ -public: - static const unsigned dtWatchdog = 10;//250; - static const unsigned dtError = dtWatchdog + 1; - - TaskWatchdog() : TimedTask(dtWatchdog) {} - - void Task(unsigned long tNow) - { - static unsigned long tPrevious = 0; - static bool fErrorsSeen = false; - unsigned long dt = tNow - tPrevious; - // Check if this task is executing on time. Allow 1 millisecond of slop. - if (dt > dtError && tPrevious != 0) { - // This task did not execute at the expected time, implying that the processor is overloaded. - // Increment the error counter; print a message only the first time. -#ifdef DEBUG_ERROR_COUNTER - counterErrors++; -#endif - if (!fErrorsSeen) { - fErrorsSeen = true; - Serial.print("ERROR: Processor overload - dt = "); - Serial.print(dt); Serial.print(" should be "); Serial.println(dtWatchdog); - } - } - tPrevious = tNow; - } -}; - -TaskWatchdog taskWatchdog; - -#endif // DEBUG_WATCHDOG - -#ifdef DEBUG_ERROR_COUNTER - -// -// TaskCheckErrors - Check Errors -// - -class TaskCheckErrors : public TimedTask -{ -public: - static const unsigned dtCheckErrors = 10; - - TaskCheckErrors() : TimedTask(dtCheckErrors) {} - - void Task(unsigned long tNow) - { - if (counterErrors != 0) { - unsigned long counterT = counterErrors; - counterErrors = 0; - Serial.print("*** ERROR "); Serial.print(counterT); Serial.println(" ***"); - } - } -}; - -TaskCheckErrors taskCheckErrors; - -#endif // DEBUG_ERROR_COUNTER - -#ifdef DEBUG_FAKE_GATES - -// -// TaskDebugGates - Fake gate signals for debugging -// - -class TaskDebugGates : public TimedTask -{ -public: - static const unsigned dtDebugGates = 2000; - - TaskDebugGates() : TimedTask(dtDebugGates) {} - - void Task(unsigned long tNow) - { - static bool fGateOn = false; - if (!fGateOn) { - fGateOn = true; - if (!envelope1.IsLooping()) - envelope1.GateStart(); - if (!envelope2.IsLooping()) - envelope2.GateStart(); - } else { - fGateOn = false; - if (!envelope1.IsLooping()) - envelope1.GateStop(); - if (!envelope2.IsLooping()) - envelope2.GateStop(); - } - } -}; - -TaskDebugGates taskDebugGates; - -#endif // DEBUG_FAKE_GATES - -#ifdef DEBUG_ENV_OUTPUT - -// -// TaskDebugOut - Debug Output -// - -class TaskDebugOut : public TimedTask -{ -public: - static const unsigned dtDebugOut = 50;//101; - - TaskDebugOut() : TimedTask(dtDebugOut) {} - - void Task(unsigned long tNow) - { - envelope2.DebugOut(); - } -}; - -TaskDebugOut taskDebugOut; - -#endif // DEBUG_ENV_OUTPUT - -#ifdef DEBUG_TIME_TEST - -// -// TaskDebugTimeTest - Time Test -// - -class TaskDebugTimeTest : public TimedTask -{ -public: - static const unsigned dtDebugTimeTest = 2010; - - TaskDebugTimeTest() : TimedTask(dtDebugTimeTest) {} - - void Task(unsigned long tNow) - { - Serial.print("testing..."); - unsigned long n = 100000; - volatile unsigned long i; - unsigned long tStart = millis(); - counterTimeTest = 0; - for (i = 0; i < n; i++) { - ; - } - unsigned long tStop = millis(); - unsigned long dt = tStop - tStart; - Serial.print("done "); - Serial.print(n); - Serial.print(" iterations in "); - Serial.print(dt); - Serial.print(" milliseconds, "); - unsigned long freqInterrupt = (1000 * counterTimeTest) / dt; - Serial.print(freqInterrupt); - Serial.println(" interrupts/s"); - } -}; - -TaskDebugTimeTest taskDebugTimeTest; - -#endif // DEBUG_TIME_TEST - - -// -// The Usual -// - -void setup() -{ - Serial.begin(115200); - Serial.println("\nEnvelope2 start"); - initIOPins(); - initSPI(); - initTimerInterrupt(); - initGateInterrupts(); - // Loop mode: Start the envelopes looping. - // NOTE: Loop mode is not fully implemented. - if (envelope1.IsLooping()) - envelope1.GateStart(); - if (envelope2.IsLooping()) - envelope2.GateStart(); -} - -void loop() -{ - // Execute timed tasks - // These tasks are lower priority than the interrupt handlers. - unsigned long tNow = millis(); - taskBlinkLEDs.Tick(tNow); - taskReadControls.Tick(tNow); - - // Debugging Tasks -#ifdef DEBUG_FAKE_GATES - taskDebugGates.Tick(tNow); -#endif -#ifdef DEBUG_ENV_OUTPUT - taskDebugOut.Tick(tNow); -#endif -#ifdef DEBUG_ERROR_COUNTER - taskCheckErrors.Tick(tNow); -#endif -#ifdef DEBUG_TIME_TEST - taskDebugTimeTest.Tick(tNow); -#endif -#ifdef DEBUG_WATCHDOG - taskWatchdog.Tick(tNow); -#endif -} +/* +Firmware for Envelope2 Eurorack module + +Copyright 2022 Len Popp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "TimedTask.h" + +// +// Misc Definitions +// + +// Debugging flags +//#define DEBUG +#ifdef DEBUG +#define DEBUG_ERROR_COUNTER +//#define DUMMY_READS +#define DEBUG_FAKE_GATES +//#define DEBUG_ENV_DUMP +#define DEBUG_ENV_OUTPUT +//#define DEBUG_TIME_TEST +#define DEBUG_WATCHDOG +#else // !DEBUG +#define DEBUG_ERROR_COUNTER +#define DEBUG_WATCHDOG +#endif + +#define INLINE __attribute__((always_inline)) + +// Macros to access flash program memory. +#define PMEMB(addr) pgm_read_byte_near(addr) +#define PMEMW(addr) pgm_read_word_near(addr) +#define PMEMD(addr) pgm_read_dword_near(addr) + +// Macros to manipulate bits in control registers. +// setBit(), clrBit() can be used as efficient substitutes for digitalWrite(). +#define setBit(xPORT, xBIT) xPORT |= (1 << (xBIT)) +#define setBits(xPORT, xBITS, xMASK) xPORT = (xPORT & ~(xMASK)) | (xBITS) +#define clrBit(xPORT, xBIT) xPORT &= (~(1 << (xBIT))) + +#ifdef DEBUG_TIME_TEST +volatile unsigned long counterTimeTest = 0; +#endif +#ifdef DEBUG_ERROR_COUNTER +volatile unsigned long counterErrors = 0; +#endif + +// Word32 is a 32-bit word whose individual bytes can be accessed for efficiency. +struct Word32 +{ + union + { + uint32_t dw; + struct + { + uint8_t b0; + uint8_t b1; + uint8_t b2; + uint8_t b3; + }; + }; + Word32() { } + Word32(uint32_t dw) { this->dw = dw; } +}; + +// +// Data tables +// + +#include "numtables.h" + +// +// I/O Definitions +// + +// For some I/O pins we define both the Arduino pin number and the chip register & bit +// so that we can access the pin directly for efficiency in time-critical code. + +// Lin/Log switch inputs +const byte pinSwLogLin1 = 4; +const byte pinSwLogLin2 = 7; + +// Gate inputs (also used as interrupts) +const byte pinGate1 = 2; +const byte pinGate2 = 3; + +// LED PWM outputs +const byte pinLED1 = 5; // The LED is on a Timer0 PWM pin (output) +const byte pinLED2 = 6; // The LED is on a Timer0 PWM pin (output) + +// ADC channel selection +const byte pinChannelSel = 9; +#ifdef CHANNEL_SEL_2_PINS // if a second switch control is needed, e.g. for CD4016/4066 +const byte pinChannelSel2 = 10; +#endif + +void initIOPins() +{ + pinMode(pinGate1, INPUT); + pinMode(pinGate2, INPUT); + pinMode(pinSwLogLin1, INPUT_PULLUP); + pinMode(pinSwLogLin2, INPUT_PULLUP); + pinMode(pinLED1, OUTPUT); + pinMode(pinLED2, OUTPUT); + pinMode(pinChannelSel, OUTPUT); +#ifdef CHANNEL_SEL_2_PINS // if a second switch control is needed, e.g. for CD4016/4066 + pinMode(pinChannelSel2, OUTPUT); +#endif + analogReference(DEFAULT); +} + +#ifdef DUMMY_READS +int dummyDigitalRead(byte pin) +{ + int n; + switch (pin) { + case pinSwLogLin1: + case pinSwLogLin2: + n = HIGH; // linear envelope + break; + //case pinGate1: + //case pinGate2: + // n = digitalRead(pin); // really read a gate signal + // break; + default: + n = LOW; + break; + } + return n; +} +#endif + +int readDigitalPin(byte pin) +{ + int w; +#ifdef DUMMY_READS + w = dummyDigitalRead(pin); +#else + w = digitalRead(pin); +#endif + return w; +} + +#ifdef DUMMY_READS +unsigned dummyAnalogRead(byte pin) +{ + unsigned w; + switch (pin) { + case 4: + w = 512; // 50% sustain + break; + default: + w = 621; // 0.5s A, D, R + break; + } + return w; +} +#endif + +unsigned readADCPin(byte pin) +{ + unsigned w; +#ifdef DUMMY_READS + w = dummyAnalogRead(pin); +#else + w = analogRead(pin); +#endif + return w; +} + +uint32_t readTimeInput(byte pin, bool fLog) +{ + // Read an A, D or R knob and return the corresponding timer increment value. + unsigned w = readADCPin(pin); + if (w > cTimeInputMapTable) + w = cTimeInputMapTable; + uint32_t result = PMEMD(TimeInputMapTable + w); // TimeInputMapTable[w]; + // For logarithmic envelope, stretch it out because it drops too quickly at first. + if (fLog) + result /= 4; + return result; +} + +unsigned readSustainInput(byte pin) +{ + // Read a Sustain knob and return the corresponding sustain value. + unsigned w = readADCPin(pin); + // Sustain range is zero to 4095. + if (w >= 1023) + w = 4095; + else + w <<= 2; + return w; +} + +// +// Envelope Implementation +// + +class ADSREnvelope +{ +public: + ADSREnvelope(byte pinA, byte pinD, byte pinS, byte pinR, byte pinL, byte pinG); + + bool IsLooping() const { return fLoop; } + word CurrentOutput() const { return wCurOut; } + + void ReadControls(); + void HandleGateInterrupt(); + void GateStart(); + void GateStop(); + void Increment(); + +private: + // Parameters + uint32_t dwIncrAttack; // per-tick increment for attack + uint32_t dwIncrDecay; // per-tick increment for decay + word wSustain; // sustain level 0-4095 + uint32_t dwIncrRelease; // per-tick increment for release + bool fLogarithmic; // true = logarithmic, false = linear + bool fLoop; // true = loop mode NOTE: not supported + + // Envelope states/phases + typedef enum { + stateOff, stateAttack, stateDecay, stateSustain, stateRelease + } ADSRState; + + // Current state + ADSRState state; // current envelope phase/state + Word32 dwCurPos; // current position in the envelope curve (24 bits) + word wCurOut; // current output level 0-4095 + word wOutOffset; // output offset, used in decay phase + + static const word wOutputRange = 4096; + static const uint32_t dwPosRange = ((uint32_t)wOutputRange) << 12; + + // Input pins + // Analog + const byte pinAttack; + const byte pinDecay; + const byte pinSustain; + const byte pinRelease; + // Digital + const byte pinLogLin; + const byte pinGate; + +private: + void InitAttack(); + void IncrementAttack(); + void InitDecay(); + void IncrementDecay(); + void InitSustain(); + void UpdateSustain(); + void InitRelease(); + void IncrementRelease(); + void StopEnvelope(); + static word LookupAttackValue(word wValue); + static word InterpolateAttackValue(word wValue); + static word LookupDecayValue(word wValue); + static word InterpolateDecayValue(word wValue); + +// Debugging functions +public: +#ifdef DEBUG_ENV_DUMP + void Dump(); +#endif +#ifdef DEBUG_ENV_OUTPUT + void DebugOut(); + bool fDisplayOn; + unsigned long tStart; +#endif +}; + +ADSREnvelope::ADSREnvelope(byte pinA, byte pinD, byte pinS, byte pinR, byte pinL, byte pinG) + : dwIncrAttack(512), + dwIncrDecay(512), + wSustain(1000), + dwIncrRelease(512), + fLogarithmic(false), + fLoop(false), + state(stateOff), + dwCurPos(0), + wCurOut(0), + wOutOffset(0), + pinAttack(pinA), + pinDecay(pinD), + pinSustain(pinS), + pinRelease(pinR), + pinLogLin(pinL), + pinGate(pinG) +#ifdef DEBUG_ENV_OUTPUT + ,fDisplayOn(false), + tStart(0) +#endif +{ +} + +void ADSREnvelope::ReadControls() +{ + // NOTE: The correct channel must be selected in the ADC switch + // before calling this function. + fLogarithmic = (readDigitalPin(pinLogLin) == LOW); + dwIncrAttack = readTimeInput(pinAttack, false); // do not adjust in log mode + dwIncrDecay = readTimeInput(pinDecay, fLogarithmic); + wSustain = readSustainInput(pinSustain); + dwIncrRelease = readTimeInput(pinRelease, fLogarithmic); +} + +void ADSREnvelope::HandleGateInterrupt() +{ + if (readDigitalPin(pinGate) == HIGH) + GateStart(); + else + GateStop(); +} + +void ADSREnvelope::GateStart() +{ + // Gate signal has gone high - Start the envelope! + InitAttack(); +} + +void ADSREnvelope::GateStop() +{ + // Gate signal has gone low - Transition to Release state. + // If the envelope isn't currently in an appropriate state, do nothing. + if (state != stateOff && state != stateRelease) { + InitRelease(); + } +} + +void ADSREnvelope::Increment() +{ + switch (state) { + case stateAttack: + IncrementAttack(); + break; + case stateDecay: + IncrementDecay(); + break; + case stateSustain: + UpdateSustain(); + break; + case stateRelease: + IncrementRelease(); + break; + case stateOff: + default: + // do nothing + break; + } +} + +void ADSREnvelope::InitAttack() +{ + // Attack starts from the current output value, even if not zero. + //wCurOut = wCurOut; + // If starting from a non-zero value, initialize dwCurPos so that it runs the + // last part of the attack not the first. That simplifies the Increment() code + // and gives a nicer logarithmic curve. + word w = wCurOut; + if (fLogarithmic) { + // Log curve + w = LookupAttackValue(w) << 2; + } + dwCurPos.dw = ((uint32_t)w) << 12; + wOutOffset = 0; + state = stateAttack; +} + +void ADSREnvelope::IncrementAttack() +{ + dwCurPos.dw += dwIncrAttack; + if (dwCurPos.b3 != 0) { //if (dwCurPos.dw > dwPosRange) + // finished this phase of the envelope + InitDecay(); + } else { + word w = ((uint32_t)dwCurPos.dw) >> 12; + if (fLogarithmic) { + // Convert to a logarithmic curve + w = InterpolateAttackValue(w); + } + wCurOut = w; // w - wOutOffset but wOutOffset is 0 + } +} + +void ADSREnvelope::InitDecay() +{ + // Decay should always start from the maximum output value (otherwise the decay + // phase wouldn't have started yet). + wCurOut = wOutputRange - 1; // max output value + // Initialize dwCurPos so that it runs the last part of the decay curve not the first. + // That simplifies the Increment() code and gives a nicer logarithmic curve. + word w = wSustain; + if (fLogarithmic) { + // Log curve + w = LookupDecayValue(w) << 2; + } + dwCurPos.dw = ((uint32_t)w) << 12; + wOutOffset = wSustain; + state = stateDecay; +} + +void ADSREnvelope::IncrementDecay() +{ + dwCurPos.dw += dwIncrDecay; + if (dwCurPos.b3 != 0) { //if (dwCurPos.dw > dwPosRange) + // finished this phase of the envelope + if (fLoop) { + // Loop mode: No sustain phase, continue right on to release + InitRelease(); + } else { + // Normal mode: Start sustain phase + InitSustain(); + } + } else { + word w = ((uint32_t)dwCurPos.dw) >> 12; + if (fLogarithmic) { + // Convert to a logarithmic curve + w = InterpolateDecayValue(w); + } + wCurOut = wOutputRange - 1 - w + wOutOffset; + } +} + +void ADSREnvelope::InitSustain() +{ + wCurOut = wSustain; + dwCurPos.dw = 0; + state = stateSustain; +} + +void ADSREnvelope::UpdateSustain() +{ + // Update the current sustain level, in case the knob setting has changed. + wCurOut = wSustain; +} + +void ADSREnvelope::InitRelease() +{ + // Release starts from the current output value, even if it's not the sustain value. + //wCurOut = wCurOut; + // Initialize dwCurPos so that it runs the last part of the decay curve not the first. + // That simplifies the Increment() code and gives a nicer logarithmic curve. + word w = wOutputRange - 1 - wCurOut; + if (fLogarithmic) { + // Log curve + w = LookupDecayValue(w) << 2; + } + dwCurPos.dw = ((uint32_t)w) << 12; + wOutOffset = 0; + state = stateRelease; +} + +void ADSREnvelope::IncrementRelease() +{ + dwCurPos.dw += dwIncrRelease; + if (dwCurPos.b3 != 0) { //if (dwCurPos.dw > dwPosRange) + // finished this phase of the envelope + if (fLoop) { + // Loop mode: Restart the envelope immediately. + wCurOut = 0; + InitAttack(); + } else { + // Normal mode: Just stop enveloping. + StopEnvelope(); + } + } else { + word w = (((uint32_t)dwCurPos.dw) >> 12); + if (fLogarithmic) { + // Convert to a logarithmic curve + w = InterpolateDecayValue(w); + } + wCurOut = wOutputRange - 1 - w; + } +} + +void ADSREnvelope::StopEnvelope() +{ + state = stateOff; + dwCurPos = 0; + wCurOut = 0; +} + +/* + * LookupAttackValue + * Look up wValue in the attack curve table and return the index of the closest (equal or greater) value. + * This is to initialize the attack portion of the envelope when it's not starting from zero. + */ +word ADSREnvelope::LookupAttackValue(word wValue) +{ + if (wValue == 0) { + // must be handled specially + return 0; + } else { + word iLo = 0; + word iHi = cLogAttackMapTable - 1; + if (wValue < PMEMW(LogAttackMapTable + iHi)) { // just in case wValue is out of range + while (iHi - iLo > 1) { + word iNew = (iLo + iHi) >> 1; + word wNew = PMEMW(LogAttackMapTable + iNew); // LogAttackMapTable[iNew] + if (wNew >= wValue) + iHi = iNew; + else + iLo = iNew; + } + } + return iHi; + } +} + +/* + * InterpolateAttackValue + * Convert wValue to a logarithmic value with table lookup and interpolation. + */ +word ADSREnvelope::InterpolateAttackValue(word wValue) +{ + // Log curve - Table lookup with interpolation using the bottom 2 bits of wValue + const word* pw = LogAttackMapTable + (wValue >> 2); + word w0 = PMEMW(pw); // LogAttackMapTable[(wValue >> 2)] + word w1 = PMEMW(pw+1); // LogAttackMapTable[(wValue >> 2)+1] + word wOut = w0; + word wT = (wValue & 1) ? w1 : w0; + wOut = (wOut + wT) >> 1; + wT = (wValue & 2) ? w1 : w0; + wOut = (wOut + wT) >> 1; + return wOut; +} + +/* + * LookupDecayValue + * Look up wValue in the decay/release curve table and return the index of the closest (equal or greater) value. + * This is to initialize the decay & release portions of the envelope starting from any value. + */ +word ADSREnvelope::LookupDecayValue(word wValue) +{ + if (wValue == 0) { + // must be handled specially + return 0; + } else { + word iLo = 0; + word iHi = cLogDecayMapTable - 1; + if (wValue < PMEMW(LogDecayMapTable + iHi)) { // just in case wValue is out of range + while (iHi - iLo > 1) { + word iNew = (iLo + iHi) >> 1; + word wNew = PMEMW(LogDecayMapTable + iNew); // LogDecayMapTable[iNew] + if (wNew >= wValue) + iHi = iNew; + else + iLo = iNew; + } + } + return iHi; + } +} + +/* + * InterpolateDecayValue + * Convert wValue to a logarithmic value with table lookup and interpolation. + */ +word ADSREnvelope::InterpolateDecayValue(word wValue) +{ + // Log curve - Table lookup with interpolation using the bottom 2 bits of wValue + const word* pw = LogDecayMapTable + (wValue >> 2); + word w0 = PMEMW(pw); // LogDecayMapTable[(wValue >> 2)] + word w1 = PMEMW(pw+1); // LogDecayMapTable[(wValue >> 2)+1] + word wOut = w0; + word wT = (wValue & 1) ? w1 : w0; + wOut = (wOut + wT) >> 1; + wT = (wValue & 2) ? w1 : w0; + wOut = (wOut + wT) >> 1; + return wOut; +} + +#ifdef DEBUG_ENV_DUMP +void ADSREnvelope::Dump() +{ + Serial.print("ADSR pins="); Serial.print(pinAttack); Serial.print(' '); Serial.print(pinDecay); Serial.print(' '); Serial.print(pinSustain); Serial.print(' '); Serial.print(pinRelease); + Serial.print(" state="); Serial.println(state); + Serial.print("Log="); Serial.print(fLogarithmic); + Serial.print(" Attack="); Serial.print(dwIncrAttack); + Serial.print(" Decay="); Serial.print(dwIncrDecay); + Serial.print(" Sustain="); Serial.print(wSustain); + Serial.print(" Release="); Serial.println(dwIncrRelease); + Serial.print("CurPos="); Serial.print(dwCurPos.dw); Serial.print(" index="); Serial.println(dwCurPos.dw >> 14); + Serial.print("CurOut="); Serial.print(wCurOut); Serial.print(" Offset="); Serial.println(wOutOffset); + Serial.print("OutputRange="); Serial.print(wOutputRange); Serial.print(" PosRange="); Serial.println(dwPosRange); +} +#endif + +#ifdef DEBUG_ENV_OUTPUT +const byte cchStars = 64; +char szDebug[cchStars+1]; +char achStars[cchStars+1] = "****************************************************************"; + +void ADSREnvelope::DebugOut() +{ + word w = wCurOut; + if (!fDisplayOn) { + if (w > 0) { + fDisplayOn = true; + tStart = millis(); + } + } else { + byte bValue = (w >> 6); + if (bValue > cchStars) { + Serial.print("?? "); Serial.print(w); + } else { + memcpy(szDebug, achStars, bValue); + szDebug[bValue] = 0; + Serial.print(szDebug); + } + Serial.println(); + if (w == 0) { + fDisplayOn = false; +#ifdef DEBUG_ENV_DUMP + Serial.print("time: "); Serial.println(millis() - tStart); + Dump(); +#endif + } + } +} +#endif // DEBUG_ENV_OUTPUT + +ADSREnvelope envelope1(0, 1, 4, 5, pinSwLogLin1, pinGate1); + +ADSREnvelope envelope2(2, 3, 4, 5, pinSwLogLin2, pinGate2); + +// +// SPI Interface to DACs +// + +const SPISettings settings(20000000, MSBFIRST, SPI_MODE0); + +const byte pinCS1 = 10; // SPI chip-select for DAC 1 (output) +const byte pinBitCS1 = 2; +//const byte pinCS2 = 10; // SPI chip-select for DAC 2 (output) +//const byte pinBitCS2 = 2; +// All the CS lines are on the same port, to simplify the code. +#define pinPortCS PORTB + +// MCP482x DAC +const byte pinLDAC = 8; // DAC LDAC signal (output) +#define pinPortLDAC PORTB +const byte pinBitLDAC = 0; +// SPI commands +const byte bitDACAB = 15; // 0 = unit A, 1 = unit B +const byte bDACUnitA = 0; +const byte bDACUnitB = 1; +const byte bitDACGain = 13; // 0 = 2x, 1 = 1x +const byte bitDACShutdown = 12; // active low +const word wDACCmdDefault = ((0 << bitDACGain) | (1 << bitDACShutdown)); + +void initSPI() +{ + // SPI setup + pinMode(pinLDAC, OUTPUT); + digitalWrite(pinLDAC, LOW); + pinMode(pinCS1, OUTPUT); + digitalWrite(pinCS1, HIGH); + //pinMode(pinCS2, OUTPUT); + //digitalWrite(pinCS2, HIGH); + SPI.begin(); + // SPI settings don't change so beginTransaction() is only called once to save time. + SPI.beginTransaction(settings); +} + +void SPISendToDAC(word wNum, byte pinBitCS, byte bDACUnit) +{ + // Send an SPI command word to the MCP4821/4822 DAC + word wSPIData = wDACCmdDefault | ((word)bDACUnit << bitDACAB) | wNum; + //SPI.beginTransaction(settings); // moved to setup() - not necessary to do this every time + clrBit(pinPortCS, pinBitCS); //digitalWrite(pinCS, LOW); + SPI.transfer16(wSPIData); + setBit(pinPortCS, pinBitCS); //digitalWrite(pinCS, HIGH); + //SPI.endTransaction(); // don't do this every time +} + +// +// Timer Interrupt Handler +// + +// Timer interrupt settings +// freqTimer, compareTimer, bitsTimerPrescaler must all be set to match +const word freqTimer = 20000; // 24000; // 25000; // 31250; // timer interrupt frequency +const word compareTimer = 799; // 666; // 639; // 511; // compare value for timer interrupts +const byte bitsTimerPrescaler = 0b001; // /1 timer clock prescaler +const byte maskTimerPrescaler = 0b111; // bit mask for setting the prescaler +// According to the datasheet, frequency = fCLK_IO / (2 * prescale * (1 + compare)) +// BUG: this gives freqTimer = 10000, not 20000 as measured + +void initTimerInterrupt() +{ + // Set Timer1 interrupt frequency. + cli(); + TCCR1A = 0; + TCCR1B = 0; + setBit(TCCR1B, WGM12); // mode = CTC with OCR1A + // The prescaler and compare values must be set to match freqTimer. + setBits(TCCR1B, bitsTimerPrescaler, maskTimerPrescaler); + OCR1A = compareTimer; + setBit(TIMSK1, OCIE1A); // enable timer compare interrupt + TCNT1 = 0; // initialize counter value + sei(); +} + +/* + * Timer1 Interrupt Handler + * This is where the envelopes are calculated and output. + */ +ISR(TIMER1_COMPA_vect) +{ +#ifdef DEBUG_TIME_TEST + counterTimeTest++; +#endif + + // Output the current envelope voltages to the DACs. + // Inhibit the DAC outputs and set them all at once. + setBit(pinPortLDAC, pinBitLDAC); //digitalWrite(pinLDAC, HIGH); + // Send the data to the DAC chips via SPI. + // Note that envelope 1 is output on DAC channel B and envelope 2 is on channel A. + SPISendToDAC(envelope1.CurrentOutput(), pinBitCS1, bDACUnitB); // send to DAC 1 unit B + SPISendToDAC(envelope2.CurrentOutput(), pinBitCS1, bDACUnitA); // send to DAC 1 unit A + //SPISendToDAC(wOut3, pinBitCS2, bDACUnitA); // send to DAC 2 + // Latch the DAC outputs. + clrBit(pinPortLDAC, pinBitLDAC); //digitalWrite(pinLDAC, LOW); + + // Increment the envelope states. + envelope1.Increment(); + envelope2.Increment(); +} + +// +// Gate Interrupt Handlers +// + +void initGateInterrupts() +{ + // Enable external interrupts INT0 & INT1 to be triggered by gate inputs + cli(); + setBits(EICRA, 0b0101, 0b1111); // both interrupts triggered by any change on pin + setBits(EIMSK, 0b11, 0b11); // both interrupts enabled + sei(); +} + +ISR(INT0_vect) +{ + envelope1.HandleGateInterrupt(); +} + + +ISR(INT1_vect) +{ + envelope2.HandleGateInterrupt(); +} + +// +// TaskBlinkLeds - Blink the indicator LEDs +// + +class TaskBlinkLeds : public TimedTask +{ +public: + static const unsigned dtBlinkLEDs = 3; + + TaskBlinkLeds() : TimedTask(dtBlinkLEDs) {} + + void Task(unsigned long tNow) + { + blinkLED(pinLED1, envelope1.CurrentOutput()); + blinkLED(pinLED2, envelope2.CurrentOutput()); + } + + static void blinkLED(byte pin, word wValue) + { + // wValue is a 12-bit DAC output value + byte b = wValue >> 4; + // Light curve mapping to make the LED look nicer. + // LEDMapTable entries are in progmem + const byte* addr = LEDMapTable + b; + b = PMEMB(addr); // LEDMapTable[index]; + analogWrite(pin, b); + } +}; + +TaskBlinkLeds taskBlinkLEDs; + +// +// TaskReadControls - Read the front panel controls +// + +class TaskReadControls : public TimedTask +{ +public: + static const unsigned dtReadControls = 50; + + TaskReadControls() : TimedTask(dtReadControls) {} + + void Task(unsigned long tNow) + { + // Read the front-panel controls for each of the envelopes. + // Note that some ADC pins are shared via a CD4016 switch + // so the appropriate channel must be selected before reading. +#ifdef CHANNEL_SEL_2_PINS // if a second switch control is needed, e.g. for CD4016/4066 + digitalWrite(pinChannelSel2, LOW); +#endif + digitalWrite(pinChannelSel, HIGH); + envelope1.ReadControls(); + digitalWrite(pinChannelSel, LOW); +#ifdef CHANNEL_SEL_2_PINS // if a second switch control is needed, e.g. for CD4016/4066 + digitalWrite(pinChannelSel2, HIGH); +#endif + envelope2.ReadControls(); + } +}; + +TaskReadControls taskReadControls; + +#ifdef DEBUG_WATCHDOG + +// +// TaskWatchdog - Task to keep an eye on processor load +// + +class TaskWatchdog : public TimedTask +{ +public: + static const unsigned dtWatchdog = 10;//250; + static const unsigned dtError = dtWatchdog + 1; + + TaskWatchdog() : TimedTask(dtWatchdog) {} + + void Task(unsigned long tNow) + { + static unsigned long tPrevious = 0; + static bool fErrorsSeen = false; + unsigned long dt = tNow - tPrevious; + // Check if this task is executing on time. Allow 1 millisecond of slop. + if (dt > dtError && tPrevious != 0) { + // This task did not execute at the expected time, implying that the processor is overloaded. + // Increment the error counter; print a message only the first time. +#ifdef DEBUG_ERROR_COUNTER + counterErrors++; +#endif + if (!fErrorsSeen) { + fErrorsSeen = true; + Serial.print("ERROR: Processor overload - dt = "); + Serial.print(dt); Serial.print(" should be "); Serial.println(dtWatchdog); + } + } + tPrevious = tNow; + } +}; + +TaskWatchdog taskWatchdog; + +#endif // DEBUG_WATCHDOG + +#ifdef DEBUG_ERROR_COUNTER + +// +// TaskCheckErrors - Check Errors +// + +class TaskCheckErrors : public TimedTask +{ +public: + static const unsigned dtCheckErrors = 10; + + TaskCheckErrors() : TimedTask(dtCheckErrors) {} + + void Task(unsigned long tNow) + { + if (counterErrors != 0) { + unsigned long counterT = counterErrors; + counterErrors = 0; + Serial.print("*** ERROR "); Serial.print(counterT); Serial.println(" ***"); + } + } +}; + +TaskCheckErrors taskCheckErrors; + +#endif // DEBUG_ERROR_COUNTER + +#ifdef DEBUG_FAKE_GATES + +// +// TaskDebugGates - Fake gate signals for debugging +// + +class TaskDebugGates : public TimedTask +{ +public: + static const unsigned dtDebugGates = 2000; + + TaskDebugGates() : TimedTask(dtDebugGates) {} + + void Task(unsigned long tNow) + { + static bool fGateOn = false; + if (!fGateOn) { + fGateOn = true; + if (!envelope1.IsLooping()) + envelope1.GateStart(); + if (!envelope2.IsLooping()) + envelope2.GateStart(); + } else { + fGateOn = false; + if (!envelope1.IsLooping()) + envelope1.GateStop(); + if (!envelope2.IsLooping()) + envelope2.GateStop(); + } + } +}; + +TaskDebugGates taskDebugGates; + +#endif // DEBUG_FAKE_GATES + +#ifdef DEBUG_ENV_OUTPUT + +// +// TaskDebugOut - Debug Output +// + +class TaskDebugOut : public TimedTask +{ +public: + static const unsigned dtDebugOut = 50;//101; + + TaskDebugOut() : TimedTask(dtDebugOut) {} + + void Task(unsigned long tNow) + { + envelope2.DebugOut(); + } +}; + +TaskDebugOut taskDebugOut; + +#endif // DEBUG_ENV_OUTPUT + +#ifdef DEBUG_TIME_TEST + +// +// TaskDebugTimeTest - Time Test +// + +class TaskDebugTimeTest : public TimedTask +{ +public: + static const unsigned dtDebugTimeTest = 2010; + + TaskDebugTimeTest() : TimedTask(dtDebugTimeTest) {} + + void Task(unsigned long tNow) + { + Serial.print("testing..."); + unsigned long n = 100000; + volatile unsigned long i; + unsigned long tStart = millis(); + counterTimeTest = 0; + for (i = 0; i < n; i++) { + ; + } + unsigned long tStop = millis(); + unsigned long dt = tStop - tStart; + Serial.print("done "); + Serial.print(n); + Serial.print(" iterations in "); + Serial.print(dt); + Serial.print(" milliseconds, "); + unsigned long freqInterrupt = (1000 * counterTimeTest) / dt; + Serial.print(freqInterrupt); + Serial.println(" interrupts/s"); + } +}; + +TaskDebugTimeTest taskDebugTimeTest; + +#endif // DEBUG_TIME_TEST + + +// +// The Usual +// + +void setup() +{ + Serial.begin(115200); + Serial.println("\nEnvelope2 start"); + initIOPins(); + initSPI(); + initTimerInterrupt(); + initGateInterrupts(); + // Loop mode: Start the envelopes looping. + // NOTE: Loop mode is not fully implemented. + if (envelope1.IsLooping()) + envelope1.GateStart(); + if (envelope2.IsLooping()) + envelope2.GateStart(); +} + +void loop() +{ + // Execute timed tasks + // These tasks are lower priority than the interrupt handlers. + unsigned long tNow = millis(); + taskBlinkLEDs.Tick(tNow); + taskReadControls.Tick(tNow); + + // Debugging Tasks +#ifdef DEBUG_FAKE_GATES + taskDebugGates.Tick(tNow); +#endif +#ifdef DEBUG_ENV_OUTPUT + taskDebugOut.Tick(tNow); +#endif +#ifdef DEBUG_ERROR_COUNTER + taskCheckErrors.Tick(tNow); +#endif +#ifdef DEBUG_TIME_TEST + taskDebugTimeTest.Tick(tNow); +#endif +#ifdef DEBUG_WATCHDOG + taskWatchdog.Tick(tNow); +#endif +} diff --git a/modules/Envelope2/firmware/Envelope2/TimedTask.h b/modules/Envelope2/firmware/Envelope2/TimedTask.h index b4ef8d04..7384da0f 100644 --- a/modules/Envelope2/firmware/Envelope2/TimedTask.h +++ b/modules/Envelope2/firmware/Envelope2/TimedTask.h @@ -1,53 +1,53 @@ -/* -Timed Task Arduino Library - -Copyright 2021 Len Popp - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef _Timed_Task_h_ -#define _Timed_Task_h_ - -//#include "Arduino.h" - -// Abstract class for timed tasks. - -class TimedTask -{ -public: - TimedTask(unsigned interval) - : dtInterval(interval), tPrevious(0) { } - - virtual void Task(unsigned long tNow) = 0; - - void Tick(unsigned long tNow) - { - if (tNow - tPrevious >= dtInterval) { - tPrevious = tNow; - Task(tNow); - } - } - -private: - unsigned dtInterval; - unsigned long tPrevious; -}; - -#endif // _Timed_Task_h_ +/* +Timed Task Arduino Library + +Copyright 2021 Len Popp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef _Timed_Task_h_ +#define _Timed_Task_h_ + +//#include "Arduino.h" + +// Abstract class for timed tasks. + +class TimedTask +{ +public: + TimedTask(unsigned interval) + : dtInterval(interval), tPrevious(0) { } + + virtual void Task(unsigned long tNow) = 0; + + void Tick(unsigned long tNow) + { + if (tNow - tPrevious >= dtInterval) { + tPrevious = tNow; + Task(tNow); + } + } + +private: + unsigned dtInterval; + unsigned long tPrevious; +}; + +#endif // _Timed_Task_h_ diff --git a/modules/Envelope2/firmware/Envelope2/numtables.h b/modules/Envelope2/firmware/Envelope2/numtables.h index 8134730c..7934717d 100644 --- a/modules/Envelope2/firmware/Envelope2/numtables.h +++ b/modules/Envelope2/firmware/Envelope2/numtables.h @@ -1,441 +1,441 @@ -#if !defined(PROGMEM) -#define PROGMEM -#endif - -// table=TimeInputMap npoints=1023 nbits=32 type=uint32_t uMax=4294967295 -const uint32_t cTimeInputMapTable = 1023; -const PROGMEM uint32_t TimeInputMapTable[] = { - 16777216, 16777216, 11205690, 7442671, 5561214, 4432381, 3679860, 3142375, - 2739287, 2425797, 2175026, 1969869, 1798922, 1654290, 1530335, 1422921, - 1328947, 1246041, 1172358, 1106442, 1047128, 993473, 944705, 900186, - 859387, 821859, 787226, 755167, 725404, 697701, 671853, 647678, - 625021, 603743, 583723, 564853, 547037, 530189, 514234, 499102, - 484732, 471068, 458059, 445660, 433830, 422530, 411726, 401385, - 391480, 381984, 372871, 364120, 355709, 347620, 339834, 332334, - 325107, 318136, 311409, 304914, 298639, 292573, 286705, 281028, - 275530, 270206, 265045, 260042, 255189, 250479, 245907, 241466, - 237152, 232958, 228881, 224915, 221056, 217300, 213643, 210081, - 206611, 203228, 199931, 196715, 193579, 190518, 187531, 184615, - 181768, 178987, 176270, 173614, 171019, 168481, 166000, 163573, - 161199, 158875, 156601, 154375, 152196, 150061, 147970, 145922, - 143915, 141949, 140021, 138131, 136277, 134460, 132677, 130929, - 129213, 127529, 125877, 124255, 122662, 121099, 119564, 118056, - 116574, 115119, 113689, 112284, 110904, 109547, 108213, 106901, - 105612, 104343, 103096, 101870, 100663, 99476, 98308, 97159, - 96028, 94915, 93819, 92741, 91679, 90634, 89604, 88591, - 87592, 86609, 85641, 84687, 83747, 82821, 81908, 81009, - 80123, 79250, 78389, 77540, 76704, 75879, 75066, 74265, - 73474, 72694, 71926, 71167, 70419, 69681, 68954, 68235, - 67527, 66828, 66138, 65458, 64786, 64123, 63469, 62823, - 62185, 61556, 60935, 60322, 59716, 59118, 58528, 57945, - 57369, 56801, 56239, 55685, 55137, 54596, 54062, 53534, - 53012, 52497, 51988, 51485, 50988, 50497, 50012, 49532, - 49058, 48590, 48127, 47669, 47217, 46770, 46328, 45892, - 45460, 45033, 44611, 44194, 43781, 43373, 42970, 42571, - 42177, 41787, 41401, 41020, 40642, 40269, 39900, 39535, - 39174, 38817, 38464, 38114, 37769, 37427, 37088, 36754, - 36423, 36095, 35771, 35450, 35133, 34819, 34508, 34200, - 33896, 33595, 33297, 33002, 32710, 32421, 32135, 31852, - 31572, 31294, 31020, 30748, 30479, 30213, 29949, 29688, - 29430, 29174, 28921, 28670, 28422, 28176, 27933, 27692, - 27454, 27217, 26983, 26752, 26522, 26295, 26070, 25848, - 25627, 25409, 25192, 24978, 24766, 24556, 24347, 24141, - 23937, 23735, 23534, 23336, 23139, 22945, 22752, 22561, - 22371, 22184, 21998, 21814, 21632, 21451, 21272, 21095, - 20919, 20745, 20573, 20402, 20233, 20065, 19899, 19734, - 19571, 19410, 19249, 19091, 18933, 18778, 18623, 18470, - 18318, 18168, 18019, 17872, 17725, 17580, 17437, 17294, - 17153, 17013, 16875, 16737, 16601, 16466, 16332, 16200, - 16068, 15938, 15809, 15681, 15554, 15428, 15304, 15180, - 15058, 14936, 14816, 14697, 14579, 14461, 14345, 14230, - 14116, 14002, 13890, 13779, 13669, 13559, 13451, 13343, - 13237, 13131, 13026, 12922, 12819, 12717, 12616, 12516, - 12416, 12318, 12220, 12123, 12027, 11931, 11837, 11743, - 11650, 11558, 11466, 11376, 11286, 11197, 11108, 11021, - 10934, 10848, 10762, 10677, 10593, 10510, 10427, 10345, - 10264, 10184, 10104, 10024, 9946, 9868, 9791, 9714, - 9638, 9562, 9488, 9413, 9340, 9267, 9195, 9123, - 9052, 8981, 8911, 8842, 8773, 8704, 8637, 8569, - 8503, 8437, 8371, 8306, 8241, 8177, 8114, 8051, - 7989, 7927, 7865, 7804, 7744, 7684, 7624, 7565, - 7507, 7449, 7391, 7334, 7278, 7221, 7166, 7110, - 7056, 7001, 6947, 6894, 6840, 6788, 6736, 6684, - 6632, 6581, 6531, 6480, 6431, 6381, 6332, 6283, - 6235, 6187, 6140, 6093, 6046, 6000, 5954, 5908, - 5863, 5818, 5773, 5729, 5685, 5642, 5599, 5556, - 5513, 5471, 5429, 5388, 5347, 5306, 5265, 5225, - 5185, 5146, 5107, 5068, 5029, 4991, 4953, 4915, - 4877, 4840, 4803, 4767, 4731, 4695, 4659, 4623, - 4588, 4553, 4519, 4484, 4450, 4416, 4383, 4350, - 4317, 4284, 4251, 4219, 4187, 4155, 4124, 4092, - 4061, 4031, 4000, 3970, 3940, 3910, 3880, 3851, - 3822, 3793, 3764, 3736, 3707, 3679, 3651, 3624, - 3596, 3569, 3542, 3515, 3489, 3463, 3436, 3410, - 3385, 3359, 3334, 3309, 3284, 3259, 3234, 3210, - 3186, 3162, 3138, 3114, 3091, 3067, 3044, 3021, - 2998, 2976, 2953, 2931, 2909, 2887, 2866, 2844, - 2823, 2801, 2780, 2759, 2739, 2718, 2697, 2677, - 2657, 2637, 2617, 2598, 2578, 2559, 2539, 2520, - 2501, 2483, 2464, 2445, 2427, 2409, 2391, 2373, - 2355, 2337, 2320, 2302, 2285, 2268, 2251, 2234, - 2217, 2201, 2184, 2168, 2152, 2135, 2119, 2104, - 2088, 2072, 2057, 2041, 2026, 2011, 1996, 1981, - 1966, 1951, 1937, 1922, 1908, 1893, 1879, 1865, - 1851, 1837, 1824, 1810, 1796, 1783, 1770, 1756, - 1743, 1730, 1717, 1704, 1692, 1679, 1666, 1654, - 1642, 1629, 1617, 1605, 1593, 1581, 1569, 1558, - 1546, 1534, 1523, 1512, 1500, 1489, 1478, 1467, - 1456, 1445, 1434, 1424, 1413, 1402, 1392, 1382, - 1371, 1361, 1351, 1341, 1331, 1321, 1311, 1301, - 1292, 1282, 1272, 1263, 1253, 1244, 1235, 1226, - 1216, 1207, 1198, 1189, 1181, 1172, 1163, 1154, - 1146, 1137, 1129, 1120, 1112, 1104, 1095, 1087, - 1079, 1071, 1063, 1055, 1047, 1040, 1032, 1024, - 1017, 1009, 1001, 994, 987, 979, 972, 965, - 958, 950, 943, 936, 929, 922, 916, 909, - 902, 895, 889, 882, 875, 869, 862, 856, - 850, 843, 837, 831, 825, 819, 812, 806, - 800, 794, 789, 783, 777, 771, 765, 760, - 754, 748, 743, 737, 732, 726, 721, 716, - 710, 705, 700, 695, 689, 684, 679, 674, - 669, 664, 659, 654, 649, 645, 640, 635, - 630, 626, 621, 616, 612, 607, 603, 598, - 594, 589, 585, 581, 576, 572, 568, 564, - 559, 555, 551, 547, 543, 539, 535, 531, - 527, 523, 519, 515, 512, 508, 504, 500, - 497, 493, 489, 486, 482, 478, 475, 471, - 468, 464, 461, 458, 454, 451, 447, 444, - 441, 438, 434, 431, 428, 425, 422, 418, - 415, 412, 409, 406, 403, 400, 397, 394, - 391, 388, 385, 383, 380, 377, 374, 371, - 369, 366, 363, 360, 358, 355, 353, 350, - 347, 345, 342, 340, 337, 335, 332, 330, - 327, 325, 322, 320, 318, 315, 313, 311, - 308, 306, 304, 301, 299, 297, 295, 293, - 290, 288, 286, 284, 282, 280, 278, 276, - 274, 272, 270, 268, 266, 264, 262, 260, - 258, 256, 254, 252, 250, 248, 247, 245, - 243, 241, 239, 238, 236, 234, 232, 231, - 229, 227, 226, 224, 222, 221, 219, 217, - 216, 214, 213, 211, 209, 208, 206, 205, - 203, 202, 200, 199, 197, 196, 194, 193, - 191, 190, 189, 187, 186, 185, 183, 182, - 180, 179, 178, 176, 175, 174, 173, 171, - 170, 169, 167, 166, 165, 164, 163, 161, - 160, 159, 158, 157, 155, 154, 153, 152, - 151, 150, 149, 148, 147, 145, 144, 143, - 142, 141, 140, 139, 138, 137, 136, 135, - 134, 133, 132, 131, 130, 129, 128, 127, - 126, 125, 124, 123, 123, 122, 121, 120, - 119, 118, 117, 116, 115, 115, 114, 113, - 112, 111, 110, 110, 109, 108, 107, 106, - 106, 105, 104, 103, 103, 102, 101, 100, - 100, 99, 98, 97, 97, 96, 95, 94, - 94, 93, 92, 92, 91, 90, 90, 89, - 88, 88, 87, 86, 86, 85, 85, 84, -}; - -// table=LogAttackMap npoints=1024 nbits=16 type=uint16_t uMax=65535 -const uint16_t cLogAttackMapTable = 1024; -const PROGMEM uint16_t LogAttackMapTable[] = { - 0, 10, 20, 31, 41, 51, 61, 71, - 81, 91, 101, 111, 121, 131, 141, 151, - 161, 171, 181, 190, 200, 210, 220, 229, - 239, 249, 258, 268, 278, 287, 297, 306, - 316, 325, 335, 344, 354, 363, 373, 382, - 391, 401, 410, 419, 429, 438, 447, 456, - 466, 475, 484, 493, 502, 511, 520, 529, - 538, 547, 556, 565, 574, 583, 592, 601, - 610, 619, 628, 637, 645, 654, 663, 672, - 680, 689, 698, 706, 715, 724, 732, 741, - 749, 758, 766, 775, 783, 792, 800, 809, - 817, 825, 834, 842, 850, 859, 867, 875, - 884, 892, 900, 908, 916, 925, 933, 941, - 949, 957, 965, 973, 981, 989, 997, 1005, - 1013, 1021, 1029, 1037, 1045, 1053, 1061, 1068, - 1076, 1084, 1092, 1100, 1107, 1115, 1123, 1131, - 1138, 1146, 1154, 1161, 1169, 1176, 1184, 1192, - 1199, 1207, 1214, 1222, 1229, 1237, 1244, 1251, - 1259, 1266, 1274, 1281, 1288, 1296, 1303, 1310, - 1318, 1325, 1332, 1339, 1347, 1354, 1361, 1368, - 1375, 1382, 1389, 1397, 1404, 1411, 1418, 1425, - 1432, 1439, 1446, 1453, 1460, 1467, 1474, 1481, - 1487, 1494, 1501, 1508, 1515, 1522, 1528, 1535, - 1542, 1549, 1556, 1562, 1569, 1576, 1582, 1589, - 1596, 1602, 1609, 1616, 1622, 1629, 1635, 1642, - 1648, 1655, 1661, 1668, 1674, 1681, 1687, 1694, - 1700, 1707, 1713, 1719, 1726, 1732, 1738, 1745, - 1751, 1757, 1764, 1770, 1776, 1782, 1788, 1795, - 1801, 1807, 1813, 1819, 1826, 1832, 1838, 1844, - 1850, 1856, 1862, 1868, 1874, 1880, 1886, 1892, - 1898, 1904, 1910, 1916, 1922, 1928, 1934, 1940, - 1945, 1951, 1957, 1963, 1969, 1975, 1980, 1986, - 1992, 1998, 2003, 2009, 2015, 2020, 2026, 2032, - 2037, 2043, 2049, 2054, 2060, 2066, 2071, 2077, - 2082, 2088, 2093, 2099, 2104, 2110, 2115, 2121, - 2126, 2132, 2137, 2143, 2148, 2153, 2159, 2164, - 2170, 2175, 2180, 2186, 2191, 2196, 2201, 2207, - 2212, 2217, 2222, 2228, 2233, 2238, 2243, 2249, - 2254, 2259, 2264, 2269, 2274, 2279, 2284, 2290, - 2295, 2300, 2305, 2310, 2315, 2320, 2325, 2330, - 2335, 2340, 2345, 2350, 2355, 2360, 2365, 2369, - 2374, 2379, 2384, 2389, 2394, 2399, 2404, 2408, - 2413, 2418, 2423, 2428, 2432, 2437, 2442, 2447, - 2451, 2456, 2461, 2465, 2470, 2475, 2479, 2484, - 2489, 2493, 2498, 2503, 2507, 2512, 2516, 2521, - 2526, 2530, 2535, 2539, 2544, 2548, 2553, 2557, - 2562, 2566, 2571, 2575, 2579, 2584, 2588, 2593, - 2597, 2601, 2606, 2610, 2615, 2619, 2623, 2628, - 2632, 2636, 2641, 2645, 2649, 2653, 2658, 2662, - 2666, 2670, 2675, 2679, 2683, 2687, 2691, 2696, - 2700, 2704, 2708, 2712, 2716, 2720, 2725, 2729, - 2733, 2737, 2741, 2745, 2749, 2753, 2757, 2761, - 2765, 2769, 2773, 2777, 2781, 2785, 2789, 2793, - 2797, 2801, 2805, 2809, 2813, 2817, 2821, 2824, - 2828, 2832, 2836, 2840, 2844, 2848, 2851, 2855, - 2859, 2863, 2867, 2870, 2874, 2878, 2882, 2885, - 2889, 2893, 2897, 2900, 2904, 2908, 2911, 2915, - 2919, 2922, 2926, 2930, 2933, 2937, 2941, 2944, - 2948, 2951, 2955, 2959, 2962, 2966, 2969, 2973, - 2976, 2980, 2984, 2987, 2991, 2994, 2998, 3001, - 3005, 3008, 3011, 3015, 3018, 3022, 3025, 3029, - 3032, 3036, 3039, 3042, 3046, 3049, 3052, 3056, - 3059, 3063, 3066, 3069, 3073, 3076, 3079, 3083, - 3086, 3089, 3092, 3096, 3099, 3102, 3105, 3109, - 3112, 3115, 3118, 3122, 3125, 3128, 3131, 3134, - 3138, 3141, 3144, 3147, 3150, 3153, 3157, 3160, - 3163, 3166, 3169, 3172, 3175, 3178, 3181, 3184, - 3188, 3191, 3194, 3197, 3200, 3203, 3206, 3209, - 3212, 3215, 3218, 3221, 3224, 3227, 3230, 3233, - 3236, 3239, 3242, 3245, 3248, 3250, 3253, 3256, - 3259, 3262, 3265, 3268, 3271, 3274, 3276, 3279, - 3282, 3285, 3288, 3291, 3294, 3296, 3299, 3302, - 3305, 3308, 3310, 3313, 3316, 3319, 3322, 3324, - 3327, 3330, 3333, 3335, 3338, 3341, 3343, 3346, - 3349, 3352, 3354, 3357, 3360, 3362, 3365, 3368, - 3370, 3373, 3376, 3378, 3381, 3384, 3386, 3389, - 3391, 3394, 3397, 3399, 3402, 3404, 3407, 3409, - 3412, 3415, 3417, 3420, 3422, 3425, 3427, 3430, - 3432, 3435, 3437, 3440, 3442, 3445, 3447, 3450, - 3452, 3455, 3457, 3460, 3462, 3465, 3467, 3469, - 3472, 3474, 3477, 3479, 3482, 3484, 3486, 3489, - 3491, 3493, 3496, 3498, 3501, 3503, 3505, 3508, - 3510, 3512, 3515, 3517, 3519, 3522, 3524, 3526, - 3529, 3531, 3533, 3535, 3538, 3540, 3542, 3545, - 3547, 3549, 3551, 3554, 3556, 3558, 3560, 3562, - 3565, 3567, 3569, 3571, 3574, 3576, 3578, 3580, - 3582, 3584, 3587, 3589, 3591, 3593, 3595, 3597, - 3600, 3602, 3604, 3606, 3608, 3610, 3612, 3614, - 3617, 3619, 3621, 3623, 3625, 3627, 3629, 3631, - 3633, 3635, 3637, 3639, 3641, 3643, 3645, 3648, - 3650, 3652, 3654, 3656, 3658, 3660, 3662, 3664, - 3666, 3668, 3670, 3672, 3674, 3676, 3677, 3679, - 3681, 3683, 3685, 3687, 3689, 3691, 3693, 3695, - 3697, 3699, 3701, 3703, 3705, 3706, 3708, 3710, - 3712, 3714, 3716, 3718, 3720, 3722, 3723, 3725, - 3727, 3729, 3731, 3733, 3734, 3736, 3738, 3740, - 3742, 3744, 3745, 3747, 3749, 3751, 3753, 3754, - 3756, 3758, 3760, 3762, 3763, 3765, 3767, 3769, - 3770, 3772, 3774, 3776, 3777, 3779, 3781, 3783, - 3784, 3786, 3788, 3789, 3791, 3793, 3795, 3796, - 3798, 3800, 3801, 3803, 3805, 3806, 3808, 3810, - 3811, 3813, 3815, 3816, 3818, 3820, 3821, 3823, - 3825, 3826, 3828, 3829, 3831, 3833, 3834, 3836, - 3838, 3839, 3841, 3842, 3844, 3846, 3847, 3849, - 3850, 3852, 3853, 3855, 3857, 3858, 3860, 3861, - 3863, 3864, 3866, 3867, 3869, 3870, 3872, 3874, - 3875, 3877, 3878, 3880, 3881, 3883, 3884, 3886, - 3887, 3889, 3890, 3892, 3893, 3895, 3896, 3897, - 3899, 3900, 3902, 3903, 3905, 3906, 3908, 3909, - 3911, 3912, 3913, 3915, 3916, 3918, 3919, 3921, - 3922, 3923, 3925, 3926, 3928, 3929, 3930, 3932, - 3933, 3935, 3936, 3937, 3939, 3940, 3941, 3943, - 3944, 3946, 3947, 3948, 3950, 3951, 3952, 3954, - 3955, 3956, 3958, 3959, 3960, 3962, 3963, 3964, - 3966, 3967, 3968, 3970, 3971, 3972, 3974, 3975, - 3976, 3977, 3979, 3980, 3981, 3983, 3984, 3985, - 3986, 3988, 3989, 3990, 3991, 3993, 3994, 3995, - 3996, 3998, 3999, 4000, 4001, 4003, 4004, 4005, - 4006, 4008, 4009, 4010, 4011, 4012, 4014, 4015, - 4016, 4017, 4018, 4020, 4021, 4022, 4023, 4024, - 4026, 4027, 4028, 4029, 4030, 4031, 4033, 4034, - 4035, 4036, 4037, 4038, 4040, 4041, 4042, 4043, - 4044, 4045, 4046, 4048, 4049, 4050, 4051, 4052, - 4053, 4054, 4055, 4057, 4058, 4059, 4060, 4061, - 4062, 4063, 4064, 4065, 4066, 4068, 4069, 4070, - 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4078, - 4079, 4080, 4081, 4083, 4084, 4085, 4086, 4087, - 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, - 4096, -}; - -// table=LogDecayMap npoints=1024 nbits=16 type=uint16_t uMax=65535 -const uint16_t cLogDecayMapTable = 1024; -const PROGMEM uint16_t LogDecayMapTable[] = { - 0, 27, 54, 81, 108, 134, 161, 187, - 213, 239, 264, 290, 315, 340, 365, 390, - 415, 439, 464, 488, 512, 536, 559, 583, - 606, 629, 652, 675, 698, 721, 743, 765, - 787, 809, 831, 853, 875, 896, 917, 938, - 959, 980, 1001, 1022, 1042, 1062, 1083, 1103, - 1123, 1142, 1162, 1181, 1201, 1220, 1239, 1258, - 1277, 1296, 1314, 1333, 1351, 1370, 1388, 1406, - 1424, 1441, 1459, 1477, 1494, 1511, 1529, 1546, - 1563, 1579, 1596, 1613, 1629, 1646, 1662, 1678, - 1694, 1710, 1726, 1742, 1758, 1773, 1789, 1804, - 1819, 1834, 1849, 1864, 1879, 1894, 1909, 1923, - 1938, 1952, 1966, 1980, 1995, 2008, 2022, 2036, - 2050, 2064, 2077, 2090, 2104, 2117, 2130, 2143, - 2156, 2169, 2182, 2195, 2207, 2220, 2232, 2245, - 2257, 2269, 2282, 2294, 2306, 2318, 2329, 2341, - 2353, 2364, 2376, 2387, 2399, 2410, 2421, 2432, - 2444, 2455, 2465, 2476, 2487, 2498, 2508, 2519, - 2530, 2540, 2550, 2561, 2571, 2581, 2591, 2601, - 2611, 2621, 2631, 2641, 2650, 2660, 2669, 2679, - 2688, 2698, 2707, 2716, 2725, 2735, 2744, 2753, - 2762, 2770, 2779, 2788, 2797, 2805, 2814, 2823, - 2831, 2839, 2848, 2856, 2864, 2873, 2881, 2889, - 2897, 2905, 2913, 2921, 2929, 2936, 2944, 2952, - 2959, 2967, 2974, 2982, 2989, 2997, 3004, 3011, - 3019, 3026, 3033, 3040, 3047, 3054, 3061, 3068, - 3075, 3081, 3088, 3095, 3102, 3108, 3115, 3121, - 3128, 3134, 3141, 3147, 3153, 3160, 3166, 3172, - 3178, 3184, 3190, 3197, 3203, 3208, 3214, 3220, - 3226, 3232, 3238, 3243, 3249, 3255, 3260, 3266, - 3271, 3277, 3282, 3288, 3293, 3299, 3304, 3309, - 3314, 3320, 3325, 3330, 3335, 3340, 3345, 3350, - 3355, 3360, 3365, 3370, 3375, 3380, 3384, 3389, - 3394, 3398, 3403, 3408, 3412, 3417, 3421, 3426, - 3430, 3435, 3439, 3444, 3448, 3452, 3457, 3461, - 3465, 3469, 3474, 3478, 3482, 3486, 3490, 3494, - 3498, 3502, 3506, 3510, 3514, 3518, 3522, 3525, - 3529, 3533, 3537, 3541, 3544, 3548, 3552, 3555, - 3559, 3562, 3566, 3570, 3573, 3577, 3580, 3583, - 3587, 3590, 3594, 3597, 3600, 3604, 3607, 3610, - 3614, 3617, 3620, 3623, 3626, 3629, 3633, 3636, - 3639, 3642, 3645, 3648, 3651, 3654, 3657, 3660, - 3663, 3666, 3668, 3671, 3674, 3677, 3680, 3683, - 3685, 3688, 3691, 3693, 3696, 3699, 3702, 3704, - 3707, 3709, 3712, 3715, 3717, 3720, 3722, 3725, - 3727, 3730, 3732, 3735, 3737, 3739, 3742, 3744, - 3746, 3749, 3751, 3753, 3756, 3758, 3760, 3763, - 3765, 3767, 3769, 3771, 3774, 3776, 3778, 3780, - 3782, 3784, 3786, 3788, 3790, 3793, 3795, 3797, - 3799, 3801, 3803, 3805, 3807, 3808, 3810, 3812, - 3814, 3816, 3818, 3820, 3822, 3824, 3825, 3827, - 3829, 3831, 3833, 3834, 3836, 3838, 3840, 3841, - 3843, 3845, 3846, 3848, 3850, 3851, 3853, 3855, - 3856, 3858, 3860, 3861, 3863, 3864, 3866, 3867, - 3869, 3870, 3872, 3873, 3875, 3876, 3878, 3879, - 3881, 3882, 3884, 3885, 3887, 3888, 3889, 3891, - 3892, 3894, 3895, 3896, 3898, 3899, 3900, 3902, - 3903, 3904, 3906, 3907, 3908, 3909, 3911, 3912, - 3913, 3914, 3916, 3917, 3918, 3919, 3920, 3922, - 3923, 3924, 3925, 3926, 3927, 3929, 3930, 3931, - 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3940, - 3941, 3942, 3943, 3944, 3945, 3946, 3947, 3948, - 3949, 3950, 3951, 3952, 3953, 3954, 3955, 3956, - 3957, 3958, 3959, 3959, 3960, 3961, 3962, 3963, - 3964, 3965, 3966, 3967, 3968, 3968, 3969, 3970, - 3971, 3972, 3973, 3974, 3974, 3975, 3976, 3977, - 3978, 3978, 3979, 3980, 3981, 3982, 3982, 3983, - 3984, 3985, 3986, 3986, 3987, 3988, 3988, 3989, - 3990, 3991, 3991, 3992, 3993, 3994, 3994, 3995, - 3996, 3996, 3997, 3998, 3998, 3999, 4000, 4000, - 4001, 4002, 4002, 4003, 4004, 4004, 4005, 4005, - 4006, 4007, 4007, 4008, 4009, 4009, 4010, 4010, - 4011, 4011, 4012, 4013, 4013, 4014, 4014, 4015, - 4015, 4016, 4017, 4017, 4018, 4018, 4019, 4019, - 4020, 4020, 4021, 4021, 4022, 4022, 4023, 4023, - 4024, 4024, 4025, 4025, 4026, 4026, 4027, 4027, - 4028, 4028, 4029, 4029, 4030, 4030, 4031, 4031, - 4032, 4032, 4032, 4033, 4033, 4034, 4034, 4035, - 4035, 4035, 4036, 4036, 4037, 4037, 4038, 4038, - 4038, 4039, 4039, 4040, 4040, 4040, 4041, 4041, - 4042, 4042, 4042, 4043, 4043, 4043, 4044, 4044, - 4044, 4045, 4045, 4046, 4046, 4046, 4047, 4047, - 4047, 4048, 4048, 4048, 4049, 4049, 4049, 4050, - 4050, 4050, 4051, 4051, 4051, 4052, 4052, 4052, - 4053, 4053, 4053, 4053, 4054, 4054, 4054, 4055, - 4055, 4055, 4056, 4056, 4056, 4056, 4057, 4057, - 4057, 4058, 4058, 4058, 4058, 4059, 4059, 4059, - 4059, 4060, 4060, 4060, 4060, 4061, 4061, 4061, - 4061, 4062, 4062, 4062, 4062, 4063, 4063, 4063, - 4063, 4064, 4064, 4064, 4064, 4065, 4065, 4065, - 4065, 4066, 4066, 4066, 4066, 4066, 4067, 4067, - 4067, 4067, 4067, 4068, 4068, 4068, 4068, 4068, - 4069, 4069, 4069, 4069, 4069, 4070, 4070, 4070, - 4070, 4070, 4071, 4071, 4071, 4071, 4071, 4072, - 4072, 4072, 4072, 4072, 4072, 4073, 4073, 4073, - 4073, 4073, 4074, 4074, 4074, 4074, 4074, 4074, - 4075, 4075, 4075, 4075, 4075, 4075, 4075, 4076, - 4076, 4076, 4076, 4076, 4076, 4077, 4077, 4077, - 4077, 4077, 4077, 4077, 4078, 4078, 4078, 4078, - 4078, 4078, 4078, 4079, 4079, 4079, 4079, 4079, - 4079, 4079, 4079, 4080, 4080, 4080, 4080, 4080, - 4080, 4080, 4080, 4081, 4081, 4081, 4081, 4081, - 4081, 4081, 4081, 4082, 4082, 4082, 4082, 4082, - 4082, 4082, 4082, 4082, 4083, 4083, 4083, 4083, - 4083, 4083, 4083, 4083, 4083, 4084, 4084, 4084, - 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4085, - 4085, 4085, 4085, 4085, 4085, 4085, 4085, 4085, - 4085, 4085, 4086, 4086, 4086, 4086, 4086, 4086, - 4086, 4086, 4086, 4086, 4086, 4087, 4087, 4087, - 4087, 4087, 4087, 4087, 4087, 4087, 4087, 4087, - 4087, 4087, 4088, 4088, 4088, 4088, 4088, 4088, - 4088, 4088, 4088, 4088, 4088, 4088, 4088, 4089, - 4089, 4089, 4089, 4089, 4089, 4089, 4089, 4089, - 4089, 4089, 4089, 4089, 4089, 4089, 4090, 4090, - 4090, 4090, 4090, 4090, 4090, 4090, 4090, 4090, - 4090, 4090, 4090, 4090, 4090, 4090, 4090, 4091, - 4091, 4091, 4091, 4091, 4091, 4091, 4091, 4091, - 4091, 4091, 4091, 4091, 4091, 4091, 4091, 4091, - 4091, 4091, 4092, 4092, 4092, 4092, 4092, 4092, - 4092, 4092, 4092, 4092, 4092, 4092, 4092, 4092, - 4092, 4092, 4092, 4092, 4092, 4092, 4092, 4093, - 4093, 4093, 4093, 4093, 4093, 4093, 4093, 4093, - 4093, 4093, 4093, 4093, 4093, 4093, 4093, 4093, - 4093, 4093, 4093, 4093, 4093, 4093, 4093, 4093, - 4094, 4094, 4094, 4094, 4094, 4094, 4094, 4094, - 4094, 4094, 4094, 4094, 4094, 4094, 4094, 4094, - 4094, 4094, 4094, 4094, 4094, 4094, 4094, 4094, - 4094, 4094, 4094, 4094, 4094, 4094, 4095, 4095, - 4095, -}; - -// table=LEDMap npoints=255 nbits=8 type=uint8_t uMax=255 -const uint8_t cLEDMapTable = 255; -const PROGMEM uint8_t LEDMapTable[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 6, - 6, 6, 6, 6, 6, 6, 6, 7, - 7, 7, 7, 7, 7, 8, 8, 8, - 8, 8, 8, 9, 9, 9, 9, 9, - 10, 10, 10, 10, 10, 11, 11, 11, - 11, 12, 12, 12, 12, 13, 13, 13, - 14, 14, 14, 14, 15, 15, 15, 16, - 16, 17, 17, 17, 18, 18, 18, 19, - 19, 20, 20, 21, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 26, 26, 27, - 27, 28, 28, 29, 30, 30, 31, 32, - 32, 33, 34, 35, 35, 36, 37, 38, - 39, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, - 55, 56, 57, 58, 60, 61, 62, 64, - 65, 66, 68, 69, 71, 72, 74, 76, - 77, 79, 81, 82, 84, 86, 88, 90, - 92, 94, 96, 98, 100, 103, 105, 107, - 109, 112, 114, 117, 119, 122, 125, 127, - 130, 133, 136, 139, 142, 145, 148, 152, - 155, 158, 162, 165, 169, 173, 177, 180, - 184, 188, 193, 197, 201, 206, 210, 215, - 219, 224, 229, 234, 239, 245, 250, 255, -}; +#if !defined(PROGMEM) +#define PROGMEM +#endif + +// table=TimeInputMap npoints=1023 nbits=32 type=uint32_t uMax=4294967295 +const uint32_t cTimeInputMapTable = 1023; +const PROGMEM uint32_t TimeInputMapTable[] = { + 16777216, 16777216, 9755542, 6475931, 4836185, 3852386, 3196559, 2728145, + 2376865, 2103673, 1885144, 1706368, 1557409, 1431385, 1323381, 1229793, + 1147919, 1075691, 1011502, 954082, 902416, 855681, 813207, 774435, + 738905, 706227, 676071, 648158, 622248, 598132, 575632, 554591, + 534873, 516357, 498937, 482519, 467020, 452365, 438488, 425328, + 412832, 400952, 389642, 378865, 368582, 358762, 349374, 340390, + 331786, 323537, 315623, 308025, 300722, 293700, 286942, 280435, + 274163, 268116, 262282, 256649, 251208, 245949, 240863, 235943, + 231180, 226567, 222097, 217764, 213562, 209485, 205528, 201686, + 197954, 194327, 190801, 187372, 184036, 180790, 177630, 174554, + 171556, 168636, 165790, 163015, 160308, 157669, 155093, 152579, + 150124, 147728, 145387, 143100, 140865, 138680, 136545, 134457, + 132414, 130416, 128461, 126548, 124676, 122842, 121047, 119289, + 117566, 115879, 114225, 112605, 111016, 109459, 107932, 106434, + 104965, 103524, 102111, 100723, 99362, 98025, 96714, 95425, + 94161, 92919, 91699, 90500, 89323, 88166, 87029, 85912, + 84814, 83735, 82674, 81630, 80604, 79595, 78603, 77627, + 76667, 75722, 74793, 73878, 72978, 72092, 71221, 70362, + 69518, 68686, 67867, 67060, 66266, 65484, 64714, 63955, + 63207, 62471, 61745, 61031, 60326, 59632, 58948, 58274, + 57609, 56954, 56308, 55672, 55044, 54425, 53815, 53213, + 52620, 52034, 51457, 50888, 50326, 49772, 49226, 48686, + 48154, 47630, 47112, 46601, 46096, 45599, 45107, 44623, + 44144, 43672, 43206, 42745, 42291, 41842, 41400, 40962, + 40531, 40104, 39683, 39267, 38857, 38451, 38051, 37655, + 37265, 36879, 36498, 36121, 35749, 35382, 35019, 34660, + 34305, 33955, 33609, 33267, 32930, 32596, 32266, 31940, + 31617, 31299, 30984, 30673, 30365, 30061, 29761, 29464, + 29170, 28880, 28593, 28309, 28029, 27752, 27477, 27206, + 26938, 26673, 26411, 26152, 25896, 25642, 25392, 25144, + 24899, 24656, 24416, 24179, 23945, 23713, 23483, 23256, + 23032, 22810, 22590, 22372, 22157, 21945, 21734, 21526, + 21320, 21116, 20915, 20715, 20518, 20323, 20129, 19938, + 19749, 19562, 19377, 19193, 19012, 18832, 18655, 18479, + 18305, 18133, 17962, 17794, 17627, 17461, 17298, 17136, + 16976, 16817, 16660, 16505, 16351, 16199, 16048, 15899, + 15752, 15605, 15461, 15317, 15176, 15035, 14896, 14759, + 14623, 14488, 14354, 14222, 14091, 13961, 13833, 13706, + 13580, 13456, 13333, 13210, 13090, 12970, 12851, 12734, + 12618, 12503, 12389, 12276, 12164, 12053, 11944, 11835, + 11728, 11621, 11516, 11411, 11308, 11206, 11104, 11004, + 10904, 10806, 10708, 10611, 10516, 10421, 10327, 10234, + 10142, 10050, 9960, 9871, 9782, 9694, 9607, 9521, + 9435, 9351, 9267, 9184, 9102, 9021, 8940, 8860, + 8781, 8702, 8625, 8548, 8472, 8396, 8321, 8247, + 8174, 8101, 8029, 7957, 7887, 7817, 7747, 7678, + 7610, 7543, 7476, 7410, 7344, 7279, 7215, 7151, + 7087, 7025, 6963, 6901, 6840, 6780, 6720, 6660, + 6602, 6543, 6486, 6429, 6372, 6316, 6260, 6205, + 6150, 6096, 6043, 5990, 5937, 5885, 5833, 5782, + 5731, 5681, 5631, 5582, 5533, 5484, 5436, 5388, + 5341, 5294, 5248, 5202, 5157, 5112, 5067, 5023, + 4979, 4935, 4892, 4849, 4807, 4765, 4723, 4682, + 4641, 4601, 4561, 4521, 4482, 4442, 4404, 4365, + 4327, 4290, 4252, 4215, 4179, 4142, 4106, 4071, + 4035, 4000, 3965, 3931, 3897, 3863, 3829, 3796, + 3763, 3731, 3698, 3666, 3634, 3603, 3572, 3541, + 3510, 3479, 3449, 3419, 3390, 3360, 3331, 3303, + 3274, 3246, 3218, 3190, 3162, 3135, 3108, 3081, + 3054, 3028, 3002, 2976, 2950, 2925, 2899, 2874, + 2849, 2825, 2800, 2776, 2752, 2729, 2705, 2682, + 2659, 2636, 2613, 2590, 2568, 2546, 2524, 2502, + 2481, 2459, 2438, 2417, 2396, 2376, 2355, 2335, + 2315, 2295, 2275, 2256, 2236, 2217, 2198, 2179, + 2160, 2142, 2123, 2105, 2087, 2069, 2051, 2034, + 2016, 1999, 1982, 1965, 1948, 1931, 1914, 1898, + 1882, 1866, 1850, 1834, 1818, 1802, 1787, 1772, + 1756, 1741, 1726, 1712, 1697, 1682, 1668, 1654, + 1639, 1625, 1611, 1598, 1584, 1570, 1557, 1544, + 1530, 1517, 1504, 1491, 1479, 1466, 1453, 1441, + 1429, 1416, 1404, 1392, 1380, 1368, 1357, 1345, + 1334, 1322, 1311, 1300, 1289, 1278, 1267, 1256, + 1245, 1234, 1224, 1213, 1203, 1193, 1183, 1172, + 1162, 1152, 1143, 1133, 1123, 1114, 1104, 1095, + 1085, 1076, 1067, 1058, 1049, 1040, 1031, 1022, + 1013, 1005, 996, 988, 979, 971, 962, 954, + 946, 938, 930, 922, 914, 906, 899, 891, + 883, 876, 868, 861, 854, 846, 839, 832, + 825, 818, 811, 804, 797, 790, 784, 777, + 770, 764, 757, 751, 744, 738, 732, 725, + 719, 713, 707, 701, 695, 689, 683, 677, + 672, 666, 660, 655, 649, 643, 638, 633, + 627, 622, 617, 611, 606, 601, 596, 591, + 586, 581, 576, 571, 566, 561, 556, 552, + 547, 542, 538, 533, 529, 524, 520, 515, + 511, 506, 502, 498, 494, 489, 485, 481, + 477, 473, 469, 465, 461, 457, 453, 449, + 445, 442, 438, 434, 430, 427, 423, 420, + 416, 412, 409, 405, 402, 399, 395, 392, + 389, 385, 382, 379, 375, 372, 369, 366, + 363, 360, 357, 354, 351, 348, 345, 342, + 339, 336, 333, 330, 328, 325, 322, 319, + 317, 314, 311, 308, 306, 303, 301, 298, + 296, 293, 291, 288, 286, 283, 281, 278, + 276, 274, 271, 269, 267, 265, 262, 260, + 258, 256, 253, 251, 249, 247, 245, 243, + 241, 239, 237, 235, 233, 231, 229, 227, + 225, 223, 221, 219, 217, 216, 214, 212, + 210, 208, 207, 205, 203, 201, 200, 198, + 196, 195, 193, 191, 190, 188, 186, 185, + 183, 182, 180, 179, 177, 176, 174, 173, + 171, 170, 168, 167, 165, 164, 163, 161, + 160, 159, 157, 156, 155, 153, 152, 151, + 149, 148, 147, 146, 144, 143, 142, 141, + 139, 138, 137, 136, 135, 134, 133, 131, + 130, 129, 128, 127, 126, 125, 124, 123, + 122, 121, 120, 119, 118, 117, 116, 115, + 114, 113, 112, 111, 110, 109, 108, 107, + 106, 105, 104, 103, 103, 102, 101, 100, + 99, 98, 97, 97, 96, 95, 94, 93, + 93, 92, 91, 90, 89, 89, 88, 87, + 86, 86, 85, 84, 84, 83, 82, 81, + 81, 80, 79, 79, 78, 77, 77, 76, + 75, 75, 74, 74, 73, 72, 72, 71, + 70, 70, 69, 69, 68, 68, 67, 66, + 66, 65, 65, 64, 64, 63, 63, 62, + 61, 61, 60, 60, 59, 59, 58, 58, + 57, 57, 56, 56, 56, 55, 55, 54, + 54, 53, 53, 52, 52, 51, 51, 51, + 50, 50, 49, 49, 48, 48, 48, 47, + 47, 46, 46, 46, 45, 45, 44, 44, + 44, 43, 43, 43, 42, 42, 42, 41, + 41, 40, 40, 40, 39, 39, 39, 38, + 38, 38, 37, 37, 37, 37, 36, 36, + 36, 35, 35, 35, 34, 34, 34, 34, + 33, 33, 33, 32, 32, 32, 32, 31, + 31, 31, 31, 30, 30, 30, 30, 29, + 29, 29, 29, 28, 28, 28, 28, 27, +}; + +// table=LogAttackMap npoints=1024 nbits=16 type=uint16_t uMax=65535 +const uint16_t cLogAttackMapTable = 1024; +const PROGMEM uint16_t LogAttackMapTable[] = { + 0, 10, 20, 31, 41, 51, 61, 71, + 81, 91, 101, 111, 121, 131, 141, 151, + 161, 171, 181, 190, 200, 210, 220, 229, + 239, 249, 258, 268, 278, 287, 297, 306, + 316, 325, 335, 344, 354, 363, 373, 382, + 391, 401, 410, 419, 429, 438, 447, 456, + 466, 475, 484, 493, 502, 511, 520, 529, + 538, 547, 556, 565, 574, 583, 592, 601, + 610, 619, 628, 637, 645, 654, 663, 672, + 680, 689, 698, 706, 715, 724, 732, 741, + 749, 758, 766, 775, 783, 792, 800, 809, + 817, 825, 834, 842, 850, 859, 867, 875, + 884, 892, 900, 908, 916, 925, 933, 941, + 949, 957, 965, 973, 981, 989, 997, 1005, + 1013, 1021, 1029, 1037, 1045, 1053, 1061, 1068, + 1076, 1084, 1092, 1100, 1107, 1115, 1123, 1131, + 1138, 1146, 1154, 1161, 1169, 1176, 1184, 1192, + 1199, 1207, 1214, 1222, 1229, 1237, 1244, 1251, + 1259, 1266, 1274, 1281, 1288, 1296, 1303, 1310, + 1318, 1325, 1332, 1339, 1347, 1354, 1361, 1368, + 1375, 1382, 1389, 1397, 1404, 1411, 1418, 1425, + 1432, 1439, 1446, 1453, 1460, 1467, 1474, 1481, + 1487, 1494, 1501, 1508, 1515, 1522, 1528, 1535, + 1542, 1549, 1556, 1562, 1569, 1576, 1582, 1589, + 1596, 1602, 1609, 1616, 1622, 1629, 1635, 1642, + 1648, 1655, 1661, 1668, 1674, 1681, 1687, 1694, + 1700, 1707, 1713, 1719, 1726, 1732, 1738, 1745, + 1751, 1757, 1764, 1770, 1776, 1782, 1788, 1795, + 1801, 1807, 1813, 1819, 1826, 1832, 1838, 1844, + 1850, 1856, 1862, 1868, 1874, 1880, 1886, 1892, + 1898, 1904, 1910, 1916, 1922, 1928, 1934, 1940, + 1945, 1951, 1957, 1963, 1969, 1975, 1980, 1986, + 1992, 1998, 2003, 2009, 2015, 2020, 2026, 2032, + 2037, 2043, 2049, 2054, 2060, 2066, 2071, 2077, + 2082, 2088, 2093, 2099, 2104, 2110, 2115, 2121, + 2126, 2132, 2137, 2143, 2148, 2153, 2159, 2164, + 2170, 2175, 2180, 2186, 2191, 2196, 2201, 2207, + 2212, 2217, 2222, 2228, 2233, 2238, 2243, 2249, + 2254, 2259, 2264, 2269, 2274, 2279, 2284, 2290, + 2295, 2300, 2305, 2310, 2315, 2320, 2325, 2330, + 2335, 2340, 2345, 2350, 2355, 2360, 2365, 2369, + 2374, 2379, 2384, 2389, 2394, 2399, 2404, 2408, + 2413, 2418, 2423, 2428, 2432, 2437, 2442, 2447, + 2451, 2456, 2461, 2465, 2470, 2475, 2479, 2484, + 2489, 2493, 2498, 2503, 2507, 2512, 2516, 2521, + 2526, 2530, 2535, 2539, 2544, 2548, 2553, 2557, + 2562, 2566, 2571, 2575, 2579, 2584, 2588, 2593, + 2597, 2601, 2606, 2610, 2615, 2619, 2623, 2628, + 2632, 2636, 2641, 2645, 2649, 2653, 2658, 2662, + 2666, 2670, 2675, 2679, 2683, 2687, 2691, 2696, + 2700, 2704, 2708, 2712, 2716, 2720, 2725, 2729, + 2733, 2737, 2741, 2745, 2749, 2753, 2757, 2761, + 2765, 2769, 2773, 2777, 2781, 2785, 2789, 2793, + 2797, 2801, 2805, 2809, 2813, 2817, 2821, 2824, + 2828, 2832, 2836, 2840, 2844, 2848, 2851, 2855, + 2859, 2863, 2867, 2870, 2874, 2878, 2882, 2885, + 2889, 2893, 2897, 2900, 2904, 2908, 2911, 2915, + 2919, 2922, 2926, 2930, 2933, 2937, 2941, 2944, + 2948, 2951, 2955, 2959, 2962, 2966, 2969, 2973, + 2976, 2980, 2984, 2987, 2991, 2994, 2998, 3001, + 3005, 3008, 3011, 3015, 3018, 3022, 3025, 3029, + 3032, 3036, 3039, 3042, 3046, 3049, 3052, 3056, + 3059, 3063, 3066, 3069, 3073, 3076, 3079, 3083, + 3086, 3089, 3092, 3096, 3099, 3102, 3105, 3109, + 3112, 3115, 3118, 3122, 3125, 3128, 3131, 3134, + 3138, 3141, 3144, 3147, 3150, 3153, 3157, 3160, + 3163, 3166, 3169, 3172, 3175, 3178, 3181, 3184, + 3188, 3191, 3194, 3197, 3200, 3203, 3206, 3209, + 3212, 3215, 3218, 3221, 3224, 3227, 3230, 3233, + 3236, 3239, 3242, 3245, 3248, 3250, 3253, 3256, + 3259, 3262, 3265, 3268, 3271, 3274, 3276, 3279, + 3282, 3285, 3288, 3291, 3294, 3296, 3299, 3302, + 3305, 3308, 3310, 3313, 3316, 3319, 3322, 3324, + 3327, 3330, 3333, 3335, 3338, 3341, 3343, 3346, + 3349, 3352, 3354, 3357, 3360, 3362, 3365, 3368, + 3370, 3373, 3376, 3378, 3381, 3384, 3386, 3389, + 3391, 3394, 3397, 3399, 3402, 3404, 3407, 3409, + 3412, 3415, 3417, 3420, 3422, 3425, 3427, 3430, + 3432, 3435, 3437, 3440, 3442, 3445, 3447, 3450, + 3452, 3455, 3457, 3460, 3462, 3465, 3467, 3469, + 3472, 3474, 3477, 3479, 3482, 3484, 3486, 3489, + 3491, 3493, 3496, 3498, 3501, 3503, 3505, 3508, + 3510, 3512, 3515, 3517, 3519, 3522, 3524, 3526, + 3529, 3531, 3533, 3535, 3538, 3540, 3542, 3545, + 3547, 3549, 3551, 3554, 3556, 3558, 3560, 3562, + 3565, 3567, 3569, 3571, 3574, 3576, 3578, 3580, + 3582, 3584, 3587, 3589, 3591, 3593, 3595, 3597, + 3600, 3602, 3604, 3606, 3608, 3610, 3612, 3614, + 3617, 3619, 3621, 3623, 3625, 3627, 3629, 3631, + 3633, 3635, 3637, 3639, 3641, 3643, 3645, 3648, + 3650, 3652, 3654, 3656, 3658, 3660, 3662, 3664, + 3666, 3668, 3670, 3672, 3674, 3676, 3677, 3679, + 3681, 3683, 3685, 3687, 3689, 3691, 3693, 3695, + 3697, 3699, 3701, 3703, 3705, 3706, 3708, 3710, + 3712, 3714, 3716, 3718, 3720, 3722, 3723, 3725, + 3727, 3729, 3731, 3733, 3734, 3736, 3738, 3740, + 3742, 3744, 3745, 3747, 3749, 3751, 3753, 3754, + 3756, 3758, 3760, 3762, 3763, 3765, 3767, 3769, + 3770, 3772, 3774, 3776, 3777, 3779, 3781, 3783, + 3784, 3786, 3788, 3789, 3791, 3793, 3795, 3796, + 3798, 3800, 3801, 3803, 3805, 3806, 3808, 3810, + 3811, 3813, 3815, 3816, 3818, 3820, 3821, 3823, + 3825, 3826, 3828, 3829, 3831, 3833, 3834, 3836, + 3838, 3839, 3841, 3842, 3844, 3846, 3847, 3849, + 3850, 3852, 3853, 3855, 3857, 3858, 3860, 3861, + 3863, 3864, 3866, 3867, 3869, 3870, 3872, 3874, + 3875, 3877, 3878, 3880, 3881, 3883, 3884, 3886, + 3887, 3889, 3890, 3892, 3893, 3895, 3896, 3897, + 3899, 3900, 3902, 3903, 3905, 3906, 3908, 3909, + 3911, 3912, 3913, 3915, 3916, 3918, 3919, 3921, + 3922, 3923, 3925, 3926, 3928, 3929, 3930, 3932, + 3933, 3935, 3936, 3937, 3939, 3940, 3941, 3943, + 3944, 3946, 3947, 3948, 3950, 3951, 3952, 3954, + 3955, 3956, 3958, 3959, 3960, 3962, 3963, 3964, + 3966, 3967, 3968, 3970, 3971, 3972, 3974, 3975, + 3976, 3977, 3979, 3980, 3981, 3983, 3984, 3985, + 3986, 3988, 3989, 3990, 3991, 3993, 3994, 3995, + 3996, 3998, 3999, 4000, 4001, 4003, 4004, 4005, + 4006, 4008, 4009, 4010, 4011, 4012, 4014, 4015, + 4016, 4017, 4018, 4020, 4021, 4022, 4023, 4024, + 4026, 4027, 4028, 4029, 4030, 4031, 4033, 4034, + 4035, 4036, 4037, 4038, 4040, 4041, 4042, 4043, + 4044, 4045, 4046, 4048, 4049, 4050, 4051, 4052, + 4053, 4054, 4055, 4057, 4058, 4059, 4060, 4061, + 4062, 4063, 4064, 4065, 4066, 4068, 4069, 4070, + 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4078, + 4079, 4080, 4081, 4083, 4084, 4085, 4086, 4087, + 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, + 4096, +}; + +// table=LogDecayMap npoints=1024 nbits=16 type=uint16_t uMax=65535 +const uint16_t cLogDecayMapTable = 1024; +const PROGMEM uint16_t LogDecayMapTable[] = { + 0, 27, 54, 81, 108, 134, 161, 187, + 213, 239, 264, 290, 315, 340, 365, 390, + 415, 439, 464, 488, 512, 536, 559, 583, + 606, 629, 652, 675, 698, 721, 743, 765, + 787, 809, 831, 853, 875, 896, 917, 938, + 959, 980, 1001, 1022, 1042, 1062, 1083, 1103, + 1123, 1142, 1162, 1181, 1201, 1220, 1239, 1258, + 1277, 1296, 1314, 1333, 1351, 1370, 1388, 1406, + 1424, 1441, 1459, 1477, 1494, 1511, 1529, 1546, + 1563, 1579, 1596, 1613, 1629, 1646, 1662, 1678, + 1694, 1710, 1726, 1742, 1758, 1773, 1789, 1804, + 1819, 1834, 1849, 1864, 1879, 1894, 1909, 1923, + 1938, 1952, 1966, 1980, 1995, 2008, 2022, 2036, + 2050, 2064, 2077, 2090, 2104, 2117, 2130, 2143, + 2156, 2169, 2182, 2195, 2207, 2220, 2232, 2245, + 2257, 2269, 2282, 2294, 2306, 2318, 2329, 2341, + 2353, 2364, 2376, 2387, 2399, 2410, 2421, 2432, + 2444, 2455, 2465, 2476, 2487, 2498, 2508, 2519, + 2530, 2540, 2550, 2561, 2571, 2581, 2591, 2601, + 2611, 2621, 2631, 2641, 2650, 2660, 2669, 2679, + 2688, 2698, 2707, 2716, 2725, 2735, 2744, 2753, + 2762, 2770, 2779, 2788, 2797, 2805, 2814, 2823, + 2831, 2839, 2848, 2856, 2864, 2873, 2881, 2889, + 2897, 2905, 2913, 2921, 2929, 2936, 2944, 2952, + 2959, 2967, 2974, 2982, 2989, 2997, 3004, 3011, + 3019, 3026, 3033, 3040, 3047, 3054, 3061, 3068, + 3075, 3081, 3088, 3095, 3102, 3108, 3115, 3121, + 3128, 3134, 3141, 3147, 3153, 3160, 3166, 3172, + 3178, 3184, 3190, 3197, 3203, 3208, 3214, 3220, + 3226, 3232, 3238, 3243, 3249, 3255, 3260, 3266, + 3271, 3277, 3282, 3288, 3293, 3299, 3304, 3309, + 3314, 3320, 3325, 3330, 3335, 3340, 3345, 3350, + 3355, 3360, 3365, 3370, 3375, 3380, 3384, 3389, + 3394, 3398, 3403, 3408, 3412, 3417, 3421, 3426, + 3430, 3435, 3439, 3444, 3448, 3452, 3457, 3461, + 3465, 3469, 3474, 3478, 3482, 3486, 3490, 3494, + 3498, 3502, 3506, 3510, 3514, 3518, 3522, 3525, + 3529, 3533, 3537, 3541, 3544, 3548, 3552, 3555, + 3559, 3562, 3566, 3570, 3573, 3577, 3580, 3583, + 3587, 3590, 3594, 3597, 3600, 3604, 3607, 3610, + 3614, 3617, 3620, 3623, 3626, 3629, 3633, 3636, + 3639, 3642, 3645, 3648, 3651, 3654, 3657, 3660, + 3663, 3666, 3668, 3671, 3674, 3677, 3680, 3683, + 3685, 3688, 3691, 3693, 3696, 3699, 3702, 3704, + 3707, 3709, 3712, 3715, 3717, 3720, 3722, 3725, + 3727, 3730, 3732, 3735, 3737, 3739, 3742, 3744, + 3746, 3749, 3751, 3753, 3756, 3758, 3760, 3763, + 3765, 3767, 3769, 3771, 3774, 3776, 3778, 3780, + 3782, 3784, 3786, 3788, 3790, 3793, 3795, 3797, + 3799, 3801, 3803, 3805, 3807, 3808, 3810, 3812, + 3814, 3816, 3818, 3820, 3822, 3824, 3825, 3827, + 3829, 3831, 3833, 3834, 3836, 3838, 3840, 3841, + 3843, 3845, 3846, 3848, 3850, 3851, 3853, 3855, + 3856, 3858, 3860, 3861, 3863, 3864, 3866, 3867, + 3869, 3870, 3872, 3873, 3875, 3876, 3878, 3879, + 3881, 3882, 3884, 3885, 3887, 3888, 3889, 3891, + 3892, 3894, 3895, 3896, 3898, 3899, 3900, 3902, + 3903, 3904, 3906, 3907, 3908, 3909, 3911, 3912, + 3913, 3914, 3916, 3917, 3918, 3919, 3920, 3922, + 3923, 3924, 3925, 3926, 3927, 3929, 3930, 3931, + 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3940, + 3941, 3942, 3943, 3944, 3945, 3946, 3947, 3948, + 3949, 3950, 3951, 3952, 3953, 3954, 3955, 3956, + 3957, 3958, 3959, 3959, 3960, 3961, 3962, 3963, + 3964, 3965, 3966, 3967, 3968, 3968, 3969, 3970, + 3971, 3972, 3973, 3974, 3974, 3975, 3976, 3977, + 3978, 3978, 3979, 3980, 3981, 3982, 3982, 3983, + 3984, 3985, 3986, 3986, 3987, 3988, 3988, 3989, + 3990, 3991, 3991, 3992, 3993, 3994, 3994, 3995, + 3996, 3996, 3997, 3998, 3998, 3999, 4000, 4000, + 4001, 4002, 4002, 4003, 4004, 4004, 4005, 4005, + 4006, 4007, 4007, 4008, 4009, 4009, 4010, 4010, + 4011, 4011, 4012, 4013, 4013, 4014, 4014, 4015, + 4015, 4016, 4017, 4017, 4018, 4018, 4019, 4019, + 4020, 4020, 4021, 4021, 4022, 4022, 4023, 4023, + 4024, 4024, 4025, 4025, 4026, 4026, 4027, 4027, + 4028, 4028, 4029, 4029, 4030, 4030, 4031, 4031, + 4032, 4032, 4032, 4033, 4033, 4034, 4034, 4035, + 4035, 4035, 4036, 4036, 4037, 4037, 4038, 4038, + 4038, 4039, 4039, 4040, 4040, 4040, 4041, 4041, + 4042, 4042, 4042, 4043, 4043, 4043, 4044, 4044, + 4044, 4045, 4045, 4046, 4046, 4046, 4047, 4047, + 4047, 4048, 4048, 4048, 4049, 4049, 4049, 4050, + 4050, 4050, 4051, 4051, 4051, 4052, 4052, 4052, + 4053, 4053, 4053, 4053, 4054, 4054, 4054, 4055, + 4055, 4055, 4056, 4056, 4056, 4056, 4057, 4057, + 4057, 4058, 4058, 4058, 4058, 4059, 4059, 4059, + 4059, 4060, 4060, 4060, 4060, 4061, 4061, 4061, + 4061, 4062, 4062, 4062, 4062, 4063, 4063, 4063, + 4063, 4064, 4064, 4064, 4064, 4065, 4065, 4065, + 4065, 4066, 4066, 4066, 4066, 4066, 4067, 4067, + 4067, 4067, 4067, 4068, 4068, 4068, 4068, 4068, + 4069, 4069, 4069, 4069, 4069, 4070, 4070, 4070, + 4070, 4070, 4071, 4071, 4071, 4071, 4071, 4072, + 4072, 4072, 4072, 4072, 4072, 4073, 4073, 4073, + 4073, 4073, 4074, 4074, 4074, 4074, 4074, 4074, + 4075, 4075, 4075, 4075, 4075, 4075, 4075, 4076, + 4076, 4076, 4076, 4076, 4076, 4077, 4077, 4077, + 4077, 4077, 4077, 4077, 4078, 4078, 4078, 4078, + 4078, 4078, 4078, 4079, 4079, 4079, 4079, 4079, + 4079, 4079, 4079, 4080, 4080, 4080, 4080, 4080, + 4080, 4080, 4080, 4081, 4081, 4081, 4081, 4081, + 4081, 4081, 4081, 4082, 4082, 4082, 4082, 4082, + 4082, 4082, 4082, 4082, 4083, 4083, 4083, 4083, + 4083, 4083, 4083, 4083, 4083, 4084, 4084, 4084, + 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4085, + 4085, 4085, 4085, 4085, 4085, 4085, 4085, 4085, + 4085, 4085, 4086, 4086, 4086, 4086, 4086, 4086, + 4086, 4086, 4086, 4086, 4086, 4087, 4087, 4087, + 4087, 4087, 4087, 4087, 4087, 4087, 4087, 4087, + 4087, 4087, 4088, 4088, 4088, 4088, 4088, 4088, + 4088, 4088, 4088, 4088, 4088, 4088, 4088, 4089, + 4089, 4089, 4089, 4089, 4089, 4089, 4089, 4089, + 4089, 4089, 4089, 4089, 4089, 4089, 4090, 4090, + 4090, 4090, 4090, 4090, 4090, 4090, 4090, 4090, + 4090, 4090, 4090, 4090, 4090, 4090, 4090, 4091, + 4091, 4091, 4091, 4091, 4091, 4091, 4091, 4091, + 4091, 4091, 4091, 4091, 4091, 4091, 4091, 4091, + 4091, 4091, 4092, 4092, 4092, 4092, 4092, 4092, + 4092, 4092, 4092, 4092, 4092, 4092, 4092, 4092, + 4092, 4092, 4092, 4092, 4092, 4092, 4092, 4093, + 4093, 4093, 4093, 4093, 4093, 4093, 4093, 4093, + 4093, 4093, 4093, 4093, 4093, 4093, 4093, 4093, + 4093, 4093, 4093, 4093, 4093, 4093, 4093, 4093, + 4094, 4094, 4094, 4094, 4094, 4094, 4094, 4094, + 4094, 4094, 4094, 4094, 4094, 4094, 4094, 4094, + 4094, 4094, 4094, 4094, 4094, 4094, 4094, 4094, + 4094, 4094, 4094, 4094, 4094, 4094, 4095, 4095, + 4095, +}; + +// table=LEDMap npoints=255 nbits=8 type=uint8_t uMax=255 +const uint8_t cLEDMapTable = 255; +const PROGMEM uint8_t LEDMapTable[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 6, + 6, 6, 6, 6, 6, 6, 6, 7, + 7, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 11, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, + 14, 14, 14, 14, 15, 15, 15, 16, + 16, 17, 17, 17, 18, 18, 18, 19, + 19, 20, 20, 21, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 26, 26, 27, + 27, 28, 28, 29, 30, 30, 31, 32, + 32, 33, 34, 35, 35, 36, 37, 38, + 39, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, + 55, 56, 57, 58, 60, 61, 62, 64, + 65, 66, 68, 69, 71, 72, 74, 76, + 77, 79, 81, 82, 84, 86, 88, 90, + 92, 94, 96, 98, 100, 103, 105, 107, + 109, 112, 114, 117, 119, 122, 125, 127, + 130, 133, 136, 139, 142, 145, 148, 152, + 155, 158, 162, 165, 169, 173, 177, 180, + 184, 188, 193, 197, 201, 206, 210, 215, + 219, 224, 229, 234, 239, 245, 250, 255, +}; diff --git a/modules/Envelope2/firmware/MakeLookupTables/MakeLookupTables.cpp b/modules/Envelope2/firmware/MakeLookupTables/MakeLookupTables.cpp index 33aae80e..9ff9bbf1 100644 --- a/modules/Envelope2/firmware/MakeLookupTables/MakeLookupTables.cpp +++ b/modules/Envelope2/firmware/MakeLookupTables/MakeLookupTables.cpp @@ -31,41 +31,36 @@ static void WriteTable(const char* tableName, unsigned npoints, unsigned nbits, int main(int argc, char* argv[]) { - std::cout << "#if !defined(PROGMEM)" << std::endl << "#define PROGMEM" << std::endl << "#endif" << std::endl << std::endl; + std::cout << "#if !defined(PROGMEM)\n#define PROGMEM\n#endif\n"; WriteTable("TimeInputMap", 1023/*npoints*/, 32, "uint32_t", std::cout, [](unsigned ipoint, unsigned npoints, uint64_t uHalf, uint64_t uMax) -> uint64_t { uint64_t n; + static constexpr uint64_t nMax = (1ull << 24); if (ipoint == 0) { - n = (1 << 24); + n = nMax; } else { - double d = 0.005 * pow(2, 0.01072 * ipoint) - 0.005; + double d = 0.005 * pow(2, 0.0123 * ipoint) - 0.005; d = (4096. * 4096. / 20000.) / d; n = (uint64_t)std::llround(d); - if (n >= (1 << 24)) - n = (1 << 24); + if (n > nMax) + n = nMax; } return n; }); - std::cout << std::endl; - WriteTable("LogAttackMap", 1024/*npoints*/, 16, "uint16_t", std::cout, [](unsigned ipoint, unsigned npoints, uint64_t uHalf, uint64_t uMax) -> uint64_t { double d = (1 - exp(-(int)(ipoint) / 444.7168)) / 0.9; return (uint64_t)std::llround(d * 4096); }); - std::cout << std::endl; - WriteTable("LogDecayMap", 1024/*npoints*/, 16, "uint16_t", std::cout, [](unsigned ipoint, unsigned npoints, uint64_t uHalf, uint64_t uMax) -> uint64_t { double d = (1 - exp(-(int)(ipoint) / 150.0)) / 0.999265; // 0.999035; return (uint64_t)std::llround(d * 4096); }); - std::cout << std::endl; - WriteTable("LEDMap", 255/*npoints*/, 8, "uint8_t", std::cout, [](unsigned ipoint, unsigned npoints, uint64_t uHalf, uint64_t uMax) -> uint64_t { uint64_t n; @@ -90,18 +85,18 @@ static void WriteTable(const char* tableName, unsigned npoints, unsigned nbits, { const uint64_t uMax = (((uint64_t)1) << nbits) - 1; const uint64_t uHalf = ((uint64_t)1) << (nbits - 1); - ostr << "// table=" << tableName << " npoints=" << npoints << " nbits=" << nbits << " type=" << typeName << " uMax=" << uMax << std::endl; - ostr << "const " << typeName << " c" << tableName << "Table = " << npoints << ';' << std::endl; + ostr << "\n// table=" << tableName << " npoints=" << npoints << " nbits=" << nbits << " type=" << typeName << " uMax=" << uMax << '\n'; + ostr << "const " << typeName << " c" << tableName << "Table = " << npoints << ";\n"; ostr << "const PROGMEM " << typeName << " " << tableName << "Table[] = {"; // Iterate npoints+1 times, to get one extra point for interpolation. for (unsigned ipoint = 0; ipoint <= npoints; ipoint++) { if ((ipoint & 7) == 0) - ostr << std::endl << " "; + ostr << "\n "; uint64_t uVal; uVal = func(ipoint, npoints, uHalf, uMax); uVal = std::min(uVal, uMax); ostr << uVal << ", "; } - ostr << std::endl << "};" << std::endl; + ostr << "\n};\n"; } diff --git a/modules/Envelope2/firmware/MakeLookupTables/MakeLookupTables.vcxproj b/modules/Envelope2/firmware/MakeLookupTables/MakeLookupTables.vcxproj index 75ae517a..dbef96d3 100644 --- a/modules/Envelope2/firmware/MakeLookupTables/MakeLookupTables.vcxproj +++ b/modules/Envelope2/firmware/MakeLookupTables/MakeLookupTables.vcxproj @@ -1,174 +1,178 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {37f2eee5-ee40-4e95-a3b2-dae9b37dabaf} - MakeLookupTables - 10.0 - - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - Link - - - false - Link - - - true - Link - - - false - Link - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - $(TargetPath) >$(SolutionDir)\numtables.h - $(SolutionDir)\numtables.h - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - $(TargetPath) >$(SolutionDir)\numtables.h - $(SolutionDir)\numtables.h - true - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - $(TargetPath) >$(SolutionDir)\numtables.h - $(SolutionDir)\numtables.h - true - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - $(TargetPath) >$(SolutionDir)\numtables.h - $(SolutionDir)\numtables.h - true - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {37f2eee5-ee40-4e95-a3b2-dae9b37dabaf} + MakeLookupTables + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + Link + + + false + Link + + + true + Link + + + false + Link + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + $(TargetPath) >$(SolutionDir)\numtables.h + $(SolutionDir)\numtables.h + true + $(TargetPath);%(Inputs) + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + $(TargetPath) >$(SolutionDir)\numtables.h + $(SolutionDir)\numtables.h + true + $(TargetPath);%(Inputs) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + $(TargetPath) >$(SolutionDir)\numtables.h + $(SolutionDir)\numtables.h + true + $(TargetPath);%(Inputs) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + $(TargetPath) >$(SolutionDir)\numtables.h + $(SolutionDir)\numtables.h + true + $(TargetPath);%(Inputs) + + + + + + + + + + + \ No newline at end of file