オーディオ出力音量調整の原理と調整方法を分析します。

簡単な説明

通常、音量調整はオーディオ パイプラインの 2 つの主要な段階、つまりデジタル ドメインとアナログ ドメインで行うことができます。システム設定で音量を調整するときは、通常、アナログ領域 (つまり、オーディオ デバイス) で調整します。この場合、すべてのオーディオ出力 (別のアプリケーションからのオーディオを含む) が影響を受けます。

特定のオーディオの音量のみを変更したい場合は、デジタル ドメインで調整できます。これは通常、オーディオ データがまだメモリ内にあり、オーディオ デバイスに送信される前です。
この段階では、音声データの振幅を調整することで音量を変更できます。このメソッドは、変更されたオーディオ ストリームにのみ影響し、他のオーディオやシステムの音量設定には影響しません。このプロセスは通常、オーディオ処理ソフトウェアまたはオーディオ プレーヤー ソフトウェアで実行されます。

一般に、システムや他のアプリケーションの音量に影響を与えることなく、特定のオーディオの音量のみを変更するようにオーディオ データを変更できます。

音量調整にはリサンプリングが必要ですか?

不確かな。ボリューム調整とリサンプリングは 2 つの別個のプロセスです。

音量調整は、オーディオ データの振幅を変更することによって実行される単純な数学的操作です。このプロセスでは、オーディオ サンプル レートを変更する必要はありません。言い換えれば、ボリュームの変更にはオーディオ信号のリサンプリングは含まれません。

ただし、リサンプリングはオーディオ信号をあるサンプリング レートから別のサンプリング レートに変換するプロセスです。これは通常、デバイスまたはオーディオ形式のサンプルレートを一致させる必要がある場合、またはある種の周波数分析を実行する必要がある場合に必要です。たとえば、オーディオ デバイスが 44.1kHz のサンプル レートのみをサポートしているにもかかわらず、オーディオ ファイルのサンプル レートが 48kHz である場合、デバイスで再生するにはオーディオ ファイルをリサンプリングする必要がある場合があります。このプロセスは、ボリュームの変化とは直接関係しません。

一般に、オーディオ出力のボリュームを調整する場合、リサンプリングは必要ありません。ただし、場合によっては、ボリュームの調整とリサンプルを同時に行う必要があり、2 つのプロセスを別々に実行できます。

デジタルドメイン

「デジタル ドメイン」という用語は、信号またはデータがデジタル形式で処理されるデジタル信号処理の環境または段階を指します。これは通常、信号またはデータがアナログ形式に変換され、スピーカーやヘッドフォンなどのハードウェア デバイスに供給される前の段階です。

オーディオ処理では、デジタル ドメインでの操作には以下が含まれますが、これらに限定されません。

  1. デジタル フィルター: デジタル フィルターを使用して、ノイズを除去したり、特定の周波数のオーディオ信号を強化したりするなど、信号の周波数応答を変更します。

  2. リサンプリング: 特定のデバイスまたはアプリケーションのニーズに合わせてオーディオ信号のサンプリング レートを変更すること。

  3. 音量調整: 音声データの振幅を変更することで音量を変更します。これによってオーディオのサンプル レートは変更されません。

  4. 圧縮とエンコード: オーディオ データをより小さいファイルに圧縮するか、保存や送信を容易にするために特定の形式にエンコードします。

これらの操作は、オーディオ デバイスが信号を再生する前にメモリ内で完了します。したがって、他のオーディオ ストリームやデバイスのグローバル設定に影響を与えることなく、各オーディオ ストリームに対して独立して実行できます。そのため、システムの音量設定や他のオーディオの音量に影響を与えることなく、デジタル ドメイン内の 1 つのオーディオの音量を変更できます。

音声データを調整する

オーディオ データの形式とサンプル タイプがわかっていれば、デコードされたオーディオ データに対して直接数学的演算を実行して音量を調整し、このデータをオーディオ出力デバイスに渡すことができます。

ここで注意する必要があるのは、操作ではオーディオ データのサンプリング タイプを考慮する必要があるということです。たとえば、オーディオ データが 16 ビット符号付き整数 ( int16_t) の場合、各サンプル値を単純に乗算または除算して音量を変更できます。ただし、オーディオ データが浮動小数点 (floatまたはdouble) の場合は、対応する浮動小数点演算を実行する必要があります。

