メインコンテンツまでスキップ

チュートリアルデシベルを使ってオーディオレベルをコントロールする

📚 Source Page

このチュートリアルでは、デシベルスケールを使ってオーディオの出力レベルを変更する方法を示します。これは、オーディオアプリケーションでオーディオレベルの値をユーザーに表示する、より一般的な方法です。

レベル:中級

プラットフォーム:Windows, macOS, Linux

クラス: Decibels,Slider,String

スタート

このチュートリアルのデモ・プロジェクトのダウンロードはこちらから:PIP|ZIP.プロジェクトを解凍し、最初のヘッダーファイルをProjucerで開く。

このステップにヘルプが必要な場合は、以下を参照してください。Tutorial: Projucer Part 1: Getting started with the Projucer.

注記

このチュートリアルはTutorial: Control audio levels.そのチュートリアルに従うべきだった。

デモ・プロジェクト

と似たようなものだ。Tutorial: Control audio levelsこのチュートリアルのデモ・プロジェクトでは、1つのスライダーを含むウィンドウを表示します。今回、スライダーの値はdecibels.この値はdecibelsオーディオ処理アルゴリズムで使用する前に、線形ゲイン値に変換する必要がある。ほとんどのオーディオアプリケーションは、ゲインをdecibelsこのようにフィーリング値が変化(または比較)するにつれて、より自然になります。デモ・プロジェクトのユーザー・インターフェースを以下のスクリーンショットに示す。

デシベル単位のコントロール・スライダーを表示したデモ・プロジェクトのメイン・ウィンドウ。
デシベル単位のコントロール・スライダーを表示したデモ・プロジェクトのメイン・ウィンドウ。

カスタマイズされたスライダーの作成

今回は、スライダーに隣接して表示されるテキストが、スライダー内の値を示すだけでなく、スライダー内の値を示していることに注目してください。decibelsと表示されますが、接尾辞 "dB "も表示されます。これはカスタム・スライダー・クラスを作ることで実現できます、DecibelSliderを継承している。Sliderクラスを作成しました。このカスタム・スライダー・クラスでは、テキストボックスのインターフェイスは、値をdecibels.の中に表示されるテキストの接尾辞はSliderオブジェクトのテキストボックスはSlider::setTextValueSuffix()関数を使うには、もうひとつカスタマイズが必要だ。これは、値が変換される方法をカスタマイズすることである。-INF dBレベルが非常に低くなったとき

注記

INFとはインフィニティここで-INF dBは、このアプリケーションの目的上、沈黙として扱われる。

デシベルズ級

についてDecibelsクラスの値の変換に必要な静的関数がいくつか含まれています。decibelsとリニアゲインがあります。の値を変換する簡単な手段も提供する。decibelsへのStringオブジェクトをオーバーライドする。例えば、仮想関数Slider::getTextFromValue()を使用する。Decibels::toString()関数の中でDecibelSliderクラス)のようなものだ:

    juce::String getTextFromValue (double value) override
{
return juce::Decibels::toString (value);
}

これによってDecibelSliderクラスを使用して、与えられたスライダー値に対して適切なテキストをテキストボックスに表示することができます。

についてDecibelsを変換する関数はありません。Stringオブジェクトをdecibelsそのため、独自のものを書く必要がある。ここではSlider::getValueFromText()仮想関数(これもDecibelSliderクラス):

    double getValueFromText (const juce::String& text) override
{
auto minusInfinitydB = -100.0;

auto decibelText = text.upToFirstOccurrenceOf ("dB", false, false).trim(); // [1]

return decibelText.equalsIgnoreCase ("-INF") ? minusInfinitydB
: decibelText.getDoubleValue(); // [2]
}

これは、ユーザーがテキストボックスに値を入力し、それがチェックされ、スライダーの有効な値に変換されることを可能にします。これを行うには

  • [1]もし "dB "という接尾辞があれば、それを取り除き、(もし "dB "という接尾辞がなければString::trim()関数)。
  • [2]残りのテキストが"-INF "であるかどうかをチェックし、その場合は-100を返す。decibelsを -INF dB に置き換えた。Decibelsクラスが使用するNotesこれについてはこのチュートリアルを参照)。そうでなければ、この残りのテキストをdouble値を返します。

スライダーの値を使う

の中でTutorial: Control audio levelsでスライダーの値に直接アクセスしている。getNextAudioBlock()関数に変換されます。からの変換はdecibelsリニアゲインへの変換には、CPUに負荷のかかる演算が含まれる可能性があるため、特にオーディオスレッドでは、あまり頻繁に変換を実行しない方が賢明でしょう。このチュートリアルのデモプロジェクトではfloatメンバーlevelでのMainContentComponentクラスを作成し、リスナーを使用してスライダーが変更されたときにこの値を更新します。

