3 Commits

11 changed files with 4919 additions and 549 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,21 @@
/*
Fontname: Velvet Screen
Copyright: Created with Fony 1.4.7
Glyphs: 52/256
BBX Build Mode: 0
*/
const uint8_t velvetscreen[437] U8G2_FONT_SECTION("velvetscreen") =
"\64\0\2\2\3\3\2\3\4\5\5\0\0\5\0\5\0\0\221\0\0\1\230 \4\200\134%\11\255tT"
"R\271RI(\6\252\334T\31)\7\252\134bJ\12+\7\233\345\322J\0,\5\221T\4-\5\213"
"f\6.\5\211T\2/\6\244\354c\33\60\10\254\354T\64\223\2\61\7\353\354\222\254\6\62\11\254l"
"\66J*\217\0\63\11\254l\66J\32\215\4\64\10\254l\242\34\272\0\65\11\254l\206\336h$\0\66"
"\11\254\354T^\61)\0\67\10\254lF\216u\4\70\11\254\354TL*&\5\71\11\254\354TL;"
")\0:\6\231UR\0A\10\254\354T\34S\6B\11\254lV\34)\216\4C\11\254\354T\324\61"
")\0D\10\254lV\64G\2E\10\254l\206\36z\4F\10\254l\206^\71\3G\11\254\354TN"
"\63)\0H\10\254l\242\34S\6I\6\251T\206\0J\10\254\354k\231\24\0K\11\254l\242J\62"
"\225\1L\7\254lr{\4M\11\255t\362ZI\353\0N\11\255t\362TI\356\0O\10\254\354T"
"\64\223\2P\11\254lV\34)g\0Q\10\254\354T\264b\12R\10\254lV\34\251\31S\11\254\354"
"FF\32\215\4T\7\253dVl\1U\10\254l\242\63)\0V\11\255t\262Ne\312\21W\12\255"
"t\262J*\251.\0X\11\254l\242L*\312\0Y\12\255tr\252\63\312(\2Z\7\253df*"
"\7p\10\255\364V\266\323\2q\7\255\364\216\257\5r\10\253d\242\32*\2t\6\255t\376#w\11"
"\255\364V\245FN\13x\6\233dR\7\0\0\0\4\377\377\0";

BIN
Extra/Fonts/theory.fon Normal file

Binary file not shown.

View File

