mirror of https://github.com/midilab/uClock
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.
276 lines
7.2 KiB
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));
|
|
}
|
|
}
|
|
|