Advertisement
atuline

rocktaves.ino

Jun 19th, 2021
1,128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.14 KB | None | 0 0
  1. /* File: Rocktaves
  2.  *
  3.  * By: Andrew Tuline
  4.  *
  5.  * Date: June, 2021
  6.  *
  7.  * This is just a proof of concept sketch that uses an ESP32 running Arduino C, along with the arduinoFFT and FastLED libraries. It creates consistent colours for the same note in different octaves, with
  8.  * a range of C3 (or 133Hz) to about B7 (at 3951Hz). For example, C3 could be a 'red', as would be C4, C5, C6 and C7.
  9.  *
  10.  * For the C3 octave, we see that the frequency range is:
  11.  *
  12.  * C3 = 131Hz
  13.  * B3 = 247Hz
  14.  *
  15.  * Looking at a notes/frequency table, we also see that octaves are 'double' in frequency from the next one down. As a result, let's divide the resultant loudest frequency value by 2 while the
  16.  * resultant value > 247. We'll call that 'folding the octaves'. Probably isn't, but that's what I'll call it anyways.
  17.  *  
  18.  * Since the starting frequency is 131Hz for C3, and we've already 'folded' down our FFT calculated frequency value to fit in the C3 octave, let's subtract 131 from the resultant value. The absolute value of
  19.  * that should range between 0 and 116 (or about 247-131). Let's multiply that by a fudge factor so that the resultant value ranges from 0 to 255, which we can now use as an index into an 8 bit colour range.
  20.  *
  21.  * As for the volume, let's find min and max values and scale accordingly. Turns out the max value goes up to about 65535, so we'll divide by 256 and get an 8 bit volume value. We'll need to
  22.  * squelch out background noise though. I ended up digitizing the resultant brightness so that LED's are ON or OFF, with no in between.
  23.  *
  24.  * Caveat: With the exception of the FFT library, these are just simple calculations. I doubt this would stand up to rigorous testing. Certainly, the DSP dudes would be scoffing.
  25.  *
  26.  *
  27.  * Reference:
  28.  *
  29.  * https://www.szynalski.com/tone-generator/
  30.  * https://pages.mtu.edu/~suits/notefreqs.html
  31.  *
  32.  *
  33.  * Hardware used:
  34.  *
  35.  * ESP32 (LOLIN D32)
  36.  * INMP401 or MAX9814 or MAX4466 microphones  (and NOT, I repeat NOT sound sensors)
  37.  * WS2812 addressable LED's
  38.  *
  39.  *
  40.  * Libraries used:
  41.  *
  42.  * Arduino FFT         https://github.com/kosme/arduinoFFT
  43.  * FastLED             https://github.com/FastLED/FastLED
  44.  *
  45.  */
  46.  
  47.  
  48. #include <FastLED.h>
  49. #include <arduinoFFT.h>
  50.  
  51. #define MIC_PIN    36                                       // Analog port for microphone.
  52. #define DC_OFFSET  500                                      // DC offset in mic signal. You may need to change this. I have not added an 'auto-leveller' to this proof of concept routine.
  53.  
  54. #define LED_DT 2
  55. #define NUM_LEDS 30
  56.  
  57. uint8_t max_bright = 128;
  58.  
  59. struct CRGB leds[NUM_LEDS];
  60.  
  61. arduinoFFT FFT = arduinoFFT();                                // Create FFT object.
  62.  
  63. const uint16_t samples = 512;                                  // This value MUST ALWAYS be a power of 2.
  64. const double samplingFrequency = 10240;                        // Keep it <10000 due to sampling method used.
  65.  
  66. unsigned int sampling_period_us;
  67. unsigned long microseconds;
  68.  
  69. double vReal[samples];                                        // These are the input and output vectors. Input vectors receive computed results from FFT.
  70. double vImag[samples];
  71.  
  72.  
  73. void setup() {
  74.   Serial.begin(115200);
  75.   LEDS.addLeds<WS2812, LED_DT, GRB>(leds, NUM_LEDS);
  76.   FastLED.setBrightness(max_bright);
  77.   sampling_period_us = round(1000000*(1.0/samplingFrequency));
  78. } // setup()
  79.  
  80.  
  81. void loop() {
  82.  
  83.   fadeToBlackBy(leds,NUM_LEDS,64);
  84.  
  85.   microseconds = micros();                                            // Sampling timer.
  86.  
  87.   for(int i=0; i<samples; i++) {                                      // We could create a task for core 0, but I'm too lazy to do that here.
  88.       vReal[i] = analogRead(MIC_PIN) - DC_OFFSET;                     // Sampling from ADC. That offset is a PITA though.
  89.       vImag[i] = 0;
  90.       while(micros() - microseconds < sampling_period_us){ }
  91.         microseconds += sampling_period_us;
  92.   } // for
  93.  
  94.   FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);    // Weigh data.
  95.   FFT.Compute(vReal, vImag, samples, FFT_FORWARD);                    // Compute FFT.
  96.   FFT.ComplexToMagnitude(vReal, vImag, samples);                      // Compute magnitudes.
  97.  
  98.   double freq;
  99.   double vol;
  100.  
  101.   FFT.MajorPeak(vReal, samples, samplingFrequency, &freq, &vol);
  102.  
  103.   double frTemp = freq;
  104.   uint8_t octCount = 0;             // Octave counter.
  105.   uint8_t volTemp = 0;
  106.   if (vol > 500) volTemp = 255;    // We need to squelch out the background noise.
  107.  
  108.   while ( frTemp > 249 ) {
  109.     octCount++;                     // This should go up to 5.
  110.     frTemp = frTemp/2;
  111.   }
  112.     frTemp -=132;                    // This should give us a base musical note of C3
  113.     frTemp = abs(frTemp * 2.1);       // Fudge factors to compress octave range starting at 0 and going to 255;
  114.  
  115.     Serial.print(frTemp); Serial.print("\t"); Serial.print(volTemp); Serial.print("\t");Serial.print(octCount); Serial.print("\t"); Serial.println(vol);
  116.     leds[beatsin8(8+octCount*4,0,NUM_LEDS-1,0,octCount*8)] = CHSV((uint8_t)frTemp,255,volTemp);                 // Back and forth with different frequencies and phase shift depending on current octave.
  117.  
  118.   FastLED.show();
  119. } // loop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement