今更，Wiiリモコンでオリジナル楽器作ってみた

ソースコードは下の方に書いておきます．

#きっかけ

リュックに偶然wiiリモコンが入っていたので，おけんきゅう以外のことがやりたくなった

ちょっと昔に流行ったオタマトーンのような楽器を目指しました．

![スクリーンショット 2017-05-31 9.48.11.png](https://qiita-image-store.s3.amazonaws.com/0/137949/71561ff7-3fbe-41d3-aebd-dac9699e6952.png)

10年以上前...

#動画
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Qiita用 <a href="https://t.co/boDcUOmimi">pic.twitter.com/boDcUOmimi</a></p>&mdash; インドア (@hakuta04) <a href="https://twitter.com/hakuta04/status/869770356109660160">2017年5月31日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>


#環境
- よくあるwiiリモコン
- macOS Sierra 10.12

#wiiリモコンをMacと接続する

wiiリモコンとPCを接続する方法は様々あるみたいですが，
OSCで通信してかっこいいことしてみたかったので，[OSCulator](https://osculator.net/)を使うことにしました．

[公式サイト](https://osculator.net/)の紹介文によると
> OSCulator is the missing link between your controllers and your music or video software. For example, you can use your Nintendo Wiimote or Apple iPhone with Ableton Live or any MIDI compatible application, with ease.
OSCulator supports the OSC protocol which makes it able to be used with a wide variety of software and devices like Processing, Max/MSP or the Lemur multitouch controller, even the TUIO protocol.


Wiimoteって書いてるし面白いことができそうw


ダウンロード＆インストールしたら，wiiリモコンと接続するための設定をします．

設定を開いて，
![スクリーンショット 2017-05-31 9.45.30.png](https://qiita-image-store.s3.amazonaws.com/0/137949/0ad3e4d0-c9bc-fd98-cd02-778aa6ef8836.png)

Pair Wiimoteを押してペアリングします．この時,mac側でBluetoothをオンにしておく必要があります．プラスボタンとマイナスボタンを同時押ししてたらいつの間にか繋がってました

![スクリーンショット 2017-05-31 10.01.13.png](https://qiita-image-store.s3.amazonaws.com/0/137949/c6cb3730-9fed-a3df-aaca-a632f40d8384.png)

テキトーにボタンを押して行くと，Messageの項目が増えると思います．多分

EventTypeをOSC Messageに，ValueをnewしてＤっぽいのにしてください．


![スクリーンショット 2017-05-31 9.45.45.png](https://qiita-image-store.s3.amazonaws.com/0/137949/b03cbee3-bbdc-1132-0f65-903f2cae2f04.png)

OSC通信するためには，ポートを指定する必要があるので，ここでポートを設定します．

`osc.udp://localhost:9000`

とりあえず，９０００にしてますが，ソースコードのPORTと合っていれば，なんでもいいです．


#openFrameworksでセンサの値を受け取る

oF側でOSCで通信された値を受け取るために，アドオン[ofxOsc](http://openframeworks.cc/ja//documentation/ofxOsc/)を使います．

いつもお世話になってます...
http://yoppa.org/ma2_10/2279.html?undefined&undefined

ここのレシーバーを参考にプログラムを組みました．

ボタン系も全部Floatで値が返ってくるので，true=>1.0,false=>0.0にしとけばいいと思います．

音を出すためのアドオンは，ofxMaximを使いました．
https://github.com/falcon4ever/ofxMaxim

本当にありがとうございます...
http://yoppa.org/geidai_graphb11/3391.html



##ソースコード
```cpp:ofApp.h
#pragma once

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

// OSC通信するポート
#define PORT 9000

using namespace std;

class ofApp : public ofBaseApp{
    
public:
    
    void setup();
    void update();
    void draw();
    void keyPressed(int key);
    void dumpOSC(ofxOscMessage m); //OSCの中身を出力する
    void audioOut(float * input, int bufferSize, int nChannels);
    
    ofxOscReceiver receiver;
    
    ofSoundStream soundStream;
    
    int initialBufferSize;
    
    int sampleRate;
    
    double wave,sample,outputs[2];
    
    //周波数
    float freq;
    
    ofxMaxiMix mymix;
    //Oscilator
    ofxMaxiOsc osc;
    int mode;
    
    vector <float> lAudio;
    vector <float> rAudio;
    
　　　　　　　　//周波数直打ちなのめっちゃカッコ悪い...
    //Cマイナーペンタトニックスケール
    float cMpenta[16] = {130.813,146.832,164.814,195.998,220.000,261.626,293.665,329.628,391.995,440.000,523.251,587.330,659.255,783.991,880.000,1046.502};
    
    //Cブルースペンタトニックスケール
    float cBluesPenta[22] = {130.813, 146.832, 155.563, 174.614, 184.997, 195.998, 233.082, 261.626, 293.665, 311.127, 349.228, 369.994, 391.995, 466.164, 523.251, 587.330, 622.254, 698.456, 739.989, 783.991, 932.328, 1046.502};
    
    
    //pitch, yaw, roll, accel(加速度)
    float pitch,yaw,roll,accel;
    
    //ボタンの状態受け取る
    float AButtonState;
    float BButtonState;
    float pulsButtonState;
    float minusButtonState;
    
};



```

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

template
<
typename TYPE,
std::size_t SIZE
>
std::size_t array_length(const TYPE (&)[SIZE])
{
    return SIZE;
}

void ofApp::setup(){
    ofBackground(0, 0, 0);
    receiver.setup( PORT );
    
    AButtonState,BButtonState = 0;
    pitch, roll, yaw, accel = 0;
    
    ofSetVerticalSync(true);
    
    sampleRate = 44100; /* Sampling Rate */
    initialBufferSize = 512;	/* Buffer Size. you have to fill this buffer with sound*/
    
    ofSoundStreamSetup(2,0,this, sampleRate, initialBufferSize, 4);
    
    lAudio.assign(initialBufferSize, 0.0);
    rAudio.assign(initialBufferSize, 0.0);
    
    mode = 0;
}

void ofApp::update(){
    
}

void ofApp::draw(){
    ofSetColor(225);
    ofNoFill();

    ofPushStyle();
    ofPushMatrix();
    
    ofTranslate(10, 0,0);

    ofDrawRectangle(0, 0, 100, ofGetHeight());
    
    ofPushMatrix();
        for (int i ; i < 36 ; i++) {
            ofTranslate(0,ofGetHeight() / 36);
            ofDrawRectangle(0, 0, 100, ofGetHeight()/36);
            cout << "" << endl; //何故かこれが無いと動かない
        }
    ofPopMatrix();
    

    ofFill();
    ofSetColor(245, 58, 135);
    
    ofTranslate(0, 10, 0);
    
    ofDrawRectangle(0, ofGetHeight()-(ofGetHeight()*pitch), 100, ofGetHeight() / 36);
    
    
    ofPopMatrix();
    ofPopStyle();
    
}


void ofApp::audioOut(float * output, int bufferSize, int nChannels){
    for (int i = 0; i < bufferSize; i++){
        
        freq = ofMap(pitch,0,1,130.813,1046.502);
        float pan = 0.5;
        
        while(receiver.hasWaitingMessages()){
            
            ofxOscMessage m;
            receiver.getNextMessage(&m);
            
            if (m.getAddress() == "/wii/1/accel/pry"){
                pitch = ofMap(m.getArgAsFloat(0), 0.15, 0.85, 0.0, 1.0);
                
                //小数点４桁以下を切り捨て
                int tmp = pitch * 1000;
                pitch = (float)tmp / 1000;
                
                pitch = MAX(pitch, 0);  //最大で1
                pitch = MIN(pitch, 1);  //最小で0
                
                roll = m.getArgAsFloat(1);
                yaw = m.getArgAsFloat(2);
                accel = m.getArgAsFloat(3);
                
            }
            else if (m.getAddress() == "/wii/1/button/B"){
                BButtonState = m.getArgAsFloat(0);;
            }else if (m.getAddress() == "/wii/1/button/A"){
                AButtonState = m.getArgAsFloat(0);;
            }else if (m.getAddress() == "/wii/1/button/Minus"){
                minusButtonState = m.getArgAsFloat(0);;
            }else if (m.getAddress() == "/wii/1/button/Plus"){
                pulsButtonState = m.getArgAsFloat(0);;
            }
            
        }
        
        
        if(minusButtonState == 1){
            mode--;
            mode = MAX(mode, 0);
        }
        
        if(pulsButtonState == 1){
            mode++;
            mode = MIN(mode, 1);
            
        }
        
        
        if(AButtonState == 1){
            
            int i;
            
            switch (mode) {
                case 0:
                    i = ofMap(pitch,0,1,0,array_length(cBluesPenta));
                    wave = osc.pulse(cBluesPenta[i], 0.9);
                    break;
                case 1:
                    i = ofMap(pitch,0,1,0,array_length(cMpenta));
                    wave = osc.pulse(cMpenta[i], 0.9);
                    break;
                default:
                    i = ofMap(pitch,0,1,0,array_length(cBluesPenta));
                    wave = osc.pulse(cBluesPenta[i], 0.9);
                    break;
            }
        }else{
            wave = osc.pulse(freq, 0.9);
        }
        
        
        if(BButtonState == 1){
            mymix.stereo(wave, outputs, pan);
            lAudio[i] = output[i*nChannels    ] = outputs[0];
            rAudio[i] = output[i*nChannels + 1] = outputs[1];
        }
    }
}

```

#感想
詰まることなく実装できました．
10年前の技術なので，Sierraに対応してるかヒヤヒヤしましたが，まだ行けそうですね

もっと真面目にゲームとかくだらないもの作って見たいと思います．


#参考にした記事
WiiリモコンのデータをOSCurator経由でProcessingに送る方法
http://d.hatena.ne.jp/metya1013/20120331/1333202187
第８回：openFrameworks サウンド・音響合成 ofxMaxim, ofxOsc, ofxSuperCollider
http://yoppa.org/geidai_graphb11/3391.html
openFramewoks – OSC (Open Sound Control) を利用したネットワーク連携
http://yoppa.org/ma2_10/2279.html?undefined&undefined
ラジオペンチ オタマトーンの音域を、周波数カウンターで測ってみた
http://radiopench.blog96.fc2.com/blog-entry-409.html