update fps to latest

This commit is contained in:
Steven Dan
2026-06-09 18:37:16 +08:00
parent 0395a811f7
commit e6cd505865
7 changed files with 455 additions and 97 deletions

View File

@@ -0,0 +1,44 @@
#ifndef __FPS_API_H__
#define __FPS_API_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* 初始化 FPS 处理链及默认运行状态。 */
void fps_xmos_xc_init(void);
/* 选择游戏配置和档位。game: 0~20=cs21=pubg2=deltalevel: 0~4。 */
void fps_xmos_xc_game_select(int game, int level);
/*
* 设置运行时三个子模块的开关。
* drc_enable: 0 表示旁路,非 0 表示开启 DRC
* fps_enable: 0 表示旁路 FPS 主处理,非 0 表示开启
* eq_enable: 0 表示在 FPS 阶段旁路 EQ非 0 表示开启
*/
void fps_xmos_xc_set_module_enable(int drc_enable, int fps_enable, int eq_enable);
/* 初始化运行,调节过程中不运行。 */
/* 设置 10 段 EQ 的全部增益,单位为 0.01 dB范围 -600 ~ 600。 */
void fps_xmos_xc_eq_set_all_gains(int16_t *gains);
/* 初始化不运行,调节过程中运行。 */
/* 设置单个 EQ 频段增益,单位为 0.01 dB范围 -600 ~ 600。 */
void fps_xmos_xc_eq_set_band_gain(int band, int16_t gain);
/*
* 处理一个双声道块。
* input/output 数据格式为解交织的平面双声道:
* input[0..511] : 左声道
* input[512..1023] : 右声道
*/
void fps_xmos_xc_process(int16_t *input, int16_t *output);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,173 @@
/* 改动原因FPS fps_eq 五模式增益在tile0侧LittleFS持久化 */
#include <string.h>
#include <stdio.h>
#include "fps_eq_flash.h"
#include "lfs_io.h"
#include "debug_print.h"
#define FPS_EQ_FLASH_PATH "fps_eq_store"
#define FPS_EQ_FLASH_VERSION 0x01u
static void fps_eq_default_name(uint8_t mode, char out_name[FPS_EQ_NAME_LEN])
{
/* 改动原因:按协议约定提供小写默认模式名 fps_eq_0 ~ fps_eq_4 */
snprintf(out_name, FPS_EQ_NAME_LEN, "fps_eq_%u", (unsigned)mode);
}
/* 改动原因仅判断“是否历史已存名称”不做ASCII限制兼容中文/多语言UTF-8 */
static int fps_eq_name_has_saved_value(const char name[FPS_EQ_NAME_LEN])
{
int i;
int all_zero = 1;
int all_ff = 1;
int has_terminator = 0;
unsigned char first = (unsigned char)name[0];
for (i = 0; i < FPS_EQ_NAME_LEN; i++) {
unsigned char c = (unsigned char)name[i];
if (c != 0x00) {
all_zero = 0;
}
if (c != 0xFF) {
all_ff = 0;
}
if (c == '\0') {
has_terminator = 1;
break;
}
}
/* 旧数据或未初始化全0或全0xFF视为“未存名称” */
if (all_zero || all_ff) {
return 0;
}
/* 改动原因:旧布局中常见 0x01 0x00...(增益=1会误判为“有名称”首字节为控制字节时视为未存 */
if (first < 0x20) {
return 0;
}
/* 有数据但无\0终止视为旧布局残留回退默认名 */
if (!has_terminator) {
return 0;
}
return 1;
}
void fps_eq_flash_set_defaults(fps_eq_flash_store_t *store)
{
int m, b;
memset(store, 0, sizeof(*store));
store->magic = FPS_EQ_FLASH_MAGIC;
store->version = FPS_EQ_FLASH_VERSION;
store->current_mode = 0;
for (m = 0; m < FPS_EQ_MODE_COUNT; m++) {
fps_eq_default_name((uint8_t)m, store->mode_names[m]);
for (b = 0; b < FPS_EQ_BAND_COUNT; b++) {
store->gains[m][b] = FPS_EQ_GAIN_DEFAULT;
}
}
}
int16_t fps_eq_clamp_gain(int16_t gain)
{
if (gain < FPS_EQ_GAIN_MIN) {
return FPS_EQ_GAIN_MIN;
}
if (gain > FPS_EQ_GAIN_MAX) {
return FPS_EQ_GAIN_MAX;
}
return gain;
}
int fps_eq_flash_load(fps_eq_flash_store_t *out)
{
fps_eq_flash_store_t tmp;
int m;
int need_repair = 0;
fps_eq_flash_set_defaults(out);
if (lfs_init() != 0) {
return -1;
}
lfs_read_config((unsigned char *)FPS_EQ_FLASH_PATH,
(unsigned char *)&tmp,
sizeof(tmp));
lfs_deinit();
if (tmp.magic != FPS_EQ_FLASH_MAGIC) {
debug_printf("fps_eq_flash: invalid magic, use defaults\n");
return -1;
}
if (tmp.version != FPS_EQ_FLASH_VERSION) {
debug_printf("fps_eq_flash: version mismatch, reset defaults\n");
return -1;
}
if (tmp.current_mode >= FPS_EQ_MODE_COUNT) {
tmp.current_mode = 0;
need_repair = 1;
}
for (m = 0; m < FPS_EQ_MODE_COUNT; m++) {
tmp.mode_names[m][FPS_EQ_NAME_LEN - 1] = '\0';
if (!fps_eq_name_has_saved_value(tmp.mode_names[m])) {
fps_eq_default_name((uint8_t)m, tmp.mode_names[m]);
need_repair = 1;
}
}
*out = tmp;
/* 改动原因:检测到历史脏数据时自动修复并回写,后续读取稳定显示 */
if (need_repair) {
(void)fps_eq_flash_save(out);
}
return 0;
}
int fps_eq_flash_save(const fps_eq_flash_store_t *store)
{
fps_eq_flash_store_t to_write = *store;
int m;
to_write.magic = FPS_EQ_FLASH_MAGIC;
to_write.version = FPS_EQ_FLASH_VERSION;
if (to_write.current_mode >= FPS_EQ_MODE_COUNT) {
to_write.current_mode = 0;
}
for (m = 0; m < FPS_EQ_MODE_COUNT; m++) {
to_write.mode_names[m][FPS_EQ_NAME_LEN - 1] = '\0';
if (to_write.mode_names[m][0] == '\0') {
fps_eq_default_name((uint8_t)m, to_write.mode_names[m]);
}
}
if (lfs_init() != 0) {
return -1;
}
lfs_write_config((unsigned char *)FPS_EQ_FLASH_PATH,
(unsigned char *)&to_write,
sizeof(to_write));
lfs_deinit();
return 0;
}
void fps_eq_name_get(const fps_eq_flash_store_t *store, uint8_t mode, char out_name[FPS_EQ_NAME_LEN])
{
if (mode >= FPS_EQ_MODE_COUNT) {
mode = 0;
}
memcpy(out_name, store->mode_names[mode], FPS_EQ_NAME_LEN);
out_name[FPS_EQ_NAME_LEN - 1] = '\0';
}
void fps_eq_name_set(fps_eq_flash_store_t *store, uint8_t mode, const char *name)
{
if (mode >= FPS_EQ_MODE_COUNT || name == NULL) {
return;
}
memset(store->mode_names[mode], 0, FPS_EQ_NAME_LEN);
strncpy(store->mode_names[mode], name, FPS_EQ_NAME_LEN - 1);
store->mode_names[mode][FPS_EQ_NAME_LEN - 1] = '\0';
}

