Home Forums General Using Ctrlr Demo panel for MIDI receive/transmit routines

This topic contains 40 replies, has 3 voices, and was last updated by dnaldoog dnaldoog 8 hours, 39 minutes ago.

Viewing 20 posts - 1 through 20 (of 41 total)
  • Author
    Posts
  • #73155

    human fly
    Participant

    thought for today (before my next Ctrlr session):
    i want to put together a little demo panel to represent a
    ‘standard’ 2-way MIDI communication setup, that can easily
    be adapted for any device, with visual feedback in the panel
    to demonstrate it working.

    it’s something i need to think about in isolation from the
    rest of my panel project at this point.

    suggestions? what existing Lua do i need?
    i’ve been avoiding dealing with this because it involves
    having tables of all parameters, and i haven’t quite sorted
    out that listing yet.

    i’m going to look at the ‘midiReceive’ methods more closely,
    and build a little panel with 20 parameters, and hopefully
    a ‘virtual device’ with a patchbank, for the ‘panel’ to interface
    with.

    (thinking about it from newb’ point of view)

    #73156

    human fly
    Participant

    here’s a first simple panel, with a ctrlr panel side,
    and an ‘external device’ side. doesn’t do anything yet,
    it’s just a mock-up with 10 parameters.

    need to give it a kind of ‘sysex’ data and work out
    how it’s going to work next.

    Attachments:
    You must be logged in to view attached files.
    #73159

    human fly
    Participant

    here’s a quick v02 – ‘save’ panel side has a method that
    collects the panel values, and puts data on a ‘lcd’ label
    at the bottom. but it crashes the 1st time it runs, and
    if you recompile it, it does send something to the lcd.
    (nothing else does anything yet – this is a quick attempt
    to collect data from the panel faders)

    edit: skip to v03(where you can click the Data box to
    delete contents)

    • This reply was modified 1 week, 4 days ago by  human fly.
    Attachments:
    You must be logged in to view attached files.
    #73163

    Icchan
    Participant

    This is exactly what this projects needs more. Good examples that limit themselves to one specific area in simple way.

    I’ve wanted to use this project to create a control panel for my Yamaha P50m piano module that has a ton of undocumented sysex commands. I’ve reverse engineered a lot of it, but since Yamaha requires you to add checksum to any sysex command, it’s not so easy to interact with it using just simple saved commands.

    thanks, and I hope you get onwards with your example so the threshold of using CTRLR gets lower 🙂

    #73164

    human fly
    Participant

    thanks; i’m hoping a few of the old hands will drop by
    to help this along.

    the methods and info are all up there, in existing panels,
    but i feel the need to separate it out so i can get my head
    round it.
    – – – –
    one problem here of course is that midiMessage commands are
    send externally over MIDI, so this has to come up with something
    to sidestep that, if it’s to send data to a ‘virtual external device’.

    #73181

    human fly
    Participant

    ‘morning.. here’s today’s installment, v04:
    still not got very far – now has randomising to generate new data
    quickly, and i fixed the ‘save’ method that collects data to the
    screen at the bottom – this still isn’t doing what i expected but
    it does return new data. so it’s more of a demo of those at the
    moment, along the way. orange buttons work. there’s an ‘info’
    method for dev’notes.

    Attachments:
    You must be logged in to view attached files.
    #73183

    human fly
    Participant

    >>skip

    • This reply was modified 1 week, 2 days ago by  human fly.
    #73185

    human fly
    Participant

    >>skip

    #73186

    human fly
    Participant

    in the MKS-50 Advanced bpanelz by layzer/bomma72, there’s a
    method called ‘setPatch’ that seems to be the basis of a
    typical sysex receive operation.

    after a dump request has been sent to the device, this is
    used to check size and identify the type of data dump.
    in this case, whether it is Tone or Patch data

    setPatch = function(midiMessage)
    
    s = midiMessage:getSize()
    if s == 54 then
    	assignToneValues(midiMessage)  
    	end
    
    if s == 31 then
    	assignPatchValues(midiMessage)  
    	end
    end

    assignToneValues and assignPatchValues are 2 functions tacked
    onto the end of the method, as:

    function assignToneValues(midiMessage)
    	
    	programData = midiMessage:getLuaData()
    
    	--console ("RAW DATA: ")
    	--console (programData:toHexString(1))
    	
    	panel:getModulatorByName("DcoEvMd"):setValueMapped(programData:getByte(7), true)
    	panel:getModulatorByName("VcfEvMd"):setValueMapped(programData:getByte(8), true)
    
    etc...
    	panel:getModulatorByName("BndRange"):setModulatorValue(programData:getByte(42), false, false, true)
    	pName = string.format("%s%s%s%s%s%s%s%s%s%s",
    			TranslateChar (string.format (programData:getByte(43), number )),
    			TranslateChar (string.format (programData:getByte(44), number )),
    
    etc..
    
    end
    
    function assignPatchValues(midiMessage)
    	
    	programData = midiMessage:getLuaData()
    
    	--console ("RAW DATA: ")
    	--console (programData:toHexString(1))
    
    	tNumber = string.format("%.2x",programData:getByte(7))
    	KeyLow =  string.format("%.2x",programData:getByte(8))
    	KeyHigh = string.format("%.2x",programData:getByte(9))
    
    etc...
    	
    end

    so programData = midiMessage:getLuaData() creates a ?memory block?

    and then bytes can be accessed as items, and values used to set panel
    modulator values, eg:

    panel:getModulatorByName("DcoEvMd"):setValueMapped(programData:getByte(7),
    true)

    parameter data starts at byte7 -previous 6 bytes are the sysex header.

    #73188

    human fly
    Participant

    there is this also, for sending a patch to the device:

    --
    -- Called when a modulator value changes
    --
    
    SendFullTone = function(modulator, newValue)
    
    if tChar ~= nil then
    
    	label = panel:getModulatorByName("lblPhTtl"):getComponent()
    	PatchName = label:getProperty("uiLabelText")
    
    	if PatchName == "" then 
    		PatchName = tostring(pNumber) 
    		label:setPropertyString ("uiLabelText", PatchName)
    	end
    	
    
    	if PatchName ~= "*Roland MKS-50*" then
    
    		TransName = ""
    		addspace = 0
    		b = 0
    
    		for l=1,10 do
    
    			char = string.sub(PatchName,l,l) 
    
    			if char=="%" then char="@" end -- % causes issues. 
    			charNum = TranslateStr(string.format(char))
    
    			if tonumber(charNum) > 63 then -- this is for special charicters that are skipped.
    				addspace = addspace + 1
    			else
    				TransName = string.format("%s%s", TransName, string.format(" %.2x", charNum))	
    			end
    
    		end
    		
    		while b < addspace do
    			TransName = string.format("%s%s", TransName, string.format(" %.2x", 62)) -- adding blank spaces at the end if characters are not available.
    			b = b + 1
    		end
    
    		---------------- Tone Transmit ------------------
    
    		PatchCommand = "F0 41 35 00 23 20 01"
    		PatchCommand = AddHexCommand("DcoEvMd", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcfEvMd", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcaEvMd", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoPuls", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoSaw", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoSub", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoRnge", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoSbLv", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoNse", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcfHpf", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("ChrsOF", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoLfo", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoEnv", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoAftr", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoPwm", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("DcoPwRt", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcfFrq", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcfRes", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcfLfo", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcfEnv", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcfFolw", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcfAftr", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcaLvl", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("VcaAftr", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("LfoRate", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("LfoDly", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("EnvT1", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("EnvL1", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("EnvT2", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("EnvL2", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("EnvT3", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("EnvL3", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("EnvT4", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("EnvFolw", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("ChrsRt", tostring(PatchCommand))
    		PatchCommand = AddHexCommand("BndRange", tostring(PatchCommand))
    
    		PatchCommand = string.format("%s%s%s", PatchCommand, TransName, " F7")
    
    		panel:sendMidiMessageNow(CtrlrMidiMessage(PatchCommand))
    
    	end
    
    end
    
    end

    so this shows how the outgoing bulk message is put together
    -and presumably would let you write *.syx files for a patch
    library.
    don’t yet understand ‘PatchCommand = string.format(..’ etc.
    what is "%s%s%s"?

    fascinating stuff for the midi fan. apologies if this is longwinded 🙂

    #73189

    human fly
    Participant

    meanwhile, this now produces the hex bytes correctly.
    had omitted ‘string.format(%..’ etc.

    preset buttons will send some set values to faders.
    now have to make those set values ‘luaData’ blocks
    somehow, that can be written to.

    (got rid of the 2nd ‘extDevice’ for the time being)

    this is a bit of a detour from the original purpose,
    to look at how the datadump is built (‘duh’ mode).

    edit: i think the crash error is a conflict after
    modulator names have been used to assign values.
    edit2: yes, just checked: the presets work when
    it opens, but not after ‘save’ has been used, bcs
    that method assigns those variable names as values.
    (i think..)
    edit3: just changed the variable names in the ‘save’
    method, adding ‘val_’ as a prefix to all of them,
    and it fixed the ‘preset’ crashing.

    Attachments:
    You must be logged in to view attached files.
    #73192

    human fly
    Participant

    i just tried to concatenate strings that i’m sending
    to text labels, containing hexdata for values. seems
    to do something…
    edit: but it is outputting gibberish. doesn’t correspond
    to what’s in the ‘lcds'(labels) – so it shouldn’t be
    ‘tostring’..

    function buildBankA()
    --concatenate strings
    local data1=panel:getComponent("lcd_presetData1"):getPropertyString("uiLabelText")
    local data2=panel:getComponent("lcd_presetData2"):getPropertyString("uiLabelText")
    local data3=panel:getComponent("lcd_presetData3"):getPropertyString("uiLabelText")
    local data4=panel:getComponent("lcd_presetData4"):getPropertyString("uiLabelText")
    
    	tabl_bankA = {}
    
    	tabl_bankA[1]	= tostring(data1)
    	tabl_bankA[2]	= tostring(data2)
    	tabl_bankA[3]	= tostring(data3)
    	tabl_bankA[4]	= tostring(data4)
    
    --concatenate table into single string
    	DatasConcat = table.concat(tabl_bankA, " ", 1, 4)
    	
    --make a memory block from the string
    	memB = MemoryBlock(DatasConcat)
    
    --send it to lcd
    panel:getComponent("lcd_bankDataA"):setPropertyString("uiLabelText",""..memB:toHexString(1))
    end
    Attachments:
    You must be logged in to view attached files.
    #73200

    human fly
    Participant

    anyone able to help with concatenating multiple strings
    from a table into a single string?
    seems like a logical way to approach sticking several
    preset values together to produce ‘bank’ data (?)

    above does not work.

    #73201

    human fly
    Participant

    This is exactly what this projects needs more. Good examples that limit themselves to one specific area in simple way.

    I’ve wanted to use this project to create a control panel for my Yamaha P50m piano module that has a ton of undocumented sysex commands. I’ve reverse engineered a lot of it, but since Yamaha requires you to add checksum to any sysex command, it’s not so easy to interact with it using just simple saved commands.

    thanks, and I hope you get onwards with your example so the threshold of using CTRLR gets lower 🙂

    sending the checksum is not so difficult, it is a Ctrlr routine,
    using ‘z(n)’, where n is the number of bytes you want to checksum.

    #73202

    human fly
    Participant

    and thus, i shall now resort to googling, because it returns
    mainly Ctrlr topics from the past, and i guess everyone who’s
    been here has got bored of answering the same things over and over.
    ;-D

    edit: *here* is precisely the issue i’m coming up against:

    printing getLuaData() in console

    so i guess that the fastest way to get responses about Ctrlr
    is to google, using what code terms that are stumping you: it
    will probably return a Ctrlr post.

    #73204
    dnaldoog
    dnaldoog
    Participant

    Hi Human Fly,

    This code below works and I think you were on the right track (didn’t know about that table.concat function), but I think the problem was the method getPropertyString – getProperty seems to work though. Also for the sendMidi function I think you wrote Memb, should be memB. Interesting!

    function buildBankA()
    
    --add strings to table
    	tabl_bankA = {}
    for i=1,4 do
    local s=L(panel:getComponent("lcd_presetData"..i):getProperty("uiLabelText"))
        table.insert(tabl_bankA,s)
    end
    --concatenate table into single string
    	DatasConcat = table.concat(tabl_bankA, " ")
    --	console (String("DatasConcat : "..DatasConcat))
    --make a memory block from the string
    memB = MemoryBlock(DatasConcat)
    
    --send it to synth
    panel:sendMidiMessageNow(CtrlrMidiMessage(memB))
    console(String("memBlock :"..memB:toHexString(1)))
    
    --send it to lcd
    panel:getComponent("lcd_bankDataA"):setPropertyString("uiLabelText",""..memB:toHexString(1))
    
    end
    #73205
    dnaldoog
    dnaldoog
    Participant

    Or this, which is much closer to your original code:

    
    function buildBankA()
    
    --concatenate strings
    
    	local data1=panel:getComponent("lcd_presetData1"):getProperty("uiLabelText")
    	local data2=panel:getComponent("lcd_presetData2"):getProperty("uiLabelText")
    	local data3=panel:getComponent("lcd_presetData3"):getProperty("uiLabelText")
    	local data4=panel:getComponent("lcd_presetData4"):getProperty("uiLabelText")
    
    	tabl_bankA = {}
    
    	tabl_bankA[1]	= data1 -- tostring() not necessary
    	tabl_bankA[2]	= data2
    	tabl_bankA[3]	= data3
    	tabl_bankA[4]	= data4
    
    --concatenate table into single string
    	DatasConcat = table.concat(tabl_bankA," ")
    	console ("DatasConcat : "..DatasConcat)
    
    --make a memory block from the string
    	memB = MemoryBlock(DatasConcat)
    
    --send it to synth
    	panel:sendMidiMessageNow(CtrlrMidiMessage(memB))
    	--console("memBlock :"..memB:toHexString(1))
    
    --send it to lcd
    	panel:getComponent("lcd_bankDataA"):setPropertyString("uiLabelText",""..memB:toHexString(1))
    
    end

    panel:sendMidiMessageNow(CtrlrMidiMessage(DatasConcat )) also works, so there’s no need for the MemoryBlock function

    #73206

    human fly
    Participant

    😀 GREAT ! thank you !
    perfect: i now get all my bytes as they should be. excellent.
    i’ve just done it the way most resembling my original, so now
    i’ll go back and do it the way you suggest. (could you elaborate
    on ?macros? s=L(etc. ) )

    so i only need to specify start and end with the table if i’m
    not concatenating all of it? and ‘data1…4’ are already strings,
    so no need for tostring.. and yes i did have ‘MemB’, and it does
    make sense to go direct with ‘DatasConcat’. i used the memory block
    bit because it was in what i was adapting : -)

    it’s the first time i’ve attempted something like this.
    along the way i’ve looked at getLuaData/getData again, and that
    seems pretty straightforward (hoho, sure i’ll have some problem
    there) – i’m wondering if i should just ditch the notion of
    using a ‘virtual external device’ for this demo panel, for the
    sake of clarity (it means figuring out how to do it, when i
    won’t even be using it, as well). any ideas how i might do
    a ‘virtual’ getData? (haven’t actually thought of it yet)

    ie: the idea there is to achieve transfer/receive without
    having an external device connected, of course. so i guess
    it needs to be something as close to a midimessage as poss’,
    without using that Ctrlr function.(don’t know if you opened
    the panel?)

    #73207

    human fly
    Participant

    very interesting, how you ‘collect’ the table like that,
    since they all have the same prefix: you can just append
    the number of each using:

    for i=1,4 do
    local s=L(panel:getComponent("lcd_presetData"..i):getProperty("uiLabelText"))
    table.insert(tabl_bankA,s)
    end

    table.insert(tabl_bankA,s) … waAaah!

    anyway: here’s the sorted-out version:

    Attachments:
    You must be logged in to view attached files.
    #73209

    human fly
    Participant

    just one little problem remaining: if i try to buildBank
    with empty source labels, Ctrlr crashes – see error png –

    strange, because it has started doing that since i added
    another function elsewhere (a popup menu to select preset
    to send – at present it just sends “preset sent” 1..4 to
    the various labels) – and i’m fairly sure it didn’t crash
    when i tried an ’empty’ buildBank before.

    so it needs some contingency for when there’s nothing to
    write, i guess. going to try it now with one or more
    source slots empty.. no: that’s ok. it’s just if there’s
    nothing to write = crash

    Attachments:
    You must be logged in to view attached files.
Viewing 20 posts - 1 through 20 (of 41 total)

You must be logged in to reply to this topic.

Comments are closed.