How to create and add a new function to the LXR
Deprecated: Creation of dynamic property PPDStack::$accum is deprecated in /www/htdocs/w0069e04/sonic-potions/wiki/includes/parser/Preprocessor_DOM.php on line 845
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!