Adding USB-audio feedback and mute command to usb_sound_card.c

USB-audio feedback (USB AudioStreaming Isochronous Feedback) is indispensable for stable sound playback without clicking noise. I added simple feedback function by checking the vacancy of the buffer. To avoid modifying other sources (such as audio.cpp in pico-extras), number of free buffers is checked in this source code.

USB audio also has mute function (mute without changing volume value). I also added this function (in the original source code, it is almost done, so I added just three lines).
pull/53/head
Shinsaku Hiura 2025-01-01 13:33:39 +09:00 zatwierdzone przez GitHub
rodzic 49a701a955
commit 18d01f3ec6
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
1 zmienionych plików z 48 dodań i 0 usunięć

Wyświetl plik

@ -17,6 +17,17 @@
// todo forget why this is using core 1 for sound: presumably not necessary
// todo noop when muted
// modification for USB-sound rate feedback and mute
#define USB_FEEDBACK 1 // USB-audio rate feedback using buffer status
#define MUTE_CMD 1 // mute command
// connected pins from RPi to DAC
#undef PICO_AUDIO_I2S_DATA_PIN
#define PICO_AUDIO_I2S_DATA_PIN 26
#undef PICO_AUDIO_I2S_CLOCK_PIN_BASE
#define PICO_AUDIO_I2S_CLOCK_PIN_BASE 27
////////////////////////////////////////
CU_REGISTER_DEBUG_PINS(audio_timing)
// ---- select at most one ---
@ -40,7 +51,12 @@ static char *descriptor_strings[] =
#undef AUDIO_SAMPLE_FREQ
#define AUDIO_SAMPLE_FREQ(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16))
#if USB_FEEDBACK
// when USB-audio feedback applies, it receives upto 49 samples in each packet
#define AUDIO_MAX_PACKET_SIZE(freq) (uint8_t)(((freq + 1999) / 1000) * 4)
#else
#define AUDIO_MAX_PACKET_SIZE(freq) (uint8_t)(((freq + 999) / 1000) * 4)
#endif
#define FEATURE_MUTE_CONTROL 1u
#define FEATURE_VOLUME_CONTROL 2u
@ -256,6 +272,22 @@ static struct {
static struct audio_buffer_pool *producer_pool;
#if USB_FEEDBACK
#define BUFFER_NUM 16 // number of buffer
//for USB-audio rate feedback, number of vacant buffers is used
static int countFreeBuffers(void) {
int i = 0;
audio_buffer_t *audio_buffer = producer_pool->free_list;
while(audio_buffer != NULL) {
audio_buffer = audio_buffer->next;
i++;
}
return i;
}
#endif
static void _as_audio_packet(struct usb_endpoint *ep) {
assert(ep->current_transfer);
struct usb_buffer *usb_buffer = usb_current_out_packet_buffer(ep);
@ -268,6 +300,11 @@ static void _as_audio_packet(struct usb_endpoint *ep) {
assert(audio_buffer->sample_count);
assert(audio_buffer->max_sample_count >= audio_buffer->sample_count);
uint16_t vol_mul = audio_state.vol_mul;
#if MUTE_CMD
if(audio_state.mute) {
vol_mul = 1;
}
#endif
int16_t *out = (int16_t *) audio_buffer->buffer->bytes;
int16_t *in = (int16_t *) usb_buffer->data;
for (int i = 0; i < audio_buffer->sample_count * 2; i++) {
@ -288,8 +325,14 @@ static void _as_sync_packet(struct usb_endpoint *ep) {
assert(buffer->data_max >= 3);
buffer->data_len = 3;
#if USB_FEEDBACK
// calc rate adjustment value between -40 to 40
int feedbackvalue = (countFreeBuffers() - BUFFER_NUM / 2) * (2 * 40 / BUFFER_NUM);
uint feedback = ((audio_state.freq + feedbackvalue) << 14u) / 1000u;
#else
// todo lie thru our teeth for now
uint feedback = (audio_state.freq << 14u) / 1000u;
#endif
buffer->data[0] = feedback;
buffer->data[1] = feedback >> 8u;
@ -613,7 +656,12 @@ int main(void) {
.sample_stride = 4
};
#if USB_FEEDBACK
// when USB-audio feedback applies, it receives upto 49 samples in each packet
producer_pool = audio_new_producer_pool(&producer_format, BUFFER_NUM, 48 + 1);
#else
producer_pool = audio_new_producer_pool(&producer_format, 8, 48); // todo correct size
#endif
bool __unused ok;
struct audio_i2s_config config = {
.data_pin = PICO_AUDIO_I2S_DATA_PIN,