Forum Replies Created
-
AuthorPosts
-
Glad it worked. I was thinking about getting and 8GB Pi 4 and using RAM disk.
I found my original VMs as virtual box. This has the cross compiler setup so much faster than Pi.Don’t forget the gotcha when opening panels – the Linux meds something unticked.
My mate loaned me his touch screen and it worked well. I met a YT via K1 posts – he has a Linux tablet that runs Ctrlr. I sure would love a powerful tablet so that I could also run ZynAddSubFX – Pi doenwt quite run it fast enough
Anyhow glad you got it to build – I found I used the debugger to get to learn more about the internals of Ctrlr.
curse of the darned code blocks!! As you once mentioned [ followed by i followed by ] seems to go to /dev/null.
In the above it did say mb:append(MemoryBlock( { g_singlePatch\[i\][z] } ) ) where I added \[ \] … remove them!!
Why is there no “preview” in this wordpress??
thanks so this is what I did to convert from what appeared to work in 6.x to 5.3.201
I really appreciate your assistance – I was finally able to create bpanelz based on my K1r editor and upload it to my Sourceforge site, and downloaded to new PC, with 5.3.201 installed it unpacked and all the images etc plus importantly the LUA code was there!!!
Now to sort out the means channel in Ctrlr — sure I think you realize I know what a midi channel is but more like how the Ctrlr is wired internally – I already created a post on that and once I find out I will repost.
Best regards
Stevefunction dumpSingleBlockIndividually(ch, bias) -- here we have read a multiBlock into our local buffers -- if you send the whole block to the K1r it chokes. -- so instead we create the sysex necessary to send as individuals. for i = 0, 31 do addDelayMS(125) console("i "..i) --[[ this worked on 6.x but not on 5.3 local sysex = string.format("F0 40 %02x 20 00 03 00 %02x ",ch, i + bias) sysex=sysex..g_singlePatch:getRange(0, g_singlePatch:getSize() - 1):toHexString(1) local checksum = 0xA5 for j=0, g_singlePatch:getSize()-1 do checksum = checksum + g_singlePatch:getByte(j) end -- console("checksum"..checksum) checksum = BitAND(checksum, 127) console("checksum"..checksum) sysex = sysex..string.format(" %02x F7",checksum) -- console(""..sysex) --]] mb =MemoryBlock() mb:loadFromHexString( string.format("F0 40 %02x 20 00 03 00 %02x ",ch, i + bias) ) -- notice kinky { } around your value to make it into valid tuple for MemoryBlock for z = 0, g_singlePatch:getSize() - 1 do mb:append(MemoryBlock( { g_singlePatch[z] } ) ) end local checksum = 0xA5 for j=0, g_singlePatch:getSize()-1 do checksum = checksum + g_singlePatch[j] end checksum = BitAND(checksum, 127) mb:append(MemoryBlock( { checksum } ) ) mb:append(MemoryBlock( { 0xF7 } ) ) panel:sendMidiMessageNow(CtrlrMidiMessage(String(mb:toHexString(1)))) end end
and then … after I get it working again … Ctrlr throws all my Lua to /dev/null. In 5.3 as well as 6.x now.
Sorry but this is getting a little concerning – I can see I am not the first victim here.
Also, in 5.3 there doesnt seem to be an export – in 6.x you can save the Lua.All very well for folks to say “just back it up” (which I have last night backup of) but there’s no easy way to be sure what Ctrlr writes.
Really quite unstable environment.
Recently when I recovered my code (from fragements) the next day the Ctrlr had found a lot of my code anyhow … go figure.
Hey 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.Ah … 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
zB 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)
what’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 🙂
So 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.
Here’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 🙂
depends 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.I 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
this 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.
I tend to do that (talk to myself) – trouble of having an Autistic brain 🙁
Somehow I found a 6.x build and “assumed” that oh the main page must just be out of date. Thanks for confirming I should be using a 5.x Ctrlr.
I accept that my issue was mostly due to me “hardcore” editing the XML – 5.x handles this better than 6.x.
I had seen a number of posts with similar issue – Crash but no debug strategy – that’s why I built to debug at lowest level and this lead me to realise “ah … Ctrlr expects path in a certain format” – which I had hacked [[did I mention my day job is uncovering insecure assumptions that dev’s make?]].In this case, it does seem that there is an issue even in 5.x.
My F:\temp causes assertion failure on Linux – Linux then does not allow me to edit that “invalid” entry (short of vim the panel with all the issues that hit).Simply to say in breaking my panel I learnt a lot more about Ctrlr – and I seems my RPi build is still ok for me to use since it is based on the latest stable codebase – thanks for helping to confirm that.
Now to check I can release my panel under 5.x and “ship it”.
Thanks again
Steveok so I _think_ I found either a bug or at least a regression in 6.x v 5.x
SHORT VERSION
I can load my panel even with logic error into 5.x but not into 6.x.
Is this some sort of regression???LONGER VERSION
I am still to stupid to work out how to build the latest source from git.
But I found my VM that I used to build RPi from (with the cross compiler).
And of course this has an older G++ on it, so I hacked similar makefile changes, and convinced Linux to build debug version base on a 5.x codebase.Long and the short of it – I stupidly edited the panel XML to remove path from the various directories.
I didnt want f:\Interests\Synths\K1r all over the place … well Atom already knows how that’s gonna work out!!So in 5.x I could debug on Linux. And with one panel it complains about assertion in Juce code. BUT crucially it loads. A bit of a bug – it dont like my f:\ … but it wont let me change it .. so I have to change that via vim and XML.
On Windows I installed my old and new Ctrl in two separate directories.
You have to be careful about the ~/AppData/Roaming … and 5.x will load my modified panel (where I create a path f:\temp\Ctrlr in front of all resources/panel).
Linux complains about this f:\ and wont let me edit it.Let me give a concrete example:
Fixed thanks to my debugging and working in 5.x
shooking@MUSICPC /cygdrive/f/temp/Ctrlr
$ grep “F:” MyMultiPanel000.panel
luaPanelOSCReceived=”– None” panelFilePath=”F:\temp\Ctrlr\MyMultiPanel000.panel”
resourceSize=”1049″ resourceFile=”backdrop_texture.jpg” resourceSourceFile=”F:\temp\Ctrlr\backdrop_texture.jpg”
resourceSize=”32270″ resourceFile=”K1rCardImage_crop.jpg” resourceSourceFile=”F:\temp\Ctrlr\K1rCardImage_crop.jpg”
resourceSize=”341672″ resourceFile=”k1r_fader.png” resourceSourceFile=”F:\temp\Ctrlr\k1r_fader.png”
resourceSize=”288674″ resourceFile=”64×64.png” resourceSourceFile=”F:\temp\Ctrlr\64×64.png”
resourceSourceFile=”F:\temp\Ctrlr\bidirect_64x64.png”
uiFileListFileDoubleClicked=”loadSysexFromDisk” uiFileListCurrentRoot=”F:\temp\Ctrlr”before you can imagine I removed the f:\temnp\Ctrlr and hoped Ctrlr would look in .\
I attach pictures from the debug on 5.x
If I could work out how to build on 6.x I am confident I can be a useful resource to the community.
In the meantime I think I will recommend to anyone wanting to use my panel to use 5.x Ctrlr since 6.x is not playing as nice as I would like
Attachments:
You must be logged in to view attached files.ok I found Ctrlr caches stuff in my AppData/Roaming/Ctrlr
But still crash – original panel loads ok.
Any hints on how to successfully expert?I did see Export but this doesnt seem to help.
I tried exporting XNL, “exe” which produces a bzpanel … I left names same … crash.Dange . and then it DID flash up my panel and write out a crash dump
C:\Program Files (x86)\Ctrlr>more Ctrlr-Win32.exe.crash
Ctrlr crash at: 30 Apr 2020 17:26:35
Stack trace:
3: UnhandledExceptionFilter + 0x1a0
4: RtlCaptureStackContext + 0x197c8
5: RtlGetAppContainerNamedObjectPath + 0xb4which is what the GUI popped up.
so some object path error?Interesting – if I run as admin
3: UnhandledExceptionFilter + 0x1a0
4: RtlCaptureStackContext + 0x197c8
5: RtlGetAppContainerNamedObjectPath + 0xb4
and complains about a 32 bit version 🙂It claims it wants to write the file to Ctrlr-Win32.exe.crash – which it doesnt.
I tried to build from source by my VS2019 preview doesnt want to play nicely.
I might try to fire up Linux.Like Atom said use something like MidiOx to observe the patterns. Any midi that claims to be larger than 7 bit has to be made from two CCs, a RPN or a NRPN for current midi standard.
If you find a commercial platform with a demo mode you could play that into MidiOx and see what that panel does.
Once you checked up on that and any spec available then plan your layout and check out similar panels for hints on how to achieve what you want.
Yes. I asked related question on https://ctrlr.org/forums/topic/any-documentation-on-midi-input-controller-output/#post-117905
See I need to send Sysex to and from a K1r. But I also want to be able to control it from a keyboard (it’s a sound module).
What I am finding is Ctrl hangs a lot. Hence I tried the reset trick. And if I set the Controller to the none well it crashes instantly.
Would be good to find definitive definition with some pictures on how to view Ctrlr. Linking in to out isn’t what a real thru does. I would prefer if Ctrlr behaved more like a standard Midi device.
In that case I would have to put k1r out to Ctrlr in and vice versa to allow sysex transfer both ways. And I would need a midi merge if I also.wanted to trigger internal k1r sounds
It seems from my experients that this is what the Controller channel is doing …it merges midi in with the controller input except I would have to write logic to forward on certain midi events.
If I connect so called thru and send a sysex it doesn’t take much for the panel to crash. Without thru it is more stable – not perfect but for sure better.
-
AuthorPosts