音频音量调节浅谈

  音乐播放器一般通过调节扬声器的音量来改变音频的播放音量,如果在不调节扬声器的情况下,如何改变音频的播放音量呢?

一、音频的音量的控制参数

  不改变输出设备的音量,那么就必须改变音频数据达到控制音量的目的。音频的音量大小由音频振幅决定,而音频振幅的PCM音频格式中的名称为:位深,即:8bits,16bits等。

二、编码实现

 1 #include <iostream>
 2 #include <fstream>
 3 #include <cassert>
 4 #include <algorithm>
 5 #include <numbers>
 6 #include <type_traits>
 7 
 8 namespace pcm {
 9 
10     namespace amplitude {
11 
12         template <typename BitDeepth, 
13                         typename = std::enable_if_t<std::same_as<T, int8_t> || 
14                std::same_as<T, uint8_t> ||
15                std::same_as<T, int16_t> ||
16                std::same_as<T, uint16_t> ||
17                std::same_as<T, int32_t> ||
18                std::same_as<T, uint32_t>>>
19         void Adjust(const std::string& pcmFile, int channels, float gain)
20         {
21             using namespace std;
22             constexpr auto kMax = numeric_limits::max();
23             constexpr auto kMin = numeric_limits::min();
24 
25             ifstream inputStream(pcmFile, ios::binary);
26             assert(inputStream.is_open() && "not open pcm file!!!");
27             auto originBuf = inputStream.rdbuf();
28             ofstream outputStream("./adjust.pcm", ios::binary);
29             assert(outputStream.is_open() && "not open pcm file!!!");
30 
31             auto sampleSize = channels * sizeof(BitDeepth);
32             auto buf = std::make_unique<BitDeepth[]>(channels);
33 
34             while (true) {
35 
36                 std::memset(buf.get(), 0x00, sampleSize);
37                 auto readSize = originBuf->sgetn(reinterpret_cast<char*>(buf.get()), sampleSize);
38                 if (readSize == 0) break;
39                 if (readSize != sampleSize) continue;
40                 for (auto channel = 0; channel < channels; ++channel) {
41                     auto& originPcmVol = buf[channel];
42                     auto gainPcmVol = static_cast(originPcmVol * gain);
43                     if (gainPcmVol > kMax) gainPcmVol = kMax;
44                     if (gainPcmVol < kMin) gainPcmVol = kMin;
45                     auto size = sizeof(BitDeepth);
46                     std::memcpy(&originPcmVol, &gainPcmVol, size);
47                 }
48                 outputStream.write(reinterpret_cast<char*>(buf.get()), sampleSize);
49                 outputStream.flush();
50             }
51         }
52 
53     }
54 }
55 
56 int main()
57 {
58     // PCM 格式存储方式(一个采样)
59     // 1通道 8bit
60     // --------
61     // | 8bit |
62     // --------
63 
64     // 2通道 8bit
65     // ---------------
66     // | 8bit | 8bit |
67     // ---------------
68 
69     // 1通道 16bit
70     // ---------
71     // | 16bit |
72     // ---------
73 
74     // 2通道 16bit
75     // -----------------
76     // | 16bit | 16bit |
77     // -----------------
78     constexpr auto kPcmFile = R"(.\test_16_1.pcm)";
79     pcm::amplitude::Adjust<int16_t>(kPcmFile, 1, 0.01f);
80 
81     system("pause");
82     return 0;
83 }    

 

三、测试样例

  下载地址:https://files.cnblogs.com/files/smartNeo/sample.zip

  或者使用ffmpeg 工具转换想要的pcm样例。ffmpeg : mp3 -> pcm命令:ffmpeg.exe -i file.mp3 -f s16le -ar 44100 -ac 2  -acodec pcm_s16le test_16_2.pcm

 

参考:

  • https://blog.jianchihu.net/pcm-volume-control.html
  • http://blog.jianchihu.net/pcm-vol-control-advance.html
  • https://docs.microsoft.com/en-us/windows/win32/coreaudio/audio-tapered-volume-controls

 

posted @ 2021-12-02 14:37  blackstar666  阅读(725)  评论(0编辑  收藏  举报