LoginSignup
12
15

More than 5 years have passed since last update.

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

Posted at

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

きっかけ

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

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

スクリーンショット 2017-05-31 9.48.11.png

10年以上前...

動画

環境

  • よくあるwiiリモコン
  • macOS Sierra 10.12

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

wiiリモコンとPCを接続する方法は様々あるみたいですが,
OSCで通信してかっこいいことしてみたかったので,OSCulatorを使うことにしました.

公式サイトの紹介文によると

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

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

スクリーンショット 2017-05-31 10.01.13.png

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

EventTypeをOSC Messageに,ValueをnewしてDっぽいのにしてください.

スクリーンショット 2017-05-31 9.45.45.png

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

osc.udp://localhost:9000

とりあえず,9000にしてますが,ソースコードのPORTと合っていれば,なんでもいいです.

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

oF側でOSCで通信された値を受け取るために,アドオン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

ソースコード

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;

};



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);

                //小数点4桁以下を切り捨て
                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
第8回: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

12
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
15