Difference between revisions of "How to create and add a new function to the LXR"

From Sonic Potions Wiki
Jump to: navigation, search
 
(16 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 +
        Where to get the source:
 +
        https://github.com/SonicPotions/LXR
 +
 
This is a DRAFT !!!! I will correct it during the next days :-)
 
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 :-)
+
* 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 :-)
  
- We start by adding a new knob 'LEN' (for Length) in  the PERF menu on the LCD display.
+
* 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', we first declare our parameter and its type.
+
* Open the file ''''Parameters.h'''', Add in the section 'enum ParamEnums' the new parameter. In our case : PAR_LOOP
  
add in the section: 'enum ParamEnums' ... your new parameter. In our case we wil add the parameter : PAR_LOOP
+
        example:  
 
+
       
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):
+
        enum ParamEnums = {
 
+
        ...
enum ParamEnums ...
 
 
         PAR_MIDI_NOTE1,
 
         PAR_MIDI_NOTE1,
 
         PAR_MIDI_NOTE2,
 
         PAR_MIDI_NOTE2,
Line 18: Line 22:
 
         PAR_MIDI_NOTE5,
 
         PAR_MIDI_NOTE5,
 
         PAR_MIDI_NOTE6,
 
         PAR_MIDI_NOTE6,
         PAR_MIDI_NOTE7,
+
         PAR_MIDI_NOTE7, // <--- YOUR parameters comes right after thoses lines...
        // 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):
         // rstephane MY VALUES ADDED FOR LOOP FUNCTION
+
         '''PAR_LOOP,'''      
         PAR_LOOP,     
+
        ...
--
+
 
  
Now, let's go the the menu text, we want that our knob display a name 'FILTER' or in our case 'RANDOM' .. well we will set it to 'RND' to make it short on the LCD screen.
+
* We need to open the '''menu.c''' file. we declare our parameter and its type :
  
We need to open the menu.c file.
 
  
menu.c
+
        menu.c
//---------------------------------------------------------------
+
        //---------------------------------------------------------------
// Parameter types. These correspond with ParamEnums and entries in parameter_values
+
        // Parameter types. These correspond with ParamEnums and entries in parameter_values
const enum Datatypes PROGMEM parameter_dtypes[NUM_PARAMS] = {
+
        const enum Datatypes PROGMEM parameter_dtypes[NUM_PARAMS] = {
 
             /*PAR_NONE*/                        DTYPE_0B127,                                                        // 0
 
             /*PAR_NONE*/                        DTYPE_0B127,                                                        // 0
 
             /*PAR_OSC_WAVE_DRUM1*/        DTYPE_MENU | (MENU_WAVEFORM<<4),
 
             /*PAR_OSC_WAVE_DRUM1*/        DTYPE_MENU | (MENU_WAVEFORM<<4),
Line 38: Line 41:
 
             /*PAR_OSC_WAVE_DRUM3*/        DTYPE_MENU | (MENU_WAVEFORM<<4),
 
             /*PAR_OSC_WAVE_DRUM3*/        DTYPE_MENU | (MENU_WAVEFORM<<4),
 
             /*PAR_OSC_WAVE_SNARE*/  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:
  
Again, place your parameter at a special place, right after the section:
+
            /*PAR_MIDI_NOTE1*/                DTYPE_NOTE_NAME,
/*PAR_MIDI_NOTE1*/                DTYPE_NOTE_NAME,
 
 
             /*PAR_MIDI_NOTE2*/                DTYPE_NOTE_NAME,
 
             /*PAR_MIDI_NOTE2*/                DTYPE_NOTE_NAME,
 
             /*PAR_MIDI_NOTE3*/                DTYPE_NOTE_NAME,
 
             /*PAR_MIDI_NOTE3*/                DTYPE_NOTE_NAME,
Line 48: Line 52:
 
             /*PAR_MIDI_NOTE6*/                DTYPE_NOTE_NAME,
 
             /*PAR_MIDI_NOTE6*/                DTYPE_NOTE_NAME,
 
             /*PAR_MIDI_NOTE7*/                DTYPE_NOTE_NAME,
 
             /*PAR_MIDI_NOTE7*/                DTYPE_NOTE_NAME,
 +
         
 
             // YOUR PARAMETER comes right here and not elsewhere!!!!!
 
             // YOUR PARAMETER comes right here and not elsewhere!!!!!
           
+
             /'''*PAR_LOOP*/                     DTYPE_1B16,''' // Values goes from 1 to 16 steps
            // rstephane MY VALUES ADDED FOR RANDOM FUNCTION
 
             /*PAR_RND_VOICE1*/       DTYPE_ON_OFF, // choose the type of your parameter, a definition of the parameter type is shown right after....
 
 
              
 
              
 
             /*PAR_ROLL*/                        DTYPE_MENU | (MENU_ROLL_RATES<<4),
 
             /*PAR_ROLL*/                        DTYPE_MENU | (MENU_ROLL_RATES<<4),
 
             /*PAR_MORPH*/                        DTYPE_0B255,
 
             /*PAR_MORPH*/                        DTYPE_0B255,
                ....
+
            ...
 
                  
 
                  
Type of parameters:
+
 
//-----------------------------------------------------------------
+
Here the list of parameters you can choose from...
enum Datatypes
+
 
{
+
        Type of parameters:
 +
        //-----------------------------------------------------------------
 +
        enum Datatypes
 +
        {
 
         DTYPE_0B255,        //0:255
 
         DTYPE_0B255,        //0:255
 
         DTYPE_0B127,        //0-127
 
         DTYPE_0B127,        //0-127
Line 79: Line 85:
 
         /*16*/
 
         /*16*/
 
         // --AS warning, we can only have 16 on this list the way things are laid out
 
         // --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
  
oki, once this done, we need to fill other infformation in the code
+
* Open the file '''menuPages.h'''
  
Open the* 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
  
/** This array hold the whole menu structure.
+
* in the section: const Page menuPages[NUM_PAGES][NUM_SUB_PAGES] PROGMEM ... add your MENU (we want that our knob display a name 'LEN')
each voice has different pages. The pages hold the top and bottom enums to indicate which values and desriptors to show
 
*/
 
  
in the section:  
+
* in our case, we add TEXT_LOOP and PAR_ROLL:
const Page menuPages[NUM_PAGES][NUM_SUB_PAGES] PROGMEM =
 
                ....
 
add your MENU !
 
  
in our case: we want to create an random knob for its voice. this new button/parameter will appear when we have selected  the 'OSC' menu
+
        const Page menuPages[NUM_PAGES][NUM_SUB_PAGES] PROGMEM =
 
+
        {
so we have:
 
 
 
const Page menuPages[NUM_PAGES][NUM_SUB_PAGES] PROGMEM =
 
{
 
 
         //page 1 - Voice 1
 
         //page 1 - Voice 1
 
         {
 
         {
                //sub page 1 - Oscillator
+
        //sub page 1 - Oscillator
                {
+
        {
                        TEXT_COARSE,        TEXT_FINE,        TEXT_WAVEFORM,                TEXT_RND_VOICE,TEXT_EMPTY,TEXT_EMPTY,TEXT_EMPTY,TEXT_EMPTY,
+
        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
+
        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,
 +
        },
 +
        ...
  
you will noticed two parameters:
 
TEXT_RND_VOICE and PAR_RND_VOICE1
 
  
those parameter are important as the program will display on the LCD the menu names that appears in this section, so if we want to show a new menu or function, we need to add it in this section/file.
+
* We also need to declare the TEXT_LOOP and PAR_LOOP in other files :-)
  
but we need now to declare the TEXT_RND_VOICE1 and PAR_RND_VOICE1 in other files :-)
+
* Open file '''menu.h''', go to section 'NamesEnum', add at the end the text 'TEXT_LOOP" :  
  
Open file menu.h
+
        enum NamesEnum
go to section
+
        {
 
 
enum NamesEnum
 
{
 
 
         TEXT_EMPTY = 0,                                        //0
 
         TEXT_EMPTY = 0,                                        //0
 
         TEXT_COARSE,
 
         TEXT_COARSE,
Line 130: Line 133:
 
         TEXT_MOD_AMOUNT,                 
 
         TEXT_MOD_AMOUNT,                 
 
         ....
 
         ....
 
add at the end, the text 'TEXT_RND_VOICE1" :
 
 
         ....
 
         ....
 
         TEXT_BAR_RESET_MODE,
 
         TEXT_BAR_RESET_MODE,
 
         TEXT_MIDI_CHAN_GLOBAL,
 
         TEXT_MIDI_CHAN_GLOBAL,
         TEXT_RND_VOICE,        // rstephane: random text  
+
         '''TEXT_LOOP''',        // rstephane: LOOP text  
 
         NUM_NAMES
 
         NUM_NAMES
};
+
        };
 +
                               
  
+
+
* Open the '''menu.c''' file, go to section '''valueNames'''
  
Open Cc2Text.c
+
        const Name valueNames[NUM_NAMES] PROGMEM =
 
+
        {
//Voice 1 - Drum 1
 
//  1 Oscillator
 
{TEXT_COARSE, PAR_COARSE1},                        //2
 
{TEXT_FINE, PAR_FINE1},
 
{TEXT_WAVEFORM, PAR_OSC_WAVE_DRUM1},
 
{TEXT_RND_VOICE, PAR_RND_VOICE1}, // rstephane : added random button                                       
 
                                       
 
Now,
 
Open the menu.c file
 
go to section valueNames:
 
 
 
const Name valueNames[NUM_NAMES] PROGMEM =
 
{
 
 
                 {SHORT_EMPTY,CAT_EMPTY,LONG_EMPTY},
 
                 {SHORT_EMPTY,CAT_EMPTY,LONG_EMPTY},
 
                 ....
 
                 ....
add the following information:
+
 
 +
* Add the following information:
 
                 ....
 
                 ....
 
                 {SHORT_BAR_RESET_MODE, CAT_SEQUENCER, LONG_BAR_RESET_MODE}, // TEXT_BAR_RESET_MODE
 
                 {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_CHANNEL, CAT_MIDI, LONG_MIDI_CHANNEL}, // TEXT_MIDI_CHAN_GLOBAL
                 {SHORT_RND, CAT_OSC, LONG_RND_VOICE}, // rstephane: TEXT_RND_VOICE
+
                 '''{SHORT_LOOP, CAT_SEQUENCER, LONG_LOOP}, // We declare it at the end of the section :-)''
};
+
       
  
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:
  
now, open the * MenuText.h file to declare the short and long version of the TEXT (TEXT_RND_VOICE1)
+
        const char shortNames[][4] PROGMEM  =  
go to section
+
        {
 
const char longNames[][16] PROGMEM =
 
et const char shortNames[][4] PROGMEM  =
 
 
 
add the parameters:
 
 
 
const char shortNames[][4] PROGMEM  =  
 
{
 
 
         {""},
 
         {""},
 
         {"coa"},
 
         {"coa"},
Line 187: Line 171:
 
         {"co2"},  // trigger clock out2 ppq
 
         {"co2"},  // trigger clock out2 ppq
 
         {"pcr"}, // pattern change resets bar counter
 
         {"pcr"}, // pattern change resets bar counter
         {"RND"}, // rstephane: RND VOice
+
         '''{"LEN"}''', // rstephane: LEN for LOOP :-)
 
          
 
          
};         
+
        };         
  
const char longNames[][16] PROGMEM =  
+
        const char longNames[][16] PROGMEM =  
{
+
        {
 
         {""},
 
         {""},
 
         //01234567
 
         //01234567
Line 204: Line 188:
 
         {"Gate Mode"},
 
         {"Gate Mode"},
 
         {"PCReset" }, // reset bar counter on manual pattern change
 
         {"PCReset" }, // reset bar counter on manual pattern change
         {"Random"}, // rstephane: RND VOice LONG text
+
         '''{"Loop"}''', // rstephane: LOOP LONG text
};
+
        };
 
   
 
   
 
Now, we will create our function
 
and will add a link between this function and our knob.
 
  
If you want you can already compile and see the results under the menu OSC of the VOICE1, normally right after COARSE, FINE, WAV, should appear RND.
+
* 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
call the function relative to the encoder:
+
        {
 
 
open midimessage.h
 
 
 
 
 
//for all parameters above 127 <- our case
 
enum
 
{
 
 
         ....
 
         ....
 
         // Again, place your parameter at a special place, right after the section:
 
         // Again, place your parameter at a special place, right after the section:
Line 235: Line 211:
 
          
 
          
 
         // YOUR PARAMETER comes right here and not elsewhere!!!!!
 
         // YOUR PARAMETER comes right here and not elsewhere!!!!!
         // rstephane MY VALUES ADDED FOR RANDOM FUNCTION
+
         // When the knob is turned , it send the CC2_LOOP message
        // rstephane : RND button :-) for CASE switch in MidiParser.C
+
         '''CC2_LOOP,'''
         CC2_RND_VOICE1,
 
 
         ....
 
         ....
}Param2Enums;
+
        }
 +
        Param2Enums;
 +
 
 +
* open  '''MidiParser.c''' file
  
open
+
        //-----------------------------------------------------------
* MidiParser.c
+
        /** handle all incoming CCs and invoke action*/
//-----------------------------------------------------------
+
        void '''midiParser_ccHandler'''(MidiMsg msg, uint8_t updateOriginalValue)
/** handle all incoming CCs and invoke action*/
+
        {
void midiParser_ccHandler(MidiMsg msg, uint8_t updateOriginalValue)
 
{
 
 
          
 
          
 
         ...
 
         ...
Line 269: Line 245:
  
 
         ...
 
         ...
        case CC2_MUTE_1:
+
                        case CC2_MUTE_1:
 
                         case CC2_MUTE_2:
 
                         case CC2_MUTE_2:
 
                         case CC2_MUTE_3:
 
                         case CC2_MUTE_3:
Line 289: Line 265:
 
                         }
 
                         }
 
                                 break;
 
                                 break;
                        // rstephane MY FUNCTIONS
+
                            //
                        // rstephane : Handle the RND button
+
                            // rstephane MY FUNCTIONS
                        case CC2_RND_VOICE1:
+
                            '''case CC2_LOOP:
                                if(msg.data2 == 1)
+
                                  if(msg.data2 == 16) // reset the loop !
                                {
+
                                  { // we stop the loop effect and
                                        // RND is ON
+
                                          // go back to prevoious track lenght
                                        randomDrumVoice123(0); //voice1 = 0, voice2 = 1 etc...
+
                                          seq_setLoopLength(16);
                                }
+
                                  }
                                break;      
+
                                  else
                                                       
+
                                  { // we change the tracks lenght
 +
                                          seq_setLoopLength(msg.data2);
 +
                                  }
 +
                                  break;'''
 +
                                     
 
                         default:
 
                         default:
 
                                 break;
 
                                 break;
Line 305: Line 285:
 
                          
 
                          
 
                          
 
                          
+
 
open drumvoice.h
 
  
 +
* open '''sequencer.h''' file, add the line : 
 +
        void seq_setLoopLength(uint8_t length);
  
// rstephane : my functions
 
//random all the parameters for voice 1 2 and 3
 
void randomDrumVoice123(const uint8_t voiceNr); 
 
  
 +
* 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
open drumvoice.c
+
* test!
 
 
 
 
// rstephane : pour random functions
 
#include "valueShaper.h"
 
 
 
+
 
 
 
//---------------------------------------------------
 
// rstephane : my functions
 
//random all the parameters for voice 1 2 and 3
 
//---------------------------------------------------
 
void randomDrumVoice123(const uint8_t voiceNr)
 
{
 
                uint8_t rndData; // , new_min, new_max;
 
                // uint32_t rndDataTemp, old_min, old_max;
 
                // COARSE
 
                rndData = (uint8_t) GetRngValue();
 
                //clear upper nibble
 
                voiceArray[voiceNr].osc.midiFreq &= 0x00ff;
 
                //set upper nibble
 
                voiceArray[voiceNr].osc.midiFreq |= rndData << 8;
 
                osc_recalcFreq(&voiceArray[voiceNr].osc);
 
                //OSC1_DIST:
 
                rndData = (uint8_t) GetRngValue();
 
#if USE_FILTER_DRIVE
 
                voiceArray[voiceNr].filter.drive = 0.5f + (rndData/127.f) *6;
 
#else
 
                setDistortionShape(&voiceArray[voiceNr].distortion,rndData);
 
#endif                       
 
               
 
}
 

Latest revision as of 11:04, 8 June 2015

       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!