DMAMEM static uint16_t analog_rx_buffer[AUDIO_BLOCK_SAMPLES]; | DMAMEM static uint16_t analog_rx_buffer[AUDIO_BLOCK_SAMPLES]; | ||||
audio_block_t * AudioInputAnalog::block_left = NULL; | audio_block_t * AudioInputAnalog::block_left = NULL; | ||||
uint16_t AudioInputAnalog::block_offset = 0; | 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; | bool AudioInputAnalog::update_responsibility = false; | ||||
DMAChannel AudioInputAnalog::dma(false); | DMAChannel AudioInputAnalog::dma(false); | ||||
void AudioInputAnalog::init(uint8_t pin) | 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 | // Configure the ADC and run at least one software-triggered | ||||
// conversion. This completes the self calibration stuff and | // conversion. This completes the self calibration stuff and | ||||
#else | #else | ||||
analogReadAveraging(4); | analogReadAveraging(4); | ||||
#endif | #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 | // set the programmable delay block to trigger the ADC at 44.1 kHz | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
} | } | ||||
} | } | ||||
void AudioInputAnalog::update(void) | void AudioInputAnalog::update(void) | ||||
{ | { | ||||
audio_block_t *new_left=NULL, *out_left=NULL; | audio_block_t *new_left=NULL, *out_left=NULL; | ||||
uint32_t i, dc, offset; | |||||
uint32_t offset; | |||||
int32_t tmp; | int32_t tmp; | ||||
int16_t s, *p, *end; | int16_t s, *p, *end; | ||||
block_offset = 0; | block_offset = 0; | ||||
__enable_irq(); | __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; | p = out_left->data; | ||||
end = p + AUDIO_BLOCK_SAMPLES; | end = p + AUDIO_BLOCK_SAMPLES; | ||||
do { | 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; | *p++ = s; | ||||
} while (p < end); | } while (p < end); | ||||
current_dc_average_index = (current_dc_average_index + 1) % 16; | |||||
// then transmit the AC data | // then transmit the AC data | ||||
transmit(out_left); | transmit(out_left); | ||||
release(out_left); | release(out_left); | ||||
} | } | ||||
private: | private: | ||||
static audio_block_t *block_left; | static audio_block_t *block_left; | ||||
static uint16_t block_offset; | 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 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 | #endif |
audio_block_t * AudioInputAnalogStereo::block_right = NULL; | audio_block_t * AudioInputAnalogStereo::block_right = NULL; | ||||
uint16_t AudioInputAnalogStereo::offset_left = 0; | uint16_t AudioInputAnalogStereo::offset_left = 0; | ||||
uint16_t AudioInputAnalogStereo::offset_right = 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; | bool AudioInputAnalogStereo::update_responsibility = false; | ||||
DMAChannel AudioInputAnalogStereo::dma0(false); | DMAChannel AudioInputAnalogStereo::dma0(false); | ||||
DMAChannel AudioInputAnalogStereo::dma1(false); | DMAChannel AudioInputAnalogStereo::dma1(false); | ||||
void AudioInputAnalogStereo::init(uint8_t pin0, uint8_t pin1) | void AudioInputAnalogStereo::init(uint8_t pin0, uint8_t pin1) | ||||
{ | { | ||||
uint32_t i, sum0=0, sum1=0; | |||||
uint32_t tmp; | |||||
//pinMode(32, OUTPUT); | //pinMode(32, OUTPUT); | ||||
//pinMode(33, OUTPUT); | //pinMode(33, OUTPUT); | ||||
analogReadAveraging(4); | analogReadAveraging(4); | ||||
ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0); | ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0); | ||||
#endif | #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 | // set the programmable delay block to trigger the ADC at 44.1 kHz | ||||
//if (!(SIM_SCGC6 & SIM_SCGC6_PDB) | //if (!(SIM_SCGC6 & SIM_SCGC6_PDB) | ||||
} | } | ||||
void AudioInputAnalogStereo::update(void) | void AudioInputAnalogStereo::update(void) | ||||
{ | { | ||||
audio_block_t *new_left=NULL, *out_left=NULL; | audio_block_t *new_left=NULL, *out_left=NULL; | ||||
audio_block_t *new_right=NULL, *out_right=NULL; | audio_block_t *new_right=NULL, *out_right=NULL; | ||||
uint32_t i, dc; | |||||
int32_t tmp; | int32_t tmp; | ||||
int16_t s, *p, *end; | int16_t s, *p, *end; | ||||
offset_right = 0; | offset_right = 0; | ||||
__enable_irq(); | __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 | // then transmit the AC data | ||||
transmit(out_left, 0); | transmit(out_left, 0); |
static audio_block_t *block_right; | static audio_block_t *block_right; | ||||
static uint16_t offset_left; | static uint16_t offset_left; | ||||
static uint16_t offset_right; | 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 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 | #endif |
{ | { | ||||
uint32_t t; | uint32_t t; | ||||
asm ("mov %[t],#0\n" | 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 | #endif |