| @@ -26,22 +26,20 @@ | |||
| #define HALF_BLOCKS AUDIO_GUITARTUNER_BLOCKS * 64 | |||
| #define LOOP1(a) a | |||
| #define LOOP2(a) a LOOP1(a) | |||
| #define LOOP3(a) a LOOP2(a) | |||
| #define LOOP4(a) a LOOP3(a) | |||
| #define LOOP8(a) a LOOP3(a) a LOOP3(a) | |||
| #define LOOP16(a) a LOOP8(a) a LOOP2(a) a LOOP3(a) | |||
| #define LOOP32(a) a LOOP16(a) a LOOP8(a) a LOOP1(a) a LOOP3(a) | |||
| #define LOOP64(a) a LOOP32(a) a LOOP16(a) a LOOP8(a) a LOOP2(a) a LOOP1(a) | |||
| #define UNROLL(n,a) LOOP##n(a) | |||
| /** | |||
| * Copy internal blocks of data to class buffer | |||
| * | |||
| * @param destination destination address | |||
| * @param source source address | |||
| */ | |||
| static void copy_buffer(void *destination, const void *source) { | |||
| const uint16_t *src = (const uint16_t *)source; | |||
| uint16_t *dst = (uint16_t *)destination; | |||
| for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) *dst++ = *src++; | |||
| } | |||
| /** | |||
| * Virtual function to override from Audio Library | |||
| */ | |||
| void AudioAnalyzeNoteFrequency::update( void ) { | |||
| audio_block_t *block; | |||
| @@ -54,7 +52,6 @@ void AudioAnalyzeNoteFrequency::update( void ) { | |||
| return; | |||
| } | |||
| digitalWriteFast(2, HIGH); | |||
| if ( next_buffer ) { | |||
| blocklist1[state++] = block; | |||
| if ( !first_run && process_buffer ) process( ); | |||
| @@ -76,12 +73,17 @@ void AudioAnalyzeNoteFrequency::update( void ) { | |||
| process_buffer = true; | |||
| first_run = false; | |||
| state = 0; | |||
| //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN)); | |||
| } | |||
| } | |||
| /** | |||
| * Start the Yin algorithm | |||
| * | |||
| * TODO: Significant speed up would be to use spectral domain to find fundamental frequency. | |||
| * This paper explains: https://aubio.org/phd/thesis/brossier06thesis.pdf -> Section 3.2.4 | |||
| * page 79. Might have to downsample for low fundmental frequencies because of fft buffer | |||
| * size limit. | |||
| */ | |||
| FASTRUN void AudioAnalyzeNoteFrequency::process( void ) { | |||
| //digitalWriteFast(0, HIGH); | |||
| const int16_t *p; | |||
| p = AudioBuffer; | |||
| @@ -91,52 +93,35 @@ FASTRUN void AudioAnalyzeNoteFrequency::process( void ) { | |||
| do { | |||
| uint16_t x = 0; | |||
| int64_t sum = 0; | |||
| //uint32_t res; | |||
| do { | |||
| /*int16_t current1, lag1, current2, lag2; | |||
| int32_t val1, val2; | |||
| lag1 = *( ( uint32_t * )p + ( x + tau ) ); | |||
| current1 = *( ( uint32_t * )p + x ); | |||
| x += 32; | |||
| lag2 = *( ( uint32_t * )p + ( x + tau ) ); | |||
| current2 = *( ( uint32_t * )p + x ); | |||
| val1 = __PKHBT(current1, current2, 0x10); | |||
| val2 = __PKHBT(lag1, lag2, 0x10); | |||
| res = __SSUB16( val1, val2 ); | |||
| sum = __SMLALD(res, res, sum); | |||
| //sum = __SMLSLD(delta1, delta2, sum);*/ | |||
| int16_t current, lag, delta; | |||
| //UNROLL(16, | |||
| lag = *( ( int16_t * )p + ( x+tau ) ); | |||
| current = *( ( int16_t * )p+x ); | |||
| delta = ( current-lag ); | |||
| sum += delta * delta; | |||
| lag = *( ( int16_t * )p + ( x+tau ) ); | |||
| current = *( ( int16_t * )p+x ); | |||
| delta = ( current-lag ); | |||
| sum += delta * delta; | |||
| #if F_CPU == 144000000 | |||
| x += 8; | |||
| x += 8; | |||
| #elif F_CPU == 120000000 | |||
| x += 12; | |||
| x += 12; | |||
| #elif F_CPU == 96000000 | |||
| x += 16; | |||
| x += 16; | |||
| #elif F_CPU < 96000000 | |||
| x += 32; | |||
| x += 32; | |||
| #endif | |||
| //); | |||
| } while ( x <= HALF_BLOCKS ); | |||
| running_sum += sum; | |||
| yin_buffer[yin_idx] = sum*tau; | |||
| rs_buffer[yin_idx] = running_sum; | |||
| yin_idx = ( ++yin_idx >= 5 ) ? 0 : yin_idx; | |||
| tau = estimate( yin_buffer, rs_buffer, yin_idx, tau ); | |||
| if ( tau == 0 ) { | |||
| process_buffer = false; | |||
| new_output = true; | |||
| yin_idx = 1; | |||
| running_sum = 0; | |||
| tau_global = 1; | |||
| //digitalWriteFast(2, LOW); | |||
| //digitalWriteFast(0, LOW); | |||
| return; | |||
| } | |||
| } while ( --cycles ); | |||
| @@ -147,20 +132,18 @@ FASTRUN void AudioAnalyzeNoteFrequency::process( void ) { | |||
| yin_idx = 1; | |||
| running_sum = 0; | |||
| tau_global = 1; | |||
| //digitalWriteFast(0, LOW); | |||
| return; | |||
| } | |||
| tau_global = tau; | |||
| //digitalWriteFast(0, LOW); | |||
| } | |||
| /** | |||
| * check the sampled data for fundmental frequency | |||
| * check the sampled data for fundamental frequency | |||
| * | |||
| * @param yin buffer to hold sum*tau value | |||
| * @param rs buffer to hold running sum for sampled window | |||
| * @param head buffer index | |||
| * @param tau lag we are currently working on this gets incremented | |||
| * @param tau lag we are currently working on gets incremented | |||
| * | |||
| * @return tau | |||
| */ | |||
| @@ -200,7 +183,6 @@ uint16_t AudioAnalyzeNoteFrequency::estimate( int64_t *yin, int64_t *rs, uint16_ | |||
| * Initialise | |||
| * | |||
| * @param threshold Allowed uncertainty | |||
| * @param cpu_max How much cpu usage before throttling | |||
| */ | |||
| void AudioAnalyzeNoteFrequency::begin( float threshold ) { | |||
| __disable_irq( ); | |||