123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- local osc = {}
- local numberConverter = require("numberConverter")
- local messageMetatable = {
- __index = function(self, index)
- if index ~= "pack" and index ~= "unpack" then
- return osc[index]
- end
- end,
- }
- function osc.toOSCString(original)
- local valid = #original % 4 == 0
- valid = valid and original:sub(#original) == string.char(0)
- -- we should not attempt to make an already valid osc string into an osc string
- if not valid then
- local newstr = original .. '\0'
- while ((#newstr)) % 4 ~= 0 do
- newstr = newstr .. '\0'
- end
- return newstr
- else
- return original
- end
- end
- function osc.appendArgument(self, newArgument, knownType)
- if knownType then
- self.argString = self.argString .. knownType
- table.insert(self, newArgument)
- else
- -- type check and update arg string
- if type(newArgument) == "number" then
- if newArgument == math.floor(newArgument) then
- self.argString = self.argString .. "i"
- table.insert(self, numberConverter.toNetworkInt(newArgument))
- else
- self.argString = self.argString .. "f"
- table.insert(self, numberConverter.toNetworkFloat(newArgument))
- end
- elseif type(newArgument) == "string" then
- self.argString = self.argString .. "s"
- table.insert(self, osc.toOSCString(newArgument))
- else
- error("invalid type for OSC message: " .. type(newArgument))
- end
- end
- end
- function osc.getArgument(self, index)
- local type = self.argString:sub(index+1,index+1)
- if type == 'i' then
- return numberConverter.intToLuaNumber(self[index])
- elseif type == 'f' then
- return numberConverter.floatToLuaNumber(self[index])
- elseif type == 's' then
- return self[index]:match("[^%z]*")
- else
- error("this should be impossible")
- end
- end
- function osc.unpack(rawDataGram)
- local msg = {}
- setmetatable(msg,messageMetatable)
- -- grab address
- -- this nifty patter to match OSC strings only works if you know there is a non-zero character after
- local addressStart, addressEnd = rawDataGram:find("[^%z]+%z+")
- msg.addr = rawDataGram:sub(addressStart, addressEnd)
- -- grab argString
- msg.argString = rawDataGram:match("[^%z]+", addressEnd+1)
- -- start of arg len of str offset for the nulls
- argEnd = addressEnd + #msg.argString + (4 - #msg.argString % 4)
-
- -- grab the arguments
- local dataStart = argEnd+1
- for index=1,#msg.argString,1 do
- local c = msg.argString:sub(index,index)
- -- we treat each type a bit differently
- if (c ~= '\0' and c ~= ',') then
- if (c == 'i') then
- msg[index-1] = rawDataGram:sub(dataStart, dataStart+3)
- dataStart = dataStart + 4
- elseif (c == 'f') then
- msg[index-1] = rawDataGram:sub(dataStart, dataStart+3)
- dataStart = dataStart + 4
- elseif (c == 's') then
- local stringEnd = rawDataGram:find(string.char(0), dataStart)
- local stringLen = stringEnd - dataStart + 1
- local dataLen = stringLen + (4-stringLen%4)
- local dataEnd = dataStart + dataLen - 1
- msg[index-1] = rawDataGram:sub(dataStart,dataEnd)
- dataStart = dataEnd + 1
- end
- -- maybe a case fore timestamp
- -- maybe a case for blobs but i probably dont care
- end
- end
- return msg
- end
- -- packs our message table back into a string that is ready to get shot over the network
- function osc.pack(tbl)
- local oscMessage = tbl.addr .. osc.toOSCString(tbl.argString)
- for i=1, #tbl, 1 do
- oscMessage = oscMessage .. tbl[i]
- end
- return oscMessage
- end
- function osc.create(addr, ...)
- local arg = {...}
- local msg = {
- addr = osc.toOSCString(addr),
- argString = ",",
- }
- for _, a in pairs(arg) do
- osc.appendArgument(msg,a)
- end
- return msg
- end
- return osc
|