Home Forums General Programming Callback error: Lua runtime error

Tagged: ,

This topic contains 13 replies, has 3 voices, and was last updated by lfo2vco lfo2vco 3 years, 6 months ago.

Viewing 14 posts - 1 through 14 (of 14 total)
  • Author
    Posts
  • #13245
    lfo2vco
    lfo2vco
    Participant

    Me again…

    I am getting an alert when I try to run the attached method called “saveToSynth”. It works OK when getting the modulator values and compiling them into strings.

    However as soon as I add lines 432 & 433 instructing the CtrlrMidiMessage I get the following error message when running the method:

    Callback error: saveToSynth
    Lua runtime error
    Error message: std::exception: ‘unable to make cast’
    Method disabled

    I have also attached the Lua console output for your perusal.

    I have compared the MIDI message against methods in other panels but cannot see where I am going wrong.

    Attachments:
    You must be logged in to view attached files.
    #13261
    lfo2vco
    lfo2vco
    Participant

    OK, I think that the problem is that I cannot put a string into at MIDI message. Is that correct?

    So in this instance I have to get the Sysex data into a memory block and compile the information there?

    I have looked through several examples in other panels but cannot decipher the mechanics of what is happening as they are very complex methods. Way beyond what I am currently capable of.

    Should I be trying something like the following?

    Write your values to a Lua table that’s indexed with numbers, like so

    myTable = {}
    myTable[1] = panel:getModulatorByName("w00f"):getValue()
    myTable[2] = panel:getModulatorByName("w00f"):getValue()
    myTable[3] = panel:getModulatorByName("w00f"):getValue()
    myTable[4] = panel:getModulatorByName("w00f"):getValue()
    

    then convert that table to a MemoryBlock

    mb = MemoryBlock (myTable)
    

    and write that to a file, do this in reverse to get the values.

    To convert a MemoryBlock to a hex string use toHexString(1) method (the 1 as the parameter is the grouping parameter for output)

    a MemoryBlock can be constructed from a hex string ex:

    mb = MemoryBlock ("f0 f1 f2 f3 f7")
    console (mb:toHexString(1))
    
    #13299

    Hecticcc
    Participant

    If you format the string correctly you can send it out over midi.
    You can even use other functions inside this formatting construction.

    This is how i send out midi-data in the emu panel, a function that accepts some values & makes a midimessage.

    
    function paramChangeMsg(paramNumLsb,paramNumMsb, paramVal)
    
    msg = string.format("f0 18 21 %.2x 55 01 02 %.2x %.2x %.2x %.2x 7f f7", devID, paramNumLsb, paramNumMsb, lsb(paramVal), msb(paramVal))
    if msg then
    panel:sendMidiMessageNow(CtrlrMidiMessage(msg))
    end
    end

    Hope this helps 😉

    #13316
    atom
    atom
    Moderator

    attach what the functions lsb() and msb() do

    #13319
    lfo2vco
    lfo2vco
    Participant

    Thanks Hecticcc, I’ll give that a go.

    Hi Atom, is your question to Hecticc? I do not recall any lsb and msb functions in the method I attached.

    #13324

    Hecticcc
    Participant

    Sure, they are some of the helper methods i use to calculate stuff.

    
    function lsb(x)
    
    	if x ~= nil then
    
    	local bi = CtrlrLuaBigInteger(x)
    	local lsb = bi:getBitRangeAsInt (0,7)
    
    	return (lsb)
    	end
    end
    
    
    function msb(x)
    
    	if x ~= nil then
    
    	local bi = CtrlrLuaBigInteger(x)
    	local msb = bi:getBitRangeAsInt (7,7)
    
    	return (msb)
    	end
    end
    
    #13325
    atom
    atom
    Moderator

    Yeah it was for hecticc cause i saw he used something i didn’t implement, and no bit operations are available in lua wihtout extra modules.

    You can shorten a function like that to

    function lsb (x)
    	return (CtrlrLuaBigInteger(x):getBitRangeAsInt(0,7))
    end
    
    #13327

    Hecticcc
    Participant
    #13350
    lfo2vco
    lfo2vco
    Participant

    If you format the string correctly you can send it out over midi.

    Yep I see what you are getting at Hecticcc, but my problem lies with this (I think)

    function saveToSynth(midiMessage)
    
    	-- Get ASCII characters from uiLCDLabel and convert into two Hexadecimal strings of 10 characters long
    	getPatchLabel = panel:getComponent("Patch Label"):getProperty("uiLabelText")
    	character00 = string.byte(getPatchLabel,1)
    	character01 = string.byte(getPatchLabel,2)
    	character02 = string.byte(getPatchLabel,3)
    	character03 = string.byte(getPatchLabel,4)
    	character04 = string.byte(getPatchLabel,5)
    	character05 = string.byte(getPatchLabel,6)
    	character06 = string.byte(getPatchLabel,7)
    	character07 = string.byte(getPatchLabel,8)
    	character08 = string.byte(getPatchLabel,9)
    	character09 = string.byte(getPatchLabel,10)
    
    		if Character00 == 0x20 then 
    			byte00 = string.format("20")
    		else
    			byte00 = string.format("%.2x",character00)
    		end
    		if Character01 == 0x20 then 
    			byte01 = string.format("20")
    		else
    			byte01 = string.format("%.2x",character01)
    		end
    		if Character02 == 0x20 then 
    			byte02 = string.format("20")
    		else
    			byte02 = string.format("%.2x",character02)
    		end
    		if Character03 == 0x20 then 
    			byte03 = string.format("20")
    		else
    			byte03 = string.format("%.2x",character03)
    		end
    		if Character04 == 0x20 then 
    			byte04 = string.format("20")
    		else
    			byte04 = string.format("%.2x",character04)
    		end
    		if Character05 == 0x20 then 
    			byte05 = string.format("20")
    		else
    			byte05 = string.format("%.2x",character05)
    		end
    		if Character06 == 0x20 then 
    			byte06 = string.format("20")
    		else
    			byte06 = string.format("%.2x",character06)
    		end
    		if Character07 == 0x20 then 
    			byte07 = string.format("20")
    		else
    			byte07 = string.format("%.2x",character07)
    		end
    		if Character08 == 0x20 then 
    			byte08 = string.format("20")
    		else
    			byte08 = string.format("%.2x",character08)
    		end
    		if Character09 == 0x20 then 
    			byte09 = string.format("20")
    		else
    			byte09 = string.format("%.2x",character09)
    		end
    
    			bytes00to09 = string.format("0x%s 0x%s 0x%s 0x%s 0x%s 0x%s 0x%s 0x%s 0x%s 0x%s", byte00, byte01, byte02, byte03, byte04, byte05, byte06, byte07, byte08, byte09)
    			console(string.format(bytes00to09))
    
    	-- Send Tone Dump Sysex message to Kiwi-3P
    	toneDump = string.format("f0 7f 06 %.2x 0xf7", bytes00to09)
    	panel:sendMidiMessageNow(CtrlrMidiMessage(toneDump))
    	end

    Above is a very abridged version of my method, I think there is enough info to make sense of what I am trying to do. However I believe (and stand to be corrected) that calling on a string (bytes00to09) in the sysex string (toneDump) may be what is causing the problem.

    I have formatted the method this way as there are a lot of modulator values to include and the values get difficult and unwieldy to follow as one long string. So I have subdivided them into groups of ten bytes, with the aim of combining them in between the Sysex start and end.

    Seems this grand plan is a bit of a failure :-\

    Complete example dump follows:
    0xf0 0x7f 0x7f 0x7f 0x60 0x01 0x00 0x06 0x00 0x01 0x48 0x69 0x67 0x68 0x20 0x53 0x74 0x72 0x69 0x6e 0x67 0x73 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x04 0x27 0x7d 0x00 0x3f 0x09 0x60 0x4a 0x2b 0x7f 0x3f 0x01 0x12 0x03 0x2d 0x64 0x2a 0x4b 0x7f 0x11 0x3f 0x00 0x00 0x7f 0x00 0x7f 0x7f 0x46 0x30 0x7f 0x00 0x05 0x7f 0x7f 0x00 0x00 0x7f 0x00 0x00 0x00 0x0f 0x40 0x00 0x3f 0x00 0x00 0x05 0x00 0x0e 0x3d 0x15 0x00 0x03 0x01 0x55 0x78 0x08 0x02 0x03 0x01 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xf7

    #13353
    atom
    atom
    Moderator

    Ok i added an example DEMO panel to the repository that will help you with that, below is a Lua method that is included with the demo with all lines commented and explained

    function sendPatchName()
    	if panel:getRestoreState() == true or panel:getProgramState() == true then
    		return
    	end
    
    	-- Your method code here
    	console ("sendPatchName")
    
    	messageToSend	= MemoryBlock ({0xf0, 0x10, 0x03, 0x01})
    	-- we prepare our message we will be sending to the device, this is just
    	-- the prefix to the message, the rest of the data will be appended at the
    	-- end of this method
    
    	messageSuffix	= MemoryBlock ({0x00, 0xf7})
    	-- this variable hold the suffix of the entire MIDI message, this can be
    	-- altered later to hold the checksum if needed
    
    	text 		= L(panel:getLabel("nameInputLabel"):getText())
    	-- we take the text from the "nameInputLabel" and convert it to Lua type of
    	-- string, that's why there is the L() macro, otherwise we'd get a String()
    	-- instance, that might not work well with the native Lua library
    
    	textLen		= string.len(text)
    	-- we can use string library function safely now
    	-- here we take the length of the string and keep it in a variable
    
    	textTable	= {}
    	-- we'll use a table to store our patch name as bytes of data
    	-- this creates a new empty table, this could be local not to confuse
    	-- other methods
    
    	for i=1,textLen do
    		textTable = string.byte(text,i)
    		-- the bytes here can be prepared to fit a MIDI message
    		-- if there are ASCII characters beyond 127 then this will
    		-- casue invalid MIDI messages, it's up to you to check
    		-- you can also apply restrictions on the input label
    	end
    
    	for j=1,#textTable do
    		console (string.format ("%d = %d %2x [%c]", j, textTable[j], textTable[j], textTable[j]))
    		-- this is for debugging purposes only, it prints every entry
    		-- in the table we created above, tables start at "1" in Lua
    		-- #textTable means the tables size/length
    	end
    
    	patchNameData	= MemoryBlock.fromLuaTable(textTable)
    	-- here we converted our table of characters into a Ctrlr compatible MemoryBlock
    	
    	console ("\tpatch name as memory block: "..patchNameData:toHexString(1))
    	-- for debugging purposes let's see how that looks like
    
    	-- Now we will construct the entire message, the variable "messageToSend"
    	-- holds all the data we need, we append any new data we gathered here
    	-- then at the end, append the messageSuffix that ends the message 
    	--(there might be a need for a checksum, that's the place to calculate it)
    	messageToSend:append (patchNameData)
    	messageToSend:append (messageSuffix)
    
    	console ("\tpatch data: "..messageToSend:toHexString(1))
    	-- for debugging let's see the entire message, we can now send it by creating
    	-- a CtrlrMidiMessage from this data, or maybe save it for later
    
    	panel:getLabel("debugOutputLabel"):setText(messageToSend:toHexString(1))
    end
    
    #13359
    lfo2vco
    lfo2vco
    Participant

    Many thanks Atom, that’s brilliant I’ve downloaded the panel and will apply to my method.

    Yippi Kay Ay indeed :~ )

    #13366
    lfo2vco
    lfo2vco
    Participant

    This is working a treat.

    I also have a label that contains numbers as Hex 00 01, what do I modify so it goes into the table as 00 01 not 30 30 20 30 31?

    Cheers.

    #13367
    atom
    atom
    Moderator
    text = panel:getLabel("myLabelWithHexString"):getText()
    mb = MemoryBlock()
    mb:loadFromHexString(text)
    -- mb should contain the data
    
    #13369
    lfo2vco
    lfo2vco
    Participant

    Cheers Atom.

Viewing 14 posts - 1 through 14 (of 14 total)

You must be logged in to reply to this topic.

Comments are closed.