diff --git a/source/native-plugins/_data.cpp b/source/native-plugins/_data.cpp index 43d4521c9..533015fc7 100644 --- a/source/native-plugins/_data.cpp +++ b/source/native-plugins/_data.cpp @@ -234,6 +234,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, /* hints */ static_cast(NATIVE_PLUGIN_IS_RTSAFE + |NATIVE_PLUGIN_HAS_INLINE_DISPLAY |NATIVE_PLUGIN_HAS_UI |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE |NATIVE_PLUGIN_USES_TIME), @@ -472,6 +473,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, /* hints */ static_cast(NATIVE_PLUGIN_IS_RTSAFE + |NATIVE_PLUGIN_HAS_INLINE_DISPLAY |NATIVE_PLUGIN_HAS_UI |NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, diff --git a/source/native-plugins/audio-file.cpp b/source/native-plugins/audio-file.cpp index 4833675e7..d732e068f 100644 --- a/source/native-plugins/audio-file.cpp +++ b/source/native-plugins/audio-file.cpp @@ -34,7 +34,8 @@ public: fLastFrame(0), fMaxFrame(0), fPool(), - fThread(this, static_cast(getSampleRate())) + fThread(this, static_cast(getSampleRate())), + fInlineDisplay() { fPool.create(static_cast(getSampleRate())); } @@ -186,6 +187,19 @@ protected: carla_zeroFloats(bufferL + poolFrame, framesToCopy); carla_zeroFloats(bufferR + poolFrame, framesToCopy); + + if (fInlineDisplay.writtenValues < 32) + { + fInlineDisplay.lastValuesL[fInlineDisplay.writtenValues] = carla_findMaxNormalizedFloat(out1, frames); + fInlineDisplay.lastValuesR[fInlineDisplay.writtenValues] = carla_findMaxNormalizedFloat(out2, frames); + ++fInlineDisplay.writtenValues; + } + + if (! fInlineDisplay.pending) + { + fInlineDisplay.pending = true; + hostQueueDrawInlineDisplay(); + } } else { @@ -210,6 +224,116 @@ protected: uiClosed(); } + // ------------------------------------------------------------------- + // Plugin dispatcher calls + + const NativeInlineDisplayImageSurface* renderInlineDisplay(const uint32_t width, const uint32_t height) override + { + CARLA_SAFE_ASSERT_RETURN(width > 0 && height > 0, nullptr); + + /* NOTE the code is this function is not optimized, still learning my way through pixels... + */ + const size_t stride = width * 4; + const size_t dataSize = stride * height; + const uint pxToMove = fInlineDisplay.writtenValues; + + uchar* data = fInlineDisplay.idisp.data; + + if (fInlineDisplay.dataSize != dataSize || data == nullptr) + { + delete[] data; + data = new uchar[dataSize]; + std::memset(data, 0, dataSize); + fInlineDisplay.idisp.data = data; + fInlineDisplay.dataSize = dataSize; + } + else if (pxToMove != 0) + { + // shift all previous values to the left + for (uint w=0; w < width - pxToMove; ++w) + for (uint h=0; h < height; ++h) + std::memmove(&data[h * stride + w * 4], &data[h * stride + (w+pxToMove) * 4], 4); + } + + fInlineDisplay.idisp.width = static_cast(width); + fInlineDisplay.idisp.height = static_cast(height); + fInlineDisplay.idisp.stride = static_cast(stride); + + const uint h2 = height / 2; + + // clear current line + for (uint w=width-pxToMove; w < width; ++w) + for (uint h=0; h < height; ++h) + memset(&data[h * stride + w * 4], 0, 4); + + // draw upper/left + for (uint i=0; i < pxToMove; ++i) + { + const float valueL = fInlineDisplay.lastValuesL[i]; + const float valueR = fInlineDisplay.lastValuesR[i]; + + const uint h2L = static_cast(valueL * (float)h2); + const uint h2R = static_cast(valueR * (float)h2); + const uint w = width - pxToMove + i; + + for (uint h=0; h < h2L; ++h) + { + // -30dB + //if (valueL < 0.032f) + // continue; + + data[(h2 - h) * stride + w * 4 + 3] = 160; + + // -12dB + if (valueL < 0.25f) + { + data[(h2 - h) * stride + w * 4 + 1] = 255; + } + // -3dB + else if (valueL < 0.70f) + { + data[(h2 - h) * stride + w * 4 + 2] = 255; + data[(h2 - h) * stride + w * 4 + 1] = 255; + } + else + { + data[(h2 - h) * stride + w * 4 + 2] = 255; + } + } + + for (uint h=0; h < h2R; ++h) + { + // -30dB + //if (valueR < 0.032f) + // continue; + + data[(h2 + h) * stride + w * 4 + 3] = 160; + + // -12dB + if (valueR < 0.25f) + { + data[(h2 + h) * stride + w * 4 + 1] = 255; + } + // -3dB + else if (valueR < 0.70f) + { + data[(h2 + h) * stride + w * 4 + 2] = 255; + data[(h2 + h) * stride + w * 4 + 1] = 255; + } + else + { + data[(h2 + h) * stride + w * 4 + 2] = 255; + } + } + } + + fInlineDisplay.writtenValues = 0; + fInlineDisplay.pending = false; + return &fInlineDisplay.idisp; + } + + // ------------------------------------------------------------------- + private: bool fLoopMode; bool fDoProcess; @@ -220,6 +344,35 @@ private: AudioFilePool fPool; AudioFileThread fThread; + struct InlineDisplay { + NativeInlineDisplayImageSurface idisp; + size_t dataSize; + float lastValuesL[32]; + float lastValuesR[32]; + volatile uint8_t writtenValues; + volatile bool pending; + + InlineDisplay() + : idisp{}, + dataSize(0), + lastValuesL{0.0f}, + lastValuesR{0.0f}, + writtenValues(0), + pending(false) {} + + ~InlineDisplay() + { + if (idisp.data != nullptr) + { + delete[] idisp.data; + idisp.data = nullptr; + } + } + + CARLA_DECLARE_NON_COPY_STRUCT(InlineDisplay) + CARLA_PREVENT_HEAP_ALLOCATION + } fInlineDisplay; + void loadFilename(const char* const filename) { CARLA_ASSERT(filename != nullptr); @@ -256,6 +409,7 @@ private: static const NativePluginDescriptor audiofileDesc = { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, /* hints */ static_cast(NATIVE_PLUGIN_IS_RTSAFE + |NATIVE_PLUGIN_HAS_INLINE_DISPLAY |NATIVE_PLUGIN_HAS_UI |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE |NATIVE_PLUGIN_USES_TIME), diff --git a/source/native-plugins/bigmeter.cpp b/source/native-plugins/bigmeter.cpp index c2c0bbdc0..0ca44aadd 100644 --- a/source/native-plugins/bigmeter.cpp +++ b/source/native-plugins/bigmeter.cpp @@ -176,7 +176,10 @@ protected: } if (needsInlineRender && ! fInlineDisplay.pending) + { + fInlineDisplay.pending = true; hostQueueDrawInlineDisplay(); + } } // ------------------------------------------------------------------- @@ -190,16 +193,22 @@ protected: const size_t stride = width * 4; const size_t dataSize = stride * height; - if (fInlineDisplay.size < dataSize || fInlineDisplay.data == nullptr) - { - fInlineDisplay.size = dataSize; + uchar* data = fInlineDisplay.idisp.data; - delete[] fInlineDisplay.data; - fInlineDisplay.data = new uchar[dataSize]; + if (fInlineDisplay.dataSize < dataSize || data == nullptr) + { + delete[] data; + data = new uchar[dataSize]; + std::memset(data, 0, dataSize); + fInlineDisplay.idisp.data = data; + fInlineDisplay.dataSize = dataSize; } - uchar* const data = fInlineDisplay.data; - std::memset(data, 0, fInlineDisplay.size); + std::memset(data, 0, dataSize); + + fInlineDisplay.idisp.width = static_cast(width); + fInlineDisplay.idisp.height = static_cast(height); + fInlineDisplay.idisp.stride = static_cast(stride); const uint heightValueLeft = static_cast(fInlineDisplay.lastLeft * static_cast(height)); const uint heightValueRight = static_cast(fInlineDisplay.lastRight * static_cast(height)); @@ -273,23 +282,8 @@ protected: data[h * stride + (width - 1) * 4 + 3] = 120; } - static const NativeInlineDisplayImageSurface nidims = { - data, - static_cast(width), - static_cast(height), - static_cast(stride), - }; - - static uint lastWidth = 0; - - if (width != lastWidth) - { - carla_stdout("rendering at %u", width); - lastWidth = width; - } - fInlineDisplay.pending = false; - return &nidims; + return &fInlineDisplay.idisp; } private: @@ -297,25 +291,25 @@ private: float fOutLeft, fOutRight; struct InlineDisplay { - uchar* data; - size_t size; + NativeInlineDisplayImageSurface idisp; + size_t dataSize; float lastLeft; float lastRight; - bool pending; + volatile bool pending; InlineDisplay() - : data(nullptr), - size(0), + : idisp{}, + dataSize(0), lastLeft(0.0f), lastRight(0.0f), pending(false) {} ~InlineDisplay() { - if (data != nullptr) + if (idisp.data != nullptr) { - delete[] data; - data = nullptr; + delete[] idisp.data; + idisp.data = nullptr; } }