如何用代码控制midi数据格式的速度_用H5和小程序发送OSC

OSC 是各软件和设备之间互传数据时常用的协议,多款 PC 软件和手机 App 都支持,一般基于 UDP 进行传输。

但有时会遇到不支持 UDP 的情况,大多是因为网络安全原因而禁止,比如用基于浏览器的 p5.js 或 H5 向 Processing/MaxMSP/Unity 传输数据,还比如我正在开发中的微信小程序 BugOSC(类似 TouchOSC 的控制器),就都无法使用 UDP 来传送 OSC 数据。

所幸这些基于 Web 的平台还支持另一种网络传输协议:WebSocket

我写了一些例子,用来演示如何通过 WebSocket 来传输 OSC 数据。

acd563b35ae311fed92a76e3180d5137.gif

有两个关键点:

  • WebSocket 传输

  • 数据按 OSC 打包与解析

用 WebSocket 可以传输自定义格式数据,之所以要按 OSC 标准格式打包,就是为了兼容各软件既有的功能。

WebSocket 客户端作为发送端,开发语言使用 p5.js;


WebSocket 服务端作为接收端,分别用 Processing、MaxMSP、Unity 来演示(Pure Data、VVVV 等附上资料,陆续补充)。

传输的数据遵循标准 OSC 格式打包成二进制形式。

http://opensoundcontrol.org/introduction-osc

OSC 发送端 - p5.js WebSocket client

p5.js 是基于浏览器的 JavaScript 库,用它来写一个简单的发送程序(其实收发皆可),作为WebSocket 客户端。

这里用到业界良心 osc.js 库,它支持 UDP (NodeJS, 无浏览器), WebSocket, TCP and Serial port(串口),也能单独对数据进行 OSC 打包和解析。

//p5.js sketch:

function setup() {
    createCanvas(400, 400);
    oscWebSocket = new osc.WebSocketPort({
        url: "ws://localhost:12345",
        metadata: true
    });

    oscWebSocket.on("ready", onSocketOpen);
    oscWebSocket.on("message", onSocketMessage);
}

function onSendClick() {    
    const msg = input.value();
    input.value('');
    // send the OSC message to server. 
    //(osc.js will convert it to binary packet)
    oscWebSocket.send({
        address: "/p5js/sayhi",
        args: [{
            type: "s",
            value: msg
        }]
    });
}

OSC 接收端 - Processing

5b7c41986d2ffc132d3ff886c45b9151.gif

WebSocket of Processing:

Processing 社区有一个不错的 WebSocket lib:processing WebSocket library。


可惜它只支持传输 String 字符串数据,不支持二进制类型。
大部分时候字符串够用,但如果传输大量数据,二进制更高效一些。

幸运的是有一个 fork 增加了二进制支持,但是年久失修有 Bug,以及仅有 Java 源代码,没有 Processing JAR 包。

基于此 fork 我增加了一版 Bug 修复版,并编译了 JAR 包(用 Processing 3),可直接下载使用。

github.com/avantcontra/processing_websockets

OSC 数据解析:

使用 oscP5 。

oscP5 的解析函数是 protected,无法直接使用。
这里不再 hack 它,而是直接起一个本地 localhost 的 oscP5 UDP,把 WebSocket 收到的二进制数据包再次转发给自己,oscP5 接收到后会内部将其解包,得到正确的数据。

// Processing sketch:

void setup(){
    //WebSocket
    ws = new WebsocketServer(this, 12345, "/");
    //use OSC (UDP) to parse the data
    oscP5 = new OscP5(this,12346);
    oscHost = new NetAddress("127.0.0.1", 12346);
}

// The data receiving handler, support byte[]
void webSocketServerEvent(byte[] buf, int offset, int length){
    //send to OSC (UDP) to parse the data   
    OscP5.flush(buf, oscHost);
}

OSC 接收端 - MaxMSP

acd563b35ae311fed92a76e3180d5137.gif

现在已有几款 Max 与浏览器通信的lib:

  • xebra.js from MiraWeb

  • wsserver

2018年新出的 Max8,增加了 Node for Max 功能,可以用 NodeJS 给 Max 写扩展,这里选用此方案。


