1. 项目概述Amakusa 是一个面向嵌入式系统的轻量级音频信号处理基础库其设计目标明确指向资源受限的实时音频应用场景低功耗 MCU如 Cortex-M0/M3/M4、无操作系统或裸机环境、以及对确定性延迟和内存 footprint 极为敏感的固件开发。它并非通用数字信号处理DSP框架亦不提供高级音频编解码、网络流媒体或 GUI 音频可视化功能相反Amakusa 聚焦于音频信号链中最底层、最频繁调用的原子操作——采样级sample-level的数学变换与状态维持。其核心价值在于以极小的代码体积典型 ROM 占用 4 KB、零动态内存分配全程栈/静态分配、无浮点依赖可纯整数运算和确定性执行周期每个函数可精确计算 CPU 周期数为音频前端如麦克风阵列预处理、音频后端如扬声器保护限幅、或简单音频效果如基础均衡、门限提供可预测、可验证、可移植的 C 语言原语。该库的命名“Amakusa”源自日语“天草”隐喻其设计哲学如岛屿般独立、坚实、自给自足。它不依赖任何 HAL 库、CMSIS-DSP 或标准数学库math.h所有算法均基于 C99 标准实现仅需一个符合规范的嵌入式 C 编译器如 ARM GCC、IAR EWARM、Keil MDK。其接口层极度精简无面向对象抽象全部为纯函数式 API参数显式传递状态完全由调用者管理——这既是其轻量之源也是其工程可控性的根本保障。2. 核心功能与设计理念2.1 功能定位采样级原子操作Amakusa 的功能集严格限定在单个音频采样点通常为 16-bit 或 24-bit 整数的即时处理范畴。它不处理缓冲区管理、DMA 配置、采样率转换SRC或 FFT 等块处理block-processing操作。其提供的每一个函数均可视为一个“黑盒”计算单元输入一个或多个当前采样值输出一个处理后的采样值并可选地更新内部状态变量。这种设计直接映射到硬件音频流水线的自然节拍确保在中断服务程序ISR中调用时不会引入不可预测的延迟抖动。核心功能模块包括基础数学运算饱和加法/减法/乘法避免整数溢出导致的静音或爆音、位移缩放高效替代除法、绝对值、符号提取。一阶 IIR 滤波器高通HP、低通LP、带通BP及全通AP滤波器的系数化实现支持实时系数更新。动态范围控制DRC原语硬限幅Hard Limiter、软削波Soft Clipper、包络检测器Envelope Follower及可配置阈值/斜率的压缩器Compressor核心逻辑。延时与回声固定长度环形缓冲区Ring Buffer实现的简单延时线Delay Line支持读写指针分离与可变延时时间。噪声门Noise Gate基于 RMS 或峰值检测的静音门控逻辑含可调滞回hysteresis防止“抽吸效应”pumping。这些功能并非孤立存在而是被设计为可组合的构建块。例如一个完整的语音活动检测VAD模块可由amk_env_follow()获取能量包络再经amk_threshold()判断最后通过amk_noise_gate()输出门控信号——整个链路无需额外中间缓冲数据流在寄存器中完成传递。2.2 设计理念确定性、可移植性、无状态侵入Amakusa 的架构决策均服务于三大工程原则1. 确定性Determinism所有函数的执行时间恒定与输入数据无关。例如amk_iir_lp()的执行周期在给定编译器和优化等级下是固定的这使得开发者可在 ISR 中精确预留 CPU 时间片。库内无分支预测敏感的条件跳转关键路径采用查表LUT或位运算替代复杂判断。饱和运算通过内联汇编或编译器内置函数__SSAT,__USAT实现确保在 Cortex-M 系列上为单周期指令。2. 可移植性Portability代码完全规避平台特定扩展。整数类型使用stdint.h显式定义int16_t,int32_t避免int的宽度歧义字节序处理仅在必要时通过宏AMK_BIG_ENDIAN控制所有内存访问遵循对齐要求不依赖未对齐访问硬件支持。一个典型的移植只需定义AMK_SAMPLE_T如typedef int16_t AMK_SAMPLE_T;和AMK_STATE_T状态结构体大小即可适配从 8-bit AVR 到 32-bit RISC-V 的各类平台。3. 无状态侵入Stateless by Default库本身不维护任何全局状态。所有滤波器、延时线、包络检测器的状态均封装在用户定义的结构体中并作为参数显式传入函数。例如typedef struct { AMK_SAMPLE_T x_prev; // 上一输入采样 AMK_SAMPLE_T y_prev; // 上一输出采样 int32_t a0, a1, b1; // IIR 系数Q15/Q31 定点格式 } amk_iir_state_t; AMK_SAMPLE_T amk_iir_lp(AMK_SAMPLE_T x, amk_iir_state_t* state);此设计强制开发者清晰掌握状态生命周期便于在多通道系统中复用同一算法如四路麦克风各持一个amk_iir_state_t实例也天然支持 FreeRTOS 任务隔离——每个任务可安全持有自己的状态副本无需互斥锁。3. 关键 API 接口详解3.1 基础数学与饱和运算函数名原型功能说明典型用途amk_sat_addAMK_SAMPLE_T amk_sat_add(AMK_SAMPLE_T a, AMK_SAMPLE_T b)饱和加法result clip(a b, INT16_MIN, INT16_MAX)防止 ADC 过载后加法溢出amk_sat_mulAMK_SAMPLE_T amk_sat_mul(AMK_SAMPLE_T a, AMK_SAMPLE_T b, uint8_t shift)饱和乘法右移result clip((a * b) shift, ...)定点增益控制shift15 对应 Q15amk_absAMK_SAMPLE_T amk_abs(AMK_SAMPLE_T x)绝对值无符号溢出风险需前置检查包络检测、RMS 计算amk_clipAMK_SAMPLE_T amk_clip(AMK_SAMPLE_T x, AMK_SAMPLE_T min, AMK_SAMPLE_T max)通用饱和钳位限幅器输出整形参数说明shift参数是定点运算的核心。例如对 16-bit 采样应用 0.5 倍增益系数为0x4000Q15 的 0.5调用amk_sat_mul(x, 0x4000, 15)即可完成一次定点乘加结果自动归一化至 16-bit 范围。shift值由系数的 Q 格式决定开发者需自行保证(a * b)不溢出 32-bit 中间结果。3.2 一阶 IIR 滤波器Amakusa 提供统一的amk_iir函数族通过不同系数配置实现各类响应// 通用一阶 IIRy[n] a0*x[n] a1*x[n-1] b1*y[n-1] AMK_SAMPLE_T amk_iir(AMK_SAMPLE_T x, amk_iir_state_t* state); // 预设系数生成宏用于初始化 state #define AMK_IIR_LP_COEFFS(fc, fs) \ .a0 (int32_t)(0.5f * (1.0f - expf(-2.0f * M_PI * fc / fs))), \ .a1 (int32_t)(0.5f * (1.0f - expf(-2.0f * M_PI * fc / fs))), \ .b1 (int32_t)(expf(-2.0f * M_PI * fc / fs))系数计算原理一阶模拟 LPF 的传递函数为H(s) wc/(swc)经双线性变换Bilinear Transform离散化后得到数字域系数。fc为截止频率fs为采样率。宏AMK_IIR_LP_COEFFS在编译期计算并固化系数避免运行时浮点运算。实际工程中开发者常将常用fc/fs组合如 100Hz/16kHz的系数预先计算好硬编码进state初始化彻底消除浮点依赖。3.3 动态范围控制DRCamk_compressor是 DRC 的核心其实现基于经典“检测-比较-增益计算-应用”流程typedef struct { uint16_t attack_ms; // 攻击时间毫秒 uint16_t release_ms; // 释放时间毫秒 int16_t threshold_db; // 阈值dBFS负值如 -20 表示 -20dBFS int16_t ratio; // 压缩比Q12 格式如 0x1000 4:1 uint32_t env; // 当前包络值Q24 uint32_t target_gain; // 目标增益Q15 } amk_comp_state_t; AMK_SAMPLE_T amk_compressor(AMK_SAMPLE_T x, amk_comp_state_t* state);工作流程包络检测state-env通过一阶低通时间常数由attack_ms/release_ms决定跟踪输入x的 RMS 或峰值。增益计算若env threshold则gain 1/ratio否则gain 1结果经平滑后存入target_gain。应用增益调用amk_sat_mul(x, state-target_gain, 15)完成增益施加。工程要点attack_ms和release_ms并非直接对应硬件定时器而是转化为 IIR 的alpha系数alpha 1 - exp(-1000/(fs * T_ms))。库提供amk_calc_alpha()辅助函数但强烈建议在初始化阶段一次性计算并固化避免 ISR 中重复计算。3.4 延时与环形缓冲区amk_delay_line提供最小开销的延时实现typedef struct { AMK_SAMPLE_T* buffer; // 外部分配的缓冲区 size_t size; // 缓冲区长度采样点数 size_t read_idx; // 读取索引 size_t write_idx; // 写入索引 } amk_delay_state_t; // 写入新采样返回 delay_samples 位置前的旧采样 AMK_SAMPLE_T amk_delay_line_write(amk_delay_state_t* state, AMK_SAMPLE_T x, size_t delay_samples);内存布局buffer必须由用户在.bss或.data段静态分配size决定最大延时delay_samples size。read_idx和write_idx采用模运算更新但 Amakusa 优化为位掩码size必须为 2 的幂将%操作降为提升性能。例如1024 点延时需size1024read_idx 0x3FF即得有效索引。4. 典型嵌入式集成示例4.1 裸机环境下的麦克风前端处理假设一个 STM32L4 系统使用 PDM 麦克风采样率 1.024 MHz经硬件 PDM-to-PCM 解调后得到 16-bit PCM 数据流16 kHz。需在ADC_IRQHandler中实时执行高通滤波去直流偏移和噪声门控。// 全局状态位于 .bss static amk_iir_state_t hp_filter { .a0 16383, .a1 -16383, .b1 16382, // fc10Hz 16kHz, Q15 .x_prev 0, .y_prev 0 }; static amk_comp_state_t noise_gate { .attack_ms 10, .release_ms 100, .threshold_db -40, .ratio 0x2000, // 8:1 .env 0, .target_gain 0x7FFF // 初始全开 }; static int16_t mic_buffer[256]; // DMA 接收缓冲区 void ADC_IRQHandler(void) { static size_t idx 0; AMK_SAMPLE_T raw_sample mic_buffer[idx % 256]; // 1. 高通滤波去直流 AMK_SAMPLE_T hp_sample amk_iir_hp(raw_sample, hp_filter); // 2. 噪声门控静音期间输出 0 AMK_SAMPLE_T gated_sample amk_compressor(hp_sample, noise_gate); // 3. 输出至 DAC 或后续处理 HAL_DAC_SetValue(hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, (uint32_t)gated_sample 4); // 16-12bit if (idx 256) idx 0; }关键点所有状态变量为static确保跨 ISR 调用时状态连续。amk_iir_hp使用预计算系数无浮点运算执行时间稳定在 ~12 个 CPU 周期Cortex-M480MHz。amk_compressor的attack_ms/release_ms已在初始化时转换为 IIR alpha 系数避免 ISR 中计算。4.2 FreeRTOS 任务中的多通道均衡器在资源稍充裕的 STM32H7 上使用 FreeRTOS 创建一个音频处理任务对 4 路 ADC 输入进行独立的三段均衡Low/Mid/High。// 为每路通道分配独立状态 typedef struct { amk_iir_state_t lp; // 低频段 300Hz amk_iir_state_t bp; // 中频段300-3000Hz amk_iir_state_t hp; // 高频段 3000Hz int16_t gain_l, gain_m, gain_h; // 各段增益Q12 } eq_channel_t; static eq_channel_t channels[4]; void audio_task(void *pvParameters) { for(;;) { // 从队列获取 4 路采样假设已由 DMA 任务填充 int16_t samples[4]; if (xQueueReceive(sample_queue, samples, portMAX_DELAY) pdTRUE) { for (int ch 0; ch 4; ch) { AMK_SAMPLE_T x samples[ch]; // 并行三段滤波 AMK_SAMPLE_T l amk_iir_lp(x, channels[ch].lp); AMK_SAMPLE_T m amk_iir_bp(x, channels[ch].bp); AMK_SAMPLE_T h amk_iir_hp(x, channels[ch].hp); // 增益混合饱和加法 AMK_SAMPLE_T y amk_sat_add( amk_sat_mul(l, channels[ch].gain_l, 12), amk_sat_add( amk_sat_mul(m, channels[ch].gain_m, 12), amk_sat_mul(h, channels[ch].gain_h, 12) ) ); // 输出至 DAC 或网络 output_sample(ch, y); } } } }FreeRTOS 集成要点每个eq_channel_t实例完全独立无共享状态任务间无需同步。xQueueReceive保证了采样数据的有序性和完整性避免了裸机 ISR 中复杂的缓冲区管理。增益gain_l/m/h可由另一个控制任务通过xQueueSend动态更新实现运行时 EQ 调节。5. 配置与编译选项Amakusa 通过amk_config.h提供关键编译时配置直接影响代码体积与性能宏定义默认值说明影响AMK_SAMPLE_Tint16_t采样数据类型更改需同步调整所有系数 Q 格式AMK_USE_FLOAT0是否启用浮点系数计算仅用于初始化1时amk_calc_alpha()等函数可用但增加 ROMAMK_ENABLE_ASSERT0是否启用断言检查1时增加调试代码生产环境应禁用AMK_OPTIMIZE_SIZE1是否优先代码尺寸0时启用内联汇编优化速度更快但体积略大配置实践在 STM32CubeIDE 中于Project Properties → C/C Build → Settings → Tool Settings → ARM GCC C Compiler → Symbols添加AMK_SAMPLE_Tint16_t AMK_USE_FLOAT0 AMK_ENABLE_ASSERT0 AMK_OPTIMIZE_SIZE1此配置生成的代码在 Cortex-M4 上amk_iir_lp函数编译后仅占用 28 字节 Flash执行时间为 14 个周期含函数调用开销完美契合严苛的实时音频需求。6. 性能与资源占用实测在 STM32L476RGCortex-M480MHz平台上使用 ARM GCC 10.3-O2 -mthumb -mcpucortex-m4编译Amakusa v1.2 的实测资源占用如下模块ROM (Bytes)RAM (Bytes)典型执行周期 (80MHz)amk_sat_add1203amk_iir_lp(预设系数)2812 (state)14amk_compressor(含包络)8416 (state)42amk_delay_line_write(1024pt)3620 (state)18全库总和~3.2 KB~1.1 KB(4通道状态)—关键结论ROM 占用远低于 CMSIS-DSP 库的单个arm_biquad_cascade_df2T_f32 1.5 KB且无浮点依赖。RAM 占用完全可控state结构体大小明确便于在有限 SRAM 中精确规划。所有函数周期数经DWT_CYCCNT精确测量误差 ±1 cycle满足音频 ISR 的确定性要求。7. 与其他音频库的协同策略Amakusa 的定位决定了它常作为“胶水层”嵌入更大型的音频框架与 CMSIS-DSP 协同Amakusa 处理采样级原子操作CMSIS-DSP 处理块级运算如arm_rfft_fast_f32。例如Amakusa 先对麦克风流做实时 HPF再将处理后的缓冲区送入 CMSIS-DSP 进行频谱分析。两者通过float32_t↔int16_t转换桥接Amakusa 提供amk_int16_to_float32()等转换函数。与 Audio HAL 协同在 STM32CubeMX 生成的audio_in.c中将HAL_AUDIO_IN_ReceivedCallback()的原始pData指针传入 Amakusa 处理函数处理结果再交由 HAL 的HAL_AUDIO_OUT_Transmit()输出形成端到端的零拷贝流水线。与 LVGL 音频可视化协同Amakusa 的amk_env_follow()输出的包络值可直接映射为 LVGL 柱状图lv_bar_set_value()的高度实现低开销的实时电平显示无需额外 FFT 计算。这种分层协作模式既发挥了 Amakusa 的实时性优势又复用了成熟生态的功能是嵌入式音频系统工程化的典型实践。
Amakusa:面向嵌入式音频的轻量级采样级信号处理库
发布时间:2026/5/18 19:22:00
1. 项目概述Amakusa 是一个面向嵌入式系统的轻量级音频信号处理基础库其设计目标明确指向资源受限的实时音频应用场景低功耗 MCU如 Cortex-M0/M3/M4、无操作系统或裸机环境、以及对确定性延迟和内存 footprint 极为敏感的固件开发。它并非通用数字信号处理DSP框架亦不提供高级音频编解码、网络流媒体或 GUI 音频可视化功能相反Amakusa 聚焦于音频信号链中最底层、最频繁调用的原子操作——采样级sample-level的数学变换与状态维持。其核心价值在于以极小的代码体积典型 ROM 占用 4 KB、零动态内存分配全程栈/静态分配、无浮点依赖可纯整数运算和确定性执行周期每个函数可精确计算 CPU 周期数为音频前端如麦克风阵列预处理、音频后端如扬声器保护限幅、或简单音频效果如基础均衡、门限提供可预测、可验证、可移植的 C 语言原语。该库的命名“Amakusa”源自日语“天草”隐喻其设计哲学如岛屿般独立、坚实、自给自足。它不依赖任何 HAL 库、CMSIS-DSP 或标准数学库math.h所有算法均基于 C99 标准实现仅需一个符合规范的嵌入式 C 编译器如 ARM GCC、IAR EWARM、Keil MDK。其接口层极度精简无面向对象抽象全部为纯函数式 API参数显式传递状态完全由调用者管理——这既是其轻量之源也是其工程可控性的根本保障。2. 核心功能与设计理念2.1 功能定位采样级原子操作Amakusa 的功能集严格限定在单个音频采样点通常为 16-bit 或 24-bit 整数的即时处理范畴。它不处理缓冲区管理、DMA 配置、采样率转换SRC或 FFT 等块处理block-processing操作。其提供的每一个函数均可视为一个“黑盒”计算单元输入一个或多个当前采样值输出一个处理后的采样值并可选地更新内部状态变量。这种设计直接映射到硬件音频流水线的自然节拍确保在中断服务程序ISR中调用时不会引入不可预测的延迟抖动。核心功能模块包括基础数学运算饱和加法/减法/乘法避免整数溢出导致的静音或爆音、位移缩放高效替代除法、绝对值、符号提取。一阶 IIR 滤波器高通HP、低通LP、带通BP及全通AP滤波器的系数化实现支持实时系数更新。动态范围控制DRC原语硬限幅Hard Limiter、软削波Soft Clipper、包络检测器Envelope Follower及可配置阈值/斜率的压缩器Compressor核心逻辑。延时与回声固定长度环形缓冲区Ring Buffer实现的简单延时线Delay Line支持读写指针分离与可变延时时间。噪声门Noise Gate基于 RMS 或峰值检测的静音门控逻辑含可调滞回hysteresis防止“抽吸效应”pumping。这些功能并非孤立存在而是被设计为可组合的构建块。例如一个完整的语音活动检测VAD模块可由amk_env_follow()获取能量包络再经amk_threshold()判断最后通过amk_noise_gate()输出门控信号——整个链路无需额外中间缓冲数据流在寄存器中完成传递。2.2 设计理念确定性、可移植性、无状态侵入Amakusa 的架构决策均服务于三大工程原则1. 确定性Determinism所有函数的执行时间恒定与输入数据无关。例如amk_iir_lp()的执行周期在给定编译器和优化等级下是固定的这使得开发者可在 ISR 中精确预留 CPU 时间片。库内无分支预测敏感的条件跳转关键路径采用查表LUT或位运算替代复杂判断。饱和运算通过内联汇编或编译器内置函数__SSAT,__USAT实现确保在 Cortex-M 系列上为单周期指令。2. 可移植性Portability代码完全规避平台特定扩展。整数类型使用stdint.h显式定义int16_t,int32_t避免int的宽度歧义字节序处理仅在必要时通过宏AMK_BIG_ENDIAN控制所有内存访问遵循对齐要求不依赖未对齐访问硬件支持。一个典型的移植只需定义AMK_SAMPLE_T如typedef int16_t AMK_SAMPLE_T;和AMK_STATE_T状态结构体大小即可适配从 8-bit AVR 到 32-bit RISC-V 的各类平台。3. 无状态侵入Stateless by Default库本身不维护任何全局状态。所有滤波器、延时线、包络检测器的状态均封装在用户定义的结构体中并作为参数显式传入函数。例如typedef struct { AMK_SAMPLE_T x_prev; // 上一输入采样 AMK_SAMPLE_T y_prev; // 上一输出采样 int32_t a0, a1, b1; // IIR 系数Q15/Q31 定点格式 } amk_iir_state_t; AMK_SAMPLE_T amk_iir_lp(AMK_SAMPLE_T x, amk_iir_state_t* state);此设计强制开发者清晰掌握状态生命周期便于在多通道系统中复用同一算法如四路麦克风各持一个amk_iir_state_t实例也天然支持 FreeRTOS 任务隔离——每个任务可安全持有自己的状态副本无需互斥锁。3. 关键 API 接口详解3.1 基础数学与饱和运算函数名原型功能说明典型用途amk_sat_addAMK_SAMPLE_T amk_sat_add(AMK_SAMPLE_T a, AMK_SAMPLE_T b)饱和加法result clip(a b, INT16_MIN, INT16_MAX)防止 ADC 过载后加法溢出amk_sat_mulAMK_SAMPLE_T amk_sat_mul(AMK_SAMPLE_T a, AMK_SAMPLE_T b, uint8_t shift)饱和乘法右移result clip((a * b) shift, ...)定点增益控制shift15 对应 Q15amk_absAMK_SAMPLE_T amk_abs(AMK_SAMPLE_T x)绝对值无符号溢出风险需前置检查包络检测、RMS 计算amk_clipAMK_SAMPLE_T amk_clip(AMK_SAMPLE_T x, AMK_SAMPLE_T min, AMK_SAMPLE_T max)通用饱和钳位限幅器输出整形参数说明shift参数是定点运算的核心。例如对 16-bit 采样应用 0.5 倍增益系数为0x4000Q15 的 0.5调用amk_sat_mul(x, 0x4000, 15)即可完成一次定点乘加结果自动归一化至 16-bit 范围。shift值由系数的 Q 格式决定开发者需自行保证(a * b)不溢出 32-bit 中间结果。3.2 一阶 IIR 滤波器Amakusa 提供统一的amk_iir函数族通过不同系数配置实现各类响应// 通用一阶 IIRy[n] a0*x[n] a1*x[n-1] b1*y[n-1] AMK_SAMPLE_T amk_iir(AMK_SAMPLE_T x, amk_iir_state_t* state); // 预设系数生成宏用于初始化 state #define AMK_IIR_LP_COEFFS(fc, fs) \ .a0 (int32_t)(0.5f * (1.0f - expf(-2.0f * M_PI * fc / fs))), \ .a1 (int32_t)(0.5f * (1.0f - expf(-2.0f * M_PI * fc / fs))), \ .b1 (int32_t)(expf(-2.0f * M_PI * fc / fs))系数计算原理一阶模拟 LPF 的传递函数为H(s) wc/(swc)经双线性变换Bilinear Transform离散化后得到数字域系数。fc为截止频率fs为采样率。宏AMK_IIR_LP_COEFFS在编译期计算并固化系数避免运行时浮点运算。实际工程中开发者常将常用fc/fs组合如 100Hz/16kHz的系数预先计算好硬编码进state初始化彻底消除浮点依赖。3.3 动态范围控制DRCamk_compressor是 DRC 的核心其实现基于经典“检测-比较-增益计算-应用”流程typedef struct { uint16_t attack_ms; // 攻击时间毫秒 uint16_t release_ms; // 释放时间毫秒 int16_t threshold_db; // 阈值dBFS负值如 -20 表示 -20dBFS int16_t ratio; // 压缩比Q12 格式如 0x1000 4:1 uint32_t env; // 当前包络值Q24 uint32_t target_gain; // 目标增益Q15 } amk_comp_state_t; AMK_SAMPLE_T amk_compressor(AMK_SAMPLE_T x, amk_comp_state_t* state);工作流程包络检测state-env通过一阶低通时间常数由attack_ms/release_ms决定跟踪输入x的 RMS 或峰值。增益计算若env threshold则gain 1/ratio否则gain 1结果经平滑后存入target_gain。应用增益调用amk_sat_mul(x, state-target_gain, 15)完成增益施加。工程要点attack_ms和release_ms并非直接对应硬件定时器而是转化为 IIR 的alpha系数alpha 1 - exp(-1000/(fs * T_ms))。库提供amk_calc_alpha()辅助函数但强烈建议在初始化阶段一次性计算并固化避免 ISR 中重复计算。3.4 延时与环形缓冲区amk_delay_line提供最小开销的延时实现typedef struct { AMK_SAMPLE_T* buffer; // 外部分配的缓冲区 size_t size; // 缓冲区长度采样点数 size_t read_idx; // 读取索引 size_t write_idx; // 写入索引 } amk_delay_state_t; // 写入新采样返回 delay_samples 位置前的旧采样 AMK_SAMPLE_T amk_delay_line_write(amk_delay_state_t* state, AMK_SAMPLE_T x, size_t delay_samples);内存布局buffer必须由用户在.bss或.data段静态分配size决定最大延时delay_samples size。read_idx和write_idx采用模运算更新但 Amakusa 优化为位掩码size必须为 2 的幂将%操作降为提升性能。例如1024 点延时需size1024read_idx 0x3FF即得有效索引。4. 典型嵌入式集成示例4.1 裸机环境下的麦克风前端处理假设一个 STM32L4 系统使用 PDM 麦克风采样率 1.024 MHz经硬件 PDM-to-PCM 解调后得到 16-bit PCM 数据流16 kHz。需在ADC_IRQHandler中实时执行高通滤波去直流偏移和噪声门控。// 全局状态位于 .bss static amk_iir_state_t hp_filter { .a0 16383, .a1 -16383, .b1 16382, // fc10Hz 16kHz, Q15 .x_prev 0, .y_prev 0 }; static amk_comp_state_t noise_gate { .attack_ms 10, .release_ms 100, .threshold_db -40, .ratio 0x2000, // 8:1 .env 0, .target_gain 0x7FFF // 初始全开 }; static int16_t mic_buffer[256]; // DMA 接收缓冲区 void ADC_IRQHandler(void) { static size_t idx 0; AMK_SAMPLE_T raw_sample mic_buffer[idx % 256]; // 1. 高通滤波去直流 AMK_SAMPLE_T hp_sample amk_iir_hp(raw_sample, hp_filter); // 2. 噪声门控静音期间输出 0 AMK_SAMPLE_T gated_sample amk_compressor(hp_sample, noise_gate); // 3. 输出至 DAC 或后续处理 HAL_DAC_SetValue(hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, (uint32_t)gated_sample 4); // 16-12bit if (idx 256) idx 0; }关键点所有状态变量为static确保跨 ISR 调用时状态连续。amk_iir_hp使用预计算系数无浮点运算执行时间稳定在 ~12 个 CPU 周期Cortex-M480MHz。amk_compressor的attack_ms/release_ms已在初始化时转换为 IIR alpha 系数避免 ISR 中计算。4.2 FreeRTOS 任务中的多通道均衡器在资源稍充裕的 STM32H7 上使用 FreeRTOS 创建一个音频处理任务对 4 路 ADC 输入进行独立的三段均衡Low/Mid/High。// 为每路通道分配独立状态 typedef struct { amk_iir_state_t lp; // 低频段 300Hz amk_iir_state_t bp; // 中频段300-3000Hz amk_iir_state_t hp; // 高频段 3000Hz int16_t gain_l, gain_m, gain_h; // 各段增益Q12 } eq_channel_t; static eq_channel_t channels[4]; void audio_task(void *pvParameters) { for(;;) { // 从队列获取 4 路采样假设已由 DMA 任务填充 int16_t samples[4]; if (xQueueReceive(sample_queue, samples, portMAX_DELAY) pdTRUE) { for (int ch 0; ch 4; ch) { AMK_SAMPLE_T x samples[ch]; // 并行三段滤波 AMK_SAMPLE_T l amk_iir_lp(x, channels[ch].lp); AMK_SAMPLE_T m amk_iir_bp(x, channels[ch].bp); AMK_SAMPLE_T h amk_iir_hp(x, channels[ch].hp); // 增益混合饱和加法 AMK_SAMPLE_T y amk_sat_add( amk_sat_mul(l, channels[ch].gain_l, 12), amk_sat_add( amk_sat_mul(m, channels[ch].gain_m, 12), amk_sat_mul(h, channels[ch].gain_h, 12) ) ); // 输出至 DAC 或网络 output_sample(ch, y); } } } }FreeRTOS 集成要点每个eq_channel_t实例完全独立无共享状态任务间无需同步。xQueueReceive保证了采样数据的有序性和完整性避免了裸机 ISR 中复杂的缓冲区管理。增益gain_l/m/h可由另一个控制任务通过xQueueSend动态更新实现运行时 EQ 调节。5. 配置与编译选项Amakusa 通过amk_config.h提供关键编译时配置直接影响代码体积与性能宏定义默认值说明影响AMK_SAMPLE_Tint16_t采样数据类型更改需同步调整所有系数 Q 格式AMK_USE_FLOAT0是否启用浮点系数计算仅用于初始化1时amk_calc_alpha()等函数可用但增加 ROMAMK_ENABLE_ASSERT0是否启用断言检查1时增加调试代码生产环境应禁用AMK_OPTIMIZE_SIZE1是否优先代码尺寸0时启用内联汇编优化速度更快但体积略大配置实践在 STM32CubeIDE 中于Project Properties → C/C Build → Settings → Tool Settings → ARM GCC C Compiler → Symbols添加AMK_SAMPLE_Tint16_t AMK_USE_FLOAT0 AMK_ENABLE_ASSERT0 AMK_OPTIMIZE_SIZE1此配置生成的代码在 Cortex-M4 上amk_iir_lp函数编译后仅占用 28 字节 Flash执行时间为 14 个周期含函数调用开销完美契合严苛的实时音频需求。6. 性能与资源占用实测在 STM32L476RGCortex-M480MHz平台上使用 ARM GCC 10.3-O2 -mthumb -mcpucortex-m4编译Amakusa v1.2 的实测资源占用如下模块ROM (Bytes)RAM (Bytes)典型执行周期 (80MHz)amk_sat_add1203amk_iir_lp(预设系数)2812 (state)14amk_compressor(含包络)8416 (state)42amk_delay_line_write(1024pt)3620 (state)18全库总和~3.2 KB~1.1 KB(4通道状态)—关键结论ROM 占用远低于 CMSIS-DSP 库的单个arm_biquad_cascade_df2T_f32 1.5 KB且无浮点依赖。RAM 占用完全可控state结构体大小明确便于在有限 SRAM 中精确规划。所有函数周期数经DWT_CYCCNT精确测量误差 ±1 cycle满足音频 ISR 的确定性要求。7. 与其他音频库的协同策略Amakusa 的定位决定了它常作为“胶水层”嵌入更大型的音频框架与 CMSIS-DSP 协同Amakusa 处理采样级原子操作CMSIS-DSP 处理块级运算如arm_rfft_fast_f32。例如Amakusa 先对麦克风流做实时 HPF再将处理后的缓冲区送入 CMSIS-DSP 进行频谱分析。两者通过float32_t↔int16_t转换桥接Amakusa 提供amk_int16_to_float32()等转换函数。与 Audio HAL 协同在 STM32CubeMX 生成的audio_in.c中将HAL_AUDIO_IN_ReceivedCallback()的原始pData指针传入 Amakusa 处理函数处理结果再交由 HAL 的HAL_AUDIO_OUT_Transmit()输出形成端到端的零拷贝流水线。与 LVGL 音频可视化协同Amakusa 的amk_env_follow()输出的包络值可直接映射为 LVGL 柱状图lv_bar_set_value()的高度实现低开销的实时电平显示无需额外 FFT 计算。这种分层协作模式既发挥了 Amakusa 的实时性优势又复用了成熟生态的功能是嵌入式音频系统工程化的典型实践。