Skip to content

Commit 411d9cd

Browse files
authored
Merge pull request #646 from davepl/main
Make Audio Great Again
2 parents a96ab44 + 3087273 commit 411d9cd

File tree

7 files changed

+65
-76
lines changed

7 files changed

+65
-76
lines changed

include/effects/matrix/PatternStocks.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,11 @@ class PatternStocks : public LEDStripEffect
464464
// We have the high and low data in the stock, but let's not trust it and calculate it ourselves
465465
// If this works, Davepl wrote it. If not, Robert made me do it!
466466

467-
auto [minpoint, maxpoint] = std::minmax_element(currentStock.points.begin(), currentStock.points.end(), [](const StockPoint& a, const StockPoint& b) { return a.val < b.val; });
467+
auto [minpoint, maxpoint] =
468+
std::minmax_element(currentStock.points.begin(), currentStock.points.end(), [](const StockPoint& a, const StockPoint& b)
469+
{
470+
return a.val < b.val;
471+
});
468472
float min = minpoint->val, max = maxpoint->val, range = max - min;
469473

470474
if (range > 0.0f)

include/effects/matrix/spectrumeffects.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class VUMeter
155155
const int MAX_FADE = 256;
156156

157157
int xHalf = pGFXChannel->width()/2-1;
158-
int bars = g_Analyzer._VURatioFade / 2.0 * xHalf; // map(g_Analyzer._VU, 0, MAX_VU/8, 1, xHalf);
158+
int bars = g_Analyzer._VURatioFade / 2.0 * xHalf;
159159
bars = min(bars, xHalf);
160160

161161
EraseVUMeter(pGFXChannel, bars, yVU);

include/effects/strip/particles.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ class ColorBeatOverRed : public LEDStripEffect, public BeatEffectBase, public Pa
478478
// also have to update and render the particle system, which does the actual pixel drawing. We clear the scene ever
479479
// pass and rely on the fade effects of the particles to blend the
480480

481-
float amount = g_Analyzer._VU / MAX_VU;
481+
float amount = g_Analyzer._VU / 4096;
482482

483483
_baseColor = CRGB(500 * amount, 0, 0);
484484
setAllOnAllChannels(_baseColor.r, _baseColor.g, _baseColor.b);

include/globals.h

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,6 @@ extern RemoteDebug Debug; // Let everyone in the project know about it
313313
#define ENABLE_REMOTE 0 // IR Remote Control
314314
#define ENABLE_AUDIO 1 // Listen for audio from the microphone and process it
315315
#define COLORDATA_SERVER_ENABLED 0
316-
#define MIN_VU 20
317-
#define NOISE_CUTOFF 1000
318316

319317
#if USE_PSRAM
320318
#define MAX_BUFFERS 500
@@ -429,10 +427,6 @@ extern RemoteDebug Debug; // Let everyone in the project know about it
429427

430428
#define LED_PIN0 32
431429

432-
#define MIN_VU 280
433-
#define NOISE_CUTOFF 1000
434-
#define NOISE_FLOOR 2000
435-
436430
// The webserver serves files that are baked into the device firmware. When running you should be able to
437431
// see/select the list of effects by visiting the chip's IP in a browser. You can get the chip's IP by
438432
// watching the serial output or checking your router for the DHCP given to a new device; often they're
@@ -560,7 +554,6 @@ extern RemoteDebug Debug; // Let everyone in the project know about it
560554
#define ENABLE_REMOTE 1 // IR Remote Control
561555
#define ENABLE_AUDIO 1 // Listen for audio from the microphone and process it
562556
#define SCALE_AUDIO_EXPONENTIAL 0
563-
#define ENABLE_AUDIO_SMOOTHING 1
564557
#define EFFECT_PERSISTENCE_CRITICAL 1 // Require effects serialization to succeed
565558

566559
#define DEFAULT_EFFECT_INTERVAL (MILLIS_PER_SECOND * 60 * 2)
@@ -581,9 +574,12 @@ extern RemoteDebug Debug; // Let everyone in the project know about it
581574

582575
#define TOGGLE_BUTTON_1 0
583576

