Difference between revisions of "Gideros LOSC"

From GiderosMobile
(Created page with "__TOC__ === LOSC === OSC 1.0 implementation for lua. Github: '''https://github.com/davidgranstrom/losc''' '''License''': * MIT License '''Features''': * implements the compl...")
 
(wip)
Line 1: Line 1:
 
__TOC__
 
__TOC__
=== LOSC ===
+
=== OSC ===
 +
OpenSoundControl: '''https://ccrma.stanford.edu/groups/osc/index.html'''
 +
 
 +
From '''''Wikipedia''''', the free encyclopedia
 +
 
 +
'''Open Sound Control (OSC) is a protocol for networking sound synthesizers, computers, and other multimedia devices for purposes such as musical performance or show control. OSC's advantages include interoperability, accuracy, flexibility and enhanced organization and documentation. Its disadvantages include inefficient coding of information, increased load on embedded processors, and lack of standardized messages/interoperability. The first specification was released in March 2002.'''
 +
 
 +
==== LOSC ====
 
OSC 1.0 implementation for lua. Github: '''https://github.com/davidgranstrom/losc'''
 
OSC 1.0 implementation for lua. Github: '''https://github.com/davidgranstrom/losc'''
  
Line 14: Line 21:
 
* scheduled bundle evaluation (plugin dependent)
 
* scheduled bundle evaluation (plugin dependent)
  
==== OSC ====
+
=== Gideros LOSC ===
OpenSoundControl: '''https://ccrma.stanford.edu/groups/osc/index.html'''
+
You can download the Gideros LOSC bundle here: '''[[Media:Losc.zip]]''' ('''tip''': right click and Save Link As).
  
From '''''Wikipedia''''', the free encyclopedia
+
To use LOSC in your project, copy the Gideros LOSC bundle in your project '''assets''' folder.
  
'''Open Sound Control (OSC) is a protocol for networking sound synthesizers, computers, and other multimedia devices for purposes such as musical performance or show control. OSC's advantages include interoperability, accuracy, flexibility and enhanced organization and documentation. Its disadvantages include inefficient coding of information, increased load on embedded processors, and lack of standardized messages/interoperability. The first specification was released in March 2002.'''
+
For documentation regarding LOSC you can refer to this link: '''https://davidgranstrom.github.io/losc/index.html'''
  
=== Gideros LOSC ===
+
There is also plenty of comments in each LOSC files, feel free to read them.
The Gideros Unite framework allows a host (server) and clients to connect over a Local Area Network. Some demo code:
 
  
'''Get all connected devices'''
+
==== Example 1 ====
 +
A simple example of a server and a client.
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- we can get all devices that are connected to our network
+
example="client"
local devices = {}
+
--example="server"
serverlink:addEventListener("device", function(e)
+
 
print(e.data.id, e.data.ip, e.data.host)
+
local losc = require"losc"
devices[e.data.id] = {}
+
local plugin = require"losc.plugins.udp-socket"
devices[e.data.id].ip = e.data.ip
+
local Packet = require"losc.packet"
devices[e.data.id].name = e.data.host
 
end)
 
  
serverlink:getDevices()
+
if example=="client" then
 +
-----------------
 +
-- Simple client.
 +
-- Uses the udp-socket plugin.
 +
local udp = plugin.new {sendAddr = "localhost", sendPort = 9000}
 +
local osc = losc.new {plugin = udp}
  
-- add some methods, that could be called by other clients or server through network
+
local message = losc.new_message {
-- draw something
+
address = "/foo/bar",
serverlink:addMethod("draw", self.drawLine, self)
+
types = "ifsb",
-- end drawing
+
123, 1.2345, "hi", "blobdata",
serverlink:addMethod("end", self.stopDrawing, self)
+
}
-- clear drawing
 
serverlink:addMethod("clear", self.reset, self)
 
  
-- then you can call this methods when needed
+
osc:send(message)
serverlink:callMethod("clear")
 
