音频音量调节浅谈
音乐播放器一般通过调节扬声器的音量来改变音频的播放音量,如果在不调节扬声器的情况下,如何改变音频的播放音量呢?
一、音频的音量的控制参数
不改变输出设备的音量,那么就必须改变音频数据达到控制音量的目的。音频的音量大小由音频振幅决定,而音频振幅的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