を初期化する。levelコンストラクタでメンバをゼロに変換し、これをdecibelsを使用している。Decibels::gainToDecibels()関数を使ってスライダーに初期位置を与えます。Slider::setValue()関数)のようなものだ:

    MainContentComponent()
{
        decibelSlider.setValue (juce::Decibels::gainToDecibels (level));
decibelLabel.setText ("Noise Level in dB", juce::dontSendNotification);

デシベルをリニアゲインに変換

のラムダ関数ではSlider::onValueChangeヘルパー・オブジェクトからdecibelsスライダーで使用されるスケールを、オーディオ処理に必要なリニアゲイン値に変更します:

        decibelSlider.onValueChange = [this] { level = juce::Decibels::decibelsToGain ((float) decibelSlider.getValue()); };

この関数は、最初にSlider::setValue()関数をコンストラクタで呼び出す。これはSlider::onValueChange値が変更されたときにヘルパーオブジェクトがlevelメンバーが正しく設定される。

エクササイズ
  • 追加LabelオブジェクトをMainContentComponentリニアゲインの値を表示するクラス。
  • 追加SliderオブジェクトをMainContentComponentクラスはリニアゲイン値を表示し、ユーザーはどちらかのスライダーを使ってノイズレベルを表示、指定することができます。どちらかのスライダを動かすと、両方のスライダが正しく更新されるはずです。(参照Tutorial: The Slider class異なる単位間の変換の簡単な例を参照)。

オーディオの処理

我々のMainContentComponent::getNextAudioBlock()オーディオを処理する:

    void getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) override
{
auto currentLevel = level;
auto levelScale = currentLevel * 2.0f;

for (auto channel = 0; channel < bufferToFill.buffer->getNumChannels(); ++channel)
{
auto* buffer = bufferToFill.buffer->getWritePointer (channel, bufferToFill.startSample);

for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
buffer[sample] = random.nextFloat() * levelScale - currentLevel;
}
}

とほぼ同じであることに注意。getNextAudioBlock()関数Tutorial: Control audio levels ただしの関数ローカルコピーを取るだけである。levelを計算する。levelScale以前と同様に

このアプローチの問題点

この方法の問題点のひとつはlevel変数は、オーディオスレッドの実行中(この場合、2回のgetNextAudioBlock).このような変更は、通常、耳に聞こえるパチパチ音などのオーディオ・アーティファクトを引き起こす。これを避けるために、実際のシンセサイザーではlevel値を滑らかに変化させます。これを達成するテクニックは他のチュートリアルで説明されています(Tutorial: Build a sine wave synthesiser).

もう一つの問題は、スレッドセーフに関するものだ。のようなメンバ変数への書き込みはlevelあるスレッド(GUIスレッド)で同じ値を別のスレッド(オーディオスレッド)から読み取ることは、スレッド同期が(クリティカルセクションを経由するかアトミックを使用して)行われない場合、C++では技術的に未定義の動作です。これらの問題はこのチュートリアルの範囲外であり、将来のチュートリアルで説明します。一般的なアーキテクチャー(x86、x86_64、ARM)では、1つのスレッドの読み書きは1つのスレッドで行われるからです。float読み取りと書き込みが混在することはなく、一般的に安全である。

さらに考えてみると、コードをさらに最適化したくなるかもしれない。levelScaleを呼び出すたびに計算する必要はない)。getNextAudioBlock()関数)。しかしそうすると、2つのメンバ変数は1つのアトミック操作として更新されなくなってしまいます。もちろん、これを回避する方法もありますが、このチュートリアルの範囲外です。

備考

このチュートリアルのデモ・プロジェクトで示されるコードでは、-100 dB 以下の値を -INF dB(つまりリニア・ゲイン値がゼロ)として扱うことを想定しています。この-100 dBという値はDecibelsクラスの計算をオーバーライドすることができる。これはDecibelsクラスで、どの値を-INF dBとして扱うかを指定します。例えば、-96 dB(およびそれ以下)を-INF dBとして使用する場合、スライダーの値をMainContentComponentコンストラクターでこれを行うことができる:

decibelSlider.setValue (juce::Decibels::gainToDecibels (level, -96.0f));

しかしもちろん、アプリケーションのすべての部分で-INF dBに同じ値を使うようにする必要がある。デモ・プロジェクトのコードには1つ問題があります。-100.0私たちのDecibelSlider::getValueFromText()関数を使用する。もしDecibelsクラスのデフォルト値が(何らかの理由で)変更されると、コードは壊れてしまう。残念ながら、このデフォルト値はDecibelsクラスには尋ねられない。Decibelsクラスのデフォルト値を指定する必要がある。その代わりに、独自のデフォルト値を指定し、これを全体を通して使用する必要がある。

エクササイズ

デモ・プロジェクトを修正して、-INFのデフォルト値を-96 dBに指定します。の両方を更新する必要があります。DecibelSliderクラスとMainContentComponentクラスである。

概要

このチュートリアルでは、次のことを紹介した:

  • についてDecibelsクラスである。
  • の間を行き来する。decibelsスケールとリニアゲイン。
  • の値を表示するカスタム・スライダーを作成する。decibels階段だ。

こちらも参照