さらに、マルチチャンネルオーディオの状況も考慮する必要があります。オーディオ データに複数のチャンネルがある場合 (ステレオや 5.1 サラウンドなど)、各チャンネルのサンプル値に対して同じ操作を実行する必要があります。

一般に、音声データを正しく扱える限り、FFmpeg ライブラリの他の機能に依存せずに、デコードされた音声データに対して直接操作を実行して音量を調整できます。ただし、この方法では音声データの形式と処理について十分に理解している必要があることに注意してください。

基本的な C++ の例を以下に示します。もちろん、前提条件は、デコードされたオーディオ データを取得することです。
オーディオ データ形式が 32 ビット浮動小数点数であると仮定すると、次のように C++ 関数を記述して、オーディオの音量を調整できます。

#include <vector>

// 音频样本数据类型假设为浮点数
typedef float SampleType;

// 调整音频音量的函数
// audioData: 音频数据,左右通道交错存储,例如: L1 R1 L2 R2 ...
// volumePercent: 音量的百分比,1.0 表示 100%
void adjustVolume(std::vector<SampleType>& audioData, float volumePercent) {
    
    
    // 遍历所有的音频样本
    for (size_t i = 0; i < audioData.size(); ++i) {
    
    
        // 将每个样本值乘以音量的百分比
        audioData[i] *= volumePercent;
    }
}

この関数は、オーディオ データを格納するベクトル (左チャンネルと右チャンネルのサンプルがインターリーブされて格納されていると仮定) とボリュームのパーセンテージ (1.0 は 100% を意味します) を取得し、ボリュームのパーセンテージを乗算して各オーディオ サンプルの値を調整します。

ボリュームのパーセンテージが 1.0 より大きい場合はボリュームが増加し、ボリュームのパーセンテージが 1.0 より小さい場合はボリュームが減少することに注意してください。音量パーセンテージが 0.0 の場合、オーディオはミュートされます。

この関数は、オーディオ データが 32 ビット浮動小数点数の形式であることを前提としているため、浮動小数点乗算を直接使用して音量を調整できます。オーディオ データの形式が異なる場合は、データ形式に合わせてこの関数を変更する必要がある場合があります。

ffmpegでデコードされた音声データの音量を調整する

オーディオデータの直接操作

FFmpeg ライブラリでは、デコードされたオーディオ サンプルを処理して音量を調整できます。

基本的な例を次に示します。

// 假设 frame 是你解码后的音频帧
AVFrame *frame;

// 解码器输出的数据类型为 int16,每个样本的最大值为 32767
// 想要将音量减半,你可以遍历所有的样本并将它们除以2
for (int i = 0; i < frame->nb_samples; ++i) {
    
    
    for (int ch = 0; ch < frame->channels; ++ch) {
    
    
        ((int16_t*)frame->data[ch])[i] /= 2;
    }
}

この例では、デコーダがint16_tサンプルあたり最大値 32767 (16 ビット符号付き整数の最大値) のデータ型を出力すると仮定します。音量を半分にするには、各オーディオ サンプルをループし、その値を 2 で割ります。

オーディオ データの特定の形式とサンプル タイプに応じてこのコードを変更する必要があることに注意してください。実際のアプリケーションでは、オーバーフロー処理、さまざまなサンプル タイプ、マルチチャンネル オーディオなど、より複雑な状況も考慮する必要がある場合があります。

さらに、この例ではすべてのサンプルを 2 で割って音量を半分にしていますが、他の数学的演算を使用して音量を変更することもできます。たとえば、係数を乗じて音量を調整したり、より複雑なアルゴリズムを使用してより洗練されたオーディオ効果を実現したりできます。

オーディオフィルター

実際、FFmpeg のオーディオ フィルターを使用して音量を調整することもできます。FFmpeg には「ボリューム」と呼ばれるオーディオ フィルタがあり、オーディオ フィルタ チェーン内の音量を調整できます。以下に例を示します。

