Browse Source

Merge remote-tracking branch 'refs/remotes/PaulStoffregen/master'

dds
Michele Perla 9 years ago
parent
commit
45bb092d2d
28 changed files with 10475 additions and 6 deletions
  1. +1
    -0
      Audio.h
  2. +267
    -0
      analyze_notefreq.cpp
  3. +132
    -0
      analyze_notefreq.h
  4. +84
    -0
      examples/Analysis/NoteFrequency/NoteFrequency.ino
  5. +4910
    -0
      examples/Analysis/NoteFrequency/a2_note.cpp
  6. +2
    -0
      examples/Analysis/NoteFrequency/a2_note.h
  7. +1
    -0
      examples/Analysis/NoteFrequency/b3_note.cpp
  8. +2
    -0
      examples/Analysis/NoteFrequency/b3_note.h
  9. +1
    -0
      examples/Analysis/NoteFrequency/d3_note.cpp
  10. +2
    -0
      examples/Analysis/NoteFrequency/d3_note.h
  11. +4912
    -0
      examples/Analysis/NoteFrequency/e2_note.cpp
  12. +2
    -0
      examples/Analysis/NoteFrequency/e2_note.h
  13. +1
    -0
      examples/Analysis/NoteFrequency/e4_note.cpp
  14. +2
    -0
      examples/Analysis/NoteFrequency/e4_note.h
  15. +1
    -0
      examples/Analysis/NoteFrequency/g3_note.cpp
  16. +2
    -0
      examples/Analysis/NoteFrequency/g3_note.h
  17. +1
    -1
      examples/WavFilePlayer/WavFilePlayer.ino
  18. +0
    -0
      extras/wav2sketch/wav2sketch.exe
  19. +0
    -0
      gui/font-awesome/fonts/fontawesome-webfont.eot
  20. +0
    -0
      gui/font-awesome/fonts/fontawesome-webfont.svg
  21. +0
    -0
      gui/font-awesome/fonts/fontawesome-webfont.ttf
  22. +0
    -0
      gui/font-awesome/fonts/fontawesome-webfont.woff
  23. +59
    -1
      gui/index.html
  24. +5
    -3
      gui/red/nodes.js
  25. +63
    -1
      gui/red/ui/view.js
  26. +4
    -0
      keywords.txt
  27. +17
    -0
      synth_waveform.cpp
  28. +4
    -0
      synth_waveform.h

+ 1
- 0
Audio.h View File

#include "analyze_fft1024.h" #include "analyze_fft1024.h"
#include "analyze_print.h" #include "analyze_print.h"
#include "analyze_tonedetect.h" #include "analyze_tonedetect.h"
#include "analyze_notefreq.h"
#include "analyze_peak.h" #include "analyze_peak.h"
#include "control_sgtl5000.h" #include "control_sgtl5000.h"
#include "control_wm8731.h" #include "control_wm8731.h"

+ 267
- 0
analyze_notefreq.cpp View File

