speaker work
This commit is contained in:
+10
-7
@@ -46,16 +46,22 @@ add_executable(ds5-bridge
|
||||
src/bt.cpp
|
||||
)
|
||||
|
||||
# Cockos WDLResampler
|
||||
add_library(wdl_resampler STATIC
|
||||
lib/WDL/WDL/resample.cpp
|
||||
)
|
||||
|
||||
target_include_directories(wdl_resampler PUBLIC
|
||||
lib/WDL/WDL
|
||||
)
|
||||
|
||||
# Opus
|
||||
set(OPUS_FIXED_POINT ON)
|
||||
add_subdirectory(lib/opus)
|
||||
|
||||
target_compile_options(wdl_resampler PRIVATE -fsigned-char)
|
||||
target_compile_options(ds5-bridge PRIVATE -fsigned-char)
|
||||
target_compile_options(wdl_resampler PRIVATE -DWDL_RESAMPLE_TYPE=float)
|
||||
target_compile_options(ds5-bridge PRIVATE -DWDL_RESAMPLE_TYPE=float)
|
||||
#target_compile_options(ds5-bridge PRIVATE -DENABLE_DSE) # 将PID和产品名称设置为DSE
|
||||
target_compile_definitions(ds5-bridge PRIVATE
|
||||
CYW43_LWIP=0
|
||||
@@ -69,12 +75,6 @@ pico_set_program_version(ds5-bridge "0.3.2")
|
||||
pico_enable_stdio_uart(ds5-bridge 1)
|
||||
pico_enable_stdio_usb(ds5-bridge 0)
|
||||
|
||||
# Add the standard library to the build
|
||||
target_link_libraries(ds5-bridge
|
||||
pico_stdlib
|
||||
pico_multicore
|
||||
)
|
||||
|
||||
# Add the standard include files to the build
|
||||
#target_include_directories(ds5-bridge PRIVATE
|
||||
# ${CMAKE_CURRENT_LIST_DIR}
|
||||
@@ -86,6 +86,8 @@ target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
|
||||
# Add any user requested libraries
|
||||
target_link_libraries(ds5-bridge
|
||||
pico_stdlib
|
||||
pico_multicore
|
||||
hardware_interp
|
||||
hardware_timer
|
||||
pico_btstack_classic
|
||||
@@ -95,6 +97,7 @@ target_link_libraries(ds5-bridge
|
||||
tinyusb_device
|
||||
tinyusb_board
|
||||
wdl_resampler
|
||||
opus
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(ds5-bridge)
|
||||
|
||||
+83
-10
@@ -8,41 +8,73 @@
|
||||
#include "tusb.h"
|
||||
#include "usb.h"
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
||||
#include "opus.h"
|
||||
#include "utils.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "pico/util/queue.h"
|
||||
|
||||
#define INPUT_CHANNELS 4
|
||||
#define OUTPUT_CHANNELS 2
|
||||
#define SAMPLE_SIZE 64
|
||||
#define REPORT_SIZE 142
|
||||
#define REPORT_ID 0x32
|
||||
#define REPORT_SIZE 398
|
||||
#define REPORT_ID 0x36
|
||||
// #define VOLUME_GAIN 2
|
||||
#define BUFFER_LENGTH 48
|
||||
|
||||
static WDL_Resampler resampler;
|
||||
static uint8_t reportSeqCounter = 0;
|
||||
static uint8_t packetCounter = 0;
|
||||
alignas(8) static uint32_t audio_core1_stack[8192];
|
||||
queue_t audio_fifo;
|
||||
queue_t opus_fifo;
|
||||
struct audio_raw_element {
|
||||
int16_t data[480 * 2];
|
||||
};
|
||||
struct opus_element {
|
||||
uint8_t data[200];
|
||||
};
|
||||
|
||||
|
||||
void audio_loop() {
|
||||
// 1. 读取 USB 音频数据
|
||||
if (!tud_audio_available()) return;
|
||||
|
||||
int16_t raw[192]; // 48000 / 3000 = 16, 64 * 16 = 1024
|
||||
uint32_t bytes_read = tud_audio_read(raw, sizeof(raw));
|
||||
int16_t raw[192];
|
||||
uint32_t bytes_read = tud_audio_read(raw, sizeof(raw)); // 每次读入 384 bytes
|
||||
int frames = bytes_read / (INPUT_CHANNELS * sizeof(int16_t));
|
||||
if (frames == 0){
|
||||
if (frames == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
static int16_t audio_buf[480 * 2];
|
||||
static uint audio_buf_pos = 0;
|
||||
// 2. 从4ch中提取ch3/ch4,转换为float输入重采样器
|
||||
WDL_ResampleSample *in_buf;
|
||||
int nframes = resampler.ResamplePrepare(frames, OUTPUT_CHANNELS, &in_buf);
|
||||
|
||||
for (int i = 0; i < nframes; i++) {
|
||||
audio_buf[audio_buf_pos++] = raw[i * INPUT_CHANNELS];
|
||||
audio_buf[audio_buf_pos++] = raw[i * INPUT_CHANNELS + 1];
|
||||
if (audio_buf_pos == 480 * 2) {
|
||||
audio_raw_element element{};
|
||||
memcpy(element.data,audio_buf,480 * 2 * 2);
|
||||
if (queue_is_full(&audio_fifo)){
|
||||
queue_try_remove(&audio_fifo,NULL);
|
||||
}
|
||||
if (!queue_try_add(&audio_fifo,&element)) {
|
||||
printf("[Audio] Warning: audio_fifo add failed\n");
|
||||
}
|
||||
audio_buf_pos = 0;
|
||||
}
|
||||
|
||||
in_buf[i * 2] = (WDL_ResampleSample) raw[i * INPUT_CHANNELS + 2] / 32768.0f;
|
||||
in_buf[i * 2 + 1] = (WDL_ResampleSample) raw[i * INPUT_CHANNELS + 3] / 32768.0f;
|
||||
}
|
||||
|
||||
// 3. 48kHz -> 3kHz 重采样
|
||||
WDL_ResampleSample out_buf[SAMPLE_SIZE]; // 64 floats = 32帧 × 2ch
|
||||
WDL_ResampleSample out_buf[SAMPLE_SIZE]; // 64 floats = 32帧 × 2ch
|
||||
int out_frames = resampler.ResampleOut(out_buf, nframes, SAMPLE_SIZE / OUTPUT_CHANNELS, OUTPUT_CHANNELS);
|
||||
|
||||
static int8_t haptic_buf[SAMPLE_SIZE];
|
||||
@@ -50,15 +82,15 @@ void audio_loop() {
|
||||
|
||||
// 4. 转换为int8并缓冲,满64字节即组包发送
|
||||
for (int i = 0; i < out_frames; i++) {
|
||||
int val_l = (int) (out_buf[i * 2] * 127.0f * (volume[0] ?: 1));
|
||||
int val_r = (int) (out_buf[i * 2 + 1] * 127.0f * (volume[0] ?: 1));
|
||||
int val_l = (int) (out_buf[i * 2] * 127.0f * (volume[0] ? : 1));
|
||||
int val_r = (int) (out_buf[i * 2 + 1] * 127.0f * (volume[0] ? : 1));
|
||||
haptic_buf[haptic_buf_pos++] = (int8_t) std::clamp(val_l, -128, 127); // 似乎clamp有点多余?还是以防万一吧
|
||||
haptic_buf[haptic_buf_pos++] = (int8_t) std::clamp(val_r, -128, 127);
|
||||
|
||||
if (haptic_buf_pos != SAMPLE_SIZE) {
|
||||
continue;
|
||||
}
|
||||
uint8_t pkt[REPORT_SIZE] = {};
|
||||
uint8_t pkt[REPORT_SIZE]{};
|
||||
pkt[0] = REPORT_ID;
|
||||
pkt[1] = reportSeqCounter << 4;
|
||||
reportSeqCounter = (reportSeqCounter + 1) & 0x0F;
|
||||
@@ -74,6 +106,16 @@ void audio_loop() {
|
||||
pkt[11] = 0x12 | (1 << 7);
|
||||
pkt[12] = SAMPLE_SIZE;
|
||||
memcpy(pkt + 13, haptic_buf, SAMPLE_SIZE);
|
||||
if (!queue_is_empty(&opus_fifo)) {
|
||||
pkt[77] = 0x16 | 0 << 6 | 1 << 7;
|
||||
pkt[78] = 200;
|
||||
opus_element opus_element{};
|
||||
if (!queue_try_remove(&opus_fifo,&opus_element)) {
|
||||
printf("[Audio] Warning: opus_fifo try remove failed");
|
||||
}else {
|
||||
memcpy(pkt + 79,opus_element.data,200);
|
||||
}
|
||||
}
|
||||
|
||||
bt_write(pkt, sizeof(pkt));
|
||||
haptic_buf_pos = 0;
|
||||
@@ -84,5 +126,36 @@ void audio_init() {
|
||||
resampler.SetMode(true, 0, false);
|
||||
resampler.SetRates(48000, 3000);
|
||||
resampler.SetFeedMode(true);
|
||||
resampler.Prealloc(2, 480, 32);
|
||||
// resampler.Prealloc(2, 480, 32);
|
||||
queue_init(&audio_fifo,sizeof(audio_raw_element),2);
|
||||
queue_init(&opus_fifo,sizeof(opus_element),2);
|
||||
multicore_launch_core1_with_stack(core1_entry,audio_core1_stack,sizeof(audio_core1_stack));
|
||||
}
|
||||
|
||||
static OpusEncoder *encoder;
|
||||
|
||||
void core1_entry() {
|
||||
int error = 0;
|
||||
encoder = opus_encoder_create(48000,2,OPUS_APPLICATION_AUDIO,&error);
|
||||
if (error != 0) {
|
||||
printf("[Audio] OpusEncoder create failed\n");
|
||||
return;
|
||||
}
|
||||
opus_encoder_ctl(encoder,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_10_MS));
|
||||
opus_encoder_ctl(encoder,OPUS_SET_BITRATE(200 * 8 * 100));
|
||||
opus_encoder_ctl(encoder,OPUS_SET_VBR(false));
|
||||
opus_encoder_ctl(encoder,OPUS_SET_COMPLEXITY(0));
|
||||
|
||||
while (true) {
|
||||
audio_raw_element audio_element{};
|
||||
queue_remove_blocking(&audio_fifo,&audio_element);
|
||||
opus_element opus_element{};
|
||||
(void)opus_encode(encoder,audio_element.data,480,opus_element.data,200);
|
||||
if (queue_is_full(&opus_fifo)) {
|
||||
queue_try_remove(&opus_fifo,NULL);
|
||||
}
|
||||
if (!queue_try_add(&opus_fifo,&opus_element)) {
|
||||
printf("[Audio] Warning: opus_fifo add failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
|
||||
void audio_init();
|
||||
void audio_loop();
|
||||
void core1_entry();
|
||||
|
||||
#endif //DS5_BRIDGE_AUDIO_H
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "utils.h"
|
||||
#include "resample.h"
|
||||
#include "audio.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
int reportSeqCounter = 0;
|
||||
@@ -84,6 +85,7 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep
|
||||
}
|
||||
|
||||
int main() {
|
||||
set_sys_clock_khz(270000, true);
|
||||
board_init();
|
||||
|
||||
tusb_rhport_init_t dev_init = {
|
||||
|
||||
+10
-1
@@ -3,6 +3,8 @@
|
||||
//
|
||||
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "hci_cmd.h"
|
||||
|
||||
@@ -212,4 +214,11 @@ struct __attribute__((packed)) USBGetStateData { // 63
|
||||
/*54.1*/ uint8_t HapticLowPassFilter : 1; // Is the Haptic Low-Pass-Filter active?
|
||||
/*54.2*/ uint8_t PluggedUnk3 : 6;
|
||||
/*55 */ uint8_t AesCmac[8];
|
||||
};
|
||||
};
|
||||
|
||||
inline void print_hex(const int16_t* data,size_t size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
Reference in New Issue
Block a user