AVFilterContext* vol_ctx;
AVFilterGraph* graph;
AVFilterInOut* inputs;
AVFilterInOut* outputs;

// 初始化滤镜图
graph = avfilter_graph_alloc();

// 创建 "volume" 滤镜并设置为减半音量
AVFilter* vol = avfilter_get_by_name("volume");
avfilter_graph_create_filter(&vol_ctx, vol, "volume", "0.5", NULL, graph);

// 将解码器的输出链接到 "volume" 滤镜
inputs = avfilter_inout_alloc();
inputs->filter_ctx = dec_ctx;  // 解码器的滤镜上下文
inputs->pad_idx = 0;
inputs->next = NULL;

// 将 "volume" 滤镜的输出链接到编码器
outputs = avfilter_inout_alloc();
outputs->filter_ctx = vol_ctx;  // "volume" 滤镜的上下文
outputs->pad_idx = 0;
outputs->next = NULL;

// 将输入和输出链接到滤镜图
avfilter_graph_parse_ptr(graph, "volume", &inputs, &outputs, NULL);

この例では、オーディオ フィルター グラフを作成し、それに「音量」フィルターを追加して、音量を半分にします。次に、デコーダの出力を「ボリューム」フィルタにリンクし、最後に「ボリューム」フィルタの出力をエンコーダにリンクします。

このようにして、FFmpeg のオーディオ フィルターを使用して音量を調整できます。FFmpeg のオーディオ フィルタは多くの事前定義されたオーディオ処理関数を提供し、フィルタ チェーン内で簡単に組み合わせることができるため、これは潜在的により便利で強力です。

シミュレーション領域

オーディオ処理では、アナログ ドメインは通常、サウンド信号がスピーカーやヘッドフォンなどの物理デバイスを駆動するために使用されるアナログ信号に変換される段階を指します。

コンピューターの内部ではデジタル信号が処理されており、デジタル信号は 0 と 1 からなる 2 値データであることがわかっています。しかし、私たちの耳に聞こえるのは、連続したアナログ音声信号です。したがって、コンピューターから出力された音声と私たちの耳の間には、デジタル信号をアナログ信号に変換するプロセスが必要になります。このプロセスは、DAC (Digital-to-Analog Converter) と呼ばれるデバイスによって実行されます。

DAC の後の段階は通常、アナログ ドメインと呼ばれます。この段階では、信号は 2 進数ではなく、連続的な電圧または電流です。この信号はオーディオ デバイス (スピーカーやヘッドフォンなど) で受信され、音声に変換されます。

オペレーティング システムの設定で音量を調整するときは、通常、アナログ領域の信号振幅を変更します。この方法の利点は、すべてのオーディオ出力の音量を変更するのが非常に簡単であることです。ただし、特定のオーディオ ストリームだけでなく、すべてのオーディオ出力に影響するという欠点もあります。

対照的に、デジタル領域で音量を変更する場合 (つまり、オーディオがまだコンピューターのメモリ内にあり、DAC によってアナログ信号にまだ変換されていない場合)、どのオーディオ ストリームの音量をより細かく制御できます。かわった。

アナログ領域では、オーディオ信号はアナログ電気信号になり、ソフトウェアで直接操作できなくなりました。この段階では、デバイス (オーディオ インターフェイスやスピーカーなど) のボリューム コントロールを調整することで音量を変更できます。

FFmpeg は、デジタル オーディオとビデオを処理するためのソフトウェア ライブラリです。これは、オーディオがまだデジタル領域にあるとき、つまりオーディオ信号がアナログ信号に変換される前に動作します。FFmpeg を使用すると、音声データのボリューム、リサンプル、コーデックなどを変更できます。

したがって、シミュレーション ドメインと FFmpeg ライブラリには 2 つの異なる段階が含まれます。FFmpeg は主にデジタル領域でオーディオおよびビデオ データを処理しますが、アナログ領域では主にハードウェア デバイスの操作によって音量が変更されます。

SDLライブラリでオーディオデバイスの音量を調整する

