Forum Rule: Always post complete source code & details to reproduce any issue!
Page 4 of 4 FirstFirst ... 2 3 4
Results 76 to 92 of 92

Thread: USB Audio Clicking Noise

  1. #76
    Senior Member
    Join Date
    Apr 2014
    Posts
    363
    This works perfectly now that the #ifdefs are added...........

  2. #77
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    Great!
    Does it work with Linux, too?

  3. #78
    Senior Member
    Join Date
    Apr 2014
    Posts
    363
    Yes, works on Linux Lubuntu 18.04 and windows 10 on Pentium. Both behave similar.
    Tested with setI2S_freq at ..... 44000, 44100, 44112 and all worked no clicks. Tested at 44116 for both and heard clicks.
    Didn't try winXP but should be OK, should be same.

  4. #79
    Senior Member
    Join Date
    Apr 2014
    Posts
    363
    Tried on Windows XP and clicking is still there. Plays about 6 seconds clear and then clicking starts.
    I am replacing my windows XP so for me not worth pursuing this XP problem any further. Windows 10 and Linux work well now.

    If I compile and program teensy on Windows XP I get clicks when recorded and played back on both windows XP and windows 10 machines.

    If I compile and program teensy on windows 10 I get clear recording no clicks when recorded and played back on both windows 10 and windows XP machines.
    Last edited by Teenfor3; 11-26-2018 at 12:30 AM. Reason: added 2 lines about compiling on either machine

  5. #80
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    Thank you for testing! I don't care about XP.

  6. #81
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    26,389
    I have no plans to ever test this on Windows XP or Vista. When I do work on it, which very likely may be late in 2019, the oldest version I'm going to test will be Windows 7.

  7. #82
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,600
    Sorry, have been absent for a few days, had to teach music in Germany. Will give FrankB's workaround a try on macOS very soon.

  8. #83
    Senior Member
    Join Date
    Jan 2019
    Posts
    109
    Frank, your code works but i think it introduced a bug.
    When I click record and stop in quick succession, the usb device quits communicating sound to the PC.
    I have to unplug/replug device for it to work again.
    This happens regardless of the software being used (tested 2).

  9. #84
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    This thread was 2018.
    I don't hear any clicking noise now, without any changes.

  10. #85
    Senior Member
    Join Date
    Jan 2019
    Posts
    109
    OK. Probably because i'm using the teensyduino install from about 2019 or so.

    Did they change anything in the code regarding that? Do you know?

  11. #86
    I realize this is a really old thread, but I’m having this same “clicking” issue on a Teensy 4.0 and Teensyduino 1.56 (on Mac) when using USB Audio.

    It happens when running the simple sine wave sketches earlier in this thread. The clicking starts after like 1min 40sec. Audio sample below.

    From Frank B’s last response it seems like this was fixed, but it’s still happening for me. I couldn’t get his workaround going since I couldn’t find Audiotiming library either. Any ideas? Thank you!

    clicking.zip
    Last edited by mattkuebrich; 05-22-2022 at 05:07 PM.

  12. #87
    Senior Member
    Join Date
    Apr 2014
    Posts
    363
    I was only testing on windows10 and Linux for Teensy3.2. FrankB_Patch worked for me as described in #75. You need to add the bits in RED text #DEFINE and #ifdefs etc.
    This is location for file for Teensy3.2 Teensyduino version 1.53. copy of link in #75
    Here is the file audio_usb.cpp that needs to be swapped in [...]/hardware/teensy/avr/cores/teensy3 :
    I assume for teensy4.0 it is as below .....the file is now called usb_audio.cpp in Teensyduino 1.53
    Here is the file usb_audio.cpp that needs to be swapped in [...]/hardware/teensy/avr/cores/teensy4 :
    Because it is an old thread and newer versions since you are probably better reading the patch mods and manual edit rather then copy the entire file...????

  13. #88
    Thanks for responding! I just tried adapting the newer usb_audio.cpp file with the FrankB patches, but am still getting the clicks. Instead of the Audiotiming library (which is missing from FrankB's Github), I tried using this function to change the sample rate to 44099.7 as Frank suggested, but that didnít help either.

    Here's the usb_audio.cpp file (from the cores/teensy4 folder) with the FrankB changes added as best I could. I don't know what they are actually doing so could have screwed something up.

    Code:
    /* Teensyduino Core Library
     * http://www.pjrc.com/teensy/
     * Copyright (c) 2017 PJRC.COM, LLC.
     *
     * Permission is hereby granted, free of charge, to any person obtaining
     * a copy of this software and associated documentation files (the
     * "Software"), to deal in the Software without restriction, including
     * without limitation the rights to use, copy, modify, merge, publish,
     * distribute, sublicense, and/or sell copies of the Software, and to
     * permit persons to whom the Software is furnished to do so, subject to
     * the following conditions:
     *
     * 1. The above copyright notice and this permission notice shall be
     * included in all copies or substantial portions of the Software.
     *
     * 2. If the Software is incorporated into a build system that allows
     * selection among a list of target devices, then similar target
     * devices manufactured by PJRC.COM must be included in the list of
     * target devices and selectable in the same manner.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     * SOFTWARE.
     */
    
    #include <Arduino.h>
    #include "usb_dev.h"
    #include "usb_audio.h"
    #include "debug/printf.h"
    
    #ifdef AUDIO_INTERFACE
    
    bool AudioInputUSB::update_responsibility;
    audio_block_t * AudioInputUSB::incoming_left;
    audio_block_t * AudioInputUSB::incoming_right;
    audio_block_t * AudioInputUSB::ready_left;
    audio_block_t * AudioInputUSB::ready_right;
    uint16_t AudioInputUSB::incoming_count;
    uint8_t AudioInputUSB::receive_flag;
    
    struct usb_audio_features_struct AudioInputUSB::features = {0,0,FEATURE_MAX_VOLUME/2};
    
    extern volatile uint8_t usb_high_speed;
    static void rx_event(transfer_t *t);
    static void tx_event(transfer_t *t);
    
    /*static*/ transfer_t rx_transfer __attribute__ ((used, aligned(32)));
    /*static*/ transfer_t sync_transfer __attribute__ ((used, aligned(32)));
    /*static*/ transfer_t tx_transfer __attribute__ ((used, aligned(32)));
    DMAMEM static uint8_t rx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(32)));
    DMAMEM static uint8_t tx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(32)));
    DMAMEM uint32_t usb_audio_sync_feedback __attribute__ ((aligned(32)));
    
    uint8_t usb_audio_receive_setting=0;
    uint8_t usb_audio_transmit_setting=0;
    uint8_t usb_audio_sync_nbytes;
    uint8_t usb_audio_sync_rshift;
    
    uint32_t feedback_accumulator;
    
    volatile uint32_t usb_audio_underrun_count;
    volatile uint32_t usb_audio_overrun_count;
    
    
    static void rx_event(transfer_t *t)
    {
    	if (t) {
    		int len = AUDIO_RX_SIZE - ((rx_transfer.status >> 16) & 0x7FFF);
    		printf("rx %u\n", len);
    		usb_audio_receive_callback(len);
    	}
    	usb_prepare_transfer(&rx_transfer, rx_buffer, AUDIO_RX_SIZE, 0);
    	arm_dcache_delete(&rx_buffer, AUDIO_RX_SIZE);
    	usb_receive(AUDIO_RX_ENDPOINT, &rx_transfer);
    }
    
    static void sync_event(transfer_t *t)
    {
    	// USB 2.0 Specification, 5.12.4.2 Feedback, pages 73-75
    	//printf("sync %x\n", sync_transfer.status); // too slow, can't print this much
    	usb_audio_sync_feedback = feedback_accumulator >> usb_audio_sync_rshift;
    	usb_prepare_transfer(&sync_transfer, &usb_audio_sync_feedback, usb_audio_sync_nbytes, 0);
    	arm_dcache_flush(&usb_audio_sync_feedback, usb_audio_sync_nbytes);
    	usb_transmit(AUDIO_SYNC_ENDPOINT, &sync_transfer);
    }
    
    void usb_audio_configure(void)
    {
    	printf("usb_audio_configure\n");
    	usb_audio_underrun_count = 0;
    	usb_audio_overrun_count = 0;
    	feedback_accumulator = 739875226; // 44.1 * 2^24
    	if (usb_high_speed) {
    		usb_audio_sync_nbytes = 4;
    		usb_audio_sync_rshift = 8;
    	} else {
    		usb_audio_sync_nbytes = 3;
    		usb_audio_sync_rshift = 10;
    	}
    	memset(&rx_transfer, 0, sizeof(rx_transfer));
    	usb_config_rx_iso(AUDIO_RX_ENDPOINT, AUDIO_RX_SIZE, 1, rx_event);
    	rx_event(NULL);
    	memset(&sync_transfer, 0, sizeof(sync_transfer));
    	usb_config_tx_iso(AUDIO_SYNC_ENDPOINT, usb_audio_sync_nbytes, 1, sync_event);
    	sync_event(NULL);
    	memset(&tx_transfer, 0, sizeof(tx_transfer));
    	usb_config_tx_iso(AUDIO_TX_ENDPOINT, AUDIO_TX_SIZE, 1, tx_event);
    	tx_event(NULL);
    }
    
    void AudioInputUSB::begin(void)
    {
    	incoming_count = 0;
    	incoming_left = NULL;
    	incoming_right = NULL;
    	ready_left = NULL;
    	ready_right = NULL;
    	receive_flag = 0;
    	// update_responsibility = update_setup();
    	// TODO: update responsibility is tough, partly because the USB
    	// interrupts aren't sychronous to the audio library block size,
    	// but also because the PC may stop transmitting data, which
    	// means we no longer get receive callbacks from usb.c
    	update_responsibility = false;
    }
    
    static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len)
    {
    	uint32_t *target = (uint32_t*) src + len;
    	while ((src < target) && (((uintptr_t) left & 0x02) != 0)) {
    		uint32_t n = *src++;
    		*left++ = n & 0xFFFF;
    		*right++ = n >> 16;
    	}
    
    	while ((src < target - 2)) {
    		uint32_t n1 = *src++;
    		uint32_t n = *src++;
    		*(uint32_t *)left = (n1 & 0xFFFF) | ((n & 0xFFFF) << 16);
    		left+=2;
    		*(uint32_t *)right = (n1 >> 16) | ((n & 0xFFFF0000)) ;
    		right+=2;
    	}
    
    	while ((src < target)) {
    		uint32_t n = *src++;
    		*left++ = n & 0xFFFF;
    		*right++ = n >> 16;
    	}
    }
    
    // Called from the USB interrupt when an isochronous packet arrives
    // we must completely remove it from the receive buffer before returning
    //
    #if 1
    void usb_audio_receive_callback(unsigned int len)
    {
    	unsigned int count, avail;
    	audio_block_t *left, *right;
    	const uint32_t *data;
    
    	AudioInputUSB::receive_flag = 1;
    	len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right
    	data = (const uint32_t *)rx_buffer;
    
    	count = AudioInputUSB::incoming_count;
    	left = AudioInputUSB::incoming_left;
    	right = AudioInputUSB::incoming_right;
    	if (left == NULL) {
    		left = AudioStream::allocate();
    		if (left == NULL) return;
    		AudioInputUSB::incoming_left = left;
    	}
    	if (right == NULL) {
    		right = AudioStream::allocate();
    		if (right == NULL) return;
    		AudioInputUSB::incoming_right = right;
    	}
    	while (len > 0) {
    		avail = AUDIO_BLOCK_SAMPLES - count;
    		if (len < avail) {
    			copy_to_buffers(data, left->data + count, right->data + count, len);
    			AudioInputUSB::incoming_count = count + len;
    			return;
    		} else if (avail > 0) {
    			copy_to_buffers(data, left->data + count, right->data + count, avail);
    			data += avail;
    			len -= avail;
    			if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) {
    				// buffer overrun, PC sending too fast
    				AudioInputUSB::incoming_count = count + avail;
    				if (len > 0) {
    					usb_audio_overrun_count++;
    					printf("!");
    					//serial_phex(len);
    				}
    				return;
    			}
    			send:
    			AudioInputUSB::ready_left = left;
    			AudioInputUSB::ready_right = right;
    			//if (AudioInputUSB::update_responsibility) AudioStream::update_all();
    			left = AudioStream::allocate();
    			if (left == NULL) {
    				AudioInputUSB::incoming_left = NULL;
    				AudioInputUSB::incoming_right = NULL;
    				AudioInputUSB::incoming_count = 0;
    				return;
    			}
    			right = AudioStream::allocate();
    			if (right == NULL) {
    				AudioStream::release(left);
    				AudioInputUSB::incoming_left = NULL;
    				AudioInputUSB::incoming_right = NULL;
    				AudioInputUSB::incoming_count = 0;
    				return;
    			}
    			AudioInputUSB::incoming_left = left;
    			AudioInputUSB::incoming_right = right;
    			count = 0;
    		} else {
    			if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) return;
    			goto send; // recover from buffer overrun
    		}
    	}
    	AudioInputUSB::incoming_count = count;
    }
    #endif
    
    void AudioInputUSB::update(void)
    {
    	audio_block_t *left, *right;
    
    	__disable_irq();
    	left = ready_left;
    	ready_left = NULL;
    	right = ready_right;
    	ready_right = NULL;
    	uint16_t c = incoming_count;
    	uint8_t f = receive_flag;
    	receive_flag = 0;
    	__enable_irq();
    	if (f) {
    		int diff = AUDIO_BLOCK_SAMPLES/2 - (int)c;
    		feedback_accumulator += diff * 1;
    		//uint32_t feedback = (feedback_accumulator >> 8) + diff * 100;
    		//usb_audio_sync_feedback = feedback;
    
    		//printf(diff >= 0 ? "." : "^");
    	}
    	//serial_phex(c);
    	//serial_print(".");
    	if (!left || !right) {
    		usb_audio_underrun_count++;
    		//printf("#"); // buffer underrun - PC sending too slow
    		if (f) feedback_accumulator += 3500;
    	}
    	if (left) {
    		transmit(left, 0);
    		release(left);
    	}
    	if (right) {
    		transmit(right, 1);
    		release(right);
    	}
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #if 1
    bool AudioOutputUSB::update_responsibility;
    audio_block_t * AudioOutputUSB::left_1st;
    audio_block_t * AudioOutputUSB::left_2nd;
    audio_block_t * AudioOutputUSB::right_1st;
    audio_block_t * AudioOutputUSB::right_2nd;
    uint16_t AudioOutputUSB::offset_1st;
    
    /*DMAMEM*/ uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] __attribute__ ((used, aligned(32)));
    
    
    static void tx_event(transfer_t *t)
    {
    	int len = usb_audio_transmit_callback();
    	usb_audio_sync_feedback = feedback_accumulator >> usb_audio_sync_rshift;
    	usb_prepare_transfer(&tx_transfer, usb_audio_transmit_buffer, len, 0);
    	arm_dcache_flush_delete(usb_audio_transmit_buffer, len);
    	usb_transmit(AUDIO_TX_ENDPOINT, &tx_transfer);
    }
    
    
    void AudioOutputUSB::begin(void)
    {
    	update_responsibility = false;
    	left_1st = NULL;
    	right_1st = NULL;
    }
    
    static void copy_from_buffers(uint32_t *dst, int16_t *left, int16_t *right, unsigned int len)
    {
    	// TODO: optimize...
    	while (len > 0) {
    		*dst++ = (*right++ << 16) | (*left++ & 0xFFFF);
    		len--;
    	}
    }
    
    void AudioOutputUSB::update(void)
    {
    	audio_block_t *left, *right;
    
    	// TODO: we shouldn't be writing to these......
    	#ifdef FRANKB_PATCH
    
    	//left = receiveReadOnly(0); // input 0 = left channel
    	//right = receiveReadOnly(1); // input 1 = right channel
    	#else
    	left = receiveWritable(0); // input 0 = left channel
    	right = receiveWritable(1); // input 1 = right channel
    	#endif
    
    	if (usb_audio_transmit_setting == 0) {
    		if (left) release(left);
    		if (right) release(right);
    		if (left_1st) { release(left_1st); left_1st = NULL; }
    		if (left_2nd) { release(left_2nd); left_2nd = NULL; }
    		if (right_1st) { release(right_1st); right_1st = NULL; }
    		if (right_2nd) { release(right_2nd); right_2nd = NULL; }
    		offset_1st = 0;
    		return;
    	}
    	if (left == NULL) {
    		left = allocate();
    		if (left == NULL) {
    			if (right) release(right);
    			return;
    		}
    		memset(left->data, 0, sizeof(left->data));
    	}
    	if (right == NULL) {
    		right = allocate();
    		if (right == NULL) {
    			release(left);
    			return;
    		}
    		memset(right->data, 0, sizeof(right->data));
    	}
    	__disable_irq();
    	if (left_1st == NULL) {
    		left_1st = left;
    		right_1st = right;
    		offset_1st = 0;
    	} else if (left_2nd == NULL) {
    		left_2nd = left;
    		right_2nd = right;
    #ifndef FRANKB_PATCH
    	} else {
    		// buffer overrun - PC is consuming too slowly
    		audio_block_t *discard1 = left_1st;
    		left_1st = left_2nd;
    		left_2nd = left;
    		audio_block_t *discard2 = right_1st;
    		right_1st = right_2nd;
    		right_2nd = right;
    		offset_1st = 0; // TODO: discard part of this data?
    		//serial_print("*");
    		release(discard1);
    		release(discard2);
    	}
    #endif
    
    	__enable_irq();
    }
    
    
    // Called from the USB interrupt when ready to transmit another
    // isochronous packet.  If we place data into the transmit buffer,
    // the return is the number of bytes.  Otherwise, return 0 means
    // no data to transmit
    unsigned int usb_audio_transmit_callback(void)
    {
    	static uint32_t count=5;
    	uint32_t avail, num, target, offset, len=0;
    	audio_block_t *left, *right;
    
    	if (++count < 10) {   // TODO: dynamic adjust to match USB rate
    		target = 44;
    	} else {
    		count = 0;
    		target = 45;
    	}
    	while (len < target) {
    		num = target - len;
    		left = AudioOutputUSB::left_1st;
    		if (left == NULL) {
    			// buffer underrun - PC is consuming too quickly
    			memset(usb_audio_transmit_buffer + len * 4, 0, num * 4);
    			//serial_print("%");
    			#ifdef FRANKB_PATCH
    			            return len * 4;
    			#endif
    			break;
    		}
    		right = AudioOutputUSB::right_1st;
    		offset = AudioOutputUSB::offset_1st;
    
    		avail = AUDIO_BLOCK_SAMPLES - offset;
    		if (num > avail) num = avail;
    
    		copy_from_buffers((uint32_t *)usb_audio_transmit_buffer + len,
    			left->data + offset, right->data + offset, num);
    		len += num;
    		offset += num;
    		if (offset >= AUDIO_BLOCK_SAMPLES) {
    			AudioStream::release(left);
    			AudioStream::release(right);
    			AudioOutputUSB::left_1st = AudioOutputUSB::left_2nd;
    			AudioOutputUSB::left_2nd = NULL;
    			AudioOutputUSB::right_1st = AudioOutputUSB::right_2nd;
    			AudioOutputUSB::right_2nd = NULL;
    			AudioOutputUSB::offset_1st = 0;
    		} else {
    			AudioOutputUSB::offset_1st = offset;
    		}
    	}
    	return target * 4;
    }
    #endif
    
    
    
    
    struct setup_struct {
      union {
        struct {
    	uint8_t bmRequestType;
    	uint8_t bRequest;
    	union {
    		struct {
    			uint8_t bChannel;  // 0=main, 1=left, 2=right
    			uint8_t bCS;       // Control Selector
    		};
    		uint16_t wValue;
    	};
    	union {
    		struct {
    			uint8_t bIfEp;     // type of entity
    			uint8_t bEntityId; // UnitID, TerminalID, etc.
    		};
    		uint16_t wIndex;
    	};
    	uint16_t wLength;
        };
      };
    };
    
    int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen)
    {
    	struct setup_struct setup = *((struct setup_struct *)stp);
    	if (setup.bmRequestType==0xA1) { // should check bRequest, bChannel, and UnitID
    			if (setup.bCS==0x01) { // mute
    				data[0] = AudioInputUSB::features.mute;  // 1=mute, 0=unmute
    				*datalen = 1;
    				return 1;
    			}
    			else if (setup.bCS==0x02) { // volume
    				if (setup.bRequest==0x81) { // GET_CURR
    					data[0] = AudioInputUSB::features.volume & 0xFF;
    					data[1] = (AudioInputUSB::features.volume>>8) & 0xFF;
    				}
    				else if (setup.bRequest==0x82) { // GET_MIN
    					//serial_print("vol get_min\n");
    					data[0] = 0;     // min level is 0
    					data[1] = 0;
    				}
    				else if (setup.bRequest==0x83) { // GET_MAX
    					data[0] = FEATURE_MAX_VOLUME;  // max level, for range of 0 to MAX
    					data[1] = 0;
    				}
    				else if (setup.bRequest==0x84) { // GET_RES
    					data[0] = 1; // increment vol by by 1
    					data[1] = 0;
    				}
    				else { // pass over SET_MEM, etc.
    					return 0;
    				}
    				*datalen = 2;
    				return 1;
    			}
    	}
    	return 0;
    }
    
    int usb_audio_set_feature(void *stp, uint8_t *buf)
    {
    	struct setup_struct setup = *((struct setup_struct *)stp);
    	if (setup.bmRequestType==0x21) { // should check bRequest, bChannel and UnitID
    			if (setup.bCS==0x01) { // mute
    				if (setup.bRequest==0x01) { // SET_CUR
    					AudioInputUSB::features.mute = buf[0]; // 1=mute,0=unmute
    					AudioInputUSB::features.change = 1;
    					return 1;
    				}
    			}
    			else if (setup.bCS==0x02) { // volume
    				if (setup.bRequest==0x01) { // SET_CUR
    					AudioInputUSB::features.volume = buf[0];
    					AudioInputUSB::features.change = 1;
    					return 1;
    				}
    			}
    	}
    	return 0;
    }
    
    
    #endif // AUDIO_INTERFACE

  14. #89
    Senior Member
    Join Date
    Apr 2014
    Posts
    363
    I am not in position to do testing at present but just reading your mods....
    I assume you have defined #define FRANKB_PATCH somewhere.....couldnt find it in your cpp file ????
    Also orig for teensy3.2 the first //left and //right receiveReadonly lines were uncommented...????
    Code:
    #ifdef FRANKB_PATCH
    
    	//left = receiveReadOnly(0); // input 0 = left channel xxxxxxxxxxxxxxx  maybe need uncomment this line..??????
    	//right = receiveReadOnly(1); // input 1 = right channelxxxxxxxxxxxxxx   maybe need uncomment this line..??????
    	#else
    	left = receiveWritable(0); // input 0 = left channel
    	right = receiveWritable(1); // input 1 = right channel
    	#endif
    Also ........The #ifdef should be after the closing curley bracket.....?

    right_2nd = right;
    #ifndef FRANKB_PATCH
    } else {
    // buffer overrun - PC is consuming too slowly
    audio_block_t *discard1 = left_1st;
    right_2nd = right;

    }

    #ifndef FRANKB_PATCH

    else {
    // buffer overrun - PC is consuming too slowly
    audio_block_t *discard1 = left_1st;

  15. #90
    Ah geez, you're right. I made those changes and now it's working. I didn't even need to mess with the sample rate with setI2SFreq() or anything. I tried with the sine wave sketch and my more complicated project and no more clicks. Thank you so much for your help!

    Here's the modified usb_audio.cpp I'm using now:

    Code:
    /* Teensyduino Core Library
     * http://www.pjrc.com/teensy/
     * Copyright (c) 2017 PJRC.COM, LLC.
     *
     * Permission is hereby granted, free of charge, to any person obtaining
     * a copy of this software and associated documentation files (the
     * "Software"), to deal in the Software without restriction, including
     * without limitation the rights to use, copy, modify, merge, publish,
     * distribute, sublicense, and/or sell copies of the Software, and to
     * permit persons to whom the Software is furnished to do so, subject to
     * the following conditions:
     *
     * 1. The above copyright notice and this permission notice shall be
     * included in all copies or substantial portions of the Software.
     *
     * 2. If the Software is incorporated into a build system that allows
     * selection among a list of target devices, then similar target
     * devices manufactured by PJRC.COM must be included in the list of
     * target devices and selectable in the same manner.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     * SOFTWARE.
     */
    
    #include <Arduino.h>
    #include "usb_dev.h"
    #include "usb_audio.h"
    #include "debug/printf.h"
    
    #ifdef AUDIO_INTERFACE
    
    #define FRANKB_PATCH
    
    bool AudioInputUSB::update_responsibility;
    audio_block_t * AudioInputUSB::incoming_left;
    audio_block_t * AudioInputUSB::incoming_right;
    audio_block_t * AudioInputUSB::ready_left;
    audio_block_t * AudioInputUSB::ready_right;
    uint16_t AudioInputUSB::incoming_count;
    uint8_t AudioInputUSB::receive_flag;
    
    struct usb_audio_features_struct AudioInputUSB::features = {0,0,FEATURE_MAX_VOLUME/2};
    
    extern volatile uint8_t usb_high_speed;
    static void rx_event(transfer_t *t);
    static void tx_event(transfer_t *t);
    
    /*static*/ transfer_t rx_transfer __attribute__ ((used, aligned(32)));
    /*static*/ transfer_t sync_transfer __attribute__ ((used, aligned(32)));
    /*static*/ transfer_t tx_transfer __attribute__ ((used, aligned(32)));
    DMAMEM static uint8_t rx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(32)));
    DMAMEM static uint8_t tx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(32)));
    DMAMEM uint32_t usb_audio_sync_feedback __attribute__ ((aligned(32)));
    
    uint8_t usb_audio_receive_setting=0;
    uint8_t usb_audio_transmit_setting=0;
    uint8_t usb_audio_sync_nbytes;
    uint8_t usb_audio_sync_rshift;
    
    uint32_t feedback_accumulator;
    
    volatile uint32_t usb_audio_underrun_count;
    volatile uint32_t usb_audio_overrun_count;
    
    
    static void rx_event(transfer_t *t)
    {
    	if (t) {
    		int len = AUDIO_RX_SIZE - ((rx_transfer.status >> 16) & 0x7FFF);
    		printf("rx %u\n", len);
    		usb_audio_receive_callback(len);
    	}
    	usb_prepare_transfer(&rx_transfer, rx_buffer, AUDIO_RX_SIZE, 0);
    	arm_dcache_delete(&rx_buffer, AUDIO_RX_SIZE);
    	usb_receive(AUDIO_RX_ENDPOINT, &rx_transfer);
    }
    
    static void sync_event(transfer_t *t)
    {
    	// USB 2.0 Specification, 5.12.4.2 Feedback, pages 73-75
    	//printf("sync %x\n", sync_transfer.status); // too slow, can't print this much
    	usb_audio_sync_feedback = feedback_accumulator >> usb_audio_sync_rshift;
    	usb_prepare_transfer(&sync_transfer, &usb_audio_sync_feedback, usb_audio_sync_nbytes, 0);
    	arm_dcache_flush(&usb_audio_sync_feedback, usb_audio_sync_nbytes);
    	usb_transmit(AUDIO_SYNC_ENDPOINT, &sync_transfer);
    }
    
    void usb_audio_configure(void)
    {
    	printf("usb_audio_configure\n");
    	usb_audio_underrun_count = 0;
    	usb_audio_overrun_count = 0;
    	feedback_accumulator = 739875226; // 44.1 * 2^24
    	if (usb_high_speed) {
    		usb_audio_sync_nbytes = 4;
    		usb_audio_sync_rshift = 8;
    	} else {
    		usb_audio_sync_nbytes = 3;
    		usb_audio_sync_rshift = 10;
    	}
    	memset(&rx_transfer, 0, sizeof(rx_transfer));
    	usb_config_rx_iso(AUDIO_RX_ENDPOINT, AUDIO_RX_SIZE, 1, rx_event);
    	rx_event(NULL);
    	memset(&sync_transfer, 0, sizeof(sync_transfer));
    	usb_config_tx_iso(AUDIO_SYNC_ENDPOINT, usb_audio_sync_nbytes, 1, sync_event);
    	sync_event(NULL);
    	memset(&tx_transfer, 0, sizeof(tx_transfer));
    	usb_config_tx_iso(AUDIO_TX_ENDPOINT, AUDIO_TX_SIZE, 1, tx_event);
    	tx_event(NULL);
    }
    
    void AudioInputUSB::begin(void)
    {
    	incoming_count = 0;
    	incoming_left = NULL;
    	incoming_right = NULL;
    	ready_left = NULL;
    	ready_right = NULL;
    	receive_flag = 0;
    	// update_responsibility = update_setup();
    	// TODO: update responsibility is tough, partly because the USB
    	// interrupts aren't sychronous to the audio library block size,
    	// but also because the PC may stop transmitting data, which
    	// means we no longer get receive callbacks from usb.c
    	update_responsibility = false;
    }
    
    static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len)
    {
    	uint32_t *target = (uint32_t*) src + len;
    	while ((src < target) && (((uintptr_t) left & 0x02) != 0)) {
    		uint32_t n = *src++;
    		*left++ = n & 0xFFFF;
    		*right++ = n >> 16;
    	}
    
    	while ((src < target - 2)) {
    		uint32_t n1 = *src++;
    		uint32_t n = *src++;
    		*(uint32_t *)left = (n1 & 0xFFFF) | ((n & 0xFFFF) << 16);
    		left+=2;
    		*(uint32_t *)right = (n1 >> 16) | ((n & 0xFFFF0000)) ;
    		right+=2;
    	}
    
    	while ((src < target)) {
    		uint32_t n = *src++;
    		*left++ = n & 0xFFFF;
    		*right++ = n >> 16;
    	}
    }
    
    // Called from the USB interrupt when an isochronous packet arrives
    // we must completely remove it from the receive buffer before returning
    //
    #if 1
    void usb_audio_receive_callback(unsigned int len)
    {
    	unsigned int count, avail;
    	audio_block_t *left, *right;
    	const uint32_t *data;
    
    	AudioInputUSB::receive_flag = 1;
    	len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right
    	data = (const uint32_t *)rx_buffer;
    
    	count = AudioInputUSB::incoming_count;
    	left = AudioInputUSB::incoming_left;
    	right = AudioInputUSB::incoming_right;
    	if (left == NULL) {
    		left = AudioStream::allocate();
    		if (left == NULL) return;
    		AudioInputUSB::incoming_left = left;
    	}
    	if (right == NULL) {
    		right = AudioStream::allocate();
    		if (right == NULL) return;
    		AudioInputUSB::incoming_right = right;
    	}
    	while (len > 0) {
    		avail = AUDIO_BLOCK_SAMPLES - count;
    		if (len < avail) {
    			copy_to_buffers(data, left->data + count, right->data + count, len);
    			AudioInputUSB::incoming_count = count + len;
    			return;
    		} else if (avail > 0) {
    			copy_to_buffers(data, left->data + count, right->data + count, avail);
    			data += avail;
    			len -= avail;
    			if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) {
    				// buffer overrun, PC sending too fast
    				AudioInputUSB::incoming_count = count + avail;
    				if (len > 0) {
    					usb_audio_overrun_count++;
    					printf("!");
    					//serial_phex(len);
    				}
    				return;
    			}
    			send:
    			AudioInputUSB::ready_left = left;
    			AudioInputUSB::ready_right = right;
    			//if (AudioInputUSB::update_responsibility) AudioStream::update_all();
    			left = AudioStream::allocate();
    			if (left == NULL) {
    				AudioInputUSB::incoming_left = NULL;
    				AudioInputUSB::incoming_right = NULL;
    				AudioInputUSB::incoming_count = 0;
    				return;
    			}
    			right = AudioStream::allocate();
    			if (right == NULL) {
    				AudioStream::release(left);
    				AudioInputUSB::incoming_left = NULL;
    				AudioInputUSB::incoming_right = NULL;
    				AudioInputUSB::incoming_count = 0;
    				return;
    			}
    			AudioInputUSB::incoming_left = left;
    			AudioInputUSB::incoming_right = right;
    			count = 0;
    		} else {
    			if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) return;
    			goto send; // recover from buffer overrun
    		}
    	}
    	AudioInputUSB::incoming_count = count;
    }
    #endif
    
    void AudioInputUSB::update(void)
    {
    	audio_block_t *left, *right;
    
    	__disable_irq();
    	left = ready_left;
    	ready_left = NULL;
    	right = ready_right;
    	ready_right = NULL;
    	uint16_t c = incoming_count;
    	uint8_t f = receive_flag;
    	receive_flag = 0;
    	__enable_irq();
    	if (f) {
    		int diff = AUDIO_BLOCK_SAMPLES/2 - (int)c;
    		feedback_accumulator += diff * 1;
    		//uint32_t feedback = (feedback_accumulator >> 8) + diff * 100;
    		//usb_audio_sync_feedback = feedback;
    
    		//printf(diff >= 0 ? "." : "^");
    	}
    	//serial_phex(c);
    	//serial_print(".");
    	if (!left || !right) {
    		usb_audio_underrun_count++;
    		//printf("#"); // buffer underrun - PC sending too slow
    		if (f) feedback_accumulator += 3500;
    	}
    	if (left) {
    		transmit(left, 0);
    		release(left);
    	}
    	if (right) {
    		transmit(right, 1);
    		release(right);
    	}
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #if 1
    bool AudioOutputUSB::update_responsibility;
    audio_block_t * AudioOutputUSB::left_1st;
    audio_block_t * AudioOutputUSB::left_2nd;
    audio_block_t * AudioOutputUSB::right_1st;
    audio_block_t * AudioOutputUSB::right_2nd;
    uint16_t AudioOutputUSB::offset_1st;
    
    /*DMAMEM*/ uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] __attribute__ ((used, aligned(32)));
    
    
    static void tx_event(transfer_t *t)
    {
    	int len = usb_audio_transmit_callback();
    	usb_audio_sync_feedback = feedback_accumulator >> usb_audio_sync_rshift;
    	usb_prepare_transfer(&tx_transfer, usb_audio_transmit_buffer, len, 0);
    	arm_dcache_flush_delete(usb_audio_transmit_buffer, len);
    	usb_transmit(AUDIO_TX_ENDPOINT, &tx_transfer);
    }
    
    
    void AudioOutputUSB::begin(void)
    {
    	update_responsibility = false;
    	left_1st = NULL;
    	right_1st = NULL;
    }
    
    static void copy_from_buffers(uint32_t *dst, int16_t *left, int16_t *right, unsigned int len)
    {
    	// TODO: optimize...
    	while (len > 0) {
    		*dst++ = (*right++ << 16) | (*left++ & 0xFFFF);
    		len--;
    	}
    }
    
    void AudioOutputUSB::update(void)
    {
    	audio_block_t *left, *right;
    
    	// TODO: we shouldn't be writing to these......
    	#ifdef FRANKB_PATCH
    	left = receiveReadOnly(0); // input 0 = left channel
    	right = receiveReadOnly(1); // input 1 = right channel
    	#else
    	left = receiveWritable(0); // input 0 = left channel
    	right = receiveWritable(1); // input 1 = right channel
    	#endif
    
    	if (usb_audio_transmit_setting == 0) {
    		if (left) release(left);
    		if (right) release(right);
    		if (left_1st) { release(left_1st); left_1st = NULL; }
    		if (left_2nd) { release(left_2nd); left_2nd = NULL; }
    		if (right_1st) { release(right_1st); right_1st = NULL; }
    		if (right_2nd) { release(right_2nd); right_2nd = NULL; }
    		offset_1st = 0;
    		return;
    	}
    	if (left == NULL) {
    		left = allocate();
    		if (left == NULL) {
    			if (right) release(right);
    			return;
    		}
    		memset(left->data, 0, sizeof(left->data));
    	}
    	if (right == NULL) {
    		right = allocate();
    		if (right == NULL) {
    			release(left);
    			return;
    		}
    		memset(right->data, 0, sizeof(right->data));
    	}
    	__disable_irq();
    	if (left_1st == NULL) {
    		left_1st = left;
    		right_1st = right;
    		offset_1st = 0;
    	} else if (left_2nd == NULL) {
    		left_2nd = left;
    		right_2nd = right;
    	}
    
    	#ifndef FRANKB_PATCH
    
    
    	else {
    		// buffer overrun - PC is consuming too slowly
    		audio_block_t *discard1 = left_1st;
    		left_1st = left_2nd;
    		left_2nd = left;
    		audio_block_t *discard2 = right_1st;
    		right_1st = right_2nd;
    		right_2nd = right;
    		offset_1st = 0; // TODO: discard part of this data?
    		//serial_print("*");
    		release(discard1);
    		release(discard2);
    	}
    #endif
    
    	__enable_irq();
    }
    
    
    // Called from the USB interrupt when ready to transmit another
    // isochronous packet.  If we place data into the transmit buffer,
    // the return is the number of bytes.  Otherwise, return 0 means
    // no data to transmit
    unsigned int usb_audio_transmit_callback(void)
    {
    	static uint32_t count=5;
    	uint32_t avail, num, target, offset, len=0;
    	audio_block_t *left, *right;
    
    	if (++count < 10) {   // TODO: dynamic adjust to match USB rate
    		target = 44;
    	} else {
    		count = 0;
    		target = 45;
    	}
    	while (len < target) {
    		num = target - len;
    		left = AudioOutputUSB::left_1st;
    		if (left == NULL) {
    			// buffer underrun - PC is consuming too quickly
    			memset(usb_audio_transmit_buffer + len * 4, 0, num * 4);
    			//serial_print("%");
    			#ifdef FRANKB_PATCH
    			            return len * 4;
    			#endif
    			break;
    		}
    		right = AudioOutputUSB::right_1st;
    		offset = AudioOutputUSB::offset_1st;
    
    		avail = AUDIO_BLOCK_SAMPLES - offset;
    		if (num > avail) num = avail;
    
    		copy_from_buffers((uint32_t *)usb_audio_transmit_buffer + len,
    			left->data + offset, right->data + offset, num);
    		len += num;
    		offset += num;
    		if (offset >= AUDIO_BLOCK_SAMPLES) {
    			AudioStream::release(left);
    			AudioStream::release(right);
    			AudioOutputUSB::left_1st = AudioOutputUSB::left_2nd;
    			AudioOutputUSB::left_2nd = NULL;
    			AudioOutputUSB::right_1st = AudioOutputUSB::right_2nd;
    			AudioOutputUSB::right_2nd = NULL;
    			AudioOutputUSB::offset_1st = 0;
    		} else {
    			AudioOutputUSB::offset_1st = offset;
    		}
    	}
    	return target * 4;
    }
    #endif
    
    
    
    
    struct setup_struct {
      union {
        struct {
    	uint8_t bmRequestType;
    	uint8_t bRequest;
    	union {
    		struct {
    			uint8_t bChannel;  // 0=main, 1=left, 2=right
    			uint8_t bCS;       // Control Selector
    		};
    		uint16_t wValue;
    	};
    	union {
    		struct {
    			uint8_t bIfEp;     // type of entity
    			uint8_t bEntityId; // UnitID, TerminalID, etc.
    		};
    		uint16_t wIndex;
    	};
    	uint16_t wLength;
        };
      };
    };
    
    int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen)
    {
    	struct setup_struct setup = *((struct setup_struct *)stp);
    	if (setup.bmRequestType==0xA1) { // should check bRequest, bChannel, and UnitID
    			if (setup.bCS==0x01) { // mute
    				data[0] = AudioInputUSB::features.mute;  // 1=mute, 0=unmute
    				*datalen = 1;
    				return 1;
    			}
    			else if (setup.bCS==0x02) { // volume
    				if (setup.bRequest==0x81) { // GET_CURR
    					data[0] = AudioInputUSB::features.volume & 0xFF;
    					data[1] = (AudioInputUSB::features.volume>>8) & 0xFF;
    				}
    				else if (setup.bRequest==0x82) { // GET_MIN
    					//serial_print("vol get_min\n");
    					data[0] = 0;     // min level is 0
    					data[1] = 0;
    				}
    				else if (setup.bRequest==0x83) { // GET_MAX
    					data[0] = FEATURE_MAX_VOLUME;  // max level, for range of 0 to MAX
    					data[1] = 0;
    				}
    				else if (setup.bRequest==0x84) { // GET_RES
    					data[0] = 1; // increment vol by by 1
    					data[1] = 0;
    				}
    				else { // pass over SET_MEM, etc.
    					return 0;
    				}
    				*datalen = 2;
    				return 1;
    			}
    	}
    	return 0;
    }
    
    int usb_audio_set_feature(void *stp, uint8_t *buf)
    {
    	struct setup_struct setup = *((struct setup_struct *)stp);
    	if (setup.bmRequestType==0x21) { // should check bRequest, bChannel and UnitID
    			if (setup.bCS==0x01) { // mute
    				if (setup.bRequest==0x01) { // SET_CUR
    					AudioInputUSB::features.mute = buf[0]; // 1=mute,0=unmute
    					AudioInputUSB::features.change = 1;
    					return 1;
    				}
    			}
    			else if (setup.bCS==0x02) { // volume
    				if (setup.bRequest==0x01) { // SET_CUR
    					AudioInputUSB::features.volume = buf[0];
    					AudioInputUSB::features.change = 1;
    					return 1;
    				}
    			}
    	}
    	return 0;
    }
    
    
    #endif // AUDIO_INTERFACE

  16. #91
    Senior Member
    Join Date
    Apr 2014
    Posts
    363
    Aye......computer always does what it is told to do...........

  17. #92
    Ha yep, I just need to be better at the "telling" part.

    So now that this issue is fixed for me, Iím wondering if Iím the only one thatís experiencing this? (Seems like it hasnít been an issue for anyone since 2018, so maybe? But that does seem strange.)

    If not, how do we go about applying this patch to usb_audio.cpp on the main repo? I don't have much experience with Github and don't really know how the patch works or any other side effects that could arise from it.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •