【TidalCycles】TidalCyclesのOSCログをopenFrameworksで確認する

# はじめに

TidalCyclesで曲を作ったあと、ProcessingやTouchDesigner、openFrameworksで音に同期させた映像をつくりたいことがあると思います。
今回はopenFrameworksを例としてTidalCyclesから送信されるOSCのログをopenFrameworksで取得・表示する方法を紹介します。

# SuperColliderでの設定

まずSuperDirtを起動(`SuperDirt.start;`)後、以下のコマンドをSuperColliderで実行します。

これによってTidalCyclesの全てのログはlocalhostのポート2020に送信されるようになります。

```supercollider:def.scd
// localhostの2020portにTidalCyclesのログ送る
(
var addr = NetAddr.new("127.0.0.1", 2020);
o = OSCFunc({
arg msg, time;
var latency = time - Main.elapsedTime;
addr.sendBundle(latency, msg)
},'dirt/play');
o.free; // ←これは不要かもしれません
o.fix;
)
```

# openFrameworksのコード

コードは[Github](https://github.com/mynkit/receiveTidalOSC)にもおいてありますが、必要な機能のみに抑えたものを以下に記載しておきます。

今回はaddOnにofxOscを用います。

```cpp:main:cpp
#include "ofMain.h"
#include "ofApp.h"

//========================================================================
int main( ){
	ofSetupOpenGL(1500,600,OF_WINDOW);			// <-------- setup the GL context

	// this kicks off the running of my app
	// can be OF_WINDOW or OF_FULLSCREEN
	// pass in width and height too:
	ofRunApp(new ofApp());

}

```

```cpp:ofApp.h
#pragma once

#include "ofMain.h"
#include "ofxOsc.h"

// listening port
#define PORT 2020
// max number of rows
#define NUM_MSG_STRINGS 30
// number of seconds before message is deleted
#define TIMER 20

class ofApp : public ofBaseApp{

	public:
		void setup();
		void update();
		void draw();
    
        ofTrueTypeFont font;
        ofxOscReceiver receiver;

        int currentMsgString;
        string msgStrings[NUM_MSG_STRINGS];
        float timers[NUM_MSG_STRINGS];
		
};

```

```cpp:ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofSetFrameRate(60); // run at 60 fps
    ofSetVerticalSync(true);

    // listen on the given port
    receiver.setup(PORT);
}

//--------------------------------------------------------------
void ofApp::update(){
    // hide old messages
    for(int i = 0; i < NUM_MSG_STRINGS; i++){
        if(timers[i] < ofGetElapsedTimef()){
            msgStrings[i] = "";
        }
    }
    
    // check for waiting messages
    while(receiver.hasWaitingMessages()){

        // get the next message
        ofxOscMessage m;
        receiver.getNextMessage(m);

        // unrecognized message: display on the bottom of the screen
        string msgString;
        msgString = m.getAddress();
        msgString += ":";
        for(size_t i = 0; i < m.getNumArgs(); i++){

            // get the argument type
            msgString += " ";
            msgString += m.getArgTypeName(i);
            msgString += ":";

            // display the argument - make sure we get the right type
            if(m.getArgType(i) == OFXOSC_TYPE_INT32){
                msgString += ofToString(m.getArgAsInt32(i));
            }
            else if(m.getArgType(i) == OFXOSC_TYPE_FLOAT){
                msgString += ofToString(m.getArgAsFloat(i));
            }
            else if(m.getArgType(i) == OFXOSC_TYPE_STRING){
                msgString += m.getArgAsString(i);
            }
            else{
                msgString += "unhandled argument type " + m.getArgTypeName(i);
            }
        }

        // add to the list of strings to display
        msgStrings[currentMsgString] = msgString;
        timers[currentMsgString] = ofGetElapsedTimef() + TIMER;
        currentMsgString = (currentMsgString + 1) % NUM_MSG_STRINGS;

        // clear the next line
        msgStrings[currentMsgString] = "";
    }
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofBackgroundGradient(100, 0);
    
    // draw recent unrecognized messages
    for(int i = 0; i < NUM_MSG_STRINGS; i++){
        ofDrawBitmapStringHighlight(msgStrings[i], 10, 40 + 15 * i);
    }

    string buf = "listening for osc messages on port " + ofToString(PORT);
    ofDrawBitmapStringHighlight(buf, 10, 20);
}
```

# ログ確認

このコードでopenFrameworksのアプリを起動し、試しにTidalCyclesで以下のコードを実行してみます。

```haskell
once $ s "bd" # gain 1.5
```

すると、アプリの画面に以下のようなログが表示されるかと思います。

```
/dirt/play: s:cps f:0.3625 s:cycle f:891.794 s:delta f:2.75862 s:gain f:1.5 s:n f:0 s:s s:bd
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437488/d333f641-242c-1563-c5d4-21c3462f700a.png)