diff --git a/equations/clock.csv b/equations/clock.csv new file mode 100644 index 0000000..ce855ba --- /dev/null +++ b/equations/clock.csv @@ -0,0 +1,9 @@ +i, sync rising, time, last_sync, delta +1, 1, 0, 0, 0 +2, 0, 10, 0, 0 +3, 0, 20, 10, 10 +4, 0, 30, 20, 10 +5, 1, 40, 30, 10 +6, 0, 50, 40, 10 +7, 0, 60, 50, 10 +8, 0, 70, 60, 10 \ No newline at end of file diff --git a/src/DebouncedBoolean.h b/src/DebouncedBoolean.h index aef2ee9..c1e206a 100644 --- a/src/DebouncedBoolean.h +++ b/src/DebouncedBoolean.h @@ -3,7 +3,7 @@ * Best used on continuously read logic inputs * * set() shifts truthiness into the past - * isFresh() only returns true if no past value is true + * isRising() only returns true if no past value is true */ #pragma once @@ -14,15 +14,15 @@ class DebouncedBoolean { bool state[2] = {false}; - void set(bool value){ + void set(bool value) { state[0] = state[1]; state[1] = value; } - bool isFresh(){ + bool isRising() { return state[0] == false && state[1] == true; } - void reset(){ + void reset() { state[2] = {false}; } }; diff --git a/src/clock.cpp b/src/clock.cpp index 11334e6..11d61da 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -6,52 +6,41 @@ */ #include "clock.h" +#include "lights.h" bool Clock::isHigh(uint16_t sync_voltage, uint16_t division_knob, uint32_t time) { - // measure time delta - const uint8_t DELTA = time - prev_time; - prev_time = time; + // get multiplier from knob + const int8_t KNOB_STEP = (division_knob * 5 + 512) >> 10; // >>10 quick divides by 1023 + + // measure time between syncs + const uint32_t PROGRESS = time - time_of_last_sync; - // reset if sync is rising + // if sync is rising sync_debounce.set(sync_voltage > LOGIC_HIGH); - if (sync_debounce.isFresh()) { + if (sync_debounce.isRising()) { - // predict milliseconds of period - // ignoring clock division - period_prediction = predictor.Predict(DELTA); - reset(); - return true; - } else { - period_accumulation += DELTA; - } + // repredict milliseconds of period + period_prediction = predictor.Predict(PROGRESS); + reset(time); - // get multiplier from knob - const int8_t KNOB_STEP = (division_knob * 5 + 512) >> 10; // quick divide by 1023 - - // if no division, duration of 1 pulse at 24ppqn is the same as period - if(KNOB_STEP == 0){ - slot_duration = period_prediction; - } else if (KNOB_STEP == 1) { - // 16ppqn * 3/2 = 24ppqn - slot_duration = period_prediction * 1.5; - } else { - // 8ppqn, 4ppqn, 2ppqn, 1ppqn - const uint16_t MULTIPLIER = pow(2, KNOB_STEP - 2) * 3; - slot_duration = period_prediction * MULTIPLIER; + // no further logic is necessary if no multiplier + if (KNOB_STEP == 0) return true; } - // if pulse has advanced, return true - const uint8_t PULSE_NUMBER = period_accumulation / slot_duration; - if(pulse_counter < 24 && PULSE_NUMBER > pulse_counter){ - pulse_counter++; + const uint8_t MULTIPLIER = pow(2, KNOB_STEP - 1) * 3; + + const uint16_t PULSE_NUMBER = PROGRESS * MULTIPLIER / period_prediction; + lights(0, PULSE_NUMBER); + + if(PULSE_NUMBER != prev_pulse_number){ + prev_pulse_number = PULSE_NUMBER; return true; } return false; } -void Clock::reset() { - pulse_counter = 0; - period_accumulation = 0; +void Clock::reset(uint32_t time) { + time_of_last_sync = time; } diff --git a/src/clock.h b/src/clock.h index d04ce07..ff9d270 100644 --- a/src/clock.h +++ b/src/clock.h @@ -1,27 +1,23 @@ -#ifndef CLOCK_H -#define CLOCK_H +#pragma once +#include "preferences.h" #include "peaks_pattern_predictor.h" #include "DebouncedBoolean.h" class Clock { private: - uint32_t prev_time; + DebouncedBoolean sync_debounce; PatternPredictor<32, 8> predictor; - uint16_t period_prediction; - uint16_t period_accumulation; - uint8_t slot_duration; - - uint8_t pulse_counter = 0; + uint32_t time_of_last_sync; + uint32_t period_prediction; + uint16_t prev_pulse_number; public: Clock() { predictor.Init(); } bool isHigh(uint16_t sync_voltage, uint16_t division_knob, uint32_t time); - void reset(); + void reset(uint32_t time); }; - -#endif diff --git a/src/grid.h b/src/grid.h index 08cce6d..fe928b9 100644 --- a/src/grid.h +++ b/src/grid.h @@ -5,11 +5,9 @@ * weight for all channels at once in a single 8-bit byte */ -#include +// #include -#define RESOLUTION 24 * 16 - -uint8_t * getWeight(uint16_t pulse, uint8_t width) { +uint8_t getWeight(uint16_t pulse, uint8_t width) { // all 3 channels' weights as expressed by: // 00110000 top // 00001100 left @@ -21,20 +19,22 @@ uint8_t * getWeight(uint16_t pulse, uint8_t width) { // 11 3 uint8_t weight_byte = 0; for(uint16_t i=pulse; i> 4); - weights[1] = ((weight_byte & B00001100) >> 2); - weights[2] = (weight_byte & B00000011); + return weight_byte; + // static uint8_t weights[3]; + // weights[0] = ((weight_byte & B00110000) >> 4); + // weights[1] = ((weight_byte & B00001100) >> 2); + // weights[2] = (weight_byte & B00000011); - return weights; + // return weights; } void setWeight(uint16_t pulse, bool top, bool left, bool right) { - uint8_t memory_byte = EEPROM.read(pulse) - - B00010000 * !top - - B00000100 * !left - - B00000001 * !right; - EEPROM.write(pulse, memory_byte); + // uint8_t memory_byte = EEPROM.read(pulse) + // - B00010000 * !top + // - B00000100 * !left + // - B00000001 * !right; + // EEPROM.write(pulse, memory_byte); } diff --git a/src/main.cpp b/src/main.cpp index fafebeb..0e869c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,7 +15,7 @@ #include "preferences.h" #include "pins.h" #include "multiplexer.h" -#include "lights.h" +// #include "lights.h" #include "grid.h" #include "clock.h" #include "DebouncedBoolean.h" @@ -65,12 +65,8 @@ void loop() { rightPressed.set(digitalRead(right_button)); uint16_t clock_div_knob__val = getTrigerMux(clock_div_knob); uint8_t threshold = getTrigerMux(roll_rate_knob) * 4 / 1024; - uint32_t time = millis(); - - uint8_t *weights; - - // set state + uint8_t weights[3]; // clock advancement if( clock.isHigh(this_clock_in, clock_div_knob__val, time) ) { @@ -80,16 +76,19 @@ void loop() { // full roll rate acts as original gate setWeight( step, - topPressed.isFresh(), - leftPressed.isFresh(), - rightPressed.isFresh() + topPressed.isRising(), + leftPressed.isRising(), + rightPressed.isRising() ); //advance clock clock_until = time + 25; //advance outputs - weights = getWeight(step, 1); + uint8_t weight_byte = getWeight(step, threshold); + weights[0] = ((weight_byte & B00110000) >> 4); + weights[1] = ((weight_byte & B00001100) >> 2); + weights[2] = (weight_byte & B00000011); if(weights[0] > threshold) { top_until = time + 25; } @@ -102,8 +101,8 @@ void loop() { //advance step step = (step+1) % RESOLUTION; + } - prev_clock_in = this_clock_in; // cv outputs digitalWrite(left_out, (left_until > time)); @@ -120,23 +119,26 @@ void loop() { 1 }; short viz = 4 * step / RESOLUTION; + uint8_t grw = 0 // reds + B01000000 * brightness[weights[0]] - + B00010000 * brightness[weights[0]] - + B00000100 * brightness[weights[0]] + + B00010000 * brightness[weights[1]] + + B00000100 * brightness[weights[2]] ; uint8_t oranges = 0 + tracker[viz] * (viz == 0 ? 1 : brightness[2]) - + threshold + + (step & B1111) // + B1000 * brightness[leftGrid.get_weight(step+0, 1)] // + B0100 * brightness[leftGrid.get_weight(step+1, 1)] // + B0010 * brightness[leftGrid.get_weight(step+2, 1)] // + B0001 * brightness[leftGrid.get_weight(step+3, 1)] ; - lights(grw, oranges); + // lights(grw, (step & 255)); + pwm = (pwm+1) % 80; + } diff --git a/src/multiplexer.h b/src/multiplexer.h index 3731879..f326c1a 100644 --- a/src/multiplexer.h +++ b/src/multiplexer.h @@ -1,5 +1,4 @@ -#ifndef MULTIPLEXER_H -#define MULTIPLEXER_H +#pragma once /** * multiplexed analog signals * all are read on A6 via the getMux() function @@ -30,5 +29,3 @@ bool getHostMode() return 0; //slave return 1; //normal } - -#endif diff --git a/src/preferences.h b/src/preferences.h index cb915c2..dd55399 100644 --- a/src/preferences.h +++ b/src/preferences.h @@ -1,2 +1,4 @@ +#define PPQN 24 // pulses per quarter note +#define RESOLUTION (PPQN * 16) // 16 quarter notes #define NOISE_FLOOR 128 // out of 1024 #define LOGIC_HIGH 900 // out of 1024