まず、SDL ライブラリを使用してオーディオ ストリームの音量を変更する方法を説明します。SDL では、SDL_MixAudioFormat関数を使用してオーディオの音量を調整できます。この関数の 4 番目のパラメータは音量です。音量の範囲は 0 (無音) から SDL_MIX_MAXVOLUME (最大音量) です。ボリュームをパーセンテージで表現する場合は、まずパーセンテージを SDL_MIX_MAXVOLUME の比率に変換します。

以下は、オーディオ バッファーとボリュームのパーセンテージを取得し、バッファーのボリュームを指定されたパーセンテージに調整する単純な関数です。

#include <SDL2/SDL.h>

void adjustVolume(Uint8 *buffer, int length, int volumePercent) {
    
    
    // Ensure volumePercent is between 0 and 100
    if(volumePercent < 0) volumePercent = 0;
    if(volumePercent > 100) volumePercent = 100;

    // Convert volumePercent to SDL volume range
    int volume = (volumePercent * SDL_MIX_MAXVOLUME) / 100;

    // Adjust the volume
    SDL_MixAudioFormat(buffer, buffer, AUDIO_S16LSB, length, volume);
}

この関数では、buffer調整する必要があるのはオーディオ データ、lengthデータの長さ、volumePercentおよび音量のパーセンテージです。まずそれが 0 ~ 100 の間であることを確認しvolumePercent、それから SDL ボリューム範囲に変換します。次に、SDL_MixAudioFormat関数を使用して音声データの音量を調整します。

この関数は、オーディオ データが 16 ビットの符号付き整数であり、リトル エンディアン形式 ( AUDIO_S16LSB) で保存されていることを前提としていることに注意してください。オーディオ データの形式が異なる場合は、それに応じてこの関数を変更する必要があります。

最後の注意点は、この機能は提供されたオーディオ データの音量を変更するだけであり、SDL オーディオ デバイスの全体の音量設定には影響しないということです。オーディオ デバイスの音量を変更する必要がある場合は、オペレーティング システムまたはハードウェア デバイスを介して行う必要があります。

Qtフレームワークでオーディオデバイスの音量を調整する

Qt では、QMediaPlayerクラスsetVolumeメソッドを使用してオーディオの音量を調整できます。このメソッドは、ボリュームのパーセンテージを表す 0 ~ 100 の範囲のパラメータを受け入れます。QMediaPlayer以下は、オブジェクトと音量パーセンテージを取得し、プレーヤーの音量を指定されたパーセンテージに調整する関数の例です。

#include <QMediaPlayer>

void adjustVolume(QMediaPlayer* player, int volumePercent) {
    
    
    // Ensure volumePercent is between 0 and 100
    if(volumePercent < 0) volumePercent = 0;
    if(volumePercent > 100) volumePercent = 100;

    // Adjust the volume
    player->setVolume(volumePercent);
}

この関数では、playerは音量を調整するオブジェクトでありQMediaPlayervolumePercent音量のパーセンテージです。volumePercentまず、0 ~ 100 の範囲にあることを確認してから、setVolumeプレーヤーの音量を調整するメソッドを使用します。

この機能は、提供されたオブジェクトの音量を変更しますQMediaPlayerが、QMediaPlayer他のオブジェクトの音量やシステム全体の音量設定には影響しません。

QMediaPlayerクラスは Qt のマルチメディア フレームワークの一部であるため、対応するモジュールをプロジェクトに追加する必要があることに注意してください。qmake を使用している場合は、次のコードを .pro ファイルに追加できます。

QT += multimedia

CMake を使用している場合は、次のコードを使用できます。

find_package(Qt6 COMPONENTS Multimedia REQUIRED)
target_link_libraries(your_project_name PRIVATE Qt6::Multimedia)

音声調整上限値

デジタル領域でもアナログ領域でも、音量コントロールには上限があります。デジタル領域では、通常、ボリュームは値の範囲として表されます。たとえば、SDL では、音量範囲は 0 (無音) から SDL_MIX_MAXVOLUME (最大音量) までです。この範囲を超える音量を設定しようとすると、通常はこの範囲に制限されます。

アナログ領域では、通常、音量の上限はハードウェア デバイスの物理的制限によって決まります。たとえば、スピーカーやヘッドフォンの音量は、最大出力レベルを超えることはできません。このレベルを超える音量を設定しようとすると、オーディオ デバイスが信号の振幅をカットしたり、極端な場合には歪みが発生したりする可能性があります。

