====== ofxMaxim ====== ofxMaximに関してあまりにWEB上に情報が少なかったので,自分のためにここにまとめておきます. 余談ですが,MaximillianのExampleが非常に良かったので,これ書いたの誰かなと思って作者のページをいろいろ見てたら * Maximilian: C++ Audio and Music DSP Library, Mick Grierson, JUCE Summit 2015 * https://www.youtube.com/watch?v=H-Av78mtFF4 にて作者が詳しく発表している動画がありましたので,ここに共有しておきます.教育におけるツールキットとして考えているので Exampleが非常に基礎を抑えたいい内容になってるんですね.libpdに関しては,とてもusefulだけど幾らかのケースにおいて,over-engineered(過剰スペック)であるとも述べています.ofxPdもとても優れているので一長一短だと思います. ===== ofxMaximとは ===== ofxMaximはMaximillan をベースにしたopenframeworks用のaddonになります.Maximillan自体はC++のみで記載されてる波形生成ライブラリになります. * 公式ウェブサイト: http://www.maximilian.strangeloop.co.uk/ * GitHub[Maximillian] : https://github.com/micknoise/Maximilian * GitHub[ofxMaxim] : https://github.com/falcon4ever/ofxMaxim 結構年代物の古いライブラリですが,C++で少ないファイル数で記述されているので環境構築も手軽です.ofxMaximのGitHubページを見てもらえればわかりますが,Exampleが同梱されていませんので,https://github.com/micknoise/Maximilian から一旦すべてのファイルをダウンロードすると良いです.addonの追加方法に関してはこちらでは触れません.このページではコードを載せているので,実際には ofxMaxim をgit cloneだけしておけばこのページは進められます. ===== サイン波を鳴らすSimple Example ===== 440Hzのサイン波を鳴らすだけのサンプルコードを記載します.ただし openframeworksの場合は音を再生するためにaudioOut関数と一緒に組み合わせて使うことになります. audioOutに関しては openframeworksのExamples/sound/audioOutputExample を参照してください.audioOut()関数はすでにopenframeworks上でサウンドバッファーのCallback関数として登録されているので,audioOutの名前でないといけません. setup()では基本的にopenframeworksのサウンドデバイスに関する設定がほとんどです.少しこの設定のコードが長いですが,システム上のデフォルトスピーカを自動選択するようにしています.こうしておくと開発のときに楽ちんです.デフォルトスピーカに関してはmacの右上タスクバーにあるスピーカアイコンをクリックすると一覧表示されるサウンドデバイスで,チェックが入っている箇所です.ちなみにaltキーを押しながらクリックすると出力/入力が一緒に表示されます.右図を参照してください.またデフォルトスピーカに対して設定可能な最も高いサンプリングレートと,設定可能な出力/入力チャンネルを設定しています.setup()最後の行では,設定されたサウンドデバイスと同じ設定にMaximillian側を合わせています. {{:of:スクリーンショット_2019-05-04_16.57.36.png|}} #include "ofApp.h" void ofApp::setup(){ ofSetFrameRate(60); // set System Default Output Device int sampling_rate; int number_output_channels; int number_input_channels; int buffer_size = 512; auto devices = soundStream.getDeviceList(); for( int i = 0; i < devices.size(); i++ ){ if( devices[i].isDefaultOutput ){ cout << devices[i].name << endl; settings.setOutDevice(devices[i]); sampling_rate = devices[i].sampleRates[devices[i].sampleRates.size()-1]; number_output_channels = devices[i].outputChannels; number_input_channels = devices[i].inputChannels; } } settings.setOutListener(this); settings.sampleRate = sampling_rate; settings.numOutputChannels = number_output_channels; settings.numInputChannels = number_input_channels; settings.bufferSize = buffer_size; soundStream.setup(settings); // set Maximillian same as sound device setting. maxiSettings::sampleRate = sampling_rate; maxiSettings::bufferSize = buffer_size; } void ofApp::update(){ } void ofApp::draw(){ ofBackground(50); ofDrawBitmapString("Can you hear a 440Hz Sinewave?", 20,20); } void ofApp::audioOut(ofSoundBuffer &buffer) { int buffer_size = settings.bufferSize; int number_channels = settings.numOutputChannels; for( int i = 0; i < buffer_size; i++ ){ wave = osc.sinewave(440); mymix.stereo(wave, outputs, 0.5); buffer[i*number_channels ] = outputs[0]; buffer[i*number_channels + 1] = outputs[1]; } } #pragma once #include "ofMain.h" #include "ofxMaxim.h" class ofApp : public ofBaseApp{ public: void setup(); void update(); void draw(); void audioOut(ofSoundBuffer & buffer); ofxMaxiMix mymix; ofxMaxiOsc osc; double wave; double outputs[2]; ofSoundStream soundStream; ofSoundStreamSettings settings; }; ===== PANを振る ===== 上記サンプルを利用して,サイン波が右から左へ移動するプログラムに記述し直してみます.PANの設定は mymix.stereo(wave, outputs, 0.5); の0.5の部分です.このパラメータを操作することで * 0: 左のみ * 0.5: 両方 * 1.0: 右のみ という具合に音の左右の鳴りを変更することができます.そこで,次のようにmymix.stereoを変更します. mymix.stereo(wave, outputs, ofMap(osc_pan.sinewave(1), -1.0, 1.0, 0.0, 1.0)); ただし,osc_pan はまだ宣言されていない変数なので,ofApp.h にこの変数を下記のように追記しておきましょう. ofxMaxiOsc osc, osc_pan; これにより,osc_pan を1Hzに設定し,その値を0.0, 1.0に変更してあげることで,0.5秒おきに音源が右から左,左から右へと移動する結果となります. ===== InputとOutputを同時に使う ===== 先程のシンプルなプログラムはサイン波を再生しているだけでした.次に簡単な雛形Exampleとして,サウンドデバイスの入力と出力を同時に扱うプログラムを記述してみます.ふるまいとしては下記のようにします. - 出力:440Hzのサイン波 - 入力:マイク入力のデータを画面に表示する ofxMaximの話というよりは,OF側の記述追加のみになります.最初のサウンドデバイス設定の際,入力デバイスに関しても同時に設定しておきます. 出力及び入力デバイスを別々に指定できますが,Sampling Rateは両方共同じ設定にしておく必要があります.少しだけ記述量が増えていますが,どれも基礎で重要なので下記コードはよく読んで十分理解してきましょう.なお,プログラムを実行した後,スペースキーを押すとサイン波の出力が停止するので,環境音を見てみたい場合にご利用ください. #include "ofApp.h" void ofApp::setup(){ ofSetFrameRate(60); // set System Output/Input Device same as System Default int number_output_channels; int number_input_channels; auto devices = soundStream.getDeviceList(); for( int i = 0; i < devices.size(); i++ ){ if( devices[i].isDefaultOutput ){ string_device_info += "Output Device: "+devices[i].name + "\n"; settings.setOutDevice(devices[i]); string_device_info += " - Configurable Sampling Rate: "; for( int j = 0; j < devices[i].sampleRates.size(); j++){ string_device_info += ofToString(devices[i].sampleRates[j])+","; } string_device_info += "\n"; settings.sampleRate = devices[i].sampleRates[0];// lowest sampling rate number_output_channels = 2; // stereo } if( devices[i].isDefaultInput ){ string_device_info += "Input Device: "+devices[i].name + "\n"; settings.setInDevice(devices[i]); string_device_info += " - Configurable Sampling Rate: "; for( int j = 0; j < devices[i].sampleRates.size(); j++){ string_device_info += ofToString(devices[i].sampleRates[j])+","; } string_device_info += "\n"; number_input_channels = 1; // mono } } string_device_info += "Sampling Rate: " + ofToString(settings.sampleRate) +"\n"; settings.setOutListener(this); settings.setInListener(this); settings.numOutputChannels = number_output_channels; settings.numInputChannels = number_input_channels; settings.bufferSize = 512; soundStream.setup(settings); // set Maximillian same as sound device setting. maxiSettings::sampleRate = settings.sampleRate; maxiSettings::bufferSize = settings.bufferSize; flg_pause = false; } void ofApp::update(){ } void ofApp::draw(){ ofBackground(50); ofDrawBitmapString("Can you see and hear a 440Hz Sinewave?", 20,20); ofNoFill(); ofBeginShape(); { for( int i = 0 ; i < settings.bufferSize; i++){ ofVertex(ofGetWidth()*(i/(float)settings.bufferSize), ofGetHeight()/2 + 300*buf_input[i]); } } ofEndShape(); ofDrawBitmapString(string_device_info, ofGetWidth()/2, 20); } void ofApp::audioOut(ofSoundBuffer &buffer) { if( flg_pause )return; int number_channels = settings.numOutputChannels; for( int i = 0; i < settings.bufferSize; i++ ){ wave = osc.sinewave(440); mymix.stereo(wave, outputs, 0.5); buffer[i*number_channels ] = outputs[0]; buffer[i*number_channels + 1] = outputs[1]; } } void ofApp::audioIn(ofSoundBuffer &buffer) { for( int i = 0; i < settings.bufferSize; i++ ){ buf_input[i] = buffer[i]; } } void ofApp::keyPressed(int key) { if( key == ' ' ){ flg_pause = !flg_pause; } } #pragma once #include "ofMain.h" #include "ofxMaxim.h" class ofApp : public ofBaseApp{ public: void setup(); void update(); void draw(); void keyPressed(int key); void audioIn(ofSoundBuffer &buffer); void audioOut(ofSoundBuffer & buffer); ofxMaxiMix mymix; ofxMaxiOsc osc; double wave; double outputs[2]; double buf_input[512]; ofSoundStream soundStream; ofSoundStreamSettings settings; string string_device_info; bool flg_pause; }; ==== 実行時のスクリーンショット ==== {{ :of:スクリーンショット_2019-05-12_9.56.31.png |}} ===== MaximillianのExampleで学習する ===== 以上を抑えて,あとはMaximillian のExampleで学習しましょう.先に紹介したMaximillianのGithubからファイル一式をダウンロードすると,ディレクトリ内にmaximilianTest.xcodeprojを見つけることができると思います.こちらをXcodeで開き,Source/main.cpp を修正することですぐに動作確認することができます.動作させる際はmaximilian_examplesディレクトリのコードをそのまま main.cpp にコピーすればOKです. {{:of:スクリーンショット_2019-05-05_8.38.43.png|}} ビルドの際,32bit に関するエラーが出た場合は下の画像にある通り,valid architectureからi386を削除してください. {{:of:スクリーンショット_2019-05-05_9.04.30.png|}}