共1个回答0条评论
分享
怎么能把不同声音大小的mp3音频统一成一个音量?
汇帮办公软件
排序方式:被封时间
时间排序由新到旧
- 23 个点赞 👍
如果不造轮,
单行命令
ffmpeg -i input.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11:dual_mono=false:print_format=summary -ar 48000 -ac 2 -b:a 192k -y pass1.mp3 && ffmpeg -i input.mp3 -af "loudnorm=I=-16:TP=-1.5:LRA=11:measured_I=-16:measured_LRA=11:measured_TP=-2:measured_thresh=-26:offset=0.0:linear=true:print_format=summary" -ar 48000 -ac 2 -b:a 192k -y output.mp3
ffmpeg -i input.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11:dual_mono=false:print_format=summary -ar 48000 -ac 2 -b:a 192k -y pass1.mp3 && ffmpeg -i input.mp3 -af "loudnorm=I=-16:TP=-1.5:LRA=11:measured_I=-16:measured_LRA=11:measured_TP=-2:measured_thresh=-26:offset=0.0:linear=true:print_format=summary" -ar 48000 -ac 2 -b:a 192k -y output.mp3自己造轮子?
C:\00OO>.\mp3_normalizer.exe .\_SAM-HU_HP8OUCE_.mp3 .\samhui_halfpd8ounce-20.mp3 -20
Samplerate=48000 Hz, Channels=2
Current RMS=-9.47 dBFS, Peak=0.00 dBFS
Target RMS=-20.00 dBFS, Applied gain=-10.53 dB (lin=0.297472)
Done.
C:\00OO>.\mp3_normalizer.exe .\_SAM-HU_HP8OUCE_.mp3 .\samhui_halfpd8ounce-20.mp3 -20 Samplerate=48000 Hz, Channels=2 Current RMS=-9.47 dBFS, Peak=0.00 dBFS Target RMS=-20.00 dBFS, Applied gain=-10.53 dB (lin=0.297472) Done.版权授权: WTFPL
// LICENSING:WTFPL // // mp3_normalizer.cpp // Usage: // mp3_normalizer.exe input.mp3 output.mp3 -18 // target RMS dBFS (default -18) // #include <mpg123.h> #include <lame/lame.h> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstdint> #include <vector> #include <string> #include <iostream> static void die(const char* msg) { std::fprintf(stderr, "Error: %s\n", msg); std::exit(1); } struct Stats { long samplerate = 0; int channels = 0; uint64_t samples = 0; // total samples across channels long double sumsq = 0.0L; // sum of squares of normalized samples [-1,1] long double peak = 0.0L; // max abs in [-1,1] }; static void configure_formats(mpg123_handle* mh) { mpg123_param(mh, MPG123_FORCE_RATE, 0, 0.0); // keep original mpg123_format_none(mh); const long* rates = nullptr; size_t count = 0; // <-- const mpg123_rates(&rates, &count); for (size_t i = 0; i < count; ++i) { mpg123_format(mh, rates[i], MPG123_MONO | MPG123_STEREO, MPG123_ENC_SIGNED_16); } } static void pass_stats(mpg123_handle* mh, Stats& st) { const size_t BUF_SAMPLES = 1152 * 16; std::vector<short> buf(BUF_SAMPLES * 2); size_t done = 0; int ret = MPG123_OK; bool got_fmt = false; while (true) { ret = mpg123_read(mh, reinterpret_cast<unsigned char*>(buf.data()), buf.size() * sizeof(short), &done); if (ret == MPG123_NEW_FORMAT) { long rate = 0; int ch = 0; int enc = 0; mpg123_getformat(mh, &rate, &ch, &enc); st.samplerate = rate; st.channels = ch; got_fmt = true; continue; } if (ret == MPG123_OK || (ret == MPG123_DONE && done > 0)) { if (!got_fmt) { long rate = 0; int ch = 0; int enc = 0; mpg123_getformat(mh, &rate, &ch, &enc); st.samplerate = rate; st.channels = ch; got_fmt = true; } size_t ns = done / sizeof(short); st.samples += ns; for (size_t i = 0; i < ns; ++i) { long double x = static_cast<long double>(buf[i]) / 32768.0L; st.sumsq += x * x; long double ax = fabsl(x); if (ax > st.peak) st.peak = ax; } if (ret == MPG123_DONE) break; continue; } if (ret == MPG123_DONE) break; die(mpg123_plain_strerror(mpg123_errcode(mh))); } if (st.samples == 0) die("empty or unreadable audio"); } static long double rms_dbfs(const Stats& st) { long double mean_sq = st.sumsq / (st.samples > 0 ? (long double)st.samples : 1.0L); long double rms = sqrtl(mean_sq); if (rms <= 0.0L) return -120.0L; return 20.0L * log10l(rms); } static void rewind_and_reconfig(mpg123_handle*& mh, const std::string& path) { mpg123_close(mh); if (mpg123_open(mh, path.c_str()) != MPG123_OK) die("mpg123 reopen failed"); configure_formats(mh); } static void pass_encode(mpg123_handle* mh, lame_t lame, FILE* fout, long double lin_gain, int expected_channels, long expected_rate) { const size_t BUF_SAMPLES = 1152 * 16; std::vector<short> inbuf(BUF_SAMPLES * 2); std::vector<short> work(inbuf.size()); std::vector<unsigned char> mp3buf(1 << 16); size_t done = 0; int ret = MPG123_OK; bool got_fmt = false; while (true) { ret = mpg123_read(mh, reinterpret_cast<unsigned char*>(inbuf.data()), inbuf.size() * sizeof(short), &done); if (ret == MPG123_NEW_FORMAT) { long rate = 0; int ch = 0; int enc = 0; mpg123_getformat(mh, &rate, &ch, &enc); got_fmt = true; if (rate != expected_rate || ch != expected_channels) { die("Input changed samplerate/channels mid-stream; not supported."); } continue; } if (ret == MPG123_OK || (ret == MPG123_DONE && done > 0)) { if (!got_fmt) { long rate = 0; int ch = 0; int enc = 0; mpg123_getformat(mh, &rate, &ch, &enc); if (rate != expected_rate || ch != expected_channels) { die("Unexpected samplerate/channels at start of pass_encode."); } got_fmt = true; } size_t ns = done / sizeof(short); for (size_t i = 0; i < ns; ++i) { long double x = (long double)inbuf[i] * lin_gain; if (x > 32767.0L) x = 32767.0L; if (x < -32768.0L) x = -32768.0L; work[i] = (short)llround(x); } int wrote = 0; if (expected_channels == 2) { wrote = lame_encode_buffer_interleaved( lame, work.data(), (int)(ns / 2), mp3buf.data(), (int)mp3buf.size()); } else { wrote = lame_encode_buffer( lame, work.data(), nullptr, (int)ns, mp3buf.data(), (int)mp3buf.size()); } if (wrote < 0) die("lame_encode_buffer failed"); if (wrote > 0) fwrite(mp3buf.data(), 1, wrote, fout); if (ret == MPG123_DONE) break; continue; } if (ret == MPG123_DONE) break; die(mpg123_plain_strerror(mpg123_errcode(mh))); } int wrote = lame_encode_flush(lame, mp3buf.data(), (int)mp3buf.size()); if (wrote < 0) die("lame_encode_flush failed"); if (wrote > 0) fwrite(mp3buf.data(), 1, wrote, fout); } int main(int argc, char** argv) { if (argc < 3 || argc > 4) { std::fprintf(stderr, "Usage: %s <in.mp3> <out.mp3> [target_rms_dbfs default=-18]\n", argv[0]); return 1; } std::string inpath = argv[1]; std::string outpath = argv[2]; double target_db = (argc == 4) ? std::atof(argv[3]) : -18.0; if (mpg123_init() != MPG123_OK) die("mpg123_init"); mpg123_handle* mh = mpg123_new(nullptr, nullptr); if (!mh) die("mpg123_new"); if (mpg123_open(mh, inpath.c_str()) != MPG123_OK) die("mpg123_open"); configure_formats(mh); Stats st; pass_stats(mh, st); long double cur_rms_db = rms_dbfs(st); long double cur_peak = st.peak; long double gain_db = (long double)target_db - cur_rms_db; long double lin_gain = powl(10.0L, gain_db / 20.0L); const long double max_peak = 0.99L; if (cur_peak > 0.0L) { long double max_lin = max_peak / cur_peak; if (lin_gain > max_lin) lin_gain = max_lin; } std::fprintf(stderr, "Samplerate=%ld Hz, Channels=%d\n", st.samplerate, st.channels); std::fprintf(stderr, "Current RMS=%.2Lf dBFS, Peak=%.2Lf dBFS\n", cur_rms_db, (cur_peak > 0 ? 20.0L * log10l(cur_peak) : -120.0L)); std::fprintf(stderr, "Target RMS=%.2f dBFS, Applied gain=%.2Lf dB (lin=%.6Lf)\n", target_db, 20.0L * log10l(lin_gain), lin_gain); rewind_and_reconfig(mh, inpath); lame_t lame = lame_init(); if (!lame) die("lame_init failed"); lame_set_in_samplerate(lame, (int)st.samplerate); lame_set_num_channels(lame, st.channels); lame_set_quality(lame, 2); lame_set_brate(lame, 192); lame_set_mode(lame, st.channels == 1 ? MONO : JOINT_STEREO); if (lame_init_params(lame) < 0) die("lame_init_params failed"); FILE* fout = std::fopen(outpath.c_str(), "wb"); if (!fout) die("cannot open output"); pass_encode(mh, lame, fout, lin_gain, st.channels, st.samplerate); std::fclose(fout); lame_close(lame); mpg123_close(mh); mpg123_delete(mh); mpg123_exit(); std::fprintf(stderr, "Done.\n"); return 0; }还没有人送礼物,鼓励一下作者吧查看全文>>
麦文学


