2019-06-28 01:03:40 +02:00
# include <MIDI.h>
# include <HID.h>
2019-07-06 03:39:35 +02:00
# include <Wire.h>
2019-07-10 03:55:27 +02:00
# include <EEPROM.h>
2019-07-06 03:39:35 +02:00
# include <Adafruit_MPR121.h>
2019-06-28 01:03:40 +02:00
2019-06-29 02:42:38 +02:00
# define BPQN 24 // Ableton sends 24, VCV rack only one, by standard should be 24?
2019-06-27 18:58:37 +02:00
# define NOTEOffset 36
2019-06-30 00:39:01 +02:00
# define DRUMSHIFT 6
2019-06-27 18:58:37 +02:00
# define drumOffset 60
2019-07-10 03:55:27 +02:00
2019-03-08 21:10:15 +01:00
# define MINUTE 60000
2019-07-10 03:55:27 +02:00
# define INTERVAL 15 // How many minutes between autosave
2019-03-09 15:23:18 +01:00
# define MIDICLOCK 0xf8
2019-07-10 03:55:27 +02:00
2019-06-27 18:58:37 +02:00
# define MAXKEYS 48
2019-07-09 21:21:15 +02:00
# define MAXDPAD 7
2019-07-08 02:45:50 +02:00
# define MAXSTEP 64
2019-07-10 03:55:27 +02:00
# define MAXCHANNEL 6
# define NKEYS 12
# define NOCTAVES 4
2019-07-04 16:11:44 +02:00
# define NBITS 6
2019-07-10 03:55:27 +02:00
2019-07-08 02:45:50 +02:00
# define DEBOUNCE 100
2018-10-31 17:18:50 +01:00
2019-03-08 21:10:15 +01:00
MIDI_CREATE_DEFAULT_INSTANCE ( ) ;
2019-06-28 01:03:40 +02:00
2019-03-10 02:33:59 +01:00
typedef struct SequencerStep * link ;
2019-07-10 03:55:27 +02:00
typedef struct SavePoint {
int headAddr [ MAXCHANNEL ] ;
int tailAddr [ MAXCHANNEL ] ;
} save_p ;
2018-10-31 17:18:50 +01:00
2019-03-10 02:33:59 +01:00
typedef struct SequencerStep {
2019-07-10 03:55:27 +02:00
int kboard_s [ 4 ] ;
int dpad_s ;
2019-06-29 02:42:38 +02:00
unsigned short stepnumber ;
2019-03-10 02:33:59 +01:00
link next ;
} step ;
2019-03-09 15:23:18 +01:00
2019-07-10 03:55:27 +02:00
save_p saveH ;
2019-03-09 19:14:18 +01:00
// PIN DECLARATIONS
2019-07-10 03:55:27 +02:00
int NOTE [ NKEYS ] = { // Pins used to read each note (C is 0, B is 11)
2019-03-09 15:23:18 +01:00
22 , 24 , 26 , 28 , 30 , 32 , 34 , 36 , 38 , 40 , 42 , 44 } ;
2019-07-10 03:55:27 +02:00
int OCTAVE [ NOCTAVES ] = { // Pins associated to each OCTAVE's contact bar
2019-03-09 15:23:18 +01:00
12 , 9 , 8 , 10 } ;
2019-07-04 16:11:44 +02:00
int LEDS [ NBITS ] = { // Pins used for leds
2019-07-09 21:21:15 +02:00
5 , 4 , 2 , 14 , 16 , 18 } ;
int OW = 3 ; // Pin used for overwrite switch
2019-07-08 02:45:50 +02:00
int NEXT = 51 ; // Pin used for next step switch
2019-07-06 03:39:35 +02:00
int DEL = 11 ; // Capacitive button used for DELETE button
int PLUS = 10 ; // Capacitive button used for PLUS button
int MINUS = 9 ; // Capacitive button used for MINUS button
2019-07-19 17:38:15 +02:00
int ARP = 7 ; // Capacitive button used for ARP button
2019-03-09 19:14:18 +01:00
2019-07-10 03:55:27 +02:00
// USEFUL ITERABLES
2019-07-06 03:39:35 +02:00
int pentathonic [ 10 ] = { // Used to quantize drum notes
0 , 2 , 5 , 7 , 9 , 12 , 14 , 17 , 19 , 21 } ;
2019-07-10 03:55:27 +02:00
int loadingDisplay [ 6 ] = {
1 , 3 , 7 , 15 , 31 , 63 } ;
2019-03-09 19:14:18 +01:00
2019-03-10 02:33:59 +01:00
// PLACEHOLDERS
2019-03-09 19:14:18 +01:00
byte velocity = 100 ; //
2019-07-08 02:45:50 +02:00
int bpm = 360 ; //
2019-03-09 19:14:18 +01:00
2019-06-30 00:39:01 +02:00
// SEQUENCER POINTERS AND RELATED ARRAYS
link head [ 6 ] ;
link current [ 6 ] ;
link previous ;
unsigned short nstep [ 6 ] ; // Keeps track of the sequencer steps
bool mute [ 6 ] ;
byte channel ; // Current selected channel. Drums are shifted of DRUMSHIFT channels (so channels can only be 6)
2019-03-10 02:33:59 +01:00
// SYSTEM VARIABLES
2019-07-19 17:38:15 +02:00
int arp [ 2 ] ; // arp[0] = OCTAVE, arp[1] = KEY (arp[0] for iterations, arp[1] for shifting)
2019-03-09 19:14:18 +01:00
int midiclock = 0 ; // Used to sync with MIDI clock
2019-07-19 17:38:15 +02:00
bool arpeggiating = LOW ; // Goes HIGH if the user is requesting an arpeggio
2019-07-06 04:09:00 +02:00
bool plus_step = LOW ; // This is used to remember the addition of a step
bool minus_step = LOW ; // This is used to remember the deletion of a step
bool clear_step = LOW ; // This is used to remember the clearing of a step
2019-06-30 00:39:01 +02:00
bool chan_up = LOW ; // Only for now because I have few buttons :C
2019-07-08 02:45:50 +02:00
bool next_step = LOW ; // Used to wait for a full switch cycle
2019-07-19 17:38:15 +02:00
bool overwrite = LOW ;
2019-06-27 18:58:37 +02:00
int sem_beat = 0 ; // Basic semaphore used to sync with MIDI beat
int sem_gate = 0 ; // Basic semaphore used for gate timing
2019-07-10 03:55:27 +02:00
unsigned long last_gate ; // Gate start time for last sequencer step
unsigned long last_next ;
unsigned long last_save ;
unsigned long gate_length = 200 ; // ms of keypress if arpeggiator
2019-06-27 18:58:37 +02:00
bool dpadhit = LOW ; // If any drum pad has been hit in this cycle, this is true
2019-07-10 03:55:27 +02:00
int npressed ; // Number of keys pressed, used to avoid doing anything when no keys are pressed
int kboard [ 4 ] ; // Last status of keyboard
int dpad ; // Last status of Capacitive Buttons
int cap_read ;
int difference = 0 ; // Used in many places, might as well be a global variable
2019-03-09 15:23:18 +01:00
2019-07-06 03:39:35 +02:00
Adafruit_MPR121 cap = Adafruit_MPR121 ( ) ;
2018-11-11 01:11:49 +01:00
2019-03-04 18:54:22 +01:00
void setup ( ) {
2019-07-10 03:55:27 +02:00
display ( loadingDisplay [ 0 ] ) ;
2019-07-22 16:52:02 +02:00
for ( int cOCTAVE = 0 ; cOCTAVE < NOCTAVES ; cOCTAVE + + ) pinMode ( OCTAVE [ cOCTAVE ] , INPUT ) ; // These have to be inputs, otherwise they'll sink current and mess with notes above octaves
2019-07-10 03:55:27 +02:00
for ( int cNOTE = 0 ; cNOTE < NKEYS ; cNOTE + + ) pinMode ( NOTE [ cNOTE ] , INPUT ) ;
2019-07-04 16:11:44 +02:00
for ( int cLED = 0 ; cLED < NBITS ; cLED + + ) pinMode ( LEDS [ cLED ] , OUTPUT ) ;
2019-07-10 03:55:27 +02:00
pinMode ( OW , INPUT_PULLUP ) ; // Used for overwrite switch
pinMode ( NEXT , INPUT_PULLUP ) ;
display ( loadingDisplay [ 1 ] ) ;
2019-07-21 16:19:51 +02:00
MIDI . begin ( 1 ) ; // was using MIDI_CHANNEL_OFF
MIDI . setHandleClock ( clocksync ) ;
MIDI . setHandleControlChange ( midisettings ) ;
2019-07-10 03:55:27 +02:00
display ( loadingDisplay [ 2 ] ) ;
2019-06-30 02:55:50 +02:00
for ( int i = 0 ; i < 6 ; i + + ) {
2019-06-30 00:39:01 +02:00
current [ i ] = NULL ;
head [ i ] = NULL ;
nstep [ i ] = 0 ;
mute [ i ] = LOW ;
}
2019-07-10 03:55:27 +02:00
display ( loadingDisplay [ 3 ] ) ;
for ( int cOCTAVE = 0 ; cOCTAVE < NOCTAVES ; cOCTAVE + + ) kboard [ cOCTAVE ] = 0 ;
dpad = 0 ;
2019-07-19 17:38:15 +02:00
arp [ 0 ] = 0 ;
arp [ 1 ] = 0 ;
2019-07-10 03:55:27 +02:00
cap_read = 0 ;
2019-06-30 02:55:50 +02:00
channel = ( byte ) 1 ;
2019-07-10 03:55:27 +02:00
display ( loadingDisplay [ 4 ] ) ;
while ( ! cap . begin ( 0x5A ) ) delay ( 10 ) ; // If MPR121 is not ready, wait for it
display ( loadingDisplay [ 5 ] ) ;
loadAll ( ) ;
last_save = millis ( ) ;
2019-07-08 02:45:50 +02:00
last_gate = millis ( ) ;
last_next = millis ( ) ;
2018-11-11 02:00:08 +01:00
}
2019-03-04 18:54:22 +01:00
void loop ( ) {
2019-07-08 02:45:50 +02:00
cap_read = cap . touched ( ) ;
2019-07-21 16:19:51 +02:00
MIDI . read ( ) ;
2019-07-06 03:39:35 +02:00
2019-07-21 16:19:51 +02:00
if ( next_step ! = ( bool ) ! digitalRead ( NEXT ) ) { // Manual step control
next_step = ( bool ) ! digitalRead ( NEXT ) ;
if ( millis ( ) > last_next + DEBOUNCE & & next_step = = HIGH ) {
last_next = millis ( ) ;
sem_beat + + ;
}
}
if ( ( cap_read > > 8 ) & 1 ) { // Only for now! Needed to change channel
2019-07-08 02:45:50 +02:00
for ( int i = 0 ; i < NBITS ; i + + ) digitalWrite ( LEDS [ i ] , LOW ) ;
digitalWrite ( LEDS [ channel - 1 ] , HIGH ) ;
}
else if ( current [ channel - 1 ] = = NULL ) display ( analogRead ( channel ) ) ;
2019-07-06 03:39:35 +02:00
else display ( current [ channel - 1 ] - > stepnumber ) ;
2019-07-06 04:09:00 +02:00
2019-07-19 17:38:15 +02:00
plus_step = plus_step | | ( bool ) ( ( cap_read > > PLUS ) & 1 ) ;
minus_step = minus_step | | ( bool ) ( ( cap_read > > MINUS ) & 1 ) ;
clear_step = clear_step | | ( bool ) ( ( cap_read > > DEL ) & 1 ) ;
arpeggiating = ( bool ) ( ( cap_read > > ARP ) & 1 ) ;
overwrite = digitalRead ( OW ) ;
2019-07-06 04:09:00 +02:00
if ( chan_up ! = ( bool ) ( ( cap_read > > 8 ) & 1 ) ) { // Used to increase channel with a button because I don't have a rotary switch (yet!)
2019-07-08 02:45:50 +02:00
chan_up = ( bool ) ( ( cap_read > > 8 ) & 1 ) ;
if ( chan_up = = HIGH ) {
channel + + ;
if ( channel > 6 ) channel = ( byte ) 1 ;
2019-07-06 04:09:00 +02:00
}
2019-07-08 02:45:50 +02:00
}
2019-06-28 01:48:24 +02:00
2019-06-27 18:58:37 +02:00
if ( sem_beat > 0 ) {
sem_beat - - ;
2019-06-29 02:42:38 +02:00
2019-07-04 16:11:44 +02:00
if ( sem_gate > 0 ) { // If step was shorter than GATE, close all open notes before next step
2019-06-27 18:58:37 +02:00
sem_gate - - ;
2019-07-19 17:38:15 +02:00
if ( arpeggiating ) playNote ( ( arp [ 0 ] * NKEYS ) + arp [ 1 ] , LOW , channel ) ;
2019-06-30 02:55:50 +02:00
for ( int chan = 0 ; chan < 6 ; chan + + ) {
2019-07-10 03:55:27 +02:00
if ( current [ chan ] = = NULL ) continue ;
for ( int i = 0 ; i < NOCTAVES ; i + + )
2019-07-19 17:38:15 +02:00
for ( int j = 0 ; j < NKEYS ; j + + ) // IF note was played AND user is not playing on this channel AND this note is not kept played
if ( ( ( current [ chan ] - > kboard_s [ i ] > > j ) & 1 ) & & ! ( chan + 1 ! = channel & & ( ( kboard [ i ] > > j ) & 1 ) ) & & ! ( ( current [ chan ] - > next - > kboard_s [ i ] > > j ) & 1 ) )
2019-07-10 03:55:27 +02:00
playNote ( ( i * NKEYS ) + j , LOW , ( byte ) chan + 1 ) ;
2019-07-04 16:11:44 +02:00
for ( int i = 0 ; i < MAXDPAD ; i + + )
2019-07-10 03:55:27 +02:00
if ( ( ( current [ chan ] - > dpad_s > > i ) & 1 ) & & ! ( chan + 1 ! = channel & & ( ( dpad > > i ) & 1 ) ) )
playDrum ( i , LOW , ( byte ) chan + 1 ) ;
}
2019-06-27 18:58:37 +02:00
}
2019-06-30 00:39:01 +02:00
2019-07-06 04:09:00 +02:00
if ( plus_step & & minus_step ) {
plus_step = LOW ;
minus_step = LOW ;
2019-06-30 00:39:01 +02:00
}
2019-07-06 04:09:00 +02:00
if ( plus_step ) {
plus_step = LOW ;
if ( nstep [ channel - 1 ] < MAXSTEP ) insertStep ( channel - 1 ) ;
2019-06-30 00:39:01 +02:00
}
2019-07-06 04:09:00 +02:00
if ( minus_step ) {
minus_step = LOW ;
if ( nstep [ channel - 1 ] > 0 ) deleteStep ( channel - 1 ) ;
2019-06-30 00:39:01 +02:00
}
2019-07-06 04:09:00 +02:00
if ( clear_step ) {
clear_step = LOW ;
if ( current [ channel - 1 ] ! = NULL ) {
2019-07-10 03:55:27 +02:00
for ( int i = 0 ; i < NOCTAVES ; i + + ) current [ channel - 1 ] - > kboard_s [ i ] = 0 ;
current [ channel - 1 ] - > dpad_s = 0 ;
2019-07-06 04:09:00 +02:00
}
}
2019-06-30 00:39:01 +02:00
2019-07-06 04:09:00 +02:00
nextStep ( ) ; // ALL STEPS INCREMENTED
2019-06-30 00:39:01 +02:00
display ( current [ channel - 1 ] - > stepnumber ) ;
2019-07-06 04:09:00 +02:00
2019-07-19 17:38:15 +02:00
if ( arpeggiating ) {
while ( npressed > 0 ) {
arp [ 1 ] + + ;
if ( arp [ 1 ] = = NKEYS ) {
arp [ 1 ] = 0 ;
arp [ 0 ] + + ;
}
if ( arp [ 0 ] = = NOCTAVES ) arp [ 0 ] = 0 ;
if ( ( kboard [ arp [ 0 ] ] > > arp [ 1 ] ) & 1 ) {
playNote ( ( arp [ 0 ] * NKEYS ) + arp [ 1 ] , HIGH , channel ) ;
if ( overwrite & & current [ channel - 1 ] ! = NULL ) {
for ( int i = 0 ; i < NOCTAVES ; i + + ) current [ channel - 1 ] - > kboard_s [ i ] = 0 ;
current [ channel - 1 ] - > kboard_s [ arp [ 0 ] ] = current [ channel - 1 ] - > kboard_s [ arp [ 0 ] ] | ( 1 < < arp [ 1 ] ) ;
}
break ;
}
}
}
2019-06-30 02:55:50 +02:00
for ( int chan = 0 ; chan < 6 ; chan + + ) {
2019-06-30 00:39:01 +02:00
if ( mute [ chan ] ) continue ;
2019-07-04 16:11:44 +02:00
if ( current [ chan ] ! = NULL ) { // PLAY all step notes in all unmuted channels
2019-07-10 03:55:27 +02:00
for ( int i = 0 ; i < NOCTAVES ; i + + )
for ( int j = 0 ; j < NKEYS ; j + + )
if ( ( ( current [ chan ] - > kboard_s [ i ] > > j ) & 1 ) & & ! ( chan + 1 = = channel & & npressed > 0 ) )
playNote ( ( i * NKEYS ) + j , HIGH , ( byte ) chan + 1 ) ;
for ( int i = 0 ; i < MAXDPAD ; i + + ) // Drums are played nonetheless because drums already layered won't overrule
if ( ( current [ chan ] - > dpad_s > > i ) & 1 )
playDrum ( i , HIGH , ( byte ) chan + 1 ) ;
2019-06-30 00:39:01 +02:00
}
2019-06-27 18:58:37 +02:00
}
2019-06-30 00:39:01 +02:00
last_gate = millis ( ) ;
sem_gate + + ;
2019-03-09 15:23:18 +01:00
}
2019-06-29 02:42:38 +02:00
2019-06-27 18:58:37 +02:00
if ( sem_gate > 0 & & ( millis ( ) - last_gate ) > gate_length ) {
sem_gate - - ;
2019-07-19 17:38:15 +02:00
if ( arpeggiating ) playNote ( ( arp [ 0 ] * NKEYS ) + arp [ 1 ] , LOW , channel ) ;
2019-06-30 02:55:50 +02:00
for ( int chan = 0 ; chan < 6 ; chan + + ) {
2019-07-10 03:55:27 +02:00
if ( current [ chan ] = = NULL ) continue ;
for ( int i = 0 ; i < NOCTAVES ; i + + )
for ( int j = 0 ; j < NKEYS ; j + + )
if ( ( ( current [ chan ] - > kboard_s [ i ] > > j ) & 1 ) & & ! ( chan + 1 ! = channel & & ( ( kboard [ i ] > > j ) & 1 ) ) )
playNote ( ( i * NKEYS ) + j , LOW , ( byte ) chan + 1 ) ;
2019-07-04 16:11:44 +02:00
for ( int i = 0 ; i < MAXDPAD ; i + + )
2019-07-10 03:55:27 +02:00
if ( ( ( current [ chan ] - > dpad_s > > i ) & 1 ) & & ! ( chan + 1 ! = channel & & ( ( dpad > > i ) & 1 ) ) )
playDrum ( i , LOW , ( byte ) chan + 1 ) ;
2019-06-30 00:39:01 +02:00
}
2019-06-27 18:58:37 +02:00
}
2019-06-29 02:42:38 +02:00
2019-06-27 18:58:37 +02:00
dpadhit = LOW ;
2019-07-10 03:55:27 +02:00
difference = dpad ^ cap_read ;
for ( int c = 0 ; c < MAXDPAD ; c + + ) {
if ( ( difference > > c ) & 1 ) playDrum ( c , ( ( cap_read > > c ) & 1 ) , channel ) ;
if ( dpadhit | | ( ( cap_read > > c ) & 1 ) ) dpadhit = HIGH ;
if ( difference ! = 0 ) dpad = cap_read ;
2019-03-08 21:10:15 +01:00
}
2019-03-10 02:33:59 +01:00
2019-06-27 18:58:37 +02:00
npressed = 0 ;
for ( int cOCTAVE = 0 ; cOCTAVE < 4 ; cOCTAVE + + ) {
2019-07-22 16:52:02 +02:00
pinMode ( OCTAVE [ cOCTAVE ] , OUTPUT ) ;
2019-06-27 18:58:37 +02:00
digitalWrite ( OCTAVE [ cOCTAVE ] , HIGH ) ;
2019-07-10 03:55:27 +02:00
npressed + = eval ( scan ( ) , cOCTAVE ) ;
2019-06-27 18:58:37 +02:00
digitalWrite ( OCTAVE [ cOCTAVE ] , LOW ) ;
2019-07-22 16:52:02 +02:00
pinMode ( OCTAVE [ cOCTAVE ] , INPUT ) ;
2019-03-09 19:14:18 +01:00
}
2019-06-28 00:14:44 +02:00
2019-07-19 17:38:15 +02:00
if ( current [ channel - 1 ] ! = NULL & & overwrite ) {
if ( ! arpeggiating & & npressed > 0 )
for ( int i = 0 ; i < NOCTAVES ; i + + ) {
difference = kboard [ i ] ^ current [ channel - 1 ] - > kboard_s [ i ] ;
if ( difference ! = 0 ) current [ channel - 1 ] - > kboard_s [ i ] = kboard [ i ] ;
}
2019-07-10 03:55:27 +02:00
if ( dpadhit ) current [ channel - 1 ] - > dpad_s = current [ channel - 1 ] - > dpad_s | dpad ; // Drum hits aren't exclusive!
2018-11-11 02:00:08 +01:00
}
2019-07-21 16:19:51 +02:00
if ( millis ( ) > last_save + ( unsigned long ) MINUTE * INTERVAL ) {
saveAll ( ) ;
last_save = millis ( ) ;
}
2018-10-31 17:21:02 +01:00
}
2019-06-27 18:58:37 +02:00
// Hardware specific functions
2019-03-04 18:56:20 +01:00
2019-07-10 03:55:27 +02:00
int scan ( ) { // This function reads the 12 NOTE pins and returns a struct
int output = 0 ;
for ( int c = 0 ; c < NKEYS ; c + + ) {
if ( digitalRead ( NOTE [ c ] ) ) output = output | ( 1 < < c ) ;
2018-11-11 01:11:49 +01:00
}
2019-03-04 18:54:22 +01:00
return output ;
2018-11-11 01:11:49 +01:00
}
2019-06-28 01:48:24 +02:00
void display ( int number ) {
2019-07-04 16:11:44 +02:00
for ( int i = 0 ; i < NBITS ; i + + ) {
2019-06-29 02:42:38 +02:00
digitalWrite ( LEDS [ i ] , number & ( unsigned short ) 1 ) ;
number = number > > 1 ;
}
2019-06-28 01:48:24 +02:00
}
2019-06-27 18:58:37 +02:00
// NOTE Functions
2019-07-10 03:55:27 +02:00
int eval ( int input , int nOct ) {
2019-03-08 21:10:15 +01:00
int pressed = 0 ;
2019-07-10 03:55:27 +02:00
int sNOTE = nOct * 12 ;
difference = kboard [ nOct ] ^ input ;
2019-03-08 21:10:15 +01:00
for ( int c = 0 ; c < 12 ; c + + ) {
2019-07-19 17:38:15 +02:00
if ( ! arpeggiating & & ( ( difference > > c ) & 1 ) ) playNote ( c + sNOTE , ( ( input > > c ) & 1 ) , channel ) ;
2019-07-10 03:55:27 +02:00
if ( ( ( input > > c ) & 1 ) ) pressed + + ;
2018-10-31 17:18:50 +01:00
}
2019-07-10 03:55:27 +02:00
if ( difference ! = 0 ) kboard [ nOct ] = input ;
2019-03-08 21:10:15 +01:00
return pressed ;
2018-11-11 01:11:49 +01:00
}
2019-06-30 00:39:01 +02:00
void playNote ( int c , bool status , byte chan ) {
2019-06-27 18:58:37 +02:00
byte n = c + NOTEOffset ;
2019-03-08 21:10:15 +01:00
if ( status = = HIGH ) {
2019-06-30 00:39:01 +02:00
MIDI . sendNoteOn ( n , velocity , chan ) ;
2019-03-08 21:10:15 +01:00
}
else if ( status = = LOW ) {
2019-06-30 00:39:01 +02:00
MIDI . sendNoteOff ( n , velocity , chan ) ;
2019-03-08 21:10:15 +01:00
}
}
2019-06-30 00:39:01 +02:00
void playDrum ( int c , bool status , byte chan ) {
2019-07-06 03:39:35 +02:00
// The note is first quantized to a pentathonic and then scaled up to start at C4.
byte n = ( byte ) ( pentathonic [ c ] + drumOffset ) ;
2019-06-27 18:58:37 +02:00
if ( status = = HIGH ) {
2019-06-30 02:55:50 +02:00
MIDI . sendNoteOn ( n , velocity , chan + ( byte ) DRUMSHIFT ) ;
2019-03-08 21:10:15 +01:00
}
2019-06-27 18:58:37 +02:00
else if ( status = = LOW ) {
2019-06-30 02:55:50 +02:00
MIDI . sendNoteOff ( n , velocity , chan + ( byte ) DRUMSHIFT ) ;
2019-03-08 21:10:15 +01:00
}
2019-03-09 19:14:18 +01:00
}
2019-07-21 16:19:51 +02:00
// MIDI callback functions
2019-07-10 03:55:27 +02:00
2019-07-21 16:19:51 +02:00
void clocksync ( ) {
midiclock + + ;
if ( midiclock = = BPQN ) {
midiclock = 0 ;
sem_beat + + ;
2019-07-10 03:55:27 +02:00
}
2019-07-21 16:19:51 +02:00
}
2019-07-10 03:55:27 +02:00
2019-07-21 16:19:51 +02:00
void midisettings ( byte channel , byte number , byte value ) {
2019-07-22 16:52:02 +02:00
if ( number = = 3 ) gate_length = ( value * 10 ) + 10 ;
2019-03-10 02:33:59 +01:00
}
2019-06-27 18:58:37 +02:00
// List management functions
2019-03-10 02:33:59 +01:00
link newStep ( ) {
return ( link ) malloc ( sizeof ( struct SequencerStep ) ) ;
}
2019-06-30 00:39:01 +02:00
bool insertStep ( byte chan ) {
2019-07-06 03:39:35 +02:00
// Creates a new enpty step and places it as next step in the channel passed as argument
2019-03-10 02:33:59 +01:00
link newS = newStep ( ) ;
2019-06-29 02:42:38 +02:00
link buffer ;
2019-06-30 02:55:50 +02:00
2019-07-09 21:21:15 +02:00
if ( newS = = NULL ) {
display ( 63 ) ;
delay ( 500 ) ;
return LOW ;
}
2019-03-10 02:33:59 +01:00
2019-07-10 03:55:27 +02:00
for ( int i = 0 ; i < NOCTAVES ; i + + ) newS - > kboard_s [ i ] = 0 ;
newS - > dpad_s = 0 ;
2019-06-27 18:58:37 +02:00
2019-06-30 02:55:50 +02:00
if ( head [ chan ] = = NULL ) {
2019-03-10 02:33:59 +01:00
newS - > next = newS ;
2019-06-29 02:42:38 +02:00
newS - > stepnumber = ( unsigned short ) 0 ;
2019-06-30 00:39:01 +02:00
current [ chan ] = newS ;
head [ chan ] = newS ;
nstep [ chan ] = 1 ;
2019-07-08 02:45:50 +02:00
return HIGH ;
2019-03-10 02:33:59 +01:00
}
2019-07-08 02:45:50 +02:00
newS - > stepnumber = current [ chan ] - > stepnumber + 1 ;
buffer = current [ chan ] - > next ;
current [ chan ] - > next = newS ;
newS - > next = buffer ;
2019-07-09 21:21:15 +02:00
int c = 0 ;
buffer = head [ chan ] ;
buffer - > stepnumber = c ;
c + + ;
buffer = buffer - > next ;
while ( buffer ! = head [ chan ] ) {
buffer - > stepnumber = c ;
c + + ;
2019-07-08 02:45:50 +02:00
buffer = buffer - > next ;
2019-03-10 02:33:59 +01:00
}
2019-07-09 21:21:15 +02:00
nstep [ chan ] = c ;
2019-07-08 02:45:50 +02:00
2019-03-10 02:33:59 +01:00
return HIGH ;
}
void nextStep ( ) {
2019-06-30 02:55:50 +02:00
for ( int chan = 0 ; chan < 6 ; chan + + ) {
if ( head [ chan ] = = NULL ) continue ;
2019-06-30 00:39:01 +02:00
current [ chan ] = current [ chan ] - > next ;
}
2019-03-10 02:33:59 +01:00
}
2019-06-30 00:39:01 +02:00
bool deleteStep ( byte chan ) {
if ( nstep [ chan ] < 1 ) return LOW ;
if ( nstep [ chan ] = = 1 ) {
2019-06-30 02:55:50 +02:00
free ( current [ chan ] ) ;
2019-06-30 00:39:01 +02:00
head [ chan ] = NULL ;
current [ chan ] = NULL ;
2019-07-06 04:09:00 +02:00
return HIGH ;
}
link buffer = current [ chan ] ;
2019-07-08 02:45:50 +02:00
while ( buffer - > next ! = current [ chan ] ) buffer = buffer - > next ; // Search for previous step
buffer - > next = current [ chan ] - > next ; // Skip step which is being deleted
if ( current [ chan ] = = head [ chan ] ) head [ chan ] = head [ chan ] - > next ; // If deleting head, head moves forward
free ( current [ chan ] ) ; // Step is actually deleted
current [ chan ] = buffer ; // Current step becomes previous step
2019-07-09 21:21:15 +02:00
int c = 0 ;
buffer = head [ chan ] ;
buffer - > stepnumber = c ;
c + + ;
buffer = buffer - > next ;
while ( buffer ! = head [ chan ] ) {
buffer - > stepnumber = c ;
c + + ;
buffer = buffer - > next ;
2019-03-10 02:33:59 +01:00
}
2019-07-09 21:21:15 +02:00
nstep [ chan ] = c ;
2019-03-10 02:33:59 +01:00
return HIGH ;
2019-07-10 03:55:27 +02:00
}
// SAVING FUNCTIONS
void saveAll ( ) {
int currAddr = ( int ) sizeof ( save_p ) ;
link buffer ;
for ( int c = 0 ; c < MAXCHANNEL ; c + + ) {
display ( loadingDisplay [ c ] ) ;
if ( current [ c ] = = NULL ) {
saveH . headAddr [ c ] = - 1 ;
saveH . tailAddr [ c ] = - 1 ;
continue ;
}
buffer = head [ c ] ;
saveH . headAddr [ c ] = currAddr ;
currAddr = saveStep ( buffer , currAddr ) ;
buffer = buffer - > next ;
while ( buffer ! = head [ c ] ) {
currAddr = saveStep ( buffer , currAddr ) ;
buffer = buffer - > next ;
}
saveH . tailAddr [ c ] = currAddr ;
}
saveHead ( saveH ) ;
}
void loadAll ( ) {
saveH = loadHead ( ) ;
int currAddr = saveH . headAddr [ 0 ] ;
link buffer ;
for ( int c = 0 ; c < MAXCHANNEL ; c + + ) {
display ( loadingDisplay [ c ] ) ;
if ( saveH . headAddr [ c ] < 0 ) continue ;
head [ c ] = newStep ( ) ;
current [ c ] = head [ c ] ;
currAddr = saveH . headAddr [ c ] ;
currAddr = loadStep ( head [ c ] , currAddr ) ;
buffer = head [ c ] ;
while ( currAddr < saveH . tailAddr [ c ] ) {
link newS = newStep ( ) ;
currAddr = loadStep ( newS , currAddr ) ;
buffer - > next = newS ;
buffer = newS ;
}
buffer - > next = head [ c ] ;
}
}
save_p loadHead ( ) {
save_p save ;
byte * pointer = ( byte * ) ( void * ) & save ;
int addr = 0 ;
for ( int i = 0 ; i < ( int ) sizeof ( save_p ) ; i + + ) {
* pointer = EEPROM . read ( addr ) ;
addr + + ;
pointer + + ;
}
return save ;
}
void saveHead ( save_p save ) {
byte * pointer = ( byte * ) ( void * ) & save ;
int addr = 0 ;
for ( int i = 0 ; i < ( int ) sizeof ( save_p ) ; i + + ) {
EEPROM . update ( addr , * pointer ) ;
addr + + ;
pointer + + ;
}
}
int saveStep ( link curr_step , int addr ) {
step buffer = * curr_step ;
buffer . next = ( link ) ( addr + ( int ) sizeof ( SequencerStep ) ) ;
byte * pointer = ( byte * ) ( void * ) & buffer ;
for ( int i = 0 ; i < ( int ) sizeof ( SequencerStep ) ; i + + ) {
EEPROM . update ( addr , * pointer ) ;
pointer + + ;
addr + + ;
}
return addr ;
}
int loadStep ( link step , int addr ) {
byte * pointer = ( byte * ) ( void * ) step ;
for ( int i = 0 ; i < ( int ) sizeof ( SequencerStep ) ; i + + ) {
* pointer = EEPROM . read ( addr ) ;
pointer + + ;
addr + + ;
}
return addr ;
2019-03-08 21:10:15 +01:00
}