From f21780483887245a88c33dda02e72c162b3d2c51 Mon Sep 17 00:00:00 2001 From: Ryzerth Date: Mon, 28 Dec 2020 14:39:30 +0100 Subject: [PATCH] push before merge --- core/src/dsp/measure.h | 99 +++++++++++++++++++++++++++ core/src/gui/widgets/volume_meter.cpp | 53 ++++++++++++++ core/src/gui/widgets/volume_meter.h | 6 ++ recorder/src/main.cpp | 1 - 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 core/src/dsp/measure.h create mode 100644 core/src/gui/widgets/volume_meter.cpp create mode 100644 core/src/gui/widgets/volume_meter.h diff --git a/core/src/dsp/measure.h b/core/src/dsp/measure.h new file mode 100644 index 00000000..00b25be8 --- /dev/null +++ b/core/src/dsp/measure.h @@ -0,0 +1,99 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace dsp { + class VolumeMeasure : public generic_block { + public: + VolumeMeasure() {} + + VolumeMeasure(stream* in) { init(in); } + + ~VolumeMeasure() { + generic_block::stop(); + delete[] leftBuf; + delete[] rightBuf; + } + + void init(stream* in) { + _in = in; + leftBuf = new float[STREAM_BUFFER_SIZE]; + rightBuf = new float[STREAM_BUFFER_SIZE]; + generic_block::registerInput(_in); + generic_block::registerOutput(&out); + } + + void setInput(stream* in) { + std::lock_guard lck(generic_block::ctrlMtx); + generic_block::tempStop(); + generic_block::unregisterInput(_in); + _in = in; + generic_block::registerInput(_in); + generic_block::tempStart(); + } + + int run() { + count = _in->read(); + if (count < 0) { return -1; } + + memcpy(out.writeBuf, _in->readBuf, count * sizeof(stereo_t)); + volk_32fc_deinterleave_32f_x2(leftBuf, rightBuf, (lv_32fc_t*)_in->readBuf, count); + + _in->flush(); + if (!out.swap(count)) { return -1; } + + // Get peak from last value + float time = (float)count / sampleRate; + peak.l -= peakFall * time; + peak.r -= peakFall * time; + stereo_t _peak; + _peak.l = powf(10, peak.l / 10.0f); + _peak.r = powf(10, peak.r / 10.0f); + + stereo_t _average; + + // Calculate average + volk_32f_s32f_power_32f(leftBuf, leftBuf, 2, count); + volk_32f_s32f_power_32f(rightBuf, rightBuf, 2, count); + volk_32f_sqrt_32f(leftBuf, leftBuf, count); + volk_32f_sqrt_32f(rightBuf, rightBuf, count); + volk_32f_accumulator_s32f(&_average.l, leftBuf, count); + volk_32f_accumulator_s32f(&_average.r, rightBuf, count); + _average.l /= (float)count; + _average.r /= (float)count; + + // Calculate peak + for (int i = 0; i < count; i++) { + if (leftBuf[i] > _peak.l) { _peak.l = leftBuf[i]; } + if (rightBuf[i] > _peak.r) { _peak.r = rightBuf[i]; } + } + + // Assign + peak.l = 10.0f * log10f(_peak.l); + peak.r = 10.0f * log10f(_peak.r); + average.l = (average.l * (1.0f - avgFilt)) + (10.0f * log10f(_average.l) * avgFilt); + average.r = (average.r * (1.0f - avgFilt)) + (10.0f * log10f(_average.r) * avgFilt); + + return count; + } + + stream out; + + stereo_t peak = {0, 0}; + stereo_t average = {0, 0}; + + private: + int count; + float peakFall = 10.0f; // dB/S + float avgFilt = 0.2f; // IIR filter coef + float sampleRate = 48000; + stream* _in; + + float* leftBuf; + float* rightBuf; + }; +} \ No newline at end of file diff --git a/core/src/gui/widgets/volume_meter.cpp b/core/src/gui/widgets/volume_meter.cpp new file mode 100644 index 00000000..1ac6b55d --- /dev/null +++ b/core/src/gui/widgets/volume_meter.cpp @@ -0,0 +1,53 @@ +#include +#include + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include + +namespace ImGui { + void VolumeMeter(float avg, float peak, float val_min, float val_max, const ImVec2& size_arg) { + ImGuiWindow* window = GetCurrentWindow(); + ImGuiStyle& style = GImGui->Style; + + avg = std::clamp(avg, val_min, val_max); + peak = std::clamp(peak, val_min, val_max); + + float pad = style.FramePadding.y; + + ImVec2 min = window->DC.CursorPos; + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (GImGui->FontSize / 2) + style.FramePadding.y); + ImRect bb(min, min + size); + + float lineHeight = size.y; + + ItemSize(size, style.FramePadding.y); + if (!ItemAdd(bb, 0)) { + return; + } + + float zeroDb = roundf(((-val_min) / (val_max - val_min)) * size.x); + + window->DrawList->AddRectFilled(min, min + ImVec2(zeroDb, lineHeight), IM_COL32( 0, 255, 0, 127 )); + window->DrawList->AddRectFilled(min + ImVec2(zeroDb, 0), min + ImVec2(size.x, lineHeight), IM_COL32( 255, 0, 0, 127 )); + + float end = roundf(((avg - val_min) / (val_max - val_min)) * size.x); + float endP = roundf(((peak - val_min) / (val_max - val_min)) * size.x); + + if (avg <= 0) { + window->DrawList->AddRectFilled(min, min + ImVec2(end, lineHeight), IM_COL32( 0, 255, 0, 255 )); + } + else { + window->DrawList->AddRectFilled(min, min + ImVec2(zeroDb, lineHeight), IM_COL32( 0, 255, 0, 255 )); + window->DrawList->AddRectFilled(min + ImVec2(zeroDb, 0), min + ImVec2(end, lineHeight), IM_COL32( 255, 0, 0, 255 )); + } + + if (peak <= 0) { + window->DrawList->AddLine(min + ImVec2(endP, -1), min + ImVec2(endP, lineHeight - 1), IM_COL32( 127, 255, 127, 255 )); + } + else { + window->DrawList->AddLine(min + ImVec2(endP, -1), min + ImVec2(endP, lineHeight - 1), IM_COL32( 255, 127, 127, 255 )); + } + } +} \ No newline at end of file diff --git a/core/src/gui/widgets/volume_meter.h b/core/src/gui/widgets/volume_meter.h new file mode 100644 index 00000000..5a58b3c6 --- /dev/null +++ b/core/src/gui/widgets/volume_meter.h @@ -0,0 +1,6 @@ +#pragma once +#include + +namespace ImGui { + void VolumeMeter(float avg, float peak, float val_min, float val_max, const ImVec2& size_arg = ImVec2(0, 0)); +} \ No newline at end of file diff --git a/recorder/src/main.cpp b/recorder/src/main.cpp index efff67b7..7e09478a 100644 --- a/recorder/src/main.cpp +++ b/recorder/src/main.cpp @@ -13,7 +13,6 @@ #include #include #include - #define CONCAT(a, b) ((std::string(a) + b).c_str()) SDRPP_MOD_INFO {