/* Audio Library Note Frequency Detection & Guitar/Bass Tuner
* Copyright (c) 2015, Colin Duffy
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "analyze_notefreq.h"
#include "utility/dspinst.h"
#include "arm_math.h"

#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)

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++;
}

void AudioAnalyzeNoteFrequency::update( void ) {
audio_block_t *block;
block = receiveReadOnly();
if (!block) return;
if ( !enabled ) {
release( block );
return;
}
digitalWriteFast(2, HIGH);
if ( next_buffer ) {
blocklist1[state++] = block;
if ( !first_run && process_buffer ) process( );
} else {
blocklist2[state++] = block;
if ( !first_run && process_buffer ) process( );
}
if ( state >= AUDIO_GUITARTUNER_BLOCKS ) {
if ( next_buffer ) {
if ( !first_run && process_buffer ) process( );
for ( int i = 0; i < AUDIO_GUITARTUNER_BLOCKS; i++ ) copy_buffer( AudioBuffer+( i * 0x80 ), blocklist1[i]->data );
for ( int i = 0; i < AUDIO_GUITARTUNER_BLOCKS; i++ ) release(blocklist1[i] );
} else {
if ( !first_run && process_buffer ) process( );
for ( int i = 0; i < AUDIO_GUITARTUNER_BLOCKS; i++ ) copy_buffer( AudioBuffer+( i * 0x80 ), blocklist2[i]->data );
for ( int i = 0; i < AUDIO_GUITARTUNER_BLOCKS; i++ ) release( blocklist2[i] );
}
process_buffer = true;
first_run = false;
state = 0;
//digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
}
}

FASTRUN void AudioAnalyzeNoteFrequency::process( void ) {
//digitalWriteFast(0, HIGH);
const int16_t *p;
p = AudioBuffer;
uint16_t cycles = 64;
uint16_t tau = tau_global;
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;
#if F_CPU == 144000000
x += 8;
#elif F_CPU == 120000000
x += 12;
#elif F_CPU == 96000000
x += 16;
#elif F_CPU < 96000000
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 );
if ( tau >= HALF_BLOCKS ) {
process_buffer = false;
new_output = false;
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
*
* @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
*
* @return tau
*/
uint16_t AudioAnalyzeNoteFrequency::estimate( int64_t *yin, int64_t *rs, uint16_t head, uint16_t tau ) {
const int64_t *y = ( int64_t * )yin;
const int64_t *r = ( int64_t * )rs;
uint16_t _tau, _head;
const float thresh = yin_threshold;
_tau = tau;
_head = head;
if ( _tau > 4 ) {
uint16_t idx0, idx1, idx2;
idx0 = _head;
idx1 = _head + 1;
idx1 = ( idx1 >= 5 ) ? 0 : idx1;
idx2 = head + 2;
idx2 = ( idx2 >= 5 ) ? 0 : idx2;
float s0, s1, s2;
s0 = ( ( float )*( y+idx0 ) / *( r+idx0 ) );
s1 = ( ( float )*( y+idx1 ) / *( r+idx1 ) );
s2 = ( ( float )*( y+idx2 ) / *( r+idx2 ) );
if ( s1 < thresh && s1 < s2 ) {
uint16_t period = _tau - 3;
periodicity = 1 - s1;
data = period + 0.5f * ( s0 - s2 ) / ( s0 - 2.0f * s1 + s2 );
return 0;
}
}
return _tau + 1;
}

/**
* Initialise
*
* @param threshold Allowed uncertainty
* @param cpu_max How much cpu usage before throttling
*/
void AudioAnalyzeNoteFrequency::begin( float threshold ) {
__disable_irq( );
process_buffer = false;
yin_threshold = threshold;
periodicity = 0.0f;
next_buffer = true;
running_sum = 0;
tau_global = 1;
first_run = true;
yin_idx = 1;
enabled = true;
state = 0;
data = 0.0f;
__enable_irq( );
}

/**
* available
*
* @return true if data is ready else false
*/
bool AudioAnalyzeNoteFrequency::available( void ) {
__disable_irq( );
bool flag = new_output;
if ( flag ) new_output = false;
__enable_irq( );
return flag;
}

/**
* read processes the data samples for the Yin algorithm.
*
* @return frequency in hertz
*/
float AudioAnalyzeNoteFrequency::read( void ) {
__disable_irq( );
float d = data;
__enable_irq( );
return AUDIO_SAMPLE_RATE_EXACT / d;
}

/**
* Periodicity of the sampled signal from Yin algorithm from read function.
*
* @return periodicity
*/
float AudioAnalyzeNoteFrequency::probability( void ) {
__disable_irq( );
float p = periodicity;
__enable_irq( );
return p;
}

