diff --git a/input_i2s_f32.cpp b/input_i2s_f32.cpp index e5aa32c..7e2189f 100644 --- a/input_i2s_f32.cpp +++ b/input_i2s_f32.cpp @@ -1,6 +1,6 @@ /* * input_i2s_f32.cpp - * + * * Audio Library for Teensy 3.X * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com * @@ -26,20 +26,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - /* + /* * Extended by Chip Audette, OpenAudio, May 2019 * Converted to F32 and to variable audio block length * The F32 conversion is under the MIT License. Use at your own risk. */ // Updated OpenAudio F32 with this version from Chip Audette's Tympan Library Jan 2021 RSL +// Removed unused pieces. RSL 30 May 2022 #include //do we really need this? (Chip: 2020-10-31) #include "input_i2s_f32.h" #include "output_i2s_f32.h" - #include -//DMAMEM __attribute__((aligned(32))) +//DMAMEM __attribute__((aligned(32))) static uint64_t i2s_rx_buffer[AUDIO_BLOCK_SAMPLES]; // Two 32-bit transfers per sample. audio_block_f32_t * AudioInputI2S_F32::block_left_f32 = NULL; audio_block_f32_t * AudioInputI2S_F32::block_right_f32 = NULL; @@ -69,7 +69,7 @@ void AudioInputI2S_F32::begin(bool transferUsing32bit) { AudioOutputI2S_F32::sample_rate_Hz = sample_rate_Hz; //these were given in the AudioSettings in the contructor AudioOutputI2S_F32::audio_block_samples = audio_block_samples;//these were given in the AudioSettings in the contructor - + //block_left_1st = NULL; //block_right_1st = NULL; @@ -100,7 +100,7 @@ void AudioInputI2S_F32::begin(bool transferUsing32bit) { #elif defined(__IMXRT1062__) CORE_PIN8_CONFIG = 3; //1:RX_DATA0 IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2; - + dma.TCD->SADDR = (void *)((uint32_t)&I2S1_RDR0 + 0); dma.TCD->SOFF = 0; dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); @@ -122,145 +122,9 @@ void AudioInputI2S_F32::begin(bool transferUsing32bit) { update_responsibility = update_setup(); dma.enable(); dma.attachInterrupt(isr); - - update_counter = 0; -} -/* void AudioInputI2S_F32::begin(bool transferUsing32bit) { - dma.begin(true); // Allocate the DMA channel first - - AudioOutputI2S_F32::sample_rate_Hz = sample_rate_Hz; //these were given in the AudioSettings in the contructor - AudioOutputI2S_F32::audio_block_samples = audio_block_samples;//these were given in the AudioSettings in the contructor - - //setup I2S parameters - AudioOutputI2S_F32::config_i2s(transferUsing32bit); - - // TODO: should we set & clear the I2S_RCSR_SR bit here? - CORE_PIN13_CONFIG = PORT_PCR_MUX(4); // pin 13, PTC5, I2S0_RXD0 - - // setup DMA parameters - //if (transferUsing32bit) { - sub_begin_i32(); - //} else { - // sub_begin_i16(); - //} - - // finish DMA setup - dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_RX); - update_responsibility = update_setup(); - dma.enable(); - // finish I2S parameters - I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR; - I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX - - //if (transferUsing32bit) { - dma.attachInterrupt(isr_32); - //} else { - // dma.attachInterrupt(isr_16); - //} - update_counter = 0; -} */ - -/* void AudioInputI2S_F32::sub_begin_i16(void) -{ - dma.TCD->SADDR = &I2S0_RDR0; - dma.TCD->SOFF = 0; - dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); - dma.TCD->NBYTES_MLNO = 2; - dma.TCD->SLAST = 0; - dma.TCD->DADDR = i2s_rx_buffer; - dma.TCD->DOFF = 2; - - //dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; //original - dma.TCD->CITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 2; - //dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer); //original - dma.TCD->DLASTSGA = -I2S_BUFFER_TO_USE_BYTES; - //dma.TCD->BITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; //original - dma.TCD->BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 2; - - dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; -}; */ - -/* void AudioInputI2S_F32::sub_begin_i32(void) -{ - //let's assume that we'll transfer one sample (left or right) each call. So, it'll transfer 4 bytes (32-bits) - dma.TCD->SADDR = (void *)((uint32_t)&I2S0_RDR0); - dma.TCD->SOFF = 0; //do not increment the source memory pointer - dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(DMA_TCD_ATTR_SIZE_32BIT) | DMA_TCD_ATTR_DSIZE(DMA_TCD_ATTR_SIZE_32BIT); - dma.TCD->NBYTES_MLNO = 4; //one sample (32bits = 4bytes). should be 4 or 8? https://forum.pjrc.com/threads/42233-I2S-Input-Question - dma.TCD->SLAST = 0; - dma.TCD->DADDR = i2s_rx_buffer; - dma.TCD->DOFF = 4; //increment one sample (32bits = 4bytes) in the destination memory - - //dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; //original, 16-bit - //dma.TCD->CITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 2; //revised WEA 16-bit - //dma.TCD->CITER_ELINKNO = sizeof(i2s_rx_buffer_32) / 4; //original, 32-bit - dma.TCD->CITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4; //number of minor loops in a major loop. I2S_BUFFER_TO_USE_BYTES/NBYTES_MLNO? ...should be 4 or 8? https://forum.pjrc.com/threads/42233-I2S-Input-Question - - //dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer); //original, 16-bit - //dma.TCD->DLASTSGA = -I2S_BUFFER_TO_USE_BYTES;//revised WEA 16-bit - //dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer_32);//original, 32-bit - dma.TCD->DLASTSGA = -I2S_BUFFER_TO_USE_BYTES;//revised WEA 32-bit - - //dma.TCD->BITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; //original, 16-bit - //dma.TCD->BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 2;//revised WEA 16-bit - //dma.TCD->BITER_ELINKNO = sizeof(i2s_rx_buffer_32) / 4; //original, 32-bit - dma.TCD->BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4; //number of minor loops in a major loop. I2S_BUFFER_TO_USE_BYTES/NBYTES_MLNO?..should be 4 or 8? https://forum.pjrc.com/threads/42233-I2S-Input-Question - - dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; -}; */ - -/* void AudioInputI2S_F32::isr_16(void) -{ - uint32_t daddr, offset; - const int16_t *src, *end; - int16_t *dest_left, *dest_right; - audio_block_t *left, *right; - //digitalWriteFast(3, HIGH); -#if defined(KINETISK) - daddr = (uint32_t)(dma.TCD->DADDR); -#endif - dma.clearInterrupt(); - //if (daddr < (uint32_t)i2s_rx_buffer + sizeof(i2s_rx_buffer) / 2) { - if (daddr < (uint32_t)i2s_rx_buffer + I2S_BUFFER_TO_USE_BYTES / 2) { - - // DMA is receiving to the first half of the buffer - // need to remove data from the second half - //src = (int16_t *)&i2s_rx_buffer[AUDIO_BLOCK_SAMPLES/2]; //original - //end = (int16_t *)&i2s_rx_buffer[AUDIO_BLOCK_SAMPLES]; //original - src = (int16_t *)&i2s_rx_buffer[audio_block_samples/2]; - end = (int16_t *)&i2s_rx_buffer[audio_block_samples]; - if (AudioInputI2S_F32::update_responsibility) AudioStream_F32::update_all(); - } else { - // DMA is receiving to the second half of the buffer - // need to remove data from the first half - src = (int16_t *)&i2s_rx_buffer[0]; - //end = (int16_t *)&i2s_rx_buffer[AUDIO_BLOCK_SAMPLES/2]; //original - end = (int16_t *)&i2s_rx_buffer[audio_block_samples/2]; - } - left = AudioInputI2S_F32::block_left; - right = AudioInputI2S_F32::block_right; - if (left != NULL && right != NULL) { - offset = AudioInputI2S_F32::block_offset; - //if (offset <= AUDIO_BLOCK_SAMPLES/2) { //original - if (offset <= ((uint32_t) audio_block_samples/2)) { - dest_left = &(left->data[offset]); - dest_right = &(right->data[offset]); - //AudioInputI2S_F32::block_offset = offset + AUDIO_BLOCK_SAMPLES/2; //original - AudioInputI2S_F32::block_offset = offset + audio_block_samples/2; - do { - //n = *src++; - // *dest_left++ = (int16_t)n; - // *dest_right++ = (int16_t)(n >> 16); - *dest_left++ = *src++; - *dest_right++ = *src++; - } while (src < end); - } - } - //digitalWriteFast(3, LOW); -} */ - +} void AudioInputI2S_F32::isr(void) { @@ -275,7 +139,6 @@ void AudioInputI2S_F32::isr(void) daddr = (uint32_t)(dma.TCD->DADDR); #endif dma.clearInterrupt(); - //Serial.println("isr"); //if (daddr < (uint32_t)i2s_rx_buffer + sizeof(i2s_rx_buffer) / 2) { //original Teensy Audio Library if (daddr < (uint32_t)i2s_rx_buffer + I2S_BUFFER_TO_USE_BYTES / 2) { @@ -284,7 +147,7 @@ void AudioInputI2S_F32::isr(void) //src = (int16_t *)&i2s_rx_buffer[AUDIO_BLOCK_SAMPLES/2]; //original Teensy Audio Library //end = (int16_t *)&i2s_rx_buffer[AUDIO_BLOCK_SAMPLES]; //original Teensy Audio Library src = (int32_t *)&i2s_rx_buffer[audio_block_samples/2]; - end = (int32_t *)&i2s_rx_buffer[audio_block_samples]; + end = (int32_t *)&i2s_rx_buffer[audio_block_samples]; update_counter++; //let's increment the counter here to ensure that we get every ISR resulting in audio if (AudioInputI2S_F32::update_responsibility) AudioStream_F32::update_all(); } else { @@ -316,68 +179,7 @@ void AudioInputI2S_F32::isr(void) } } -/* void AudioInputI2S_F32::isr_32(void) -{ - static bool flag_beenSuccessfullOnce = false; - uint32_t daddr, offset; - const int32_t *src_i32, *end_i32; - //int16_t *dest_left, *dest_right; - float32_t *dest_left_f32, *dest_right_f32; - audio_block_f32_t *left_f32, *right_f32; - daddr = (uint32_t)(dma.TCD->DADDR); - - dma.clearInterrupt(); - //if (daddr < (uint32_t)i2s_rx_buffer + sizeof(i2s_rx_buffer) / 2) { - if (daddr < (uint32_t)i2s_rx_buffer + I2S_BUFFER_TO_USE_BYTES / 2) { - - // DMA is receiving to the first half of the buffer - // need to remove data from the second half - //src = (int32_t *)&i2s_rx_buffer_32[AUDIO_BLOCK_SAMPLES]; - //end = (int32_t *)&i2s_rx_buffer_32[AUDIO_BLOCK_SAMPLES*2]; - src_i32 = (int32_t *)&i2s_rx_buffer[audio_block_samples]; //WEA revised - end_i32 = (int32_t *)&i2s_rx_buffer[audio_block_samples*2]; //WEA revised - update_counter++; //let's increment the counter here to ensure that we get every ISR resulting in audio - if (AudioInputI2S_F32::update_responsibility) AudioStream_F32::update_all(); - - } else { - // DMA is receiving to the second half of the buffer - // need to remove data from the first half - //src = (int32_t *)&i2s_rx_buffer_32[0]; - //end = (int32_t *)&i2s_rx_buffer_32[AUDIO_BLOCK_SAMPLES]; - src_i32 = (int32_t *)&i2s_rx_buffer[0]; - end_i32 = (int32_t *)&i2s_rx_buffer[audio_block_samples]; - } - - // OLD COMMENT: extract 16 but from 32 bit I2S buffer but shift to right first - // OLD COMMENT: there will be two buffers with each having "AUDIO_BLOCK_SAMPLES" samples - left_f32 = AudioInputI2S_F32::block_left_f32; - right_f32 = AudioInputI2S_F32::block_right_f32; - if ((left_f32 != NULL) && (right_f32 != NULL)) { - offset = AudioInputI2S_F32::block_offset; - //if (offset <= AUDIO_BLOCK_SAMPLES/2) { //original - if (offset <= ((uint32_t) audio_block_samples/2)) { - dest_left_f32 = &(left_f32->data[offset]); - dest_right_f32 = &(right_f32->data[offset]); - //AudioInputI2S_F32::block_offset = offset + AUDIO_BLOCK_SAMPLES/2; //original - AudioInputI2S_F32::block_offset = offset + audio_block_samples/2; - do { - //n = *src++; - // *dest_left++ = (int16_t)n; - // *dest_right++ = (int16_t)(n >> 16); - *dest_left_f32++ = (float32_t) *src_i32++; - *dest_right_f32++ = (float32_t) *src_i32++; - } while (src_i32 < end_i32); - } - flag_beenSuccessfullOnce = true; - } else { - if (flag_beenSuccessfullOnce) { - //but we were not successful this time - Serial.println("Input I2S: isr_32: WARNING!!! Null memory block."); - } - } -} */ - -#define I16_TO_F32_NORM_FACTOR (3.051850947599719e-05) //which is 1/32767 +#define I16_TO_F32_NORM_FACTOR (3.051850947599719e-05) //which is 1/32767 void AudioInputI2S_F32::scale_i16_to_f32( float32_t *p_i16, float32_t *p_f32, int len) { for (int i=0; i= AUDIO_BLOCK_SAMPLES) { //original - if (block_offset >= audio_block_samples) { - // the DMA filled 2 blocks, so grab them and get the - // 2 new blocks to the DMA, as quickly as possible - out_left = block_left; - block_left = new_left; - out_right = block_right; - block_right = new_right; - block_offset = 0; - __enable_irq(); - - // then transmit the DMA's former blocks - - // but, first, convert them to F32 - audio_block_f32_t *out_left_f32=NULL, *out_right_f32=NULL; - out_left_f32 = AudioStream_F32::allocate_f32(); - if (out_left_f32 != NULL) { - out_right_f32 = AudioStream_F32::allocate_f32(); - if (out_right_f32 == NULL) { - flag_out_of_memory = 2; - AudioStream_F32::release(out_left_f32); - out_left_f32 = NULL; - } - } else { - flag_out_of_memory = 2; - } - if (out_left_f32 != NULL) { - //convert int16 to float 32 - scale_i16_to_f32(out_left->data, out_left_f32->data, audio_block_samples); - scale_i16_to_f32(out_right->data, out_right_f32->data, audio_block_samples); - - //prepare to transmit - update_counter++; - out_left_f32->id = update_counter; - out_right_f32->id = update_counter; - - //transmit the f32 data! - AudioStream_F32::transmit(out_left_f32,0); - AudioStream_F32::transmit(out_right_f32,1); - AudioStream_F32::release(out_left_f32); - AudioStream_F32::release(out_right_f32); - } - AudioStream::release(out_left); - AudioStream::release(out_right); - //Serial.print("."); - } else if (new_left != NULL) { - // the DMA didn't fill blocks, but we allocated blocks - if (block_left == NULL) { - // the DMA doesn't have any blocks to fill, so - // give it the ones we just allocated - block_left = new_left; - block_right = new_right; - block_offset = 0; - __enable_irq(); - } else { - // the DMA already has blocks, doesn't need these - __enable_irq(); - AudioStream::release(new_left); - AudioStream::release(new_right); - } - } else { - // The DMA didn't fill blocks, and we could not allocate - // memory... the system is likely starving for memory! - // Sadly, there's nothing we can do. - __enable_irq(); - } -} - */ - void AudioInputI2S_F32::update_1chan(int chan, audio_block_f32_t *&out_f32) { if (!out_f32) return; - + //scale the float values so that the maximum possible audio values span -1.0 to + 1.0 scale_i32_to_f32(out_f32->data, out_f32->data, audio_block_samples); //scale_i16_to_f32(out_f32->data, out_f32->data, audio_block_samples); //prepare to transmit by setting the update_counter (which helps tell if data is skipped or out-of-order) out_f32->id = update_counter; - + //transmit the f32 data! AudioStream_F32::transmit(out_f32,chan); //release the memory blocks AudioStream_F32::release(out_f32); } - + void AudioInputI2S_F32::update(void) { static bool flag_beenSuccessfullOnce = false; audio_block_f32_t *new_left=NULL, *new_right=NULL, *out_left=NULL, *out_right=NULL; - + new_left = AudioStream_F32::allocate_f32(); new_right = AudioStream_F32::allocate_f32(); if ((!new_left) || (!new_right)) { @@ -510,7 +226,7 @@ void AudioInputI2S_F32::update(void) } else { flag_beenSuccessfullOnce = true; } - + __disable_irq(); if (block_offset >= audio_block_samples) { // the DMA filled 2 blocks, so grab them and get the @@ -521,12 +237,12 @@ void AudioInputI2S_F32::update(void) block_right_f32 = new_right; block_offset = 0; __enable_irq(); - + //update_counter++; //I chose to update it in the ISR instead. update_1chan(0,out_left); //uses audio_block_samples and update_counter update_1chan(1,out_right); //uses audio_block_samples and update_counter - - + + } else if (new_left != NULL) { // the DMA didn't fill blocks, but we allocated blocks if (block_left_f32 == NULL) { @@ -583,35 +299,6 @@ void AudioInputI2Sslave_F32::begin(void) I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR; I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX dma.attachInterrupt(isr); -#endif -} - -/* -void AudioInputI2Sslave::begin(void) -{ - dma.begin(true); // Allocate the DMA channel first - //block_left_1st = NULL; - //block_right_1st = NULL; - AudioOutputI2Sslave::config_i2s(); - CORE_PIN13_CONFIG = PORT_PCR_MUX(4); // pin 13, PTC5, I2S0_RXD0 -#if defined(KINETISK) - dma.TCD->SADDR = &I2S0_RDR0; - dma.TCD->SOFF = 0; - dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); - dma.TCD->NBYTES_MLNO = 2; - dma.TCD->SLAST = 0; - dma.TCD->DADDR = i2s_rx_buffer; - dma.TCD->DOFF = 2; - dma.TCD->CITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; - dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer); - dma.TCD->BITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; - dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; #endif - dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_RX); - update_responsibility = update_setup(); - dma.enable(); - I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR; - I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX - dma.attachInterrupt(isr); } -*/ + diff --git a/input_i2s_f32.h b/input_i2s_f32.h index 9c5f955..2fb9c0e 100644 --- a/input_i2s_f32.h +++ b/input_i2s_f32.h @@ -1,6 +1,6 @@ /* * ***** input_i2s_f32.h ****** - * + * * Audio Library for Teensy 3.X * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com * @@ -26,20 +26,21 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - /* + /* * Extended by Chip Audette, OpenAudio, May 2019 * Converted to F32 and to variable audio block length * The F32 conversion is under the MIT License. Use at your own risk. */ // Updated OpenAudio F32 with this version from Chip Audette's Tympan Library Jan 2021 RSL +// Removed unused pieces. RSL 30 May 2022 #ifndef _input_i2s_f32_h_ #define _input_i2s_f32_h_ #include -#include +#include #include "AudioStream_F32.h" -#include "AudioStream.h" //Do we really need this?? (Chip, 2020-10-31) +// #include "AudioStream.h" // included AudioStream_F32.h > Audio.h > AudioStream.h #include "DMAChannel.h" class AudioInputI2S_F32 : public AudioStream_F32 @@ -47,24 +48,24 @@ class AudioInputI2S_F32 : public AudioStream_F32 //GUI: inputs:0, outputs:2 //this line used for automatic generation of GUI nodes public: AudioInputI2S_F32(void) : AudioStream_F32(0, NULL) { begin(); } //uses default AUDIO_SAMPLE_RATE and BLOCK_SIZE_SAMPLES from AudioStream.h - AudioInputI2S_F32(const AudioSettings_F32 &settings) : AudioStream_F32(0, NULL) { + AudioInputI2S_F32(const AudioSettings_F32 &settings) : AudioStream_F32(0, NULL) { sample_rate_Hz = settings.sample_rate_Hz; audio_block_samples = settings.audio_block_samples; - begin(); + begin(); } - + virtual void update(void); static void scale_i16_to_f32( float32_t *p_i16, float32_t *p_f32, int len) ; static void scale_i24_to_f32( float32_t *p_i24, float32_t *p_f32, int len) ; static void scale_i32_to_f32( float32_t *p_i32, float32_t *p_f32, int len); void begin(void); void begin(bool); - void sub_begin_i32(void); - //void sub_begin_i16(void); + // void sub_begin_i32(void); // These 2 are prototypes without functions RSL May 22 + // void sub_begin_i16(void); int get_isOutOfMemory(void) { return flag_out_of_memory; } void clear_isOutOfMemory(void) { flag_out_of_memory = 0; } //friend class AudioOutputI2S_F32; -protected: +protected: AudioInputI2S_F32(int dummy): AudioStream_F32(0, NULL) {} // to be used only inside AudioInputI2Sslave !! static bool update_responsibility; static DMAChannel dma; diff --git a/output_i2s_f32.cpp b/output_i2s_f32.cpp index d66052d..1bab8a7 100644 --- a/output_i2s_f32.cpp +++ b/output_i2s_f32.cpp @@ -32,88 +32,12 @@ * The F32 conversion is under the MIT License. Use at your own risk. */ // Updated OpenAudio F32 with this version from Chip Audette's Tympan Library Jan 2021 RSL +// Removed old commented out code. RSL 30 May 2022 #include "output_i2s_f32.h" -//#include "input_i2s_f32.h" -//include "memcpy_audio.h" -//#include "memcpy_interleave.h" #include #include //to get access to Audio/utlity/imxrt_hw.h...do we really need this??? WEA 2020-10-31 - /* Comment this out -//taken from Teensy Audio utility/imxrt_hw.h and imxrt_hw.cpp... -#if defined(__IMXRT1062__) - #ifndef imxr_hw_h_ - #define imxr_hw_h_ - #define IMXRT_CACHE_ENABLED 2 // 0=disabled, 1=WT, 2= WB - #include - #include - PROGMEM - void set_audioClock_tympan(int nfact, int32_t nmult, uint32_t ndiv, bool force = false) // sets PLL4 - { - if (!force && (CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_ENABLE)) return; - CCM_ANALOG_PLL_AUDIO = CCM_ANALOG_PLL_AUDIO_BYPASS | CCM_ANALOG_PLL_AUDIO_ENABLE - | CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2) // 2: 1/4; 1: 1/2; 0: 1/1 - | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(nfact); - CCM_ANALOG_PLL_AUDIO_NUM = nmult & CCM_ANALOG_PLL_AUDIO_NUM_MASK; - CCM_ANALOG_PLL_AUDIO_DENOM = ndiv & CCM_ANALOG_PLL_AUDIO_DENOM_MASK; - - CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_POWERDOWN;//Switch on PLL - while (!(CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK)) {}; //Wait for pll-lock - - const int div_post_pll = 1; // other values: 2,4 - CCM_ANALOG_MISC2 &= ~(CCM_ANALOG_MISC2_DIV_MSB | CCM_ANALOG_MISC2_DIV_LSB); - if(div_post_pll>1) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_LSB; - if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; - - CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS;//Disable Bypass - } - #endif -#else - //No IMXRT - #define IMXRT_CACHE_ENABLED 0 -#endif -*/ //end of commented block - -//////////// -// -// Changing the sample rate based on changing the I2S bus freuqency (just for Teensy 3.x??) -// -//Here's the function to change the sample rate of the system (via changing the clocking of the I2S bus) -//https://forum.pjrc.com/threads/38753-Discussion-about-a-simple-way-to-change-the-sample-rate?p=121365&viewfull=1#post121365 -// -//And, a post on how to compute the frac and div portions? I haven't checked the code presented in this post: -//https://forum.pjrc.com/threads/38753-Discussion-about-a-simple-way-to-change-the-sample-rate?p=188812&viewfull=1#post188812 -// -//Finally, here is my own Matlab code for computing the mult and div values...(again, just for Teensy 3.x??) -/* - %choose the sample rates that you are hoping to hit - targ_fs_Hz = [2000, 8000, 11025, 16000, 22050, 24000, 32000, 44100, floor(44117.64706) , ... - 48000, 88200, floor(44117.64706 * 2), (37000/256*662), 96000, 176400, floor(44117.64706 * 4), 192000]; - F_PLL = 180e6; %choose the clock rate used for this calculation - PLL_div = 256; - all_n=[];all_d=[]; - for Itarg=1:length(targ_fs_Hz) - if (0) - [best_d,best_n]=rat((F_PLL/PLL_div)/targ_fs_Hz(Itarg)); - else - best_n = 1; best_d = 1; best_err = 1e10; - for n=1:255 - d = [1:4095]; - act_fs_Hz = F_PLL / PLL_div * n ./ d; - [err,I] = min(abs(act_fs_Hz - targ_fs_Hz(Itarg))); - if err < best_err - best_n = n; best_d = d(I); - best_err = err; - end - end - end - all_n(Itarg) = best_n; - all_d(Itarg) = best_d; - disp(['fs = ' num2str(targ_fs_Hz(Itarg)) ', n = ' num2str(best_n) ', d = ' num2str(best_d) ', true = ' num2str(F_PLL/PLL_div * best_n / best_d)]) - end -*/ - float AudioOutputI2S_F32::setI2SFreq_T3(const float freq_Hz) { #if defined(KINETISK) //for Teensy 3.x only! int freq = (int)(freq_Hz+0.5); @@ -329,288 +253,6 @@ void AudioOutputI2S_F32::isr(void) #endif } -/* void AudioOutputI2S_F32::begin(bool transferUsing32bit) { - dma.begin(true); // Allocate the DMA channel first - block_left_1st = NULL; - block_right_1st = NULL; - // TODO: should we set & clear the I2S_TCSR_SR bit here? - config_i2s(transferUsing32bit); - CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0 - //setup DMA parameters - //if (transferUsing32bit) { - sub_begin_i32(); - //} else { - // sub_begin_i16(); - //} - - dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX); - update_responsibility = update_setup(); - dma.enable(); - I2S0_TCSR = I2S_TCSR_SR; - I2S0_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE; - dma.attachInterrupt(isr_32); - - // change the I2S frequencies to make the requested sample rate - setI2SFreq(AudioOutputI2S_F32::sample_rate_Hz); - - enabled = 1; - - //AudioInputI2S_F32::begin_guts(); -} */ - -/* void AudioOutputI2S_F32::sub_begin_i16(void) { - dma.TCD->SADDR = i2s_tx_buffer; - dma.TCD->SOFF = 2; - dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); - dma.TCD->NBYTES_MLNO = 2; - //dma.TCD->SLAST = -sizeof(i2s_tx_buffer); //original - dma.TCD->SLAST = -I2S_BUFFER_TO_USE_BYTES; - dma.TCD->DADDR = &I2S0_TDR0; - dma.TCD->DOFF = 0; - //dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; //original - dma.TCD->CITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 2; - dma.TCD->DLASTSGA = 0; - //dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; //original - dma.TCD->BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 2; - dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; -} -void AudioOutputI2S_F32::sub_begin_i32(void) { - dma.TCD->SADDR = i2s_tx_buffer; //here's where to get the data from - - //let's assume that we'll transfer each sample (left or right) independently. So 4-byte (32bit) transfers. - dma.TCD->SOFF = 4; //step forward pointer for source data by 4 bytes (ie, 32 bits) after each read - dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(DMA_TCD_ATTR_SIZE_32BIT) | DMA_TCD_ATTR_DSIZE(DMA_TCD_ATTR_SIZE_32BIT); //each read is 32 bits - dma.TCD->NBYTES_MLNO = 4; //how many bytes to send per minor loop. Do each sample (left or right) independently. So, 4 bytes? Should be 4 or 8? - - //dma.TCD->SLAST = -sizeof(i2s_tx_buffer); //original - dma.TCD->SLAST = -I2S_BUFFER_TO_USE_BYTES; //jump back to beginning of source data when hit the end - dma.TCD->DADDR = &I2S0_TDR0; //destination of DMA transfers - dma.TCD->DOFF = 0; //do not increment the destination pointer - //dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; //original - dma.TCD->CITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4; //number of minor loops in a major loop. I2S_BUFFER_TO_USE_BYTES/NBYTES_MLNO? Should be 4 or 8? - dma.TCD->DLASTSGA = 0; - //dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; //original - dma.TCD->BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4; //number of minor loops in a major loop. I2S_BUFFER_TO_USE_BYTES/NBYTES_MLNO? should be 4 or 8? - dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; -} - */ - -/* void AudioOutputI2S_F32::isr_16(void) -{ -#if defined(KINETISK) - int16_t *dest; - audio_block_t *blockL, *blockR; - uint32_t saddr, offsetL, offsetR; - saddr = (uint32_t)(dma.TCD->SADDR); - dma.clearInterrupt(); - //if (saddr < (uint32_t)i2s_tx_buffer + sizeof(i2s_tx_buffer) / 2) { //original - if (saddr < (uint32_t)i2s_tx_buffer + I2S_BUFFER_TO_USE_BYTES / 2) { - // DMA is transmitting the first half of the buffer - // so we must fill the second half - //dest = (int16_t *)&i2s_tx_buffer[AUDIO_BLOCK_SAMPLES/2]; //original - dest = (int16_t *)&i2s_tx_buffer[audio_block_samples/2]; - if (AudioOutputI2S_F32::update_responsibility) AudioStream_F32::update_all(); - } else { - // DMA is transmitting the second half of the buffer - // so we must fill the first half - dest = (int16_t *)i2s_tx_buffer; - } - blockL = AudioOutputI2S_F32::block_left_1st; - blockR = AudioOutputI2S_F32::block_right_1st; - offsetL = AudioOutputI2S_F32::block_left_offset; - offsetR = AudioOutputI2S_F32::block_right_offset; - - int16_t *d = dest; - if (blockL && blockR) { - //memcpy_tointerleaveLR(dest, blockL->data + offsetL, blockR->data + offsetR); - //memcpy_tointerleaveLRwLen(dest, blockL->data + offsetL, blockR->data + offsetR, audio_block_samples/2); - int16_t *pL = blockL->data + offsetL; - int16_t *pR = blockR->data + offsetR; - for (int i=0; i < audio_block_samples/2; i++) { *d++ = *pL++; *d++ = *pR++; } //interleave - offsetL += audio_block_samples / 2; - offsetR += audio_block_samples / 2; - } else if (blockL) { - //memcpy_tointerleaveLR(dest, blockL->data + offsetL, blockR->data + offsetR); - int16_t *pL = blockL->data + offsetL; - for (int i=0; i < audio_block_samples / 2 * 2; i+=2) { *(d+i) = *pL++; } //interleave - offsetL += audio_block_samples / 2; - } else if (blockR) { - int16_t *pR = blockR->data + offsetR; - for (int i=0; i < audio_block_samples /2 * 2; i+=2) { *(d+i) = *pR++; } //interleave - offsetR += audio_block_samples / 2; - } else { - //memset(dest,0,AUDIO_BLOCK_SAMPLES * 2); - memset(dest,0,audio_block_samples * 2); - return; - } - //if (offsetL < AUDIO_BLOCK_SAMPLES) { //original - if (offsetL < (uint16_t)audio_block_samples) { - AudioOutputI2S_F32::block_left_offset = offsetL; - } else { - AudioOutputI2S_F32::block_left_offset = 0; - AudioStream::release(blockL); - AudioOutputI2S_F32::block_left_1st = AudioOutputI2S_F32::block_left_2nd; - AudioOutputI2S_F32::block_left_2nd = NULL; - } - //if (offsetR < AUDIO_BLOCK_SAMPLES) { - if (offsetR < (uint16_t)audio_block_samples) { - AudioOutputI2S_F32::block_right_offset = offsetR; - } else { - AudioOutputI2S_F32::block_right_offset = 0; - AudioStream::release(blockR); - AudioOutputI2S_F32::block_right_1st = AudioOutputI2S_F32::block_right_2nd; - AudioOutputI2S_F32::block_right_2nd = NULL; - } -#else - const int16_t *src, *end; - int16_t *dest; - audio_block_t *block; - uint32_t saddr, offset; - saddr = (uint32_t)(dma.CFG->SAR); - dma.clearInterrupt(); - if (saddr < (uint32_t)i2s_tx_buffer + sizeof(i2s_tx_buffer) / 2) { - // DMA is transmitting the first half of the buffer - // so we must fill the second half - dest = (int16_t *)&i2s_tx_buffer[AUDIO_BLOCK_SAMPLES/2]; - end = (int16_t *)&i2s_tx_buffer[AUDIO_BLOCK_SAMPLES]; - if (AudioOutputI2S_F32::update_responsibility) AudioStream_F32::update_all(); - } else { - // DMA is transmitting the second half of the buffer - // so we must fill the first half - dest = (int16_t *)i2s_tx_buffer; - end = (int16_t *)&i2s_tx_buffer[AUDIO_BLOCK_SAMPLES/2]; - } - block = AudioOutputI2S_F32::block_left_1st; - if (block) { - offset = AudioOutputI2S_F32::block_left_offset; - src = &block->data[offset]; - do { - *dest = *src++; - dest += 2; - } while (dest < end); - offset += AUDIO_BLOCK_SAMPLES/2; - if (offset < AUDIO_BLOCK_SAMPLES) { - AudioOutputI2S_F32::block_left_offset = offset; - } else { - AudioOutputI2S_F32::block_left_offset = 0; - AudioStream::release(block); - AudioOutputI2S_F32::block_left_1st = AudioOutputI2S_F32::block_left_2nd; - AudioOutputI2S_F32::block_left_2nd = NULL; - } - } else { - do { - *dest = 0; - dest += 2; - } while (dest < end); - } - dest -= AUDIO_BLOCK_SAMPLES - 1; - block = AudioOutputI2S_F32::block_right_1st; - if (block) { - offset = AudioOutputI2S_F32::block_right_offset; - src = &block->data[offset]; - do { - *dest = *src++; - dest += 2; - } while (dest < end); - offset += AUDIO_BLOCK_SAMPLES/2; - if (offset < AUDIO_BLOCK_SAMPLES) { - AudioOutputI2S_F32::block_right_offset = offset; - } else { - AudioOutputI2S_F32::block_right_offset = 0; - AudioStream::release(block); - AudioOutputI2S_F32::block_right_1st = AudioOutputI2S_F32::block_right_2nd; - AudioOutputI2S_F32::block_right_2nd = NULL; - } - } else { - do { - *dest = 0; - dest += 2; - } while (dest < end); - } -#endif -} */ - -/* void AudioOutputI2S_F32::isr_32(void) //should be called every half of an audio block -{ - int32_t *dest; //int32 is the data type being sent to the audio codec - audio_block_f32_t *blockL, *blockR; - uint32_t saddr; - uint32_t offsetL, offsetR; - - saddr = (uint32_t)(dma.TCD->SADDR); - dma.clearInterrupt(); - //if (saddr < (uint32_t)i2s_tx_buffer + sizeof(i2s_tx_buffer) / 2) { //original 16-bit - if (saddr < (uint32_t)i2s_tx_buffer + I2S_BUFFER_TO_USE_BYTES / 2) { //are we transmitting the first half or second half of the buffer? - // DMA is transmitting the first half of the buffer - // so we must fill the second half - //dest = (int16_t *)&i2s_tx_buffer[AUDIO_BLOCK_SAMPLES/2]; //original, half-way through buffer (buffer is 32-bit elements filled with 16-bit stereo samples) - dest = (int32_t *)&i2s_tx_buffer[2*(audio_block_samples/2)]; //half-way through the buffer..remember, buffer is 32-bit elements filled with 32-bit stereo samples) - if (AudioOutputI2S_F32::update_responsibility) AudioStream_F32::update_all(); - } else { - // DMA is transmitting the second half of the buffer so we must fill the first half - dest = (int32_t *)i2s_tx_buffer; //beginning of the buffer - } - blockL = AudioOutputI2S_F32::block_left_1st; - blockR = AudioOutputI2S_F32::block_right_1st; - offsetL = AudioOutputI2S_F32::block_left_offset; - offsetR = AudioOutputI2S_F32::block_right_offset; - - int32_t *d = dest; - if (blockL && blockR) { - //memcpy_tointerleaveLR(dest, blockL->data + offsetL, blockR->data + offsetR); - //memcpy_tointerleaveLRwLen(dest, blockL->data + offsetL, blockR->data + offsetR, audio_block_samples/2); - float32_t *pL = blockL->data + offsetL; - float32_t *pR = blockR->data + offsetR; - for (int i=0; i < audio_block_samples/2; i++) { //loop over half of the audio block (this routine gets called every half an audio block) - *d++ = (int32_t) (*pL++); - *d++ = (int32_t) (*pR++); //cast and interleave - } - offsetL += (audio_block_samples / 2); - offsetR += (audio_block_samples / 2); - } else if (blockL) { - //memcpy_tointerleaveLR(dest, blockL->data + offsetL, blockR->data + offsetR); - float32_t *pL = blockL->data + offsetL; - for (int i=0; i < audio_block_samples /2; i++) { - *d++ = (int32_t) *pL++; //cast and interleave - *d++ = 0; - } - offsetL += (audio_block_samples / 2); - } else if (blockR) { - float32_t *pR = blockR->data + offsetR; - for (int i=0; i < audio_block_samples /2; i++) { - *d++ = 0; - *d++ = (int32_t) *pR++; //cast and interleave - } - offsetR += (audio_block_samples / 2); - } else { - //memset(dest,0,AUDIO_BLOCK_SAMPLES * 2); //half buffer (AUDIO_BLOCK_SAMPLES/2), 16-bits per sample (AUDIO_BLOCK_SAMPLES/2*2), stereo (AUDIO_BLOCK_SAMPLES/2*2*2) - //memset(dest,0,audio_block_samples * 2 * 4 / 2);//half buffer (AUDIO_BLOCK_SAMPLES/2), 32-bits per sample (AUDIO_BLOCK_SAMPLES/2*4), stereo (AUDIO_BLOCK_SAMPLES/2*4*2) - for (int i=0; i < audio_block_samples/2; i++) { //loop over half of the audio block (this routine gets called every half an audio block) - *d++ = (int32_t) 0; - *d++ = (int32_t) 0; - } - return; - } - //if (offsetL < AUDIO_BLOCK_SAMPLES) { //original - if (offsetL < (uint16_t)audio_block_samples) { - AudioOutputI2S_F32::block_left_offset = offsetL; - } else { - AudioOutputI2S_F32::block_left_offset = 0; - AudioStream_F32::release(blockL); - AudioOutputI2S_F32::block_left_1st = AudioOutputI2S_F32::block_left_2nd; - AudioOutputI2S_F32::block_left_2nd = NULL; - } - //if (offsetR < AUDIO_BLOCK_SAMPLES) { - if (offsetR < (uint16_t)audio_block_samples) { - AudioOutputI2S_F32::block_right_offset = offsetR; - } else { - AudioOutputI2S_F32::block_right_offset = 0; - AudioStream_F32::release(blockR); - AudioOutputI2S_F32::block_right_1st = AudioOutputI2S_F32::block_right_2nd; - AudioOutputI2S_F32::block_right_2nd = NULL; - } -} - */ #define F32_TO_I16_NORM_FACTOR (32767) //which is 2^15-1 void AudioOutputI2S_F32::scale_f32_to_i16(float32_t *p_f32, float32_t *p_i16, int len) { for (int i=0; idata, block_f32_scaled->data, audio_block_samples); //scale_f32_to_i16(block_f32->data, block_f32_scaled->data, audio_block_samples); - //count++; - //if (count > 100) { - // Serial.print("AudioOutputI2S_F32::update() orig, scaled = "); - // Serial.print(block_f32->data[30]); - // Serial.print(", "); - // Serial.println(block_f32_scaled->data[30]); - // count=0; - //} - - //now process the data blocks + //now process the data blocks __disable_irq(); if (block_left_1st == NULL) { block_left_1st = block_f32_scaled; @@ -897,11 +530,11 @@ void AudioOutputI2S_F32::config_i2s(bool transferUsing32bit, float fs_Hz) /******************************************************************/ -// From Chip: The I2SSlave functionality has NOT been extended to allow for different block sizes or sample rates (2020-10-31) +// From Chip: The I2SSlave functionality has NOT been extended to +// allow for different block sizes or sample rates (2020-10-31) void AudioOutputI2Sslave_F32::begin(void) { - dma.begin(true); // Allocate the DMA channel first //pinMode(2, OUTPUT); diff --git a/output_i2s_f32.h b/output_i2s_f32.h index bfea439..b8fe324 100644 --- a/output_i2s_f32.h +++ b/output_i2s_f32.h @@ -32,6 +32,7 @@ * The F32 conversion is under the MIT License. Use at your own risk. */ // Updated OpenAudio F32 with this version from Chip Audette's Tympan Library Jan 2021 RSL +// Removed old commented out code. RSL 30 May 2022 #ifndef output_i2s_f32_h_ #define output_i2s_f32_h_ @@ -39,7 +40,6 @@ #include #include #include "AudioStream_F32.h" -//include "AudioStream.h" #include "DMAChannel.h" class AudioOutputI2S_F32 : public AudioStream_F32 @@ -64,10 +64,7 @@ public: virtual void update(void); void begin(void); void begin(bool); - void sub_begin_i32(void); - void sub_begin_i16(void); friend class AudioInputI2S_F32; - friend class AudioInputI2S_F32; #if defined(__IMXRT1062__) friend class AudioOutputI2SQuad_F32; @@ -89,8 +86,6 @@ protected: static void config_i2s(bool); static void config_i2s(float); static void config_i2s(bool, float); - //static void config_i2s_i16(void,float); - //static void config_i2s_i32(void,float); static audio_block_f32_t *block_left_1st; static audio_block_f32_t *block_right_1st; static bool update_responsibility;