Help with getting the hang of lua+ ctrlr

Home Forums General Programming Help with getting the hang of lua+ ctrlr

Viewing 10 posts - 1 through 10 (of 10 total)
  • Author
    Posts
  • #119645
    Jsh
    Participant
      • Topics: 6
      • Replies: 12
      • Total: 18

      Hello all,

      I’m fairly new to Ctrlr and have been rummaging through the forums and experimenting with Ctrlr. Im in the process of familiarizing myself with both LUA and Sysex in order to access parameters that are not directly accessible without receiving a Sysex dump, changing the parameter value, and then sending the Sysex dump as well as look at implementing librarians/patch savers for synths in the future.

      At the moment I’m learning by experimenting with my Korg Minilogue XD. So far I’ve been able to change the portamento by sending CC in LUA (also having done things the default/non-LUA way with no hiccups), but lately, I’ve been to change the portamento sending Sysex via LUA that I get more comfortable with all of the aspects that I’m aiming to learn in a relatively simple example…However, I can’t seem to figure out where I’m going wrong here.

      I have used Sysex to change the portamento by simply entering the following into the Sysex formula (with midi message type as sysex)

      sysex formula: f0 42 3g 00 51 b6 05 xx f7

      But I have thus far been unable to manage this using LUA. Here is my LUA script called on modulator value changed:


      — Called when a modulator value changes
      — @mod http://ctrlr.org/api/class_ctrlr_modulator.html
      — @value new numeric value of the modulator

      porta2Send = function(–[[ CtrlrModulator –]] mod, –[[ number –]] value, –[[ number –]] source)

      — Send Midi
      local sysexMsg = string.format(“f0 42 3g 00 51 b6 05 %.2X f7”, value)
      panel:sendMidiMessageNow(CtrlrMidiMessage(sysexMsg))

      end

      Any pointers on where I’m going wrong here would be massively appreciated. Cheers.

      #119647
      samoht
      Participant
        • Topics: 1
        • Replies: 54
        • Total: 55

        Hi Jsh,

        Some pointers:

        For sending a modulator value using lua to an external midi device:
        -first you have to make some lua code to catch the actual midivalue of the modulator that controls the portamento
        -thereafter you have to make code to insert that value into the sysex formula your midi device understands
        -and last but not least your code must continue with a structure to send this sysex to the right memory area in your midi device
        All these steps are usually written in one lua code structure (a lua method).

        For receiving the actual midi value of a memory address in your midi device and to send its value to a ctrlr modulator:
        you have to make a structure in lua to ask your device for sending the right sysex and then you have to make lua code to extract the value bytes out of this information and to send it to the modulator.

        It sounds quite complicated.
        And yes it is.
        But after studying some panels (all panels using lua have a lot of such structures), it will turn out to be mostly the same and therefore not that difficult.

        Thomas

        • This reply was modified 3 years, 7 months ago by samoht.
        #119649
        Jsh
        Participant
          • Topics: 6
          • Replies: 12
          • Total: 18

          Thanks for the advice Samoht.

          Fixed the method to achieve what I was going for by changing a mistake in the SysEx string where I had 3g, which is what I found as the exclusive header in the midi implementation chart and strangely works when used outside of the LUA method in the SysEx formula box in the midi section of the modulator settings (not sure of the proper terminology lol). After getting a SysEx program dump using Midi-Ox I found the ID should be 36…of course 3g would not work as g is not a hexadecimal value…whoops.

          Anyways thank you again for the pointers, will definitely help as I progress.

          Cheers, Josh.

          #119650
          Jsh
          Participant
            • Topics: 6
            • Replies: 12
            • Total: 18

            Now my aim is to receive a program dump, edit one of the values and then dump this back to the synth in order to access parameters on some of my synths that can (as far as I can tell) only be accessed in this way, but I’m not entirely sure what the approach is for this so any help here would be appreciated. For simplicity sake, I’ll just be using this method to change the portamento (which has been my go-to for some reason), even though yes this can be done with far easier methods, it’s just a way to learn the process with something that is easy to identify the change in for me.

            An example program dump from my Minilogue XD looks like this:

            “F0 42 36 00 01 51 40 00 50 52 4F 47 49 6E 69 00 74 20 50 72 6F 67 72 00 61 6D 02 7F 00 01 00 00 04 02 01 00 02 00 00 00 02 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 7F 03 10 00 00 00 00 7F 03 00 00 00 00 00 00 00 00 02 01 7F 03 1E 00 00 00 00 40 02 00 02 00 01 01 28 00 02 00 02 02 00 01 00 50 00 00 00 00 7F 01 7F 28 01 00 00 7F 01 7F 01 14 00 00 7F 01 7F 01 02 00 02 16 78 0C 0A 00 04 01 48 0C 00 00 0C 32 01 00 01 00 00 00 01 00 01 00 01 00 66 64 64 64 64 00 64 64 00 00 00 00 00 06 00 7F 7F 0D 00 02 00 00 02 00 50 52 45 44 53 08 45 51 44 30 04 10 00 00 4B 36 00 ~ …etc ~ F7”, where the 28th byte is the portamento at full (127), reading 7F

            I have a basic understanding of how to read the dump using the offset table in the midi implementation document…kinda. But I’m not too sure exactly where I would call a method that would request a program dump, how I would store the dump (in a table?) then modify it and send it back.

            Thanks in advance for any advice anyone can offer, in the meantime I’ll continue to look through the forums (as I have seen this topic discussed a lot but am struggling to understand it) and experiment.

            Cheers

            #119657
            samoht
            Participant
              • Topics: 1
              • Replies: 54
              • Total: 55

              Hello Josh

              1. Click on the canvas of your panel and add a component, an uiToggleButton to your canvas.
              2. From dropdown menu go to: Panel -> Panel mode. Now you are in edit mode.
              3. Click on your uiToggleButton to edit this button. Go to the item “called when the modulator value changes. When in the dropdown menu the item “propertyIDs/Names” is checked, you will not see “called when the modulator value changes”, but instead the technical property description “luaModulatorValueChange”.
              On the left in this field you can see three icons. When the mouse is moving over them you can see that there is one to edit the selected method, one to remove the selected method and one to add a new method.
              4. Click on this last one and fill in your chosen name for this new method. By instance: myDumpFromSynth.
              On the far right of this field there are arrows to open the available methods. Choose myDumpFromSynth.
              5. Now click on the “edit selected method” icon and the lua editor is opening showing you the bare bones of the selected method myDumpFromSynth.
              BETWEEN the lines, the first beginning with “myDumpFromSynth = function” and the last one with only “end” you have to complete your method.
              It should be something like this (this example is for a Roland synth):

              myDumpFromSynth = function(--[[ CtrlrModulator --]] mod, --[[ number --]] value, --[[ number --]] source)
                  mD = {}
                  mD = CtrlrMidiMessage({0xF0, 0x41, 0x0F, 0x2B, 0x11, 0x00, 0x06, 0x00, 0x00, 0x01, 0x20, 0x59, 0xF7}) -- REQUEST PATCH MESSAGE
                  panel:sendMidiMessageNow(mD) -- SENDS THE DUMP REQUEST MESSAGE
              end

              After completing this step you open the lua editor drop down menu and click on “File –> save and compile all”.
              Close the lua editor.

              6. Leave the edit mode in Ctrlr by clicking again on Panel -> Panel mode.
              Go to the dropdown menu item “Tools” and click on “MIDI Monitor”. This will open this monitor. Go to the dropdown menu of this monitor and check in the menu item “View” three sub items: “monitor input”, “monitor output” and “show RAW data size”.
              When clicking on your uiToggleButton you should see the incoming midi you requested. Otherwise there is something wrong with you sysex request in the myDumpFromSunth method.

              7. Go in edit mode and click on the withe canvas (not on a component). In the edit panel is an item “Called when a panel receives a midi message”. When in the dropdown menu the item “propertyIDs/Names” is checked, you will not see “Called when a panel receives a midi message”, but instead the technical property description “luaPanelMidiReceived”.
              Here, you open a new method with the name “midiMessageReceived” according to the procedure described above.
              So here you have to catch the midi flow your synth has sent. Between all the midi flows you can identify the right flow when you know its data size (you can read this size in the midi monitor as described above) or using some of its address bytes.
              This method should be something like this:

              --
              -- Called when a panel receives a midi message (does not need to match any modulator mask)
              -- @midi   CtrlrMidiMessage object
              --
              
              midiMessageReceived = function(midi)
              
              	local s = midi:getSize()
              	local Id1 = midi:getLuaData():getByte(5)
              	local Id2 = midi:getLuaData():getByte(6)
              
              	if s == 138 then --s = size
               	   	if Id1 == 0x00 then -- first address byte
                  		if Id2 == 0x06 then -- second address byte
              		mData1 = midi:getData()
              		console (string.format ("size(dec.)=%d Id1(hex)=%x Id2(hex)=%x", s, Id1, Id2))
              		mData2 = midi:getData():getRange(0, 135)
              		console(midi:getData():toString())
              			end --if Id2
              		end -- if Id1
              	end --if s
              end -- function

              8. Some notes about the console:

              8.1. From dropdown menu go to: Panel -> LUA console
              8.2 Click on the bottom part of the Console
              8.3 type console(“Hello world”)
              8.4 The text “Hello world” should appear on the upper part of the Console.
              8.5 If this works, you can try using console(“Any text”) in LUA code you use for your Panels.

              Cheers,
              Thomas

              #119658
              dnaldoog
              Participant
                • Topics: 4
                • Replies: 480
                • Total: 484
                • ★★

                Hi there Jsh,

                See here for a way of doing this .

                You can also convert midi:getData() to a lua table using:

                
                t={}
                midi:getData():toLuaTable(t)
                

                You could then modify the contents of the table and repack as a MemoryBlock and resend to the Synth: … or send the table as you did!

                
                m=MemoryBlock()
                m:createFromTable(t)
                panel:sendMidiMessageNow(CtrlrMidiMessage(m:toHexString(1)))
                

                or

                
                panel:sendMidiMessageNow(CtrlrMidiMessage(t))
                

                The other option would be to work solely with MemoryBlocks:

                Regards,

                ?

                • This reply was modified 3 years, 7 months ago by dnaldoog. Reason: replied to post in future but didn't create new post
                #119663
                Jsh
                Participant
                  • Topics: 6
                  • Replies: 12
                  • Total: 18

                  Awesome!

                  Thank you both (Samoht and dnaldoog) for the help. I’ve managed to receive the dump change the value and send it back. The scripts look like this:

                  — Called when a modulator value changes
                  — @mod http://ctrlr.org/api/class_ctrlr_modulator.html
                  — @value new numeric value of the modulator

                  GetSysexProgDump = function()

                  progData = {}
                  progData = CtrlrMidiMessage({0xF0, 0x42, 0x36, 0x00, 0x01, 0x51, 0x10, 0xF7})
                  panel:sendMidiMessageNow(progData)

                  end


                  — Called when a panel receives a midi message (does not need to match any modulator mask)
                  — @midi CtrlrMidiMessage object

                  CheckIncomingMidi = function(–[[ CtrlrMidiMessage –]] midi)

                  local msgSize = midi:getSize()

                  if msgSize == 1179 then

                  progDumpTable = {}
                  midi:getData():toLuaTable(progDumpTable)
                  progDumpTable[28] = 0x7f

                  progDumpMsg = CtrlrMidiMessage(progDumpTable)
                  panel:sendMidiMessageNow(progDumpMsg)
                  end
                  end

                  Here I’m just setting the portamento to full on the button press. I’ve also been experimenting with the table (just looping through and printing the values ert with a basic “for i, v in pairs(table) do” to see results and familiarize myself with other practices.

                  Next on the agenda is to actually pass a value from the modulator knob from the panel and use this to set the value. I’ll let you know how I get on.

                  Many thanks.

                  #119666
                  Jsh
                  Participant
                    • Topics: 6
                    • Replies: 12
                    • Total: 18

                    Hmmm…

                    So I’ve run into a bit of an issue trying to send the value from the portamento modulator. My initial instinct was to do this:

                    --
                    -- Called when a panel receives a midi message (does not need to match any modulator mask)
                    -- @midi   CtrlrMidiMessage object
                    --
                    myMethod = function(--[[ CtrlrMidiMessage --]] midi)
                    	local msgSize = midi:getSize()
                    	if msgSize == 1179 then -- If message is program dump
                    		local portaValRaw = panel:getModulatorByName("Portamento"):getModulatorValue()
                    		local portaVal = tostring(string.format("%.2X", portaValRaw))
                    		progDump = {}
                    		midi:getData():toLuaTable(progDump)
                    		progDump[28] = portaVal
                    		progDumpMsg = CtrlrMidiMessage(progDump)
                    		panel:sendMidiMessageNow(progDumpMsg)
                    	end
                    end

                    However, this gives me the compile error:

                    At line [-1]: [C]
                    Error message: std::exception: ‘unable to make cast’

                    I’m thinking that I’m not referencing/passing the portamento modulator value in the correct way, but I’m not really too sure. Any thoughts?

                    Cheers

                    • This reply was modified 3 years, 7 months ago by Jsh.
                    #119668
                    dnaldoog
                    Participant
                      • Topics: 4
                      • Replies: 480
                      • Total: 484
                      • ★★

                      Hi Jsh,

                      You are casting a number as a string then assigning it to the table, when in fact it’s already a number.

                      The two character hex form is just a printing convention for a number, not the number itself if that makes sense.

                      local portaVal = tostring(string.format(“%.2X”, portaValRaw))

                      Should be:

                      
                      myMethod = function(--[[ CtrlrMidiMessage --]] midi)
                      	local msgSize = midi:getSize()
                      	if msgSize == 1179 then -- If message is program dump
                      		local portaValRaw = panel:getModulatorByName("Portamento"):getModulatorValue()
                      		progDump = {}
                      		midi:getData():toLuaTable(progDump)
                      		progDump[28] = portaValRaw
                      		progDumpMsg = CtrlrMidiMessage(progDump)
                      		panel:sendMidiMessageNow(progDumpMsg)
                      	end
                      end
                      
                      
                      • This reply was modified 3 years, 7 months ago by dnaldoog.
                      #119680
                      Jsh
                      Participant
                        • Topics: 6
                        • Replies: 12
                        • Total: 18

                        Chuffed, Thanks guys!

                      Viewing 10 posts - 1 through 10 (of 10 total)
                      • The forum ‘Programming’ is closed to new topics and replies.
                      There is currently 0 users and 81 guests online
                      No users are currently active
                      Forum Statistics
                      Threads: 2,495, Posts: 17,374, Members: 77,605
                      Most users ever online was 12 on January 22, 2019 3:47 pm
                      Ctrlr