/**
* Initialise parameters.
*
* @param thresh Allowed uncertainty
*/
void AudioAnalyzeNoteFrequency::threshold( float p ) {
__disable_irq( );
yin_threshold = p;
__enable_irq( );
}

+ 132
- 0
analyze_notefreq.h View File

/* Audio Library Note Frequency Detection & Guitar/Bass Tuner
* Copyright (c) 2015, Colin Duffy
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef AudioAnalyzeNoteFrequency_h_
#define AudioAnalyzeNoteFrequency_h_

#include "AudioStream.h"
/***********************************************************************
* Safe to adjust these values below *
* *
* This parameter defines the size of the buffer. *
* *
* 1. AUDIO_GUITARTUNER_BLOCKS - Buffer size is 128 * AUDIO_BLOCKS. *
* The more AUDIO_GUITARTUNER_BLOCKS the lower *
* the frequency you can detect. The default *
* (24) is set to measure down to 29.14 Hz *
* or B(flat)0. *
* *
***********************************************************************/
#define AUDIO_GUITARTUNER_BLOCKS 24
/***********************************************************************/
class AudioAnalyzeNoteFrequency : public AudioStream {
public:
/**
* constructor to setup Audio Library and initialize
*
* @return none
*/
AudioAnalyzeNoteFrequency( void ) : AudioStream( 1, inputQueueArray ), enabled( false ), new_output(false) {
}
/**
* initialize variables and start conversion
*
* @param threshold Allowed uncertainty
* @param cpu_max How much cpu usage before throttling
*
* @return none
*/
void begin( float threshold );
/**
* sets threshold value
*
* @param thresh
* @return none
*/
void threshold( float p );
/**
* triggers true when valid frequency is found
*
* @return flag to indicate valid frequency is found
*/
bool available( void );
/**
* get frequency
*
* @return frequency in hertz
*/
float read( void );
/**
* get predicitity
*
* @return probability of frequency found
*/
float probability( void );
/**
* Audio Library calls this update function ~2.9ms
*
* @return none
*/
virtual void update( void );

private:
/**
* 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
*
* @return tau
*/
uint16_t estimate( int64_t *yin, int64_t *rs, uint16_t head, uint16_t tau );
/**
* process audio data
*
* @return none
*/
void process( void );
/**
* Variables
*/
uint64_t running_sum;
uint16_t tau_global;
int64_t rs_buffer[5], yin_buffer[5];
int16_t AudioBuffer[AUDIO_GUITARTUNER_BLOCKS*128] __attribute__ ( ( aligned ( 4 ) ) );
uint8_t yin_idx, state;
float periodicity, yin_threshold, cpu_usage_max, data;
bool enabled, next_buffer, first_run;
volatile bool new_output, process_buffer;
audio_block_t *blocklist1[AUDIO_GUITARTUNER_BLOCKS];
audio_block_t *blocklist2[AUDIO_GUITARTUNER_BLOCKS];
audio_block_t *inputQueueArray[1];
};
#endif

+ 84
- 0
examples/Analysis/NoteFrequency/NoteFrequency.ino View File

