| #define HALF_BLOCKS AUDIO_GUITARTUNER_BLOCKS * 64 | #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) { | static void copy_buffer(void *destination, const void *source) { | ||||
| const uint16_t *src = (const uint16_t *)source; | const uint16_t *src = (const uint16_t *)source; | ||||
| uint16_t *dst = (uint16_t *)destination; | uint16_t *dst = (uint16_t *)destination; | ||||
| for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) *dst++ = *src++; | for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) *dst++ = *src++; | ||||
| } | } | ||||
| /** | |||||
| * Virtual function to override from Audio Library | |||||
| */ | |||||
| void AudioAnalyzeNoteFrequency::update( void ) { | void AudioAnalyzeNoteFrequency::update( void ) { | ||||
| audio_block_t *block; | audio_block_t *block; | ||||
| return; | return; | ||||
| } | } | ||||
| digitalWriteFast(2, HIGH); | |||||
| if ( next_buffer ) { | if ( next_buffer ) { | ||||
| blocklist1[state++] = block; | blocklist1[state++] = block; | ||||
| if ( !first_run && process_buffer ) process( ); | if ( !first_run && process_buffer ) process( ); | ||||
| process_buffer = true; | process_buffer = true; | ||||
| first_run = false; | first_run = false; | ||||
| state = 0; | 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 ) { | FASTRUN void AudioAnalyzeNoteFrequency::process( void ) { | ||||
| //digitalWriteFast(0, HIGH); | |||||
| const int16_t *p; | const int16_t *p; | ||||
| p = AudioBuffer; | p = AudioBuffer; | ||||
| do { | do { | ||||
| uint16_t x = 0; | uint16_t x = 0; | ||||
| int64_t sum = 0; | int64_t sum = 0; | ||||
| //uint32_t res; | |||||
| do { | 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; | 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 | #if F_CPU == 144000000 | ||||
| x += 8; | |||||
| x += 8; | |||||
| #elif F_CPU == 120000000 | #elif F_CPU == 120000000 | ||||
| x += 12; | |||||
| x += 12; | |||||
| #elif F_CPU == 96000000 | #elif F_CPU == 96000000 | ||||
| x += 16; | |||||
| x += 16; | |||||
| #elif F_CPU < 96000000 | #elif F_CPU < 96000000 | ||||
| x += 32; | |||||
| x += 32; | |||||
| #endif | #endif | ||||
| //); | |||||
| } while ( x <= HALF_BLOCKS ); | } while ( x <= HALF_BLOCKS ); | ||||
| running_sum += sum; | running_sum += sum; | ||||
| yin_buffer[yin_idx] = sum*tau; | yin_buffer[yin_idx] = sum*tau; | ||||
| rs_buffer[yin_idx] = running_sum; | rs_buffer[yin_idx] = running_sum; | ||||
| yin_idx = ( ++yin_idx >= 5 ) ? 0 : yin_idx; | yin_idx = ( ++yin_idx >= 5 ) ? 0 : yin_idx; | ||||
| tau = estimate( yin_buffer, rs_buffer, yin_idx, tau ); | tau = estimate( yin_buffer, rs_buffer, yin_idx, tau ); | ||||
| if ( tau == 0 ) { | if ( tau == 0 ) { | ||||
| process_buffer = false; | process_buffer = false; | ||||
| new_output = true; | new_output = true; | ||||
| yin_idx = 1; | yin_idx = 1; | ||||
| running_sum = 0; | running_sum = 0; | ||||
| tau_global = 1; | tau_global = 1; | ||||
| //digitalWriteFast(2, LOW); | |||||
| //digitalWriteFast(0, LOW); | |||||
| return; | return; | ||||
| } | } | ||||
| } while ( --cycles ); | } while ( --cycles ); | ||||
| yin_idx = 1; | yin_idx = 1; | ||||
| running_sum = 0; | running_sum = 0; | ||||
| tau_global = 1; | tau_global = 1; | ||||
| //digitalWriteFast(0, LOW); | |||||
| return; | return; | ||||
| } | } | ||||
| tau_global = tau; | 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 yin buffer to hold sum*tau value | ||||
| * @param rs buffer to hold running sum for sampled window | * @param rs buffer to hold running sum for sampled window | ||||
| * @param head buffer index | * @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 | * @return tau | ||||
| */ | */ | ||||
| * Initialise | * Initialise | ||||
| * | * | ||||
| * @param threshold Allowed uncertainty | * @param threshold Allowed uncertainty | ||||
| * @param cpu_max How much cpu usage before throttling | |||||
| */ | */ | ||||
| void AudioAnalyzeNoteFrequency::begin( float threshold ) { | void AudioAnalyzeNoteFrequency::begin( float threshold ) { | ||||
| __disable_irq( ); | __disable_irq( ); |