Files
P4-USB-transfer/main/NS4168/wav_demux.c
T
zhengxinandCursor 851e347cf5 初始提交卡包 USB 工程
纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。

Co-authored-by: Cursor <[email protected]>
2026-10-13 21:54:50 +08:00

380 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdint.h>
#include "esp_log.h"
#include "NS4168/micro_decoder_wrapper.h"
#include "NS4168/wav_demux.h"
#include "NS4168/ns4168.h"
#include <math.h>
#include <stdio.h>
#include <stdint.h>
static FILE* g_fp = NULL;
void md_init(const char* path)
{
g_fp = fopen(path, "rb"); // 标准 C
}
int md_read(uint8_t* buf, int len)
{
if (!g_fp) return 0;
return fread(buf, 1, len, g_fp); // 标准 C
}
void md_deinit()
{
if (g_fp) {
fclose(g_fp); // 标准 C
g_fp = NULL; // 标准 C(替换 nullptr)
}
}
void play_wav(void)
{
ns4168_i2s_init();
uint8_t header[70];
size_t written = 0;
int ret;
md_init("/extflash/ring2.wav");
md_read(header, sizeof(header));
ESP_LOG_BUFFER_HEX("WAV", header, sizeof(header));
ESP_LOGI("WAV", "WAV解析成功,开始播放");
uint8_t buf[1024];
int n;
while ((n = md_read(buf, sizeof(buf))) > 0) {
i2s_write(NS4168_I2S_PORT, buf, n, &written, portMAX_DELAY);
}
md_deinit();
ESP_LOGI("WAV", "WAV播放结束");
}
/**
* @param volume 音量系数,0.0=静音,1.0=原始音量,推荐 0.0~1.0
*/
void play_wav2(float volume)
{
uint8_t header[70];
size_t written = 0;
md_init("/extflash/ring2.wav");
md_read(header, sizeof(header));
ESP_LOG_BUFFER_HEX("WAV", header, sizeof(header));
ESP_LOGI("WAV", "WAV解析成功,开始播放");
uint8_t buf[1024];
int n;
while ((n = md_read(buf, sizeof(buf))) > 0) {
// 仅当音量不是 1.0 时才缩放(优化性能)
if (volume != 1.0f) {
int16_t *samples = (int16_t *)buf;
int num_samples = n / 2; // 假定为 16-bit PCM
for (int i = 0; i < num_samples; i++) {
int32_t val = (int32_t)(samples[i] * volume);
// 饱和限幅,防止溢出破音
if (val > 32767) val = 32767;
if (val < -32768) val = -32768;
samples[i] = (int16_t)val;
}
}
i2s_write(NS4168_I2S_PORT, buf, n, &written, portMAX_DELAY);
}
md_deinit();
ESP_LOGI("WAV", "WAV播放结束");
}
void play_wav3(float volume)
{
// 1. 打开文件
md_init("/extflash/ring2.wav");
// 2. 读取头部(沿用 70 字节,兼容你的原逻辑)
uint8_t header[70];
md_read(header, sizeof(header));
ESP_LOG_BUFFER_HEX("WAV", header, sizeof(header));
ESP_LOGI("WAV", "WAV解析成功,开始播放,音量=%.2f", volume);
// 3. 将浮点音量转换为 Q15 定点数 (范围 0 ~ 32768)
int32_t vol_fixed = (int32_t)(volume * 32768.0f + 0.5f);
if (vol_fixed > 32768) vol_fixed = 32768;
if (vol_fixed < 0) vol_fixed = 0;
size_t written = 0;
uint8_t buf[1024];
int n;
// 4. 循环读取音频数据并处理
while ((n = md_read(buf, sizeof(buf))) > 0) {
// 确保处理偶数个字节,防止破坏样本对齐
int bytes_to_process = (n / 2) * 2;
int num_samples = bytes_to_process / 2;
int16_t *samples = (int16_t *)buf;
// 音量接近静音时直接填零(避免处理微小信号产生的噪声)
if (vol_fixed < 32) {
memset(buf, 0, bytes_to_process);
}
else if (vol_fixed != 32768) { // 不等于 1.0 时才缩放
for (int i = 0; i < num_samples; i++) {
// 整数定点缩放 + 四舍五入
int32_t val = ((int32_t)samples[i] * vol_fixed + 16384) >> 15;
// 饱和限幅(实际不会溢出,但保留保护)
if (val > 32767) val = 32767;
if (val < -32768) val = -32768;
samples[i] = (int16_t)val;
}
}
// 发送对齐后的数据(丢弃奇数尾字节)
i2s_write(NS4168_I2S_PORT, buf, bytes_to_process, &written, portMAX_DELAY);
}
// 5. 关闭文件
md_deinit();
ESP_LOGI("WAV", "WAV播放结束");
}
void play_wav4(float volume)
{
uint8_t header[70];
size_t written = 0;
md_init("/extflash/ring2.wav");
md_read(header, sizeof(header));
ESP_LOG_BUFFER_HEX("WAV", header, sizeof(header));
ESP_LOGI("WAV", "WAV解析成功,开始播放");
uint8_t buf[1024];
int n;
while ((n = md_read(buf, sizeof(buf))) > 0) {
if (volume != 1.0f) {
int16_t *samples = (int16_t *)buf;
int num_samples = n / 2; // 16-bit PCM
for (int i = 0; i < num_samples; i++) {
// 浮点缩放
float scaled = (float)samples[i] * volume;
// 四舍五入(关键)
int32_t val = lrintf(scaled);
// 饱和限幅
if (val > 32767) val = 32767;
if (val < -32768) val = -32768;
samples[i] = (int16_t)val;
}
}
i2s_write(NS4168_I2S_PORT, buf, n, &written, portMAX_DELAY);
}
md_deinit();
ESP_LOGI("WAV", "WAV播放结束");
}
void play_wav5(float volume)
{
uint8_t header[70];
size_t written = 0;
md_init("/extflash/ring2.wav");
md_read(header, sizeof(header));
ESP_LOG_BUFFER_HEX("WAV", header, sizeof(header));
ESP_LOGI("WAV", "WAV解析成功,开始播放");
uint8_t buf[1024];
int n;
// 将浮点音量转换为 8-bit 定点(0~256)
int32_t vol_fixed = (int32_t)(volume * 256.0f);
while ((n = md_read(buf, sizeof(buf))) > 0) {
if (volume != 1.0f) {
int16_t *samples = (int16_t *)buf;
int num_samples = n / 2; // 16-bit PCM
for (int i = 0; i < num_samples; i++) {
// 原始 16-bit PCM
int32_t v = samples[i];
// 定点缩放:扩大到 24-bit 精度再缩回
v = (v * vol_fixed) >> 8;
// 饱和限幅
if (v > 32767) v = 32767;
if (v < -32768) v = -32768;
samples[i] = (int16_t)v;
}
}
i2s_write(NS4168_I2S_PORT, buf, n, &written, portMAX_DELAY);
}
md_deinit();
ESP_LOGI("WAV", "WAV播放结束");
}
void play_wav_p4(float volume)
{
uint8_t header[70];
size_t written = 0;
md_init("/extflash/ring2.wav");
md_read(header, sizeof(header));
ESP_LOG_BUFFER_HEX("WAV", header, sizeof(header));
ESP_LOGI("WAV", "WAV解析成功,开始播放");
uint8_t buf[1024];
int n;
// 如果音量是 1.0,直接原样播放,完全无损
bool bypass = (fabsf(volume - 1.0f) < 0.0001f);
// 简单 dither 强度(可以微调)
const float dither_amp = 1.0f / 512.0f; // 很小的抖动
while ((n = md_read(buf, sizeof(buf))) > 0) {
if (!bypass) {
int16_t *samples = (int16_t *)buf;
int num_samples = n / 2; // 16-bit PCM
for (int i = 0; i < num_samples; i++) {
// 提升到 float 32-bit 精度
float v = (float)samples[i];
// 音量缩放
v *= volume;
// 加一点点 dither,打散量化误差
// 简单线性同余随机数(不依赖 rand())
static uint32_t rnd = 0x12345678;
rnd = rnd * 1664525u + 1013904223u;
float noise = ((int32_t)(rnd >> 16) - 32768) * (dither_amp / 32768.0f);
v += noise;
// 高精度四舍五入
float v_rounded = floorf(v + 0.5f * (v >= 0 ? 1.0f : -1.0f));
// 饱和限幅
if (v_rounded > 32767.0f) v_rounded = 32767.0f;
if (v_rounded < -32768.0f) v_rounded = -32768.0f;
samples[i] = (int16_t)v_rounded;
}
}
i2s_write(NS4168_I2S_PORT, buf, n, &written, portMAX_DELAY);
}
md_deinit();
ESP_LOGI("WAV", "WAV播放结束");
}
#include <stdbool.h>
#include "driver/i2s.h"
// 简单的 32-bit 伪随机数,用于 dither
static inline uint32_t prng32(void)
{
static uint32_t s = 0x12345678u;
s = s * 1664525u + 1013904223u;
return s;
}
void play_wav_ring_with_volume(float volume)
{
const char *TAG = "WAV_RING";
uint8_t header[70];
size_t written = 0;
// 初始化并读取 WAV 头
md_init("/extflash/ring2.wav");
md_read(header, sizeof(header));
ESP_LOG_BUFFER_HEX(TAG, header, sizeof(header));
ESP_LOGI(TAG, "WAV解析成功,开始播放");
uint8_t buf[1024];
int n;
// 音量为 1.0 时完全绕过处理,保证绝对无损
bool bypass = (fabsf(volume - 1.0f) < 0.0001f);
// dither 强度(非常小,人耳几乎感知不到)
const float dither_amp = 1.0f / 4096.0f; // 可微调
while ((n = md_read(buf, sizeof(buf))) > 0) {
if (!bypass) {
int16_t *samples = (int16_t *)buf;
int num_samples = n / 2; // 16-bit PCM
for (int i = 0; i < num_samples; i++) {
// 提升到 float 32-bit 精度
float v = (float)samples[i];
// 音量缩放
v *= volume;
// 三角 dither(TDPF):(rand1 - rand2) * scale
uint32_t r1 = prng32();
uint32_t r2 = prng32();
float noise = ((int32_t)(r1 & 0xFFFF) - (int32_t)(r2 & 0xFFFF))
* (dither_amp / 65536.0f);
v += noise;
// 高精度四舍五入
float v_rounded = floorf(v + 0.5f * (v >= 0.0f ? 1.0f : -1.0f));
// 轻微 soft-clip,避免极端削波毛刺
if (v_rounded > 32767.0f) {
float over = v_rounded - 32767.0f;
v_rounded = 32767.0f + over * 0.01f; // 把硬削波变成软削波
} else if (v_rounded < -32768.0f) {
float under = v_rounded + 32768.0f;
v_rounded = -32768.0f + under * 0.01f;
}
// 最终饱和限幅
if (v_rounded > 32767.0f) v_rounded = 32767.0f;
if (v_rounded < -32768.0f) v_rounded = -32768.0f;
samples[i] = (int16_t)v_rounded;
}
}
// 写入 I2S
i2s_write(NS4168_I2S_PORT, buf, n, &written, portMAX_DELAY);
}
md_deinit();
ESP_LOGI(TAG, "WAV播放结束");
}