/* Detect the frequency of music notes, by Colin Duffy

This example repeatedly plays a guitar note (output to the DAC pin)
and prints an analysis of the frequency to the Arduino Serial Monitor

https://forum.pjrc.com/threads/32252-Different-Range-FFT-Algorithm/page2
https://github.com/duff2013/AudioTuner
*/
/*
C C# D Eb E F F# G G# A Bb B
0 16.35 17.32 18.35 19.45 20.60 21.83 23.12 24.50 25.96 27.50 29.14 30.87
1 32.70 34.65 36.71 38.89 41.20 43.65 46.25 49.00 51.91 55.00 58.27 61.74
2 65.41 69.30 73.42 77.78 82.41 87.31 92.50 98.00 103.8 110.0 116.5 123.5
3 130.8 138.6 146.8 155.6 164.8 174.6 185.0 196.0 207.7 220.0 233.1 246.9
4 261.6 277.2 293.7 311.1 329.6 349.2 370.0 392.0 415.3 440.0 466.2 493.9
5 523.3 554.4 587.3 622.3 659.3 698.5 740.0 784.0 830.6 880.0 932.3 987.8
6 1047 1109 1175 1245 1319 1397 1480 1568 1661 1760 1865 1976
7 2093 2217 2349 2489 2637 2794 2960 3136 3322 3520 3729 3951
8 4186 4435 4699 4978 5274 5588 5920 6272 6645 7040 7459 7902
Guitar strings are E2=82.41Hz, A2=110Hz, D3=146.8Hz, G3=196Hz, B3=246.9Hz, E4=329.6Hz
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
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
signal.
*/
#include <SerialFlash.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
//---------------------------------------------------------------------------------------
#include "e2_note.h"
#include "a2_note.h"
#include "d3_note.h"
#include "g3_note.h"
#include "b3_note.h"
#include "e4_note.h"
//---------------------------------------------------------------------------------------
AudioAnalyzeNoteFrequency notefreq;
AudioOutputAnalog dac;
AudioPlayMemory wav_note;
AudioMixer4 mixer;
//---------------------------------------------------------------------------------------
AudioConnection patchCord0(wav_note, 0, mixer, 0);
AudioConnection patchCord1(mixer, 0, notefreq, 0);
AudioConnection patchCord2(mixer, 0, dac, 0);
//---------------------------------------------------------------------------------------
IntervalTimer playNoteTimer;

void playNote(void) {
if (!wav_note.isPlaying()) {
wav_note.play(e2_note);
//wav_note.play(a2_note);
//wav_note.play(d3_note);
//wav_note.play(g3_note);
//wav_note.play(b3_note);
//wav_note.play(e4_note);
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
}
}
//---------------------------------------------------------------------------------------
void setup() {
AudioMemory(30);
/*
* Initialize the yin algorithm's absolute
* threshold, this is good number.
*/
notefreq.begin(.15);
pinMode(LED_BUILTIN, OUTPUT);
playNoteTimer.begin(playNote, 1000);
}

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

+ 4910
- 0
examples/Analysis/NoteFrequency/a2_note.cpp
File diff suppressed because it is too large
View File


+ 2
- 0
examples/Analysis/NoteFrequency/a2_note.h View File

#include "Arduino.h"
extern const unsigned int a2_note[53971];

+ 1
- 0
examples/Analysis/NoteFrequency/b3_note.cpp
File diff suppressed because it is too large
View File


+ 2
- 0
examples/Analysis/NoteFrequency/b3_note.h View File

#include "Arduino.h"
extern const unsigned int b3_note[53990];

+ 1
- 0
examples/Analysis/NoteFrequency/d3_note.cpp
File diff suppressed because it is too large
View File


+ 2
- 0
examples/Analysis/NoteFrequency/d3_note.h View File

#include "Arduino.h"
extern const unsigned int d3_note[53974];

+ 4912
- 0
examples/Analysis/NoteFrequency/e2_note.cpp
File diff suppressed because it is too large
View File


+ 2
- 0
examples/Analysis/NoteFrequency/e2_note.h View File

#include "Arduino.h"
extern const unsigned int e2_note[53990];

+ 1
- 0
examples/Analysis/NoteFrequency/e4_note.cpp
File diff suppressed because it is too large
View File


+ 2
- 0
examples/Analysis/NoteFrequency/e4_note.h View File

#include "Arduino.h"
extern const unsigned int e4_note[53990];

+ 1
- 0
examples/Analysis/NoteFrequency/g3_note.cpp
File diff suppressed because it is too large
View File


+ 2
- 0
examples/Analysis/NoteFrequency/g3_note.h View File

#include "Arduino.h"
extern const unsigned int g3_note[53965];

