Implement application specific behavior of an Audio Device Class (ADC) USB Device.
More...
Implement application specific behavior of an Audio Device Class (ADC) USB Device.
Use the following class specific functions to customize the functionality of an Audio Device Class (ADC) Device. Adapt these functions in the user code template file USBD_User_ADC_n.c.
The USB Component allows multiple instances of the ADC class. This feature is used to create USB Composite Devices. Each ADC class instance has a separate files and interface functions:
The following source code can be used to implement the application specific behavior of an USB ADC Device.
The following source code can be used to implement the application specific behavior of an USB ADC Headphone Device.
#include <stdint.h>
#include <stdbool.h>
#include "rl_usb.h"
#include ".\RTE\USB\USBD_Config_ADC_n.h"
#include "Board_Audio.h"
#define RECORD_BUFFER_SIZE_USB (USBD_ADC0_IN_BUF_SIZE)
#define PLAYBACK_BUFFER_SIZE_USB (USBD_ADC0_OUT_BUF_SIZE)
#define RECORD_CHANNELS 1 // Mono microphone = 1 channel (stereo not implemented)
#define RECORD_BUFFER_SIZE_AUDIO 64 // In samples (64 mono samples at 32 kHz = 2 ms of samples)
#define RECORD_SAMPLE_CORRECTION_COUNTER (100/2) // 100 ms / 2 ms of samples (compensates 625 ppm clock difference)
#define PLAYBACK_CHANNELS 2 // Stereo speakers = 2 channels (mono not implemented)
#define PLAYBACK_BUFFER_SIZE_AUDIO 128 // Out samples (128 stereo samples at 32 kHz = 2 ms samples)
#define PLAYBACK_SAMPLE_CORRECTION_COUNTER (100/2) // 100 ms / 2 ms of samples (compensates 625 ppm clock difference)
static osThreadId play_buf_tid = 0 ;
static volatile bool play = false;
static uint8_t play_buf_index = 0 ;
static int16_t play_buf[2][PLAYBACK_BUFFER_SIZE_AUDIO+2] = { 0 };
static int32_t play_num = { 0 };
static int32_t play_add = 0 ;
static uint16_t play_sample_correction_cnt = 0 ;
static uint8_t rec_buf_index = 0 ;
static int16_t rec_buf[2][RECORD_BUFFER_SIZE_AUDIO+1] = { 0 };
static int32_t rec_num = 0 ;
static int32_t rec_add = 0 ;
static uint16_t rec_sample_correction_cnt = 0 ;
void AudioPlaybackInitialBufferingThreadn (void const *arg) {
uint32_t play_samples_available;
int32_t play_num0;
while (1) {
if (!play && (play_samples_available > (PLAYBACK_BUFFER_SIZE_USB / 2))) {
play = true;
play_buf_index = 1;
Audio_SendData (&play_buf[0][0], play_num0);
}
if (play && !play_samples_available) {
play = false;
}
osDelay(10);
}
}
osThreadDef (AudioPlaybackInitialBufferingThreadn, osPriorityNormal, 1, 0);
static void AudioCallback (uint32_t event) {
uint32_t rec_samples_pending;
int32_t rec_num_last;
uint8_t rec_correct_sample;
uint32_t play_samples_available;
int32_t play_num_last;
uint8_t play_correct_sample;
if (event & AUDIO_EVENT_RECEIVE_COMPLETE) {
rec_num_last = rec_num;
rec_num = RECORD_BUFFER_SIZE_AUDIO;
Audio_ReceiveData (&rec_buf[rec_buf_index ^ 1][0], rec_num);
rec_correct_sample = 0;
if (rec_sample_correction_cnt++ >= RECORD_SAMPLE_CORRECTION_COUNTER) {
rec_sample_correction_cnt = 0;
rec_correct_sample = 1;
}
if (rec_samples_pending < RECORD_BUFFER_SIZE_USB/8) {
rec_add = 0;
} else if (rec_samples_pending < RECORD_BUFFER_SIZE_USB/4) {
rec_add = 1;
} else if ((rec_samples_pending > 3*RECORD_BUFFER_SIZE_USB/8) &&
(rec_samples_pending < 5*RECORD_BUFFER_SIZE_USB/8)) {
rec_add = 0;
} else if (rec_samples_pending > 3*RECORD_BUFFER_SIZE_USB/4) {
rec_add = -1;
}
if (rec_correct_sample) {
if (rec_add == -1) {
rec_buf[rec_buf_index][rec_num_last-2] = (rec_buf[rec_buf_index][rec_num_last-3] +
rec_buf[rec_buf_index][rec_num_last-2] +
rec_buf[rec_buf_index][rec_num_last-1] +
rec_buf[rec_buf_index][rec_num_last ])/4;
rec_buf[rec_buf_index][rec_num_last-1] = rec_buf[rec_buf_index][rec_num_last ];
}
if (rec_add == 1) {
rec_buf[rec_buf_index][rec_num_last+1] = rec_buf[rec_buf_index][rec_num_last ];
rec_buf[rec_buf_index][rec_num_last] = (rec_buf[rec_buf_index][rec_num_last-1] +
rec_buf[rec_buf_index][rec_num_last+1])/2;
}
}
USBD_ADC_WriteSamples (n, &rec_buf[rec_buf_index][0], rec_num_last + (rec_add*RECORD_CHANNELS*rec_correct_sample));
rec_buf_index ^= 1;
}
if (event & AUDIO_EVENT_SEND_COMPLETE) {
if (play) {
play_num_last = play_num;
play_correct_sample = 0;
if (play_sample_correction_cnt++ >= PLAYBACK_SAMPLE_CORRECTION_COUNTER) {
play_sample_correction_cnt = 0;
play_correct_sample = 1;
}
if (play_samples_available < PLAYBACK_BUFFER_SIZE_USB/8) {
rec_add = 0;
} else if (play_samples_available < PLAYBACK_BUFFER_SIZE_USB/4) {
rec_add = 1;
} else if ((play_samples_available > 3*PLAYBACK_BUFFER_SIZE_USB/8) &&
(play_samples_available < 5*PLAYBACK_BUFFER_SIZE_USB/8)) {
rec_add = 0;
} else if (play_samples_available > 3*PLAYBACK_BUFFER_SIZE_USB/4) {
rec_add = -1;
}
if (play_correct_sample) {
if (play_add == -1) {
if (play_num >= 8) {
play_buf[play_buf_index][play_num-6] = (play_buf[play_buf_index][play_num-8] +
play_buf[play_buf_index][play_num-6] +
play_buf[play_buf_index][play_num-4] +
play_buf[play_buf_index][play_num-2])/4;
play_buf[play_buf_index][play_num-5] = (play_buf[play_buf_index][play_num-7] +
play_buf[play_buf_index][play_num-5] +
play_buf[play_buf_index][play_num-3] +
play_buf[play_buf_index][play_num-1])/4;
play_buf[play_buf_index][play_num-4] = play_buf[play_buf_index][play_num-2];
play_buf[play_buf_index][play_num-3] = play_buf[play_buf_index][play_num-1];
}
}
if (play_add == 1) {
if (play_num >= 4) {
play_buf[play_buf_index][play_num] = play_buf[play_buf_index][play_num-2];
play_buf[play_buf_index][play_num+1] = play_buf[play_buf_index][play_num-1];
play_buf[play_buf_index][play_num-2] = (play_buf[play_buf_index][play_num-4] +
play_buf[play_buf_index][play_num ])/2;
play_buf[play_buf_index][play_num-1] = (play_buf[play_buf_index][play_num-3] +
play_buf[play_buf_index][play_num+1])/2;
}
}
}
if (play_num_last > 0) {
Audio_SendData (&play_buf[play_buf_index][0], play_num + (play_add*PLAYBACK_CHANNELS*play_correct_sample));
play_buf_index ^= 1;
play_num =
USBD_ADC_ReadSamples (n, (
void *)(&play_buf[play_buf_index][0]), PLAYBACK_BUFFER_SIZE_AUDIO);
}
}
}
}
Audio_Initialize (&AudioCallback);
Audio_SetDataFormat (AUDIO_STREAM_OUT, AUDIO_DATA_16_STEREO);
Audio_SetFrequency (AUDIO_STREAM_OUT, 32000);
Audio_SetMute (AUDIO_STREAM_OUT, AUDIO_CHANNEL_MASTER, false);
Audio_SetVolume (AUDIO_STREAM_OUT, AUDIO_CHANNEL_MASTER, 50);
Audio_Start (AUDIO_STREAM_OUT);
Audio_SetFrequency (AUDIO_STREAM_IN, 32000);
Audio_SetDataFormat (AUDIO_STREAM_IN, AUDIO_DATA_16_MONO);
Audio_SetMute (AUDIO_STREAM_IN, AUDIO_CHANNEL_MASTER, false);
Audio_SetVolume (AUDIO_STREAM_IN, AUDIO_CHANNEL_MASTER, 50);
}
Audio_Uninitialize ();
}
if (active) {
Audio_Start (AUDIO_STREAM_OUT);
play_buf_tid = osThreadCreate (osThread (AudioPlaybackInitialBufferingThreadn), NULL);
} else {
if (play_buf_tid) {
if (osThreadTerminate (play_buf_tid) == osOK) { play_buf_tid = 0; }
}
Audio_Stop (AUDIO_STREAM_OUT);
}
}
Audio_SetMute (AUDIO_STREAM_OUT, AUDIO_CHANNEL_MASTER, cur);
}
Audio_SetVolume (AUDIO_STREAM_OUT, ch, cur);
}
if (active) {
rec_num = RECORD_BUFFER_SIZE_AUDIO;
rec_buf_index = 0;
Audio_ReceiveData(&rec_buf[0][0],rec_num);
Audio_Start (AUDIO_STREAM_IN);
} else {
Audio_Stop (AUDIO_STREAM_IN);
}
}
Audio_SetMute (AUDIO_STREAM_IN, AUDIO_CHANNEL_MASTER, cur);
}
Audio_SetVolume (AUDIO_STREAM_IN, ch, cur);
}