584-
#define COLOR_ORDER EOrder::RGB
577+
// The mesmerizer mic isn't quite as sensitive as the M5 mic that the code was originally written for
578+
// so we adjust by a scalar to get the same effect.
579+
580+
#define AUDIO_MIC_SCALAR 1.5
585581

586-
#define MIN_VU 80
582+
#define COLOR_ORDER EOrder::RGB
587583

588584
#elif TTGO
589585

@@ -983,10 +979,9 @@ extern RemoteDebug Debug; // Let everyone in the project know about it
983979
#define NUM_LEDS (MATRIX_WIDTH*MATRIX_HEIGHT)
984980
#define LED_FAN_OFFSET_BU 6
985981

986-
// The mic in the M5 is not quite the same as the Mesmerizer, so it gets a different minimum VU than default
987-
988-
#define MIN_VU 150
989-
#define NOISE_CUTOFF 100
982+
//#define MIN_VU 400
983+
//#define NOISE_FLOOR 30
984+
//#define NOISE_CUTOFF 5
990985

991986
#if !(ELECROW)
992987
#define TOGGLE_BUTTON_1 37
@@ -1036,11 +1031,6 @@ extern RemoteDebug Debug; // Let everyone in the project know about it
10361031
#define NUM_LEDS (MATRIX_WIDTH*MATRIX_HEIGHT)
10371032
#define LED_FAN_OFFSET_BU 6
10381033

1039-
// The mic in the M5 is not quite the same as the Mesmerizer, so it gets a different minimum VU than default
1040-
1041-
#define MIN_VU 280
1042-
#define NOISE_CUTOFF 1000
1043-
10441034
#define TOGGLE_BUTTON_1 39
10451035
#define TOGGLE_BUTTON_2 37
10461036

@@ -1289,16 +1279,19 @@ extern RemoteDebug Debug; // Let everyone in the project know about it
12891279
#define NUM_BANDS 16
12901280
#endif
12911281
#ifndef NOISE_FLOOR
1292-
#define NOISE_FLOOR 4000
1282+
#define NOISE_FLOOR 30
12931283
#endif
12941284
#ifndef NOISE_CUTOFF
1295-
#define NOISE_CUTOFF 1000
1285+
#define NOISE_CUTOFF 10
1286+
#endif
1287+
#ifndef AUDIO_MIC_SCALAR
1288+
#define AUDIO_MIC_SCALAR 1.0
12961289
#endif
12971290
#ifndef AUDIO_PEAK_REMOTE_TIMEOUT
12981291
#define AUDIO_PEAK_REMOTE_TIMEOUT 1000.0f // How long after remote PeakData before local microphone is used again
12991292
#endif
13001293
#ifndef ENABLE_AUDIO_SMOOTHING
1301-
#define ENABLE_AUDIO_SMOOTHING 0
1294+
#define ENABLE_AUDIO_SMOOTHING 1
13021295
#endif
13031296
#ifndef BARBEAT_ENHANCE
13041297
#define BARBEAT_ENHANCE 0.3 // How much the SpectrumAnalyzer "pulses" with the music

include/soundanalyzer.h

Lines changed: 35 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,6 @@
3636
#include <arduinoFFT.h>
3737
#include <driver/i2s.h>
3838
#include <driver/adc.h>
39-
// #include <driver/adc_deprecated.h>
40-
41-
#define SUPERSAMPLES 1 // How many supersamples to take
42-
#define SAMPLE_BITS 12 // Sample resolution (0-4095)
43-
#define MAX_ANALOG_IN ((1 << SAMPLE_BITS) * SUPERSAMPLES) // What our max analog input value is on all analog pins (4096 is default 12 bit resolution)
44-
#ifndef MAX_VU
45-
#define MAX_VU (MAX_ANALOG_IN / 2)
46-
#endif
4739

4840
#define MS_PER_SECOND 1000
4941

@@ -77,8 +69,6 @@ class SoundAnalyzer : public AudioVariables // Non-audio case. Inherits only th
7769

7870
#define EXAMPLE_I2S_NUM (I2S_NUM_0)
7971
#define EXAMPLE_I2S_FORMAT (I2S_CHANNEL_FMT_RIGHT_LEFT) // I2S data format
80-
#define I2S_ADC_UNIT ADC_UNIT_1 // I2S built-in ADC unit
81-
#define I2S_ADC_CHANNEL ADC1_CHANNEL_0 // I2S built-in ADC channel
8272

