You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++从NDI FLTP音频流获取音频电平与EQ数据?

从NDI音频流提取音频电平与EQ数据的C++实现方案

先明确NDI音频帧的核心格式

从你给出的NDIlib_audio_frame_v3_t结构体默认构造函数可知,NDI默认输出32位浮点平面格式(NDIlib_FourCC_audio_type_FLTP):

  • 每个采样是4字节的float,取值范围[-1.0, 1.0]
  • 平面格式:每个声道的采样数据连续存放,比如双声道先存完左声道所有采样,再存右声道,通过channel_stride_in_bytes定位每个声道的起始地址

一、提取音频电平(峰值/RMS)

音频电平分为峰值(瞬时最大音量)和RMS(均方根,反映感知音量),直接通过时域采样计算即可:

1. 解析FLTP格式的采样数据

// 假设已获取到NDI音频帧NDIlib_audio_frame_v3_t& frame
if (frame.FourCC == NDIlib_FourCC_audio_type_FLTP) {
    for (int ch = 0; ch < frame.no_channels; ch++) {
        // 定位当前声道的采样起始地址
        float* channel_samples = reinterpret_cast<float*>(frame.p_data + ch * frame.channel_stride_in_bytes);
        // 遍历该声道的所有采样进行处理
        for (int i = 0; i < frame.no_samples; i++) {
            float sample = channel_samples[i];
            // 后续计算用
        }
    }
}

2. 计算电平值

#include <cmath>
#include <algorithm>

// 计算单声道的峰值和RMS电平
void calculate_channel_levels(float* samples, int num_samples, float& peak, float& rms) {
    peak = 0.0f;
    float sum_squares = 0.0f;
    for (int i = 0; i < num_samples; i++) {
        float abs_sample = fabsf(samples[i]);
        peak = std::max(peak, abs_sample);
        sum_squares += samples[i] * samples[i];
    }
    rms = sqrtf(sum_squares / num_samples);
}

// 处理NDI音频帧的所有声道电平
void process_ndi_audio_levels(const NDIlib_audio_frame_v3_t& frame) {
    if (frame.FourCC != NDIlib_FourCC_audio_type_FLTP) {
        // 如果是16位整数格式(如S16P),需先转成float:int16_t转float要除以32768.0f
        return;
    }

    for (int ch = 0; ch < frame.no_channels; ch++) {
        float* channel_samples = reinterpret_cast<float*>(frame.p_data + ch * frame.channel_stride_in_bytes);
        float peak, rms;
        calculate_channel_levels(channel_samples, frame.no_samples, peak, rms);
        
        // 转成音频行业常用的dBFS单位(全幅信号为0dB)
        float peak_dbfs = peak > 0.0f ? 20.0f * log10f(peak) : -INFINITY;
        float rms_dbfs = rms > 0.0f ? 20.0f * log10f(rms) : -INFINITY;
        // 这里可以输出或存储电平值
    }
}

二、提取特定频率的电平(EQ相关)

要获取特定赫兹的电平,需要通过**傅里叶变换(FFT)**将时域采样转成频域,再提取对应频段的能量。推荐用轻量易用的C库:

推荐库选择

  • kissFFT:纯C实现,无外部依赖,容易集成到C++项目
  • FFTW:高性能FFT库,适合对处理速度要求高的场景

基于kissFFT的实现示例

#include "kiss_fftr.h"
#include <cmath>

// 计算单声道中目标频率的电平(dBFS)
void calculate_frequency_level(float* samples, int num_samples, int sample_rate, float target_freq, float& level) {
    // 初始化FFT计划,num_samples建议为2的幂(kissFFT性能最优)
    kiss_fftr_cfg fft_cfg = kiss_fftr_alloc(num_samples, 0, NULL, NULL);
    if (!fft_cfg) {
        level = -INFINITY;
        return;
    }

    // 分配频域输出缓冲区,长度为num_samples/2 + 1
    kiss_fft_cpx* fft_output = new kiss_fft_cpx[num_samples / 2 + 1];
    
    // 执行FFT,将时域采样转成频域复数
    kiss_fftr(fft_cfg, samples, fft_output);

    // 计算目标频率对应的频点索引:index = 目标频率 * 采样点数 / 采样率
    int target_idx = static_cast<int>(target_freq * num_samples / sample_rate);
    if (target_idx >= num_samples / 2 + 1) {
        level = -INFINITY;
        goto cleanup;
    }

    // 计算该频点的能量(复数模的平方)
    float real = fft_output[target_idx].r;
    float imag = fft_output[target_idx].i;
    float energy = real * real + imag * imag;
    // 转成dBFS单位
    level = 10.0f * log10f(energy / (num_samples * num_samples));

cleanup:
    delete[] fft_output;
    kiss_fftr_free(fft_cfg);
}

// 在NDI音频帧中调用
void process_ndi_audio_eq(const NDIlib_audio_frame_v3_t& frame, float target_freq) {
    if (frame.FourCC != NDIlib_FourCC_audio_type_FLTP) return;

    for (int ch = 0; ch < frame.no_channels; ch++) {
        float* channel_samples = reinterpret_cast<float*>(frame.p_data + ch * frame.channel_stride_in_bytes);
        float freq_level;
        calculate_frequency_level(channel_samples, frame.no_samples, frame.sample_rate, target_freq, freq_level);
        // 输出或存储特定频率的电平
    }
}

注意事项

  • 格式兼容:如果NDI输出的是其他格式(如16位整数S16P),需先将采样值转换为float(16位整数转float除以32768.0f)
  • 性能优化:实时处理时,FFT采样点数建议选1024或2048,平衡延迟和频率分辨率
  • 多声道处理:可以分别对每个声道计算,也可以混合声道后再处理

内容的提问来源于stack exchange,提问作者Akandesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 20:45:28