7

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

  • 我能够将 OSC 消息从 Pure Data 发送到 Pure Data
  • 我可以将消息从 MATLAB 发送到 MATLAB
  • 我什至可以将消息从 MATLAB 发送到 Pure Data
  • ...我真的很难让 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 发送和接收消息。

当我尝试从一个程序与另一个程序交谈时,问题就出在了这里。如果我设置了 MATLAB 在端口 3333 上发送,Pure Data 在 3333 上接收,Pure Data 在 2222 上发送,MATLAB 在 2222 上接收,如果 MATLAB 的主机是“127.0.0.1” ,我可以让 Pure Data接收. 但是,使用“127.0.0.1”,MATLAB 无法发送给自己。

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

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

我知道我不能在任何时候打开多个具有相同端口的 OSC 服务器,因此我目前对解决方案的尝试涉及从一个端口上的 MATLAB 发送,并在另一个端口上从纯数据发送,只有单个服务器同时在任一端口上打开。

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

让 PD 与 MATLAB 交谈的任何帮助将不胜感激。

更新:我已经解决了“localhost”问题,但这似乎并没有解决问题(我必须将 localhost 添加到我的 Windows 'hosts' 文件中)。所以,我可能一直在担心 localhost 的事情而找错了树。但是,我仍然无法让 PD 与 MATLAB 对话。

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

4

2 回答 2

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

客户端_MATLAB

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

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

unpackOSC: PrintTypeTaggedArgs: [A 64-bit float] 未实现

因此,有必要手动将值转换为single或明确指定传递给osc_sendOSC-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

服务器_MATLAB

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


3) 其他组合:

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

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

高温高压


编辑:

我设法自己编译了 OSC-MEX 包,步骤如下。首先下载osc-mex 及其依赖项。这包括:liblo pthreads-win32 二进制文件premake4可执行文件。

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

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

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

#define ENABLE_IPV6 1

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
    
  • *.mexw32对于每个xxxxxx.c源文件,您应该最终得到六个文件

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

为了给您省点麻烦,这里是编译的 MEX 文件,在 WinXP 32 位和 Win8 64 位都使用 VS2010 构建。如果您想自己编译,这里是源代码osc_make.m(只需在 VS2010 中构建解决方案,然后在 MATLAB 中运行)

于 2013-06-16T17:56:13.957 回答
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);

于 2013-06-13T09:57:21.807 回答