Added CV and Gate outputs via 2x i2c MCP4725 modules

This commit is contained in:
2025-10-15 13:30:25 +03:00
parent e0da8f123d
commit d4772ad52d
15 changed files with 2299 additions and 4 deletions

183
PageSequencer.ino Normal file
View File

@ -0,0 +1,183 @@
/*
[step edit]
knobs: octave, note, global tunning, sequence length
buttons: prev step, next step, rest, glide/tie, accent, play/stop
*/
void sendPreviewNote(uint8_t step)
{
unsigned long milliTime, preMilliTime;
uint8_t note;
// enable or disable harmonizer
if ( _harmonize == 1 ) {
note = harmonizer(_sequencer[_selected_track].data.step[step].note);
} else {
note = _sequencer[_selected_track].data.step[step].note;
}
ATOMIC(sendMidiMessage(NOTE_ON, note, _sequencer[_selected_track].data.step[step].accent ? ACCENT_VELOCITY : NOTE_VELOCITY, _sequencer[_selected_track].channel))
// avoid delay() call because of uClock timmer1 usage
//delay(200);
preMilliTime = millis();
while ( true ) {
milliTime = millis();
if (abs(milliTime - preMilliTime) >= 200) {
break;
}
}
ATOMIC(sendMidiMessage(NOTE_OFF, note, 0, _sequencer[_selected_track].channel))
}
void processSequencerPots()
{
static int8_t octave, note, step_note;
static int16_t value;
uint8_t relative_step = uint8_t(_step_edit + _sequencer[_selected_track].data.step_init_point) % _sequencer[_selected_track].data.step_length;
// GENERIC_POT_1: Note Octave Selector
octave = getPotChanges(GENERIC_POT_1, 0, 10);
if ( octave != -1 ) {
_last_octave = octave;
}
// GENERIC_POT_2: Note Selector (generic C to B, no octave)
note = getPotChanges(GENERIC_POT_2, 0, 11);
if ( note != -1 ) {
_last_note = note;
}
// changes on octave or note pot?
if ( octave != -1 || note != -1 ) {
//ATOMIC(_sequencer[_selected_track].data.step[relative_step].note = (_last_octave * 8) + _last_note);
note = (_last_octave * 8) + _last_note;
ATOMIC(_sequencer[_selected_track].data.step[relative_step].note = note);
if ( _playing == false && _sequencer[_selected_track].data.step[relative_step].rest == 0 ) {
sendPreviewNote(relative_step);
}
}
// GENERIC_POT_3: global tunning (afects booth tracks) or track tunning
value = getPotChanges(GENERIC_POT_3, 0, 24);
if ( value != -1 ) {
//clearStackNote();
// -12 (0) +12
ATOMIC(_transpose = value-12);
}
// GENERIC_POT_4: sequencer step length
value = getPotChanges(GENERIC_POT_4, 1, STEP_MAX_SIZE);
if ( value != -1 ) {
//clearStackNote(_selected_track);
ATOMIC(_sequencer[_selected_track].data.step_length = value);
if ( relative_step >= _sequencer[_selected_track].data.step_length ) {
_step_edit = _sequencer[_selected_track].data.step_length-1;
}
}
}
void processSequencerButtons()
{
uint8_t relative_step = uint8_t(_step_edit + _sequencer[_selected_track].data.step_init_point) % _sequencer[_selected_track].data.step_length;
// previous step edit
if ( released(GENERIC_BUTTON_1) ) {
if ( _step_edit != 0 ) {
// add a lock here for octave and note to not mess with edit mode when moving steps around
lockPotsState(true);
--_step_edit;
}
if ( _playing == false && _sequencer[_selected_track].data.step[relative_step].rest == 0 ) {
sendPreviewNote(relative_step-1);
}
}
// next step edit
if ( released(GENERIC_BUTTON_2) ) {
if ( _step_edit < _sequencer[_selected_track].data.step_length-1 ) {
// add a lock here for octave and note to not mess with edit mode when moving steps around
lockPotsState(true);
++_step_edit;
}
if ( _playing == false && _sequencer[_selected_track].data.step[relative_step].rest == 0 ) {
sendPreviewNote(relative_step+1);
}
}
// step rest
if ( pressed(GENERIC_BUTTON_3) ) {
ATOMIC(_sequencer[_selected_track].data.step[relative_step].rest = !_sequencer[_selected_track].data.step[relative_step].rest);
if ( _playing == false && _sequencer[_selected_track].data.step[relative_step].rest == 0 ) {
sendPreviewNote(relative_step);
}
}
// step glide/tie
if ( pressed(GENERIC_BUTTON_4) ) {
// if last step is on or it has a tie, we manage tie data
if ((_sequencer[_selected_track].data.step[relative_step-1].rest == 0 || _sequencer[_selected_track].data.step[relative_step-1].tie) && _sequencer[_selected_track].data.step[relative_step].rest && relative_step != 0) {
ATOMIC(_sequencer[_selected_track].data.step[relative_step].tie = !_sequencer[_selected_track].data.step[relative_step].tie);
// otherwise glide step
} else {
ATOMIC(_sequencer[_selected_track].data.step[relative_step].glide = !_sequencer[_selected_track].data.step[relative_step].glide);
}
}
// step accent
if ( pressed(GENERIC_BUTTON_5) ) {
ATOMIC(_sequencer[_selected_track].data.step[relative_step].accent = !_sequencer[_selected_track].data.step[relative_step].accent);
if ( _playing == false && _sequencer[_selected_track].data.step[relative_step].rest == 0 ) {
sendPreviewNote(relative_step);
}
}
}
void processSequencerLeds()
{
uint8_t relative_step = uint8_t(_step_edit + _sequencer[_selected_track].data.step_init_point) % _sequencer[_selected_track].data.step_length;
// Editing First Step?
if ( _step_edit == 0 ) {
digitalWrite(GENERIC_LED_1 , HIGH);
} else {
digitalWrite(GENERIC_LED_1 , LOW);
}
// Editing Last Step?
if ( _step_edit == _sequencer[_selected_track].data.step_length-1 ) {
digitalWrite(GENERIC_LED_2 , HIGH);
} else {
digitalWrite(GENERIC_LED_2 , LOW);
}
// Rest
if ( _sequencer[_selected_track].data.step[relative_step].rest == 1 ) {
digitalWrite(GENERIC_LED_3 , HIGH);
} else {
digitalWrite(GENERIC_LED_3 , LOW);
}
// Glide/Tie
uint8_t tie_glide_staus = 0;
// if last step is on or it has a tie, check for tie event
if ((_sequencer[_selected_track].data.step[relative_step-1].rest == 0 || _sequencer[_selected_track].data.step[relative_step-1].tie) && _sequencer[_selected_track].data.step[relative_step].rest && relative_step != 0) {
tie_glide_staus = _sequencer[_selected_track].data.step[relative_step].tie;
} else {
tie_glide_staus = _sequencer[_selected_track].data.step[relative_step].glide;
}
if ( tie_glide_staus ) {
digitalWrite(GENERIC_LED_4 , HIGH);
} else {
digitalWrite(GENERIC_LED_4 , LOW);
}
// Accent
if ( _sequencer[_selected_track].data.step[relative_step].accent == 1 ) {
digitalWrite(GENERIC_LED_5 , HIGH);
} else {
digitalWrite(GENERIC_LED_5 , LOW);
}
}