Home › Forums › General › Programming › Help getting ASCII Characters into uiLabel
- This topic has 13 replies, 3 voices, and was last updated 3 years, 11 months ago by shooking.
-
AuthorPosts
-
May 6, 2020 at 5:42 pm #118219
OK, I’ve hit a bit of brick wall with this one so hopefully some nice person can shed some light!
I have a Yamaha DX11 here and I have successfully managed to capture the SysEx it spits out when you change Patches and to route them through to some uiSliders on my panel, but I am having problems trying to extract the 10 Bytes of Data that represent the Patch Name and get them to display in the Panel.
Below is part of my LUA script which is relevant to building the Patch Name and spitting it out to the Console:
if size == 101 then
PatchDataLoaded = midiMessage:getData()
VCED_Data = midiMessage:getData():getRange(6,94)
— Extracting the Patch Name Characters & assigning them to variables char1, char2 …etc
char1 = string.char(VCED_Data:getByte(76))
char2 = string.char(VCED_Data:getByte(77))
char3 = string.char(VCED_Data:getByte(78))
char4 = string.char(VCED_Data:getByte(79))
char5 = string.char(VCED_Data:getByte(80))
char6 = string.char(VCED_Data:getByte(81))
char7 = string.char(VCED_Data:getByte(82))
char8 = string.char(VCED_Data:getByte(83))
char9 = string.char(VCED_Data:getByte(84))
char10 = string.char(VCED_Data:getByte(85))getPatchName = char1..char2..char3..char4..char5..char6..char7..char8..char9..char10
console (“Assigning patch name:”..getPatchName)
assign_VCED_Values(midiMessage,false)
else
console (“Byte Sizes Incorrect”)
end
Now as I understand it, string.char converts Hex into ASCII, so that code should construct an ASCII String which is 10 letters long in a Variable called getPatchName?
Except all I seem to get on the Console and in the uiLabel is 10 Blanks!
Is there some where else I need to define what Hex Code translates to what ASCII Code, or am I just going about this all the wrong way?
- This topic was modified 3 years, 11 months ago by spiffo.
May 6, 2020 at 7:50 pm #118222this is what I do
console("processSingleD calling generatePatchPrefix") getPatchName = generatePatchPrefix(patch, string.format("%.10s", d:getRange(0,10):toString())) console("[["..getPatchName.."]]")
so i see you know the range of values for your chars. 76 – 85 == 10 chars like my K1r.
console("generatePatchPrefix") getPatchName = generatePatchPrefix(patch, string.format("%.10s", VCED_Data:getRange(76,10):toString())) console("[["..getPatchName.."]]")
I _think_ that might work … try it in the console .. SAVE YOUR WORK BEFORE YOU DO IT … I have bitter experience recently of Ctrlr crashing and nuking my Lua.
May 6, 2020 at 7:52 pm #118223I typed too fast .. of course you dont need to generate a patch prefix!!
console("generatePatchPrefix") getPatchName = string.format("%.10s", VCED_Data:getRange(76,10):toString()) console("[["..getPatchName.."]]")
sorry about that. so the idea is use the format to restrict to 10 chars (the %.10s)
grab range of bytes you want … start at 76 and get 10 .. turn that to a string .. put that into variable print variable.Hope this works for you
May 6, 2020 at 9:05 pm #118224OK, so that seems a lot more elegant, use string.format to form a 10 Character String from 10 Bytes starting at Byte 76 in my Memory Block called VCED_Data !
I’m trying to learn this LUA as I go along, basically winging it by copying bits of code, trial & error, and some programming knowledge from way back in school.
Yep I’ve got the Yamaha MIDI Implementation in front of me, I can follow most of it and with a bit of Trial & Error I’ve managed to work out which Byte is which. I’ve managed to extract the correct Bytes to throw at the right uiSliders. But this afternoon I just couldn’t get that HEX Code converted to ASCII and displayed in a uiLabel, I’ll give your method a go first thing tomorrow.
Thanks!
May 7, 2020 at 11:27 am #118240I don’t think you need string.format, but it’s certainly interesting and something I didn’t know about.
getPatchName =VCED_Data:getRange(76,10):toString()
- This reply was modified 3 years, 11 months ago by dnaldoog.
May 7, 2020 at 7:06 pm #118246depends what you want … in my day job you would be surprised the amount of chaos caused by overwriting bounds.
Lua and luabind cause rather a lot of havoc to the C/C++ … so I figure explicitly limiting stuff might be ok.
There again if Lua strings work like more modern languages then it will just keep adding length on until you run out of memory … except often times I am moving data into a memory block and for sure that doesnt keep extending :-))>>> console(string.format(“[[%.10s]]”, “hi”))
[[hi]]>>> console(string.format(“[[%.10s]]”, “hiIamAlongstringhaha”))
[[hiIamAlong]]>>> console(string.format(“[[%.10s]]”, “012345678901234567890”))
[[0123456789]]Now since posting this I have had to roll back to 5.3 and it behaves quite differently to 6.x
Spiffo – when you say “My memory block VCED_Data” can you post how you created it please?
What I am finding is with 5.3 I have to “loop” whereas with 6.x I can use range operators.
The key difference is I dont seem able to create a MemoryBlock in 5.3 but can create a CtrlrLuaMemoryBlock.
The latter appears to behave quite differently to a MemoryBlock — copyTo dont work the same OR I am just confusing myself.May 7, 2020 at 7:29 pm #118247Here’s what I had to hack … man if someone would be so kind to help me build 6.x on Linux I am sure I can help to make it more stable!
Or how to use MemoryBlock in 5.3 – these CtrlrLuaMemoryBlock behave differently – I am sure I am missing an L somewhere ??
-- /* idx: 0 */ char Name[10]; // PatchName local name = "" -- name = string.format("%.10s", d:getRange(0,10):toString()) for i = 0, 9 do console("[[inval_"..i.."]] == [["..d.."]]") console(""..d[1]) name = name..string.char(d)
clearly the 6.x method using MemoryBlock is far cleaner than what I am doing with 5.3
If anyone an spot an obvious mistake I am making and they are near me in UK I will “socially distance” them a beer 🙂
May 8, 2020 at 2:25 am #118255Hi shooking,
‘d’ is a MemoryBlock object, so to access each byte, you need
d:getByte(i)
notd[ i ]
the latter being a reference to an index of a non-existent lua table.d=MemoryBlock("68 69 49 61 6D 41 6C 6F 6E 67 73 74 72 69 6E 67 68 61 68 61") name = string.format("%.10s", d:getRange(0,10):toString()) console(name) --hiIamAlong for i = 0, 9 do console("[[inval_"..i.."]] == [["..d:getByte(i).."]]") console(""..d:getByte(i)) name = name..string.char(d:getByte(i)) end console(name) -- hiIamAlonghiIamAlong
Also in lua, you can do
console(String(string.sub("hiIamAlongstringhaha",1,10)))
instead of ` console(string.format(“[[%.10s]]”, “hiIamAlongstringhaha”)) but I guess they both produce the same output.- This reply was modified 3 years, 11 months ago by dnaldoog.
May 8, 2020 at 2:51 am #118256Hi shooking,
copyTo and copyFrom seem to crash Ctrlr.
I would use ‘append`
d=MemoryBlock("68 69 49 61 6D 41 6C 6F 6E 67 73 74 72 69 6E 67 68 61 68 61") e=MemoryBlock() e:append(d) console("size\t"..e:getSize()) size 20
I think CtrlrLuaMemoryBlock is deprecated, but not sure what that really means.
- This reply was modified 3 years, 11 months ago by dnaldoog.
May 8, 2020 at 7:08 pm #118272So what I found is in the 6.x version (which I was using thinking latest is greatest) the copyTo etc can work.
I will try the append.
Right now with my debugging hints I can see my 5.x panel is failing on what seems to be 6.x specific stuff .. bummer.In process of getting my head around it, lighting BBQ, drinking beer and cooking some seriously seasoned chicken – from my Miniaktools secret lair I can use my PC and look out at progress from my pseudo pit …
Really want to get this memory block peacefully coexisting with MidiData.
May 8, 2020 at 7:12 pm #118273what’s smart way of appending a range?
So I read in raw Sysex from K1r.
I then strip of the first header 8 bytes (because I can regenerate those), the last but one and F7 byte (checksum and trailing)so my MemoryBlocks are what 10 bytes smaller than the raw sysex.
I just want to take the range 0, 8 [[ from 0 for 8 bytes]] from original midiMessage.
Then I want to create a block with the residual – 2.
And from there on I want to reference new blocks as 0 for 1st byte (ie the first char of the name).This worked in 6.0 … but then I hit various snags — backporting to 5.3 is messing with my head 🙂
May 8, 2020 at 7:17 pm #118274zB does this seem legitimate?
local d1 = MemoryBlock() d1:append(d:getRange(0, gMULTIPLE_SINGLE_SYSEX_TRAN)) local d2 = d:getRange(gMULTIPLE_SINGLE_SYSEX_TRAN, gMULTIPLE_SINGLE_SYSEX_TRAN) local d3 = d:getRange(2 * gMULTIPLE_SINGLE_SYSEX_TRAN, gMULTIPLE_MULTI_SYSEX_TRAN)
ie I am testing the append range of d into empty d1 – you see the way I did it in 6.x and it seemed to work (for d2 and d3)
May 8, 2020 at 8:22 pm #118276Ah … I dont mean to contradict you my friend but I will – because clearly I didnt share everything with you.
I am creating a Multi dimensional array
SINGLE_SYSEX_STORAGE_SIZE = 88 g_singlePatch = {} for i = 0, 63 do --[[ version 6 has a true parameter, 5 does not -- g_singlePatch = MemoryBlock(SINGLE_SYSEX_STORAGE_SIZE, true) --]] g_singlePatch = MemoryBlock(SINGLE_SYSEX_STORAGE_SIZE) end -- -- 32 slots for multis -- deliberately starting from 0 - could start from 64? Examine sysex and make decision -- recall the number == patch, so no need to store header nor F7 g_multiPatch = {} -- let store it as 32 -- note 76 data -- strip of Sysex Header and F7 MULTI_SYSEX_STORAGE_SIZE = 76 for i = 0, 31 do --[[ version 6 has a true parameter, 5 does not -- g_multiPatch = MemoryBlock(MULTI_SYSEX_STORAGE_SIZE, true) --]] g_multiPatch = MemoryBlock(MULTI_SYSEX_STORAGE_SIZE) end
You can see my my comments I am pulling what’s left of my hair out 🙂
So I read in d =midiMessage:getDataWe all agree this has MemoryBlock type semantics.
But see later I want to “copyTo” .. and in 6.x this works great.
But in 5.3 it doesnt seem to (or I am doing it wrong).So I process according to this stack:
05/08/20 18:49:27 [FILE: [string "requestSinglePatch"]]: Line: 8 FUNC: 05/08/20 18:49:27 [TRACEBACK] 05/08/20 18:49:27 [FILE: [string "handlePanelMidiMessage"]]: Line: 11 FUNC: 05/08/20 18:49:27 [Handling sysex size 97 bytes] 05/08/20 18:49:27 [TRACEBACK] 05/08/20 18:49:27 [FILE: [string "handleKawaiSysex"]]: Line: 20 FUNC: handleKawaiSysex 05/08/20 18:49:27 [FILE: [string "handlePanelMidiMessage"]]: Line: 66 FUNC: 05/08/20 18:49:28 [Handling size 97 bytes.] 05/08/20 18:49:28 [TRACEBACK] 05/08/20 18:49:28 [FILE: [string "processSingleD"]]: Line: 303 FUNC: processSingleD 05/08/20 18:49:28 [FILE: [string "handleKawaiSysex"]]: Line: 129 FUNC: 05/08/20 18:49:28 [FILE: [string "handlePanelMidiMessage"]]: Line: 66 FUNC: 05/08/20 18:49:28 [TRACEBACK] 05/08/20 18:49:28 [FILE: [string "processSingleD"]]: Line: 4 FUNC: validateSysexHeader 05/08/20 18:49:28 [FILE: [string "processSingleD"]]: Line: 305 FUNC: 05/08/20 18:49:28 [FILE: [string "handleKawaiSysex"]]: Line: 129 FUNC: 05/08/20 18:49:28 [FILE: [string "handlePanelMidiMessage"]]: Line: 66 FUNC: 05/08/20 18:49:33 [d is not empty] 05/08/20 18:49:38 [TRACEBACK] 05/08/20 18:49:38 [FILE: [string "processSingleD"]]: Line: 50 FUNC: process_one_single 05/08/20 18:49:38 [FILE: [string "processSingleD"]]: Line: 332 FUNC: 05/08/20 18:49:38 [FILE: [string "handleKawaiSysex"]]: Line: 129 FUNC: 05/08/20 18:49:38 [FILE: [string "handlePanelMidiMessage"]]: Line: 66 FUNC: 05/08/20 18:49:38 [TRACEBACK] 05/08/20 18:49:38 [FILE: [string "generatePatchPrefix"]]: Line: 3 FUNC: generatePatchPrefix 05/08/20 18:49:38 [FILE: [string "processSingleD"]]: Line: 77 FUNC: 05/08/20 18:49:38 [FILE: [string "processSingleD"]]: Line: 332 FUNC: 05/08/20 18:49:38 [FILE: [string "handleKawaiSysex"]]: Line: 129 FUNC: 05/08/20 18:49:38 [FILE: [string "handlePanelMidiMessage"]]: Line: 66 FUNC: 05/08/20 18:49:38 [TRACEBACK] 05/08/20 18:49:38 [FILE: [string "handleKawaiSysex"]]: Line: 6 FUNC: bankChange 05/08/20 18:49:38 [FILE: [string "handleKawaiSysex"]]: Line: 139 FUNC: 05/08/20 18:49:38 [FILE: [string "handlePanelMidiMessage"]]: Line: 66 FUNC: 05/08/20 18:49:38 [TRACEBACK] 05/08/20 18:49:38 [FILE: [string "processSourceMode"]]: Line: 11 FUNC:
And if you saw my earlier post this is a developing stack of what I am doing.
So hopefully one can see I request a single
The Sysex I send out is caught by my handleMidiMessage.
It filters based on size then header content.
And dispatches to handleKawaiSysex because it has that manufactures reserved ID.
We see 97 bytes come in … so we go to next function in the stack ..processSingleD — because this 97 is the exact size of a SYSEX dump for an individual single.And one can see further this calls a method in same file validateSysexHeader. It’s good.
So then we drop back into processSingleD which calls process_one_single. (line 50 of processSingleD).
He generatepathcPrexi and eventually that cpmpletes, pops stakc, pops state and I am done.The complexity that you couldnt have seen
handlePandelMidiMessage … d is == MidiMessage:getData()
that is passed into handleKawaiSysexend elseif handleKawaiSysex(d, size, false) == true then -- cool it worked return 1 else
who then passes this (via my debug we can see)
05/08/20 18:49:28 [FILE: [string "handleKawaiSysex"]]: Line: 129 FUNC: ... elseif size == gSINGLE_SYSEX_TRAN then debugConsole("received single single") worked = processSingleD(d, true) <<<<<<< this is line 129 if worked == true and fromFile == true then -- send to synth utils.warnWindow("\n\nINFO", "About to load Single into K1.") console("sending 1") panel:sendMidiMessageNow(CtrlrMidiMessage(d)) end debugConsole("Endreceived single single") local bias = d:getByte(7) bankChange(bias) end end
so d is still a form of MidiMessage but then the fun starts
Here I convert the subset into a Lua table .. so now I do need the square bracketsfunction processSingleD(--[[ CtrlrLuaMemoryBlock --]] d, --[[ bool --]] singlePatch ) console("in processSingleD") g_debugFile = openDebugFile() whereAmI(g_debugFile, __DFUNC__()) debugConsole("in processSingleD") if validateSysexHeader(d, singlePatch) == false then debugConsole("invalid sysex header") return false end debugConsole("single sysex header was valid", true) if singlePatch == true then debugConsole("Single") local size = d:getSize() local patch = d:getByte(7) debugConsole(""..patch) console("single "..patch) local lp -- skip the F0 -- first 8 bytes and we dont and the F7 and index is a 0 not 1 debugConsole("about to copyTo", true) for i=0, SINGLE_SYSEX_STORAGE_SIZE -1 do g_singlePatch[patch] = d:getByte(8 + i) end debugConsole(string.format("Single %d", size)) debugConsole(string.format("Single %d", g_singlePatch[patch]:getSize() ))
and from now on I need to not use getByte … well maybe I cna use it but it doesnt seem to work because I am a 2 dimensional MemoryBlock.
Simply to say there was no way you could have know that – and this explains why d[ noti ] references noti byte from d. It’s a MeoryBlock that contains wnother memory block
>>> console(what(g_singlePatch[0])) Object type [MemoryBlock] ----------------------------------------------------------------- Members: getData: function setBitRange: function getByte: function loadFromHexString: function toHexString: function insertIntoTable: function setSize: function fillWith: function insert: function setByte: function getSize: function getRange: function removeSection: function createFromTable: function swapWith: function ensureSize: function getBitRange: function copyTo: function replaceWith: function __init: function copyFrom: function toString: function append: function fromBase64Encoding: function toBase64Encoding: function toLuaTable: function Attributes: ----------------------------------------------------------------- Object type [MemoryBlock] ----------------------------------------------------------------- Members: getData: function setBitRange: function getByte: function loadFromHexString: function toHexString: function insertIntoTable: function setSize: function fillWith: function insert: function setByte: function getSize: function getRange: function removeSection: function createFromTable: function swapWith: function ensureSize: function getBitRange: function copyTo: function replaceWith: function __init: function copyFrom: function toString: function append: function fromBase64Encoding: function toBase64Encoding: function toLuaTable: function Attributes:
and most of the above methods, like you said, are suspect. ie copyTo should work but it doesnt. But on 6.x is does 🙂
I am hence using old school scalars to work with my vectors.
When I tried
local name="" for i = 0, 9 do name = name..string.char(d) if d == d:getByte(i) then console("d is same as d:getByte(i)") else console("d is DIFFERENT as d:getByte(i)") end end
it crashes because for sure dLgetByte(i) is not what one expects
And when I comment it out my code works againlocal name="" for i = 0, 9 do name = name..string.char(d) --[[ if d == d:getByte(i) then console("d is same as d:getByte(i)") else console("d is DIFFERENT as d:getByte(i)") end --]] end
May 8, 2020 at 9:31 pm #118277Hey dnaldoog … I thank you from the bottom of my heart (if I have one :-()
So once I realized the semantics of my d -> d … well I renamed them d, mb_d and used d:getByte(i) v mb_d.
What do you know … my 5.3 seems to be working very similar to 6.x before it crashed and stole my Lua.
Chicken and more beer awaits but thank the Lord, and you, that I found my logic errors.
I do hope there is an easier way to get the debug like I showed in another post.
BUT it did help to track down this issue.Thanks again whichever continent you are on .. I have to figure it’s the other side of The Pond 🙂
Cheer and now time to reflect on events of 75 years ago. -
AuthorPosts
- The forum ‘Programming’ is closed to new topics and replies.