How to create and add a new function to the LXR

Where to get the source: https://github.com/SonicPotions/LXR

This is a DRAFT !!!! I will correct it during the next days :-)


 * GOAL:
 * We will implement a function that change the length of all the tracks at once. A sort of loop/divide (like on the arturia spark machine). We will add a special knob in the PERF menu: when this knob is turned, the length of the tracks changes from 1 to 16 making the whole pattern ROLL :-)
 * another aim is to make you look at the difrent files, inspect them and start undestand the logic of the LXR drum system that Julian made :-)


 * First step, we start by adding a new knob 'LEN' (for Length) in the PERF menu on the LCD display.


 * Open the file 'Parameters.h', Add in the section 'enum ParamEnums' the new parameter. In our case : PAR_LOOP

example: enum ParamEnums = { ...       PAR_MIDI_NOTE1, PAR_MIDI_NOTE2, PAR_MIDI_NOTE3, PAR_MIDI_NOTE4, PAR_MIDI_NOTE5, PAR_MIDI_NOTE6, PAR_MIDI_NOTE7, // <--- YOUR parameters comes right after thoses lines... // You have to add all the new parameters right after a dedicated section in the code declaration //(otherwise you want link later the knob with the function you want to execute): PAR_LOOP, ...


 * We need to open the menu.c file. we declare our parameter and its type :

menu.c       //--- // Parameter types. These correspond with ParamEnums and entries in parameter_values const enum Datatypes PROGMEM parameter_dtypes[NUM_PARAMS] = { /*PAR_NONE*/                        DTYPE_0B127,                                                        // 0 /*PAR_OSC_WAVE_DRUM1*/        DTYPE_MENU | (MENU_WAVEFORM<<4), /*PAR_OSC_WAVE_DRUM2*/        DTYPE_MENU | (MENU_WAVEFORM<<4), /*PAR_OSC_WAVE_DRUM3*/        DTYPE_MENU | (MENU_WAVEFORM<<4), /*PAR_OSC_WAVE_SNARE*/ DTYPE_MENU | (MENU_WAVEFORM<<4), ....


 * Place your parameter at a special place, right after the section:

/*PAR_MIDI_NOTE1*/               DTYPE_NOTE_NAME, /*PAR_MIDI_NOTE2*/               DTYPE_NOTE_NAME, /*PAR_MIDI_NOTE3*/               DTYPE_NOTE_NAME, /*PAR_MIDI_NOTE4*/               DTYPE_NOTE_NAME, /*PAR_MIDI_NOTE5*/               DTYPE_NOTE_NAME, /*PAR_MIDI_NOTE6*/               DTYPE_NOTE_NAME, /*PAR_MIDI_NOTE7*/               DTYPE_NOTE_NAME, // YOUR PARAMETER comes right here and not elsewhere!!!!! /*PAR_LOOP*/                     DTYPE_1B16, // Values goes from 1 to 16 steps /*PAR_ROLL*/                        DTYPE_MENU | (MENU_ROLL_RATES<<4), /*PAR_MORPH*/                        DTYPE_0B255, ...

Here the list of parameters you can choose from...

Type of parameters: //-       enum Datatypes {       DTYPE_0B255,        //0:255 DTYPE_0B127,       //0-127 DTYPE_PM100,       //-100:100 DTYPE_MENU,               //text type outputs DTYPE_PM63,               //-63 <-> 63 DTYPE_1B16,               //1-16 DTYPE_ON_OFF,       //0-1 DTYPE_MIX_FM,       //0-1 DTYPE_TARGET_SELECTION_LFO, DTYPE_TARGET_SELECTION_VELO, DTYPE_VOICE_LFO, DTYPE_AUTOM_TARGET, DTYPE_0b1, DTYPE_NOTE_NAME, // --AS eg C#0, D 1 for note name DTYPE_0B15,               //0-15 /*15*/       /*16*/        // --AS warning, we can only have 16 on this list the way things are laid out };


 * oki, once this done, we need to fill other information in the code


 * Open the file menuPages.h


 * This array hold the whole menu structure. each voice has different pages. The pages hold the top and bottom enums to indicate which values and descriptors to show


 * in the section: const Page menuPages[NUM_PAGES][NUM_SUB_PAGES] PROGMEM ... add your MENU (we want that our knob display a name 'LEN')


 * in our case, we add TEXT_LOOP and PAR_ROLL:

const Page menuPages[NUM_PAGES][NUM_SUB_PAGES] PROGMEM = {       //page 1 - Voice 1 {       //sub page 1 - Oscillator {       TEXT_COARSE,        TEXT_FINE,        TEXT_WAVEFORM,                TEXT_RND_VOICE,TEXT_EMPTY,TEXT_EMPTY,TEXT_EMPTY,TEXT_EMPTY, PAR_COARSE1,       PAR_FINE1,        PAR_OSC_WAVE_DRUM1,        PAR_RND_VOICE1,PAR_NONE,PAR_NONE,PAR_NONE,PAR_NONE },               ...        //Page 10 // Performance Mode Menu pages --- //These pages are shown when the selected mode is the "mute/pattern select" page //there is only one page with subpages shown for the whole mode {       {		        TEXT_SHUFFLE,	TEXT_ROLL_SPEED,	TEXT_X_FADE,	TEXT_SAMPLE_RATE,		 TEXT_LOOP,	TEXT_EMPTY, PAR_SHUFFLE,	PAR_ROLL,			PAR_MORPH,		PAR_VOICE_DECIMATION_ALL,		PAR_LOOP, },       ...


 * We also need to declare the TEXT_LOOP and PAR_LOOP in other files :-)


 * Open file menu.h, go to section 'NamesEnum', add at the end the text 'TEXT_LOOP" :

enum NamesEnum {       TEXT_EMPTY = 0,                                        //0 TEXT_COARSE, TEXT_FINE, TEXT_ATTACK, TEXT_DECAY, TEXT_PITCH_DECAY, TEXT_MOD_AMOUNT, ....       ....        TEXT_BAR_RESET_MODE, TEXT_MIDI_CHAN_GLOBAL, TEXT_LOOP,       // rstephane: LOOP text NUM_NAMES };


 * Open the menu.c file, go to section valueNames

const Name valueNames[NUM_NAMES] PROGMEM = {               {SHORT_EMPTY,CAT_EMPTY,LONG_EMPTY}, ....

....               {SHORT_BAR_RESET_MODE, CAT_SEQUENCER, LONG_BAR_RESET_MODE}, // TEXT_BAR_RESET_MODE {SHORT_CHANNEL, CAT_MIDI, LONG_MIDI_CHANNEL}, // TEXT_MIDI_CHAN_GLOBAL '{SHORT_LOOP, CAT_SEQUENCER, LONG_LOOP}, // We declare it at the end of the section :-)
 * Add the following information:


 * now, open the MenuText.h file to declare the short and long version of the TEXT (TEXT_LOOP)
 * go to section 'const char longNames[][16] PROGMEM = ' and 'const char shortNames[][4] PROGMEM = '
 * add the parameters marked in bold:

const char shortNames[][4] PROGMEM = {       {""},        {"coa"}, {"fin"}, {"atk"}, {"dec"}, {"eg2"}, ....       {"co2"},  // trigger clock out2 ppq {"pcr"}, // pattern change resets bar counter {"LEN"}, // rstephane: LEN for LOOP :-)       };

const char longNames[][16] PROGMEM = {       {""},        //01234567        {"Coarse"}, {"Fine"}, {"Attack"}, {"Decay"}, {"Amount"}, ....       {"Out2 PPQ"}, {"Gate Mode"}, {"PCReset" }, // reset bar counter on manual pattern change {"Loop"}, // rstephane: LOOP LONG text };


 * If you want you can already compile and see the results: under the PERF sub menu, your should see 'LEN' on the first knob.
 * Now, we will create our function
 * open midimessage.h file

//for all parameters above 127 <- our case enum {       ....        // Again, place your parameter at a special place, right after the section: CC2_MIDI_NOTE1, CC2_MIDI_NOTE2, CC2_MIDI_NOTE3, CC2_MIDI_NOTE4, CC2_MIDI_NOTE5, CC2_MIDI_NOTE6, CC2_MIDI_NOTE7, // s/b 111 i think // YOUR PARAMETER comes right here and not elsewhere!!!!! // When the knob is turned, it send the CC2_LOOP message CC2_LOOP, ....       }        Param2Enums;


 * open MidiParser.c file

//---       /** handle all incoming CCs and invoke action*/ void midiParser_ccHandler(MidiMsg msg, uint8_t updateOriginalValue) {       ...        else //MIDI_CC2 {               const uint16_t paramNr = msg.data1+1 + 127;

if(updateOriginalValue) { midiParser_originalCcValues[paramNr] = msg.data2; }               switch(msg.data1) {

case CC2_TRANS1_WAVE: voiceArray[0].transGen.waveform = msg.data2; break;

case CC2_TRANS1_VOL: voiceArray[0].transGen.volume = msg.data2/127.f;                               break;

...                       case CC2_MUTE_1: case CC2_MUTE_2: case CC2_MUTE_3: case CC2_MUTE_4: case CC2_MUTE_5: case CC2_MUTE_6: case CC2_MUTE_7: {                               const uint8_t voiceNr = msg.data1 - CC2_MUTE_1; if(msg.data2 == 0) {                                       seq_setMute(voiceNr,0); }                               else {                                       seq_setMute(voiceNr,1); }

}                               break; //                           // rstephane MY FUNCTIONS '''case CC2_LOOP: if(msg.data2 == 16) // reset the loop ! {	// we stop the loop effect and // go back to prevoious track lenght seq_setLoopLength(16); }                                  else {	// we change the tracks lenght seq_setLoopLength(msg.data2); }                                  break;''' default: break; ....

void seq_setLoopLength(uint8_t length);
 * open sequencer.h file, add the line :

void seq_setLoopLength(uint8_t length) {       uint8_t i;        // we set the new Loop Track Lenght for(i=0;i<NUM_TRACKS;i++) { seq_setTrackLength(i, length); }       }
 * open sequencer.c file, add the function:


 * compile !
 * upload on the machine with the new firmware
 * test!