Связь между 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.
Проблема заключается в том, что я пытаюсь говорить из одной программы в другую. Если я настрою так, чтобы 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:
Теперь вот простой клиент, реализованный как графический интерфейс в 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
При перемещении ползунка сообщения отправляются на сервер (с использованием интерфейса 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:
Опять же, вот сервер, реализованный как графический интерфейс 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
Серверная часть была немного сложнее в 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);