使用OSC在纯数据和MATLAB之间进行通信

时间:2013-06-13 00:04:17

标签: matlab udp osc puredata max-msp-jitter

我正在尝试接收通过OSC从Pure Data(或Max / MSP)发送到MATLAB的消息。

  • 我能够将纯数据的OSC消息发送到纯数据
  • 我可以从MATLAB发送消息到MATLAB
  • 我甚至可以将消息从MATLAB发送到Pure Data
  • ......我真的很难让纯数据与MATLAB交谈

这是我从MATLAB发送消息的代码(我使用的是oscmex协议):

host = 'localhost'; % local host UDP address
sendPort = 3333; % UDP port number to send over
receivePort = 3333; % UDP port number to receive from
oscAddress = osc_new_address(host, sendPort); % open send address
oscServer = osc_new_server(receivePort); % open server

dataPacket = struct('path','/foo','tt','f','data',{num2cell([1.0])}); % create packet
osc_send(oscAddress, dataPacket); % write packet to OSC

oscMessage = osc_recv(oscServer, 0.1); % listen for packet on OSC

% check to see if anything is there...
if length(oscMessage) > 0
    fprintf('Found something!')
else
    fprintf('Failed to find anything')
end

osc_free_address(oscAddress);
osc_free_server(oscServer);

如果我使用主机'localhost'发送,一切正常,使用上面的代码将 MATLAB 发送到 MATLAB。如果我将其设置为'127.0.0.1',MATLAB将发送到Pure Data,但MATLAB无法接收自己的消息。

现在为了事情的另一端。这是我的纯数据补丁:

Pure Data patch image

同样,单独运行上述补丁会成功通过Pure Data发送和接收消息。

当我尝试从一个程序谈到另一个程序时,问题就在于此。如果我设置的东西使得MATLAB在端口3333上发送并且Pure Data在3333上接收,并且Pure Data在2222上发送并且MATLAB在2222上接收,那么如果MATLAB的话,我可以使Pure Data 接收主机是'127.0.0.1'。但是,使用'127.0.0.1',MATLAB无法发送给自己。

无论如何,无论我尝试什么,我都无法将纯数据发送发送到MATLAB,尽管能够将其发送给自己。我怀疑它与“主机”地址有关。

我的实际IPv4地址(使用MS命令提示符的'ipconfig'找到)与127.0.0.1完全不同,并且使用此处指定的值似乎不会使事情更好。

我知道我不能在任何时候打开同一个端口的多个OSC服务器,因此我目前尝试解决方案涉及从一个端口上的MATLAB发送,另一个端口上从Pure Data发送,在任一端口上一次只打开一台服务器。

注意我也知道我使用/foo来自MATLAB的消息和来自Pure Data的/test。但是,我的MATLAB代码不加选择地接收通过OSC发送的所有内容,因此没有区别。

任何帮助PD与MATLAB交流的帮助都将不胜感激。

更新:我解决了'localhost'问题,似乎没有解决问题(我必须将localhost添加到我的Windows'主机'文件中)。所以,我可能因为担心本地主机事而咆哮错误的树。但是,我仍然无法让PD与MATLAB交谈。

更新#2 :Amro在下面发布了一个优雅的解决方案,而仍然无法让MATLAB接收来自Pure Data的消息。我已安装CloseTheDoor来监控我的UDP连接,并注意到当MATLAB设置服务器时,它使用'Interface'[::0],而PD集使用'Interface'0.0.0.0。由于PureData是成功接收消息的那个,也许我需要让MATLAB监听0.0.0.0

2 个答案:

答案 0 :(得分:5)

首先我要说我之前从未使用过PureData或OSC,而我只是复制了您创建的用于创建服务器/客户端的图形/补丁。

1)PureData中的服务器,MATLAB中的客户端:

首先让我们在PureData中创建服务器:

server_PD: pastebin.com/hwJzxri2

现在这里是一个在MATLAB中作为GUI实现的简单客户端:

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

client_MATLAB

移动滑块时,消息将发送到服务器(使用OSC-MEX界面),值将显示在PureData模型中。

在测试时,我注意到不支持double类型,因为我在PD日志窗口中看到以下消息:

  

unpackOSC:PrintTypeTaggedArgs:[64位浮点数]未实现

因此有必要手动将值转换为single或在传递给osc_send OSC-MEX函数的结构中明确指定提示类型:

val = single(1);
m = struct('path','/test', 'tt','f', 'data',{{val}});
osc_send(osc, m);

2)MATLAB中的服务器,PureData中的客户端:

类似地,我们在PureData中创建客户端:

client_PD: pastebin.com/P1KcM00m

同样,这里是作为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

server_MATLAB

服务器部分在MATLAB中有点棘手。我们的想法是,我们不希望MATLAB无限期地阻止等待消息。所以我创建了一个每0.11秒执行一次的计时器。在计时器功能内部,我们尝试以阻塞方式接收消息,但超时为0.1秒。这样,GUI和MATLAB IDE都能保持响应。


3)其他组合:

使用上述解决方案,您还可以在PureData中打开客户端和服务器,或者在MATLAB中打开客户端和服务器。它应该以任何方式工作。

最后,我应该说,无论我使用主机名localhost还是直接指定IP地址127.0.0.1,都没有区别。

HTH


编辑:

我自己编译了OSC-MEX包,以下是步骤。首先下载osc-mex sources及其依赖项。其中包括:liblo sourcespthreads-win32 binariespremake4可执行文件。

1)我们首先构建liblo库:

  • 将“premake4.exe”复制到“build”目录中,然后运行:premake4 --platform=x32 vs2010
  • 在VS2010中打开生成的“liblo.sln”解决方案文件。选择“liblo”项目并转到“Project> Properties”。在“其他包含目录”字段中添加包含pthreads头文件的include文件夹。同样,为链接器添加lib文件夹,并将pthreadVC2.lib指定为附加依赖项。
  • 选择“ReleaseLib”Win32目标并构建项目。这应该创建最终目标:lib\ReleaseLib\liblo.lib

请注意,by default,在liblo中禁用了IPv6支持,因为像Pd这样的OSC应用程序存在IPv6问题。如果您仍想启用它,请将以下行添加到config.h文件:

#define ENABLE_IPV6 1

2)接下来我们在MATLAB中编译MEX函数:

  • 转到包含MEX功能的C源的文件夹
  • 将上一步中的liblo.lib复制到此目录中。同时从pthreads库中复制pthreadVC2.lib
  • 使用以下方法编译每个函数:

    mex -largeArrayDims -I../path/to/liblo-0.27 xxxxxx.c pthreadVC2.lib liblo.lib -lwsock32 -lws2_32 -liphlpapi
    
  • 对于每个*.mexw32源文件,您最终应该有六个xxxxxx.c个文件

  • 最后将pthreads DLL复制到同一个文件夹中:pthreadVC2.dll

为了省去一些麻烦,以下是使用VS2010构建在WinXP 32-bit和Win8 64-bit上的已编译MEX文件。如果您想自己编译(只需在VS2010中构建解决方案,然后在MATLAB中运行osc_make.m),这里有the sources

答案 1 :(得分:0)

localhost127.0.0.1的别名;它们确实是相同的IP地址。所以如果matlab只收到一些东西,如果它发送到localhost而不是发送给127.0.0.1,那么他们可能会有一个错误的OSC实现。

只要您的补丁中有[udpreceive 2222],Pd就会阻止端口UDP / 2222,并且matlab将无法在该端口上接收任何内容。

所以简单的解决方案是:在使用[udpreceive 2222]创建matlab服务器之前删除osc_new_server(2222);