#include #include "esp_log.h" #include "NS4168/micro_decoder_wrapper.h" #include "NS4168/wav_demux.h" #include "NS4168/ns4168.h" #include #include #include 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 #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播放结束"); }