You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
uClock/examples/AcidStepSequencer/DefaultUserInterface.ino

276 lines
7.2 KiB

#define SEQUENCER_MIN_BPM 50
#define SEQUENCER_MAX_BPM 177
// Ui config
#define LOCK_POT_SENSTIVITY 3
// hardware setup to fit different kinda of setups and arduino models
#define OCTAVE_POT_PIN A3
#define NOTE_POT_PIN A2
#define STEP_LENGTH_POT_PIN A1
#define TEMPO_POT_PIN A0
#define PREVIOUS_STEP_BUTTON_PIN 2
#define NEXT_STEP_BUTTON_PIN 3
#define REST_BUTTON_PIN 4
#define GLIDE_BUTTON_PIN 5
#define ACCENT_BUTTON_PIN 6
#define PLAY_STOP_BUTTON_PIN 7
#define PREVIOUS_STEP_LED_PIN 8
#define NEXT_STEP_LED_PIN 9
#define REST_LED_PIN 10
#define GLIDE_LED_PIN 11
#define ACCENT_LED_PIN 12
#define PLAY_STOP_LED_PIN 13
// User Interface data
uint16_t _step_edit = 0;
uint8_t _last_octave = 3;
uint8_t _last_note = 0;
uint8_t _bpm_blink_timer = 1;
void configureInterface()
{
// Buttons config
// use internal pullup for buttons
pinMode(PREVIOUS_STEP_BUTTON_PIN, INPUT_PULLUP);
pinMode(NEXT_STEP_BUTTON_PIN, INPUT_PULLUP);
pinMode(REST_BUTTON_PIN, INPUT_PULLUP);
pinMode(GLIDE_BUTTON_PIN, INPUT_PULLUP);
pinMode(ACCENT_BUTTON_PIN, INPUT_PULLUP);
pinMode(PLAY_STOP_BUTTON_PIN, INPUT_PULLUP);
// Leds config
pinMode(PREVIOUS_STEP_LED_PIN, OUTPUT);
pinMode(NEXT_STEP_LED_PIN, OUTPUT);
pinMode(REST_LED_PIN, OUTPUT);
pinMode(GLIDE_LED_PIN, OUTPUT);
pinMode(ACCENT_LED_PIN, OUTPUT);
pinMode(PLAY_STOP_LED_PIN, OUTPUT);
digitalWrite(PREVIOUS_STEP_LED_PIN, LOW);
digitalWrite(NEXT_STEP_LED_PIN, LOW);
digitalWrite(REST_LED_PIN, LOW);
digitalWrite(GLIDE_LED_PIN, LOW);
digitalWrite(ACCENT_LED_PIN, LOW);
digitalWrite(PLAY_STOP_LED_PIN, LOW);
// getting first value state
pressed(PREVIOUS_STEP_BUTTON_PIN);
pressed(NEXT_STEP_BUTTON_PIN);
pressed(REST_BUTTON_PIN);
pressed(GLIDE_BUTTON_PIN);
pressed(ACCENT_BUTTON_PIN);
pressed(PLAY_STOP_BUTTON_PIN);
// getting first values
getPotChanges(OCTAVE_POT_PIN, 0, 10);
getPotChanges(NOTE_POT_PIN, 0, 11);
getPotChanges(STEP_LENGTH_POT_PIN, 1, STEP_MAX_SIZE);
getPotChanges(TEMPO_POT_PIN, SEQUENCER_MIN_BPM, SEQUENCER_MAX_BPM);
lockPotsState(true);
//acidRandomize();
}
void processInterface()
{
processButtons();
processLeds();
processPots();
}
void tempoInterface(uint32_t * tick)
{
// BPM led indicator
if ( !(*tick % (96)) || (*tick == 0) ) { // first compass step will flash longer
_bpm_blink_timer = 8;
digitalWrite(PLAY_STOP_LED_PIN , HIGH);
} else if ( !(*tick % (24)) ) { // each quarter led on
digitalWrite(PLAY_STOP_LED_PIN , HIGH);
} else if ( !(*tick % _bpm_blink_timer) ) { // get led off
digitalWrite(PLAY_STOP_LED_PIN , LOW);
_bpm_blink_timer = 1;
}
}
void sendPreviewNote(uint16_t step)
{
unsigned long milliTime, preMilliTime;
sendMidiMessage(NOTE_ON, _sequencer[step].note, _sequencer[step].accent ? ACCENT_VELOCITY : NOTE_VELOCITY);
// avoid delay() call because of uClock timmer1 usage
//delay(200);
preMilliTime = millis();
while ( true ) {
milliTime = millis();
if (abs(milliTime - preMilliTime) >= 200) {
break;
}
}
sendMidiMessage(NOTE_OFF, _sequencer[step].note, 0);
}
void processPots()
{
static int8_t octave, note, step_note;
static int16_t tempo, step_length;
octave = getPotChanges(OCTAVE_POT_PIN, 0, 10);
if ( octave != -1 ) {
_last_octave = octave;
}
note = getPotChanges(NOTE_POT_PIN, 0, 11);
if ( note != -1 ) {
_last_note = note;
}
// changes on octave or note pot?
if ( octave != -1 || note != -1 ) {
ATOMIC(_sequencer[_step_edit].note = (_last_octave * 8) + _last_note);
if ( _playing == false && _sequencer[_step_edit].rest == false ) {
sendPreviewNote(_step_edit);
}
}
step_length = getPotChanges(STEP_LENGTH_POT_PIN, 1, STEP_MAX_SIZE);
if ( step_length != -1 ) {
ATOMIC(_step_length = step_length);
if ( _step_edit >= _step_length ) {
_step_edit = _step_length-1;
}
}
tempo = getPotChanges(TEMPO_POT_PIN, SEQUENCER_MIN_BPM, SEQUENCER_MAX_BPM);
if ( tempo != -1 ) {
//uClock.setTempo(tempo);
}
}
void processButtons()
{
// play/stop
if ( pressed(PLAY_STOP_BUTTON_PIN) ) {
if ( _playing == false ) {
// Starts the clock, tick-tac-tick-tac...
uClock.start();
} else {
// stop the clock
uClock.stop();
}
}
// ramdom test
//if ( pressed(PREVIOUS_STEP_BUTTON_PIN) && pressed(NEXT_STEP_BUTTON_PIN) ) {
//acidRandomize();
//return;
//}
// previous step edit
if ( pressed(PREVIOUS_STEP_BUTTON_PIN) ) {
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;
} else { // TODO: just for tests.. take this guy off here and put it on second page
acidRandomize();
}
if ( _playing == false && _sequencer[_step_edit].rest == false ) {
sendPreviewNote(_step_edit);
}
}
// next step edit
if ( pressed(NEXT_STEP_BUTTON_PIN) ) {
if ( _step_edit < _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[_step_edit].rest == false ) {
sendPreviewNote(_step_edit);
}
}
// step rest
if ( pressed(REST_BUTTON_PIN) ) {
ATOMIC(_sequencer[_step_edit].rest = !_sequencer[_step_edit].rest);
if ( _playing == false && _sequencer[_step_edit].rest == false ) {
sendPreviewNote(_step_edit);
}
}
// step glide
if ( pressed(GLIDE_BUTTON_PIN) ) {
ATOMIC(_sequencer[_step_edit].glide = !_sequencer[_step_edit].glide);
}
// step accent
if ( pressed(ACCENT_BUTTON_PIN) ) {
ATOMIC(_sequencer[_step_edit].accent = !_sequencer[_step_edit].accent);
if ( _playing == false && _sequencer[_step_edit].rest == false ) {
sendPreviewNote(_step_edit);
}
}
}
void processLeds()
{
// Editing First Step?
if ( _step_edit == 0 ) {
digitalWrite(PREVIOUS_STEP_LED_PIN , HIGH);
} else {
digitalWrite(PREVIOUS_STEP_LED_PIN , LOW);
}
// Editing Last Step?
if ( _step_edit == _step_length-1 ) {
digitalWrite(NEXT_STEP_LED_PIN , HIGH);
} else {
digitalWrite(NEXT_STEP_LED_PIN , LOW);
}
// Rest
if ( _sequencer[_step_edit].rest == true ) {
digitalWrite(REST_LED_PIN , HIGH);
} else {
digitalWrite(REST_LED_PIN , LOW);
}
// Glide
if ( _sequencer[_step_edit].glide == true ) {
digitalWrite(GLIDE_LED_PIN , HIGH);
} else {
digitalWrite(GLIDE_LED_PIN , LOW);
}
// Accent
if ( _sequencer[_step_edit].accent == true ) {
digitalWrite(ACCENT_LED_PIN , HIGH);
} else {
digitalWrite(ACCENT_LED_PIN , LOW);
}
// shut down play led if we are stoped
if ( _playing == false ) {
digitalWrite(PLAY_STOP_LED_PIN , LOW);
}
}
void acidRandomize()
{
// ramdom it all
for ( uint16_t i = 0; i < STEP_MAX_SIZE; i++ ) {
ATOMIC(_sequencer[i].note = random(36, 70)); // octave 2 to 4. octave 3 to 5 (40 - 83)
ATOMIC(_sequencer[i].accent = random(0, 2));
ATOMIC(_sequencer[i].glide = random(0, 2));
ATOMIC(_sequencer[i].rest = random(0, 1));
}
}