Home Forums General Programming tonumber to convert to hex?

This topic contains 21 replies, has 4 voices, and was last updated by goodweather goodweather 5 days, 22 hours ago.

Viewing 20 posts - 1 through 20 (of 22 total)
  • Author
  • #72611

    human fly

    i want to convert ascii to hex. i can currently do it to decimal
    (using something i found) and there’s an example panel to illustrate


    (getDatas v02.panel)

    i see in Goodweather’s DSI Pro2 panel ‘miscellaneous’ method:

    -- 	For the conversion of a DECimal number to anything else
    --	it is just needed to use the built-in Lua function tonumber(string, base)
    --	print(tonumber("0100",2))
    --	4
    -- 	print(tonumber("3F",16))
    -- 	63

    and i would like to figure out how to use it in a method.
    i tried a couple of things but it was just poking around
    in the dark. one worked, the other reported a concatenation
    with a global variable error. i’ve forgotten what i did this
    morning, it may not have been far off.
    does tonumber() ‘know’ the characters for hex representation?
    must assume it does, if it can convert 3F to 63.

    i tried to mess around with this:
    and put instead:
    i think that one produced the concatenation error …
    the other one actually produced a result, but it was a 3-figure
    decimal, not what i was after.


    Hopefully this helps.

    This is the method I use in a panel I’m developing for the Kurzweil PC3/Artis/Forte

    Symbols is an array initialized in my initializePanel method. (Borrowed from the Miniak Panel, as the PC3 uses the same symbol set)

    symbols = { [0]=””,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,
    ” “,”!”,”\””,”#”,”$”,”%”,”&”,”‘”,”(“,”)”,”*”,”+”,”,”,”-“,”.”,”/”,
    “0”,”1″,”2″,”3″,”4″,”5″,”6″,”7″,”8″,”9″,”:”,”;”,”< ","=",">“,”?”,
    symbols2 = { [0]=””,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,”|”,
    ” “,”!”,”\””,”#”,”$”,”%”,”&”,”\'”,”(“,”)”,”*”,”+”,”,”,”-“,”.”,”/”,
    “0”,”1″,”2″,”3″,”4″,”5″,”6″,”7″,”8″,”9″,”:”,”;”,”< ","=",">“,”?”,

    Data is the SYSEX dump assigned in the MIDI Receive method

    data = midi:getData()

    To generate the Program name I do this

    local a={}
    for i=0,30 do -- this collects first 31 bytes and puts them into array a. This should include the program name.
    end โ€“for

    Then later.

    		while a[j] ~= 0x00 do
    			name = name..symbols[a[j]]
    		end --while
    		prgName[receivedProgramNum]=": "..name
    		-- update Program Received
    		currentProg = string.format(nPrg)

    I need the while statement because on the PC3 the program name is variable length and delimited by 0x00. If you have a fixed length program name you could make the while statement while a[j] < 20 (for example)

    • This reply was modified 1 week, 6 days ago by Puppeteer Puppeteer.
    • This reply was modified 1 week, 6 days ago by Puppeteer Puppeteer.

    The Puppeteer


    human fly

    haha well thanks for the symbols list ๐Ÿ™‚ i can copy that.
    was dreading having to type that lot out in notepad… i think
    i’ve got a wrong count for ascii to decimal anyway: i think
    ‘A’ should be 47 not 48 (??? …forgotten… or is that ‘0’..)
    -we need a ‘resources’ sticky somewhere with useful stuff
    like that.

    it would be useful to see what tonumber() (class?) looks like,
    eg: what is does/how it works.

    all i’m trying to do at this point is send the separate byte results
    to their labels, the way i’m doing with the decimal. i can see how
    tonumber() works with ‘print’/console (in theory) but didn’t yet
    get it to write to a label with setProperty("uiLabelText")

    nb: my ‘coding’ is still extremely basic: i can manage routine stuff
    quite well now, find a few things for myself, but not much good with
    iterative/recursive stuff yet.

    i *really really* need some way to play around with console-type
    results within the Ctrlr workspace – can’t be too hard to send it
    to a uiLabel rather than Console?(my imagination is a bit lumpen
    as i write; need to pick up on that idea again).

    because this, to me, is how i’m going to master assigning variables,
    iteration operations etc. – ie: a friendlier way of observing results,
    because i find opening the console page before triggering the method
    not very satisfying – note that i quite like making these little
    demo panels to test something out while i get the hang of it.(can kick
    up all sorts of ideas/revelations too)


    The last line of my example does this


    The Puppeteer


    Here is how I convert ASCII to HEX. You could do it using loops but with as few as 18 chars I went the stupid way:

    	-- GET the Patch Name
    	local PatchName=L(panel:getComponent("PatchName"):getPropertyString("uiLabelText"))
    	local PatchNameUp=string.upper(PatchName)
    	-- Store each char in a variable and convert it from ASCII to numerical code
    	local char1 =string.byte(PatchNameUp, 1)
    	local char2 =string.byte(PatchNameUp, 2)
    	local char3 =string.byte(PatchNameUp, 3)
    	local char4 =string.byte(PatchNameUp, 4)
    	local char5 =string.byte(PatchNameUp, 5)
    	local char6 =string.byte(PatchNameUp, 6)
    	local char7 =string.byte(PatchNameUp, 7)
    	local char8 =string.byte(PatchNameUp, 8)
    	local char9 =string.byte(PatchNameUp, 9)
    	local char10=string.byte(PatchNameUp,10)
    	local char11=string.byte(PatchNameUp,11)
    	local char12=string.byte(PatchNameUp,12)
    	local char13=string.byte(PatchNameUp,13)
    	local char14=string.byte(PatchNameUp,14)
    	local char15=string.byte(PatchNameUp,15)
    	local char16=string.byte(PatchNameUp,16)
    	local char17=string.byte(PatchNameUp,17)
    	local char18=string.byte(PatchNameUp,18)
    	-- Check for empty chars and put each char value in _G["ToneTabNr"..t] (with corresponding byte number)
    	if char1 == nil then char1 =32 end _G[PatchTblName..p][10]=string.format("%.2x", char1)
    	if char2 == nil then char2 =32 end _G[PatchTblName..p][11]=string.format("%.2x", char2)
    	if char3 == nil then char3 =32 end _G[PatchTblName..p][12]=string.format("%.2x", char3)
    	if char4 == nil then char4 =32 end _G[PatchTblName..p][13]=string.format("%.2x", char4)
    	if char5 == nil then char5 =32 end _G[PatchTblName..p][14]=string.format("%.2x", char5)
    	if char6 == nil then char6 =32 end _G[PatchTblName..p][15]=string.format("%.2x", char6)
    	if char7 == nil then char7 =32 end _G[PatchTblName..p][16]=string.format("%.2x", char7)
    									   _G[PatchTblName..p][17]="00" -- This Byte is not used
    	if char8 == nil then char8 =32 end _G[PatchTblName..p][18]=string.format("%.2x", char8)
    	if char9 == nil then char9 =32 end _G[PatchTblName..p][19]=string.format("%.2x", char9)
    	if char10== nil then char10=32 end _G[PatchTblName..p][20]=string.format("%.2x",char10)
    	if char11== nil then char11=32 end _G[PatchTblName..p][21]=string.format("%.2x",char11)
    	if char12== nil then char12=32 end _G[PatchTblName..p][22]=string.format("%.2x",char12)
    	if char13== nil then char13=32 end _G[PatchTblName..p][23]=string.format("%.2x",char13)
    	if char14== nil then char14=32 end _G[PatchTblName..p][24]=string.format("%.2x",char14)
    									   _G[PatchTblName..p][25]="00" -- This Byte is not used
    	if char15== nil then char15=32 end _G[PatchTblName..p][26]=string.format("%.2x",char15)
    	if char16== nil then char16=32 end _G[PatchTblName..p][27]=string.format("%.2x",char16)
    	if char17== nil then char17=32 end _G[PatchTblName..p][28]=string.format("%.2x",char17)
    	if char18== nil then char18=32 end _G[PatchTblName..p][29]=string.format("%.2x",char18)

    human fly

    Puppeteer’s method is a bit complex for what i need.
    i recognise Possemo’s because it is similar to what
    i’ve used so far to extract from ascii characters on the
    label to separate labels, as decimal numbers
    -but i realise i have no idea how it works ๐Ÿ™‚

    ? > what is ‘string.byte’, as in:

    character1 = string.byte(NewPatchName,1)

    i assumed it just goes through a string assigning each
    character as a byte..but how does it know what decimal
    to assign to characters?

    Possemo please explain your method, it
    looks like it could do it here – if you could go through
    and explain what’s going on … you know how useless
    i am at coding lol so …

    here’s what i found in Goodweather’s panel:

    dec2hex = function(num)
        local hexstr = '0123456789ABCDEF'
        local s = ''
        while num > 0 do
            local mod = math.fmod(num, 16)
            s = string.sub(hexstr, mod+1, mod+1) .. s
            num = math.floor(num / 16)
        if s == '' then s = '0' end
        return s


    function str2hex(str)
        local hex = ''
        while #str > 0 do
            local hb = dec2hex(string.byte(str, 1, 1))
            if #hb < 2 then hb = '0' .. hb end
            hex = hex .. hb
            str = string.sub(str, 2)
        return hex

    how/where would one use these?(and how do they work?)

    i’m going to try out your code and see what happens,
    in the meantime.


    human fly

    (Puppeteer: i think i can see what your method does – it isn’t quite
    what i’m trying to do, as it produces a single string/result)

    OK i tried Possemo’s and got a string concatenation error
    -global PatchTblName was a nil value, because i haven’t got it defined.

    so it is trying to concatenate it into a single string – i’m not ready
    for that yet ๐Ÿ™‚ i am trying to send each ‘byte’ individually to its own
    label first – just to check/observe conversion to hex.
    that’s why i’m curious about tonumber(string,base) – and these other
    convert methods.

    my current ‘enterToneName’, at this point, goes:

    if value~=nil then 

    and this sends the text characters onto the labels as decimals – but not
    as hex. i’m thinking i need a little subfunction i can invoke at this
    point to perform translation on each byte (ok, i know it won’t be any
    use at this stage, because hex needs the prefix ‘0x’ to be useful – unless
    i include that in the process).


    human fly

    ok: myBad: … i’m not conversant with ‘%.2x’. or was lost
    in the avalanche of things i’ve been familiarising myself

    reading this: (if you can think of more targeted info…)

    so it appears ‘%’ means hex?
    and this is a representation/definition of string format?
    (still looking for more reading matter..)

    On the difference of the meaning of 2 in “0x%2x” and “0x%.2x”:

    In “0x%2x” the 2 defines the “fieldwidth”: if the hex representation of the value consists of less than 2 digits, it is prefixed with spaces to end up with a fieldwidth of 2.

    In “0x%.2x” the 2 defines the precision: there will be at least 2 hex digits in the result, if the representation of the value has less digits, it is prefixed with 0’s

    Some examples (using 4 as width, for clarity):
    Printf(“0x%4x”,12) “0x C”
    Printf(“0x%.2x”,12) “0x0C”
    Printf(“0x%4.2x”,12) “0x 0C”
    Printf(“0x%04x”,12) “0x000C”

    mmm.. so i can generate the ‘0x’ prefix like that, yeah?


    once again, I think you are searching too far and too complex…
    What do you want to achieve precisely?
    Do you need the hexa representation or the values?
    An hexa value is the same as the corresponding decimal one
    So, writing myVar = 0x2A is the same as writing myVar = 42
    You write 0x to indicate it is hexa.
    Please note that there are no quotes around 0x2A because it is not a string but a value.

    tonumber() is a standard Lua function as tostring().
    tonumber converts from any base to decimal.

    So, back to basics: what do you want to achieve?
    From there I can hopefully guide you in an easy way ๐Ÿ™‚


    Something else…
    In your initial post you get an error with

    It’s because you made errors the end.
    .. concatenates strings. So you must have strings…
    with tonumber() you get… a number ๐Ÿ˜‰
    Correct syntax is thus:
    setPropertyString("uiLabelText", tostring(tonumber(character1, 16)))
    Assuming character1 is a string looking as an hexa number.
    character1 = “2A”


    human fly

    aha. thanks – i tried it but it isn’t producing expected results ๐Ÿ™‚

    here, have a look at this little test panel:
    one method extracts decimal numbers from the text string,
    and the other is supposed to extract it as hex.

    (look in the ‘reference’ lua folder)



    edit: looks like it is treating the source number as a
    hexadecimal it wants to convert to decimal: 50 is decimal
    for 0x32 – so tonumber would appear to convert TO decimal,
    but not to hex.(correct?)

    what are dec2hex and strng2hex for, and how are they used?
    Possemo’s method with the %.2x seems like the path to
    pursue.. but it’s missing a line about that global macro
    thingy.(is it?)


    Looking at your panel…
    Can you explain me what you are trying to do (not what you do in this conversion)?
    Like: a get a patch in sysex and wants to convert to decimal OR I have a text file containing hexa text separated by blanks and wants to see it in decimal OR…

    Knowing that I can surely help you.

    Coming back to your panel (please correct me)
    – you enter a patch name
    – pressing enterToneName you get the decimal representation
    – pressing getHex you want to get the same but in hexa

    tonumber(string, base): standard Lua function converting a number represented as a string in a certain base to decimal
    Example1: from binary to decimal you do tonumber(“0101”, 2) to give 5
    Example2: from hexa to decimal you do tonumber(“3F”, 16) to give 63

    dec2hex(integer): “decimal to hexa” = own function to convert an integer to an hexa represented as a string (thus not the hexa value!)
    dec2hex(63) gives “3F”
    In Ctrlr console you test with

    In your code if you write 63 or 0x3F (without any quote), this is exactly the same. You are using the value of the number; not its representation.
    This is very important to understand! Don’t mix value and text representation.
    You should use text representation only to show to the user (seldom needed) or to verify some value when not in decimal.

    str2hex(string): “string to hexa” = own function to convert a string to an hexa representation as a string
    str2hex(“Hello”) gives “48656C6C6F”
    In Ctrlr console you test with
    I’m using this function to store patch names in sysex.

    For all sysex and patch manipulations (reading, writing, modifying) I strongly advise you to use MemoryBlocks. Very easy to use and very flexible. You can read any byte or range, append, suppress, replace… perform operations between blocks…

    for your getHex and to get your 8 LCD filled in:
    – fill lcd1 with string.sub(str2hex(patchname),1,2)
    – fill lcd2 with string.sub(str2hex(patchname),3,4)

    Back to the main question: why do you want to see the hexa string of the name?


    I’m a bit late, here is a little explanation of my code. I have to say that this is Carl Licroy’s code not mine. I copied it from one of his panels. This is a snippet of a method that copies the actual patch data (including the patch name from an uiLabel) into the library. It will construct a valid sysex dump that can be sent to the synth or saved to disk.
    string.byte(PatchNameUp, 1)
    This returns the numerical code of the first character of the string called PatchNameUp. So for “ALCOHOL” it would return 65 – the numerical code of “A”.

    Then I put the number into a table to construct the sysex dump:
    PatchDataValuesTable[10]=string.format("%.2x", char1)
    string.format formats a string. I know this is a bit strange. Maybe Goodweather would know a more elegant way but it works. %x will convert the number it to hex, .2 will always return two digits, like 04, or 0F – needed for a working sysex dump.

    Btw. string.format is very useful when you want to ouput a numeric variable to the console for debugging / checking purpose.

    console(MyNumber) -- this does not work - console needs a string.
    -- you can do it like this:
    console(string.format("%x", MyNumber)) -- as hex
    console(string.format("%d", MyNumber)) -- as decimal
    console(string.format("%c", MyNumber)) -- as ascii charcter

    There are lots of other string.format variations, see here:

    It may be a bit weird making a table filled with strings when you want a hex sysexdump but it works flawlessly and the code is very fast. When you want to send the sysex dump to the synth you just have to do this:

     -- the table has 279 records. concatenate them all into a single string with a space between the records.
    PatchDat=table.concat(PatchDataValuesTable," ",1,279)
     -- make a memoryblock out of the big string
     -- send it to the synth

    Well, even if this method is working I would say it doesn’t sound so straightforward / efficient imho…
    You would work directly with MemoryBlocks where each byte is a value that you can adapt as you want without getting the burden of string manipulations.
    A sysex dump is a memory block; a file content can go to a memory block; the midi message data is memory block…

    Some examples:

    -- empty mb creation
    BasicProgramData = MemoryBlock()  
    -- creation based on another mb
    LoadedProgramData = MemoryBlock(BasicProgramData)  
    -- checking size (used for dumps)
    LoadedProgramData:getSize() == 1024  
    -- converting patch name into a mb using my function str2hex explained above
    mbTemp = MemoryBlock(str2hex(txtProgramName:getComponent():getProperty("uiLabelText")))
    -- replacing a 20 characters patch name in an existing mb
    LoadedProgramData:copyFrom (mbTemp,378, 20)
    -- setting a byte according to a modulator value. 4 is the offset in the sysex dump
    LoadedProgramData:setByte(4, modOsc1Pitch:getModulatorValue())
    -- setting a modulator based on a byte
    modOsc1Pitch:setValue(LoadedProgramData:getByte(4), true)
    -- setting a label based on a range of bytes
    txtProgramName:getComponent():setPropertyString ("uiLabelText", LoadedProgramData:getRange(378,20):toString())

    Actually in a panel, beside a patch name, all data is numbers. So why going to hexa text and not using hexa directly? And a patch name can easily get converted to numbers.
    So you can just do things like the following, there are the same:

    LoadedProgramData:setByte(4, modOsc1Pitch:getModulatorValue())
    LoadedProgramData:setByte(4, 63)
    LoadedProgramData:setByte(4, 0x3F)

    On top of that, in many cases, the bytes get packed/unpacked.

    So I would say:
    – make a memory block (empty or not, copied from another one…)
    – adapt content with setByte, append, copyFrom…
    – send as midi message or save to a file

    Info on memory blocks at Juce API: https://www.juce.com/doc/classMemoryBlock

    There will be a paragraphs on mb in Step by step guide 2.0 (I have fixed a release date target to end of this year – whatever state. It is delayed because I’m changing from Sub37 explanations to Pro 2 ones + adding a lot of stuff. Also delayed because I’m doing further additions to my Pro 2 panel + created a Prophet 12 one)

    Good discussion even if the initial topic was looking very simple to answer ๐Ÿ™‚


    human fly

    great, more stuff to try ๐Ÿ™‚
    in fact i found a solution after my last post, and can now
    concatenate a table with spaces(or whatever you want) between
    bytes hehe. new mini-panel here:

    i did this:

    if character1 == nil then character1 = "32" else character1 = ""..character1 end 
    hexNameTabl[1] = string.format("%.2x", character1)

    setPropertyString needed the table part with square brackets but would not
    accept it with regular brackets and comma – is that because it was a macro
    before ( with the Carl Licroy method)?

    this gets individual bytes onto the labels. and then to put them all in
    a single string with spaces beteen on a single label:

    hexDatasConcat = table.concat(hexNameTabl, "-", 1, 10)
    --console ("hexDatasConcat : "..hexDatasConcat)

    edit: correction: i put a ‘-‘ (hyphen) instead of a space with that example, just to check what happened/where they were inserted.


    Well, as I explained above, I just find the method not adequate at all.
    But this is the beauty of programming: a lot of different ways to achieve some result…
    Just a matter of taste and colors ๐Ÿ˜‰


    @goodweather: I remember when I quickly looked into your panel I saw that you manipulate memoryblocks directly. Unfortuntely, at that time I already finished my panels. When you are not experienced in coding it is maybe a bit easier to work with strings first. You can debug it easily. Well this could be just false pretence. On my next panel I will try your way.

    @human fly: one unconvenient thing about working with tables and converting them later into memoryblocks: Lua tables are starting with record [1], memoryblocks are starting with byte 0. When you want to put a value into byte position 10 you must put it into table record nr [11]. So a dump begins with PatchDataValuesTable[1]=”F0″ (will be byte nr. 0)


    Hรฉhรฉ… and I don’t remember how I discovered the memory blocks… Hahaha, funny…
    Either the Virus panel from dasfaker or some other forum topic.

    Anyway, when I find a new object, mainly by reading Ctrlr forum topics, I’m then looking in Juce API to check if this is not an object and if yes I can then see all the possible functions (did it for mb but also for checking the left/right keys…

    About memory blocks, they are very flexible…


    human fly

    Well, as I explained above, I just find the method not adequate at all.
    But this is the beauty of programming: a lot of different ways to achieve some resultโ€ฆ
    Just a matter of taste and colors ๐Ÿ˜‰

    haha well i’m a newb so i’m trying to get things working by any means
    necessary, and i’ll worry about elegance later – i did see memory blocks
    used, and did see that type of method, and it all looks interesting.
    i just found this more accessible at this point – and i’m still juggling
    lots of concepts i’m not fully conversant with.

    as for converting to text first: yes, agree, not necessary at all, just
    wanted to get it visible on screen and play around with it a bit.
    (if you want to have a look at where i’ve got to with my main panel,
    i posted a recent instance on the D-110 thread)


    …and I forgot to mention that if you want to see the content of a memory block in hexa (for verification in the console for example) then you do that with one single command. Easy ๐Ÿ™‚


Viewing 20 posts - 1 through 20 (of 22 total)

You must be logged in to reply to this topic.

Comments are closed.