serverlink:callMethod("draw", someX, someY)
 
  
-- or call method of specific device using its id
+
stage:addEventListener(Event.KEY_DOWN, function(e)
serverlink:callMethodOf("clear", 112233)
+
if e.keyCode == KeyCode.M then
serverlink:callMethodOf("draw", someX, someY, 112233)
+
osc:send(message)
 +
end
 +
end)
 +
end
  
-- and when game is finished
 
serverlink:close()
 
</syntaxhighlight>
 
  
'''Server example code'''
+
if example=="server" then
<syntaxhighlight lang="lua">
+
-----------------
function onAccept(e)
+
-- Simple server.
-- auto accept client with provided id
+
-- Uses the udp-socket plugin.
serverlink:accept(e.data.id)
+
local udp = plugin.new {
end
+
recvAddr = "localhost",
 +
recvPort = 9000,
 +
ignore_late = true, -- ignore late bundles
 +
non_blocking = true, -- do not block on :open(), :poll() handles processing
 +
}
 +
local osc = losc.new {plugin = udp}
  
-- create a server instance
+
local function print_data(data)
serverlink = Server.new({username = 'myServer'})
+
local msg = data.message
-- add event to monitor when new client wants to join
+
print("address: " .. msg.address, "timestamp: " .. data.timestamp)
serverlink:addEventListener('newClient', onAccept)
+
for index, argument in ipairs(msg) do
-- start broadcasting to discover devices
+
print("index: " .. index, "arg: " .. argument)
serverlink:startBroadcast()
+
end
 +
end
 +
local function print_message(msg)
 +
local text = TextField.new(nil, msg.address)
 +
stage:addChild(text)
 +
text:setPosition(math.random(400), math.random(400))
 +
print("address: " .. msg.address, "time: "..plugin:now():timestamp(plugin.precision))
 +
for index, argument in ipairs(msg) do
 +
print("index: " .. index, "arg: " .. argument)
 +
end
 +
end
  
-- and then before entering game logic
+
osc:add_handler("/foo/bar", function(data)
-- if we are ready to play stop broadcasting
+
print_data(data)
serverlink:stopBroadcast()
+
end)
-- and start only listening to clients
+
osc:add_handler("/foo/bar2", function(data)
serverlink:startListening()
+
print_data(data)
</syntaxhighlight>
+
end)
  
'''Client example code'''
+
osc:open() -- non blocking call :)
<syntaxhighlight lang="lua">
+
isopened=true
function onJoin(e)
 
-- auto connect to server with provided id
 
serverlink:connect(e.data.id)
 
end
 
  
-- create client instance
+
function onEnterFrame()
serverlink = Client.new({username = 'IAmAClient'})
+
local status, data = osc:poll()
-- create event to monitor when new server starts broadcasting
+
if status and data then
serverlink:addEventListener('newServer', onJoin)
+
local message = Packet.unpack(data)
 +
print_message(message)
 +
end
 +
end
 +
stage:addEventListener(Event.ENTER_FRAME, onEnterFrame)
  
-- event to listen if server accepted our connection
+
stage:addEventListener(Event.KEY_DOWN, function(e)
serverlink:addEventListener('onAccepted', function()
+
if e.keyCode == KeyCode.S then
print('server accepted our connection')
+
if not isopened then
end)
+
print("server opened")
 +
osc:open()
 +
isopened = true
 +
end
 +
elseif e.keyCode == KeyCode.P then
 +
if isopened then
 +
print("server closed")
 +
isopened = false
 +
osc:close()
 +
end
 +
end
 +
end)
 +
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
'''Game logic example''' (the game logic is the same for server and clients)
+
To test the LOSC protocol:
 +
* uncomment ''example="server"''
 +
* and comment ''example="client"''
 +
* compile the server as an executable then launch it
 +
* in Gideros
 +
* uncomment ''example="client"''
 +
* and comment ''example="server"''
 +
* run the client in Gideros Player
 +
* the communication should be established between the server and the client
 +
 
 +
==== Example 2 ====
 +
