AudioSampleBufferクラスを使ったオーディオのループ再生
このチュートリアルでは、AudioSampleBufferオブジェクトに格納されたオーディオを再生し、ループさせる方法を説明します。これは、録音されたオーディオデータを操作するサンプリングアプリケーションの基礎として役立ちます。
レベル:中級
プラットフォーム:Windows, macOS, Linux
クラス: AudioBuffer,AudioFormatReader,AudioAppComponent
スタート
このチュートリアルではTutorial: Build a white noise generatorそしてTutorial: Build an audio player.そうでなければ、まずこれらを見るべきだ。
このチュートリアルのデモ・プロジェクトのダウンロードはこちらから:PIP|ZIP.プロジェクトを解凍し、最初のヘッダーファイルをProjucerで開く。
このステップにヘルプが必要な場合は、以下を参照してください。Tutorial: Projucer Part 1: Getting started with the Projucer.
デモ・プロジェクト
このチュートリアルのデモプロジェクトでは、サウンドファイルを開き、ファイル全体をAudioSampleBufferオブジェクトを作成し、それをループ再生する。でTutorial: Build an audio playerを使ってサウンドファイルを再生した。AudioFormatReaderSourceオブジェクトに接続されたAudioTransportSourceオブジェクトでサウンドを再生します。を有効にすれば、この方法でループ再生が可能です。AudioFormatReaderSourceオブジェクトのループフラグAudioFormatReaderSource::setLooping()関数である。
このチュートリアルの議論に関連するコードはすべてMainContentComponent
クラスがある。
サンプルデータをメモリにロ ードする
サウンドファイルの再生には、組み込みのクラスを使った方が良い場合が多いでしょう。このチュートリアルでは、いくつかのテクニックを紹介します。サンプラーアプリケーションは、特にサウンドが比較的短い場合、このようにサウンドファイルのデータをメモリにロードするのが一般的です(詳しくはSamplerSoundクラスの例)。サウンドを合成するには、ウェーブテーブルをAudioSampleBufferオブジェクトを適切な速度でループさせ、必要な音高を作り出す。これはTutorial: Wavetable synthesis.
また、このチュートリアルでは、ファイルへのアクセスとオーディオ処理をオーディオスレッドで組み合わせるときに遭遇する可能性のある、マルチスレッドの問題をいくつか取り上げます。これらの問題のいくつかは、表面的には単純に見えますが、クラッシュやオーディオの不具合を避けるために、注意深く適用するテクニックが必要になることがよくあります。これらのテクニックについてはTutorial: Looping audio using the AudioSampleBuffer class (advanced).
なぜ長さに制限があるのですか?
デモ・プロジェクトでは、読み込めるサウンドファイルの長さを2秒未満に制限しています。この制限はかなり恣意的ですが、これには大まかに2つの理由があります:
- ファイル全体が非常に大きい場合、コンピューターが物理メモリーを使い果たしてしまうかもしれない。実際のアプリケーションでは、もちろん、もっと大きな制限を使うことができるだろう。サンプルレート44.1kHzの2秒間のステレオオーディオファイルをAudioSampleBufferオブジェクトは705,600バイトのメモリーしか占有しない。(注を参照)
- かなり短いファイルであっても、読み込みには些細な時間しかかからない。
ポイント1について:コンピュータが持っている物理メモリの量を超えると、仮想メモリ(つまりハードドライブなどの二次記憶装置)を使い始める可能性がある。これでは、そもそもデータをメモリにロードする意味がなくなってしまう! もちろん、メモリが不足すれば、デバイスによっては動作が失敗することもある。
2について:この例では、オーディオデータを直接ロードすることで、シンプルにしています。FileChooser::browseForFileToOpen()関数は、ユーザーが選択したファイルを返した。これはメッセージスレッドにすべての音声が読み込まれるまでブロックされます。AudioSampleBufferオブジェクトで行う必要があります。短いサウンドであっても、ユーザーインタフェースのレスポンスを可能な限り維持するために、バックグラウンドスレッドで行うべきです。長いサウンドの場合、遅延や無反応が非常に目立ちます。別の(バックグラウンド)スレッドを追加すると、この例の複雑さが増します。参照Tutorial: Looping audio using the AudioSampleBuffer class (advanced)この方法でバックグラウンド・スレッドにファイルをロードする方法の例を参照されたい。
シンプルにするために、デモ・プロジェクトでは長いファイルをロードしようとしてもエ ラーは報告されない。このようなエラー報告を追加することは、追加の練習としてあなたに残されています。
サウンドファイルの読み込み
ユーザーが**オープン...**ボタンをクリックすると、ファイル・セレクタが表示される。ファイル全体がAudioSampleBufferメンバーfileBuffer
私たちのMainContentComponent
クラスである。
void openButtonClicked()
{
shutdownAudio(); // [1]
chooser = std::make_unique ("Select a Wave file shorter than 2 seconds to play...",
juce::File{},
"*.wav");
auto chooserFlags = juce::FileBrowserComponent::openMode
| juce::FileBrowserComponent::canSelectFiles;
chooser->launchAsync (chooserFlags, [this] (const juce::FileChooser& fc)
{
auto file = fc.getResult();
if (file == juce::File{})
return;
std::unique_ptr reader (formatManager.createReaderFor (file)); // [2]
if (reader.get() != nullptr)
{
auto duration = (float) reader->lengthInSamples / reader->sampleRate; // [3]
if (duration < 2)
{
fileBuffer.setSize ((int) reader->numChannels, (int) reader->lengthInSamples); // [4]
reader->read (&fileBuffer, // [5]
0, // [5.1]
(int) reader->lengthInSamples, // [5.2]
0, // [5.3]
true, // [5.4]
true); // [5.5]
position = 0; // [6]
setAudioChannels (0, (int) reader->numChannels); // [7]
}
else
{
// handle the error that the file is 2 seconds or longer..
}
}
});
}
-
[1]オーディオシステムをシャットダウンしていることに注目してください。AudioAppComponentオブジェクトを生成する。これは、すでにほのめかしたマルチスレッドの問題を避けるためだ。オーディオシステムがシャットダウンされれば、私たちの
getNextAudioBlock()
関数はオーディオスレッドへのコール内にいる間は、まだButton::onClickラムダ関数(これは、このopenButtonClicked()
関数からメッセージスレッド). -
[2]ここではAudioFormatReaderオブジェクトを使用する。AudioFormatManagerオブジェクトに格納している。このオブジェクトを自分たちで管理する必要があ るため、std::unique_ptrオブジェクトに格納していることに注意してほしい。(つまりTutorial: Build an audio playerを渡す。AudioFormatReaderオブジェクトをAudioFormatReaderSourceオブジェクトを生成して管理してくれる)。この操作はリーダー・オブジェクトの生成に失敗するかもしれない。
reader
ポインタはnullptr
の値を次の行に書く。 -
[3]ここでは、ファイルの長さ(サンプル数)をサンプル・レートで割って、サウンド・ファイルの長さを計算します。これが2秒以下であることを次の行でチェックする。
-
[4]ここではAudioSampleBufferオブジェクトを呼び出す。AudioSampleBuffer::setSize()関数のチャンネル数と長さを使用します。AudioFormatReaderオブジェクトがある。