| @@ -31,15 +31,17 @@ | |||
| DMAMEM static uint16_t analog_rx_buffer[AUDIO_BLOCK_SAMPLES]; | |||
| audio_block_t * AudioInputAnalog::block_left = NULL; | |||
| uint16_t AudioInputAnalog::block_offset = 0; | |||
| int32_t AudioInputAnalog::dc_average_hist[16]; | |||
| int32_t AudioInputAnalog::current_dc_average_index = 0; | |||
| int32_t AudioInputAnalog::hpf_y1 = 0; | |||
| int32_t AudioInputAnalog::hpf_x1 = 0; | |||
| int32_t AudioInputAnalog::a = 1048300; | |||
| bool AudioInputAnalog::update_responsibility = false; | |||
| DMAChannel AudioInputAnalog::dma(false); | |||
| void AudioInputAnalog::init(uint8_t pin) | |||
| { | |||
| uint32_t i, sum=0; | |||
| int32_t tmp; | |||
| a = 1048300; // DC Removal filter coefficient in S12.19 | |||
| // Configure the ADC and run at least one software-triggered | |||
| // conversion. This completes the self calibration stuff and | |||
| @@ -51,13 +53,13 @@ void AudioInputAnalog::init(uint8_t pin) | |||
| #else | |||
| analogReadAveraging(4); | |||
| #endif | |||
| // Actually, do many normal reads, to start with a nice DC level | |||
| for (i=0; i < 1024; i++) { | |||
| sum += analogRead(pin); | |||
| } | |||
| for (i = 0; i < 16; i++) { | |||
| dc_average_hist[i] = sum >> 10; | |||
| } | |||
| // Note for review: | |||
| // Probably not useful to spin cycles here stabilizing | |||
| // since DC blocking is similar to te external analog filters | |||
| tmp = (uint16_t) analogRead(pin); | |||
| tmp = ( ((int32_t) tmp) << 4); | |||
| hpf_x1 = tmp; // With constant DC level x1 would be x0 | |||
| hpf_y1 = 0; // Output will settle here when stable | |||
| // set the programmable delay block to trigger the ADC at 44.1 kHz | |||
| #if defined(KINETISK) | |||
| @@ -135,12 +137,10 @@ void AudioInputAnalog::isr(void) | |||
| } | |||
| } | |||
| void AudioInputAnalog::update(void) | |||
| { | |||
| audio_block_t *new_left=NULL, *out_left=NULL; | |||
| uint32_t i, dc, offset; | |||
| uint32_t offset; | |||
| int32_t tmp; | |||
| int16_t s, *p, *end; | |||
| @@ -185,28 +185,31 @@ void AudioInputAnalog::update(void) | |||
| block_offset = 0; | |||
| __enable_irq(); | |||
| // Find and subtract DC offset... We use an average of the | |||
| // last 16 * AUDIO_BLOCK_SAMPLES samples. | |||
| dc = 0; | |||
| for (i = 0; i < 16; i++) { | |||
| dc += dc_average_hist[i]; | |||
| } | |||
| dc /= 16 * AUDIO_BLOCK_SAMPLES; | |||
| dc_average_hist[current_dc_average_index] = 0; | |||
| // | |||
| // DC Offset Removal Filter | |||
| // 1-pole digital high-pass filter implementation | |||
| // y = a*(x[n] - x[n-1] + y[n-1]) | |||
| // The coefficient "a" is as follows: | |||
| // a = UNITY*e^(-2*pi*fc/fs) | |||
| // UNITY = 2^20 | |||
| // fc = 2 | |||
| // fs = 44100 | |||
| // | |||
| p = out_left->data; | |||
| end = p + AUDIO_BLOCK_SAMPLES; | |||
| do { | |||
| dc_average_hist[current_dc_average_index] += (uint16_t)(*p); | |||
| tmp = (uint16_t)(*p) - (int32_t)dc; | |||
| s = signed_saturate_rshift(tmp, 16, 0); | |||
| tmp = (uint16_t)(*p); | |||
| tmp = ( ((int32_t) tmp) << 4); | |||
| int32_t acc = tmp; | |||
| acc += hpf_y1; | |||
| acc -= hpf_x1; | |||
| hpf_y1 = FRACMUL_SHL(acc, a, 11); | |||
| hpf_x1 = tmp; | |||
| s = signed_saturate_rshift(hpf_y1, 16, 4); | |||
| *p++ = s; | |||
| } while (p < end); | |||
| current_dc_average_index = (current_dc_average_index + 1) % 16; | |||
| // then transmit the AC data | |||
| transmit(out_left); | |||
| release(out_left); | |||
| } | |||
| @@ -41,12 +41,15 @@ public: | |||
| private: | |||
| static audio_block_t *block_left; | |||
| static uint16_t block_offset; | |||
| static int32_t dc_average_hist[16]; | |||
| static int32_t current_dc_average_index; | |||
| static int32_t hpf_y1; | |||
| static int32_t hpf_x1; | |||
| static int32_t a; | |||
| static bool update_responsibility; | |||
| static DMAChannel dma; | |||
| static void isr(void); | |||
| static void init(uint8_t pin); | |||
| static DMAChannel dma; | |||
| static void isr(void); | |||
| static void init(uint8_t pin); | |||
| }; | |||
| #endif | |||
| @@ -36,9 +36,9 @@ audio_block_t * AudioInputAnalogStereo::block_left = NULL; | |||
| audio_block_t * AudioInputAnalogStereo::block_right = NULL; | |||
| uint16_t AudioInputAnalogStereo::offset_left = 0; | |||
| uint16_t AudioInputAnalogStereo::offset_right = 0; | |||
| int32_t AudioInputAnalogStereo::left_dc_average_hist[16]; | |||
| int32_t AudioInputAnalogStereo::right_dc_average_hist[16]; | |||
| int32_t AudioInputAnalogStereo::current_dc_average_index = 0; | |||
| int32_t AudioInputAnalogStereo::hpf_y1[2] = { 0, 0 }; | |||
| int32_t AudioInputAnalogStereo::hpf_x1[2] = { 0, 0 }; | |||
| int32_t AudioInputAnalogStereo::a = 1048300; | |||
| bool AudioInputAnalogStereo::update_responsibility = false; | |||
| DMAChannel AudioInputAnalogStereo::dma0(false); | |||
| DMAChannel AudioInputAnalogStereo::dma1(false); | |||
| @@ -47,7 +47,7 @@ static int analogReadADC1(uint8_t pin); | |||
| void AudioInputAnalogStereo::init(uint8_t pin0, uint8_t pin1) | |||
| { | |||
| uint32_t i, sum0=0, sum1=0; | |||
| uint32_t tmp; | |||
| //pinMode(32, OUTPUT); | |||
| //pinMode(33, OUTPUT); | |||
| @@ -64,15 +64,20 @@ void AudioInputAnalogStereo::init(uint8_t pin0, uint8_t pin1) | |||
| analogReadAveraging(4); | |||
| ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0); | |||
| #endif | |||
| // Actually, do many normal reads, to start with a nice DC level | |||
| for (i=0; i < 1024; i++) { | |||
| sum0 += analogRead(pin0); | |||
| sum1 += analogReadADC1(pin1); | |||
| } | |||
| for (i = 0; i < 16; i++) { | |||
| left_dc_average_hist[i] = sum0 >> 10; | |||
| right_dc_average_hist[i] = sum1 >> 10; | |||
| } | |||
| // Note for review: | |||
| // Probably not useful to spin cycles here stabilizing | |||
| // since DC blocking is similar to te external analog filters | |||
| tmp = (uint16_t) analogRead(pin0); | |||
| tmp = ( ((int32_t) tmp) << 4); | |||
| hpf_x1[0] = tmp; // With constant DC level x1 would be x0 | |||
| hpf_y1[0] = 0; // Output will settle here when stable | |||
| tmp = (uint16_t) analogReadADC1(pin1); | |||
| tmp = ( ((int32_t) tmp) << 4); | |||
| hpf_x1[1] = tmp; // With constant DC level x1 would be x0 | |||
| hpf_y1[1] = 0; // Output will settle here when stable | |||
| // set the programmable delay block to trigger the ADC at 44.1 kHz | |||
| //if (!(SIM_SCGC6 & SIM_SCGC6_PDB) | |||
| @@ -203,13 +208,10 @@ void AudioInputAnalogStereo::isr1(void) | |||
| } | |||
| void AudioInputAnalogStereo::update(void) | |||
| { | |||
| audio_block_t *new_left=NULL, *out_left=NULL; | |||
| audio_block_t *new_right=NULL, *out_right=NULL; | |||
| uint32_t i, dc; | |||
| int32_t tmp; | |||
| int16_t s, *p, *end; | |||
| @@ -254,38 +256,46 @@ void AudioInputAnalogStereo::update(void) | |||
| offset_right = 0; | |||
| __enable_irq(); | |||
| // Find and subtract DC offset... We use an average of the | |||
| // last 16 * AUDIO_BLOCK_SAMPLES samples. | |||
| dc = 0; | |||
| for (i = 0; i < 16; i++) { | |||
| dc += left_dc_average_hist[i]; | |||
| } | |||
| dc /= 16 * AUDIO_BLOCK_SAMPLES; | |||
| left_dc_average_hist[current_dc_average_index] = 0; | |||
| p = out_left->data; | |||
| end = p + AUDIO_BLOCK_SAMPLES; | |||
| do { | |||
| left_dc_average_hist[current_dc_average_index] += (uint16_t)(*p); | |||
| tmp = (uint16_t)(*p) - (int32_t)dc; | |||
| s = signed_saturate_rshift(tmp, 16, 0); | |||
| *p++ = s; | |||
| } while (p < end); | |||
| dc = 0; | |||
| for (i = 0; i < 16; i++) { | |||
| dc += right_dc_average_hist[i]; | |||
| } | |||
| dc /= 16 * AUDIO_BLOCK_SAMPLES; | |||
| right_dc_average_hist[current_dc_average_index] = 0; | |||
| p = out_right->data; | |||
| end = p + AUDIO_BLOCK_SAMPLES; | |||
| do { | |||
| right_dc_average_hist[current_dc_average_index] += (uint16_t)(*p); | |||
| tmp = (uint16_t)(*p) - (int32_t)dc; | |||
| s = signed_saturate_rshift(tmp, 16, 0); | |||
| *p++ = s; | |||
| } while (p < end); | |||
| current_dc_average_index = (current_dc_average_index + 1) % 16; | |||
| // | |||
| // DC Offset Removal Filter | |||
| // 1-pole digital high-pass filter implementation | |||
| // y = a*(x[n] - x[n-1] + y[n-1]) | |||
| // The coefficient "a" is as follows: | |||
| // a = UNITY*e^(-2*pi*fc/fs) | |||
| // UNITY = 2^20 | |||
| // fc = 2 | |||
| // fs = 44100 | |||
| // | |||
| // DC removal, LEFT | |||
| p = out_left->data; | |||
| end = p + AUDIO_BLOCK_SAMPLES; | |||
| do { | |||
| tmp = (uint16_t)(*p); | |||
| tmp = ( ((int32_t) tmp) << 4); | |||
| int32_t acc = tmp; | |||
| acc += hpf_y1[0]; | |||
| acc -= hpf_x1[0]; | |||
| hpf_y1[0] = FRACMUL_SHL(acc, a, 11); | |||
| hpf_x1[0] = tmp; | |||
| s = signed_saturate_rshift(hpf_y1[0], 16, 4); | |||
| *p++ = s; | |||
| } while (p < end); | |||
| // DC removal, RIGHT | |||
| p = out_right->data; | |||
| end = p + AUDIO_BLOCK_SAMPLES; | |||
| do { | |||
| tmp = (uint16_t)(*p); | |||
| tmp = ( ((int32_t) tmp) << 4); | |||
| int32_t acc = tmp; | |||
| acc += hpf_y1[1]; | |||
| acc -= hpf_x1[1]; | |||
| hpf_y1[1]= FRACMUL_SHL(acc, a, 11); | |||
| hpf_x1[1] = tmp; | |||
| s = signed_saturate_rshift(hpf_y1[1], 16, 4); | |||
| *p++ = s; | |||
| } while (p < end); | |||
| // then transmit the AC data | |||
| transmit(out_left, 0); | |||
| @@ -46,15 +46,16 @@ private: | |||
| static audio_block_t *block_right; | |||
| static uint16_t offset_left; | |||
| static uint16_t offset_right; | |||
| static int32_t left_dc_average_hist[16]; | |||
| static int32_t right_dc_average_hist[16]; | |||
| static int32_t current_dc_average_index; | |||
| static int32_t hpf_y1[2]; | |||
| static int32_t hpf_x1[2]; | |||
| static int32_t a; | |||
| static bool update_responsibility; | |||
| static DMAChannel dma0; | |||
| static DMAChannel dma1; | |||
| static void isr0(void); | |||
| static void isr1(void); | |||
| static void init(uint8_t pin0, uint8_t pin1); | |||
| static DMAChannel dma0; | |||
| static DMAChannel dma1; | |||
| static void isr0(void); | |||
| static void isr1(void); | |||
| static void init(uint8_t pin0, uint8_t pin1); | |||
| }; | |||
| #endif | |||
| @@ -348,7 +348,23 @@ static inline void clr_q_psr(void) | |||
| { | |||
| uint32_t t; | |||
| asm ("mov %[t],#0\n" | |||
| "msr APSR_nzcvq,%0\n" : [t] "=&r" (t)::"cc"); | |||
| "msr APSR_nzcvq,%0\n" : [t] "=&r" (t)::"cc"); | |||
| } | |||
| // Multiply two S.31 fractional integers, and return the 32 most significant | |||
| // bits after a shift left by the constant z. | |||
| // This comes from rockbox.org | |||
| static inline int32_t FRACMUL_SHL(int32_t x, int32_t y, int z) | |||
| { | |||
| int32_t t, t2; | |||
| asm ("smull %[t], %[t2], %[a], %[b]\n\t" | |||
| "mov %[t2], %[t2], asl %[c]\n\t" | |||
| "orr %[t], %[t2], %[t], lsr %[d]\n\t" | |||
| : [t] "=&r" (t), [t2] "=&r" (t2) | |||
| : [a] "r" (x), [b] "r" (y), | |||
| [c] "Mr" ((z) + 1), [d] "Mr" (31 - (z))); | |||
| return t; | |||
| } | |||
| #endif | |||