server.lua
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- we can get all devices that are connected to our network
+
print("----")
local devices = {}
+
print("LOSC GIDEROS DEMO")
serverlink:addEventListener('device', function(e)
+
print("LOSC SERVER")
print(e.data.id, e.data.ip, e.data.host)
+
print("")
devices[e.data.id] = {}
+
 
devices[e.data.id].ip = e.data.ip
+
local losc = require "losc"
devices[e.data.id].name = e.data.host
+
local plugin = require "losc.plugins.udp-socket"
end)
+
local packet = require "losc.packet"
serverlink:getDevices()
 
  
-- add some methods, that could be called by other clients or server through network
+
-- simple server, uses the udp-socket plugin
-- draw something
+
local udp = plugin.new {
serverlink:addMethod('draw', self.drawLine, self)
+
recvAddr="localhost",
-- end drawing
+
recvPort=9000,
serverlink:addMethod('end', self.stopDrawing, self)
+
ignore_late=true, -- true, false, ignore late bundles
-- clear drawing
+
non_blocking=true, -- true, false, do not block on :open(), :poll() handles processing
serverlink:addMethod('clear', self.reset, self)
+
}
 +
local osc = losc.new { plugin=udp }
  
-- then you can call these methods when needed
+
-- a pixel list
serverlink:callMethod('clear')
+
local pixels = {}
serverlink:callMethod('draw', someX, someY)
 
  
-- or call method of specific device using its id
+
-- open server
serverlink:callMethodOf('clear', 112233)
+
osc:open() -- non blocking call :)
serverlink:callMethodOf('draw', someX, someY, 112233)
+
print("server opened")
 +
local isopened = true
  
-- when game is finished
+
-- listeners
serverlink:close()
+
local function process_message(msg)
 +
local pixel = Pixel.new(math.random(0xffff00), 1, 32, 32)
 +
pixel:setAnchorPoint(0.5, 0.5)
 +
pixel:setPosition(msg[1] or 0, msg[2] or 0)
 +
pixels[#pixels+1] = pixel
 +
stage:addChild(pixel)
 +
end
 +
stage:addEventListener(Event.ENTER_FRAME, function(e)
 +
local status, data = osc:poll()
 +
if status and data then
 +
local message = packet.unpack(data)
 +
process_message(message)
 +
end
 +
for i = #pixels, 1, -1 do
 +
local pposx, pposy = pixels[i]:getPosition()
 +
pposy += 2
 +
pixels[i]:setPosition(pposx, pposy)
 +
if pposy > 200 then
 +
stage:removeChild(pixels[i])
 +
pixels[i] = nil
 +
table.remove(pixels, i)
 +
end
 +
end
 +
end)
 +
stage:addEventListener(Event.KEY_DOWN, function(e)
 +
isopened = not isopened
 +
if isopened then
 +
osc:open() -- non blocking call :)
 +
print("server opened")
 +
else
 +
osc:close()
 +
print("server closed")
 +
end
 +
end)
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Using the Gideros Unite Framework ===
+
client.lua
ar2rsawseen 2012/07/25 Gideros Mobile, '''updated 2023/12/13 (V2)'''
+
<syntaxhighlight lang="lua">
 +
print("----")
 +
print("LOSC GIDEROS DEMO")
 +
print("LOSC CLIENT")
 +
print("")
  
<youtube>https://www.youtube.com/watch?v=WBFLSz34I4I</youtube>
+
local losc = require "losc"
 +
local plugin = require "losc.plugins.udp-socket"
  
Gideros Unite framework provides a way to implement Multiplayer games:
+
-- simple client, uses the udp-socket plugin
* using LuaSocket to establish socket connections and create server/client instances
+
local udp = plugin.new { sendAddr="localhost", sendPort=9000, }
* device discovery over Local Area Network
+
local osc = losc.new { plugin=udp, }
* call methods on devices through the network
 
* protocols: '''tcp''', '''udp''' or both. Binding some method to tcp if reliability is needed, and others to udp for faster data processing
 
  
You can download the Gideros Unite Framework here: '''[[Media:Unite.zip|Unite.zip]]'''
+
-- send message
 
+
local message
And a Gideros project: '''[[Media:DrawTogetherV2.zip|DrawTogetherV2.zip]]'''
+
local mousex, mousey = 0, 0
 +
