update main uClock README.md to reflect the changes on 303 step sequencer engine.

pull/7/head
midilab 7 years ago
parent f7c6b04d48
commit 44dd9e7df0
  1. 178
      README.md

@ -22,6 +22,60 @@ Here a few examples on the usage of Clock library for MIDI devices, keep in mind
If you dont want to build a MIDI interface and you are going to use your arduino only with your PC, you can use a Serial-to-Midi bridge and connects your arduino via USB cable to your conputer to use it as a MIDI tool [like this one](http://projectgus.github.io/hairless-midiserial/). If you dont want to build a MIDI interface and you are going to use your arduino only with your PC, you can use a Serial-to-Midi bridge and connects your arduino via USB cable to your conputer to use it as a MIDI tool [like this one](http://projectgus.github.io/hairless-midiserial/).
### A Simple MIDI Sync Box sketch example
Here is a example on how to create a simple MIDI Sync Box
```c++
#include <uClock.h>
// MIDI clock, start and stop byte definitions - based on MIDI 1.0 Standards.
#define MIDI_CLOCK 0xF8
#define MIDI_START 0xFA
#define MIDI_STOP 0xFC
// The callback function wich will be called by Clock each Pulse of 96PPQN clock resolution.
void ClockOut96PPQN(uint32_t * tick) {
// Send MIDI_CLOCK to external gears
Serial.write(MIDI_CLOCK);
}
// The callback function wich will be called when clock starts by using Clock.start() method.
void onClockStart() {
Serial.write(MIDI_START);
}
// The callback function wich will be called when clock stops by using Clock.stop() method.
void onClockStop() {
Serial.write(MIDI_STOP);
}
void setup() {
// Initialize serial communication at 31250 bits per second, the default MIDI serial speed communication:
Serial.begin(31250);
// Inits the clock
uClock.init();
// Set the callback function for the clock output to send MIDI Sync message.
uClock.setClock96PPQNOutput(ClockOut96PPQN);
// Set the callback function for MIDI Start and Stop messages.
uClock.setOnClockStartOutput(onClockStart);
uClock.setOnClockStopOutput(onClockStop);
// Set the clock BPM to 126 BPM
uClock.setTempo(126);
// Starts the clock, tick-tac-tick-tac...
uClock.start();
}
// Do it whatever to interface with Clock.stop(), Clock.start(), Clock.setTempo() and integrate your environment...
void loop() {
}
```
### Acid Step Sequencer ### Acid Step Sequencer
A clone of Roland TB303 step sequencer main engine, here is a example with no user interface for interaction. If you're looking for a user interactable TB303 sequencer engine clone with user interface please take a look here https://github.com/midilab/uClock/tree/development/examples/AcidStepSequencer. A clone of Roland TB303 step sequencer main engine, here is a example with no user interface for interaction. If you're looking for a user interactable TB303 sequencer engine clone with user interface please take a look here https://github.com/midilab/uClock/tree/development/examples/AcidStepSequencer.
@ -34,11 +88,14 @@ A clone of Roland TB303 step sequencer main engine, here is a example with no us
// Sequencer config // Sequencer config
#define STEP_MAX_SIZE 16 #define STEP_MAX_SIZE 16
#define SEQUENCER_MIN_BPM 50
#define SEQUENCER_MAX_BPM 177
#define NOTE_LENGTH 4 // min: 1 max: 5 DO NOT EDIT BEYOND!!! #define NOTE_LENGTH 4 // min: 1 max: 5 DO NOT EDIT BEYOND!!!
#define NOTE_VELOCITY 90 #define NOTE_VELOCITY 90
#define ACCENT_VELOCITY 127 #define ACCENT_VELOCITY 127
#define NOTE_STACK_SIZE 3 // 1 for no glide note, other 2 for overlap glide notes
// MIDI modes // MIDI config
#define MIDI_CHANNEL 0 // 0 = channel 1 #define MIDI_CHANNEL 0 // 0 = channel 1
// Sequencer data // Sequencer data
@ -58,10 +115,10 @@ typedef struct
int8_t length; int8_t length;
} STACK_NOTE_DATA; } STACK_NOTE_DATA;
STACK_NOTE_DATA _note_stack[2]; STACK_NOTE_DATA _note_stack[NOTE_STACK_SIZE];
bool _playing = false; bool _playing = false;
uint16_t _step = 0; uint16_t _step, _step_edit = 0;
uint16_t _step_length = STEP_MAX_SIZE; uint16_t _step_length = STEP_MAX_SIZE;
// MIDI clock, start, stop, note on and note off byte definitions - based on MIDI 1.0 Standards. // MIDI clock, start, stop, note on and note off byte definitions - based on MIDI 1.0 Standards.
@ -84,33 +141,37 @@ void sendMidiMessage(uint8_t command, uint8_t byte1, uint8_t byte2)
// Each call represents exactly one step here. // Each call represents exactly one step here.
void ClockOut16PPQN(uint32_t * tick) void ClockOut16PPQN(uint32_t * tick)
{ {
uint16_t step; uint16_t step, length;
bool glide_ahead;
// get actual step. // get actual step.
_step = *tick % _step_length; _step = *tick % _step_length;
// send note on only if this step are not in rest mode // send note on only if this step are not in rest mode
if ( _sequencer[_step].rest == false ) { if ( _sequencer[_step].rest == false ) {
// send note on
sendMidiMessage(NOTE_ON, _sequencer[_step].note, _sequencer[_step].accent ? ACCENT_VELOCITY : NOTE_VELOCITY); sendMidiMessage(NOTE_ON, _sequencer[_step].note, _sequencer[_step].accent ? ACCENT_VELOCITY : NOTE_VELOCITY);
// do we have a glide ahead us?
// check for glide event ahead of _step
step = _step; step = _step;
for ( uint16_t i = 1; i < _step_length; i++ ) { for ( uint16_t i = 1; i < _step_length; i++ ) {
++step; ++step;
step = step % _step_length; step = step % _step_length;
if ( _sequencer[step].glide == true && _sequencer[step].rest == false ) { if ( _sequencer[step].glide == true && _sequencer[step].rest == false ) {
_note_stack[1].note = _sequencer[_step].note; length = NOTE_LENGTH + (i * 6);
_note_stack[1].length = NOTE_LENGTH + (i * 6);
glide_ahead = true;
break; break;
} else if ( _sequencer[step].rest == false ) { } else if ( _sequencer[step].rest == false ) {
glide_ahead = false; length = NOTE_LENGTH;
break; break;
} }
} }
if ( glide_ahead == false ) {
_note_stack[0].note = _sequencer[_step].note; // find a free note stack to fit in
_note_stack[0].length = NOTE_LENGTH; for ( uint8_t i = 0; i < NOTE_STACK_SIZE; i++ ) {
if ( _note_stack[i].length == -1 ) {
_note_stack[i].note = _sequencer[_step].note;
_note_stack[i].length = length;
return;
}
} }
} }
} }
@ -122,20 +183,13 @@ void ClockOut96PPQN(uint32_t * tick)
Serial.write(MIDI_CLOCK); Serial.write(MIDI_CLOCK);
// handle note on stack // handle note on stack
// [1] is notes to be glided, its in hold on mode until we reach the glided step for ( uint8_t i = 0; i < NOTE_STACK_SIZE; i++ ) {
if ( _note_stack[1].length != -1 ) { if ( _note_stack[i].length != -1 ) {
--_note_stack[1].length; --_note_stack[i].length;
if ( _note_stack[1].length == 0 ) { if ( _note_stack[i].length == 0 ) {
sendMidiMessage(NOTE_OFF, _note_stack[1].note, 0); sendMidiMessage(NOTE_OFF, _note_stack[i].note, 0);
_note_stack[1].length = -1; _note_stack[i].length = -1;
}
} }
// [0] is the actual step note stack
if ( _note_stack[0].length != -1 ) {
--_note_stack[0].length;
if ( _note_stack[0].length == 0 ) {
sendMidiMessage(NOTE_OFF, _note_stack[0].note, 0);
_note_stack[0].length = -1;
} }
} }
} }
@ -144,14 +198,18 @@ void ClockOut96PPQN(uint32_t * tick)
void onClockStart() void onClockStart()
{ {
Serial.write(MIDI_START); Serial.write(MIDI_START);
_playing = true;
} }
// The callback function wich will be called when clock stops by using Clock.stop() method. // The callback function wich will be called when clock stops by using Clock.stop() method.
void onClockStop() void onClockStop()
{ {
Serial.write(MIDI_STOP); Serial.write(MIDI_STOP);
sendMidiMessage(NOTE_OFF, _note_stack[1].note, 0); for ( uint8_t i = 0; i < NOTE_STACK_SIZE; i++ ) {
sendMidiMessage(NOTE_OFF, _note_stack[0].note, 0); sendMidiMessage(NOTE_OFF, _note_stack[i].note, 0);
_note_stack[i].length = -1;
}
_playing = false;
} }
void setup() void setup()
@ -184,71 +242,25 @@ void setup()
_sequencer[i].rest = false; _sequencer[i].rest = false;
} }
// starts the sequencer // initing note stack data
uClock.start(); for ( uint8_t i = 0; i < NOTE_STACK_SIZE; i++ ) {
_note_stack[i].note = 0;
_note_stack[i].length = -1;
}
// pins, buttons, leds and pots config // pins, buttons, leds and pots config
//configureYourUserInterface(); //configureYourUserInterface();
// start sequencer
uClock.start();
} }
// User interaction goes here // User interaction goes here
void loop() void loop()
{ {
// Controls your 303 engine interacting with user here...
//processYourButtons(); //processYourButtons();
//processYourLeds(); //processYourLeds();
//processYourPots(); //processYourPots();
} }
``` ```
### A Simple MIDI Sync Box sketch example
Here is a example on how to create a simple MIDI Sync Box
```c++
#include <uClock.h>
// MIDI clock, start and stop byte definitions - based on MIDI 1.0 Standards.
#define MIDI_CLOCK 0xF8
#define MIDI_START 0xFA
#define MIDI_STOP 0xFC
// The callback function wich will be called by Clock each Pulse of 96PPQN clock resolution.
void ClockOut96PPQN(uint32_t * tick) {
// Send MIDI_CLOCK to external gears
Serial.write(MIDI_CLOCK);
}
// The callback function wich will be called when clock starts by using Clock.start() method.
void onClockStart() {
Serial.write(MIDI_START);
}
// The callback function wich will be called when clock stops by using Clock.stop() method.
void onClockStop() {
Serial.write(MIDI_STOP);
}
void setup() {
// Initialize serial communication at 31250 bits per second, the default MIDI serial speed communication:
Serial.begin(31250);
// Inits the clock
uClock.init();
// Set the callback function for the clock output to send MIDI Sync message.
uClock.setClock96PPQNOutput(ClockOut96PPQN);
// Set the callback function for MIDI Start and Stop messages.
uClock.setOnClockStartOutput(onClockStart);
uClock.setOnClockStopOutput(onClockStop);
// Set the clock BPM to 126 BPM
uClock.setTempo(126);
// Starts the clock, tick-tac-tick-tac...
uClock.start();
}
// Do it whatever to interface with Clock.stop(), Clock.start(), Clock.setTempo() and integrate your environment...
void loop() {
}
```
Loading…
Cancel
Save