+ 1
- 1
examples/WavFilePlayer/WavFilePlayer.ino View File





void loop() { void loop() {
playFile("SDTEST1.WAV");
playFile("SDTEST1.WAV"); // filenames are always uppercase 8.3 format
delay(500); delay(500);
playFile("SDTEST2.WAV"); playFile("SDTEST2.WAV");
delay(500); delay(500);

+ 0
- 0
extras/wav2sketch/wav2sketch.exe View File


+ 0
- 0
gui/font-awesome/fonts/fontawesome-webfont.eot View File


+ 0
- 0
gui/font-awesome/fonts/fontawesome-webfont.svg View File


+ 0
- 0
gui/font-awesome/fonts/fontawesome-webfont.ttf View File


+ 0
- 0
gui/font-awesome/fonts/fontawesome-webfont.woff View File


+ 59
- 1
gui/index.html View File

{"type":"AudioAnalyzeFFT256","data":{"defaults":{"name":{"value":"new"}},"shortName":"fft256","inputs":1,"outputs":0,"category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png"}}, {"type":"AudioAnalyzeFFT256","data":{"defaults":{"name":{"value":"new"}},"shortName":"fft256","inputs":1,"outputs":0,"category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png"}},
{"type":"AudioAnalyzeFFT1024","data":{"defaults":{"name":{"value":"new"}},"shortName":"fft1024","inputs":1,"outputs":0,"category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png"}}, {"type":"AudioAnalyzeFFT1024","data":{"defaults":{"name":{"value":"new"}},"shortName":"fft1024","inputs":1,"outputs":0,"category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png"}},
{"type":"AudioAnalyzeToneDetect","data":{"defaults":{"name":{"value":"new"}},"shortName":"tone","inputs":1,"outputs":0,"category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png"}}, {"type":"AudioAnalyzeToneDetect","data":{"defaults":{"name":{"value":"new"}},"shortName":"tone","inputs":1,"outputs":0,"category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png"}},
{"type":"AudioAnalyzeNoteFrequency","data":{"defaults":{"name":{"value":"new"}},"shortName":"notefreq","inputs":1,"outputs":0,"category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png"}},
{"type":"AudioAnalyzePrint","data":{"defaults":{"name":{"value":"new"}},"shortName":"print","inputs":1,"outputs":0,"category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png"}}, {"type":"AudioAnalyzePrint","data":{"defaults":{"name":{"value":"new"}},"shortName":"print","inputs":1,"outputs":0,"category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png"}},
{"type":"AudioControlSGTL5000","data":{"defaults":{"name":{"value":"new"}},"shortName":"sgtl5000","inputs":0,"outputs":0,"category":"control-function","color":"#E6E0F8","icon":"arrow-in.png"}}, {"type":"AudioControlSGTL5000","data":{"defaults":{"name":{"value":"new"}},"shortName":"sgtl5000","inputs":0,"outputs":0,"category":"control-function","color":"#E6E0F8","icon":"arrow-in.png"}},
{"type":"AudioControlWM8731","data":{"defaults":{"name":{"value":"new"}},"shortName":"wm8731","inputs":0,"outputs":0,"category":"control-function","color":"#E6E0F8","icon":"arrow-in.png"}}, {"type":"AudioControlWM8731","data":{"defaults":{"name":{"value":"new"}},"shortName":"wm8731","inputs":0,"outputs":0,"category":"control-function","color":"#E6E0F8","icon":"arrow-in.png"}},
</p> </p>
<p>I2S master objects can be used together with non-I2S input and output <p>I2S master objects can be used together with non-I2S input and output
objects, for simultaneous audio streaming on different hardware.</p> objects, for simultaneous audio streaming on different hardware.</p>
</script><
</script>
<script type="text/x-red" data-template-name="AudioInputI2S"> <script type="text/x-red" data-template-name="AudioInputI2S">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<ul> <ul>
<li><span class=literal>WAVEFORM_SINE</span></li> <li><span class=literal>WAVEFORM_SINE</span></li>
<li><span class=literal>WAVEFORM_SAWTOOTH</span></li> <li><span class=literal>WAVEFORM_SAWTOOTH</span></li>
<li><span class=literal>WAVEFORM_SAWTOOTH_REVERSE</span></li>
<li><span class=literal>WAVEFORM_SQUARE</span></li> <li><span class=literal>WAVEFORM_SQUARE</span></li>
<li><span class=literal>WAVEFORM_TRIANGLE</span></li> <li><span class=literal>WAVEFORM_TRIANGLE</span></li>
<li><span class=literal>WAVEFORM_ARBITRARY</span></li> <li><span class=literal>WAVEFORM_ARBITRARY</span></li>
<li><span class=literal>WAVEFORM_PULSE</span></li> <li><span class=literal>WAVEFORM_PULSE</span></li>
<li><span class=literal>WAVEFORM_SAMPLE_HOLD</span></li>
</ul> </ul>
</p> </p>
</script> </script>
</div> </div>
</script> </script>


<script type="text/x-red" data-help-name="AudioAnalyzeNoteFrequency">
<h3>Summary</h3>
<p>Detect with fairly good accuracy the fundamental frequency f<sub>o</sub>
of musical notes, such as electric guitar and bass.</p>
<p>Written By Collin Duffy</p>
<h3>Audio Connections</h3>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Port</th><th>Purpose</th></tr>
<tr class=odd><td align=center>In 0</td><td>Signal to analyze</td></tr>
</table>
<h3>Functions</h3>
<p class=func><span class=keyword>begin</span>(threshold);</p>
<p class=desc>Initialize and start detecting frequencies,
with an initial threshold (the amount of allowed uncertainty).
</p>
<p class=func><span class=keyword>available</span>();</p>
<p class=desc>Returns true (non-zero) when a valid
frequency is detected.
</p>
<p class=func><span class=keyword>read</span>();</p>
<p class=desc>Read the detected frequency.
</p>
<p class=func><span class=keyword>probability</span>();</p>
<p class=desc>Return the level of certainty, betweeo 0 to 1.0.
</p>
<p class=func><span class=keyword>threshold</span>(level);</p>
<p class=desc>Set the detection threshold, the amount of allowed uncertainty.
</p>
<h3>Examples</h3>
<p class=exam>File &gt; Examples &gt; Audio &gt; Analysis &gt; NoteFrequency
</p>
<h3>Notes</h3>
<p>The <a href="http://recherche.ircam.fr/equipes/pcm/cheveign/pss/2002_JASA_YIN.pdf">YIN algorithm</a> (PDF)
is used to detect frequencies, with many optimizations for
frequencies between 29-400Hz. This algorithm can be somewhat
memory and processor hungry but will allow you to detect with
fairly good accuracy the fundamental frequencies from
electric guitars and basses.</p>
<p>Within the code, AUDIO_GUITARTUNER_BLOCKS
may be edited to control low frequency range. The default
(24) allows measurement down to 29.14 Hz, or B(flat)0.</p>
<p>TODO: The usable upper range of this object is not well known.
Duff says "it should be good up to 1000Hz", but may have trouble
at 4 kHz. Please <a href="https://forum.pjrc.com/threads/32252-Different-Range-FFT-Algorithm/page2">post feedback here</a>, ideally with audio clips for the NoteFrequency example.</p>
<p>This object was contributed by Collin Duffy from his
<a href="https://github.com/duff2013/AudioTuner">AudioTuner project</a>.
Additional details and documentation may be found there.</p>
</script>
<script type="text/x-red" data-template-name="AudioAnalyzeNoteFrequency">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>

<script type="text/x-red" data-help-name="AudioAnalyzePrint"> <script type="text/x-red" data-help-name="AudioAnalyzePrint">
<h3>Summary</h3> <h3>Summary</h3>
<p>Print raw audio data to the Arduino Serial Monitor. This <p>Print raw audio data to the Arduino Serial Monitor. This

+ 5
- 3
gui/red/nodes.js View File

return node_defs[type]; return node_defs[type];
} }
function selectNode(name) { function selectNode(name) {
// window.history.pushState(null, null, window.location.protocol + "//"
// + window.location.host + window.location.pathname + '?info=' + name);
// on Chrome this causes "Uncaught SecurityError" when used from file:
// but other than errors in the console, doesn't seem to harm anything
window.history.pushState(null, null, window.location.protocol + "//"
+ window.location.host + window.location.pathname + '?info=' + name);
} }
function addNode(n) { function addNode(n) {
if (n._def.category == "config") { if (n._def.category == "config") {
} }


// ... and it has to end with an semikolon ... // ... and it has to end with an semikolon ...
var pattSe = new RegExp(/.*;$/);
var pattSe = new RegExp(/.*;.*$/);
var pattCoord = new RegExp(/.*\/\/xy=\d+,\d+$/); var pattCoord = new RegExp(/.*\/\/xy=\d+,\d+$/);
if (pattSe.test(line) || pattCoord.test(line)) { if (pattSe.test(line) || pattCoord.test(line)) {
var word = parts[1].trim(); var word = parts[1].trim();

+ 63
- 1
gui/red/ui/view.js View File

} }
} }


