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

Cap*_*rog 6 matlab udp osc max-msp-jitter puredata

我正在尝试接收通过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);
Run Code Online (Sandbox Code Playgroud)

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

现在为了事情的另一端.这是我的Pure Data补丁:

纯数据补丁图像

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

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

在任何情况下,无论我尝试什么,我都无法将纯数据发送到MATLAB,尽管能够将其发送给自己.我怀疑它与"主机"地址有关.

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

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

注意我也知道我/foo用于来自MATLAB和/testPure Data的消息.但是,我的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

Amr*_*mro 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
Run Code Online (Sandbox Code Playgroud)

client_MATLAB

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

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

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

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

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

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
Run Code Online (Sandbox Code Playgroud)

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 及其依赖项.这包括:liblo 源代码,pthreads-win32 二进制文件,premake4可执行文件.

1)我们从构建liblo库开始:

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

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

#define ENABLE_IPV6 1
Run Code Online (Sandbox Code Playgroud)

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

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

    mex -largeArrayDims -I../path/to/liblo-0.27 xxxxxx.c pthreadVC2.lib liblo.lib -lwsock32 -lws2_32 -liphlpapi
    
    Run Code Online (Sandbox Code Playgroud)
  • *.mexw32每个xxxxxx.c源文件最终应该有六个文件

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

为了省去一些麻烦,这里是使用VS2010 在WinXP 32位和Win8 64位上构建的已编译MEX文件.下面是源代码,如果你想自己编译(简单地构建VS2010解决方案,然后运行osc_make.m在MATLAB)


uml*_*ute 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);