stage:addEventListener(Event.MOUSE_MOVE, function(e)
 +
mousex, mousey = e.x, e.y
 +
message = losc.new_message {
 +
address="/foo/bar2", -- "/foo/bar"
 +
types="ii", -- "ifsb"
 +
mousex, mousey, -- 123, 1.2345, "hi", "blobdata"
 +
}
 +
osc:send(message)
 +
end)
 +
</syntaxhighlight>
  
=== Standard scenario ===
+
This as a Gideros project: '''[[Media:DrawTogetherV2.zip|DrawTogetherV2.zip]]'''
This is a standard scenario that can be created using Gideros Unite framework:
 
# Server starts broadcasting or skip to step 5, if all clients know server IP address
 
# Client's start listening to servers
 
# Client receives broadcast message from server, newServer event is initiated
 
# Client autoconnects to server or user manually (by pushing button) connects to specific server
 
# Server receives newClient event
 
# Server accepts client automatically or user manually (by pushing button) accepts specific client
 
# Client receives onAccept event
 
# Implement your game logic here, where both clients and server can call methods on all devices or on one specific device in the network
 
# When one of the clients becomes unreachable, all clients and server get onClientClose event
 
# When server becomes unreachable, all clients get onServerClose event
 
# When you are finished, close client or server using close method, which stops all timers, closes all connections and destroys instance
 
  
=== Framework ===
 
*1 [[Unite Server Method list]]
 
*2 [[Unite Client Method list]]
 
*3 [[Unite Server Event list]]
 
*4 [[Unite Client Event list]]
 
  
{{Unite Framework}}
+
'''[[Multiplayer]]'''
 +
{{GIDEROS IMPORTANT LINKS}}

Revision as of 20:21, 8 December 2024

OSC

OpenSoundControl: https://ccrma.stanford.edu/groups/osc/index.html

From Wikipedia, the free encyclopedia
Open Sound Control (OSC) is a protocol for networking sound synthesizers, computers, and other multimedia devices for purposes such as musical performance or show control. OSC's advantages include interoperability, accuracy, flexibility and enhanced organization and documentation. Its disadvantages include inefficient coding of information, increased load on embedded processors, and lack of standardized messages/interoperability. The first specification was released in March 2002.

LOSC

OSC 1.0 implementation for lua. Github: https://github.com/davidgranstrom/losc

License:

  • MIT License

Features:

  • implements the complete OSC 1.0 specification
  • pure lua implementation, no platform dependent libraries
  • support for extended OSC types
  • plugin system for transport layers
  • address pattern matching
  • scheduled bundle evaluation (plugin dependent)

Gideros LOSC

You can download the Gideros LOSC bundle here: Media:Losc.zip (tip: right click and Save Link As).

To use LOSC in your project, copy the Gideros LOSC bundle in your project assets folder.

For documentation regarding LOSC you can refer to this link: https://davidgranstrom.github.io/losc/index.html

There is also plenty of comments in each LOSC files, feel free to read them.

Example 1

A simple example of a server and a client.

example="client"
--example="server"

local losc = require"losc"
local plugin = require"losc.plugins.udp-socket"
local Packet = require"losc.packet"

if example=="client" then
	-----------------
	-- Simple client.
	-- Uses the udp-socket plugin.
	local udp = plugin.new {sendAddr = "localhost", sendPort = 9000}
	local osc = losc.new {plugin = udp}

	local message = losc.new_message {
		address = "/foo/bar",
		types = "ifsb",
		123, 1.2345, "hi", "blobdata",
	}

	osc:send(message)

	stage:addEventListener(Event.KEY_DOWN, function(e)
		if e.keyCode == KeyCode.M then
			osc:send(message)
		end
	end)
end