function doSort (arr) {
arr.sort(function (a, b) {
var nameA = a.name ? a.name : a.id;
var nameB = b.name ? b.name : b.id;
return nameA.localeCompare(nameB, 'en', {numeric: 'true'});
});
}

function setNewCoords (lastX, lastY, arr) {
var x = lastX;
var y = lastY;
for (var i = 0; i < arr.length; i++) {
var node = arr[i];
var name = node.name ? node.name : node.id;
var def = node._def;
var dH = Math.max(RED.view.defaults.height, (Math.max(def.outputs, def.inputs) || 0) * 15);
x = lastX + Math.max(RED.view.defaults.width, RED.view.calculateTextWidth(name) + (def.inputs > 0 ? 7 : 0));
node.x = x;
node.y = y + dH/2;
y = y + dH + 15;
node.dirty = true;
}
return { x: x, y: y };
}

function arrangeAll() { function arrangeAll() {
// TODO: arrange imported nodes without coordinates
var ioNoIn = [];
var ioInOut = [];
var ioMultiple = [];
var ioNoOut = [];
var ioCtrl = [];

RED.nodes.eachNode(function (node) {

if (node._def.inputs == 0 && node._def.outputs == 0) {
ioCtrl.push(node);
} else if (node._def.inputs == 0) {
ioNoIn.push(node);
} else if (node._def.outputs == 0) {
ioNoOut.push(node);
} else if (node._def.inputs == 1 && node._def.outputs == 1) {
ioInOut.push(node);
} else if (node._def.inputs > 1) {
ioMultiple.push(node);
}
});

var cols = new Array(ioNoIn, ioInOut, ioMultiple, ioNoOut, ioCtrl);
var lowestY = 0;

for (var i = 0; i < cols.length; i++) {
var dX = ((i < cols.length - 1) ? i : 0) * (RED.view.defaults.width * 2) + (RED.view.defaults.width / 2) + 15;
var dY = ((i < cols.length - 1) ? (RED.view.defaults.height / 4) : lowestY) + 15;
var startX = 0;
var startY = 0;

doSort(cols[i]);
var last = setNewCoords(startX + dX, startY + dY, cols[i]);
lowestY = Math.max(lowestY, last.y);
startX = ((i < cols.length - 1) ? last.x : 0) + (RED.view.defaults.width) * 4;
startY = lowestY + (RED.view.defaults.height * 1.5);
}
RED.storage.update();
redraw();
} }


