How to create and add a new function to the LXR

From Sonic Potions Wiki
Jump to: navigation, search
       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},
               ....
  • Add the following information:
               ....
               {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 :-)
       
  • 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;
                               
                       ....
                       
                       
  • open sequencer.h file, add the line :
       void seq_setLoopLength(uint8_t length);


  • open sequencer.c file, add the function:
       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);	
       }
       }
  • compile !
  • upload on the machine with the new firmware
  • test!