Связь между Pure Data и MATLAB с использованием OSC

Я пытаюсь получить сообщение, отправленное через OSC из Pure Data (или Max/MSP) в MATLAB.

  • Я могу отправлять сообщения OSC из Pure Data в Pure Data
  • Я могу отправлять сообщения из 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:

Изображение исправления Pure Data

Опять же, запуск только вышеупомянутого патча успешно отправляет и получает сообщения через Pure Data.

Проблема заключается в том, что я пытаюсь говорить из одной программы в другую. Если я настрою так, чтобы MATLAB отправлял через порт 3333, а Pure Data - на 3333, а Pure Data - на 2222, а MATLAB - на 2222, я могу заставить Pure Data получать, если хост MATLAB имеет номер 127.0.0.1., Но с 127.0.0.1 MATLAB не может отправлять самому себе.

В любом случае, независимо от того, что я пытаюсь, я не могу заставить Pure Data отправлять в MATLAB, несмотря на то, что я могу заставить его отправлять самому себе. Я подозреваю, что это как-то связано с адресом хоста.

Мой фактический IPv4-адрес (найденный с помощью "ipconfig" из командной строки MS) полностью отличается от 127.0.0.1, и использование указанного здесь значения, похоже, не делает вещи лучше.

Я знаю, что у меня не может быть одновременно открыто более одного сервера OSC с одним и тем же портом, и поэтому моя текущая попытка найти решение включает в себя отправку из MATLAB на один порт и отправку из Pure Data на другой, только один сервер, открытый одновременно на любом порту.

Обратите внимание, я также знаю, что я использую /foo для сообщений от MATLAB и /test из чистых данных. Однако мой код MATLAB без разбора получает все, что отправлено через OSC, так что это не имеет значения.

Буду признателен за любую помощь в получении ПД, чтобы поговорить с MATLAB.

Обновление: я решил проблему с 'localhost', и это, похоже, не решает проблемы (мне пришлось добавить localhost в мой файл hosts для Windows). Таким образом, я, возможно, лаю не на том дереве, беспокоясь о местных вещах. Но я все еще не могу заставить PD поговорить с MATLAB.

Обновление № 2: Amro опубликовал элегантное решение ниже, и я до сих пор не могу получить MATLAB для получения сообщений из Pure Data. Я установил CloseTheDoor для мониторинга моих UDP-соединений и заметил, что когда MATLAB устанавливает сервер, он использует "Интерфейс" [::0]тогда как наборы ПД используют "Интерфейс" 0.0.0.0, Так как PureData - это тот, который успешно принимает сообщения, возможно, мне нужно заставить MATLAB прослушивать 0.0.0.0 также?

2 ответа

Позвольте мне начать с того, что я никогда раньше не использовал PureData или OSC, и я просто продублировал график / патч, который вы показали, для создания сервера / клиента.

1) сервер в PureData, клиент в MATLAB:

Сначала давайте создадим сервер в PureData:

server_PD: pastebin.com/hwJzxri2

Теперь вот простой клиент, реализованный как графический интерфейс в 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

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:

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,

НТН


РЕДАКТИРОВАТЬ:

Мне удалось скомпилировать пакет OSC-MEX самостоятельно, вот шаги. Сначала загрузите источники osc-mex и их зависимости. Это включает в себя: исходные коды liblo, двоичные файлы pthreads-win32, исполняемый файл premake4.

1) Начнем с создания библиотеки liblo:

  • Скопируйте файл "premake4.exe" в каталог "build" и запустите: premake4 --platform=x32 vs2010
  • откройте созданный файл решения "liblo.sln" в VS2010. Выберите проект "liblo" и перейдите в "Проект> Свойства". Добавить include папка, содержащая заголовочные файлы pthreads в поле "Дополнительные каталоги включения". Аналогичным образом добавьте lib папку для компоновщика и укажите pthreadVC2.lib как дополнительная зависимость.
  • Выберите цель Win32 "ReleaseLib" и соберите проект. Это должно создать конечную цель: lib\ReleaseLib\liblo.lib

Обратите внимание, что по умолчанию поддержка IPv6 отключена в liblo, поскольку такие приложения OSC, как Pd, имеют проблемы с IPv6. Если вы все еще хотите включить его, добавьте следующую строку в config.h файл:

#define ENABLE_IPV6 1

2) Далее мы скомпилируем MEX-функции в MATLAB:

  • Перейдите в папку, содержащую C-источники MEX-функций
  • копия 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 в эту же папку: pthreadVC2.dll

Чтобы избавить вас от хлопот, вот скомпилированные MEX-файлы, построенные на 32-битных WinXP и 64-битных Win8, использующих VS2010. Вот источники, если вы хотите скомпилировать их самостоятельно (просто соберите решение в VS2010, затем запустите osc_make.m в MATLAB)

localhost это псевдоним для 127.0.0.1; это действительно один и тот же IP-адрес. так что, если Matlab получает что-то, только если он отправляет localhost но не при отправке 127.0.0.1, они, вероятно, имеют ошибочную реализацию OSC.

пока у вас есть [udpreceive 2222] в вашем патче Pd заблокирует порт UDP/2222, и Matlab не сможет ничего получить на этот порт.

так что простое решение: удалить [udpreceive 2222] перед созданием сервера Matlab с помощью osc_new_server(2222);

Другие вопросы по тегам