RED.keyboard.add(/* z */ 90,{ctrl:true},function(){RED.history.pop();}); RED.keyboard.add(/* z */ 90,{ctrl:true},function(){RED.history.pop();});

+ 4
- 0
keywords.txt View File

AudioAnalyzePeak KEYWORD2 AudioAnalyzePeak KEYWORD2
AudioAnalyzePrint KEYWORD2 AudioAnalyzePrint KEYWORD2
AudioAnalyzeToneDetect KEYWORD2 AudioAnalyzeToneDetect KEYWORD2
AudioAnalyzeGuitarTuner KEYWORD2
AudioEffectChorus KEYWORD2 AudioEffectChorus KEYWORD2
AudioEffectFade KEYWORD2 AudioEffectFade KEYWORD2
AudioEffectFlange KEYWORD2 AudioEffectFlange KEYWORD2
sampleRate KEYWORD2 sampleRate KEYWORD2
bits KEYWORD2 bits KEYWORD2
mute_PCM KEYWORD2 mute_PCM KEYWORD2
probability KEYWORD2


AudioMemoryUsage KEYWORD2 AudioMemoryUsage KEYWORD2
AudioMemoryUsageMax KEYWORD2 AudioMemoryUsageMax KEYWORD2
WAVEFORM_TRIANGLE LITERAL1 WAVEFORM_TRIANGLE LITERAL1
WAVEFORM_ARBITRARY LITERAL1 WAVEFORM_ARBITRARY LITERAL1
WAVEFORM_PULSE LITERAL1 WAVEFORM_PULSE LITERAL1
WAVEFORM_SAWTOOTH_REVERSE LITERAL1
WAVEFORM_SAMPLE_HOLD LITERAL1


