Advertisement

JUCEハンズオン@Ableton and Max Community Japan #009

Software Developer, Patent Engineer
Nov. 15, 2020
Advertisement

More Related Content

Slideshows for you(20)

Similar to JUCEハンズオン@Ableton and Max Community Japan #009(20)

Advertisement

Recently uploaded(20)

JUCEハンズオン@Ableton and Max Community Japan #009

  1. JUCEハンズオン @Ableton and Max Community Japan #009 塩澤達矢(COx2) 2020/11/14
  2. Note ・本内容は、JUCEユーザーである発表者個人の感想であり、JUCEの開発元である Raw Material Software, Ltd.を代表するものではありません ・JUCEの仕様に関わる事項は、発表当日(2020/11/14)のReleaseバージョン(JUCE 6.0.4)に準拠します ・ご紹介する範囲は、JUCEの一部機能や一部APIに留めております ・時間の都合上、C++言語の文法についての説明は割愛させていただきます ・本日のソースコード https://github.com/COx2/amcj009-juce-study
  3. 自己紹介 名前: 塩澤達矢(COx2) 属性: JUCE enthusiast オーディオプログラマー/インデペンデントJUCEプログ ラマー/JUCE JAPAN編集部代表 JUCE案件を中心に取り扱う個人事業主のソフトウェア 開発者 趣味でVSTプラグインを制作する中でJUCEと出会い、 その強力な開発環境に衝撃を受ける 日本のエンジニアにJUCEの魅力を伝えるべく、2016年 に非公式ガイド「JUCE JAPAN」を発行 @CO_CO_ tatsuya.shiozawa.99
  4. オーディオプラグインを作ってみたいと思っ たことはありますか?
  5. オーディオプラグイン開発の魅力 ・僕の考えた最強のシンセサイザー ・音楽制作ソフトで使える(Cubase, Live, Max...) ・楽器の原理や仕組みが学べる ・楽曲制作に使える ・プラグインビジネス
  6. オーディオプラグインを開発する方法を調 べてみたことはありますか?
  7. オーディオプラグイン開発特有の難しさ ・C/C++プログラミングって難しそう… ・VST SDK? VST3 SDK? AAX SDK? ・プラグイン・インターフェースって何? ・プラグイン・アーキテクチャとは? ・リアルタイムプログラミング、マルチスレッド… ・音を鳴らしたいだけなのに…
  8.  JUCEがその悩みを解決します
  9. JUCEハンズオン ・JUCEとは? ・JUCEをはじめよう! ・Q&A ・JUCEでオーディオプラグイン開発入門 ・JUCEで広がるオーディオソフトウェア開発 ・Audio Developer Conferenceへのお誘い ・Q&A
  10. JUCEとは?
  11. JUCE 名前の由来 = Jules' Utility Class Extensionsの略称 Julian Storer※が開発したマルチメディア向けの C++フ レームワーク ※https://github.com/julianstorer Julian StorerがDAWソフト『Tracktion※』を制作する際 に開発したライブラリが基となっている ※現在の製品名は『WAVEFORM』https://www.tracktion.com/ 初期リリースは2004年 最新版は2020年10月リリースのJUCE 6.0.4
  12. Cross-platform クロスプラットフォーム設計の C++ライブラリ 公式では以下のプラットフォームに対応する  - Windows  - macOS  - Linux  - iOS  - Android 抽象化されたクラス群とネイティブ APIをCallするク ラス群とに分離された設計になっている 任意のネイティブAPI層の実装を追加することで、 ユーザーが独自に対応プラットフォームを追加する ことが可能
  13. Audio programming オーディオプログラミングに特化したクラス群が用 意されている (AudioProcessor, Synthesiser, AudioBuffer, MidiMessage) 各プラットフォームの主要なネイティブオーディオ APIとMIDI APIをサポートしている  - Windows: WASAPI/ASIO/DirectSound  - macOS/iOS: CoreAudio  - Linux: ALSA/JACK/Bela  - Android: OpenSL ES/Oboe ネイティブオーディオ APIの層と信号処理の層が分 離しており、信号処理のコードがプラットフォーム依 存なく実装することができる
  14. Audio plugin development VSTをはじめ、DAWでサポートされている主要な プラグインフォーマットをビルドするためのインター フェース群とプロジェクトテンプレートが用意されて いる サポートするプラグインフォーマット  - VST  - VST3  - AudioUnit  - AudioUnit v3  - AAX  - RTAS  - Unity
  15. GUI library JUCE独自のGUIライブラリを提供することにより、 GUIをクロスプラットフォームで実装することができ る JUCEのGUIシステムに則ったUIコンポーネントを 作成することで、ユーザー独自に GUIを拡張するこ とが可能 OpenGLをUIコンポーネントに描画するクラスが用 意されているので、OpenGLを用いたリッチUIを実 装することも可能
  16. Useful modules アプリケーションの各種機能を実装するのに便利なモジュール群が提供されている ・コアモジュール  juce_core… JUCEライブラリの基礎となるコアモジュール。 Basicなクラス(String, MemoryBlock他)、プラット フォーム固有のAPIを抽象化するクラス(Thread, Socket他)が含まれる ・その他モジュール(一部)  juce_audio_formats... WAV, FLAC等のオーディオファイルを Read, Writeする機能を提供  juce_data_structures… DynamicObjectを実現するValueTreeクラスなど  juce_cryptography… RSAなどのさまざまな暗号化機能を持つクラスなど  juce_osc… OSC(Open Sound Control)の送信受信を実装したクラスなど  juce_video… ビデオ再生、カメラ入力キャプチャをするためのクラスなど  juce_product_unlocking… オンライン製品認証を実装するクラスなど  juce_analytics… GoogleAnalytics等に利用情報を収集して送信するクラスなど
  17. Easy to integration JUCEは、ソースコード形式で提供されていること、 元はC++ライブラリとして開発が始まったことから、 様々なC++ライブラリと組み合わせ易い設計思想 になっている 既にあるソフトウェア資産を利用することで、リッチ で多機能なソフトウェアを開発することができる 他のC++ライブラリとの組み合わせ例 ・juce_meets_link JUCEにAbleton Linkを組み込むことで、Link対応 のソフトウェアとテンポ同期ができるプログラム https://github.com/COx2/juce_meets_link ・juce_meets_ndi JUCEにNDIを組み込むことで、同一 LAN内のオー ディオプラグイン間で Video/Audioの送受信ができ るプログラム https://github.com/COx2/juce_meets_ndi
  18. Made with JUCE 多数の楽器メーカー、オーディオアプリ /プラグイン ベンダーによる採用実績がある Maxの開発にJUCEを採用した件についてのインタ ビュー記事がある。それによると、 Maxのクロスプ ラットフォーム化、一部の UIの実装にJUCEを利用 しているらしい https://juce.com/discover/stories/building-max-with-juce
  19. Development Github上でオープンに開発が行われている https://github.com/juce-framework/JUCE ユーザーからIssueやPull Request※を立てることが できる ※著作権のコンタミを避けるために Pull Requestをmergeしない運用を取っている 新規機能などの開発が行われているブランチは Closedな場合がある
  20. License ProprietaryとOSSのデュアルライセンス方式 ・JUCE 6 End User License Agreement  ・使用料: 無料/有料  ・ユーザーの組織規模, 事業規模によって価格が設定されている  ・クローズドソースで製品を販売したい用途向け ・GNU GPL v3  ・使用料: 無料  ・製品のプログラムはGPLの派生物とみなされる  ・製品をOSSとして運用したい(しても気にしない)用途向け
  21. Price
  22. Price 無料版では起動時にスプラッシュスクリーンが表 示される ※GPL版ではスプラッシュスクリーンの表示が免 除される
  23. Support ・JUCE Forum https://forum.juce.com/ ・チュートリアル https://juce.com/learn/tutorials
  24. JUCEとは… ・クロスプラットフォームなC++フレームワーク ・オーディオプログラミングに便利なクラス群とAPI設計 ・オーディオプラグイン開発用のテンプレート ・独自のGUIライブラリでクロスプラットフォームなGUIを実現 ・多機能なモジュール群 ・継続的な開発とサポート ・音楽系ソフトウェアでの採用実績が多数 ・(条件を満たせば)無料で使える
  25. JUCEをはじめよう!
  26. JUCEのはじめかた JUCEをはじめて触る方に向けて、次の点について解説します ・開発環境の構築 ・JUCEの入手方法 ・Projucerのセットアップ ・DemoRunnerの解説(実演) ・簡単なオーディオアプリケーションの制作(実演)
  27. JUCEのセットアップ
  28. 開発環境の準備 ・C++コンパイラとIDE   ・コンパイラ: GCC, Clang, MSVCをサポート   ・Windows: Visual Studioをインストールする   ・macOS: Xcodeをインストールする   ・Linux: 後述 ・JUCEライブラリ ・公式サイトからDLまたはGitHubからCloneする ・Projucer   ・公式サイトからDLした場合... ZIP内に同梱されています   ・GitHubからCloneした場合... ローカルでビルドしてください ※JUCE 6からCMakeもサポートされましたが、本内容では触れません。
  29. 開発環境の準備 ・Linux  Ubuntu 20.04において、以下の依存ライブラリをインストールすることでビルド出来る ことを確認しています。 $ sudo apt-get update $ sudo apt-get install make clang g++ freeglut3-dev libasound2-dev libcurl4-openssl-dev libfreetype6-dev libjack-jackd2-dev libx11-dev libxcomposite-dev libxcursor-dev libxinerama-dev libxrandr-dev mesa-common-dev webkit2gtk-4.0 ladspa-sdk
  30. JUCEを入手しよう JUCEを入手するだけであれば購入手続き等は不要 JUCEを入手する方法は主に2通りある  A. 公式サイトからDLする  B. GitHubリポジトリからCloneする B.の方法はProjucerをローカルでビルドする必要があるので、 C++に不慣れな方はA.の方法をおすすめします JUCE 6からCMakeに対応しているので、CIに組み込む場合はB.の方法が便利
  31. A. 公式サイトからDL https://juce.com/get-juce Personal欄のDownloadリンクを選択すると、 プラットフォーム別に DLリンクが表示される
  32. B. GitHubからClone $ git clone https://github.com/juce-framework/JUCE.git Cloneした後、Projucerをビルドしておきます JUCE/extras/Projucer 以下にある各IDE用プロ ジェクトファイルからプロジェクトを開き、ビルドを実 行しましょう
  33. Projucer 各種プラットフォーム IDE用プロジェクトを生成する プロジェクトジェネレータ JUCEライブラリとユーザーが実装するプログラム とをリンクするための設定を自動で行ってくれる Projucer自身は独自の.jucerフォーマットでプロ ジェクトを管理する 他のサードパーティライブラリとのリンクのための 設定をProjucerのプロジェクトで設定することが出 来る
  34. Projucerの準備 1. Projucerを起動する 2. [File]→[Global Paths...]メニューをクリックし て『Global paths』ダイアログを開く
  35. Projucerの準備 3. 『Path to JUCE』欄に、JUCEのルートディレクトリを 入力する A. 公式サイトからDLした場合はZIPの解凍先ディレ クトリ B. git cloneした場合はリポジトリのルートディレクトリ 4. 『JUCE Modules』欄に、JUCEディレクトリの直下に 置かれた『modules』ディレクトリを入力する
  36. JUCE DemoRunner Projucerのメニューから[File]→[Open Example]→ [Launch Demo Runner]をクリック A. 公式サイトからDLした場合、ビルド済みの DemoRunnerバイナリが同梱されているた め、ビルドをスキップして DemoRunnerが起 動する B. git cloneした場合、DemoRunnerを新規にビ ルドする必要がある。 ProjucerからIDEでプ ロジェクトを開くかどうか尋ねられるので、そ れにしたがってプロジェクトを開いてビルドを 実行する
  37. JUCE DemoRunner DemoRunnerの実行ファイルの用意が済んだら、 Projucerの[File]→[Open Example]→[Launch Demo Runner]からDemoRunnerを起動する DemoRunnerのブラウジングメニューから様々な デモプログラムを起動してみよう 各デモプログラムから JUCEライブラリのリファレン ス実装を確認することができる
  38. JUCEでアプリ制作
  39. JUCEのワークフロー JUCEでは次の手順でプログラムを作成します 1. [Projucer] 『Application』テンプレートを選択する 2. [Projucer] 対象プラットフォーム設定、モジュール設定を行う 3. [Projucer] プログラムの基礎となるソースコードが自動生成される 4. [IDE] ソースコードを編集する 5. [IDE] プロジェクトをビルドする
  40. 実演 Hello sine wave
  41. Hello sine wave ToneGenerator系オーディオアプリケーション
  42. プロジェクト作成 Projucerのスタート画面で次の項目を設定 ・テンプレートの選択『 Application - Audio』 ・プロジェクト名の設定 『HelloSineWave』 ・対象プラットフォームにチェック
  43. プロジェクト作成 プログラムの基礎となるソースコードが自動生成さ れる Main.cpp =プログラムのエントリポイント MainComponent.h/cpp =UIコンポーネントとオーディオ処理の実装が一 体となったクラス
  44. 主に実装を追加する関数 ・MainComponent::MainComponent コンストラクタ メンバ変数やインスタンスの初期化を実装する ・MainComponent::getNextAudioBlock オーディオデバイスからのコールバックで(定期的に)呼ばれる関数 引数で受け取るオーディオバッファにサンプルデータを書き込むと、オーディオデバイス 側でサンプルデータの再生が行われる
  45. 主に実装を追加する関数 ・MainComponent::paint コンポーネント内の描画処理を実行する関数 引数で受け取るグラフィックコンテキストに対して各種命令を呼ぶことで描画処理を組み 込むことができる ・MainComponent::resized コンポーネントのサイズが変更された時に呼ばれる関数 Parentコンポーネントのサイズが変更されたことをトリガーとしてChildコンポーネントの サイズと配置座標を決定することでレスポンシブなGUIを実装することができる
  46. サウンドプログラミング 1. オーディオデバイスからオーディオバッファ が渡される 2. オーディオバッファ( float配列)にサイン波一 周分(360°=2π)の波形サンプルを書き込む 3. オーディオバッファがオーディオデバイスに 返される 4. オーディオデバイスがオーディオバッファに 書き込まれた波形(サイン波)を再生する 上記のうち、1.3.4.の処理はJUCEライブラリによっ て予め実装されている
  47. サウンドプログラミング ・MainComponent.cpp - getNextAudioBlock関数にサイン波のサンプルをバッファに渡す処理を実装する void MainComponent::getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) { bufferToFill.clearActiveBufferRegion(); auto* buffer = bufferToFill.buffer; for (int channel = 0; channel < buffer->getNumChannels(); ++channel) { float* channelData = buffer->getWritePointer(channel); for (int sample = 0; sample < buffer->getNumSamples(); ++sample) { const float phase = juce::MathConstants<float>::twoPi * sample / buffer->getNumSamples() * 2; channelData[sample] = sinf(phase); } } const float gain = 0.5f; buffer->applyGain(gain); }
  48. GUIプログラミング - コントローラ 1. juce::Sliderクラス(UIコンポーネント)のイン スタンス(sliderGain)を生成する 2. sliderGainをMainComponent(アプリケー ションウインドウのChildコンポーネント)の Childに追加する 3. juce::Labelクラス(UIコンポーネント)のイン スタンス(labelGain)を生成する 4. labelGainをsliderGainに関連付けする 5. sliderGainのサイズと配置座標を決める 6. getNextAudioBlock関数内で、オーディオ バッファに対して、sliderGainの値を用いて バッファにゲイン量を適用する
  49. GUIプログラミング - コントローラ ・MainComponent.h - MainComponentクラスにjuce::Sliderを保持するメンバ変数を追加する class MainComponent : public juce::AudioAppComponent { ~省略~ private: // juce::Sliderクラスのポインタ変数 std::unique_ptr<juce::Slider> sliderGain; // juce::Labelクラスのポインタ変数 std::unique_ptr<juce::Label> labelGain; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent) };
  50. GUIプログラミング - コントローラ ・MainComponent.cpp - コンストラクタでsliderGainのインスタンス生成と各種設定を行う // コンストラクタの初期化指定子でjuce::Sliderのインスタンスを生成する MainComponent::MainComponent() : sliderGain(std::make_unique<juce::Slider>(juce::Slider::RotaryHorizontalVerticalDrag, juce::Slider::TextBoxBelow)) , labelGain(std::make_unique<juce::Label>("Gain", "GAIN")) { // ラベルコンポーネントをスライダーに関連付ける labelGain->attachToComponent(sliderGain.get(), false); labelGain->setJustificationType(juce::Justification::centred); // スライダーの値の範囲を0.0 ~ 1.0に設定する sliderGain->setRange(0.0, 1.0); // sliderGainをMainComponentのChildに追加する addAndMakeVisible(sliderGain.get()); ~省略~ }
  51. GUIプログラミング - コントローラ ・MainComponent.cpp - resized関数にコンポーネントのサイズ指定と配置座標の指定を実装する void MainComponent::resized() { // MainComponentの中心座標を取得する const auto panelCenter = getBounds().getCentre(); // gainSliderのサイズを幅200px, 高さ200pxにする sliderGain->setSize(200, 200); // gainSliderの中心座標をMainComponentの中心座標に移動する sliderGain->setCentrePosition(panelCenter); }
  52. GUIプログラミング - コントローラ ・MainComponent.cpp - getNextAudioBlock関数にバッファ全体のゲイン変更処理を実装する void MainComponent::getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) { bufferToFill.clearActiveBufferRegion(); auto* buffer = bufferToFill.buffer; for (int channel = 0; channel < buffer->getNumChannels(); ++channel) { ~省略~ } // バッファ全体のサンプルにゲイン量を適用する(乗算処理) const float gain = sliderGain->getValue(); bufferToFill.buffer->applyGain(gain); }
  53. GUIプログラミング - ビジュアライザ 1. オーディオサンプルデータを貯めておくメン バ変数を追加する 2. MainComponent::paint関数に、サンプル データからPathを生成して描画する処理を 追加する 3. MainComponentクラスにjuce::Timerクラス を継承させる 4. juce::Timer::TimerCallback関数をoverride して関数内でpaint関数のトリガーを実装す る 5. juce::Timerクラスのタイマーを開始する関数 を呼ぶ ※時間の都合上、簡易的な設計となっています。よりよい設 計は完成版のコードをご確認ください。
  54. GUIプログラミング - ビジュアライザ ・MainComponent.h - MainComponentクラスにオーディオバッファを保持するメンバ変数を追加する class MainComponent : public juce::AudioAppComponent { ~省略~ private: // juce::AudioBufferはfloat配列を保持するオブジェクトとして有効に利用できる juce::AudioBuffer<float> drawBuffer; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent) };
  55. GUIプログラミング - ビジュアライザ ・MainComponent.cpp - getNextAudioBlock関数内でサンプルデータをメンバ変数にコピーする void MainComponent::getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) { bufferToFill.clearActiveBufferRegion(); auto* buffer = bufferToFill.buffer; for (int channel = 0; channel < buffer->getNumChannels(); ++channel) { ~省略~ } const float gain = 0.5f; buffer->applyGain(gain); // オーディオバッファ内のサンプルデータをメンバ変数にコピーする drawBuffer.makeCopyOf(*bufferToFill.buffer); }
  56. GUIプログラミング - ビジュアライザ ・MainComponent.cpp - サンプルデータから波形パスを生成してパスを描画する関数を追加する void drawWaveShape(juce::Graphics& g, const juce::Rectangle<float>& drawArea, const float* plotData, const int numSamples) { juce::Path wavePath; const float x0 = drawArea.getX(); const float cloped_sample0 = juce::jmax<float>(-1.0f, juce::jmin<float>(1.0f, plotData[0])); const float y0 = juce::jmap<float>(cloped_sample0, -1.0f, 1.0f, drawArea.getBottom(), drawArea.getY()); wavePath.startNewSubPath(x0, y0); for (int i = 1; i < numSamples; ++i) { const float x = juce::jmap<float>(i, 0, numSamples, x0, x0 + drawArea.getWidth()); const float cloped_sample = juce::jmax<float>(-1.0f, juce::jmin<float>(1.0f, plotData[i])); const float y = juce::jmap<float>(cloped_sample, -1.0f, 1.0f, drawArea.getBottom(), drawArea.getY()); wavePath.lineTo(x, y); } g.setColour(juce::Colours::cyan); g.strokePath(wavePath, juce::PathStrokeType(2.0f)); }
  57. GUIプログラミング - ビジュアライザ ・MainComponent.cpp - paint関数からdrawWaveShape関数を呼んで波形パスを描画する void MainComponent::paint (juce::Graphics& g) { g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); const auto bounds = getLocalBounds(); // Draw wave shape background const juce::Rectangle<float> drawArea = { bounds.getWidth() * 0.1f, bounds.getHeight() * 0.75f, bounds.getWidth() * 0.8f, bounds.getHeight() * 0.2f }; g.setColour(juce::Colours::darkgrey); g.fillRect(drawArea); // Draw wave shape drawWaveShape(g, drawArea, drawBuffer.getReadPointer(0), drawBuffer.getNumSamples()); }
  58. GUIプログラミング - ビジュアライザ ・MainComponent.h - juce::Timerクラスを継承して仮想関数を overrideする class MainComponent : public juce::AudioAppComponent, public juce::Timer { ~省略~ private: // juce::Timerで宣言されている仮想関数を overrideする virtual void timerCallback() override; // juce::AudioBufferはfloat配列を保持するオブジェクトとして有効に利用できる juce::AudioBuffer<float> drawBuffer; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent) };
  59. GUIプログラミング - ビジュアライザ ・MainComponent.cpp - timerCallback関数の実装とstartTimerHz関数の実行を追加する MainComponent::MainComponent() : sliderGain(std::make_unique<juce::Slider>(juce::Slider::RotaryHorizontalVerticalDrag, juce::Slider::TextBoxBelow)) { ~省略~ // juce::Timerクラス内のタイマーを起動する // 30Hz間隔でtimerCallback関数が呼ばれるようになる startTimerHz(30); } void MainComponent::timerCallback() { // MainComponent::paint関数を呼び出すためのトリガー repaint(); }
  60. 動作確認
  61. 完成版 以下の機能を追加 ・オシレータ(Square/Saw/Triangle/Noise) ・周波数を変更するスライダー ・オシレータを選択するコンボボックス ・操作パラメータを示すラベル UI ・オシロスコープのトリガ機能 ※ソースコード https://github.com/COx2/amcj009-juce-study/tree/main/HelloSineWave
  62. Building for mobile モバイルプラットフォームでも動きます
  63. FAQ
  64. オーディオバッファに音声を渡してるのに音が出ない 症状として、JUCEアプリケーションにおけるオーディオの出力先のデバイスが設定され ていない可能性があります。特に端末によってオーディオデバイスにバラツキがあるプ ラットフォームで発生しやすいです(Windows, Linux) 特にプロジェクトを新規作成したときなどは、オーディオデバイスの設定が存在しないせ いで、出力自体が無効化されているケースに遭遇することがあります 次の記事に、上記の対策としてJUCEアプリケーションでのオーディオデバイス設定パネ ルを表示するためのコードスニペットを示しています https://qiita.com/COx2/items/c9e87059d349aa8ff707
  65. オーディオバッファに音声を渡してるのに音が出ない ・MainComponent.cpp - オーディオデバイス設定パネルを表示するコードスニペット void showDeviceSetting() { AudioDeviceSelectorComponent selector(deviceManager, 0, 256, 0, 256, true, true, true, false); selector.setSize(400, 600); DialogWindow::LaunchOptions dialog; dialog.content.setNonOwned(&selector); dialog.dialogTitle = "Audio/MIDI Device Settings"; dialog.componentToCentreAround = this; dialog.dialogBackgroundColour = getLookAndFeel().findColour(ResizableWindow::backgroundColourId); dialog.escapeKeyTriggersCloseButton = true; dialog.useNativeTitleBar = false; dialog.resizable = false; dialog.useBottomRightCornerResizer = false; dialog.runModal(); } MainComponent::MainComponent() { showDeviceSetting(); }
  66. 日本語のテキストが文字化けする 次の記事に、JUCEで日本語表示をするためのコードスニペットを示しています https://qiita.com/COx2/items/c9e87059d349aa8ff707 MainComponent::MainComponent() { #if JUCE_WINDOWS String typeFaceName = "Meiryo UI"; Desktop::getInstance().getDefaultLookAndFeel().setDefaultSansSerifTypefaceName(typeFaceName); #elif JUCE_MAC String typeFaceName = "Arial Unicode MS"; Desktop::getInstance().getDefaultLookAndFeel().setDefaultSansSerifTypefaceName(typeFaceName); #elif JUCE_LINUX String typeFaceName = "IPAGothic"; Desktop::getInstance().getDefaultLookAndFeel().setDefaultSansSerifTypefaceName(typeFaceName); #endif }
  67. Q&A
  68. JUCEでオーディオプラグイン開発入門
  69. JUCEでオーディオプラグインを作る手順 1. [Projucer] 『Plug-In』テンプレートを選択する 2. [Projucer] 対象プラットフォーム設定、モジュール設定を行う 3. [Projucer] プログラムの基本となるソースコードが自動生成される 4. [IDE] ソースコードを編集する 5. [IDE] プロジェクトをビルドする アプリケーション開発と同様のワークフローで作成することが出来る
  70. 実演 Hello audio plugin
  71. Hello audio plugin ToneGenerator系オーディオプラグイン
  72. プロジェクト作成 Projucerのスタート画面で次の項目を設定 ・テンプレートの選択『 Plug-In - Basic』 ・プロジェクト名の設定 『HelloAudioPlugin』 ・対象プラットフォームにチェック
  73. プロジェクト作成 プログラムの基礎となるソースコードが自動生成さ れる PluginProcessor.h/cpp =プラグインインターフェースと音声処理を実装す る。Processorと呼ばれる PluginEditor.h/cpp =プラグインウインドウに表示する GUIを実装す る。Editorと呼ばれる
  74. プロジェクト作成 ・ProcessorとEditor VSTをはじめとするオーディオプラグインフォーマッ トでは、先に説明した ProcessorとEditorと呼ばれ る2つのコンポーネントを使用するアーキテクチャ であることが多いです Processorの実装は必須な一方で、プラグイン フォーマットによっては Editorの実装は任意な場合 があります
  75. プロジェクト作成 歯車アイコンをクリックするとプロジェクト設が表示 される 対象プラグインフォーマットにチェック - VST3 - AudioUnit - Standalone - Unity ※一部のプラグインフォーマットをビルドするには 別途SDKを用意する必要があります
  76. Processorの実装 プラグイン特有の実装として、プラグインパラメータ をProcessorに持たせる juce::AudioProcessorValueTreeStateクラス(通称 APVTS)を用いてプラグインパラメータを実装する のがモダンで安全 一つのAPVTSで複数のプラグインパラメータの状 態を管理することができる APVTSを用いると、GUIのコンポーネントとの連携 を短いコードで実装することができる 信号処理のコードは HelloSineWaveの実装をほぼ そのまま移植する ※プラグインパラメータ = プラグインインターフェー スを介してホスト⇔プラグイン間で Get/Setすること ができる状態管理用の変数
  77. Processorの実装 ・PluginProcessor.h - ProcessorクラスのメンバにAPVTS変数とその参照を取得する関数を追加する class HelloAudioPluginAudioProcessor : public juce::AudioProcessor { ~省略~ // EditorクラスからAPVTSを参照できるように関数を追加する juce::AudioProcessorValueTreeState& getProcessorState() { return apvts; } private: // juce::AudioProcessorValueTreeStateクラスの変数を追加する juce::AudioProcessorValueTreeState apvts; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent) };
  78. Processorの実装 ・PluginProcessor.cpp - Processorクラスのコンストラクタに APVTSの初期化処理を追加する // APVTSに持たせるプラグインパラメータのリストを返す関数を追加 juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout() { juce::AudioProcessorValueTreeState::ParameterLayout layout; layout.add(std::make_unique<juce::AudioParameterFloat> ("Gain", "Gain", juce::NormalisableRange<float>{ 0.0f, 1.0f, 0.01f }, 0.5f)); return layout; } // コンストラクタにAPVTSの初期化処理を追加 HelloAudioPluginAudioProcessor::HelloAudioPluginAudioProcessor() ~省略~ , apvts(*this, nullptr, "PARAMETERS", createParameterLayout()) { };
  79. Processorの実装 ・PluginProcessor.cpp - processBlock関数にオーディオバッファの操作処理を実装する void HelloAudioPluginAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) { ~省略~ for (int channel = 0; channel < buffer.getNumChannels(); ++channel) { float* channelData = buffer.getWritePointer(channel); for (int sample = 0; sample < buffer.getNumSamples(); ++sample) { const float phase = juce::MathConstants<float>::twoPi * sample / buffer.getNumSamples() * 2; channelData[sample] = sinf(phase); } } // パラメータの値をAPVTSのインターフェースから取得すると0.0~1.0の範囲にNormalizedされている // ここでは、パラメータが保持するjuce::RangeのconvertFrom0to1関数を用いてRangedな値に戻す const auto* gain_param = apvts.getParameter("Gain"); const float gain = gain_param->getNormalisableRange().convertFrom0to1(gain_param->getValue()); buffer.applyGain(gain); }
  80. Editorの実装 Processorで実装したAPVTS内のパラメータと juce::Slider(sliderGain)を連携するコードを追加 する juce::AudioProcessorValueTreeState::Slider Attachmentを利用すると、Sliderとプラグインパラ メータをバインドすることができ、 Sliderとパラメータ の値の同期処理を短いコードで実装することがで きる HelloSineWaveで実装したGUI関連のコードを Editorに移植する
  81. Editorの実装 ・PluginEditor.h - Editorのクラスにjuce::Sliderを保持するメンバ変数を追加する class HelloAudioPluginAudioProcessorEditor : public juce::AudioProcessorEditor { ~省略~ private: // Processorクラスの参照を保持する変数(自動生成) HelloAudioPluginAudioProcessor& audioProcessor; // juce::Sliderクラスのポインタ変数 std::unique_ptr<juce::Slider> sliderGain; // juce::Sliderとプラグインパラメータを自動的に連携してくれるオブジェクト juce::OwnedArray<juce::AudioProcessorValueTreeState::SliderAttachment> sliderAttachments; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HelloAudioPluginAudioProcessorEditor) };
  82. Editorの実装 ・PluginEditor.cpp - コンストラクタでsliderGainのインスタンス生成と各種設定を行う // コンストラクタの初期化指定子でjuce::Sliderのインスタンスを生成する HelloAudioPluginAudioProcessorEditor::HelloAudioPluginAudioProcessorEditor (HelloAudioPluginAudioProcessor& p) : AudioProcessorEditor (&p), audioProcessor (p) , sliderGain(std::make_unique<juce::Slider>(juce::Slider::RotaryHorizontalVerticalDrag, juce::Slider::TextBoxBelow)) { // APVTS内の”Gain”パラメータとsliderGainとをバインディングする sliderAttachments.add(std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment> (audioProcessor.getProcessorState(), "Gain", *sliderGain)); // sliderGainをこのComponentのChildに追加する addAndMakeVisible(sliderGain.get()); setSize (400, 300); }
  83. 動作確認
  84. オーディオプラグインの動作確認 プラグインのインストール先 ・macOS  ・AudioUnit   ・System     /Library/Audio/Plug-Ins/Components   ・User         ~/(UserName)/Library/Audio/Plug-Ins/Components  ・VST3   ・System     /Library/Audio/Plug-Ins/VST3   ・User     ~/(UserName)/Library/Audio/Plug-Ins/VST3
  85. オーディオプラグインの動作確認 プラグインのインストール先 ・macOS  ・VST   ・System     /Library/Audio/Plug-Ins/VST   ・User     ~/(UserName)/Library/Audio/Plug-Ins/VST ・Windows  ・VST3    C:Program FilesCommon FilesVST3  ・VST    任意の場所にインストール可能
  86. オーディオプラグインの動作確認 Juce Plug-in Host JUCEのプラグインホスト機構を利用した軽量なホ ストアプリケーション プラグインをノードとして扱い、ノードベースな入出 力接続を行うことができる 場所: JUCE/extras/AudioPluginHost
  87. オーディオプラグインの動作確認 Unity Native Audio Pluginのホスティングについて は次の記事にまとめています https://qiita.com/COx2/items/8d2c1441c6e9e00 910c6
  88. 完成版 HelloSineWave同様の機能を追加 ・パラメータを追加(Frequency/Oscillator) ・オシレータ(Square/Saw/Triangle/Noise) ・周波数を変更するスライダー ・オシレータを選択するコンボボックス ・操作パラメータを示すラベル UI ・オシロスコープのトリガ機能 ※ソースコード https://github.com/COx2/amcj009-juce-study/tree/main/HelloAudioPlugin
  89. FAQ
  90. 入力信号にEffectを適用して出力したい processBlock関数の引数にはミキサー上の入力信号が入っており、その値を取得して変更を適用することで出 力信号が変化する。例えば、サンプルデータの値を取得し、閾値の範囲内に収めるクリップ処理を行ったものを オーディオバッファに代入すると、簡易的なリミッターを実装することができる void LimiterAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) { ~省略~ for (int channel = 0; channel < buffer.getNumChannels(); ++channel) { float* channelData = buffer.getWritePointer(channel); for (int sample = 0; sample < buffer.getNumSamples(); ++sample) { if(channelData[sample] > 0.7f) channelData[sample] = 0.7f; else if(channelData[sample] < -0.7f) channelData[sample] = -0.7f; } } ~省略~ }
  91. EffectとInstrument プラグイン仕様によってはEffectとInstrumentの2種類の 属性がある e.g. VST Effect / VST Instrument Effectプラグイン = DAWのEffect Rackにインサートするもの Instrumentプラグイン = DAWのInstrument Rackにインサートするもの Projucerのプロジェクト設定内の[Plugin Characteristics]→[Plugin is a Synth]項目で選択 ・チェック有り = Instrument ・チェック無し = Effect
  92. MIDI入出力のサポート プラグイン仕様によってはMIDI入出力をサポートする。 特にシンセサイザー系のInstrumentプラグインではMIDI 入力のサポートはほぼ必須 Projucerのプロジェクト設定内の[Plugin Characteristics]で設定を選択 ・Plugin MIDI Input = MIDI入力をサポート ・Plugin MIDI Output = MIDI出力をサポート MIDI出力をサポートするプラグインをDAWにインサート すると、プラグインからのMIDI出力ポートをトラックの MIDI入力にルーティングすることができる※ ※DAWの実装に依存する
  93. パラメータ状態を保存/復帰したい ・PluginProcessor.cpp - 次の関数の実装を追加します。これらの関数はDAWがプロ ジェクトをSave/Loadするタイミングで呼ばれます void XxxAudioProcessor::getStateInformation() = パラメータ状態を外部ファイル(DAWプロジェクト)にセーブする関数 void XxxAudioProcessor::setStateInformation() = パラメータ状態を外部ファイル(DAWプロジェクト)からロードする関数
  94. プラグイン開発時の注意点 ・ProcessorからEditorのインスタンスに直接アクセスすることは避ける オーディオプラグインでは、Processorの寿命とEditorの寿命が異なる場合が多いです。具体 的には、Editorはウインドウが表示⇔非表示するびにインスタンスの生成⇔消去が内部で行 われています この点に注意して実装しないと、Editorのインスタンスが先に消失したにも関わらず ProcessorがEditorにアクセスしようとしてクラッシュを引き起こす原因になります ・プラグインがクラッシュするとDAW本体も道連れにされてクラッシュするので、自作プラグイ ンを使用して制作するときはこまめに保存するようにしましょう ※Bitwig Studioはサンドボックス方式を採用しているので DAWを道連れにしないらしい
  95. JUCEで広がるオーディオソフトウェア開発
  96. Tracktion Engine JUCEライブラリで構築された、 DAWの開発に特化 したフレームワーク Tracktion WAVEFORMのシーケンサーエンジンと して開発されたフレームワークがオープン化されて 利用できるようになった 無償/有償プランがある https://www.tracktion.com/develop/tracktion-engi ne https://github.com/Tracktion/tracktion_engine
  97. SOUL JUCEを開発したJulian Storerがリードする、音声 処理プログラムを作成することに特化したプログラ ミング言語 SOUL = SOUnd Language SOUL言語のランタイムライブラリをアプリケーショ ンに組み込むための JUCE用ライブラリが提供され ている https://github.com/soul-lang/SOUL https://soul.dev/
  98. Made with JUCE
  99. Ben Kuper / Chataigne メディアアーティスト向けに制作された、モジュラー ベースのインタラクティブ・システム開発ツール 通信プロトコルのサポート OSC, MIDI, DMX, HTTP, WebSockets, PJLink… ハードウェアのサポート KinectV2, StreamDeck, Gamepad, Wiimote… ソフトウェア外部コントロールのサポート Madmapper, Reaper, Resolume, Powerpoint... http://benjamin.kuperberg.fr/chataigne https://github.com/benkuper/Chataigne
  100. FigBug / slPlugins シンプルなUIと機能だけを持つ、無料配布のプラ グイン・スイート ToneGenerator, Oscilloscope, ABTestなど、プラ グイン開発時のテストツールとして重宝 プロジェクトの規模も小さいので JUCEの学習用途 にも向いている 同じ開発者のGinという3rd party JUCEモジュール にも便利な機能が沢山 https://socalabs.com/ https://github.com/FigBug/slPlugins
  101. ffAudio / PluginGuiMagic JUCE GUIコンポーネントにリッチ UIとライブ編集 機能を提供するJUCE用ライブラリ オーディオプロセッサのパラメータからデフォルトの GUIを自動生成 CSSライクな構造でスタイル化 ドラッグ&ドロップによるレイアウト操作 FFTアナライザーやオシロスコープなど、すぐに使 えるビジュアライザー https://github.com/ffAudio/PluginGuiMagic
  102. Dreamtonics / Web Synthesizer V JUCE製プログラムをWASMで実行できるようにす るプロジェクト Emscriptenの対応と、Native層にWebプラット フォームのAPI(OpenAL, Web MIDI等)を組み込む ことで、Webブラウザ上でもJUCE製アプリケーショ ンを動かすことを実現した https://synthesizerv.com/web https://github.com/Dreamtonics/juce_emscripten https://github.com/beschulz/juce_emscripten
  103. まだまだあります hotwatermorning / wahwth https://github.com/hotwatermorning/wahwth yokemura / Magical8bitPlug2 https://github.com/yokemura/Magical8bitPlug2 m-masaki72 / SANA_8BIT_VST https://github.com/m-masaki72/SANA_8BIT_VS T chikashimiyama / trevor https://github.com/chikashimiyama/trevor GuitarML / SmartGuitarPedal https://github.com/GuitarML/SmartGuitarPedal balandinodidonato /MyoMapper https://github.com/balandinodidonato/MyoMapp er jatinchowdhury18 / KlonCentaur https://github.com/jatinchowdhury18/KlonCentau r AustrianAudio / PolarDesigner https://github.com/AustrianAudio/PolarDesigner
  104. Audio Developer Conferenceへのお誘い
  105. Audio Developer Conference https://audio.dev/ 通称ADC 音楽アプリケーションに興味のある世界各地の開発者がロンドンに集まる DAW、プラグイン、フレームワーク、プラットフォームの開発者が対象 他のイベントとの違い… ・NAMM - 楽器の展示が中心 ・GDC - ゲーム全般 オーディオに関連する話題もある 歴史的な経緯もあってJUCEの話題が多い印象
  106. Audio Developer Conference ADC is an annual event celebrating all audio development technologies, from music applications and game audio to audio processing and embedded systems. ADC’s mission is to help attendees acquire and develop new skills, and build a network that will support their career development. It is also aimed at showcasing academic research and facilitating collaborations between research and industry. - cited from https://audio.dev/
  107. ADCの歴史 2015年: JUCE Summit 2015 2016年: Audio Developer Conference 2016 2017年: Audio Developer Conference 2017 2018年: Audio Developer Conference 2018 2019年: Audio Developer Conference 2019 2020年: Audio Developer Conference 2020
  108. ADCで何が見られるの? ハンズオン セッション ライブパフォーマンス ブース展示 Drinkup, Open Mic Night (LT大会)
  109. ハンズオン JUCEオーディオプラグイン作成入門 ELKハードウェアシンセサイザー作成 信号処理 SOUL (SOUnd Language) 深層学習 + Speech Synthesis JUCE + ReactNative 1 on 1 セッション ・Appleオーディオオフィスアワー ・Androidスタジオセッション
  110. セッション ADC2018 ・SOUL ・AudioKit ・WebAudio (Europa, WAMs) ・C++ std::audio (draft) ・Speech Synthesis ・MPE ・Audio debugging ADC2019 ・MIDI 2.0 ・Deep Learning ・リアルタイムオーディオ処理 ・デザイン & プロトタイピング ・ゲームオーディオ ・JUCE + React Native
  111. ADC2019 - Live concert (using MI.MU) Reshaping live performance with MI.MU
  112. ADC2019 - JUCE x React Native x Unity Developing a rich, consumer experience for LUMI with JUCE, React Native & Unity
  113. ADC2019 - How to make a multi-track loop sequencer with JUCE Loopers and bloopers
  114. JUCE Youtubeチャンネル ADCのセッション動画がアーカイブされている https://www.youtube.com/channel/UCaF6fKdDrSmPDmi Zcl9KLnQ
  115. Audio Developer Conference 2020 ・オンライン開催 ・日時  11月19-20日 25:00〜31:00 JST ・セッション一覧  https://audio.dev/schedule ・チケット  オンライン販売  価格は例年の1/10 https://audio.dev/news/adc-tickets
  116. Opening keynoteはMax for Live開発にまつわる話
  117. JUCE関連のセッション
  118. Q&A
  119. 宣伝
  120. JUCE JAPAN シリーズ最新『JUCE JAPAN 2018』 ・JUCEハンズオン ・シンセサイザーの設計と実装 ・ワンショットサンプラーを作ろう ・VAシンセサイザーを作ろう Amazon Kindleにて販売中 https://www.amazon.co.jp/dp/B07HQHFKX9
  121. JUCEもくもく会 https://juce.connpass.com/ 不定期で開催 主な会場は都内コワーキングスペース 遠征開催を計画中
  122. JUCE Advent Calendar 2020 https://qiita.com/advent-calendar/2020/juce 絶賛参加者募集中!!!
  123. END
  124. TEMPLATE: Azusa 3 VERSION 3.0 CREATED AND MAINTAINED BY @SANOGRAPHIX JUCE は英国 Raw Material Software, Ltd.の登録商標です VST は独国 Steinberg Media Technologies GmbH の登録商標です Audio Units は米国Apple Computers Inc. の登録商標です Unity は米国およびその他の地域でのUnity Technologies またはその関連会社の商標または登録商標です
Advertisement