8373
void IRAM_ATTR AudioSamplerTaskEntry(void *);
8474
void IRAM_ATTR AudioSerialTaskEntry(void *);
@@ -89,7 +79,7 @@ void IRAM_ATTR AudioSerialTaskEntry(void *);
8979
// results are simplified down to this small class of band peaks.
9080

9181
#ifndef MIN_VU
92-
#define MIN_VU 180 // Minimum VU value to use for the span when computing VURatio. Contributes to
82+
#define MIN_VU 2 // Minimum VU value to use for the span when computing VURatio. Contributes to
9383
#endif // how dynamic the music is (smaller values == more dynamic)
9484

9585

@@ -155,26 +145,26 @@ class PeakData
155145
case MESMERIZERMIC:
156146
{
157147
static constexpr std::array<float, 16> Scalars16 = {0.4, .5, 0.75, 1.0, 0.6, 0.6, 0.8, 0.8, 1.2, 1.5, 3.0, 3.0, 3.0, 3.0, 3.5, 2.5}; // {0.08, 0.12, 0.3, 0.35, 0.35, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.4, 1.4, 1.0, 1.0, 1.0};
158-
float result = (NUM_BANDS == 16) ? Scalars16[i] : map(i, 0, NUM_BANDS - 1, 1.0, 1.0);
148+
float result = (NUM_BANDS == 16) ? Scalars16[i] : 1.0;
159149
return result;
160150
}
161151
case PCREMOTE:
162152
{
163153

164154
static constexpr std::array<float, 16> Scalars16 = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
165-
float result = (NUM_BANDS == 16) ? Scalars16[i] : map(i, 0, NUM_BANDS - 1, 1.0, 1.0);
155+
float result = (NUM_BANDS == 16) ? Scalars16[i] : 1.0;
166156
return result;
167157
}
168158
case M5PLUS2:
169159
{
170-
static constexpr std::array<float, 16> Scalars16 = {0.3, .5, 0.8, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.7, 0.7, 0.7};
171-
float result = (NUM_BANDS == 16) ? Scalars16[i] : map(i, 0, NUM_BANDS - 1, 1.0, 1.0);
160+
static constexpr std::array<float, 16> Scalars16 = {0.5, 1.0, 2.5, 2.2, 1.5, 2.0, 2.0, 2.0, 1.5, 1.5, 1.5, 1.5, 1.0, 0.8, 1.0, 1.0};
161+
float result = (NUM_BANDS == 16) ? Scalars16[i] : 1.0;
172162
return result;
173163
}
174164
default:
175165
{
176166
static constexpr std::array<float, 16> Scalars16 = {0.5, .5, 0.8, 1.0, 1.5, 1.2, 1.5, 1.6, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 5.0, 2.5};
177-
float result = (NUM_BANDS == 16) ? Scalars16[i] : map(i, 0, NUM_BANDS - 1, 1.0, 1.0);
167+
float result = (NUM_BANDS == 16) ? Scalars16[i] : 1.0;
178168
return result;
179169
}
180170
}
@@ -202,13 +192,13 @@ class PeakData
202192
class SoundAnalyzer : public AudioVariables
203193
{
204194
static constexpr size_t MAX_SAMPLES = 256;
205-
std::unique_ptr<uint16_t[]> ptrSampleBuffer;
195+
std::unique_ptr<int16_t[]> ptrSampleBuffer;
206196

207197
// I'm old enough I can only hear up to about 12K, but feel free to adjust. Remember from
208198
// school that you need to sample at double the frequency you want to process, so 24000 is 12K
209199

210200
static constexpr size_t SAMPLING_FREQUENCY = 20000;
211-
static constexpr size_t LOWEST_FREQ = 40;
201+
static constexpr size_t LOWEST_FREQ = 100;
212202
static constexpr size_t HIGHEST_FREQ = SAMPLING_FREQUENCY / 2;
213203

214204
static constexpr size_t _sampling_period_us = PERIOD_FROM_FREQ(SAMPLING_FREQUENCY);
@@ -288,9 +278,9 @@ class SoundAnalyzer : public AudioVariables
288278
if (M5.Mic.record((int16_t *)ptrSampleBuffer.get(), MAX_SAMPLES, SAMPLING_FREQUENCY, false))
289279
bytesRead = bytesExpected;
290280
#else
291-
ESP_ERROR_CHECK(i2s_start(EXAMPLE_I2S_NUM));
292-
ESP_ERROR_CHECK(i2s_read(EXAMPLE_I2S_NUM, (void *) ptrSampleBuffer.get(), bytesExpected, &bytesRead, 100 / portTICK_RATE_MS));
293-
ESP_ERROR_CHECK(i2s_stop(EXAMPLE_I2S_NUM));
281+
ESP_ERROR_CHECK(i2s_start(I2S_NUM_0));
282+
ESP_ERROR_CHECK(i2s_read(I2S_NUM_0, (void *) ptrSampleBuffer.get(), bytesExpected, &bytesRead, 100 / portTICK_PERIOD_MS));
283+
ESP_ERROR_CHECK(i2s_stop(I2S_NUM_0));
294284
#endif
295285

296286
if (bytesRead != bytesExpected)
@@ -364,10 +354,7 @@ class SoundAnalyzer : public AudioVariables
364354

365355
for (int i = 2; i < MAX_SAMPLES / 2; i++)
366356
{
367-
#if USE_M5
368-
// The M5 Mic returns some large vales, so we normalize here
369-
_vReal[i] = _vReal[i] / MAX_SAMPLES;
370-
#endif
357+
_vReal[i] = _vReal[i] / MAX_SAMPLES * AUDIO_MIC_SCALAR;
371358

372359
int freq = GetBucketFrequency(i-2);
373360
if (freq >= LOWEST_FREQ)
@@ -468,16 +455,19 @@ class SoundAnalyzer : public AudioVariables
468455
}
469456
else
470457
{
471-
// uses geometric spacing to calculate the upper frequency for each of the 12 bands, starting with a frequency of 200 Hz
472-
// and ending with a frequency of 12.5 kHz. The spacing ratio r is calculated as the 11th root of the ratio of the maximum
473-
// frequency to the minimum frequency, and each upper frequency is calculated as f1 * r^(i+1).
474-
458+
// Calculate the logarithmic spacing for the frequency bands
475459
float f1 = LOWEST_FREQ;
476460
float f2 = HIGHEST_FREQ;
477-
float r = pow(f2 / f1, 1.0 / (NUM_BANDS - 1));
461+
462+
// Calculate the ratio based on logarithmic scale
463+
float log_f1 = log10(f1);
464+
float log_f2 = log10(f2);
465+
float delta = (log_f2 - log_f1) / (NUM_BANDS - 1);
466+
478467
for (int i = 0; i < NUM_BANDS; i++)
479468
{
480-
_cutOffsBand[i] = round(f1 * pow(r, i + 1));
469+
// Calculate the upper frequency for each band
470+
_cutOffsBand[i] = round(pow(10, log_f1 + delta * (i + 1)));
481471
debugV("BAND %d: %d\n", i, _cutOffsBand[i]);
482472
}
483473
}
@@ -489,7 +479,10 @@ class SoundAnalyzer : public AudioVariables
489479

490480
SoundAnalyzer()
491481
{
492-
ptrSampleBuffer = make_unique_psram_array<uint16_t>(MAX_SAMPLES);
482+
ptrSampleBuffer.reset( (int16_t *)heap_caps_malloc(MAX_SAMPLES * sizeof(int16_t), MALLOC_CAP_8BIT) );
483+
if (!ptrSampleBuffer)
484+
throw std::runtime_error("Failed to allocate sample buffer");
485+
493486
_vReal = (double *)PreferPSRAMAlloc(MAX_SAMPLES * sizeof(_vReal[0]));
494487
_vImaginary = (double *)PreferPSRAMAlloc(MAX_SAMPLES * sizeof(_vImaginary[0]));
495488
_vPeaks = (double *)PreferPSRAMAlloc(NUM_BANDS * sizeof(_vPeaks[0]));
@@ -530,17 +523,13 @@ class SoundAnalyzer : public AudioVariables
530523

531524
#if USE_M5
532525

533-
auto miccfg = M5.Mic.config();
534-
miccfg.over_sampling = 4;
535-
miccfg.magnification = 1;
536-
miccfg.dma_buf_count = 2;
537-
miccfg.dma_buf_len = MAX_SAMPLES;
538-
miccfg.sample_rate = SAMPLING_FREQUENCY;
539-
miccfg.use_adc = false;
540-
M5.Mic.config(miccfg);
541-
526+
527+
// Can't use speaker and mic at the same time, and speaker defaults on, so turn it off
528+
529+
M5.Speaker.setVolume(255);
530+
M5.Speaker.end();
542531
M5.Mic.begin();
543-
532+
544533
#elif ELECROW
545534

546535
const i2s_config_t i2s_config = {
@@ -582,8 +571,8 @@ class SoundAnalyzer : public AudioVariables
582571

583572
ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_12));
584573
ESP_ERROR_CHECK(adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_0));
585-
ESP_ERROR_CHECK(i2s_driver_install(EXAMPLE_I2S_NUM, &i2s_config, 0, NULL));
586-
ESP_ERROR_CHECK(i2s_set_adc_mode(I2S_ADC_UNIT, I2S_ADC_CHANNEL));
574+
ESP_ERROR_CHECK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
575+
ESP_ERROR_CHECK(i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_0));
587576