所以这个例子中的 WebSocket 与 OSC 相关功能,实际上是用 NodeJS 实现的。

仍然用前文 p5.js 部分用到的 osc.js 即可,OSC 数据格式处理及 WebSocket 传输都用此库。

webSocketPort = new osc.WebSocketPort({
    socket: ws
});

// receive message
ws.on("message", function incoming(message) {
    const msgParsed = osc.readPacket(message, { metadata: true });
    console.log("received parsed : ", msgParsed);
    
    maxAPI.outlet('message', msgParsed);
});

// send message
maxAPI.addHandler("send", (...args) => {
    if (webSocketPort && isConnected) {
        webSocketPort.send({
                address: "/max/midi",
                args: [{
                        type: "i",
                        value: args[0]
                }]
            });
    }
});

OSC 接收端 - Unity

fe6a424e9b0bb1034f190cf2900703ff.gif

Unity WebSocket:

websocket-sharp 是 WebSocket 的 C# 实现。

我编译了 websocket-sharp.dll,添加到 Unity 工程目录 Assets/ 下即可。 
如果这个 dll 你无法使用,可以在自己环境下自行编译。

OSC 数据解析:

市面上有几款 Unity OSC 库,但大部分跟 oscP5 一样,把 OSC 数据打包解析和 UDP 传输合在一起,在这个案例下反而不方便使用。

这时目光转向了 VVVV ... 
同是 C# 生,而 VVVV 当然也支持 OSC。

VVVVUnityOSC 这一款想什么来什么的库,就是把 VVVV SDK 中对 OSC 的支持,移植到 Unity 上,并且使用非常方便:

打包new OSCMessage("/unity/midi", 87).BinaryData解析OSCPacket.Unpack(oscPacketRawData)

public class WebSocketOSC : MonoBehaviour
{
    public WebSocketServer wssv;
    void Start()
    {
        wssv = new WebSocketServer("ws://127.0.0.1:12345");
        wssv.AddWebSocketService("/");
        wssv.Start();
    }
}

public class Echo : WebSocketBehavior
{
    //receive message
    protected override void OnMessage(MessageEventArgs e)
    {
        if (e.IsBinary)
        {
            OSCPacket msg = OSCPacket.Unpack(e.RawData);
            Debug.Log(string.Format("recv OSC addr: {0}, value: {1}", msg.Address, msg.Values[0]));
        }
    }

    protected override void OnOpen()
    {
        //send message
        Send(new OSCMessage("/unity/midi", 87).BinaryData);
    }
}

其他 OSC 接收端

另几款常见的互动开发软件,先补充一些资料在这里,欢迎PR!!?

Pure Data:

Websocket-Server-in-a-Patch

"websocket-server in a patch.pd" single Pd file contains a reusable and fully documented websocket server, meant as an easy way to experiment with Pure Data web-browsers communications through websockets, without the need of other software (like node.js or python) or any specific external to compile (just one deken library is required).

pd-ws

Communicate between Pure Data & web browser over a websocket.

VVVV:
  • C# websocket-sharp

  • VVVV Websocket (Network Server)

  • VVVV Venode 这个更像是用 NodeJS 写了一个 Bridge,桥接中转方案。

Bridge 桥接中转方案

当然还可以用桥接的方案:

p5js BRIDGE receivers

用 NodeJS/Python/Whatever 等写一个中转,一方面接收浏览器发来的 WebSocket 数据,另一方面把数据用基于 UDP 的标准 OSC 库发出去,而其他接收端,不用做任何更改,直接用既有的 UDP OSC 接收即可。

这个方案开发简单,但使用时需要多启动一个第三方的 Bridge 程序,各有利弊。

而上文中的 Processing 方案,其实也可以看作是一个中转,只是把收到的数据自己转给了自己,内部消化。

更多

所有例子的源代码都在这里(点击阅读原文):
github.com/avantcontra/osc-websocket-example
Welcome PR!?

Cheers~

文章封面用 Max 生成。

Contra

  • website: floatbug.com/contra

  • 微信公众号/知乎专栏:浮生开方

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值