This commit is contained in:
Armin 2026-08-14 21:48:05 +02:00
commit 831d53380b
4 changed files with 48 additions and 27 deletions

View file

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.22) cmake_minimum_required(VERSION 3.22)
project(Mindball VERSION 1.0.0 LANGUAGES C CXX) project(Mindball VERSION 0.0.5 LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -54,8 +54,8 @@ endif()
juce_add_plugin(Mindball juce_add_plugin(Mindball
PRODUCT_NAME "Mindball" PRODUCT_NAME "Mindball"
VENDOR_NAME "Mindball" VENDOR_NAME "Mindball"
VERSION "1.0.0" VERSION "0.0.5"
DESCRIPTION "Mindball - a tiny, minimal delay plugin" DESCRIPTION "Mindball - a minimalist delay plugin"
FORMATS ${_formats} FORMATS ${_formats}
PLUGIN_MANUFACTURER_CODE Mind PLUGIN_MANUFACTURER_CODE Mind
PLUGIN_CODE Mbll PLUGIN_CODE Mbll
@ -116,7 +116,7 @@ if(Git_FOUND)
endif() endif()
endif() endif()
endif() endif()
string(TIMESTAMP MINDBALL_BUILD_TIME "%Y-%m-%d %H:%M:%S UTC") string(TIMESTAMP MINDBALL_BUILD_TIME "%Y-%m-%d %H:%M:%S")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Source/BuildInfo.h.in configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Source/BuildInfo.h.in
${CMAKE_CURRENT_BINARY_DIR}/buildinfo/BuildInfo.h @ONLY) ${CMAKE_CURRENT_BINARY_DIR}/buildinfo/BuildInfo.h @ONLY)

View file

@ -1,6 +1,6 @@
# Mindball # Mindball
A tiny, minimal stereo delay plugin with a no-frills UI. Feedback echoes, ping-pong A minimalist stereo delay plugin with a no-frills UI. Feedback echoes, ping-pong
and inverting modes, tempo-synced delay time, and an auto-panner - all wrapped in a and inverting modes, tempo-synced delay time, and an auto-panner - all wrapped in a
clean, resizable interface with 20 factory presets. clean, resizable interface with 20 factory presets.

View file

@ -68,7 +68,7 @@ public:
if (branch.isEmpty() || branch == "n/a") if (branch.isEmpty() || branch == "n/a")
branch = "-"; branch = "-";
buildInfo.setText ("Mindball v1.0.0\n" buildInfo.setText ("Mindball v0.0.5\n"
+ hash + " " + branch + dirty + "\n" + hash + " " + branch + dirty + "\n"
+ juce::String (mindball::BuildInfo::buildTime), + juce::String (mindball::BuildInfo::buildTime),
juce::dontSendNotification); juce::dontSendNotification);
@ -88,9 +88,8 @@ public:
void timerCallback() override void timerCallback() override
{ {
const float decay = std::exp (-1.0f / (0.9f * 30.0f)); dryMeter.update (proc.getDryMeterL(), proc.getDryMeterR(), meterDecay);
dryMeter.update (proc.getDryMeterL(), proc.getDryMeterR(), decay); wetMeter.update (proc.getWetMeterL(), proc.getWetMeterR(), meterDecay);
wetMeter.update (proc.getWetMeterL(), proc.getWetMeterR(), decay);
} }
void parameterChanged (const juce::String& paramID, float) override void parameterChanged (const juce::String& paramID, float) override
@ -176,6 +175,8 @@ private:
using SliderAttachment = juce::AudioProcessorValueTreeState::SliderAttachment; using SliderAttachment = juce::AudioProcessorValueTreeState::SliderAttachment;
using ButtonAttachment = juce::AudioProcessorValueTreeState::ButtonAttachment; using ButtonAttachment = juce::AudioProcessorValueTreeState::ButtonAttachment;
static constexpr float meterDecay = 0.9636077f; // exp (-1.0f / (0.9f * 30.0f))
MindballAudioProcessor& proc; MindballAudioProcessor& proc;
static const juce::StringArray syncDivisionNames; static const juce::StringArray syncDivisionNames;

View file

@ -155,18 +155,16 @@ public:
void update (float linL, float linR, float decay) void update (float linL, float linR, float decay)
{ {
levels[0] = linL; const bool changedL = updateChannel (0, linL, decay);
levels[1] = linR; const bool changedR = updateChannel (1, linR, decay);
peaks[0] = std::max (peaks[0] * decay, linL);
peaks[1] = std::max (peaks[1] * decay, linR); if (changedL || changedR)
repaint(); repaint();
} }
void paint (juce::Graphics& g) override void paint (juce::Graphics& g) override
{ {
constexpr int steps = 15; constexpr int steps = 15;
constexpr float dbMin = -30.0f;
constexpr float dbPerStep = 2.0f;
auto b = getLocalBounds().toFloat(); auto b = getLocalBounds().toFloat();
g.setColour (MindballColors::textDim); g.setColour (MindballColors::textDim);
@ -180,32 +178,54 @@ public:
for (int ch = 0; ch < 2; ++ch) for (int ch = 0; ch < 2; ++ch)
{ {
auto row = b.removeFromTop (rowH); auto row = b.removeFromTop (rowH);
const float lin = std::max (0.0f, levels[ch]);
const float db = 20.0f * std::log10 (lin > 0.0f ? lin : 1e-9f);
const int lit = juce::jlimit (0, steps, juce::roundToInt ((db - dbMin) / dbPerStep));
const int pk = juce::jlimit (0, steps, juce::roundToInt ((20.0f * std::log10 (std::max (1e-9f, peaks[ch])) - dbMin) / dbPerStep));
for (int s = 0; s < steps; ++s) for (int s = 0; s < steps; ++s)
{ {
const auto seg = juce::Rectangle<float> (row.getX() + s * (segW + segGap), const auto seg = juce::Rectangle<float> (row.getX() + s * (segW + segGap),
row.getY() + 2.0f, segW, rowH - 4.0f); row.getY() + 2.0f, segW, rowH - 4.0f);
g.setColour (s < lit ? MindballColors::meterGreen : MindballColors::arcBg); g.setColour (s < lit[ch] ? MindballColors::meterGreen : MindballColors::arcBg);
g.fillRoundedRectangle (seg, 1.0f); g.fillRect (seg);
} }
if (pk > lit) if (pk[ch] > 0)
{ {
const auto seg = juce::Rectangle<float> (row.getX() + pk * (segW + segGap), const int peakSeg = juce::jmin (pk[ch], steps - 1);
const auto seg = juce::Rectangle<float> (row.getX() + peakSeg * (segW + segGap),
row.getY() + 2.0f, segW, rowH - 4.0f); row.getY() + 2.0f, segW, rowH - 4.0f);
g.setColour (MindballColors::meterRed); g.setColour (MindballColors::meterRed);
g.fillRoundedRectangle (seg, 1.0f); g.fillRect (seg);
} }
} }
} }
private: private:
bool updateChannel (int ch, float lin, float decay)
{
peaks[ch] = std::max (peaks[ch] * decay, lin);
const int newLit = levelToSteps (lin);
const int newPk = levelToSteps (peaks[ch]);
if (newLit == lit[ch] && newPk == pk[ch])
return false;
lit[ch] = newLit;
pk[ch] = newPk;
return true;
}
static int levelToSteps (float lin)
{
constexpr int steps = 15;
constexpr float dbMin = -30.0f;
constexpr float dbPerStep = 2.0f;
const float db = 20.0f * std::log10 (lin > 0.0f ? lin : 1e-9f);
return juce::jlimit (0, steps, juce::roundToInt ((db - dbMin) / dbPerStep));
}
juce::String name; juce::String name;
float levels[2] = { 0.0f, 0.0f }; int lit[2] = { 0, 0 };
int pk[2] = { 0, 0 };
float peaks[2] = { 0.0f, 0.0f }; float peaks[2] = { 0.0f, 0.0f };
}; };