588577
#else
589578

@@ -600,8 +589,8 @@ class SoundAnalyzer : public AudioVariables
600589

601590
ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_12));
602591
ESP_ERROR_CHECK(adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_0));
603-
ESP_ERROR_CHECK(i2s_driver_install(EXAMPLE_I2S_NUM, &i2s_config, 0, NULL));
604-
ESP_ERROR_CHECK(i2s_set_adc_mode(I2S_ADC_UNIT, I2S_ADC_CHANNEL));
592+
ESP_ERROR_CHECK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
593+
ESP_ERROR_CHECK(i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_0));
605594

606595
#endif
607596

src/audio.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ void IRAM_ATTR AudioSamplerTaskEntry(void *)
8080
0.0 :
8181
(g_Analyzer._VU - g_Analyzer._MinVU) / std::max(g_Analyzer._PeakVU - g_Analyzer._MinVU, (float) MIN_VU) * 2.0f;
8282

83+
debugV("VU: %f\n", g_Analyzer._VU);
84+
debugV("PeakVU: %f\n", g_Analyzer._PeakVU);
85+
debugV("MinVU: %f\n", g_Analyzer._MinVU);
8386
debugV("VURatio: %f\n", g_Analyzer._VURatio);
8487

8588
// Delay enough time to yield 60fps max