View File

@@ -0,0 +1,32 @@
#ifndef FPS_EQ_FLASH_H
#define FPS_EQ_FLASH_H
#include <stdint.h>
/* 改动原因FPS库fps_eq五套预设(模式0-4)每套10段增益单位0.01dB存于tile0 Flash */
#define FPS_EQ_MODE_COUNT 5
#define FPS_EQ_BAND_COUNT 10
#define FPS_EQ_NAME_LEN 16
#define FPS_EQ_GAIN_DEFAULT 1
#define FPS_EQ_GAIN_MIN (-600)
#define FPS_EQ_GAIN_MAX 600
#define FPS_EQ_FLASH_MAGIC 0x46505345u /* "FPSE" */
typedef struct {
uint32_t magic;
uint8_t version;
uint8_t current_mode;
uint8_t reserved[2];
char mode_names[FPS_EQ_MODE_COUNT][FPS_EQ_NAME_LEN];
int16_t gains[FPS_EQ_MODE_COUNT][FPS_EQ_BAND_COUNT];
} fps_eq_flash_store_t;
void fps_eq_flash_set_defaults(fps_eq_flash_store_t *store);
int fps_eq_flash_load(fps_eq_flash_store_t *out);
int fps_eq_flash_save(const fps_eq_flash_store_t *store);
int16_t fps_eq_clamp_gain(int16_t gain);
void fps_eq_name_get(const fps_eq_flash_store_t *store, uint8_t mode, char out_name[FPS_EQ_NAME_LEN]);
void fps_eq_name_set(fps_eq_flash_store_t *store, uint8_t mode, const char *name);
#endif

View File

@@ -0,0 +1,22 @@
#ifndef FPS_EQ_SYNC_H
#define FPS_EQ_SYNC_H
#include <stdint.h>
#include "fps_eq_flash.h"
/* 改动原因int16增益经5个int32共享字在tile0/tile1间传递(dp仅支持32位SHARED_GLOBAL) */
extern unsigned g_fps_eq_mode;
extern int32_t g_fps_eq_pack0;
extern int32_t g_fps_eq_pack1;
extern int32_t g_fps_eq_pack2;
extern int32_t g_fps_eq_pack3;
extern int32_t g_fps_eq_pack4;
void fps_eq_unpack_gains(int16_t out[FPS_EQ_BAND_COUNT]);
void fps_eq_publish_gains_to_shared(const int16_t gains[FPS_EQ_BAND_COUNT]);
void fps_eq_publish_mode_and_gains(unsigned mode, const int16_t gains[FPS_EQ_BAND_COUNT]);
void fps_apply_eq_mode(void);
void fps_apply_eq_band_gain(unsigned band, int16_t gain);
#endif

View File

@@ -10,33 +10,115 @@
#include "xc_ptr.h"
#include "xua_conf.h"
extern void fps_xmos_init();
extern void fps_xmos_process(int16_t * input, int16_t* output, int channel);
/* 改动原因FPS库V1.5改为单核xc接口使用fps_api.h中的fps_xmos_xc_*声明 */
#include "fps_api.h"
#include "fps_eq_sync.h"
#define FPS_SLOT_NUM 3
#define FPS_FRAME_SIZE 512
#define FPS_NUM_OUT 2
short __attribute__((aligned (4))) dsp_fps_input_buf[FPS_SLOT_NUM][2][FPS_FRAME_SIZE];
short __attribute__((aligned (4))) dsp_fps_out_buf[FPS_SLOT_NUM][2][FPS_FRAME_SIZE];
/* 改动原因新库process接口为平面双声道左0..511、右512..1023每槽1024个sample */
#define FPS_PLANAR_SAMPLES (FPS_FRAME_SIZE * 2)
unsigned fps1_buf_ready = 0;
unsigned fps2_buf_ready = 0;
unsigned fps_write_pos = 0;
unsigned fps_process_pos = 0;
short __attribute__((aligned (4))) dsp_fps_input_buf[FPS_SLOT_NUM][FPS_PLANAR_SAMPLES];
short __attribute__((aligned (4))) dsp_fps_out_buf[FPS_SLOT_NUM][FPS_PLANAR_SAMPLES];
unsigned fps_buf_ready = 0;
unsigned fps_write_pos = 0;
unsigned fps_process_pos = 0;
/* 改动原因game/level仍由tile0经HID/Flash同步到tile1全局变量供初始化与audiohw同步回调使用 */
unsigned g_fps_game_select = 1;
unsigned g_fps_level_select = 2;
/* 改动原因FPS 默认开、DRC/fps_eq 默认关;与 audiohw 中 g_fps_enable(模式选择) 区分命名 */
unsigned g_fps_drc_enable = 0;
unsigned g_fps_sub_enable = 1;
unsigned g_fps_eq_enable = 0;
/* 改动原因fps_eq当前模式(0-4)与10段增益经5个pack字在tile0/tile1共享 */
unsigned g_fps_eq_mode = 0;
int32_t g_fps_eq_pack0 = 0;
int32_t g_fps_eq_pack1 = 0;
int32_t g_fps_eq_pack2 = 0;
int32_t g_fps_eq_pack3 = 0;
int32_t g_fps_eq_pack4 = 0;
static int32_t fps_eq_make_pack(int16_t lo, int16_t hi)
{
return ((int32_t)(uint16_t)lo) | (((int32_t)(uint16_t)hi) << 16);
}
static int16_t fps_eq_pack_lo(int32_t w)
{
return (int16_t)(w & 0xFFFF);
}
static int16_t fps_eq_pack_hi(int32_t w)
{
return (int16_t)((w >> 16) & 0xFFFF);
}
void fps_eq_unpack_gains(int16_t out[FPS_EQ_BAND_COUNT])
{
int32_t p0, p1, p2, p3, p4;
GET_SHARED_GLOBAL(p0, g_fps_eq_pack0);
GET_SHARED_GLOBAL(p1, g_fps_eq_pack1);
GET_SHARED_GLOBAL(p2, g_fps_eq_pack2);
GET_SHARED_GLOBAL(p3, g_fps_eq_pack3);
GET_SHARED_GLOBAL(p4, g_fps_eq_pack4);
out[0] = fps_eq_pack_lo(p0);
out[1] = fps_eq_pack_hi(p0);
out[2] = fps_eq_pack_lo(p1);
out[3] = fps_eq_pack_hi(p1);
out[4] = fps_eq_pack_lo(p2);
out[5] = fps_eq_pack_hi(p2);
out[6] = fps_eq_pack_lo(p3);
out[7] = fps_eq_pack_hi(p3);
out[8] = fps_eq_pack_lo(p4);
out[9] = fps_eq_pack_hi(p4);
}
void fps_eq_publish_gains_to_shared(const int16_t gains[FPS_EQ_BAND_COUNT])
{
SET_SHARED_GLOBAL(g_fps_eq_pack0, fps_eq_make_pack(gains[0], gains[1]));
SET_SHARED_GLOBAL(g_fps_eq_pack1, fps_eq_make_pack(gains[2], gains[3]));
SET_SHARED_GLOBAL(g_fps_eq_pack2, fps_eq_make_pack(gains[4], gains[5]));
SET_SHARED_GLOBAL(g_fps_eq_pack3, fps_eq_make_pack(gains[6], gains[7]));
SET_SHARED_GLOBAL(g_fps_eq_pack4, fps_eq_make_pack(gains[8], gains[9]));
}
void fps_eq_publish_mode_and_gains(unsigned mode, const int16_t gains[FPS_EQ_BAND_COUNT])
{
SET_SHARED_GLOBAL(g_fps_eq_mode, mode);
fps_eq_publish_gains_to_shared(gains);
}
void fps_apply_eq_mode(void)
{
int16_t gains[FPS_EQ_BAND_COUNT];
fps_eq_unpack_gains(gains);
/* 改动原因切换模式时用eq_set_all_gains一次性加载当前模式10段增益 */
fps_xmos_xc_eq_set_all_gains(gains);
}
void fps_apply_eq_band_gain(unsigned band, int16_t gain)
{
if (band >= FPS_EQ_BAND_COUNT) {
return;
}
/* 改动原因运行中单段调节使用fps_xmos_xc_eq_set_band_gain */
fps_xmos_xc_eq_set_band_gain((int)band, gain);
}
void fps_main (chanend_t c_data ) {
int input[2];
int output[2];
int count = 0;
unsigned write_pos = 0;
unsigned process_pos = 0;
unsigned write_pos = 0;
unsigned read_pos = 0;
while (1) {
chan_in_buf_word (c_data , input, 2) ;
@@ -44,19 +126,12 @@ void fps_main (chanend_t c_data ) {
if (count == 0)
read_pos = (write_pos + 1 + FPS_SLOT_NUM) % FPS_SLOT_NUM;
// 修改原因: 写入当前buffer读取前一个已处理完的buffer实现1帧延时
// 写入位置write_pos当前正在填充的buffer
for (int i = 0; i <2; i++)
{
dsp_fps_input_buf[write_pos][i][count] = (short)(input[i] >> 16);
}
/* 改动原因按fps_xmos_xc_process要求的平面格式写入左声道在前512右声道在后512 */
dsp_fps_input_buf[write_pos][count] = (short)(input[0] >> 16);
dsp_fps_input_buf[write_pos][FPS_FRAME_SIZE + count] = (short)(input[1] >> 16);
// 读取位置read_pos前一个已经DSP处理完成的buffer
// 这样可以实现最小延时1帧避免原来的3帧延时问题
for (int i = 0; i < 2; i++)
{
output[i] = (int)(dsp_fps_out_buf[read_pos][i][count]) << 16;
}
output[0] = (int)(dsp_fps_out_buf[read_pos][count]) << 16;
output[1] = (int)(dsp_fps_out_buf[read_pos][FPS_FRAME_SIZE + count]) << 16;
if (count != (FPS_FRAME_SIZE - 1))
{
@@ -64,84 +139,101 @@ void fps_main (chanend_t c_data ) {
}
else
{
// 一帧完成,进行缓冲区切换
count = 0;
// 修改原因: 实现1帧延时的三缓冲机制
// 步骤1: 将当前完成的写入buffer交给DSP处理任务
SET_SHARED_GLOBAL(fps_process_pos, write_pos);
// 步骤2: 切换到下一个buffer进行写入三缓冲循环0→1→2→0
write_pos = (write_pos + 1) % FPS_SLOT_NUM;
SET_SHARED_GLOBAL(fps_write_pos, write_pos);
SET_SHARED_GLOBAL(fps1_buf_ready, 1);
SET_SHARED_GLOBAL(fps2_buf_ready, 1);
/* 改动原因单核处理整帧立体声仅需一个ready标志 */
SET_SHARED_GLOBAL(fps_buf_ready, 1);
}
}
}
unsigned long get_reference_time();
/* 改动原因按全局变量同步DRC/FPS主处理/fps_eq三模块开关到算法库 */
void fps_apply_module_enable(void)
{
unsigned drc_enable;
unsigned fps_sub_enable;
unsigned eq_enable;
GET_SHARED_GLOBAL(drc_enable, g_fps_drc_enable);
GET_SHARED_GLOBAL(fps_sub_enable, g_fps_sub_enable);
GET_SHARED_GLOBAL(eq_enable, g_fps_eq_enable);
fps_xmos_xc_set_module_enable(
(drc_enable != 0) ? 1 : 0,
(fps_sub_enable != 0) ? 1 : 0,
(eq_enable != 0) ? 1 : 0);
}
/* 改动原因HID/tile0同步时在audiohw.xc中调用供tile1在收到0xA7时更新FPS算法参数 */
void fps_apply_game_level_select(void)
{
unsigned game_select;
unsigned level_select;
GET_SHARED_GLOBAL(game_select, g_fps_game_select);
GET_SHARED_GLOBAL(level_select, g_fps_level_select);
if (game_select > 2) {
game_select = 0;
}
/* 改动原因:无效 level 默认档位 2与 fps_level_g0/g1/g2 及 g_fps_level_select 一致 */
if (level_select > 4) {
level_select = 2;
}
fps_xmos_xc_game_select((int)game_select, (int)level_select);
}
/* 改动原因集中FPS库初始化顺序——init→fps_eq全段增益→game/level→三模块使能 */
static void fps_xmos_modules_init(void)
{
unsigned game_select;
unsigned level_select;
int16_t gains[FPS_EQ_BAND_COUNT];
fps_xmos_xc_init();
/* 改动原因从tile0已同步的共享pack字解出当前模式10段增益后初始化fps_eq */
fps_eq_unpack_gains(gains);
fps_xmos_xc_eq_set_all_gains(gains);
GET_SHARED_GLOBAL(game_select, g_fps_game_select);
GET_SHARED_GLOBAL(level_select, g_fps_level_select);
if (game_select > 2) {
game_select = 0;
}
/* 改动原因:上电/初始化时无效 level 默认档位 2 */
if (level_select > 4) {
level_select = 2;
}
fps_xmos_xc_game_select((int)game_select, (int)level_select);
fps_apply_module_enable();
}
void fps1_dsp_proc_task()
{
fps_xmos_init();
#if 1
fps_xmos_modules_init();
while (1)
{
unsigned ready1;
// 修改原因: 使用声道0独立的ready标志与声道1完全独立避免竞态
GET_SHARED_GLOBAL(ready1, fps1_buf_ready);
while (ready1)
{
// 修改原因: 关键修复 - 直接读取fps_main设置好的process_pos避免自己计算导致的竞态
unsigned cur_pos;
GET_SHARED_GLOBAL(cur_pos, fps_process_pos);
#if 0
for (int i = 0; i < FPS_FRAME_SIZE; i++)
{
dsp_fps_out_buf[cur_pos][0][i] = dsp_fps_input_buf[cur_pos][0][i];
}
#else
// 处理声道0数据
fps_xmos_process(&dsp_fps_input_buf[cur_pos][0], &dsp_fps_out_buf[cur_pos][0], 0);
#endif
unsigned ready;
ready1 = 0;
SET_SHARED_GLOBAL(fps1_buf_ready, 0);
GET_SHARED_GLOBAL(ready, fps_buf_ready);
while (ready)
{
unsigned cur_pos;
GET_SHARED_GLOBAL(cur_pos, fps_process_pos);
/* 改动原因:单核一次处理左右声道平面块,不再分声道两次调用 */
fps_xmos_xc_process(dsp_fps_input_buf[cur_pos], dsp_fps_out_buf[cur_pos]);
ready = 0;
SET_SHARED_GLOBAL(fps_buf_ready, 0);
}
}
#endif
}
void fps2_dsp_proc_task()
{
#if 1
while (1)
{
unsigned ready2;
GET_SHARED_GLOBAL(ready2, fps2_buf_ready);
while (ready2)
{
unsigned cur_pos;
GET_SHARED_GLOBAL(cur_pos, fps_process_pos);
// 处理声道1数据
unsigned long start_time = get_reference_time();
#if 0
for (int i = 0; i < FPS_FRAME_SIZE; i++)
{
dsp_fps_out_buf[cur_pos][1][i] = dsp_fps_input_buf[cur_pos][1][i];
}
#else
fps_xmos_process(&dsp_fps_input_buf[cur_pos][1], &dsp_fps_out_buf[cur_pos][1], 1);
#endif
unsigned long end_time = get_reference_time();
// printf("fps2_dsp_proc_task time: %d ms\n", end_time - start_time);
// 修改原因: 只清除自己的ready标志不影响声道0
ready2 = 0;
SET_SHARED_GLOBAL(fps2_buf_ready, 0);
}
}
#endif
}

View File

@@ -422,7 +422,6 @@ void usb_audio_io(chanend ?c_aud_in,
#if XMOS_FPS_EN
extern void fps_main(chanend c_data);
extern void fps1_dsp_proc_task();
extern void fps2_dsp_proc_task();
#endif
/* Main for USB Audio Applications */
@@ -528,10 +527,6 @@ int main()
set_core_high_priority_on();
fps1_dsp_proc_task();
}
on tile[1]: {
set_core_high_priority_on();
fps2_dsp_proc_task();
}
#else
#if UAC1
on tile[1]: {