feat: Add configurable pulse output feature with UI control and associated logic.
This commit is contained in:
@ -37,7 +37,8 @@ enum GlobalParam {
|
||||
PARAM_GLOBAL_BPM = 1,
|
||||
PARAM_GLOBAL_CV1_DEST = 2,
|
||||
PARAM_GLOBAL_CV2_DEST = 3,
|
||||
PARAM_GLOBAL_LAST = 4
|
||||
PARAM_GLOBAL_PULSE_OUT = 4,
|
||||
PARAM_GLOBAL_LAST = 5
|
||||
};
|
||||
|
||||
enum CvDest {
|
||||
@ -56,6 +57,7 @@ GlobalParam current_global_param = PARAM_GLOBAL_CLK_SRC;
|
||||
CvDest cv1_dest = CV_DEST_MAP_X;
|
||||
CvDest cv2_dest = CV_DEST_CHAOS;
|
||||
Clock::Source selected_source = Clock::SOURCE_INTERNAL;
|
||||
Clock::Pulse selected_pulse = Clock::PULSE_PPQN_4;
|
||||
|
||||
// UI & Navigation
|
||||
enum SelectedParam {
|
||||
@ -163,6 +165,20 @@ void ProcessSequencerTick(uint32_t tick) {
|
||||
}
|
||||
}
|
||||
|
||||
// Expansion Pulse Out gate
|
||||
if (selected_pulse != Clock::PULSE_NONE) {
|
||||
int pulse_high_ticks = 96; // 1 PPQN
|
||||
if (selected_pulse == Clock::PULSE_PPQN_4) pulse_high_ticks = 24;
|
||||
else if (selected_pulse == Clock::PULSE_PPQN_24) pulse_high_ticks = 4;
|
||||
|
||||
int pulse_low_ticks = tick + max(pulse_high_ticks / 2, 1);
|
||||
if (tick % pulse_high_ticks == 0) {
|
||||
gravity.pulse.High();
|
||||
} else if (pulse_low_ticks % pulse_high_ticks == 0) {
|
||||
gravity.pulse.Low();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle new 16th note step
|
||||
if (tick % PULSES_PER_16TH == 0) {
|
||||
|
||||
@ -256,6 +272,7 @@ void HandleExtClockTick() {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
gravity.outputs[i].Low();
|
||||
}
|
||||
gravity.pulse.Low();
|
||||
gravity.clock.Reset();
|
||||
current_step = 0;
|
||||
break;
|
||||
@ -270,12 +287,23 @@ void OnPlayPress() {
|
||||
gravity.clock.Stop();
|
||||
for (int i = 0; i < 6; i++)
|
||||
gravity.outputs[i].Low();
|
||||
gravity.pulse.Low();
|
||||
} else {
|
||||
gravity.clock.Start();
|
||||
}
|
||||
needs_redraw = true;
|
||||
}
|
||||
|
||||
void OnShiftPress() {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
gravity.outputs[i].Low();
|
||||
}
|
||||
gravity.pulse.Low();
|
||||
gravity.clock.Reset();
|
||||
current_step = 0;
|
||||
needs_redraw = true;
|
||||
}
|
||||
|
||||
void OnEncoderPress() {
|
||||
editing_param = !editing_param;
|
||||
needs_redraw = true;
|
||||
@ -375,6 +403,15 @@ void OnEncoderRotate(int val) {
|
||||
cv2_dest = (CvDest)dest;
|
||||
break;
|
||||
}
|
||||
case PARAM_GLOBAL_PULSE_OUT: {
|
||||
int pulse = (int)selected_pulse + val;
|
||||
pulse = constrain(pulse, 0, Clock::PULSE_LAST - 1);
|
||||
selected_pulse = (Clock::Pulse)pulse;
|
||||
if (selected_pulse == Clock::PULSE_NONE) {
|
||||
gravity.pulse.Low();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -437,7 +474,8 @@ const char str_source[] PROGMEM = "SOURCE";
|
||||
const char str_tempo[] PROGMEM = "TEMPO";
|
||||
const char str_cv1dest[] PROGMEM = "CV1 DEST";
|
||||
const char str_cv2dest[] PROGMEM = "CV2 DEST";
|
||||
const char* const global_menu_items[] PROGMEM = {str_source, str_tempo, str_cv1dest, str_cv2dest};
|
||||
const char str_pulse[] PROGMEM = "PULSE OUT";
|
||||
const char* const global_menu_items[] PROGMEM = {str_source, str_tempo, str_cv1dest, str_cv2dest, str_pulse};
|
||||
|
||||
void drawMenuItems(const char* const menu_items[], int menu_size, int current_item) {
|
||||
gravity.display.setFont(TEXT_FONT);
|
||||
@ -588,6 +626,25 @@ void DisplayMainArea() {
|
||||
strcpy_P(mainText, PSTR("CV2"));
|
||||
strcpy(subText, GetCvDestName(cv2_dest));
|
||||
break;
|
||||
case PARAM_GLOBAL_PULSE_OUT:
|
||||
switch (selected_pulse) {
|
||||
case Clock::PULSE_NONE:
|
||||
strcpy_P(mainText, PSTR("OFF"));
|
||||
break;
|
||||
case Clock::PULSE_PPQN_24:
|
||||
strcpy_P(mainText, PSTR("24"));
|
||||
break;
|
||||
case Clock::PULSE_PPQN_4:
|
||||
strcpy_P(mainText, PSTR("4"));
|
||||
break;
|
||||
case Clock::PULSE_PPQN_1:
|
||||
strcpy_P(mainText, PSTR("1"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
strcpy_P(subText, PSTR("PPQN"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -645,6 +702,7 @@ void setup() {
|
||||
LoadState();
|
||||
|
||||
gravity.play_button.AttachPressHandler(OnPlayPress);
|
||||
gravity.shift_button.AttachPressHandler(OnShiftPress);
|
||||
gravity.encoder.AttachPressHandler(OnEncoderPress);
|
||||
gravity.encoder.AttachRotateHandler(OnEncoderRotate);
|
||||
gravity.encoder.AttachPressRotateHandler(OnEncoderPressRotate);
|
||||
|
||||
Reference in New Issue
Block a user