osc.lua 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. local osc = {}
  2. local numberConverter = require("numberConverter")
  3. local messageMetatable = {
  4. __index = function(self, index)
  5. if index ~= "pack" and index ~= "unpack" then
  6. return osc[index]
  7. end
  8. end,
  9. }
  10. function osc.toOSCString(original)
  11. local valid = #original % 4 == 0
  12. valid = valid and original:sub(#original) == string.char(0)
  13. -- we should not attempt to make an already valid osc string into an osc string
  14. if not valid then
  15. local newstr = original .. '\0'
  16. while ((#newstr)) % 4 ~= 0 do
  17. newstr = newstr .. '\0'
  18. end
  19. return newstr
  20. else
  21. return original
  22. end
  23. end
  24. function osc.appendArgument(self, newArgument, knownType)
  25. if knownType then
  26. self.argString = self.argString .. knownType
  27. table.insert(self, newArgument)
  28. else
  29. -- type check and update arg string
  30. if type(newArgument) == "number" then
  31. if newArgument == math.floor(newArgument) then
  32. self.argString = self.argString .. "i"
  33. table.insert(self, numberConverter.toNetworkInt(newArgument))
  34. else
  35. self.argString = self.argString .. "f"
  36. table.insert(self, numberConverter.toNetworkFloat(newArgument))
  37. end
  38. elseif type(newArgument) == "string" then
  39. self.argString = self.argString .. "s"
  40. table.insert(self, osc.toOSCString(newArgument))
  41. else
  42. error("invalid type for OSC message: " .. type(newArgument))
  43. end
  44. end
  45. end
  46. function osc.getArgument(self, index)
  47. local type = self.argString:sub(index+1,index+1)
  48. if type == 'i' then
  49. return numberConverter.intToLuaNumber(self[index])
  50. elseif type == 'f' then
  51. return numberConverter.floatToLuaNumber(self[index])
  52. elseif type == 's' then
  53. return self[index]:match("[^%z]*")
  54. else
  55. error("this should be impossible")
  56. end
  57. end
  58. function osc.unpack(rawDataGram)
  59. local msg = {}
  60. setmetatable(msg,messageMetatable)
  61. -- grab address
  62. -- this nifty patter to match OSC strings only works if you know there is a non-zero character after
  63. local addressStart, addressEnd = rawDataGram:find("[^%z]+%z+")
  64. msg.addr = rawDataGram:sub(addressStart, addressEnd)
  65. -- grab argString
  66. msg.argString = rawDataGram:match("[^%z]+", addressEnd+1)
  67. -- start of arg len of str offset for the nulls
  68. argEnd = addressEnd + #msg.argString + (4 - #msg.argString % 4)
  69. -- grab the arguments
  70. local dataStart = argEnd+1
  71. for index=1,#msg.argString,1 do
  72. local c = msg.argString:sub(index,index)
  73. -- we treat each type a bit differently
  74. if (c ~= '\0' and c ~= ',') then
  75. if (c == 'i') then
  76. msg[index-1] = rawDataGram:sub(dataStart, dataStart+3)
  77. dataStart = dataStart + 4
  78. elseif (c == 'f') then
  79. msg[index-1] = rawDataGram:sub(dataStart, dataStart+3)
  80. dataStart = dataStart + 4
  81. elseif (c == 's') then
  82. local stringEnd = rawDataGram:find(string.char(0), dataStart)
  83. local stringLen = stringEnd - dataStart + 1
  84. local dataLen = stringLen + (4-stringLen%4)
  85. local dataEnd = dataStart + dataLen - 1
  86. msg[index-1] = rawDataGram:sub(dataStart,dataEnd)
  87. dataStart = dataEnd + 1
  88. end
  89. -- maybe a case fore timestamp
  90. -- maybe a case for blobs but i probably dont care
  91. end
  92. end
  93. return msg
  94. end
  95. -- packs our message table back into a string that is ready to get shot over the network
  96. function osc.pack(tbl)
  97. local oscMessage = tbl.addr .. osc.toOSCString(tbl.argString)
  98. for i=1, #tbl, 1 do
  99. oscMessage = oscMessage .. tbl[i]
  100. end
  101. return oscMessage
  102. end
  103. function osc.create(addr, ...)
  104. local arg = {...}
  105. local msg = {
  106. addr = osc.toOSCString(addr),
  107. argString = ",",
  108. }
  109. for _, a in pairs(arg) do
  110. osc.appendArgument(msg,a)
  111. end
  112. return msg
  113. end
  114. return osc