また、デジタル領域とアナログ領域の間には DAC (デジタルアナログコンバータ) があることに注意してください。DAC には独自のダイナミック レンジもあり、この範囲外の信号は制限されたり、歪んだりする可能性があります。

一般にボリュームコントロールには上限があり、デジタル信号処理の範囲やDACのダイナミックレンジ、あるいはDACの物理的限界によって、この上限を超える部分が制限されたり歪んだりすることがあります。オーディオデバイス。

システムレベルの音量

SDL ライブラリと Qt ライブラリは、オーディオ データの処理および再生機能を提供しますが、オペレーティング システム レベルでオーディオ デバイスの音量を直接制御するものではありません。これらのライブラリはオーディオ データの音量を変更できますが、システムの音量設定やオーディオ デバイスの音量を直接変更することはできません。

システムの音量や特定のオーディオ デバイスの音量を変更する必要がある場合は、通常、オペレーティング システムが提供する API を使用するか、専用のライブラリを使用する必要があります。たとえば、Windows では Windows Core Audio API を使用する必要がある場合があり、Linux では ALSA または PulseAudio API を使用する必要がある場合があり、macOS では Core Audio API を使用する必要がある場合があります。

通常、これらの API を使用すると、オペレーティング システムのボリュームやオーディオ デバイスのボリュームを直接操作できますが、これらの API の操作にはシステム リソースの制御が含まれるため、特別な権限が必要になる場合があることにも注意してください。

システムレベルの音量制御は、デジタル領域とアナログ領域の両方で実行できます。これは、特定のシステムとハードウェアによって異なります。

デジタル ドメインでは、オペレーティング システムのオーディオ サービスを通じてシステム レベルの音量制御を実現できます。たとえば、Windows では、Windows Audio Session API (WASAPI) を通じて音量を制御できます。この場合、実際の音量調整はデジタル信号処理段階で行われ、デジタルオーディオデータの振幅が変化します。

このデジタル オーディオ データは、DAC (デジタル アナログ コンバーター) に送信され、アナログ信号に変換されます。アナログ領域では、音量を制御する方法もあります。たとえば、スピーカーやヘッドフォンなどの多くのオーディオ デバイスには、ハードウェアのボリューム コントロールが備わっています。この場合、音量制御はアナログ電気信号の強度を変化させることによって実現されます。

一般に、システム レベルのボリューム コントロールは、システムとハードウェアに応じて、デジタル ドメインとアナログ ドメインの両方で発生します。デジタル領域では、通常、オペレーティング システムのオーディオ サービスを通じて実装されます。アナログ領域では、通常、オーディオ デバイスのハードウェア ボリューム コントロールを操作することによって実現されます。

Windows でシステム音量を調整する

Windows システムでは、Windows Audio Session API (WASAPI) を通じてシステム レベルの音量を制御できます。以下は、C++ と WASAPI を使用してシステム音量を調整する方法を示す簡単な例です。

#include <Windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>

// Function to adjust system volume
void setSystemVolume(int volumePercent) {
    
    
    // Ensure volumePercent is between 0 and 100
    if (volumePercent < 0) volumePercent = 0;
    if (volumePercent > 100) volumePercent = 100;

    // Convert volumePercent to float scale (0.0 to 1.0)
    float volume = volumePercent / 100.0f;

    // Initialize COM
    CoInitialize(NULL);

    // Get default audio device
    IMMDeviceEnumerator *deviceEnumerator = NULL;
    CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);

    IMMDevice *defaultDevice = NULL;
    deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);

    // Get volume control
    IAudioEndpointVolume *endpointVolume = NULL;
    defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);

    // Set volume
    endpointVolume->SetMasterVolumeLevelScalar(volume, NULL);

    // Clean up
    endpointVolume->Release();
    defaultDevice->Release();
    deviceEnumerator->Release();
    CoUninitialize();
}

