From b63db61b9cdf0e55261a3d9129cec64a44d2ffe6 Mon Sep 17 00:00:00 2001 From: pschatzmann Date: Sat, 16 Nov 2024 19:59:34 +0100 Subject: [PATCH] Unsigned support for NumberFormatConverterStreamT --- .../numberformat-converter.ino | 28 +++++++++ src/AudioConfig.h | 2 + src/AudioTools/AudioLibs/FFTDisplay.h | 2 +- src/AudioTools/AudioLibs/LEDOutput.h | 2 +- src/AudioTools/AudioLibs/LEDOutputUnoR4.h | 2 +- .../CoreAudio/AudioBasic/FloatAudio.h | 52 ++++++++++++++++ .../CoreAudio/AudioBasic/Int24_3bytes_t.h | 15 ++++- .../CoreAudio/AudioBasic/Int24_4bytes_t.h | 15 ++++- src/AudioTools/CoreAudio/AudioOutput.h | 2 +- .../CoreAudio/AudioStreamsConverter.h | 6 ++ src/AudioTools/CoreAudio/AudioTypes.h | 60 ++++++++++++++----- src/AudioTools/CoreAudio/ResampleStream.h | 2 +- src/AudioTools/CoreAudio/VolumeControl.h | 4 +- 13 files changed, 168 insertions(+), 24 deletions(-) create mode 100644 examples/tests/conversion/numberformat-converter-typed/numberformat-converter.ino create mode 100644 src/AudioTools/CoreAudio/AudioBasic/FloatAudio.h diff --git a/examples/tests/conversion/numberformat-converter-typed/numberformat-converter.ino b/examples/tests/conversion/numberformat-converter-typed/numberformat-converter.ino new file mode 100644 index 0000000000..e8d7e48578 --- /dev/null +++ b/examples/tests/conversion/numberformat-converter-typed/numberformat-converter.ino @@ -0,0 +1,28 @@ +#include "AudioTools.h" + +using target_t = uint32_t; // uint8_t, int8_t, int16_t, uint16_t, int24_t, uint32_t, int32_t, FloatAudio +SineWaveGenerator sineWave; // subclass of SoundGenerator with max amplitude of 32000 +GeneratedSoundStream sound(sineWave); // Stream generated from sine wave +CsvOutput out(Serial, sound.audioInfo().channels); +NumberFormatConverterStreamT nfc(out); +StreamCopy copier(nfc, sound); // copies sound into i2s + +// Arduino Setup +void setup(void) { + // Open Serial + Serial.begin(115200); + AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning); + + nfc.begin(); + out.begin(); + sineWave.begin(); + + // Setup sine wave + sineWave.setFrequency(N_B4); + Serial.println("started..."); +} + +// Arduino loop - copy sound to out +void loop() { + copier.copy(); +} diff --git a/src/AudioConfig.h b/src/AudioConfig.h index 8f4c4d99d2..4543d89894 100644 --- a/src/AudioConfig.h +++ b/src/AudioConfig.h @@ -818,6 +818,8 @@ using WiFiServerSecure = BearSSL::WiFiServerSecure; // select int24 implementation #include "AudioTools/CoreAudio/AudioBasic/Int24_3bytes_t.h" #include "AudioTools/CoreAudio/AudioBasic/Int24_4bytes_t.h" +#include "AudioTools/CoreAudio/AudioBasic/FloatAudio.h" + namespace audio_tools { #ifdef USE_3BYTE_INT24 using int24_t = audio_tools::int24_3bytes_t; diff --git a/src/AudioTools/AudioLibs/FFTDisplay.h b/src/AudioTools/AudioLibs/FFTDisplay.h index be66e7d4eb..aa8846d5d0 100644 --- a/src/AudioTools/AudioLibs/FFTDisplay.h +++ b/src/AudioTools/AudioLibs/FFTDisplay.h @@ -57,7 +57,7 @@ class FFTDisplay { } int getMagnitudeScaled(int x, int max) { - int result = mapFloat(getMagnitude(x), 0, fft_max_magnitude, 0.0f, + int result = mapT(getMagnitude(x), 0, fft_max_magnitude, 0.0f, static_cast(max)); if (result > max){ LOGD("fft_max_magnitude too small: current value is %f", getMagnitude(x)) diff --git a/src/AudioTools/AudioLibs/LEDOutput.h b/src/AudioTools/AudioLibs/LEDOutput.h index 2868071245..dc73a0f52d 100644 --- a/src/AudioTools/AudioLibs/LEDOutput.h +++ b/src/AudioTools/AudioLibs/LEDOutput.h @@ -265,7 +265,7 @@ void fftLEDOutput(LEDOutputConfig *cfg, LEDOutput *matrix) { /// Default update implementation which provides the fft result as "barchart" void volumeLEDOutput(LEDOutputConfig *cfg, LEDOutput *matrix) { float vol = matrix->getMaxMagnitude(); - int currY = mapFloat(vol, 0, + int currY = mapT(vol, 0, cfg->max_magnitude, 0.0f, static_cast(cfg->y)); matrix->addColumnBar(currY); diff --git a/src/AudioTools/AudioLibs/LEDOutputUnoR4.h b/src/AudioTools/AudioLibs/LEDOutputUnoR4.h index ef9f7b3c79..39dfc1ba26 100644 --- a/src/AudioTools/AudioLibs/LEDOutputUnoR4.h +++ b/src/AudioTools/AudioLibs/LEDOutputUnoR4.h @@ -183,7 +183,7 @@ void fftLEDOutputUnoR4(LEDOutputUnoR4Config *cfg, LEDOutputUnoR4 *matrix) { /// Default update implementation which provides the fft result as "barchart" void volumeLEDOutputUnoR4(LEDOutputUnoR4Config *cfg, LEDOutputUnoR4 *matrix) { float vol = matrix->getMaxMagnitude(); - int currY = mapFloat(vol, 0.0, + int currY = mapT(vol, 0.0, cfg->max_magnitude, 0.0f, static_cast(cfg->y)); matrix->addColumnBar(currY); diff --git a/src/AudioTools/CoreAudio/AudioBasic/FloatAudio.h b/src/AudioTools/CoreAudio/AudioBasic/FloatAudio.h new file mode 100644 index 0000000000..3e9b249353 --- /dev/null +++ b/src/AudioTools/CoreAudio/AudioBasic/FloatAudio.h @@ -0,0 +1,52 @@ +#pragma once +#include "AudioConfig.h" + +namespace audio_tools { + +/*** + * A simple float number (in the range of -1.0 to 1.0) the supports the conversion to + * it's corresponding scaled int values. + */ + +class FloatAudio { + public: + FloatAudio() = default; + FloatAudio(float in) { this->value = in; } + + explicit inline operator int8_t() { return value * 127; } + + explicit inline operator int16_t() { return value * 32767; } + + inline operator float() { return value; } + + // explicit inline operator int24_t() { + // return value * 8388607; + // } + + explicit inline operator int32_t() { return value * 2147483647; } + + protected: + float value = 0.0f; +}; + +} // namespace audio_tools + +#ifdef USE_TYPETRAITS + +namespace std { +template <> +class numeric_limits { + public: + static audio_tools::FloatAudio lowest() { + return audio_tools::FloatAudio(-1.0f); + }; + static audio_tools::FloatAudio min() { + return audio_tools::FloatAudio(-1.0f); + }; + static audio_tools::FloatAudio max() { + return audio_tools::FloatAudio(1.0f); + }; +}; +} // namespace std + +#endif diff --git a/src/AudioTools/CoreAudio/AudioBasic/Int24_3bytes_t.h b/src/AudioTools/CoreAudio/AudioBasic/Int24_3bytes_t.h index b79b3d0421..60289275d0 100644 --- a/src/AudioTools/CoreAudio/AudioBasic/Int24_3bytes_t.h +++ b/src/AudioTools/CoreAudio/AudioBasic/Int24_3bytes_t.h @@ -129,4 +129,17 @@ class int24_3bytes_t { }; -} // namespace audio_tools \ No newline at end of file +} // namespace audio_tools + +#ifdef USE_TYPETRAITS + +namespace std { + template<> class numeric_limits { + public: + static audio_tools::int24_3bytes_t lowest() {return audio_tools::int24_3bytes_t(-0x7FFFFF);}; + static audio_tools::int24_3bytes_t min() {return audio_tools::int24_3bytes_t(-0x7FFFFF);}; + static audio_tools::int24_3bytes_t max() {return audio_tools::int24_3bytes_t(0x7FFFFF);}; + }; +} + +#endif \ No newline at end of file diff --git a/src/AudioTools/CoreAudio/AudioBasic/Int24_4bytes_t.h b/src/AudioTools/CoreAudio/AudioBasic/Int24_4bytes_t.h index f29beb748b..cb128f450b 100644 --- a/src/AudioTools/CoreAudio/AudioBasic/Int24_4bytes_t.h +++ b/src/AudioTools/CoreAudio/AudioBasic/Int24_4bytes_t.h @@ -134,4 +134,17 @@ class int24_4bytes_t { }; -} // namespace audio_tools \ No newline at end of file +} // namespace audio_tools + +#ifdef USE_TYPETRAITS + +namespace std { + template<> class numeric_limits { + public: + static audio_tools::int24_4bytes_t lowest() {return audio_tools::int24_4bytes_t(-0x7FFFFF);}; + static audio_tools::int24_4bytes_t min() {return audio_tools::int24_4bytes_t(-0x7FFFFF);}; + static audio_tools::int24_4bytes_t max() {return audio_tools::int24_4bytes_t(0x7FFFFF);}; + }; +} + +#endif \ No newline at end of file diff --git a/src/AudioTools/CoreAudio/AudioOutput.h b/src/AudioTools/CoreAudio/AudioOutput.h index b40d32b70c..bd63587616 100644 --- a/src/AudioTools/CoreAudio/AudioOutput.h +++ b/src/AudioTools/CoreAudio/AudioOutput.h @@ -220,7 +220,7 @@ template class CsvOutput : public AudioOutput { for (size_t j = 0; j < frameCount; j++) { for (int ch = 0; ch < cfg.channels; ch++) { if (out_ptr != nullptr && data_ptr != nullptr) { - int value = *data_ptr; + T value = *data_ptr; out_ptr->print(value); } data_ptr++; diff --git a/src/AudioTools/CoreAudio/AudioStreamsConverter.h b/src/AudioTools/CoreAudio/AudioStreamsConverter.h index 7c3ddc75ed..19ebb662a0 100644 --- a/src/AudioTools/CoreAudio/AudioStreamsConverter.h +++ b/src/AudioTools/CoreAudio/AudioStreamsConverter.h @@ -362,7 +362,13 @@ class NumberFormatConverterStreamT : public ReformatBaseStream { TRACED(); if (p_print == nullptr) return 0; //addNotifyOnFirstWrite(); + +#ifdef USE_TYPETRAITS + if (std::is_same::value) return p_print->write(data, len); +#else if (sizeof(TFrom) == sizeof(TTo)) return p_print->write(data, len); +#endif + size_t samples = len / sizeof(TFrom); size_t result_size = 0; TFrom *data_source = (TFrom *)data; diff --git a/src/AudioTools/CoreAudio/AudioTypes.h b/src/AudioTools/CoreAudio/AudioTypes.h index 37d0358938..83fdc83749 100644 --- a/src/AudioTools/CoreAudio/AudioTypes.h +++ b/src/AudioTools/CoreAudio/AudioTypes.h @@ -3,7 +3,9 @@ #include "AudioConfig.h" #ifdef USE_TYPETRAITS # include +# include #endif + #include "AudioTools/CoreAudio/AudioLogger.h" #include "AudioTools/CoreAudio/AudioBasic/Collections/Vector.h" @@ -291,6 +293,20 @@ class AudioTime { } }; +/// @brief Similar to Arduino map function but using floats +/// @param x +/// @param in_min +/// @param in_max +/// @param out_min +/// @param out_max +/// @return +template +inline T mapT(T x, T in_min, T in_max, T out_min, T out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + + + /** * @brief Converts from a source to a target number with a different type * @ingroup basic @@ -314,15 +330,29 @@ class NumberConverter { /// provides the biggest number for the indicated type template - static int64_t maxValueT(){ + static float maxValueT(){ #ifdef USE_TYPETRAITS // int24_t uses 4 bytes instead of 3! - return (std::is_same::value ) ? 8388607 : maxValue(sizeof(T)*8); + //return (std::is_same::value ) ? 8388607 : maxValue(sizeof(T)*8); + return std::numeric_limits::max(); #else return maxValue(sizeof(T)*8); #endif } + template + static float minValueT(){ +#ifdef USE_TYPETRAITS + // int24_t uses 4 bytes instead of 3! + //return (std::is_same::value ) ? 8388607 : maxValue(sizeof(T)*8); + return std::numeric_limits::min(); +#else + return -maxValue(sizeof(T)*8); +#endif + } + + + /// Clips the value to avoid any over or underflows template static T clipT(float value){ @@ -372,7 +402,18 @@ class NumberConverter { template static ToT convert(FromT value){ float value1 = value; - return clipT(value1 * maxValueT() / maxValueT()); + float minTo = minValueT(); + float maxTo = maxValueT(); + float maxFrom = maxValueT(); + float minFrom = minValueT(); + + if (maxTo - minTo > 1.0f + || maxFrom - minFrom > 1.0f) { + return mapT(value1, minFrom, maxFrom, minTo, maxTo); + } + + + return value1 * maxValueT() / maxValueT(); } /// Convert an array of int types @@ -381,7 +422,7 @@ class NumberConverter { float factor = static_cast(maxValueT()) / maxValueT(); float vol_factor = factor * vol; for (int j=0;j(vol_factor * from[j]); + to[j] = clipT(vol * convert(from[j])); } } @@ -478,17 +519,6 @@ size_t writeSamples(Print* p_out, T* data, int samples, int maxSamples=512){ } -/// @brief Similar to Arduino map function but using floats -/// @param x -/// @param in_min -/// @param in_max -/// @param out_min -/// @param out_max -/// @return -inline float mapFloat(float x, float in_min, float in_max, float out_min, float out_max) { - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; -} - /// @brief Mime type for PCM static const char* mime_pcm = "audio/pcm"; diff --git a/src/AudioTools/CoreAudio/ResampleStream.h b/src/AudioTools/CoreAudio/ResampleStream.h index 9adf88cce5..49059f659c 100644 --- a/src/AudioTools/CoreAudio/ResampleStream.h +++ b/src/AudioTools/CoreAudio/ResampleStream.h @@ -300,7 +300,7 @@ class ResampleStream : public ReformatBaseStream { T val0 = lookup(data, frame_idx0, channel); T val1 = lookup(data, frame_idx1, channel); - float result = mapFloat(frame_idx, frame_idx0, frame_idx1, val0, val1); + float result = mapT(frame_idx, frame_idx0, frame_idx1, val0, val1); LOGD("getValue idx: %d:%d / val: %d:%d / %f -> %f", frame_idx0, frame_idx1, (int)val0, (int)val1, frame_idx, result) return (float)round(result); diff --git a/src/AudioTools/CoreAudio/VolumeControl.h b/src/AudioTools/CoreAudio/VolumeControl.h index f9e0f29717..df42ad4ab3 100644 --- a/src/AudioTools/CoreAudio/VolumeControl.h +++ b/src/AudioTools/CoreAudio/VolumeControl.h @@ -129,9 +129,9 @@ class SimulatedAudioPot : public VolumeControl { virtual float getVolumeFactor(float volume) { float result = 0; if (volume<=x){ - result = mapFloat(volume, 0.0, x, 0, y ); + result = mapT(volume, 0.0, x, 0, y ); } else { - result = mapFloat(volume, x, 1.0, y, 1.0); + result = mapT(volume, x, 1.0, y, 1.0); } return limit(result); }