Merge branch 'audioreactive-prototype' into merge-audio

This commit is contained in:
Blaz Kristan 2022-08-17 20:14:11 +02:00
commit 67a51be9ee
4 changed files with 581 additions and 361 deletions

File diff suppressed because it is too large Load Diff

View File

@ -18,19 +18,36 @@
Until this configuration is moved to the webinterface Until this configuration is moved to the webinterface
*/ */
// if you have problems to get your microphone work on the left channel, uncomment the following line
//#define I2S_USE_RIGHT_CHANNEL // (experimental) define this to use right channel (digital mics only)
#ifdef I2S_USE_RIGHT_CHANNEL
#define I2S_MIC_CHANNEL I2S_CHANNEL_FMT_ONLY_RIGHT
#define I2S_MIC_CHANNEL_TEXT "right channel only."
#else
#define I2S_MIC_CHANNEL I2S_CHANNEL_FMT_ONLY_LEFT
#define I2S_MIC_CHANNEL_TEXT "left channel only."
#endif
// Uncomment the line below to utilize ADC1 _exclusively_ for I2S sound input.
// benefit: analog mic inputs will be sampled contiously -> better response times and less "glitches"
// WARNING: this option WILL lock-up your device in case that any other analogRead() operation is performed;
// for example if you want to read "analog buttons"
//#define I2S_GRAB_ADC1_COMPLETELY // (experimental) continously sample analog ADC microphone. WARNING will cause analogRead() lock-up
// data type requested from the I2S driver - currently we always use 32bit // data type requested from the I2S driver - currently we always use 32bit
//#define I2S_USE_16BIT_SAMPLES // (experimental) define this to request 16bit - more efficient but possibly less compatible //#define I2S_USE_16BIT_SAMPLES // (experimental) define this to request 16bit - more efficient but possibly less compatible
#ifdef I2S_USE_16BIT_SAMPLES #ifdef I2S_USE_16BIT_SAMPLES
#define I2S_SAMPLE_RESOLUTION I2S_BITS_PER_SAMPLE_16BIT #define I2S_SAMPLE_RESOLUTION I2S_BITS_PER_SAMPLE_16BIT
#define I2S_datatype int16_t #define I2S_datatype int16_t
#define I2S_unsigned_datatype uint16_t
#undef I2S_SAMPLE_DOWNSCALE_TO_16BIT #undef I2S_SAMPLE_DOWNSCALE_TO_16BIT
#else #else
#define I2S_SAMPLE_RESOLUTION I2S_BITS_PER_SAMPLE_32BIT #define I2S_SAMPLE_RESOLUTION I2S_BITS_PER_SAMPLE_32BIT
#define I2S_datatype int32_t #define I2S_datatype int32_t
#define I2S_unsigned_datatype uint32_t
#define I2S_SAMPLE_DOWNSCALE_TO_16BIT #define I2S_SAMPLE_DOWNSCALE_TO_16BIT
#endif #endif
/* Interface class /* Interface class
AudioSource serves as base class for all microphone types AudioSource serves as base class for all microphone types
This enables accessing all microphones with one single interface This enables accessing all microphones with one single interface
@ -62,27 +79,26 @@ class AudioSource {
*/ */
virtual void getSamples(float *buffer, uint16_t num_samples) = 0; virtual void getSamples(float *buffer, uint16_t num_samples) = 0;
/* Get an up-to-date sample without DC offset */ /* check if the audio source driver was initialized successfully */
virtual int getSampleWithoutDCOffset() { return _sampleNoDCOffset; }; virtual bool isInitialized(void) {return(_initialized);}
/* identify Audiosource type - I2S-ADC or I2S-digital */
typedef enum{Type_unknown=0, Type_I2SAdc=1, Type_I2SDigital=2} AudioSourceType;
virtual AudioSourceType getType(void) {return(Type_I2SDigital);} // default is "I2S digital source" - ADC type overrides this method
protected: protected:
/* Post-process audio sample - currently on needed for I2SAdcSource*/
virtual I2S_datatype postProcessSample(I2S_datatype sample_in) {return(sample_in);} // default method can be overriden by instances (ADC) that need sample postprocessing
// Private constructor, to make sure it is not callable except from derived classes // Private constructor, to make sure it is not callable except from derived classes
AudioSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : AudioSource(int sampleRate, int blockSize) :
_sampleRate(sampleRate), _sampleRate(sampleRate),
_blockSize(blockSize), _blockSize(blockSize),
_sampleNoDCOffset(0),
_dcOffset(0.0f),
_shift(lshift),
_mask(mask),
_initialized(false) _initialized(false)
{}; {};
int _sampleRate; // Microphone sampling rate int _sampleRate; // Microphone sampling rate
int _blockSize; // I2S block size int _blockSize; // I2S block size
volatile int _sampleNoDCOffset; // Up-to-date sample without DCOffset
float _dcOffset; // Rolling average DC offset
int16_t _shift; // Shift obtained samples to the right (positive) or left(negative) by this amount
uint32_t _mask; // Bitmask for sample data after shifting. Bitmask 0X0FFF means that we need to convert 12bit ADC samples from unsigned to signed
bool _initialized; // Gets set to true if initialization is successful bool _initialized; // Gets set to true if initialization is successful
}; };
@ -91,13 +107,13 @@ class AudioSource {
*/ */
class I2SSource : public AudioSource { class I2SSource : public AudioSource {
public: public:
I2SSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : I2SSource(int sampleRate, int blockSize) :
AudioSource(sampleRate, blockSize, lshift, mask) { AudioSource(sampleRate, blockSize) {
_config = { _config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = _sampleRate, .sample_rate = _sampleRate,
.bits_per_sample = I2S_SAMPLE_RESOLUTION, .bits_per_sample = I2S_SAMPLE_RESOLUTION,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .channel_format = I2S_MIC_CHANNEL,
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S), .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),
#else #else
@ -176,9 +192,6 @@ class I2SSource : public AudioSource {
size_t bytes_read = 0; /* Counter variable to check if we actually got enough data */ size_t bytes_read = 0; /* Counter variable to check if we actually got enough data */
I2S_datatype newSamples[num_samples]; /* Intermediary sample storage */ I2S_datatype newSamples[num_samples]; /* Intermediary sample storage */
// Reset dc offset
_dcOffset = 0.0f;
err = i2s_read(I2S_NUM_0, (void *)newSamples, sizeof(newSamples), &bytes_read, portMAX_DELAY); err = i2s_read(I2S_NUM_0, (void *)newSamples, sizeof(newSamples), &bytes_read, portMAX_DELAY);
if (err != ESP_OK) { if (err != ESP_OK) {
DEBUGSR_PRINTF("Failed to get samples: %d\n", err); DEBUGSR_PRINTF("Failed to get samples: %d\n", err);
@ -193,30 +206,17 @@ class I2SSource : public AudioSource {
// Store samples in sample buffer and update DC offset // Store samples in sample buffer and update DC offset
for (int i = 0; i < num_samples; i++) { for (int i = 0; i < num_samples; i++) {
// pre-shift samples down to 16bit
#ifdef I2S_SAMPLE_DOWNSCALE_TO_16BIT
if (_shift != 0)
newSamples[i] >>= 16;
#endif
float currSample = 0.0f;
if(_shift > 0)
currSample = (float) (newSamples[i] >> _shift);
else {
if(_shift < 0)
currSample = (float) (newSamples[i] << (- _shift)); // need to "pump up" 12bit ADC to full 16bit as delivered by other digital mics
else
#ifdef I2S_SAMPLE_DOWNSCALE_TO_16BIT
currSample = (float) newSamples[i] / 65536.0f; // _shift == 0 -> use the chance to keep lower 16bits
#else
currSample = (float) newSamples[i];
#endif
}
buffer[i] = currSample;
_dcOffset = ((_dcOffset * 31) + currSample) / 32;
}
// Update no-DC sample newSamples[i] = postProcessSample(newSamples[i]); // perform postprocessing (needed for ADC samples)
_sampleNoDCOffset = buffer[num_samples - 1] - _dcOffset;
float currSample = 0.0f;
#ifdef I2S_SAMPLE_DOWNSCALE_TO_16BIT
currSample = (float) newSamples[i] / 65536.0f; // 32bit input -> 16bit; keeping lower 16bits as decimal places
#else
currSample = (float) newSamples[i]; // 16bit input -> use as-is
#endif
buffer[i] = currSample;
}
} }
} }
@ -275,8 +275,8 @@ class ES7243 : public I2SSource {
} }
public: public:
ES7243(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : ES7243(int sampleRate, int blockSize) :
I2SSource(sampleRate, blockSize, lshift, mask) { I2SSource(sampleRate, blockSize) {
_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT; _config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
}; };
@ -314,8 +314,8 @@ public:
*/ */
class I2SAdcSource : public I2SSource { class I2SAdcSource : public I2SSource {
public: public:
I2SAdcSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : I2SAdcSource(int sampleRate, int blockSize) :
I2SSource(sampleRate, blockSize, lshift, mask) { I2SSource(sampleRate, blockSize) {
_config = { _config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN), .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
.sample_rate = _sampleRate, .sample_rate = _sampleRate,
@ -326,14 +326,22 @@ class I2SAdcSource : public I2SSource {
#else #else
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
#endif #endif
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8, .dma_buf_count = 8,
.dma_buf_len = _blockSize .dma_buf_len = _blockSize,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0
}; };
} }
/* identify Audiosource type - I2S-ADC*/
AudioSourceType getType(void) {return(Type_I2SAdc);}
void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) {
_myADCchannel = 0x0F;
if(!pinManager.allocatePin(audioPin, false, PinOwner::UM_Audioreactive)) { if(!pinManager.allocatePin(audioPin, false, PinOwner::UM_Audioreactive)) {
DEBUGSR_PRINTF("failed to allocate GPIO for audio analog input: %d\n", audioPin);
return; return;
} }
_audioPin = audioPin; _audioPin = audioPin;
@ -345,6 +353,7 @@ class I2SAdcSource : public I2SSource {
return; return;
} else { } else {
adc_gpio_init(ADC_UNIT_1, adc_channel_t(channel)); adc_gpio_init(ADC_UNIT_1, adc_channel_t(channel));
_myADCchannel = channel;
} }
// Install Driver // Install Driver
@ -360,8 +369,9 @@ class I2SAdcSource : public I2SSource {
DEBUGSR_PRINTF("Failed to set i2s adc mode: %d\n", err); DEBUGSR_PRINTF("Failed to set i2s adc mode: %d\n", err);
return; return;
} }
// adc1_config_channel_atten(adc1_channel_t(channel), ADC_ATTEN_DB_11)); //see https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/I2S/HiFreq_ADC/HiFreq_ADC.ino
#if defined(ARDUINO_ARCH_ESP32) #if defined(I2S_GRAB_ADC1_COMPLETELY)
// according to docs from espressif, the ADC needs to be started explicitly // according to docs from espressif, the ADC needs to be started explicitly
// fingers crossed // fingers crossed
err = i2s_adc_enable(I2S_NUM_0); err = i2s_adc_enable(I2S_NUM_0);
@ -369,52 +379,105 @@ class I2SAdcSource : public I2SSource {
DEBUGSR_PRINTF("Failed to enable i2s adc: %d\n", err); DEBUGSR_PRINTF("Failed to enable i2s adc: %d\n", err);
//return; //return;
} }
#endif #else
err = i2s_adc_disable(I2S_NUM_0);
//err = i2s_stop(I2S_NUM_0);
if (err != ESP_OK) {
DEBUGSR_PRINTF("Failed to initially disable i2s adc: %d\n", err);
}
#endif
_initialized = true; _initialized = true;
} }
I2S_datatype postProcessSample(I2S_datatype sample_in) {
static I2S_datatype lastADCsample = 0; // last good sample
static unsigned int broken_samples_counter = 0; // number of consecutive broken (and fixed) ADC samples
I2S_datatype sample_out = 0;
// bring sample down down to 16bit unsigned
I2S_unsigned_datatype rawData = * reinterpret_cast<I2S_unsigned_datatype *> (&sample_in); // C++ acrobatics to get sample as "unsigned"
#ifndef I2S_USE_16BIT_SAMPLES
rawData = (rawData >> 16) & 0xFFFF; // scale input down from 32bit -> 16bit
I2S_datatype lastGoodSample = lastADCsample / 16384 ; // prepare "last good sample" accordingly (26bit-> 12bit with correct sign handling)
#else
rawData = rawData & 0xFFFF; // input is already in 16bit, just mask off possible junk
I2S_datatype lastGoodSample = lastADCsample * 4; // prepare "last good sample" accordingly (10bit-> 12bit)
#endif
// decode ADC sample data fields
uint16_t the_channel = (rawData >> 12) & 0x000F; // upper 4 bit = ADC channel
uint16_t the_sample = rawData & 0x0FFF; // lower 12bit -> ADC sample (unsigned)
I2S_datatype finalSample = (int(the_sample) - 2048); // convert unsigned sample to signed (centered at 0);
if ((the_channel != _myADCchannel) && (_myADCchannel != 0x0F)) { // 0x0F means "don't know what my channel is"
// fix bad sample
finalSample = lastGoodSample; // replace with last good ADC sample
broken_samples_counter ++;
if (broken_samples_counter > 256) _myADCchannel = 0x0F; // too many bad samples in a row -> disable sample corrections
//Serial.print("\n!ADC rogue sample 0x"); Serial.print(rawData, HEX); Serial.print("\tchannel:");Serial.println(the_channel);
} else broken_samples_counter = 0; // good sample - reset counter
// back to original resolution
#ifndef I2S_USE_16BIT_SAMPLES
finalSample = finalSample << 16; // scale up from 16bit -> 32bit;
#endif
finalSample = finalSample / 4; // mimic old analog driver behaviour (12bit -> 10bit)
sample_out = (3 * finalSample + lastADCsample) / 4; // apply low-pass filter (2-tap FIR)
//sample_out = (finalSample + lastADCsample) / 2; // apply stronger low-pass filter (2-tap FIR)
lastADCsample = sample_out; // update ADC last sample
return(sample_out);
}
void getSamples(float *buffer, uint16_t num_samples) { void getSamples(float *buffer, uint16_t num_samples) {
/* Enable ADC. This has to be enabled and disabled directly before and /* Enable ADC. This has to be enabled and disabled directly before and
* after sampling, otherwise Wifi dies * after sampling, otherwise Wifi dies
*/ */
if (_initialized) { if (_initialized) {
#if !defined(ARDUINO_ARCH_ESP32) #if !defined(I2S_GRAB_ADC1_COMPLETELY)
// old code - works for me without enable/disable, at least on ESP32. // old code - works for me without enable/disable, at least on ESP32.
esp_err_t err = i2s_adc_enable(I2S_NUM_0);
//esp_err_t err = i2s_start(I2S_NUM_0); //esp_err_t err = i2s_start(I2S_NUM_0);
esp_err_t err = i2s_adc_enable(I2S_NUM_0);
if (err != ESP_OK) { if (err != ESP_OK) {
DEBUGSR_PRINTF("Failed to enable i2s adc: %d\n", err); DEBUGSR_PRINTF("Failed to enable i2s adc: %d\n", err);
return; return;
} }
#endif #endif
I2SSource::getSamples(buffer, num_samples); I2SSource::getSamples(buffer, num_samples);
#if !defined(ARDUINO_ARCH_ESP32) #if !defined(I2S_GRAB_ADC1_COMPLETELY)
// old code - works for me without enable/disable, at least on ESP32. // old code - works for me without enable/disable, at least on ESP32.
err = i2s_adc_disable(I2S_NUM_0); err = i2s_adc_disable(I2S_NUM_0); //i2s_adc_disable() may cause crash with IDF 4.4 (https://github.com/espressif/arduino-esp32/issues/6832)
//err = i2s_stop(I2S_NUM_0); //err = i2s_stop(I2S_NUM_0);
if (err != ESP_OK) { if (err != ESP_OK) {
DEBUGSR_PRINTF("Failed to disable i2s adc: %d\n", err); DEBUGSR_PRINTF("Failed to disable i2s adc: %d\n", err);
return; return;
} }
#endif #endif
} }
} }
void deinitialize() { void deinitialize() {
pinManager.deallocatePin(_audioPin, PinOwner::UM_Audioreactive); pinManager.deallocatePin(_audioPin, PinOwner::UM_Audioreactive);
_initialized = false; _initialized = false;
_myADCchannel = 0x0F;
esp_err_t err; esp_err_t err;
#if defined(ARDUINO_ARCH_ESP32) #if defined(I2S_GRAB_ADC1_COMPLETELY)
// according to docs from espressif, the ADC needs to be stopped explicitly // according to docs from espressif, the ADC needs to be stopped explicitly
// fingers crossed // fingers crossed
err = i2s_adc_disable(I2S_NUM_0); err = i2s_adc_disable(I2S_NUM_0);
if (err != ESP_OK) { if (err != ESP_OK) {
DEBUGSR_PRINTF("Failed to disable i2s adc: %d\n", err); DEBUGSR_PRINTF("Failed to disable i2s adc: %d\n", err);
//return;
} }
#endif #endif
i2s_stop(I2S_NUM_0);
err = i2s_driver_uninstall(I2S_NUM_0); err = i2s_driver_uninstall(I2S_NUM_0);
if (err != ESP_OK) { if (err != ESP_OK) {
DEBUGSR_PRINTF("Failed to uninstall i2s driver: %d\n", err); DEBUGSR_PRINTF("Failed to uninstall i2s driver: %d\n", err);
@ -424,6 +487,7 @@ class I2SAdcSource : public I2SSource {
private: private:
int8_t _audioPin; int8_t _audioPin;
int8_t _myADCchannel = 0x0F; // current ADC channel for analog input. 0x0F means "undefined"
}; };
/* SPH0645 Microphone /* SPH0645 Microphone
@ -432,8 +496,8 @@ class I2SAdcSource : public I2SSource {
*/ */
class SPH0654 : public I2SSource { class SPH0654 : public I2SSource {
public: public:
SPH0654(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : SPH0654(int sampleRate, int blockSize) :
I2SSource(sampleRate, blockSize, lshift, mask) I2SSource(sampleRate, blockSize)
{} {}
void initialize(uint8_t i2swsPin, uint8_t i2ssdPin, uint8_t i2sckPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { void initialize(uint8_t i2swsPin, uint8_t i2ssdPin, uint8_t i2sckPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) {

View File

@ -6157,7 +6157,8 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline.
} }
float volumeSmth = *(float*) um_data->u_data[0]; float volumeSmth = *(float*) um_data->u_data[0];
SEGMENT.fade_out(240); //SEGMENT.fade_out(240);
SEGMENT.fade_out(251); // 30%
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f;
segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling
@ -6206,8 +6207,9 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew
// printUmData(); // printUmData();
SEGMENT.fade_out(240); //SEGMENT.fade_out(240);
SEGMENT.fade_out(240); // twice? really? //SEGMENT.fade_out(240); // twice? really?
SEGMENT.fade_out(253); // 50%
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0; float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0;
segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivty" upscaling segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivty" upscaling
@ -6254,7 +6256,8 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline.
} }
float volumeSmth = *(float*) um_data->u_data[0]; float volumeSmth = *(float*) um_data->u_data[0];
SEGMENT.fade_out(240); //SEGMENT.fade_out(240);
SEGMENT.fade_out(249); // 25%
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0; float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0;
segmentSampleAvg *= 0.25; // divide by 4, to compensate for later "sensitivty" upscaling segmentSampleAvg *= 0.25; // divide by 4, to compensate for later "sensitivty" upscaling
@ -6294,7 +6297,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline.
} }
float volumeSmth = *(float*) um_data->u_data[0]; float volumeSmth = *(float*) um_data->u_data[0];
SEGMENT.fade_out(224); SEGMENT.fade_out(224); // 6.25%
uint16_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); uint16_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0);
for (size_t i=0; i<SEGMENT.intensity/32+1U; i++) { for (size_t i=0; i<SEGMENT.intensity/32+1U; i++) {
@ -6419,11 +6422,13 @@ uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline.
float volumeSmth = *(float*) um_data->u_data[0]; float volumeSmth = *(float*) um_data->u_data[0];
int16_t volumeRaw = *(int16_t*)um_data->u_data[1]; int16_t volumeRaw = *(int16_t*)um_data->u_data[1];
uint8_t fadeRate = map(SEGMENT.speed,0,255,224,255); //uint8_t fadeRate = map(SEGMENT.speed,0,255,224,255);
uint8_t fadeRate = map(SEGMENT.speed,0,255,200,254);
SEGMENT.fade_out(fadeRate); SEGMENT.fade_out(fadeRate);
float tmpSound2 = volumeRaw * 2.0 * (float)SEGMENT.intensity / 255.0; float tmpSound2 = volumeRaw * 2.0 * (float)SEGMENT.intensity / 255.0;
int maxLen = mapf(tmpSound2, 0, 255, 0, SEGLEN); // map to pixels availeable in current segment // Still a bit too sensitive. int maxLen = mapf(tmpSound2, 0, 255, 0, SEGLEN); // map to pixels availeable in current segment // Still a bit too sensitive.
if (maxLen <0) maxLen = 0;
if (maxLen >SEGLEN) maxLen = SEGLEN; if (maxLen >SEGLEN) maxLen = SEGLEN;
for (int i=0; i<maxLen; i++) { // The louder the sound, the wider the soundbar. By Andrew Tuline. for (int i=0; i<maxLen; i++) { // The louder the sound, the wider the soundbar. By Andrew Tuline.
@ -6521,7 +6526,7 @@ static const char _data_FX_MODE_PLASMOID[] PROGMEM = "Plasmoid@Phase,# of pixels
uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline.
uint16_t size = 0; uint16_t size = 0;
uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 255); uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254);
uint16_t pos = random(SEGLEN); // Set a random starting position. uint16_t pos = random(SEGLEN); // Set a random starting position.
um_data_t *um_data; um_data_t *um_data;
@ -6563,7 +6568,7 @@ static const char _data_FX_MODE_PUDDLEPEAK[] PROGMEM = "Puddlepeak@Fade rate,Pud
////////////////////// //////////////////////
uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline. uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline.
uint16_t size = 0; uint16_t size = 0;
uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 255); uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254);
uint16_t pos = random16(SEGLEN); // Set a random starting position. uint16_t pos = random16(SEGLEN); // Set a random starting position.
SEGMENT.fade_out(fadeVal); SEGMENT.fade_out(fadeVal);
@ -6714,10 +6719,13 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN.
SEGMENT.fade_out(SEGMENT.speed); SEGMENT.fade_out(SEGMENT.speed);
uint16_t locn = (log10f((float)FFT_MajorPeak) - 1.78f) * (float)SEGLEN/(3.71f-1.78f); // log10 frequency range is from 1.78 to 3.71. Let's scale to SEGLEN. // int locn = (log10f((float)FFT_MajorPeak) - 1.78f) * (float)SEGLEN/(3.71f-1.78f); // log10 frequency range is from 1.78 to 3.71. Let's scale to SEGLEN.
int locn = (log10f((float)FFT_MajorPeak) - 1.78f) * (float)SEGLEN/(4.0102f-1.78f); // log10 frequency range is from 1.78 to 3.71. Let's scale to SEGLEN.
if (locn < 1) locn = 0; // avoid underflow
if (locn >=SEGLEN) locn = SEGLEN-1; if (locn >=SEGLEN) locn = SEGLEN-1;
uint16_t pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(3.71f-1.78f); // Scale log10 of frequency values to the 255 colour index. //uint16_t pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(3.71f-1.78f); // Scale log10 of frequency values to the 255 colour index.
uint16_t pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(4.0102f-1.78f); // Scale log10 of frequency values to the 255 colour index.
uint16_t bright = (int)my_magnitude; uint16_t bright = (int)my_magnitude;
SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), bright)); SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), bright));
@ -6756,7 +6764,8 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch
CRGB color = CRGB::Black; CRGB color = CRGB::Black;
if (FFT_MajorPeak > 5120) FFT_MajorPeak = 0; //if (FFT_MajorPeak > 5120) FFT_MajorPeak = 0;
if (FFT_MajorPeak > 10240) FFT_MajorPeak = 0;
// MajorPeak holds the freq. value which is most abundant in the last sample. // MajorPeak holds the freq. value which is most abundant in the last sample.
// With our sampling rate of 10240Hz we have a usable freq range from roughtly 80Hz to 10240/2 Hz // With our sampling rate of 10240Hz we have a usable freq range from roughtly 80Hz to 10240/2 Hz
// we will treat everything with less than 65Hz as 0 // we will treat everything with less than 65Hz as 0
@ -6803,7 +6812,8 @@ uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline.
for (int i=0; i < SEGMENT.intensity/32+1; i++) { for (int i=0; i < SEGMENT.intensity/32+1; i++) {
uint16_t locn = random16(0,SEGLEN); uint16_t locn = random16(0,SEGLEN);
uint8_t pixCol = (log10f(FFT_MajorPeak) - 1.78) * 255.0/(3.71-1.78); // Scale log10 of frequency values to the 255 colour index. //uint8_t pixCol = (log10f(FFT_MajorPeak) - 1.78) * 255.0/(3.71-1.78); // Scale log10 of frequency values to the 255 colour index.
uint8_t pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(4.0102f-1.78f); // Scale log10 of frequency values to the 255 colour index.
SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude));
} }
@ -6853,7 +6863,8 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun
CRGB color = 0; CRGB color = 0;
if (FFT_MajorPeak > 5120) FFT_MajorPeak = 0.0f; //if (FFT_MajorPeak > 5120) FFT_MajorPeak = 0.0f;
if (FFT_MajorPeak > 10240) FFT_MajorPeak = 0.0f;
// MajorPeak holds the freq. value which is most abundant in the last sample. // MajorPeak holds the freq. value which is most abundant in the last sample.
// With our sampling rate of 10240Hz we have a usable freq range from roughtly 80Hz to 10240/2 Hz // With our sampling rate of 10240Hz we have a usable freq range from roughtly 80Hz to 10240/2 Hz
// we will treat everything with less than 65Hz as 0 // we will treat everything with less than 65Hz as 0
@ -6909,7 +6920,8 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline.
for (int i=0; i<tempsamp; i++) { for (int i=0; i<tempsamp; i++) {
uint8_t index = (log10((int)FFT_MajorPeak) - (3.71-1.78)) * 255; //int? shouldn't it be floor() or similar //uint8_t index = (log10((int)FFT_MajorPeak) - (3.71-1.78)) * 255; //int? shouldn't it be floor() or similar
uint8_t index = (log10f(FFT_MajorPeak) - (4.0102f-1.78f)) * 255; //int? shouldn't it be floor() or similar
SEGMENT.setPixelColor(i+SEGLEN/2, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); SEGMENT.setPixelColor(i+SEGLEN/2, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0));
SEGMENT.setPixelColor(SEGLEN/2-i-1, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); SEGMENT.setPixelColor(SEGLEN/2-i-1, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0));

View File

@ -216,10 +216,13 @@ void handleAnalog(uint8_t b)
void handleButton() void handleButton()
{ {
static unsigned long lastRead = 0UL; static unsigned long lastRead = 0UL;
static unsigned long lastRun = 0UL;
bool analog = false; bool analog = false;
unsigned long now = millis(); unsigned long now = millis();
if (strip.isUpdating()) return; // don't interfere with strip updates. Our button will still be there in 1ms (next cycle) //if (strip.isUpdating()) return; // don't interfere with strip updates. Our button will still be there in 1ms (next cycle)
if (strip.isUpdating() && (millis() - lastRun < 400)) return; // be niced, but avoid button starvation
lastRun = millis();
for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) { for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
#ifdef ESP8266 #ifdef ESP8266