Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
8 years, 6 months ago.
Getting doubles of USB audio packages
With the folllowing code it looks like the USB packages comes two times. Can the usb audio-driver in Win7 be wrong or where to start looking for error?
// USBAudio speaker example #include "mbed.h" #include "USBAudio.h" // frequency: 48 kHz #define FREQ 48000 // 1 channel: mono #define NB_CHA 1 // length of an audio packet: each ms, we receive 48 * 16bits ->48 * 2 bytes. as there is one channel, the length will be 48 * 2 * 1 #define AUDIO_LENGTH_PACKET (FREQ / 1000) * 2 * NB_CHA // USBAudio (we just use audio packets received, we don't send audio packets to the computer in this example) USBAudio audio(FREQ, NB_CHA, 8000, 1, 0x7180, 0x7500); // speaker connected to the AnalogOut output. The audio stream received over USb will be sent to the speaker AnalogOut DAC(DAC0_OUT); DigitalOut gpo(PTC1); // ticker to send data to the speaker at the good frequency Ticker tic; // buffer where will be store one audio packet (LENGTH_AUDIO_PACKET/2 because we are storing int16 and not uint8) int16_t buf[AUDIO_LENGTH_PACKET/2]; // show if an audio packet is available volatile bool available = false; // index of the value which will be send to the speaker int index_buf = 0; // previous value sent to the speaker uint16_t p_val = 0; // function executed each 1/FREQ s void tic_handler() { float speaker_value; if (available) { speaker_value = (float)(buf[index_buf]); //convert 2 bytes in float speaker_value += 32768.0; // speaker_value between 0 and 65535 //temp = audio.getVolume(); // get current volume (dont use) index_buf++; // as two bytes has been read, we move the index of two bytes if (index_buf == AUDIO_LENGTH_PACKET / 2 ) { // if we have read all the buffer, no more data available index_buf = 0; available = false; } } else { speaker_value = p_val; // keep last value if no new } p_val = speaker_value; DAC.write_u16((uint16_t)speaker_value); // send value to the speaker } int main() { wait_ms(3); // wait for 3 packages? tic.attach_us(tic_handler, 1000000.0/(float)FREQ + 1 ); // attach a function executed each 1/FREQ s while (1) { static int n = true; audio.read((uint8_t *)buf); //if (n == true) available = true; n = !n; // toggle gpo = n; // out on PTC1 } }
Question relating to:
1 Answer
8 years, 6 months ago.
Your main while loop is reading one audio packet per ms. Once the packet is received it sets available to true and starts receiving the next packet into the buffer.
At the same time your tic_handler is outputting the data in the buffer and once it finishes it sets available to false.
You have a race condition, if things happen in the wrong order you skip every other packet of data:
Packet 1 arrives.
Available becomes true
tic_handler starts outputting data.
1ms later packet 2 finishes arriving
Available is set to true.
tic_handler finishes outputting the first packet and sets available to false.
available is false so nothing further is output.
packet 3 arrives.
Available is set to true.
tic_handler starts outputting data again.
You also have the bug that you are reading out of the same buffer as data is being written into, this could give you some nasty audio glitches.
You can fix both problems by having two buffers, while bufferA is being received you output from bufferB, once buffer A is complete you switch and start outputting from A while receiving into B. If you use pointers to the buffers you can avoid having if statements on every buffer read so there is only a minimal performance hit.
By switching buffers once the frame has been received rather than once you've finished outputting a full buffer you make skip the odd sample but that's better than the alternative of gradually falling more and more behind.
And on a performance point, when adding the offset to the output value it would be far more efficient to cast to an int32 add 32768 and cast to a uint16 than the current method of converting to a float and back.
I don't have the means to test this but I think this should do what you want.
// USBAudio speaker example #include "mbed.h" #include "USBAudio.h" // frequency: 48 kHz #define FREQ 48000 // 1 channel: mono #define NB_CHA 1 // length of an audio packet: each ms, we receive 48 * 16bits ->48 * 2 bytes. as there is one channel, the length will be 48 * 2 * 1 #define AUDIO_LENGTH_PACKET (FREQ / 1000) * 2 * NB_CHA // USBAudio (we just use audio packets received, we don't send audio packets to the computer in this example) USBAudio audio(FREQ, NB_CHA, 8000, 1, 0x7180, 0x7500); // speaker connected to the AnalogOut output. The audio stream received over USb will be sent to the speaker AnalogOut DAC(DAC0_OUT); DigitalOut gpo(PTC1); // ticker to send data to the speaker at the good frequency Ticker tic; // buffer where will be store one audio packet (LENGTH_AUDIO_PACKET/2 because we are storing int16 and not uint8) int16_t bufA[AUDIO_LENGTH_PACKET/2]; int16_t bufB[AUDIO_LENGTH_PACKET/2]; // show if an audio packet is available volatile bool available = false; int16_t *rxBuffer = NULL; int16_t *txBuffer = NULL; // index of the value which will be send to the speaker volatile int index_buf = 0; // function executed each 1/FREQ s void tic_handler() { // previous value sent to the speaker static uint16_t p_val = 32768; // start mid range. int32_t speaker_value; if (txBuffer) { speaker_value = (int32_t)(txBuffer[index_buf]); speaker_value += 32768; // speaker_value between 0 and 65535 //temp = audio.getVolume(); // get current volume (dont use) index_buf++; // as two bytes has been read, we move the index of two bytes if (index_buf == AUDIO_LENGTH_PACKET / 2 ) { // if we have read all the buffer, no more data available txBuffer = NULL; } p_val = (uint16_t) speaker_value; } DAC.write_u16(p_val); // send value to the speaker } int main() { rxBuffer = bufA; wait_ms(3); // wait for 3 packages? tic.attach_us(tic_handler, 1000000.0/(float)FREQ + 1 ); // attach a function executed each 1/FREQ s int n = true; while (1) { audio.read((uint8_t *)rxBuffer); __disable_irq(); // switch buffers - to be safe make sure we don't get interrupted while doing this. index_buf = 0; txBuffer = rxBuffer; __enable_irq(); if (rxBuffer == bufA) // switch to the next buffer rxBuffer = bufB; else rxBuffer = bufA; n = !n; // toggle gpo = n; // out on PTC1 } }
Please edit to use
posted by Andy A 27 Oct 2015<<code>>
not <code>, the preview button is there for a reason.Ok, edited that.
posted by Anders Eriksson 27 Oct 2015Thanks.
posted by Andy A 27 Oct 2015