if example=="server" then
	-----------------
	-- Simple server.
	-- Uses the udp-socket plugin.
	local udp = plugin.new {
		recvAddr = "localhost",
		recvPort = 9000,
		ignore_late = true, -- ignore late bundles
		non_blocking = true, -- do not block on :open(), :poll() handles processing
	}
	local osc = losc.new {plugin = udp}

	local function print_data(data)
		local msg = data.message
		print("address: " .. msg.address, "timestamp: " .. data.timestamp)
		for index, argument in ipairs(msg) do
			print("index: " .. index, "arg: " .. argument)
		end
	end
	local function print_message(msg)
		local text = TextField.new(nil, msg.address)
		stage:addChild(text)
		text:setPosition(math.random(400), math.random(400))
		print("address: " .. msg.address, "time: "..plugin:now():timestamp(plugin.precision))
		for index, argument in ipairs(msg) do
			print("index: " .. index, "arg: " .. argument)
		end
	end

	osc:add_handler("/foo/bar", function(data)
		print_data(data)
	end)
	osc:add_handler("/foo/bar2", function(data)
		print_data(data)
	end)

	osc:open() -- non blocking call :)
	isopened=true

	function onEnterFrame()
		local status, data = osc:poll()
		if status and data then
			local message = Packet.unpack(data)
			print_message(message)
		end
	end
	stage:addEventListener(Event.ENTER_FRAME, onEnterFrame)

	stage:addEventListener(Event.KEY_DOWN, function(e)
		if e.keyCode == KeyCode.S then
			if not isopened then
				print("server opened")
				osc:open()
				isopened = true
			end
		elseif e.keyCode == KeyCode.P then
			if isopened then
				print("server closed")
				isopened = false
				osc:close()
			end
		end
	end)
end

To test the LOSC protocol:

  • uncomment example="server"
  • and comment example="client"
  • compile the server as an executable then launch it
  • in Gideros
  • uncomment example="client"
  • and comment example="server"
  • run the client in Gideros Player
  • the communication should be established between the server and the client

Example 2

server.lua

print("----")
print("LOSC GIDEROS DEMO")
print("LOSC SERVER")
print("")

local losc = require "losc"
local plugin = require "losc.plugins.udp-socket"
local packet = require "losc.packet"

-- simple server, uses the udp-socket plugin
local udp = plugin.new {
	recvAddr="localhost",
	recvPort=9000,
	ignore_late=true, -- true, false, ignore late bundles
	non_blocking=true, -- true, false, do not block on :open(), :poll() handles processing
}
local osc = losc.new { plugin=udp }

-- a pixel list
local pixels = {}

-- open server
osc:open() -- non blocking call :)
print("server opened")
local isopened = true

-- listeners
local function process_message(msg)
	local pixel = Pixel.new(math.random(0xffff00), 1, 32, 32)
	pixel:setAnchorPoint(0.5, 0.5)
	pixel:setPosition(msg[1] or 0, msg[2] or 0)
	pixels[#pixels+1] = pixel
	stage:addChild(pixel)
end
stage:addEventListener(Event.ENTER_FRAME, function(e)
	local status, data = osc:poll()
	if status and data then
		local message = packet.unpack(data)
		process_message(message)
	end
	for i = #pixels, 1, -1 do
		local pposx, pposy = pixels[i]:getPosition()
		pposy += 2
		pixels[i]:setPosition(pposx, pposy)
		if pposy > 200 then
			stage:removeChild(pixels[i])
			pixels[i] = nil
			table.remove(pixels, i)
		end
	end
end)
stage:addEventListener(Event.KEY_DOWN, function(e)
	isopened = not isopened
	if isopened then
		osc:open() -- non blocking call :)
		print("server opened")
	else
		osc:close()
		print("server closed")
	end
end)

client.lua

print("----")
print("LOSC GIDEROS DEMO")
print("LOSC CLIENT")
print("")

local losc = require "losc"
local plugin = require "losc.plugins.udp-socket"

-- simple client, uses the udp-socket plugin
local udp = plugin.new { sendAddr="localhost", sendPort=9000, }
local osc = losc.new { plugin=udp, }

-- send message
local message
local mousex, mousey = 0, 0
stage:addEventListener(Event.MOUSE_MOVE, function(e)
	mousex, mousey = e.x, e.y
	message = losc.new_message {
		address="/foo/bar2", -- "/foo/bar"
		types="ii", -- "ifsb"
		mousex, mousey, -- 123, 1.2345, "hi", "blobdata"
	}
	osc:send(message)
end)

This as a Gideros project: DrawTogetherV2.zip


Multiplayer