@ -1,152 +1,194 @@
#include <Wire.h> #include <Wire.h>
#include <RotaryEncoder.h>
#include <FlexiTimer2.h> #include <FlexiTimer2.h>
#include <EEPROM.h> #include <EEPROM.h>
#include <U8g2lib.h> #include <U8g2lib.h>
#include <avr/wdt.h> #include <avr/wdt.h>
#include <NeoHWSerial.h> #include <NeoHWSerial.h>
#include "config.h" #define VERSION "V:1.1.2"
#include "fonts.h"
#define VERSION "V:1.2A2" byte memCode = 'D'; //Change to different letter if you changed the data structure
#define PPQN 24
#define PULSE_LENGTH 120 //1/10ms resolution. 12ms was failing at 1ms resolution at higher bpm. 60000/200/24 = 12.5 the max pulse length at 1ms resolution for 200bpm is 11ms
#define MAXBPM 200 //250 at 24ppqn with 5ms pulse will be 50/50 square wave
#define MINBPM 20
#define SCREEN_ADDRESS 0x3C
// Rev 2+ Config
#define ENC_BTN_PIN 14
#define ENC_D1_PIN 17
#define ENC_D2_PIN 4
#define START_STOP_BTN_PIN 5
#define SHIFT_BTN_PIN 12
#define EXT_INPUT_PIN 2 //needs to be an interrupt pin
#define ANALOGUE_INPUT_1_PIN A7
#define ANALOGUE_INPUT_2_PIN A6
const byte outsPins[6] = { 7, 8, 10, 6, 9, 11 };
const byte clockOutPin = 3;
bool rotateScreen = false;
bool reverseEnc = false;
//
/* Rev 1 Config
#define ENC_BTN_PIN 14
#define ENC_D1_PIN 17
#define ENC_D2_PIN 4
#define START_STOP_BTN_PIN 5
#define SHIFT_BTN_PIN 100
#define EXT_INPUT_PIN 2 //needs to be an interrupt pin
#define ANALOGUE_INPUT_1_PIN A2
#define ANALOGUE_INPUT_2_PIN A1
const byte clockOutPin = 13;
const byte outsPins[6] = {6, 11, 7, 10, 8, 9};
bool rotateScreen = true;
*/
uint8_t memCode = '0'; //Change to different letter if you changed the data structure
uint16_t CV1Calibration = 512; uint16_t CV1Calibration = 512;
uint16_t CV2Calibration = 512; uint16_t CV2Calibration = 512;
bool showDone = false; bool showDone = false;
const int subDivs[] = { -24, -12, -8, -6, -4, -3, -2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 24, 32, 64, 128 }; //positive - divide, negative - multiply, 0 - off const int subDivs[20] = { -24, -12, -8, -6, -4, -3, -2, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 64, 128 }; //positive - divide, negative - multiply, 0 - off
uint8_t bpm = 130; byte bpm = 130;
uint8_t bpmModulationChannel = 200; //0 - CV1, 1 - CV2, 255 - OFF byte bpmModulationChannel = 200; //0 - CV1, 1 - CV2, 255 - OFF
uint8_t bpmModulationRange = 0; byte bpmModulationRange = 0;
enum modes {Clock, Random, Sequencer, Swing, Gate};
struct channel { struct channel {
enum modes mode : 3; //mv: 7. 0 - CLK, 1 - RND, 2 - SEQ, 3 - SWING, 4 - Gate byte mode; //0 - CLK, 1 - RND, 2 - SEQ
uint8_t subDiv : 5; //mv: 31 byte subDiv;
uint8_t random : 4; //mv: 15 byte CV1Target; //0 - Off, 1 - Subdiv, 2 - RND, 3 - SeqPattern
uint8_t seqPattern : 5; byte CV1Range;
uint8_t CV1Target : 3; //0 - Off, 1 - Subdiv, 2 - RND, 3 - SeqPattern byte CV2Target;
uint8_t CV2Target : 3; byte CV2Range;
uint8_t swing : 3; uint8_t offset;
uint8_t offset : 7; //mv: 127 byte random;
uint8_t gate : 7; byte seqPattern;
bool isMute : 1;
}; };
channel channels[7] = { //array of channel settings channel channels[6] = { //array of channel settings
{ 0, 7, 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 7, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 7, 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 7, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 7, 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 7, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 7, 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 7, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 7, 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 7, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 7, 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 7, 0, 0, 0, 0, 0, 0, 0 }
{ 0, 7, 0, 0, 0, 0, 0, 0, 1, 0 }
}; };
struct sequence { bool seqA1[16] = {1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1};
uint32_t sequence; bool seqA2[16] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0};
uint8_t length : 5 ; //don't forget to add 1 where needed, values 0 - 31 bool seqA3[16] = {1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0};
}; bool seqA4[16] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1};
bool seqA5[16] = {0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1};
bool seqA6[16] = {0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0};
bool seqA7[16] = {1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0};
bool seqA8[16] = {1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1};
bool seqB1[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool seqB2[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool seqB3[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool seqB4[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool seqB5[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool seqB6[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool seqB7[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool seqB8[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte currentStep = 0;
byte stepNumSelected = 0;
bool *patternToEdit;
sequence sequences[] { unsigned int channelPulseCount[6];
{0b000000000000000001001000100010001, 15}, unsigned int channelPulsesPerCycle[6];
{0b000000000000000000000100000010000, 11}, byte sixteenthPulseCount = 0;
{0b000000000000000000001001001001001, 6}, int playingModes[6]; // should be renamed to currentSubdivs or something. Updated from channels object on beat and with applied CV modulation
{0b000000000000000001100110011001100, 20}, int playingModesOld[6];
{0b000000000000000001110111011101110, 30},
{0b000000000000000000101010001010100, 31},
{0b000000000000000000111111111011111, 15},
{0b000000000000000001101101110110011, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15},
{0b000000000000000000000000000000000, 15}
};
uint8_t currentStep[7] = {0}; unsigned int pulsePeriod;
int8_t stepNumSelected = 0; bool isPlaying;// = false;
uint8_t patternToEdit;
unsigned int channelPulseCount[7];
unsigned int channelPulsesPerCycle[7];
uint8_t sixteenthPulseCount = 0;
int playingModes[7]; // should be renamed to currentSubdivs or something. Updated from channels object on beat and with applied CV modulation
int playingModesOld[7];
uint16_t pulsePeriod;
bool isPlaying;// = false; // replace with some flags like uint8_t status where 1xxxxxx isPlaying, x1xxxxx isRecording etc
bool isRecording = false; bool isRecording = false;
bool recordToNextStep = false; bool recordToNextStep = false;
bool MIDIClockReceived = false; bool MIDIClockReceived = false;
uint16_t tickCount = 0; unsigned int tickCount = 0;
uint16_t pulseCount = 0; unsigned int pulseCount = 0;
uint8_t masterClockMode = 0; // 0 - internal, 1 - external 24ppqn, 2 - MIDI byte masterClockMode = 0; // 0 - internal, 1 - external 24ppqn, 2 - MIDI
uint8_t extClockPPQN = 0; // 0 - 24, 1 - 4 (1/16) byte extClockPPQN = 0; // 0 - 24, 1 - 4 (1/16)
uint8_t extraChannel = 0; // 0 - off, 1 - pulse out = 7th channel unsigned long lastExtPulseTime = 0;
uint32_t lastExtPulseTime = 0; unsigned long newExtPulseTime = 0;
uint32_t newExtPulseTime = 0;
bool needPulseReset[] = { true, true, true, true, true, true, true }; //to optimise, can be switched to uint8_t bool needPulseReset[6] = { true, true, true, true, true, true };
uint16_t gateLengthTime[] = {0, 0, 0, 0, 0, 0, 0};
uint16_t gateCountDown[7];
bool stepIsOdd = 1;
uint8_t displayTab = 0; byte displayTab = 0;
bool insideTab = false; bool insideTab = false;
uint8_t menuItem = 0; byte menuItem = 0;
bool menuItemSelected = false; bool menuItemSelected = false;
uint8_t lastMenuItem = 3; byte lastMenuItem = 3;
uint8_t displayScreen = 0; //0 - main, 1 - sequencer, 2 - settings byte displayScreen = 0; //0 - main, 1 - sequencer, 2 - settings
int16_t CV1Input = 0;
int16_t CV2Input = 0;
bool playBtnPushed = false; bool playBtnPushed = false;
bool shiftBtnPushed = false; bool shiftBtnPushed = false;
bool encBtnPushed;
int CV1Input = 0;
int CV2Input = 0;
int encPositionOld = 0; int encPositionOld = 0;
uint8_t encDirectionOld = 0; int encDirectionOld = 0;
uint32_t encPressedTime; unsigned long encPressedTime;
uint32_t encReleasedTime; unsigned long encReleasedTime;
uint32_t playPressedTime; unsigned long playPressedTime;
uint32_t playReleasedTime; unsigned long playReleasedTime;
uint32_t shiftPressedTime; unsigned long shiftPressedTime;
uint32_t shiftReleasedTime; unsigned long shiftReleasedTime;
bool encBtnPushed;
int extResetCountdown; int extResetCountdown;
int extTriggerCount; int extTriggerCount;
//uint32_t lastInteractionTime; // used for display timeout //unsigned long lastInteractionTime; // used for display timeout
U8G2_SSD1306_128X64_NONAME_2_HW_I2C u8g2(U8G2_R2, SCL, SDA, U8X8_PIN_NONE); U8G2_SSD1306_128X64_NONAME_2_HW_I2C u8g2(U8G2_R2, SCL, SDA, U8X8_PIN_NONE);
RotaryEncoder encoder(ENC_D1_PIN, ENC_D2_PIN, RotaryEncoder::LatchMode::TWO03);
//Font
const PROGMEM uint8_t velvetscreen[437] U8G2_FONT_SECTION("velvetscreen") =
"\64\0\2\2\3\3\2\3\4\5\5\0\0\5\0\5\0\0\221\0\0\1\230 \4\200\134%\11\255tT"
"R\271RI(\6\252\334T\31)\7\252\134bJ\12+\7\233\345\322J\0,\5\221T\4-\5\213"
"f\6.\5\211T\2/\6\244\354c\33\60\10\254\354T\64\223\2\61\7\353\354\222\254\6\62\11\254l"
"\66J*\217\0\63\11\254l\66J\32\215\4\64\10\254l\242\34\272\0\65\11\254l\206\336h$\0\66"
"\11\254\354T^\61)\0\67\10\254lF\216u\4\70\11\254\354TL*&\5\71\11\254\354TL;"
")\0:\6\231UR\0A\10\254\354T\34S\6B\11\254lV\34)\216\4C\11\254\354T\324\61"
")\0D\10\254lV\64G\2E\10\254l\206\36z\4F\10\254l\206^\71\3G\11\254\354TN"
"\63)\0H\10\254l\242\34S\6I\6\251T\206\0J\10\254\354k\231\24\0K\11\254l\242J\62"
"\225\1L\7\254lr{\4M\11\255t\362ZI\353\0N\11\255t\362TI\356\0O\10\254\354T"
"\64\223\2P\11\254lV\34)g\0Q\10\254\354T\264b\12R\10\254lV\34\251\31S\11\254\354"
"FF\32\215\4T\7\253dVl\1U\10\254l\242\63)\0V\11\255t\262Ne\312\21W\12\255"
"t\262J*\251.\0X\11\254l\242L*\312\0Y\12\255tr\252\63\312(\2Z\7\253df*"
"\7p\10\255\364V\266\323\2q\7\255\364\216\257\5r\10\253d\242\32*\2t\6\255t\376#w\11"
"\255\364V\245FN\13x\6\233dR\7\0\0\0\4\377\377\0";
const PROGMEM uint8_t stkL[569] U8G2_FONT_SECTION("stk-l") =
"\25\0\4\4\4\5\2\1\6\17\27\1\0\27\0\0\0\1\77\0\0\2\34%'\17\37\313\330R#&"
"\32!F\14\211I\310\24!\65\204(MF\21)Cd\304\10\62b\14\215\60Vb\334\20\0/\14"
"\272\336\336d\244\350\263q\343\0\60\37|\377\12\32\25\17\2\35\263\253ChD\30\21bB\14\242S"
"\306lv\350A\10\65H\0\61\24z\337\322\60R\205\314\234\31\61F\310\270\371\177\224\42\3\62\33|"
"\377\216\251$*\10\35\63\66r\206\304\314`c\252\34\301\221\263|\360\300\0\63\34|\377\216)\64*"
"\10\35\63\66r \71\332YIr\226\306\16\221P\203\312\14\0\64 |\377\226\220AC\306\20\31B"
"f\310\240\21\204F\214\32\61j\304(cv\366\200\305\312\371\0\65\32}\17\307\12.\206\316\213Bj"
"\226\214\42JtN\315\235\42\261&\325\31\0\66\33}\17\317\251\64+\206\235\63:/\314,aA\352"
"\234\335\235\42\261&\325\31\0\67\23|\377\302\212\7)\347Crt\70\345\300\221\363\16\0\70 |\377"
"\216)\64*\10\35\263\331!\22D\310\240\62\205\206\10\11B\307lv\210\204\32Tf\0\71\32|\377"
"\216)\64*\10\35\263\263C$\226\250I\71_\14\42\241\6\225\31\0A\26}\17S\271Si(\31"
"\65d\324\210q\366\356\301w\366\273\1B$}\17\203\232%KF\221\30\66b\330\210a#\206\215\30"
"Eb\311&\243H\14;g\317\36\204`\261\4\0D\33}\17C\42\65KF\15\31\66b\330\210q"
"\366\77;\66b\24\211%j\22\1E\21|\377\302\7)\347%\42\214F\316/\37<\60I\7so"
"\302\37$M$}\17\203\310r\346N\245Q\263\202E\12)L\224\60Q\302\310\20#C\214\14\61\23"
"\306L\30s\366\335\0T\15}\17\303\7\251\206\316\377\377\12\0X)~\37\303@\203\307H\14\33B"
"\210\14\21RC\206\241\63h\222(I\203\346\220\15\31E\204\14!\42\303F\20;h\341\0x\24\312"
"\336\302 CGH\240\61E\312\14\222)\6Y\64\0\0\0\0\4\377\377\0";
String version; String version;
@ -162,22 +204,12 @@ void setup() {
pinMode(EXT_INPUT_PIN, INPUT_PULLUP); pinMode(EXT_INPUT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(EXT_INPUT_PIN), externalClock, FALLING); attachInterrupt(digitalPinToInterrupt(EXT_INPUT_PIN), externalClock, FALLING);
for (uint8_t i = 0; i < 6; i++) { for (byte i = 0; i < 6; i++) {
pinMode(outsPins[i], OUTPUT); pinMode(outsPins[i], OUTPUT);
} }
pinMode(clockOutPin, OUTPUT); pinMode(clockOutPin, OUTPUT);
pinMode(ENC_D1_PIN, INPUT_PULLUP);
pinMode(ENC_D2_PIN, INPUT_PULLUP);
//Enabling PinChange Interrupts for the encoder
//pins 17 (PC3/PCINT11) and 4 (PD4/PCINT20), ports C and D
PCICR |= 0b00000110;
PCMSK1 |= 0b00001000;
PCMSK2 |= 0b00010000;
loadState(); loadState();
u8g2.begin(); u8g2.begin();
@ -186,11 +218,10 @@ void setup() {
calculateCycles(); calculateCycles();
calculateBPMTiming(); calculateBPMTiming();
checkEncoderStatus();
resetClocks(); resetClocks();
FlexiTimer2::set(1, 1.0 / 10000, clock); // 1.0/1000 = 1ms period FlexiTimer2::set(1, 1.0 / 10000, clock); // 1.0/1000 = 1ms period. If other than 1ms calculateBPMTiming() might need tweaking
FlexiTimer2::start(); FlexiTimer2::start();
} }
@ -201,62 +232,6 @@ void loop() {
checkInputs(); checkInputs();
} }
//Encoder interrupts
ISR (PCINT1_vect) {
checkEncoderStatus();
}
ISR (PCINT2_vect) {
checkEncoderStatus();
}
uint8_t encoderStatus;
uint32_t encoderCheckTime = 0;
uint32_t encoderTimeBetweenPulses = 0;
bool encoderDirectionOld; //0 = -, 1 = +, Old because current direction can be determined by encoderChange
int8_t encoderChange = 0;
uint8_t encoderBurstCount = 0;
void checkEncoderStatus() {
//bool pin1Status = digitalRead(ENC_D1_PIN);
//bool pin2Status = digitalRead(ENC_D2_PIN);
uint8_t newStatus = (digitalRead(ENC_D1_PIN) << 1) | digitalRead(ENC_D2_PIN);
switch(encoderStatus) { // encoderStatus & 0b00000011 - to check only 2 last bits
case 0b00:
if (newStatus == 0b01) {
encoderChange++;
} else if (newStatus == 0b10) {
encoderChange--;
}
break;
case 0b01:
if (newStatus == 0b11) {
encoderChange++;
} else if (newStatus == 0b00) {
encoderChange--;
}
break;
case 0b11:
if (newStatus == 0b10) {
encoderChange++;
} else if (newStatus == 0b01) {
encoderChange--;
}
break;
case 0b10:
if (newStatus == 0b00) {
encoderChange++;
} else if (newStatus == 0b11) {
encoderChange--;
}
break;
}
encoderStatus = newStatus;
uint32_t currentTime = millis();
encoderTimeBetweenPulses = currentTime - encoderCheckTime;
encoderCheckTime = currentTime;
}
void sendMIDIClock() { void sendMIDIClock() {
NeoSerial.write(0xF8); NeoSerial.write(0xF8);
} }
@ -269,12 +244,17 @@ void sendMIDIStop() {
void receiveMIDI( uint8_t msg, uint8_t status ) { void receiveMIDI( uint8_t msg, uint8_t status ) {
if (masterClockMode == 2) { if (masterClockMode == 2) {
if (msg == 0xF8) { //Clock tick //int msg = NeoSerial.read();
if (msg == 0xF8) { //Clock
MIDIClockReceived = true; MIDIClockReceived = true;
} else if (msg == 0xFC) { //stop } else if (msg == 0xFC) { //stop
isPlaying = false; isPlaying = false;
resetClocks();
sendMIDIStop();
} else if (msg == 0xFA || msg == 0xFB) { //start and continue } else if (msg == 0xFA || msg == 0xFB) { //start and continue
resetClocks();
isPlaying = true; isPlaying = true;
sendMIDIStart();
} }
} }
} }
@ -286,9 +266,7 @@ void clock() {
// Action on each pulse // Action on each pulse
if (tickCount == 0) { if (tickCount == 0) {
sendTriggers(); sendTriggers();
if (!extraChannel) { digitalWrite(clockOutPin, HIGH);
digitalWrite(clockOutPin, HIGH);
}
sendMIDIClock(); sendMIDIClock();
} }
@ -305,11 +283,6 @@ void clock() {
} }
if (bpmModulationRange != 0) { if (bpmModulationRange != 0) {
calculateBPMTiming(); calculateBPMTiming();
for (uint8_t i; i < 7; i++) {
if (channels[i].mode == Gate) {
calculateGate(i);
}
}
} }
} }
} }
@ -320,7 +293,7 @@ void clock() {
} }
} }
if (masterClockMode == 2 && MIDIClockReceived) { if (masterClockMode == 2 && MIDIClockReceived) { // MIDI should happen here (needs testing)
tickCount = 0; //to make things happen in the main clock function tickCount = 0; //to make things happen in the main clock function
if (pulseCount < (PPQN - 1)) { if (pulseCount < (PPQN - 1)) {
pulseCount++; pulseCount++;
@ -331,17 +304,12 @@ void clock() {
} }
// pull low all outputs after set pulse length // pull low all outputs after set pulse length
for (uint8_t i = 0; i < 7; i++) { if (tickCount >= PULSE_LENGTH) {
if (channels[i].mode != Gate && tickCount >= PULSE_LENGTH) { //everything but gate mode for (byte i = 0; i < 6; i++) {
digitalWrite(outsPins[i], LOW); digitalWrite(outsPins[i], LOW);
} else if (channels[i].mode == Gate && tickCount >= gateCountDown[i]) { //gate mode gateLengthTime[i] < pulsePeriod
digitalWrite(outsPins[i], LOW);
gateCountDown[i] = gateLengthTime[i];
} else if (channels[i].mode == Gate && gateCountDown[i] > pulsePeriod && tickCount == 0) {
gateCountDown[i] = gateCountDown[i] - pulsePeriod;
} }
digitalWrite(clockOutPin, LOW);
} }
} }
} }
@ -356,6 +324,7 @@ void externalClock() {
//reset cycles if there were no pulses for a while //reset cycles if there were no pulses for a while
if ((newExtPulseTime - lastExtPulseTime) > 125) { //125ms is 20bpm if ((newExtPulseTime - lastExtPulseTime) > 125) { //125ms is 20bpm
resetClocks(); resetClocks();
} }
@ -394,22 +363,24 @@ void externalClock() {
} }
} }
void sendTriggers() { //rename to onPulse or something void sendTriggers() {
for (uint8_t i = 0; i < (extraChannel ? 7 : 6); i++) { for (byte i = 0; i < 6; i++) {
if (playingModes[i] != subDivs[channels[i].subDiv] && playingModesOld[i] != playingModes[i]) { if (playingModes[i] != subDivs[channels[i].subDiv] && playingModesOld[i] != playingModes[i]) {
needPulseReset[i] = true; needPulseReset[i] = true;
playingModesOld[i] = playingModes[i]; playingModesOld[i] = playingModes[i];
} }
} }
//16th notes for sequencer and swing
//16th notes for sequencer
if (sixteenthPulseCount == 0) { if (sixteenthPulseCount == 0) {
stepIsOdd = !stepIsOdd; bool *currentSeq;
for (uint8_t i = 0; i < (extraChannel ? 7 : 6); i++) {
for (byte i = 0; i < 6; i++) {
//pattern modulation //pattern modulation
int seqMod = 0; int seqMod = 0;
uint8_t seqPattern; byte seqPattern;
if (channels[i].CV2Target == 3) { if (channels[i].CV2Target == 3) {
seqMod = map(CV2Input, -1, 1024, -8, 8); //-1 and 1024 are to try to make the last step not at max value (should make the range from -7 to +7) seqMod = map(CV2Input, -1, 1024, -8, 8); //-1 and 1024 are to try to make the last step not at max value (should make the range from -7 to +7)
} else if (channels[i].CV1Target == 3) { } else if (channels[i].CV1Target == 3) {
@ -427,8 +398,40 @@ void sendTriggers() { //rename to onPulse or something
seqPattern = channels[i].seqPattern + seqMod; seqPattern = channels[i].seqPattern + seqMod;
} }
bool currentStepValue = bitRead(sequences[channels[i].seqPattern].sequence, currentStep[i]); if (seqPattern == 0) {
if (channels[i].mode == Sequencer && currentStepValue && !channels[i].isMute) { currentSeq = seqA1;
} else if (seqPattern == 1) {
currentSeq = seqA2;
} else if (seqPattern == 2) {
currentSeq = seqA3;
} else if (seqPattern == 3) {
currentSeq = seqA4;
} else if (seqPattern == 4) {
currentSeq = seqA5;
} else if (seqPattern == 5) {
currentSeq = seqA6;
} else if (seqPattern == 6) {
currentSeq = seqA7;
} else if (seqPattern == 7) {
currentSeq = seqA8;
} else if (seqPattern == 8) {
currentSeq = seqB1;
} else if (seqPattern == 9) {
currentSeq = seqB2;
} else if (seqPattern== 10) {
currentSeq = seqB3;
} else if (seqPattern == 11) {
currentSeq = seqB4;
} else if (seqPattern == 12) {
currentSeq = seqB5;
} else if (seqPattern == 13) {
currentSeq = seqB6;
} else if (seqPattern == 14) {
currentSeq = seqB7;
} else if (seqPattern == 15) {
currentSeq = seqB8;
}
if (channels[i].mode == 2 && currentSeq[currentStep]) { // EXT CLOCK SEQUENCER BUG IS SOMEWHERE HERE ???? && channelPulseCount[i] == 0 might be related to channelPulsesPerCycle not calculated in time
digitalWrite(outsPins[i], HIGH); digitalWrite(outsPins[i], HIGH);
} }
} }
@ -440,12 +443,10 @@ void sendTriggers() { //rename to onPulse or something
} }
} else { } else {
sixteenthPulseCount = 0; sixteenthPulseCount = 0;
for (uint8_t i; i < 7; i++) { if (currentStep < 15) {
if (channels[i].mode == Sequencer && currentStep[i] < sequences[channels[i].seqPattern].length) { currentStep ++;
currentStep[i] ++; } else {
} else { currentStep = 0;
currentStep[i] = 0;
}
} }
recordToNextStep = false; recordToNextStep = false;
} }
@ -453,22 +454,19 @@ void sendTriggers() { //rename to onPulse or something
//switching modes on the beat and resetting channel clock //switching modes on the beat and resetting channel clock
if (pulseCount == 0) { if (pulseCount == 0) {
calculateCycles(); calculateCycles();
for (uint8_t i = 0; i < (extraChannel ? 7 : 6); i++) { for (byte i = 0; i < 6; i++) {
if (needPulseReset[i] == true) { if (needPulseReset[i] == true) {
channelPulseCount[i] = 0; channelPulseCount[i] = 0;
needPulseReset[i] = false; needPulseReset[i] = false;
} }
if (channels[i].mode == Gate) {
calculateGate(i);
}
} }
} }
//multiplier //multiplier
for (uint8_t i = 0; i < (extraChannel ? 7 : 6); i++) { for (byte i = 0; i < 6; i++) {
//RND modulation //RND modulation
uint8_t randMod = 0; byte randMod = 0;
if (channels[i].CV1Target == 2) { if (channels[i].CV1Target == 2) {
randMod = randMod + CV1Input; randMod = randMod + CV1Input;
} }
@ -478,26 +476,17 @@ void sendTriggers() { //rename to onPulse or something
if (channels[i].CV1Target == 2 || channels[i].CV2Target == 2) { if (channels[i].CV1Target == 2 || channels[i].CV2Target == 2) {
randMod = map(randMod, 0, 1023, -5, +5); randMod = map(randMod, 0, 1023, -5, +5);
} }
uint8_t randAmount = channels[i].random + randMod; byte randAmount = channels[i].random + randMod;
if (randAmount > 100) { if (randAmount > 100) {
randAmount = 0; randAmount = 0;
} else if (randAmount > 10) { } else if (randAmount > 10) {
randAmount = 10; randAmount = 10;
} }
if (!channels[i].isMute) { if ((channels[i].mode == 0 && channelPulseCount[i] == channels[i].offset) //CLK with offset
if ((channels[i].mode == Swing && channelPulseCount[i] == 0 && stepIsOdd == 0) || (channels[i].mode == 1 && channelPulseCount[i] == 0 && (random(10) + 1) > randAmount) //RND
|| (channels[i].mode == Swing && channelPulseCount[i] == channels[i].swing && stepIsOdd == 1) //swing ) {
) { digitalWrite(outsPins[i], HIGH);
digitalWrite(outsPins[i], HIGH);
}
if ((channels[i].mode == Clock && channelPulseCount[i] == channels[i].offset) //CLK with offset
|| (channels[i].mode == Random && channelPulseCount[i] == 0 && (random(10) + 1) > randAmount) //RND
|| (channels[i].mode == Gate && channelPulseCount[i] == 0) //Gate
) {
digitalWrite(outsPins[i], HIGH);
}
} }
if (channelPulseCount[i] < channelPulsesPerCycle[i]) { if (channelPulseCount[i] < channelPulsesPerCycle[i]) {
channelPulseCount[i]++; channelPulseCount[i]++;
@ -505,11 +494,12 @@ void sendTriggers() { //rename to onPulse or something
channelPulseCount[i] = 0; channelPulseCount[i] = 0;
} }
} }
} }
void calculateCycles() { void calculateCycles() {
for (uint8_t i = 0; i < (extraChannel ? 7 : 6); i++) { for (byte i = 0; i < 6; i++) {
int mod = 0; //subdiv modulation happens here int mod = 0; //subdiv modulation happens here
if (channels[i].CV1Target == 1) { if (channels[i].CV1Target == 1) {
mod = map(CV1Input, -1, 1024, -5, 5); mod = map(CV1Input, -1, 1024, -5, 5);
@ -518,24 +508,17 @@ void calculateCycles() {
} }
playingModes[i] = subDivs[channels[i].subDiv - mod]; //subtracting because the innitial array is backwards playingModes[i] = subDivs[channels[i].subDiv - mod]; //subtracting because the innitial array is backwards
if (channels[i].mode == Sequencer || channels[i].mode == Swing) { //Sequencer and swing plays 1/16th if (channels[i].mode == 2) { //Sequencer plays 1/16th
channelPulsesPerCycle[i] = (PPQN / 4) - 1; channelPulsesPerCycle[i] = (PPQN / 4) - 1;
} else if (playingModes[i] > 0) { } else if (playingModes[i] > 0) {
channelPulsesPerCycle[i] = (playingModes[i] * PPQN) - 1; channelPulsesPerCycle[i] = (playingModes[i] * PPQN) - 1;
} else if (playingModes[i] < 0) { } else if (playingModes[i] < 0) {
channelPulsesPerCycle[i] = (PPQN / abs(playingModes[i])) - 1; channelPulsesPerCycle[i] = (PPQN / abs(playingModes[i])) - 1;
} }
} }
} }
void calculateGate(uint8_t channel) {
//if (subDivs[channels[channel].subDiv] > 0) {
gateLengthTime[channel] = ((channelPulsesPerCycle[channel] + 1) * (pulsePeriod + 1) / 100) * channels[channel].gate;
gateCountDown[channel] = gateLengthTime[channel];
//}
}
void calculateBPMTiming() { void calculateBPMTiming() {
int mod = 0; int mod = 0;
if (masterClockMode == 0) { //Internal clock if (masterClockMode == 0) { //Internal clock
@ -544,31 +527,28 @@ void calculateBPMTiming() {
} else if (bpmModulationRange != 0 && bpmModulationChannel == 1) { } else if (bpmModulationRange != 0 && bpmModulationChannel == 1) {
mod = map(CV2Input, 0, 1023, bpmModulationRange * -10, bpmModulationRange * 10); mod = map(CV2Input, 0, 1023, bpmModulationRange * -10, bpmModulationRange * 10);
} }
uint8_t calcbpm = bpm + mod; byte calcbpm = bpm + mod;
if (calcbpm > MAXBPM) { calcbpm = MAXBPM; }; if (calcbpm > MAXBPM) { calcbpm = MAXBPM; };
pulsePeriod = 600000 / (calcbpm * PPQN); // 600000.0 / ((float)(calcbpm * PPQN)) - floats eat up ~2% of program memory, but are they more precise? need to measure pulsePeriod = 600000 / (calcbpm * PPQN);
} else if (masterClockMode == 1 && extClockPPQN == 1) { //for ext 1/16 clock } else if (masterClockMode == 1 && extClockPPQN == 1) { //for ext 1/16 clock (hardcoded)
pulsePeriod = (newExtPulseTime - lastExtPulseTime) * 10 / 6; pulsePeriod = ((newExtPulseTime - lastExtPulseTime) * 10) / 6;
} }
} }
void resetClocks() { void resetClocks() {
for (uint8_t i = 0; i < (extraChannel ? 7 : 6); i++) { for (byte i = 0; i < 6; i++) {
channelPulseCount[i] = 0; channelPulseCount[i] = 0;
digitalWrite(outsPins[i], LOW); //to avoid stuck leds digitalWrite(outsPins[i], LOW); //to avoid stuck leds
} }
pulseCount = 0; pulseCount = 0;
tickCount = 0; tickCount = 0;
sixteenthPulseCount = 0; sixteenthPulseCount = 0;
for (uint8_t i; i < 7; i++) { currentStep = 0;
currentStep[i] = 0;
}
stepIsOdd = 1;
} }
void saveState() { void saveState() {
uint16_t addr = 0; int addr = 0;
EEPROM.put(addr, bpm); EEPROM.put(addr, bpm);
addr = addr + sizeof(bpm); addr = addr + sizeof(bpm);
EEPROM.put(addr, bpmModulationChannel); EEPROM.put(addr, bpmModulationChannel);
@ -579,8 +559,38 @@ void saveState() {
addr = addr + sizeof(masterClockMode); addr = addr + sizeof(masterClockMode);
EEPROM.put(addr, channels); EEPROM.put(addr, channels);
addr = addr + sizeof(channels); addr = addr + sizeof(channels);
EEPROM.put(addr, sequences); EEPROM.put(addr, seqA1);
addr = addr + sizeof(sequences); addr = addr + sizeof(seqA1);
EEPROM.put(addr, seqA2);
addr = addr + sizeof(seqA2);
EEPROM.put(addr, seqA3);
addr = addr + sizeof(seqA3);
EEPROM.put(addr, seqA4);
addr = addr + sizeof(seqA4);
EEPROM.put(addr, seqA5);
addr = addr + sizeof(seqA5);
EEPROM.put(addr, seqA6);
addr = addr + sizeof(seqA6);
EEPROM.put(addr, seqA7);
addr = addr + sizeof(seqA7);
EEPROM.put(addr, seqA8);
addr = addr + sizeof(seqA8);
EEPROM.put(addr, seqB1);
addr = addr + sizeof(seqB1);
EEPROM.put(addr, seqB2);
addr = addr + sizeof(seqB2);
EEPROM.put(addr, seqB3);
addr = addr + sizeof(seqB3);
EEPROM.put(addr, seqB4);
addr = addr + sizeof(seqB4);
EEPROM.put(addr, seqB5);
addr = addr + sizeof(seqB5);
EEPROM.put(addr, seqB6);
addr = addr + sizeof(seqB6);
EEPROM.put(addr, seqB7);
addr = addr + sizeof(seqB7);
EEPROM.put(addr, seqB8);
addr = addr + sizeof(seqB8);
EEPROM.put(addr, CV1Calibration); EEPROM.put(addr, CV1Calibration);
addr = addr + sizeof(CV1Calibration); addr = addr + sizeof(CV1Calibration);
EEPROM.put(addr, CV2Calibration); EEPROM.put(addr, CV2Calibration);
@ -590,14 +600,12 @@ void saveState() {
EEPROM.put(addr, extClockPPQN); EEPROM.put(addr, extClockPPQN);
addr = addr + sizeof(extClockPPQN); addr = addr + sizeof(extClockPPQN);
EEPROM.put(addr, reverseEnc); EEPROM.put(addr, reverseEnc);
addr = addr + sizeof(reverseEnc);
EEPROM.put(addr, extraChannel);
} }
void loadState() { //optimisation: try to make an abstraction that can take an array (of pointers?) of settings to be loaded/saved void loadState() {
//check last bit in eeprom to know if the correct settings were stored //check last bit in eeprom to know if the correct settings were stored
if (EEPROM.read(1023) == memCode) { if (EEPROM.read(1023) == memCode) {
uint16_t addr = 0; int addr = 0;
EEPROM.get(addr, bpm); EEPROM.get(addr, bpm);
addr = addr + sizeof(bpm); addr = addr + sizeof(bpm);
EEPROM.get(addr, bpmModulationChannel); EEPROM.get(addr, bpmModulationChannel);
@ -608,8 +616,38 @@ void loadState() { //optimisation: try to make an abstraction that can take an a
addr = addr + sizeof(masterClockMode); addr = addr + sizeof(masterClockMode);
EEPROM.get(addr, channels); EEPROM.get(addr, channels);
addr = addr + sizeof(channels); addr = addr + sizeof(channels);
EEPROM.get(addr, sequences); EEPROM.get(addr, seqA1);
addr = addr + sizeof(sequences); addr = addr + sizeof(seqA1);
EEPROM.get(addr, seqA2);
addr = addr + sizeof(seqA2);
EEPROM.get(addr, seqA3);
addr = addr + sizeof(seqA3);
EEPROM.get(addr, seqA4);
addr = addr + sizeof(seqA4);
EEPROM.get(addr, seqA5);
addr = addr + sizeof(seqA5);
EEPROM.get(addr, seqA6);
addr = addr + sizeof(seqA6);
EEPROM.get(addr, seqA7);
addr = addr + sizeof(seqA7);
EEPROM.get(addr, seqA8);
addr = addr + sizeof(seqA8);
EEPROM.get(addr, seqB1);
addr = addr + sizeof(seqB1);
EEPROM.get(addr, seqB2);
addr = addr + sizeof(seqB2);
EEPROM.get(addr, seqB3);
addr = addr + sizeof(seqB3);
EEPROM.get(addr, seqB4);
addr = addr + sizeof(seqB4);
EEPROM.get(addr, seqB5);
addr = addr + sizeof(seqB5);
EEPROM.get(addr, seqB6);
addr = addr + sizeof(seqB6);
EEPROM.get(addr, seqB7);
addr = addr + sizeof(seqB7);
EEPROM.get(addr, seqB8);
addr = addr + sizeof(seqB8);
EEPROM.get(addr, CV1Calibration); EEPROM.get(addr, CV1Calibration);
addr = addr + sizeof(CV1Calibration); addr = addr + sizeof(CV1Calibration);
EEPROM.get(addr, CV2Calibration); EEPROM.get(addr, CV2Calibration);
@ -619,8 +657,6 @@ void loadState() { //optimisation: try to make an abstraction that can take an a
EEPROM.get(addr, extClockPPQN); EEPROM.get(addr, extClockPPQN);
addr = addr + sizeof(extClockPPQN); addr = addr + sizeof(extClockPPQN);
EEPROM.get(addr, reverseEnc); EEPROM.get(addr, reverseEnc);
addr = addr + sizeof(reverseEnc);
EEPROM.get(addr, extraChannel);
} else { } else {
saveState(); //write default values to EEPROM saveState(); //write default values to EEPROM
EEPROM.write(1023, memCode); EEPROM.write(1023, memCode);

View File

@ -12,8 +12,40 @@ void checkInputs() {
} else if (encReleasedTime - encPressedTime <= 300) { // press shorter than .3s is for entering the submenu } else if (encReleasedTime - encPressedTime <= 300) { // press shorter than .3s is for entering the submenu
if (!insideTab && displayScreen == 0) { if (!insideTab && displayScreen == 0) {
insideTab = true; insideTab = true;
} else if (insideTab && channels[displayTab - 1].mode == Sequencer && menuItem == 2 && displayScreen == 0) { //enter the pattern editor } else if (insideTab && channels[displayTab - 1].mode == 2 && menuItem == 2 && displayScreen == 0) { //enter the pattern editor
patternToEdit = channels[displayTab - 1].seqPattern; if (channels[displayTab - 1].seqPattern == 0) {
patternToEdit = seqA1;
} else if (channels[displayTab - 1].seqPattern == 1) {
patternToEdit = seqA2;
} else if (channels[displayTab - 1].seqPattern == 2) {
patternToEdit = seqA3;
} else if (channels[displayTab - 1].seqPattern == 3) {
patternToEdit = seqA4;
} else if (channels[displayTab - 1].seqPattern == 4) {
patternToEdit = seqA5;
} else if (channels[displayTab - 1].seqPattern == 5) {
patternToEdit = seqA6;
} else if (channels[displayTab - 1].seqPattern == 6) {
patternToEdit = seqA7;
} else if (channels[displayTab - 1].seqPattern == 7) {
patternToEdit = seqA8;
} else if (channels[displayTab - 1].seqPattern == 8) {
patternToEdit = seqB1;
} else if (channels[displayTab - 1].seqPattern == 9) {
patternToEdit = seqB2;
} else if (channels[displayTab - 1].seqPattern == 10) {
patternToEdit = seqB3;
} else if (channels[displayTab - 1].seqPattern == 11) {
patternToEdit = seqB4;
} else if (channels[displayTab - 1].seqPattern == 12) {
patternToEdit = seqB5;
} else if (channels[displayTab - 1].seqPattern == 13) {
patternToEdit = seqB6;
} else if (channels[displayTab - 1].seqPattern == 14) {
patternToEdit = seqB7;
} else if (channels[displayTab - 1].seqPattern == 15) {
patternToEdit = seqB8;
}
displayScreen = 1; displayScreen = 1;
isRecording = 0; isRecording = 0;
} else if (insideTab && displayScreen == 0) { } else if (insideTab && displayScreen == 0) {
@ -35,9 +67,6 @@ void checkInputs() {
showDone = true; showDone = true;
updateScreen(); updateScreen();
} else if (displayScreen == 2 && menuItem == 3) { } else if (displayScreen == 2 && menuItem == 3) {
extraChannel = !extraChannel;
updateScreen();
} else if (displayScreen == 2 && menuItem == 4) {
EEPROM.put(1023, memCode - 1); EEPROM.put(1023, memCode - 1);
reboot(); reboot();
} }
@ -45,9 +74,7 @@ void checkInputs() {
if (menuItemSelected == 1) { if (menuItemSelected == 1) {
menuItemSelected = 0; menuItemSelected = 0;
} else if (displayScreen != 0) { } else if (displayScreen != 0) {
menuItem = 0;
displayScreen = 0; displayScreen = 0;
menuItemSelected = 0;
} else if (insideTab == 1) { } else if (insideTab == 1) {
insideTab = 0; insideTab = 0;
menuItem = 0; menuItem = 0;
@ -61,40 +88,37 @@ void checkInputs() {
} }
//encoder //encoder
if (encoderChange != 0) { encoder.tick();
if (!reverseEnc) { int encPosition = encoder.getPosition();
encoderChange = encoderChange * -1; int encDirection = (int)(encoder.getDirection());
if (encPositionOld != encPosition) {
int change = encPositionOld - encPosition;
if (reverseEnc) {
change = change * -1;
} }
unsigned long ms = encoder.getMillisBetweenRotations();
/*if (((encoderChange > 0) != encoderDirectionOld) && encoderTimeBetweenPulses < 150) { //filter out encoder "jumps". Comented out /*if (encDirectionOld == encDirection && ms < 20) { //encoder acceleration
encoderChange = 0; //because it seems like sometimes it was preventing normal scroll change = change * 5;
} //if it works ok without it delete encoderDirectionOld var altogether } else if (encDirectionOld == encDirection && ms < 80) {
encoderDirectionOld = (encoderChange > 0);*/ change = change * 2;
} else */ if (encDirectionOld != encDirection && ms < 200) { //filter out encoder "jumps"
//encoder acceleration change = 0;
if (encoderTimeBetweenPulses < 15) { // <--
encoderBurstCount++;
} else {
encoderBurstCount = 0;
} }
if (encoderBurstCount > 3) { // <-- encDirectionOld = encDirection;
encoderChange = encoderChange * 3; // <-- The three params need to be finetuned to feel natural
}
if (displayScreen == 0) { if (displayScreen == 0) {
uint8_t channelCV; byte channelCV;
if (!insideTab && !shiftBtnPushed) { //Change tab if (!insideTab && !shiftBtnPushed) { //Change tab
displayTab = displayTab + encoderChange; displayTab = displayTab + change;
if (displayTab > 100) { //to address "negative" numbers if (displayTab > 100) { //to address "negative" numbers
displayTab = 0; displayTab = 0;
} else if (displayTab > (extraChannel ? 7 : 6)) { } else if (displayTab > 6) {
displayTab = (extraChannel ? 7 : 6); displayTab = 6;
} }
} else if (((!insideTab && shiftBtnPushed) } else if (((!insideTab && shiftBtnPushed)
|| (insideTab && menuItem == 0 || (insideTab && menuItem == 0
&& (menuItemSelected || shiftBtnPushed))) && (menuItemSelected || shiftBtnPushed)))
&& displayTab == 0 && masterClockMode == 0) { //Change BPM && displayTab == 0 && masterClockMode == 0) { //Change BPM
bpm = bpm + encoderChange; bpm = bpm + change;
if (bpm > MAXBPM) { if (bpm > MAXBPM) {
bpm = MAXBPM; bpm = MAXBPM;
} else if (bpm < MINBPM) { } else if (bpm < MINBPM) {
@ -106,13 +130,13 @@ void checkInputs() {
|| (insideTab && menuItem == 0 || (insideTab && menuItem == 0
&& (menuItemSelected || shiftBtnPushed))) && (menuItemSelected || shiftBtnPushed)))
&& displayTab != 0 && displayTab != 0
&& channels[displayTab - 1].mode == Clock) { && channels[displayTab - 1].mode == 0) {
channels[displayTab - 1].subDiv = channels[displayTab - 1].subDiv - encoderChange; channels[displayTab - 1].subDiv = channels[displayTab - 1].subDiv - change;
//channels[displayTab - 1].offset = 0; //channels[displayTab - 1].offset = 0;
if (channels[displayTab - 1].subDiv > 100) { if (channels[displayTab - 1].subDiv > 100) {
channels[displayTab - 1].subDiv = 0; channels[displayTab - 1].subDiv = 0;
} if (channels[displayTab - 1].subDiv > (sizeof(subDivs) / sizeof(subDivs[0])) - 1) { } if (channels[displayTab - 1].subDiv > (sizeof(subDivs) / sizeof(int)) - 1) {
channels[displayTab - 1].subDiv = (sizeof(subDivs) / sizeof(subDivs[0])) - 1; channels[displayTab - 1].subDiv = (sizeof(subDivs) / sizeof(int)) - 1;
} }
if (!isPlaying) { if (!isPlaying) {
calculateCycles(); calculateCycles();
@ -131,8 +155,8 @@ void checkInputs() {
|| (insideTab && menuItem == 0 || (insideTab && menuItem == 0
&& (menuItemSelected || shiftBtnPushed))) && (menuItemSelected || shiftBtnPushed)))
&& displayTab != 0 && displayTab != 0
&& channels[displayTab - 1].mode == Random) { //Change Random && channels[displayTab - 1].mode == 1) { //Change Random
channels[displayTab - 1].random = channels[displayTab - 1].random + encoderChange; channels[displayTab - 1].random = channels[displayTab - 1].random + change;
if (channels[displayTab - 1].random > 100) { if (channels[displayTab - 1].random > 100) {
channels[displayTab - 1].random = 0; channels[displayTab - 1].random = 0;
} else if (channels[displayTab - 1].random > 9) { } else if (channels[displayTab - 1].random > 9) {
@ -143,42 +167,16 @@ void checkInputs() {
|| (insideTab && menuItem == 0 || (insideTab && menuItem == 0
&& (menuItemSelected || shiftBtnPushed))) && (menuItemSelected || shiftBtnPushed)))
&& displayTab != 0 && displayTab != 0
&& channels[displayTab - 1].mode == Sequencer) { //Change SEQ pattern && channels[displayTab - 1].mode == 2) { //Change SEQ pattern
if (channels[displayTab - 1].seqPattern == 0 && encoderChange == -1) { channels[displayTab - 1].seqPattern = channels[displayTab - 1].seqPattern + change;
if (channels[displayTab - 1].seqPattern > 100) {
channels[displayTab - 1].seqPattern = 0; channels[displayTab - 1].seqPattern = 0;
} else if (channels[displayTab - 1].seqPattern == 31 && encoderChange == 1) { } else if (channels[displayTab - 1].seqPattern > 15) {
channels[displayTab - 1].seqPattern = 31; channels[displayTab - 1].seqPattern = 15;
} else {
channels[displayTab - 1].seqPattern = channels[displayTab - 1].seqPattern + encoderChange;
} }
saveState(); saveState();
} else if (((!insideTab && shiftBtnPushed)
|| (insideTab && menuItem == 0
&& (menuItemSelected || shiftBtnPushed)))
&& displayTab != 0
&& channels[displayTab - 1].mode == Swing) { //Change SWING
channels[displayTab - 1].swing = channels[displayTab - 1].swing + encoderChange;
if (channels[displayTab - 1].swing > 6) {
channels[displayTab - 1].swing = 0;
} else if (channels[displayTab - 1].swing > 5) {
channels[displayTab - 1].swing = 5;
}
saveState();
} else if (((!insideTab && shiftBtnPushed)
|| (insideTab && menuItem == 0
&& (menuItemSelected || shiftBtnPushed)))
&& displayTab != 0
&& channels[displayTab - 1].mode == Gate) { //Change GATE
channels[displayTab - 1].gate = channels[displayTab - 1].gate + encoderChange;
if (channels[displayTab - 1].gate > 100 || channels[displayTab - 1].gate == 0) {
channels[displayTab - 1].gate = 1;
} else if (channels[displayTab - 1].gate > 99) {
channels[displayTab - 1].gate = 99;
}
calculateGate(displayTab - 1);
saveState();
} else if (insideTab && !shiftBtnPushed && !menuItemSelected) { } else if (insideTab && !shiftBtnPushed && !menuItemSelected) {
menuItem = menuItem + encoderChange; menuItem = menuItem + change;
if (menuItem > 100) { //for "negative" values if (menuItem > 100) { //for "negative" values
menuItem = 0; menuItem = 0;
} else if (menuItem > lastMenuItem) { } else if (menuItem > lastMenuItem) {
@ -188,14 +186,14 @@ void checkInputs() {
&& (shiftBtnPushed || menuItemSelected) && (shiftBtnPushed || menuItemSelected)
&& displayTab == 0 && displayTab == 0
&& menuItem == 1) { //Master Clock Mode && menuItem == 1) { //Master Clock Mode
if (masterClockMode == 1) { // && encoderChange == -1) { //Stop when switching from ext to int or to midi if (masterClockMode == 1) { // && change == -1) { //Stop when switching from ext to int or to midi
isPlaying = false; isPlaying = false;
} }
masterClockMode = masterClockMode + encoderChange; masterClockMode = masterClockMode + change;
if (masterClockMode > 100) { if (masterClockMode > 100) {
masterClockMode = 0; masterClockMode = 0;
} else if (masterClockMode > 2) { } else if (masterClockMode > 2) { //Set to 1 to hide MIDI mode
masterClockMode = 2; masterClockMode = 2;
} }
saveState(); saveState();
@ -204,7 +202,7 @@ void checkInputs() {
&& displayTab == 0 && displayTab == 0
&& menuItem == 2 && menuItem == 2
&& masterClockMode == 0) { //Modulation channel && masterClockMode == 0) { //Modulation channel
bpmModulationChannel = bpmModulationChannel + encoderChange; bpmModulationChannel = bpmModulationChannel + change;
if (bpmModulationChannel == 0 || bpmModulationChannel == 1) { if (bpmModulationChannel == 0 || bpmModulationChannel == 1) {
bpmModulationRange = 1; bpmModulationRange = 1;
} else if (bpmModulationChannel > 100) { } else if (bpmModulationChannel > 100) {
@ -219,7 +217,7 @@ void checkInputs() {
&& displayTab == 0 && displayTab == 0
&& menuItem == 2 && menuItem == 2
&& masterClockMode == 1) { //PPQN && masterClockMode == 1) { //PPQN
extClockPPQN = extClockPPQN + encoderChange; extClockPPQN = extClockPPQN + change;
if (extClockPPQN > 100) { if (extClockPPQN > 100) {
extClockPPQN = 0; extClockPPQN = 0;
} else if (extClockPPQN > 1) { } else if (extClockPPQN > 1) {
@ -230,7 +228,7 @@ void checkInputs() {
&& (menuItemSelected || shiftBtnPushed) && (menuItemSelected || shiftBtnPushed)
&& displayTab == 0 && displayTab == 0
&& menuItem == 3) { //Modulation range && menuItem == 3) { //Modulation range
bpmModulationRange = bpmModulationRange + encoderChange; bpmModulationRange = bpmModulationRange + change;
if (bpmModulationRange == 0) { if (bpmModulationRange == 0) {
bpmModulationRange = 1; bpmModulationRange = 1;
} else if (bpmModulationRange > 100) { } else if (bpmModulationRange > 100) {
@ -243,11 +241,11 @@ void checkInputs() {
&& (menuItemSelected || shiftBtnPushed) && (menuItemSelected || shiftBtnPushed)
&& displayTab != 0 && displayTab != 0
&& menuItem == 1) { //Channel Mode && menuItem == 1) { //Channel Mode
channels[displayTab - 1].mode = channels[displayTab - 1].mode + encoderChange; channels[displayTab - 1].mode = channels[displayTab - 1].mode + change;
if (channels[displayTab - 1].mode == 7) { if (channels[displayTab - 1].mode > 100) {
channels[displayTab - 1].mode = 4; //to make it cycle through all the modes
} else if (channels[displayTab - 1].mode > 4) {
channels[displayTab - 1].mode = 0; channels[displayTab - 1].mode = 0;
} else if (channels[displayTab - 1].mode > 2) {
channels[displayTab - 1].mode = 2;
} }
channels[displayTab - 1].CV1Target = 0; channels[displayTab - 1].CV1Target = 0;
channels[displayTab - 1].CV2Target = 0; channels[displayTab - 1].CV2Target = 0;
@ -255,8 +253,8 @@ void checkInputs() {
} else if (insideTab } else if (insideTab
&& (menuItemSelected || shiftBtnPushed) && (menuItemSelected || shiftBtnPushed)
&& displayTab != 0 && menuItem == 2 && displayTab != 0 && menuItem == 2
&& channels[displayTab - 1].mode == Clock) { //Offset && channels[displayTab - 1].mode == 0) { //Offset
channels[displayTab - 1].offset = channels[displayTab - 1].offset + encoderChange; channels[displayTab - 1].offset = channels[displayTab - 1].offset + change;
if (channels[displayTab - 1].offset == 255) { // 0 - 1 for uint8 is 255 if (channels[displayTab - 1].offset == 255) { // 0 - 1 for uint8 is 255
channels[displayTab - 1].offset = 0; channels[displayTab - 1].offset = 0;
} else if (channels[displayTab - 1].offset > channelPulsesPerCycle[displayTab-1]) { } else if (channels[displayTab - 1].offset > channelPulsesPerCycle[displayTab-1]) {
@ -267,12 +265,12 @@ void checkInputs() {
&& (menuItemSelected || shiftBtnPushed) && (menuItemSelected || shiftBtnPushed)
&& displayTab != 0 && displayTab != 0
&& menuItem == 2 && menuItem == 2
&& (channels[displayTab - 1].mode == Random || channels[displayTab - 1].mode == Gate)) { //SUBDIV for RANDOM and GATE && channels[displayTab - 1].mode == 1) { //SUBDIV for RANDOM
channels[displayTab - 1].subDiv = channels[displayTab - 1].subDiv - encoderChange; channels[displayTab - 1].subDiv = channels[displayTab - 1].subDiv - change;
if (channels[displayTab - 1].subDiv > 200) { if (channels[displayTab - 1].subDiv > 200) {
channels[displayTab - 1].subDiv = 0; channels[displayTab - 1].subDiv = 0;
} else if (channels[displayTab - 1].subDiv > (sizeof(subDivs) / sizeof(subDivs[0])) - 1) { } else if (channels[displayTab - 1].subDiv > (sizeof(subDivs) / sizeof(int)) - 1) {
channels[displayTab - 1].subDiv = (sizeof(subDivs) / sizeof(subDivs[0])) - 1; channels[displayTab - 1].subDiv = (sizeof(subDivs) / sizeof(int)) - 1;
} }
if (!isPlaying) { if (!isPlaying) {
calculateCycles(); calculateCycles();
@ -282,7 +280,7 @@ void checkInputs() {
&& (menuItemSelected || shiftBtnPushed) && (menuItemSelected || shiftBtnPushed)
&& displayTab != 0 && displayTab != 0
&& menuItem == 3 && menuItem == 3
&& channels[displayTab - 1].mode == Clock) { //CV for CLK && channels[displayTab - 1].mode == 0) { //CV for CLK
if (channels[displayTab - 1].CV1Target == 1 && channels[displayTab - 1].CV2Target == 0) { if (channels[displayTab - 1].CV1Target == 1 && channels[displayTab - 1].CV2Target == 0) {
channelCV = 1; channelCV = 1;
} else if (channels[displayTab - 1].CV1Target == 0 && channels[displayTab - 1].CV2Target == 1) { } else if (channels[displayTab - 1].CV1Target == 0 && channels[displayTab - 1].CV2Target == 1) {
@ -290,7 +288,7 @@ void checkInputs() {
} else { } else {
channelCV = 0; channelCV = 0;
} }
channelCV = channelCV + encoderChange; channelCV = channelCV + change;
if (channelCV == 0 || channelCV > 100) { if (channelCV == 0 || channelCV > 100) {
channelCV = 0; channelCV = 0;
channels[displayTab - 1].CV1Target = 0; channels[displayTab - 1].CV1Target = 0;
@ -304,7 +302,7 @@ void checkInputs() {
channels[displayTab - 1].CV2Target = 1; channels[displayTab - 1].CV2Target = 1;
} }
saveState(); saveState();
} else if (insideTab && (menuItemSelected || shiftBtnPushed) && displayTab != 0 && menuItem == 3 && channels[displayTab - 1].mode == Random) { //CV for RND } else if (insideTab && (menuItemSelected || shiftBtnPushed) && displayTab != 0 && menuItem == 3 && channels[displayTab - 1].mode == 1) { //CV for RND
if (channels[displayTab - 1].CV1Target == 2 && channels[displayTab - 1].CV2Target == 0) { if (channels[displayTab - 1].CV1Target == 2 && channels[displayTab - 1].CV2Target == 0) {
channelCV = 1; channelCV = 1;
} else if (channels[displayTab - 1].CV1Target == 0 && channels[displayTab - 1].CV2Target == 2) { } else if (channels[displayTab - 1].CV1Target == 0 && channels[displayTab - 1].CV2Target == 2) {
@ -312,7 +310,7 @@ void checkInputs() {
} else { } else {
channelCV = 0; channelCV = 0;
} }
channelCV = channelCV + encoderChange; channelCV = channelCV + change;
if (channelCV == 0 || channelCV > 100) { if (channelCV == 0 || channelCV > 100) {
channelCV = 0; channelCV = 0;
channels[displayTab - 1].CV1Target = 0; channels[displayTab - 1].CV1Target = 0;
@ -326,7 +324,7 @@ void checkInputs() {
channels[displayTab - 1].CV2Target = 2; channels[displayTab - 1].CV2Target = 2;
} }
saveState(); saveState();
} else if (insideTab && (menuItemSelected || shiftBtnPushed) && displayTab != 0 && menuItem == 3 && channels[displayTab - 1].mode == Sequencer) { //CV1 for SEQ } else if (insideTab && (menuItemSelected || shiftBtnPushed) && displayTab != 0 && menuItem == 3 && channels[displayTab - 1].mode == 2) { //CV1 for SEQ
if (channels[displayTab - 1].CV1Target == 3 && channels[displayTab - 1].CV2Target == 0) { if (channels[displayTab - 1].CV1Target == 3 && channels[displayTab - 1].CV2Target == 0) {
channelCV = 1; channelCV = 1;
} else if (channels[displayTab - 1].CV1Target == 0 && channels[displayTab - 1].CV2Target == 3) { } else if (channels[displayTab - 1].CV1Target == 0 && channels[displayTab - 1].CV2Target == 3) {
@ -334,7 +332,7 @@ void checkInputs() {
} else { } else {
channelCV = 0; channelCV = 0;
} }
channelCV = channelCV + encoderChange; channelCV = channelCV + change;
if (channelCV == 0 || channelCV > 100) { if (channelCV == 0 || channelCV > 100) {
channelCV = 0; channelCV = 0;
channels[displayTab - 1].CV1Target = 0; channels[displayTab - 1].CV1Target = 0;
@ -349,20 +347,15 @@ void checkInputs() {
} }
saveState(); saveState();
} }
} else if (displayScreen == 1 && !isRecording && !shiftBtnPushed) { } else if (displayScreen == 1 && !isRecording) {
stepNumSelected = stepNumSelected + encoderChange; stepNumSelected = stepNumSelected + change;
if (stepNumSelected < -1 ) { if (stepNumSelected > 100) {
stepNumSelected = -1; stepNumSelected = 15;
} else if (stepNumSelected > sequences[channels[displayTab - 1].seqPattern].length && !shiftBtnPushed) { } else if (stepNumSelected > 15) {
stepNumSelected = 0; stepNumSelected = 0;
} }
} else if (displayScreen == 1 && !isRecording && stepNumSelected == -1 && shiftBtnPushed) {
if ((sequences[channels[displayTab - 1].seqPattern].length != 31 && encoderChange > 0) ||
(sequences[channels[displayTab - 1].seqPattern].length != 0 && encoderChange < 0)) {
sequences[channels[displayTab - 1].seqPattern].length += encoderChange;
}
} else if (displayScreen == 2 && !shiftBtnPushed) { } else if (displayScreen == 2 && !shiftBtnPushed) {
menuItem = menuItem + encoderChange; menuItem = menuItem + change;
if (menuItem > 100) { //for "negative" values if (menuItem > 100) { //for "negative" values
menuItem = 0; menuItem = 0;
} else if (menuItem > lastMenuItem) { } else if (menuItem > lastMenuItem) {
@ -371,11 +364,11 @@ void checkInputs() {
} }
updateScreen(); updateScreen();
encoderChange = 0; encPositionOld = encPosition;
} }
//play button //play button
if (!digitalRead(START_STOP_BTN_PIN) && !playBtnPushed && !shiftBtnPushed) { if (!digitalRead(START_STOP_BTN_PIN) && !playBtnPushed) {
if (masterClockMode == 0) { if (masterClockMode == 0) {
calculateBPMTiming(); calculateBPMTiming();
if (!isPlaying) { if (!isPlaying) {
@ -394,15 +387,6 @@ void checkInputs() {
playBtnPushed = false; playBtnPushed = false;
} }
//shift + play = mute channel
if (!digitalRead(START_STOP_BTN_PIN) && !playBtnPushed && shiftBtnPushed) {
channels[displayTab - 1].isMute = !channels[displayTab - 1].isMute;
playBtnPushed = true;
updateScreen(); //to wake up the screen if turned off
} else if (digitalRead(START_STOP_BTN_PIN) && playBtnPushed) {
playBtnPushed = false;
}
//shift button //shift button
if (!digitalRead(SHIFT_BTN_PIN) && !shiftBtnPushed) { if (!digitalRead(SHIFT_BTN_PIN) && !shiftBtnPushed) {
shiftBtnPushed = true; shiftBtnPushed = true;
@ -410,22 +394,24 @@ void checkInputs() {
if (isRecording) { //Live triggering if (isRecording) { //Live triggering
digitalWrite(outsPins[displayTab - 1], HIGH); digitalWrite(outsPins[displayTab - 1], HIGH);
} }
if (displayScreen == 1 && !isRecording && stepNumSelected <= sequences[patternToEdit].length && stepNumSelected != -1) { if (displayScreen == 1 && !isRecording) {
sequences[patternToEdit].sequence = bitFlip(sequences[patternToEdit].sequence, stepNumSelected); patternToEdit[stepNumSelected] = !patternToEdit[stepNumSelected];
} else if (displayScreen == 1 && isRecording && !recordToNextStep) { //Recording } else if (displayScreen == 1 && isRecording && !recordToNextStep) { //Recording
bitSet(sequences[patternToEdit].sequence, currentStep[displayTab - 1]); patternToEdit[currentStep] = 1;
} else if (displayScreen == 1 && isRecording && recordToNextStep && currentStep != 15) { } else if (displayScreen == 1 && isRecording && recordToNextStep && currentStep != 15) {
bitSet(sequences[patternToEdit].sequence, currentStep[displayTab - 1] + 1); patternToEdit[currentStep+1] = 1;
} else if (displayScreen == 1 && isRecording && recordToNextStep && currentStep == 15) { } else if (displayScreen == 1 && isRecording && recordToNextStep && currentStep == 15) {
bitSet(sequences[patternToEdit].sequence, 0); patternToEdit[0] = 1;
} }
saveState(); saveState();
updateScreen(); updateScreen();
} else if (digitalRead(SHIFT_BTN_PIN) && shiftBtnPushed) { } else if (digitalRead(SHIFT_BTN_PIN) && shiftBtnPushed) {
shiftBtnPushed = false; shiftBtnPushed = false;
shiftReleasedTime = millis(); shiftReleasedTime = millis();
if (displayScreen == 1 && shiftReleasedTime - shiftPressedTime > 1000 && !encBtnPushed && stepNumSelected != -1) { //&& shiftReleasedTime - shiftPressedTime < 2000 //Clear the sequence if (displayScreen == 1 && shiftReleasedTime - shiftPressedTime > 500 && !encBtnPushed) { //&& shiftReleasedTime - shiftPressedTime < 2000 //Clear the sequence
sequences[patternToEdit].sequence = 0b000000000000000000000000000000000; for (byte i = 0; i < 16; i++) {
patternToEdit[i] = 0;
}
} else if (shiftReleasedTime - shiftPressedTime > 2000 && encBtnPushed) { } else if (shiftReleasedTime - shiftPressedTime > 2000 && encBtnPushed) {
displayScreen = 2; displayScreen = 2;
menuItemSelected = 1; //hack to prevent from going back when the encoder is released menuItemSelected = 1; //hack to prevent from going back when the encoder is released

View File

@ -2,8 +2,8 @@ void updateScreen() {
u8g2.firstPage(); u8g2.firstPage();
do { do {
uint8_t leftOffset; byte leftOffset;
uint8_t width; byte width;
String valueStr; String valueStr;
u8g2.setDrawColor(1); u8g2.setDrawColor(1);
@ -11,7 +11,7 @@ void updateScreen() {
//BPM Tab //BPM Tab
if (displayTab == 0) { //BPM if (displayTab == 0) { //BPM
u8g2.setFont(stkS); u8g2.setFont(velvetscreen);
//Menu items //Menu items
lastMenuItem = 4; lastMenuItem = 4;
@ -27,7 +27,7 @@ void updateScreen() {
lastMenuItem = 1; lastMenuItem = 1;
} }
for (uint8_t i = 1; i <= lastMenuItem; i++) { for (byte i = 1; i <= lastMenuItem; i++) {
if (i == 1) { if (i == 1) {
valueStr = F("MODE:"); valueStr = F("MODE:");
} else if (i == 2 && masterClockMode == 0) { } else if (i == 2 && masterClockMode == 0) {
@ -48,7 +48,7 @@ void updateScreen() {
} }
//Values //Values
for (uint8_t i = 1; i <= lastMenuItem; i++) { for (byte i = 1; i <= lastMenuItem; i++) {
if (i == 1 && masterClockMode == 0) { //Channel mode if (i == 1 && masterClockMode == 0) { //Channel mode
valueStr = F("INT"); valueStr = F("INT");
} else if (i == 1 && masterClockMode == 1) { } else if (i == 1 && masterClockMode == 1) {
@ -91,19 +91,19 @@ void updateScreen() {
if ((!insideTab && !shiftBtnPushed) || (insideTab && menuItem != 0)) { //default view, nothing is selected or editable if ((!insideTab && !shiftBtnPushed) || (insideTab && menuItem != 0)) { //default view, nothing is selected or editable
u8g2.setFont(stkL); u8g2.setFont(stkL);
u8g2.drawButtonUTF8(leftOffset-1, 28, U8G2_BTN_BW0|U8G2_BTN_HCENTER, width, 0, 3, valueStr.c_str() ); u8g2.drawButtonUTF8(leftOffset-1, 28, U8G2_BTN_BW0|U8G2_BTN_HCENTER, width, 0, 3, valueStr.c_str() );
u8g2.setFont(stkS); u8g2.setFont(velvetscreen);
valueStr = F("BPM"); valueStr = F("BPM");
u8g2.drawButtonUTF8(leftOffset, 40, U8G2_BTN_BW0|U8G2_BTN_HCENTER, width, 0, 2, valueStr.c_str() ); u8g2.drawButtonUTF8(leftOffset, 40, U8G2_BTN_BW0|U8G2_BTN_HCENTER, width, 0, 2, valueStr.c_str() );
} else if ((!insideTab && shiftBtnPushed) || (insideTab && menuItem == 0 && (menuItemSelected || shiftBtnPushed))) { //show value as editable } else if ((!insideTab && shiftBtnPushed) || (insideTab && menuItem == 0 && (menuItemSelected || shiftBtnPushed))) { //show value as editable
u8g2.setFont(stkL); u8g2.setFont(stkL);
u8g2.drawButtonUTF8(leftOffset-1, 28, U8G2_BTN_BW1|U8G2_BTN_HCENTER, width, 0, 3, valueStr.c_str() ); u8g2.drawButtonUTF8(leftOffset-1, 28, U8G2_BTN_BW1|U8G2_BTN_HCENTER, width, 0, 3, valueStr.c_str() );
u8g2.setFont(stkS); u8g2.setFont(velvetscreen);
valueStr = F("BPM"); valueStr = F("BPM");
u8g2.drawButtonUTF8(leftOffset, 40, U8G2_BTN_BW1|U8G2_BTN_INV|U8G2_BTN_HCENTER, width, 0, 2, valueStr.c_str() ); u8g2.drawButtonUTF8(leftOffset, 40, U8G2_BTN_BW1|U8G2_BTN_INV|U8G2_BTN_HCENTER, width, 0, 2, valueStr.c_str() );
} else if (insideTab && menuItem == 0 && !menuItemSelected) { //show as selected menu item } else if (insideTab && menuItem == 0 && !menuItemSelected) { //show as selected menu item
u8g2.setFont(stkL); u8g2.setFont(stkL);
u8g2.drawButtonUTF8(leftOffset-1, 28, U8G2_BTN_BW1|U8G2_BTN_INV|U8G2_BTN_HCENTER, width, 0, 3, valueStr.c_str() ); u8g2.drawButtonUTF8(leftOffset-1, 28, U8G2_BTN_BW1|U8G2_BTN_INV|U8G2_BTN_HCENTER, width, 0, 3, valueStr.c_str() );
u8g2.setFont(stkS); u8g2.setFont(velvetscreen);
valueStr = F("BPM"); valueStr = F("BPM");
u8g2.drawButtonUTF8(leftOffset, 40, U8G2_BTN_BW1|U8G2_BTN_INV|U8G2_BTN_HCENTER, width, 0, 2, valueStr.c_str() ); u8g2.drawButtonUTF8(leftOffset, 40, U8G2_BTN_BW1|U8G2_BTN_INV|U8G2_BTN_HCENTER, width, 0, 2, valueStr.c_str() );
} }
@ -118,26 +118,18 @@ void updateScreen() {
//Channel Tabs //Channel Tabs
else { else {
//Menu items //Menu items
if (channels[displayTab - 1].mode == Swing) { lastMenuItem = 3;
lastMenuItem = 1;
} else if (channels[displayTab - 1].mode == Gate) {
lastMenuItem = 3;
} else {
lastMenuItem = 3;
}
width = 32; width = 32;
leftOffset = 62; leftOffset = 62;
for (uint8_t i = 1; i <= lastMenuItem; i++) { for (byte i = 1; i <= lastMenuItem; i++) {
if (i == 1) { if (i == 1) {
valueStr = F("MODE:"); valueStr = F("MODE:");
} else if (i == 2 && channels[displayTab - 1].mode == Clock) { } else if (i == 2 && channels[displayTab - 1].mode == 0) {
valueStr = F("OFFSET:"); valueStr = F("OFFSET:");
} else if (i == 2 && (channels[displayTab - 1].mode == Random || channels[displayTab - 1].mode == Gate)) { } else if (i == 2 && channels[displayTab - 1].mode == 1) {
valueStr = F("SUBDIV:"); valueStr = F("SUBDIV:");
} else if (i == 2 && channels[displayTab - 1].mode == Sequencer) { } else if (i == 2 && channels[displayTab - 1].mode == 2) {
valueStr = F("EDIT PATTERN"); valueStr = F("EDIT PATTERN");
} else if (i == 3 && channels[displayTab - 1].mode == Gate) {
valueStr = (String(pulsePeriod) + " " + String(channelPulsesPerCycle[displayTab - 1]));
} else if (i == 3) { } else if (i == 3) {
valueStr = F("MOD:"); valueStr = F("MOD:");
} }
@ -149,18 +141,14 @@ void updateScreen() {
} }
//Values //Values
for (uint8_t i = 1; i <= lastMenuItem; i++) { for (byte i = 1; i <= lastMenuItem; i++) {
if (i == 1 && channels[displayTab - 1].mode == Clock) { //Channel mode if (i == 1 && channels[displayTab - 1].mode == 0) { //Channel mode
valueStr = F("CLOCK"); valueStr = F("CLOCK");
} else if (i == 1 && channels[displayTab - 1].mode == Random) { } else if (i == 1 && channels[displayTab - 1].mode == 1) {
valueStr = F("RAND"); valueStr = F("RAND");
} else if (i == 1 && channels[displayTab - 1].mode == Sequencer) { } else if (i == 1 && channels[displayTab - 1].mode == 2) {
valueStr = F("SEQ"); valueStr = F("SEQ");
} else if (i == 1 && channels[displayTab - 1].mode == Swing) { } else if (i == 2 && channels[displayTab - 1].mode == 0) { //SubDiv and offset
valueStr = F("SWING");
} else if (i == 1 && channels[displayTab - 1].mode == Gate) {
valueStr = F("GATE");
} else if (i == 2 && channels[displayTab - 1].mode == Clock) { //SubDiv and offset
valueStr = String(channels[displayTab - 1].offset) + F("/"); valueStr = String(channels[displayTab - 1].offset) + F("/");
int PulsesPerStep; int PulsesPerStep;
if (subDivs[channels[displayTab - 1].subDiv] < 0) { if (subDivs[channels[displayTab - 1].subDiv] < 0) {
@ -169,10 +157,10 @@ void updateScreen() {
PulsesPerStep = subDivs[channels[displayTab - 1].subDiv] * PPQN; PulsesPerStep = subDivs[channels[displayTab - 1].subDiv] * PPQN;
} }
valueStr = valueStr + String(PulsesPerStep); //(playingModes[i] * PPQN) - 1 //String(channelPulsesPerCycle[displayTab-1]+1) valueStr = valueStr + String(PulsesPerStep); //(playingModes[i] * PPQN) - 1 //String(channelPulsesPerCycle[displayTab-1]+1)
} else if (i == 2 && (channels[displayTab - 1].mode == Random || channels[displayTab - 1].mode == Gate) && subDivs[channels[displayTab - 1].subDiv] > 0) { } else if (i == 2 && channels[displayTab - 1].mode == 1 && subDivs[channels[displayTab - 1].subDiv] > 0) {
valueStr = F("/"); valueStr = F("/");
valueStr = valueStr + String(subDivs[channels[displayTab - 1].subDiv]); valueStr = valueStr + String(subDivs[channels[displayTab - 1].subDiv]);
} else if (i == 2 && (channels[displayTab - 1].mode == Random || channels[displayTab - 1].mode == Gate) && subDivs[channels[displayTab - 1].subDiv] < 0) { } else if (i == 2 && channels[displayTab - 1].mode == 1 && subDivs[channels[displayTab - 1].subDiv] < 0) {
valueStr = F("x"); valueStr = F("x");
valueStr = valueStr + String(abs(subDivs[channels[displayTab - 1].subDiv])); valueStr = valueStr + String(abs(subDivs[channels[displayTab - 1].subDiv]));
} else if (i == 3 && channels[displayTab - 1].CV1Target == 0 && channels[displayTab - 1].CV2Target == 0) { //MOD } else if (i == 3 && channels[displayTab - 1].CV1Target == 0 && channels[displayTab - 1].CV2Target == 0) { //MOD
@ -183,7 +171,7 @@ void updateScreen() {
valueStr = F("CV2"); valueStr = F("CV2");
} }
if (i == 2 && channels[displayTab - 1].mode == Sequencer) { //EDIT PATTERN thing if (i == 2 && channels[displayTab - 1].mode == 2) { //EDIT PATTERN thing
if (menuItem == i && insideTab) { if (menuItem == i && insideTab) {
u8g2.drawBox(leftOffset + 54, ((i-1) * 11), 11, 11); u8g2.drawBox(leftOffset + 54, ((i-1) * 11), 11, 11);
} }
@ -201,52 +189,36 @@ void updateScreen() {
//Main Param //Main Param
leftOffset = 29; leftOffset = 29;
width = 55; width = 55;
if (channels[displayTab - 1].mode == Clock) { if (channels[displayTab - 1].mode == 0) {
valueStr = F("SUBDIVISION"); valueStr = F("SUBDIVISION");
} else if (channels[displayTab - 1].mode == Random) { } else if (channels[displayTab - 1].mode == 1) {
valueStr = F("SKIP CHANCE"); valueStr = F("SKIP CHANCE");
} else if (channels[displayTab - 1].mode == Sequencer) { } else if (channels[displayTab - 1].mode == 2) {
valueStr = F("PATTERN"); valueStr = F("PATTERN");
} else if (channels[displayTab - 1].mode == Swing) {
valueStr = F("SWING");
} else if (channels[displayTab - 1].mode == Gate) {
valueStr = gateLengthTime[displayTab - 1];
} }
if ((!insideTab && shiftBtnPushed) || (insideTab && menuItem == 0)) { if ((!insideTab && shiftBtnPushed) || (insideTab && menuItem == 0)) {
u8g2.drawButtonUTF8(leftOffset, 41, U8G2_BTN_BW1|U8G2_BTN_INV|U8G2_BTN_HCENTER, width, 0, 3, valueStr.c_str() ); u8g2.drawButtonUTF8(leftOffset, 41, U8G2_BTN_BW1|U8G2_BTN_INV|U8G2_BTN_HCENTER, width, 0, 3, valueStr.c_str() );
} else { } else {
u8g2.drawButtonUTF8(leftOffset, 41, U8G2_BTN_BW0|U8G2_BTN_HCENTER, width, 1, 2, valueStr.c_str() ); u8g2.drawButtonUTF8(leftOffset, 41, U8G2_BTN_BW0|U8G2_BTN_HCENTER, width, 1, 2, valueStr.c_str() );
} }
if (channels[displayTab - 1].mode == Clock) { if (channels[displayTab - 1].mode == 0) {
if (subDivs[channels[displayTab - 1].subDiv] > 0) { if (subDivs[channels[displayTab - 1].subDiv] > 0) {
valueStr = F("/"); valueStr = F("/");
} else { } else {
valueStr = F("x"); valueStr = F("x");
} }
valueStr = valueStr + String(abs(subDivs[channels[displayTab - 1].subDiv])); valueStr = valueStr + String(abs(subDivs[channels[displayTab - 1].subDiv]));
} else if (channels[displayTab - 1].mode == Random) { } else if (channels[displayTab - 1].mode == 1) {
valueStr = String(channels[displayTab - 1].random) + (channels[displayTab - 1].random == 0 ? "%" : "0%"); valueStr = String(channels[displayTab - 1].random) + "0%";
} else if (channels[displayTab - 1].mode == Sequencer) { } else if (channels[displayTab - 1].mode == 2) {
if (channels[displayTab - 1].seqPattern < 8) { if (channels[displayTab - 1].seqPattern < 8) {
valueStr = F("A"); valueStr = F("A");
valueStr = valueStr + String(channels[displayTab - 1].seqPattern + 1); valueStr = valueStr + String(channels[displayTab - 1].seqPattern + 1);
} else if (channels[displayTab - 1].seqPattern >= 8 && channels[displayTab - 1].seqPattern < 16) { } else {
valueStr = F("B"); valueStr = F("B");
valueStr = valueStr + String(channels[displayTab - 1].seqPattern - 7); valueStr = valueStr + String(channels[displayTab - 1].seqPattern - 7);
} else if (channels[displayTab - 1].seqPattern >= 16 && channels[displayTab - 1].seqPattern < 24) {
valueStr = F("C");
valueStr = valueStr + String(channels[displayTab - 1].seqPattern - 15);
} else if (channels[displayTab - 1].seqPattern >= 24 && channels[displayTab - 1].seqPattern < 32) {
valueStr = F("D");
valueStr = valueStr + String(channels[displayTab - 1].seqPattern - 23);
} }
} else if (channels[displayTab - 1].mode == Swing) {
uint8_t swingVals[6] = {50, 58, 66, 75, 83, 92};
valueStr = String(swingVals[channels[displayTab - 1].swing]) + "%";
} else if (channels[displayTab - 1].mode == Gate) {
valueStr = String(channels[displayTab - 1].gate) + "%";
} }
u8g2.setFont(stkL); u8g2.setFont(stkL);
if ((!insideTab && shiftBtnPushed) || (insideTab && menuItem == 0 && (menuItemSelected || shiftBtnPushed))) { if ((!insideTab && shiftBtnPushed) || (insideTab && menuItem == 0 && (menuItemSelected || shiftBtnPushed))) {
@ -260,9 +232,9 @@ void updateScreen() {
//Tabs //Tabs
u8g2.drawHLine(0, 53, 128); u8g2.drawHLine(0, 53, 128);
u8g2.setFont(stkS); u8g2.setFont(velvetscreen);
uint8_t yPos = 61; byte yPos = 61;
uint8_t xWidth = 12; byte xWidth = 12;
valueStr = F("w"); valueStr = F("w");
if (displayTab == 0) { if (displayTab == 0) {
if (insideTab == true || shiftBtnPushed == true) { if (insideTab == true || shiftBtnPushed == true) {
@ -274,7 +246,7 @@ void updateScreen() {
u8g2.drawButtonUTF8(xWidth/2, yPos, U8G2_BTN_BW0|U8G2_BTN_HCENTER, xWidth, 0, 2, valueStr.c_str() ); u8g2.drawButtonUTF8(xWidth/2, yPos, U8G2_BTN_BW0|U8G2_BTN_HCENTER, xWidth, 0, 2, valueStr.c_str() );
} }
for (uint8_t i = 1; i <= (extraChannel ? 7 : 6); i++) { for (int i = 1; i <= 6; i++) {
valueStr = String(i); valueStr = String(i);
if (displayTab == i) { if (displayTab == i) {
if (insideTab == true || shiftBtnPushed == true) { if (insideTab == true || shiftBtnPushed == true) {
@ -298,8 +270,8 @@ void updateScreen() {
//Edit Pattern Screen (Sequencer) //Edit Pattern Screen (Sequencer)
else if (displayScreen == 1) { else if (displayScreen == 1) {
u8g2.setFont(stkS); u8g2.setFont(velvetscreen);
uint8_t pattern = channels[displayTab - 1].seqPattern; byte pattern = channels[displayTab - 1].seqPattern;
if (pattern < 8) { if (pattern < 8) {
valueStr = F("PATTERN A"); valueStr = F("PATTERN A");
valueStr = valueStr + String(pattern + 1); valueStr = valueStr + String(pattern + 1);
@ -307,31 +279,27 @@ void updateScreen() {
valueStr = F("PATTERN B"); valueStr = F("PATTERN B");
valueStr = valueStr + String(pattern - 7); valueStr = valueStr + String(pattern - 7);
} }
u8g2.drawUTF8(8, 6, valueStr.c_str() ); u8g2.drawButtonUTF8(64, 5, U8G2_BTN_BW1|U8G2_BTN_HCENTER, 128, 0, 2, valueStr.c_str() );
valueStr = F("L: "); for (byte i = 0; i < 8; i++) {
//u8g2.drawUTF8(100, 5, valueStr.c_str() ); if (patternToEdit[i]) {
if (!isRecording && stepNumSelected == -1) { u8g2.drawUTF8(19 + i*12, 24, "q");
u8g2.drawButtonUTF8(97, 6, U8G2_BTN_BW1|U8G2_BTN_INV, 5, 1, 2, valueStr.c_str() ); } else {
} else { u8g2.drawUTF8(19 + i*12, 24, "p");
u8g2.drawButtonUTF8(97, 6, U8G2_BTN_BW0, 5, 1, 2, valueStr.c_str() ); }
} }
for (byte i = 8; i < 16; i++) {
valueStr = String(sequences[patternToEdit].length + 1); if (patternToEdit[i]) {
//u8g2.drawUTF8(110, 5, valueStr.c_str() ); u8g2.drawUTF8(19 + (i-8)*12, 40, "q");
if (!isRecording && stepNumSelected == -1 && (menuItemSelected || shiftBtnPushed)) { } else {
u8g2.drawButtonUTF8(110, 6, U8G2_BTN_BW1, 8, 1, 2, valueStr.c_str() ); u8g2.drawUTF8(19 + (i-8)*12, 40, "p");
} else if (!isRecording && stepNumSelected == -1 && (!menuItemSelected || !shiftBtnPushed)) { }
u8g2.drawButtonUTF8(110, 6, U8G2_BTN_BW1|U8G2_BTN_INV, 8, 1, 2, valueStr.c_str() );
} else {
u8g2.drawButtonUTF8(110, 6, U8G2_BTN_BW0, 8, 1, 2, valueStr.c_str() );
} }
if (!isRecording) {
u8g2.drawHLine(0, 8, 128); if (stepNumSelected < 8 ) {
for (uint8_t i = 0; i <= sequences[patternToEdit].length; i++) { u8g2.drawFrame(16 + stepNumSelected * 12, 16, 11, 11);
u8g2.drawUTF8(19 + (i % 8)*12, 33 - ((sequences[patternToEdit].length / 8) * 5) + ((i / 8) * 11), (bitRead(sequences[patternToEdit].sequence, i) ? "q" : "p")); } else {
} u8g2.drawFrame(16 + (stepNumSelected-8) * 12, 32, 11, 11);
if (!isRecording && stepNumSelected >= 0) { }
u8g2.drawFrame(16 + (stepNumSelected % 8)*12, 25 - ((sequences[patternToEdit].length / 8) * 5) + ((stepNumSelected / 8) * 11), 11, 11); //cursor
} }
if (isRecording) { if (isRecording) {
@ -346,9 +314,9 @@ void updateScreen() {
u8g2.drawStr(8, 5, valueStr.c_str() ); u8g2.drawStr(8, 5, valueStr.c_str() );
u8g2.drawStr(122 - (u8g2.getStrWidth(version.c_str())), 5, version.c_str() ); u8g2.drawStr(122 - (u8g2.getStrWidth(version.c_str())), 5, version.c_str() );
u8g2.drawHLine(0, 8, 128); u8g2.drawHLine(0, 8, 128);
lastMenuItem = 4; lastMenuItem = 3;
uint8_t width = 112; byte width = 112;
for (uint8_t i = 0; i <= lastMenuItem; i++) { for (byte i = 0; i <= lastMenuItem; i++) {
switch(i) { switch(i) {
case 0: case 0:
valueStr = F("CALIBRATE CV INS"); valueStr = F("CALIBRATE CV INS");
@ -360,9 +328,6 @@ void updateScreen() {
valueStr = F("REVERSE ENCODER"); valueStr = F("REVERSE ENCODER");
break; break;
case 3: case 3:
valueStr = (extraChannel ? F("7TH CHANNEL: ON") : F("7TH CHANNEL: OFF"));
break;
case 4:
valueStr = F("FACTORY RESET"); valueStr = F("FACTORY RESET");
break; break;
}; };

View File

@ -1,40 +0,0 @@
#pragma once
#define PPQN 24
#define PULSE_LENGTH 120 //1/10ms resolution. 12ms was failing at 1ms resolution at higher bpm. 60000/200/24 = 12.5 the max pulse length at 1ms resolution for 200bpm is 11ms
#define MAXBPM 200 //250 at 24ppqn with 5ms pulse will be 50/50 square wave
#define MINBPM 20
#define SCREEN_ADDRESS 0x3C
// Rev 2+ Config
#define ENC_BTN_PIN 14
#define ENC_D1_PIN 17
#define ENC_D2_PIN 4
#define START_STOP_BTN_PIN 5
#define SHIFT_BTN_PIN 12
#define EXT_INPUT_PIN 2 //needs to be an interrupt pin
#define ANALOGUE_INPUT_1_PIN A7
#define ANALOGUE_INPUT_2_PIN A6
const uint8_t clockOutPin = 3;
const uint8_t outsPins[] = { 7, 8, 10, 6, 9, 11, clockOutPin };
bool rotateScreen = false;
bool reverseEnc = false;
/* Rev 1 Config
#define ENC_BTN_PIN 14
#define ENC_D1_PIN 17
#define ENC_D2_PIN 4
#define START_STOP_BTN_PIN 5
#define SHIFT_BTN_PIN 100
#define EXT_INPUT_PIN 2 //needs to be an interrupt pin
#define ANALOGUE_INPUT_1_PIN A2
#define ANALOGUE_INPUT_2_PIN A1
const byte clockOutPin = 13;
const byte outsPins[6] = {6, 11, 7, 10, 8, 9, clockOutPin};
bool rotateScreen = true;
*/
#define bitFlip(value, bit) ((value) ^ (1UL << (bit)))

View File

@ -1,38 +0,0 @@
#pragma once
const PROGMEM uint8_t stkS[437] U8G2_FONT_SECTION("stk-s") =
"\64\0\2\2\3\3\2\3\4\5\5\0\0\5\0\5\0\0\221\0\0\1\230 \4\200\134%\11\255tT"
"R\271RI(\6\252\334T\31)\7\252\134bJ\12+\7\233\345\322J\0,\5\221T\4-\5\213"
"f\6.\5\211T\2/\6\244\354c\33\60\10\254\354T\64\223\2\61\7\353\354\222\254\6\62\11\254l"
"\66J*\217\0\63\11\254l\66J\32\215\4\64\10\254l\242\34\272\0\65\11\254l\206\336h$\0\66"
"\11\254\354T^\61)\0\67\10\254lF\216u\4\70\11\254\354TL*&\5\71\11\254\354TL;"
")\0:\6\231UR\0A\10\254\354T\34S\6B\11\254lV\34)\216\4C\11\254\354T\324\61"
")\0D\10\254lV\64G\2E\10\254l\206\36z\4F\10\254l\206^\71\3G\11\254\354TN"
"\63)\0H\10\254l\242\34S\6I\6\251T\206\0J\10\254\354k\231\24\0K\11\254l\242J\62"
"\225\1L\7\254lr{\4M\11\255t\362ZI\353\0N\11\255t\362TI\356\0O\10\254\354T"
"\64\223\2P\11\254lV\34)g\0Q\10\254\354T\264b\12R\10\254lV\34\251\31S\11\254\354"
"FF\32\215\4T\7\253dVl\1U\10\254l\242\63)\0V\11\255t\262Ne\312\21W\12\255"
"t\262J*\251.\0X\11\254l\242L*\312\0Y\12\255tr\252\63\312(\2Z\7\253df*"
"\7p\10\255\364V\266\323\2q\7\255\364\216\257\5r\10\253d\242\32*\2t\6\255t\376#w\11"
"\255\364V\245FN\13x\6\233dR\7\0\0\0\4\377\377\0";
const PROGMEM uint8_t stkL[592] U8G2_FONT_SECTION("stk-l") =
"\26\0\4\4\4\5\2\1\6\17\27\1\0\27\0\0\0\1\77\0\0\2\63%'\17\37\313\330R#&"
"\32!F\14\211I\310\24!\65\204(MF\21)Cd\304\10\62b\14\215\60Vb\334\20\0/\14"
"\272\336\336d\244\350\263q\343\0\60\37|\377\216!%*\10\35\263\253ChD\30\21bB\14\242S"
"\306lv\210\204\22Ef\0\61\24z\337\322\60R\205\314\234\31\61F\310\270\371\177\224\42\3\62\33|"
"\377\216)\64*\10\35\63\66r\206\304\314`c\252\34\301\221\263|\360\300\0\63\34|\377\216)\64*"
"\10\35\63\66r \71\332YIr\226\306\16\221P\203\312\14\0\64 |\377\226\220AC\306\20\31B"
"f\310\240\21\204F\214\32\61j\304(cv\366\200\305\312\371\0\65\32|\377\206\212-F\316\27\204\224"
"\254\30\65t\344,\215\35\42\241\6\225\31\0\66\33}\17\317\251\64+\206\235\63:/\314,aA\352"
"\234\335\235\42\261&\325\31\0\67\23|\377\302\212\7)\347Crt\70\345\300\221\363\16\0\70 |\377"
"\216)\64*\10\35\263\354\20\11\42d\20\235BC\204\4\241cvv\210\204\32Tf\0\71\32|\377"
"\216)\64*\10\35\263\263C$\226\250I\71_\14\42\241\6\225\31\0A\26}\17S\271Si(\31"
"\65d\324\210q\366\356\301w\366\273\1B$}\17C\42\65KF\221\30\66b\330\210a#\206\215\30"
"Eb\311&\243H\14;g\317\36\204`\261\4\0C\27}\17\317\251\64K\10!\63:\377\247\304F"
"\20\42\261F\21\22\0D\33}\17C\42\65KF\15\31\66b\330\210q\366\77;\66b\24\211%j"
"\22\1E\21|\377\302\7)\347%\42\214F\316/\37<\60I\7so\302\37$M$}\17\203\310"
"r\346N\245Q\263\202E\12)L\224\60Q\302\310\20#C\214\14\61\23\306L\30s\366\335\0T\15"
"}\17\303\7\251\206\316\377\377\12\0X)~\37\303@\203\307H\14\33B\210\14\21RC\206\241\63h"
"\222(I\203\346\220\15\31E\204\14!\42\303F\20;h\341\0x\24\312\336\302 CGH\240\61E"
"\312\14\222)\6Y\64\0\0\0\0\4\377\377\0";