首页/怎么能把不同声音大小的mp3音频统一成一个音量?/
共1个回答0条评论

怎么能把不同声音大小的mp3音频统一成一个音量?

汇帮办公软件
排序方式:被封时间
时间排序由新到旧
  • 23 个点赞 👍

    如果不造轮,

    直接用 FFmpegEBU R128(双遍校准):

    单行命令

    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;
    }

    查看全文>>

    麦文学

1

  • 1
  • 跳至
Copyright © 2022 GreatFire.org