システム情報を表示するオーディオプラグインをJUCEで作ってみた

本記事は[JUCE Advent Calendar 2020](https://qiita.com/advent-calendar/2020/juce) の12月25日向けに投稿した記事です。

# JUCEって何？

JUCE (Jules' Utility Class Extensions)は、C++言語によるマルチメディア系アプリケーションの開発を支援するフレームワークです。クロスプラットフォーム設計のライブラリと、付属されているプロジェクトジェネレータ『Projucer』から各種IDE(VisualStudio, Xcode, Makefile)向けにプロジェクトファイルを出力することで、ワンソースからWindows, macOS, Linux, iOS, Android で動作するアプリケーションを作成することができます。
[公式サイト](https://juce.com/)

## JUCEの特徴は？

JUCEの最大の特徴として、オーディオプラグインを開発するためのテンプレートが充実していることが挙げられます。VST/AudioUnit/AAX/RTASプラグインといった、DTMユーザーにはお馴染みのプラグインフォーマットを開発するのに長けており、日本国内外で多くの採用事例があります。
[公式サイトによる採用事例の紹介](https://juce.com/made-with-juce)

<img width="694" alt="スクリーンショット 2017-11-26 15.08.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/93566/6c8bdc2f-10f4-2153-31de-5eec7181ebff.png">

# クロスプラットフォーム開発あるある
フレームワークやライブラリから提供される抽象化されたAPIを利用するだけでアプリケーション開発が完結するならそれに越したことは無いのですが、フレームワークやライブラリではカバーされていない範囲でのファイルIOやウインドウ操作などを記述するにあたり、OSやハードウェア特有のAPI呼び出しなどを記述する場合が往々にして発生します。
その際に、『現在の実行環境を取得する』APIがあると便利だと思います。


# COx2/SystemInfoPlugin
https://github.com/COx2/SystemInfoPlugin
`juce::SystemStats`および`juce::File`APIから取得する値をUI上に表示するVSTプラグインです。
表示されているテキストをクリップボードにコピーする機能も付けています。
以降ではこのプロジェクトで利用しているJUCE APIについて解説します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93566/47d70737-4dce-4b41-34c1-c0a161294165.png)


# `juce::SystemStats`

`juce::SystemStats`クラスを利用すると、実行環境のOSやハードウェア構成などの情報を抽象化されたAPIから取得することができます。
これらの情報は、プラットフォーム特有に発生する不具合の特定や、機能実装に有効に利用することができます。

```
// OSの名前（Windows 10, macOSX, ...etc)
SystemStats::getOperatingSystemName();

// ログオンしているユーザー名
SystemStats::getLogonName();

// コンピュータの地域設定
SystemStats::getUserRegion();

// コンピュータの言語設定
SystemStats::getUserLanguage();

// コンピュータの表示言語設定
SystemStats::getDisplayLanguage()
```

# `juce::File::SpecialLocationType`

`juce::File`クラスにある`juce::File::SpecialLocationType`の値を利用することで、抽象化されたAPIから、プラットフォーム固有のフォルダ・ディレクトリへの絶対パスを取得することができます。

例えば、Userドキュメンタリのフォルダまでのパスを取得するAPIは、プラットフォームに問わず、次のAPIに集約されています。

```
// 各プラットフォームにおけるユーザーのドキュメントディレクトリへのパスが取得できる
// Windows: C:\Users\(ユーザー名)\Documents
// macOS: /Users/(ユーザー名)/Documents
juce::File::getSpecialLocation(File::userDocumentsDirectory).getFullPathName()
```

その他にも、現在の実行プログラムやDLL自身についてのパスを取得することができるAPIも用意されており、例えば、DAWでロードするVSTプラグイン上でこのAPIを呼び出すと、それぞれ次の値が返ってきます

```
// VSTホスト（DAW）の実行ファイルまでのパス
juce::File::getCurrentWorkingDirectory().getFullPathName()

// VSTプラグインのバイナリファイルまでのパス
juce::File::getSpecialLocation(File::currentApplicationFile).getFullPathName()
juce::File::getSpecialLocation(File::currentExecutableFile).getFullPathName()
juce::File::getSpecialLocation(File::invokedExecutableFile).getFullPathName()
```

## macOSのAppSandbox機構がもたらす影響

macOSのメジャーなDAWとしてLogic ProとGarageBandがありますが、Logic Proは非AppSandbox環境なのに対して、GarageBandはAppSandbox環境のアプリケーションとなっています。このことは、次に示す通り、`juce::File::getSpecialLocation`APIの結果に影響を与えます

### Logic Pro(非AppSandbox環境）
```
Current working directory:  /
Current application file:   /Users/(ユーザー名)/Library/Audio/Plug-Ins/Components/SystemInfoPlugin.component
Current executable file:    /Users/(ユーザー名)/Library/Audio/Plug-Ins/Components/SystemInfoPlugin.component/Contents/MacOS/SystemInfoPlugin
Invoked executable file:    /Users/(ユーザー名)/Library/Audio/Plug-Ins/Components/SystemInfoPlugin.component/Contents/MacOS/SystemInfoPlugin

User home folder:               /Users/(ユーザー名)
User desktop folder:            /Users/(ユーザー名)/Desktop
User documents folder:          /Users/(ユーザー名)/Documents
User application data folder:   /Users/(ユーザー名)/Library
User music folder:              /Users/(ユーザー名)/Music
User movies folder:             /Users/(ユーザー名)/Movies
User pictures folder:           /Users/(ユーザー名)/Pictures
Common application data folder: /Library
Common documents folder:        /Users/Shared
Local temp folder:              /Users/(ユーザー名)/Library/Caches/SystemInfoPlugin
```

### GarageBand(AppSandbox環境）
```
Current working directory:  /Users/(ユーザー名)/Library/Containers/com.apple.garageband10/Data
Current application file:   /Users/(ユーザー名)/Library/Audio/Plug-Ins/Components/SystemInfoPlugin.component
Current executable file:    /Users/(ユーザー名)/Library/Audio/Plug-Ins/Components/SystemInfoPlugin.component/Contents/MacOS/SystemInfoPlugin
Invoked executable file:    /Users/(ユーザー名)/Library/Audio/Plug-Ins/Components/SystemInfoPlugin.component/Contents/MacOS/SystemInfoPlugin

User home folder:               /Users/(ユーザー名)/Library/Containers/com.apple.garageband10/Data
User desktop folder:            /Users/(ユーザー名)/Library/Containers/com.apple.garageband10/Data/Desktop
User documents folder:          /Users/(ユーザー名)/Library/Containers/com.apple.garageband10/Data/Documents
User application data folder:   /Users/(ユーザー名)/Library/Containers/com.apple.garageband10/Data/Library
User music folder:              /Users/(ユーザー名)/Library/Containers/com.apple.garageband10/Data/Music
User movies folder:             /Users/(ユーザー名)/Library/Containers/com.apple.garageband10/Data/Movies
User pictures folder:           /Users/(ユーザー名)/Library/Containers/com.apple.garageband10/Data/Pictures
Common application data folder: /Library
Common documents folder:        /Users/Shared
Local temp folder:              /Users/(ユーザー名)/Library/Containers/com.apple.garageband10/Data/Library/Caches/SystemInfoPlugin
```