src/screen.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,8 @@ void CurrentEffectSummary(bool bRedraw)
349349

350350
// Draw the spectrum analyzer bars
351351

352-
int spectrumTop = topMargin + ySizeVU + 1; // Start at the bottom of the VU meter
353-
int bandHeight = display.height() - spectrumTop - display.BottomMargin;
352+
const int spectrumTop = topMargin + ySizeVU + 1; // Start at the bottom of the VU meter
353+
const int bandHeight = display.height() - spectrumTop - display.BottomMargin;
354354

355355
for (int iBand = 0; iBand < NUM_BANDS; iBand++)
356356
{
@@ -363,14 +363,14 @@ void CurrentEffectSummary(bool bRedraw)
363363
auto val = min(1.0f, g_Analyzer._peak2Decay[iBand]);
364364
assert(bandHeight * val <= bandHeight);
365365
display.fillRect(iBand * bandWidth, spectrumTop + topSection, bandWidth - 1, bandHeight - topSection, color16);
366+
for (int iLine = spectrumTop; iLine <= spectrumTop + bandHeight; iLine += display.width() / 40)
367+
display.drawFastHLine(iBand * bandWidth, iLine, bandWidth, BLACK16);
366368
}
367369

368-
display.EndFrame();
369-
370370
// Draw horizontal lines so the bars look like they are made of segments
371371

372-
// for (int iLine = spectrumTop; iLine <= spectrumTop + bandHeight; iLine += display.height() / 25)
373-
// display.drawLine(0, iLine, display.width()-1, iLine, BLACK16);
372+
display.EndFrame();
373+
374374
#endif
375375
}
376376

0 commit comments

Comments
 (0)