この関数では、まず値が 0 ~ 100 の範囲にあることを確認しvolumePercent、次にそれを 0.0 ~ 1.0 の浮動小数点の範囲に変換します。次に、WASAPI を使用してデフォルトのオーディオ デバイスを取得し、そのデバイスのボリューム コントロールを取得します。次に、IAudioEndpointVolume::SetMasterVolumeLevelScalar関数を使用して音量を設定します。最後に、すべての COM オブジェクトを解放し、COM の初期化を解除します。

このコードをコンパイルして実行するには、プロジェクトに Windows SDK を含めてリンクする必要があることに注意してくださいmmdevapi.lib

さらに、この機能はシステム全体の音量を変更し、すべてのオーディオ ストリームに影響を与えます。特定のオーディオ ストリームの音量のみを変更したい場合は、前に述べたように、デジタル ドメインでオーディオ データの振幅を変更するなど、別のアプローチを使用する必要があります。

Windows オーディオ セッション API (WASAPI) を通じて設定された音量はシステム全体の音量に影響するため、タスク バーの音量アイコンに表示される音量もそれに応じて変化します。

これは、WASAPI がシステム レベルの音量制御を操作し、オーディオ デバイスに出力されるすべてのオーディオ ストリームに影響を与えるためです。これには、すべてのアプリケーションとシステムサウンドが含まれます。したがって、WASAPI 経由でボリュームを変更すると、タスクバーのボリューム アイコンに変更が反映されます。

ただし、特定のアプリケーション内でオーディオ データの音量を変更した場合 (SDL または他のオーディオ ライブラリなどを使用して)、通常、この変更はタスクバーの音量アイコンに反映されないことに注意してください。これは、この方法では特定のオーディオ ストリームのみが変更され、システム レベルの音量設定には影響しないためです。

Linux でシステム音量を調整する

Linux システムでは、一般的に使用されるオーディオ デバイス制御プログラムは ALSA または PulseAudio です。以下は、ALSA を使用してシステム音量を調整する例です。これには、ALSA の開発ライブラリをインストールする必要があります (ほとんどの Linux ディストリビューションでは、パッケージ名は通常libasound2-devまたはですalsa-lib-devel)。

#include <alsa/asoundlib.h>
#include <math.h>

// Function to adjust system volume
void setSystemVolume(int volumePercent) {
    
    
    // Ensure volumePercent is between 0 and 100
    if (volumePercent < 0) volumePercent = 0;
    if (volumePercent > 100) volumePercent = 100;

    // Open mixer
    snd_mixer_t *handle;
    snd_mixer_open(&handle, 0);
    snd_mixer_attach(handle, "default");
    snd_mixer_selem_register(handle, NULL, NULL);
    snd_mixer_load(handle);

    // Get mixer element
    snd_mixer_selem_id_t *sid;
    snd_mixer_selem_id_alloca(&sid);
    snd_mixer_selem_id_set_index(sid, 0);
    snd_mixer_selem_id_set_name(sid, "Master");
    snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);

    // Convert volumePercent to ALSA volume range
    long minv, maxv;
    snd_mixer_selem_get_playback_volume_range(elem, &minv, &maxv);
    long volume = (volumePercent * (maxv - minv) / 100) + minv;

    // Set volume
    snd_mixer_selem_set_playback_volume_all(elem, volume);

    // Clean up
    snd_mixer_close(handle);
}

この関数では、まずそれが 0 ~ 100 の間であることを確認しvolumePercent、次に ALSA のミキサーを開いて「Master」という名前のミックス要素を取得します。次に、要素の体積範囲を取得し、volumePercentそれをこの範囲内の値に変換します。最後に、snd_mixer_selem_set_playback_volume_all関数を使用して音量を設定し、ミキサーをオフにします。

この機能はシステム全体の音量を変更し、すべてのオーディオ ストリームに影響を与えることに注意してください。特定のオーディオ ストリームの音量のみを変更したい場合は、デジタル ドメインでオーディオ データの振幅を変更するなど、別の方法を使用する必要があります。

さらに、この機能は、システムが ALSA を使用してオーディオ デバイスを管理し、「マスター」がマスター ボリュームを制御するミキシング要素であることを前提としています。これはシステムや構成によって異なる場合があります。システム構成に応じて、この機能を変更する必要がある場合があります。

おすすめ

転載: blog.csdn.net/qq_21438461/article/details/131044205