How to create and add a new function to the LXR

From Sonic Potions Wiki
Revision as of 17:46, 9 May 2014 by Rstephane (talk | contribs)
Jump to: navigation, search

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 :-)
  • 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.
  • Add in the section: 'enum ParamEnums' your new parameter. In our case we will add the parameter : PAR_LOOP
  • 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):
       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...
                  
       // rstephane MY VALUES ADDED FOR LOOP FUNCTION
       PAR_LOOP,     
       ...


  • We need to open the menu.c file. we want that our knob display a name 'LEN'


       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
  • in our case, we have:
       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 need now to declare the TEXT_LOOP and PAR_LOOP in other files :-)
  • Open file menu.h, and go to section
       enum NamesEnum
       {
       TEXT_EMPTY = 0,                                        //0
       TEXT_COARSE,
       TEXT_FINE,
       TEXT_ATTACK,
       TEXT_DECAY,
       TEXT_PITCH_DECAY,
       TEXT_MOD_AMOUNT,                
       ....
  • Add at the end, the text 'TEXT_LOOP" :
       ....
       TEXT_BAR_RESET_MODE,
       TEXT_MIDI_CHAN_GLOBAL,
       TEXT_LOOP,        // rstephane: LOOP text 
       NUM_NAMES
       };
  • Open Cc2Text.c file and under the section

//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


  • 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}, // rstephane: TEXT_LOOP
       
  • We NEED 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:
       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 menu PERF menu (normally under the second page, your should see 'LEN' on the first knob).
  • Now, we will create our function
  • We will add a link between this function and our knob.


/////

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:
       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!!!!!
       // rstephane MY VALUES ADDED FOR RANDOM FUNCTION
       // rstephane : RND button :-) for CASE switch in MidiParser.C
       CC2_RND_VOICE1,
       ....

}Param2Enums;

open

  • MidiParser.c

//----------------------------------------------------------- /** 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
                       // rstephane : Handle the RND button
                       case CC2_RND_VOICE1:
                               if(msg.data2 == 1)
                               {
                                       // RND is ON
                                       randomDrumVoice123(0); //voice1 = 0, voice2 = 1 etc...
                               }
                               break;        
                                                       
                       default:
                               break;
                               
                       ....
                       
                       

+ open drumvoice.h


// rstephane : my functions //random all the parameters for voice 1 2 and 3 void randomDrumVoice123(const uint8_t voiceNr);


+ open drumvoice.c


// rstephane : pour random functions

  1. 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();
  1. if USE_FILTER_DRIVE
               voiceArray[voiceNr].filter.drive = 0.5f + (rndData/127.f) *6;
  1. else
               setDistortionShape(&voiceArray[voiceNr].distortion,rndData);
  1. endif

}