AUDIO_MEMORY_23LC1024 LITERAL1 AUDIO_MEMORY_23LC1024 LITERAL1
AUDIO_MEMORY_MEMORYBOARD LITERAL1 AUDIO_MEMORY_MEMORYBOARD LITERAL1

+ 17
- 0
synth_waveform.cpp View File

} }
break; break;


case WAVEFORM_SAWTOOTH_REVERSE:
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
*bp++ = ((short)(tone_phase>>15)*tone_amp) >> 15;
// phase and incr are both unsigned 32-bit fractions
tone_phase -= tone_incr;
}
break;

case WAVEFORM_TRIANGLE: case WAVEFORM_TRIANGLE:
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
if(tone_phase & 0x80000000) { if(tone_phase & 0x80000000) {
} }
break; break;
case WAVEFORM_SAMPLE_HOLD:
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
if(tone_phase < tone_incr) {
sample = random(-tone_amp, tone_amp);
}
*bp++ = sample;
tone_phase += tone_incr;
}
break;
} }
if (tone_offset) { if (tone_offset) {
bp = block->data; bp = block->data;

+ 4
- 0
synth_waveform.h View File

#define WAVEFORM_TRIANGLE 3 #define WAVEFORM_TRIANGLE 3
#define WAVEFORM_ARBITRARY 4 #define WAVEFORM_ARBITRARY 4
#define WAVEFORM_PULSE 5 #define WAVEFORM_PULSE 5
#define WAVEFORM_SAWTOOTH_REVERSE 6
#define WAVEFORM_SAMPLE_HOLD 7


// todo: remove these... // todo: remove these...
#define TONE_TYPE_SINE 0 #define TONE_TYPE_SINE 0
short tone_freq; short tone_freq;
uint32_t tone_phase; uint32_t tone_phase;
uint32_t tone_width; uint32_t tone_width;
// sample for SAMPLE_HOLD
short sample;
// volatile prevents the compiler optimizing out the frequency function // volatile prevents the compiler optimizing out the frequency function
volatile uint32_t tone_incr; volatile uint32_t tone_incr;
short tone_type; short tone_type;

Loading…
Cancel
Save