Let me start by saying that I've never used PureData or OSC before, and I just duplicated the graph/patch you've shown to create the server/client.
1) server in PureData, client in MATLAB:
First lets create the server in PureData:
Now here is a simple client implemented as a GUI in MATLAB:
function example_osc_client()
handles = createGUI();
osc = [];
function h = createGUI()
h.fig = figure('Menubar','none', 'Resize','off', ...
'CloseRequestFcn',@onClose, ...
'Name','OSC Client', 'Position',[100 100 220 140]);
movegui(h.fig, 'center')
h.conn = uicontrol('Style','pushbutton', 'String','Connect', ...
'Callback',{@onClick,'connect'}, ...
'Parent',h.fig, 'Position',[20 20 80 20]);
h.disconn = uicontrol('Style','pushbutton', 'String','Disconnect', ...
'Callback',{@onClick,'disconnect'}, ...
'Parent',h.fig, 'Position',[120 20 80 20]);
h.slid = uicontrol('Style','slider', 'Callback',@onSlide, ...
'Min',-10, 'Max',10, 'Value',0, ...
'Parent',h.fig, 'Position',[30 60 160 20]);
h.txt = uicontrol('Style','text', 'String','0.0', ...
'Parent',h.fig, 'Position',[80 100 60 20]);
set([h.slid;h.disconn], 'Enable','off');
drawnow
end
function onClick(~,~,action)
switch lower(action)
case 'connect'
osc = osc_new_address('127.0.0.1', 2222);
set(handles.conn, 'Enable','off')
set(handles.disconn, 'Enable','on')
set(handles.slid, 'Enable','on')
case 'disconnect'
osc_free_address(osc); osc = [];
set(handles.conn, 'Enable','on')
set(handles.disconn, 'Enable','off')
set(handles.slid, 'Enable','off')
end
drawnow
end
function onSlide(~,~)
if isempty(osc), return; end
val = single(get(handles.slid,'Value'));
m = struct('path','/test', 'tt','f', 'data',{{val}});
osc_send(osc, m);
set(handles.txt, 'String',num2str(val))
drawnow
end
function onClose(~,~)
if ~isempty(osc)
osc_free_address(osc);
end
delete(handles.fig);
end
end
As you move the slider, messages are sent to the server (using OSC-MEX interface), and the values are displayed in the PureData model.
While testing this, I noticed that double
type was not supported, as I saw the following message in the PD log window:
unpackOSC: PrintTypeTaggedArgs: [A 64-bit float] not implemented
So it was necessary to either manually cast values as single
or explicitly specify the hint type in the structure passed to osc_send
OSC-MEX function:
val = single(1);
m = struct('path','/test', 'tt','f', 'data',{{val}});
osc_send(osc, m);
2) server in MATLAB, client in PureData:
Similarly we create the client in PureData:
Again, here is the server implemented as a MATLAB GUI:
function example_osc_server()
handles = createGUI();
osc = [];
function h = createGUI()
h.fig = figure('Menubar','none', 'Resize','off', ...
'CloseRequestFcn',@onClose, ...
'Name','OSC Server', 'Position',[100 100 220 140]);
movegui(h.fig, 'center')
h.start = uicontrol('Style','pushbutton', 'String','Start', ...
'Callback',{@onClick,'start'}, ...
'Parent',h.fig, 'Position',[20 20 80 20]);
h.stop = uicontrol('Style','pushbutton', 'String','Stop', ...
'Callback',{@onClick,'stop'}, ...
'Parent',h.fig, 'Position',[120 20 80 20]);
h.txt = uicontrol('Style','text', 'String','', ...
'Parent',h.fig, 'Position',[60 80 100 20]);
set(h.stop, 'Enable','off');
drawnow expose
h.timer = timer('TimerFcn',@receive, 'BusyMode','drop', ...
'ExecutionMode','fixedRate', 'Period',0.11);
end
function onClick(~,~,action)
switch lower(action)
case 'start'
set(handles.start, 'Enable','off')
set(handles.stop, 'Enable','on')
osc = osc_new_server(2222);
start(handles.timer);
case 'stop'
set(handles.start, 'Enable','on')
set(handles.stop, 'Enable','off')
osc_free_server(osc); osc = [];
stop(handles.timer);
end
drawnow expose
end
function receive(~,~)
if isempty(osc), return; end
m = osc_recv(osc, 0.1);
if isempty(m), return; end
set(handles.txt, 'String',num2str(m{1}.data{1}))
drawnow expose
end
function onClose(~,~)
if ~isempty(osc)
osc_free_server(osc);
end
stop(handles.timer); delete(handles.timer);
delete(handles.fig);
clear handles osc
end
end
The server part was a bit trickier in MATLAB. The idea is that we don't want MATLAB to block indefinitely waiting for messages. So I created a timer which executes every 0.11 second. Inside the timer function we try to receive message in a blocking manner but with a timeout of 0.1 sec. This way both the GUI and MATLAB IDE stay responsive.
3) other combinations:
Using the above solutions, you could also open both client and server in PureData, or both client and server in MATLAB. It should work either way.
Finally I should say that it made no difference whether I'm using the hostname as localhost
or specified the IP address directly 127.0.0.1
.
HTH
EDIT:
I managed to compile the OSC-MEX package myself, here are the steps. First download osc-mex sources and its dependencies. This includes: liblo sources, pthreads-win32 binaries, premake4 executable.
1) We start by building the liblo library:
- Copy "premake4.exe" into the "build" directory, and run:
premake4 --platform=x32 vs2010
- open the generated "liblo.sln" solution file in VS2010. Select the "liblo" project and go to "Project > Properties". Add the
include
folder containing pthreads header files in the "Additional Include Directories" field. Similarly add the lib
folder for the linker, and specify pthreadVC2.lib
as additional dependency.
- Select the "ReleaseLib" Win32 target and build the project. This should create the final target:
lib\ReleaseLib\liblo.lib
Note that by default, IPv6 support is disabled in liblo because OSC applications like Pd have problems with IPv6. If you still want to enable it, add the following line to config.h
file:
#define ENABLE_IPV6 1
2) Next we compile the MEX-functions in MATLAB:
- Go to the folder containing the C-sources of the MEX-functions
- copy
liblo.lib
from the previous step into this directory. Also copy pthreadVC2.lib
from the pthreads library.
compile each function using:
mex -largeArrayDims -I../path/to/liblo-0.27 xxxxxx.c pthreadVC2.lib liblo.lib -lwsock32 -lws2_32 -liphlpapi
You should end up with six *.mexw32
files for each of the xxxxxx.c
source files
- Finally copy the pthreads DLL into this same folder:
pthreadVC2.dll
To save you some troubles, here are the compiled MEX-files built on WinXP 32-bit and Win8 64-bit both using VS2010. Here are the sources if you would like to compile it yourself (simply build the solution in VS2010, then run osc_make.m
in MATLAB)
Best Answer
Could you create an ActiveX EXE in VB6 to simply forward messages between the different parties? When anyone called it, it would raise an event with the parameters passed to the call. Your VB6 and VB.NET code could establish a reference to the ActiveX exe to call it and sink its events. I'm not familiar with Matlab so I don't know whether it would be accessible there.
EDIT: you've written that Matlab 2009a can access .NET directly. If it can sink .NET events, you could also have a .NET wrapper on the VB6 ActiveX EXE.
Here's some sample code I knocked up quickly.
VB6 ActiveX EXE project with project name VB6MatlabMessenger. Each message has a text string Destination (that somehow identifies the intended recipient) and a string with the message.
And a test VB6 normal exe, with a reference to the VB6MatlabMessenger. Here is the whole frm file. Build this as an exe, run a few copies. Fill in the destination and message text fields and click the button - you will see that the messages are received in all the exes (reported in the listboxes).
I started writing a VB.NET class library that wraps the VB6 to make it accessible to .NET. I haven't tested this one. It has a reference to the VB6MatLabMessenger.
This might get you started. Note that the VB6 messenger objects will live forever because the messenger keeps a reference to them internally, so COM will never tidy them up. If this becomes a problem (if many messages are sent without rebooting the PC) you could add a method to the VB6 messenger which instructs it to removed the messenger object from its collection,