duff2013 9 år sedan
förälder
incheckning
2bd0f198d4
9 ändrade filer med 97 tillägg och 73 borttagningar
  1. +60
    -47
      AudioTuner.cpp
  2. +7
    -8
      AudioTuner.h
  3. +2
    -2
      README.md
  4. +10
    -7
      examples/Sample_Guitar_Tunning_Notes/Sample_Guitar_Tunning_Notes.ino
  5. +2
    -2
      examples/Simple_Sine/Handle_Commands.ino
  6. Binär
      examples/Simple_Sine/Simple_Sine.cpp.elf
  7. +10
    -6
      examples/Simple_Sine/Simple_Sine.ino
  8. +1
    -1
      library.properties
  9. +5
    -0
      revision.md

+ 60
- 47
AudioTuner.cpp Visa fil

end = p + AUDIO_BLOCK_SAMPLES; end = p + AUDIO_BLOCK_SAMPLES;
/* /*
* Set the number of cycles to processed per receiving block.
*
*/
uint16_t cycles;
const uint16_t usage_max = cpu_usage_max;
if ( AudioProcessorUsage( ) > usage_max ) {
#if NUM_SAMPLES >= 8192
cycles = tau_global + 2;
#elif NUM_SAMPLES == 4096
cycles = tau_global + 4;
#elif NUM_SAMPLES == 2048
cycles = tau_global + 8;
#elif NUM_SAMPLES <= 1024
cycles = tau_global + 16;
#endif
* Double buffering, one fills while the other is processed
* 2x the throughput.
*/
uint16_t *dst;
bool next = next_buffer;
if ( next ) {
//digitalWriteFast(6, HIGH);
dst = ( uint16_t * )buffer;
} }
else { else {
#if NUM_SAMPLES >= 8192
cycles = tau_global + 8;
#elif NUM_SAMPLES == 4096
cycles = tau_global + 16;
#elif NUM_SAMPLES == 2048
cycles = tau_global + 32;
#elif NUM_SAMPLES <= 1024
cycles = tau_global + 64;
#endif
//digitalWriteFast(6, LOW);
dst = ( uint16_t * )buffer + NUM_SAMPLES;
} }
// gather data/and release block
uint16_t count = count_global; uint16_t count = count_global;
/*
* Double buffering, one fill while the other is processed
* 2x the throughput.
*/
uint16_t *dst;
if ( next_buffer ) dst = ( uint16_t * )buffer;
else dst = ( uint16_t * )buffer + NUM_SAMPLES;
// gather data
do { do {
*( dst+count++ ) = *( uint16_t * )p; *( dst+count++ ) = *( uint16_t * )p;
p += SAMPLE_RATE; p += SAMPLE_RATE;
*/ */
if ( count >= NUM_SAMPLES ) { if ( count >= NUM_SAMPLES ) {
//digitalWriteFast(2, !digitalReadFast(2)); //digitalWriteFast(2, !digitalReadFast(2));
__disable_irq();
next_buffer = !next_buffer; next_buffer = !next_buffer;
process_buffer = true; process_buffer = true;
count_global = 0; count_global = 0;
yin_idx = 1; yin_idx = 1;
running_sum = 0; running_sum = 0;
count = 0; count = 0;
__enable_irq();
} }
count_global = count;// update global count count_global = count;// update global count
/*
* Set the number of cycles to be processed per receiving block.
*/
uint16_t cycles;
const uint16_t usage_max = cpu_usage_max;
if ( AudioProcessorUsage( ) > usage_max ) {
#if NUM_SAMPLES >= 8192
cycles = tau_global + 2;
#elif NUM_SAMPLES == 4096
cycles = tau_global + 4;
#elif NUM_SAMPLES == 2048
cycles = tau_global + 8;
#elif NUM_SAMPLES <= 1024
cycles = tau_global + 32;
#endif
}
else {
#if NUM_SAMPLES >= 8192
cycles = tau_global + 8;
#elif NUM_SAMPLES == 4096
cycles = tau_global + 16;
#elif NUM_SAMPLES == 2048
cycles = tau_global + 32;
#elif NUM_SAMPLES <= 1024
cycles = tau_global + 64;
#endif
}
if ( process_buffer ) { if ( process_buffer ) {
//digitalWriteFast(0, HIGH); //digitalWriteFast(0, HIGH);
uint16_t tau; uint16_t tau;
uint16_t next;
next = next_buffer; next = next_buffer;
tau = tau_global; tau = tau_global;
do { do {
int64_t sum = 0; int64_t sum = 0;
const int16_t *end, *buf; const int16_t *end, *buf;
if ( next ) buf = buffer + NUM_SAMPLES;
else buf = buffer;
if ( next ) {
//digitalWriteFast(4, LOW);
buf = buffer + NUM_SAMPLES;
}
else {
//digitalWriteFast(4, HIGH);
buf = buffer;
}
end = buf + HALF_BUFFER; end = buf + HALF_BUFFER;
// TODO: How to make faster?
do { do {
int16_t current, lag, delta; int16_t current, lag, delta;
UNROLL( 8, UNROLL( 8,
idx2 = ( idx2 >= 5 ) ? 0 : idx2; idx2 = ( idx2 >= 5 ) ? 0 : idx2;
float s0, s1, s2; float s0, s1, s2;
s0 = ( ( float )*( p+idx0 ) / r[idx0] );
s1 = ( ( float )*( p+idx1 ) / r[idx1] );
s2 = ( ( float )*( p+idx2 ) / r[idx2] );
s0 = ( ( float )*( p+idx0 ) / *( r+idx0 ) );
s1 = ( ( float )*( p+idx1 ) / *( r+idx1 ) );
s2 = ( ( float )*( p+idx2 ) / *( r+idx2 ) );
if ( s1 < yin_threshold && s1 < s2 ) { if ( s1 < yin_threshold && s1 < s2 ) {
uint16_t period = _tau - 3; uint16_t period = _tau - 3;
return 0; return 0;
} }
if ( s1 > 2.4 ) return _tau + 2;
else return _tau + 1;
//if ( s1 > 2.4 ) return _tau + 2;
//else return _tau + 1;
} }
return _tau + 1; return _tau + 1;
} }
* @param threshold Allowed uncertainty * @param threshold Allowed uncertainty
* @param cpu_max How much cpu usage before throttling * @param cpu_max How much cpu usage before throttling
*/ */
void AudioTuner::initialize( float threshold, uint8_t cpu_max ) {
void AudioTuner::initialize( float threshold, float cpu_max ) {
__disable_irq( ); __disable_irq( );
cpu_usage_max = cpu_max;
cpu_usage_max = cpu_max*100;
yin_threshold = threshold; yin_threshold = threshold;
process_buffer = false; process_buffer = false;
periodicity = 0.0f; periodicity = 0.0f;
next_buffer = 1;
next_buffer = true;
running_sum = 0; running_sum = 0;
count_global = 0; count_global = 0;
yin_idx = 1; yin_idx = 1;
__disable_irq( ); __disable_irq( );
float d = data; float d = data;
__enable_irq( ); __enable_irq( );
d = SAMPLE_RATE_EXACT / d;
return d;
return SAMPLE_RATE_EXACT / d;
} }


/** /**

+ 7
- 8
AudioTuner.h Visa fil

* *
* @return none * @return none
*/ */
AudioTuner( void ) : AudioStream( 1, inputQueueArray ), enabled( false ), new_output(false) {
digitalWriteFast(2, LOW);
}
AudioTuner( void ) : AudioStream( 1, inputQueueArray ), enabled( false ), new_output(false) {}
/** /**
* initialize variables and start conversion * initialize variables and start conversion
* *
* @param threshold Allowed uncertainty * @param threshold Allowed uncertainty
* @param cpu_max How much cpu usage before throttling * @param cpu_max How much cpu usage before throttling
*/ */
void initialize( float threshold, uint8_t cpu_max);
void initialize( float threshold, float cpu_max);
/** /**
* sets threshold value * sets threshold value
uint16_t estimate( int64_t *yin, int64_t *rs, uint16_t head, uint16_t tau ); uint16_t estimate( int64_t *yin, int64_t *rs, uint16_t head, uint16_t tau );
int16_t buffer[NUM_SAMPLES*2] __attribute__ ( ( aligned ( 4 ) ) ); int16_t buffer[NUM_SAMPLES*2] __attribute__ ( ( aligned ( 4 ) ) );
float periodicity, yin_threshold, data;
float periodicity, yin_threshold, data, cpu_usage_max;
int64_t rs_buffer[5], yin_buffer[5]; int64_t rs_buffer[5], yin_buffer[5];
uint64_t running_sum; uint64_t running_sum;
uint16_t tau_global, count_global, tau_cycles, cpu_usage_max;
uint8_t next_buffer, yin_idx;
bool enabled, process_buffer;
uint16_t tau_global, count_global, tau_cycles;
uint8_t yin_idx;
bool enabled, process_buffer, next_buffer;
volatile bool new_output; volatile bool new_output;
audio_block_t *inputQueueArray[1]; audio_block_t *inputQueueArray[1];
}; };

+ 2
- 2
README.md Visa fil

<p align="center"> <p align="center">
<b>Guitar and Bass Tuner Library</b><br>
<b>Teensy 3.1/2 v2.1</b><br>
<b>Guitar and Bass Tuner Library v2.2</b><br>
<b>Teensy 3.1/2</b><br>
</p> </p>


>Software algorithm ([YIN]) for guitar and bass tuning using a Teensy Audio Library. This audio object's algorithm can be some what memory and processor hungry but will allow you to detect with fairly good accuracy the fundamental frequencies f<sub>o</sub> from electric guitars and basses. >Software algorithm ([YIN]) for guitar and bass tuning using a Teensy Audio Library. This audio object's algorithm can be some what memory and processor hungry but will allow you to detect with fairly good accuracy the fundamental frequencies f<sub>o</sub> from electric guitars and basses.

+ 10
- 7
examples/Sample_Guitar_Tunning_Notes/Sample_Guitar_Tunning_Notes.ino Visa fil

Bass strings are (5th string) B0=30.87Hz, (4th string) E1=41.20Hz, A1=55Hz, D2=73.42Hz, G2=98Hz Bass strings are (5th string) B0=30.87Hz, (4th string) E1=41.20Hz, A1=55Hz, D2=73.42Hz, G2=98Hz
This example tests the yin algorithm with actual notes from nylon string guitar recorded This example tests the yin algorithm with actual notes from nylon string guitar recorded
as wav format at 16B @ 44100smpls/sec. Since the decay of the notes will be longer than what
as wav format at 16B @ 44100 samples/sec. Since the decay of the notes will be longer than what
the teensy can store in flash these notes are truncated to ~120,000B or about 1/2 of the whole the teensy can store in flash these notes are truncated to ~120,000B or about 1/2 of the whole
signal. signal.
*/ */
void setup() { void setup() {
AudioMemory(4); AudioMemory(4);
/* /*
* Intialize the yin algorithm's threshold
* and percent of current cpu usage used
* before slowing the algorithm down.
* Initialize the yin algorithm's absolute
* threshold, this is good number.
*
* Percent of overall current cpu usage used
* before making the search algorithm less
* aggressive (0.0 - 1.0).
*/ */
tuner.initialize(.15f, 90);
tuner.initialize(.15, .99);
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
playNoteTimer.begin(playNote, 1000); playNoteTimer.begin(playNote, 1000);
} }


void loop() { void loop() {
// read back fundmental frequency
// read back fundamental frequency
if (tuner.available()) { if (tuner.available()) {
float note = tuner.read(); float note = tuner.read();
float prob = tuner.probability(); float prob = tuner.probability();
Serial.printf("Note: %3.2f | Probility: %.2f\n", note, prob);
Serial.printf("Note: %3.2f | Probability: %.2f\n", note, prob);
} }
} }

+ 2
- 2
examples/Simple_Sine/Handle_Commands.ino Visa fil

float t = p.toFloat(); float t = p.toFloat();
Serial.print("new frequency: "); Serial.print("new frequency: ");
Serial.println(t); Serial.println(t);
//AudioNoInterrupts(); // disable audio library momentarily
AudioNoInterrupts(); // disable audio library momentarily
sine.frequency(p.toFloat()); sine.frequency(p.toFloat());
//AudioInterrupts(); // enable, both tones will start together
AudioInterrupts(); // enable, both tones will start together
} }
else if (p.startsWith("a ")) { else if (p.startsWith("a ")) {
p.trim(); p.trim();

Binär
examples/Simple_Sine/Simple_Sine.cpp.elf Visa fil


+ 10
- 6
examples/Simple_Sine/Simple_Sine.ino Visa fil

void setup() { void setup() {
AudioMemory(4); AudioMemory(4);
/* /*
* Intialize the yin algorithm's threshold
* and percent of current cpu usage used
* before slowing the algorithm down.
* Initialize the yin algorithm's absolute
* threshold, this is good number.
*
* Percent of overall current cpu usage used
* before making the search algorithm less
* aggressive (0.0 - 1.0).
*/ */
tuner.initialize(.15f, 90);
tuner.initialize(.15, .99);
sine.frequency(30.87); sine.frequency(30.87);
sine.amplitude(1); sine.amplitude(1);
} }


void loop() { void loop() {
// read back fundmental frequency
// read back fundamental frequency
if (tuner.available()) { if (tuner.available()) {
float note = tuner.read(); float note = tuner.read();
float prob = tuner.probability(); float prob = tuner.probability();
Serial.printf("Note: %3.2f | Probility: %.2f\n", note, prob);
Serial.printf("Note: %3.2f | Probability: %.2f\n", note, prob);
} }
if (Serial.available()) { if (Serial.available()) {

+ 1
- 1
library.properties Visa fil

name=AudioTuner name=AudioTuner
version=2.1
version=2.2
author=Colin Duffy author=Colin Duffy
maintainer=Colin Duffy maintainer=Colin Duffy
sentence=Yin algorithm sentence=Yin algorithm

+ 5
- 0
revision.md Visa fil

><b>Updated (10/12/15 v2.2)</b><br>
* Fixed yin cpu usage throttling code in update function.<br>
* Function initialize second param takes a float (0.0 - 1.0).<br>
* Fix many spelling and grammar errors. :(<br>

><b>Updated (10/11/15 v2.1)</b><br> ><b>Updated (10/11/15 v2.1)</b><br>
* Made yin implementation faster and more reliable.<br> * Made yin implementation faster and more reliable.<br>
* Improved user interface.<br> * Improved user interface.<br>

Laddar…
Avbryt
Spara