Home › Forums › General › Programming › what do you need to know in order to make panels?
- This topic has 45 replies, 5 voices, and was last updated 3 years, 2 months ago by
goodweather.
-
AuthorPosts
-
December 5, 2014 at 11:12 am #33261
I don’t know what LUA is, but I dont know if i have years to learn this or that random programming language, so it would be great to know what one needs to know in order to make a panel. Is LUA necessary for this? I reached my max google searches for the day.
“you need a basic understanding of C++” would be a good answer for example.
at this time, it is not clear how to proceed, but there seems to be loads of users who are making panels. what do they know that the thousands of users who are not making panels do not? a short list would be fine. and LUA just popped out of nowhere in 2014, never heard of that before.
-
This topic was modified 9 years ago by
reklamchef.
December 5, 2014 at 11:24 am #33263Lua is not needed for a basic panel (two way control of parameters), if you need to implement program dumps and some more complex data exchange between the device and Ctrlr then you will need Lua.
Lua is a scriptin language, it’s fast simple and very popular (i know that there is a lot of lua in the gaming world)
December 5, 2014 at 12:49 pm #33265what is needed to make things for ctrlr? c++ or java or html etc?
December 5, 2014 at 12:52 pm #33266If you wish to help with the development of the app itself it’s all C++, 90% of the code is written in the JUCE Library, 10% is luabind/boost (boost is used only for luabind and is not used anywhere in the code of core Ctrlr)
There are some platform specific snips of ANSI C that are needed to do syscalls on each OS but this are real small pieces of code.
There are some helper scripts for building and generating some headers, those are written in bash/awk.
No other programming language/technology is used.
December 6, 2014 at 5:35 am #33296Just open a sample ensemble and take a look at the edit mode. It,s really easy to understand how cc’s or sysex are sent.
Then try an easy job. Send notes from a panel, then CC,s…
Seems very complex but is just like a mixer console, once you’re done to one channel, doesn’t care how many.MVXSynths
R3 / MOX6 / Electribe2 / Electribe R MkII / Electribe MX / K4R / BCR2000 / XStation61 / XStation25 / Virus Rack / Chameleon / Proteus 2500 / RM1X / KN2600December 11, 2014 at 6:37 am #33534climb the highest moutain you can find, perform the voodoo ritual and ask the LUA Gods to grant you the knowledge
December 13, 2014 at 7:41 am #33619I also want to learn The Art Of Ctrlr Panel Creation. I guess the best way is to just start and see what problems I have to solve to reach my goal.
For my first project I have choosen the Korg DS8 (any other Korg DS-8 or 707 owners in this forum?). And I am making some progress already 🙂
First question. I can copy/paste a modulator (slider, rotary etc) or a group including a set of controllers which is a real timesaver since I have two more or less identical groups of parameters for Oscillator 1 and 2.
But after pasting, the VST-index numbers are not automatically changed, so I have many controllers sharing the same VST-index number that I have to manually change to give them each unique numbers. Goodbye timesaver!
Is this a bug or o feature? If it is a feature I would like to see a way to automatically renumber the VST-index numbers.
December 15, 2014 at 11:46 am #33693It’s just the default behavior in Ctrlr, i think there was a fix for that but it looks as if didn’t help much. What version of Ctrlr are you using ?
December 15, 2014 at 1:01 pm #33697I am using (according to Help->About)
Version = 5.3.26, Build date = Wed Dec 3 16:01:40 CET 2014, Branch = Nightly, Juce = 3.1.0
December 15, 2014 at 4:32 pm #33715I just uploaded a new nightly build that should fix this issue.
December 16, 2014 at 12:41 am #33740The issue still exists after this update, at least that is what I experience:
1. I create a group, but some rotary sliders in it
2. I right-click on the group and select “copy with children”
3. I paste
4. I check the VST index numbers: The VST index numbers in the pasted group are identical to the ones in the original group.December 16, 2014 at 11:04 am #33753You might be right i just fixed the situation when you create/copy/paste single components, i’ll have a look at the groupping stuff asap.
December 16, 2014 at 12:12 pm #33758I uploaded a new version again, it should fix the group indexing issue.
December 19, 2014 at 10:28 am #33924Help wanted!
My first Ctrlr project (a Korg DS-8 panel) has now reached a point where I will have to start understanding how to use Lua in Ctrlr. There are some basic things I want to do. I can’t be that difficult, because almost every existing panel should be able to do this:A1. Receive a SysEx dump with the parameters from one complete Single Voice from my synth via MIDI. (For example when using a SysEx dump request message)
A2. Read the databytes from the dump, if necesary first do some rearranging from the bits and bytes in the dumpdata, and then pass the indivual parameter values to the corresponding modulators in my Ctrlr panel.
A3. The panel now reflects the actual data in my synthB1. Read the state of all the controller values in my panel.
B2. If necessary to some rearranging with the bits and bytes to put the data in the correct SysEx dump format, maybe add a SysEx checksum.
B3. Send the paneldata as a Single Voice SysEx dump to the synth via MIDI: The synth now reflects the data in my Ctrlr panel.Looking how other panels work does help, but I really could use some “getting started” advice to speed up my learning process. Once I can understand and grasp the basic mechanisms I can find out the detailed Lua coding and syntax details that are specific for my synth’s SysEx internals myself.
I hope someone can give me some usable advice!
December 23, 2014 at 3:18 am #34107Yes, that’d be great…
MVXSynths
R3 / MOX6 / Electribe2 / Electribe R MkII / Electribe MX / K4R / BCR2000 / XStation61 / XStation25 / Virus Rack / Chameleon / Proteus 2500 / RM1X / KN2600December 23, 2014 at 11:31 am #34128This is a very basic guide to manage sysex dumps.
In theory your panel is finished and you created a modulator for each byte from the dump.
Now you need to request a dump from the synth. You need to know the sysex command for this. This is an example dump request, that can be added to the LUA code of a button, for instance:
m = CtrlrMidiMessage({0xF0, 0x00, 0x20, 0x33, 0x01, 0x10, 0x30, 0x00, 0x00, 0xF7}) -- REQUEST PATCH MESSAGE panel:sendMidiMessageNow(m) -- SENDS THE DUMP REQUEST MESSAGE
Once you send the dump request, the synth will respond sending a sysex message containing the data of the patch. This message usually contains a header followed by the parameters of the synth engine, and this is the part you need to manage. This is an reduced example of a sysex patch:
f0 00 20 33 01 00 10 00 00 0c 01 02 7d 00 00 00 00 00 00 40 00 00 00 00 00 00 40 00 00 40 60 40 00 00 40 f7
You need to know where the actual data of patch starts, in this case is byte 9 (0c)(starting from the first byte that is number 0).
In order to manage the sysex dump received, you need to create a LUA method for “Called when panel receives a MIDI message” panel property. This is a basic method for this:
midiMessageReceived = function(midiMessage) s = midiMessage:getSize() -- Size of the midi dump received if s == 524 then -- if size match the expected size of the dump requested PatchDataLoaded = midiMessage:getData() -- create a memoryblock with the data dump programData = midiMessage:getData():getRange(09,514) -- create a memory block with the synth engine data, leaving the header assignValues(midiMessage,false) -- call a script to assign each byte to each modulator. end end
Now the assignValues script will look like this:
function assignValues(midiMessage,var) panel:getModulatorByName("Portamento"):setModulatorValue(programData:getByte(0), false,var,false) -- assign the first byte of programData memoryBlock to it's correspondent modulator panel:getModulatorByName("Osc1 Volme"):setModulatorValue(programData:getByte(1), false,var,false) -- assign the second byte of programData memoryBlock to it's correspondent modulator. . . . -- And so on till the last byte. end
Of course, you need to know the target modulator for each byte of the dump.
Now to send a patch to the synth, you can do it in several ways: you can send each modulator individually, or collect all modulator values in a memoryBlock and send it to the synth in the same form the panel will receive a dump patch.
To do it individually, just create a button and add this lua method:
function sendPatch() a = panel:getModulatorByName("Portamento"):getValue() -- get the value of this modulator panel:getModulatorByName("Portamento"):setModulatorValue(a,false,true,false) -- set the same value for this modulator, sending it to the synth a = panel:getModulatorByName("Osc1 Volume"):getValue() -- get the value of this modulator panel:getModulatorByName("Osc1 Volume"):setModulatorValue(a,false,true,false) -- set the same value for this modulator, sending it to the synth . . . -- and so on till the last modulator. end
Your modulators could be arranged in some way to do this more easy. In the following case, modulators where created in the same order they have in a dump message (so modulator with index 0 corresponds to dump’s byte 0 and so on)
function sendPatch() for n = 0, 514, 1 do -- the amount of modulators to send a = panel:getModulatorByIndex(n) -- get modulator with index n b = a:getModulatorValue() -- get it's value a:setModulatorValue(b, false,true,false) -- set it's value, sending it to the synth. end end
If you want to send the patch to the synth as a single dump the procedure is similar; collect modulator values, add them to a memoryBlock and send the memoryBlock as a sysex message:
function sendPatch() a = panel:getModulatorByName("Portamento"):getValue() -- get the value of this modulator PatchDataLoaded:setByte(9,a) -- write it in the memory block in the correct byte a = panel:getModulatorByName("Osc1 Volume"):getValue() PatchDataLoaded:setByte(10,a) . . . m = CtrlrMidiMessage(PatchDataLoaded:toHexString(1)) -- convert the memory block in a midi message panel:sendMidiMessageNow(m) -- send the midi message to the synth end
Hope that helps.
December 23, 2014 at 11:59 am #34129Tnak you! This an answer that will really really help! I will print it out as a getting-started reference 🙂
I noticed there are a lot of good questions posted in this this forum but few of them are really answered.
Now I can start writing the necessary Lua code for my panel. One tricky (typical for KORG synths) part will be to convert 7-bit MIDI data to 8-bit internal Korg data and vice versa. I should write a dedicated function for that, so that it can be re-used for probably every Korg synth since the M1 and DS-8/707. I have written such a function Python ( for another project:http://dxconvert.martintarenskeen.nl ) that I now need to port to LUA.
Korg uses a system where 7 bytes of 8-bit data are remapped to 8 bytes of 7-bit data before they are stored in a SysEx bulk dump, using a special method.December 23, 2014 at 1:06 pm #34132In fact a lot of questions are answered. This question has been around several times, and answered several times (I remember a big post from msepsis), but it’s true that it’s hard to find where it is, it could be spread across many posts or even threads.
About the Korg thing I can’t help you, I don’t own any Korg and none of my panels do bit conversions.
December 24, 2014 at 1:10 pm #34207I’m making progress:-)
An additional question: I have created a uiLCDLabel in my panel to display a 10-character patchname. In the MIDI bulkdump there are 10 bytes used for the patchname. How do I construct MIDI bytes from the uiCDLabel and vice versa? (The MIDI bytes in my case do not represent ASCII values in my case. For ASCII values 32 to 127 a MIDI value of 0 to 85 is used instead.)December 24, 2014 at 1:49 pm #34208To pass the name of a label to modulators with patch name bytes, I put a script in label’s property “called when the label content changes”.
Those are simplified lines from my scripts, so it could lack something
b = panel:getModulatorByName("GLOBAL Patch Name") -- Label with patch name if b ~= nil then c = b:getComponent() namePatch = c:getProperty("uiLabelText") namePatchLength = string.len(namePatch) if namePatchLength > 0 then character = string.byte(namePatch), 1) panel:getModulatorByName("CMON NameChar 1"):setValue(character,true) -- -- in your case you should do some maths else panel:getModulatorByName("CMON NameChar 1"):setValue(32,true) -- space char end if namePatchLength > 1 then character = string.byte((namePatch), 2) panel:getModulatorByName("CMON NameChar 2"):setValue(character,true) -- modulator with first character byte else panel:getModulatorByName("CMON NameChar 2"):setValue(32,true) end . . . end end
This is how I pass the bytes of a dump to a label
-- custom ascii character list, modify it to suit your needs. symbols = {"|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|"," ","!","","#","$","%","&"," ","(",")","*","+","4","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","b","]","^","_","
“,”a”,”b”,”c”,”d”,”e”,”f”,”g”,”h”,”i”,”j”,”k”,”l”,”m”,”n”,”o”,”p”,”q”,”r”,”s”,”t”,”u”,”v”,”w”,”x”,”y”,”z”,”{“,”|”,”}”,”~”}
— get bytes from dump
char1 = symbols[programData:getByte(240)]
char2 = symbols[programData:getByte(241)]
char3 = symbols[programData:getByte(242)]
char4 = symbols[programData:getByte(243)]
char5 = symbols[programData:getByte(244)]
char6 = symbols[programData:getByte(245)]
char7 = symbols[programData:getByte(246)]
char8 = symbols[programData:getByte(247)]
char9 = symbols[programData:getByte(248)]
char10 = symbols[programData:getByte(249)]text1 = string.format(“%s%s%s%s%s%s%s%s%s%s”, char1, char2, char3, char4, char5, char6, char7, char8, char9, char10)
patchName = panel:getModulatorByName(“GLOBAL Patch Name”) — label with patch name
if patchName ~= nil then
c = patchName:getComponent()
c:setPropertyString (“uiLabelText”, text1)
end`PS: The list of characters get fucked with the wordpress code, I hope you get the point of the list.
-
This topic was modified 9 years ago by
-
AuthorPosts
- The forum ‘Programming’ is closed to new topics and replies.