From 720ceb50c2ca11ea5d7dafeff61a11a83b514253 Mon Sep 17 00:00:00 2001 From: suplstfdo Date: Sat, 11 Jul 2026 14:50:56 +0200 Subject: [PATCH 1/2] Add opt-in blackout while no music is playing Adds a global "Blackout on Silence" toggle to the main control window, below the Next Effect button. When enabled, the stage fades to black within one second after the input level stayed below the minimum level threshold for a 1.5s grace period, and resumes as soon as music is audible again. The toggle is off by default, so existing behaviour is unchanged, and it is persisted through the regular settings save/load. The effect list and its per-effect RND/settings columns move down to make room for the toggle, and the window grows slightly so all entries still fit. --- MusicBeam/Effect.pde | 2 +- MusicBeam/MusicBeam.pde | 28 ++++++++++++++++++++++++---- MusicBeam/Stage.pde | 15 ++++++++++++++- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/MusicBeam/Effect.pde b/MusicBeam/Effect.pde index 4468f4a..a923299 100644 --- a/MusicBeam/Effect.pde +++ b/MusicBeam/Effect.pde @@ -37,7 +37,7 @@ public abstract class Effect stg = controller.stage; frameRate = stg.frameRate; - int posy = 115+(i*50); + int posy = 170+(i*50); controlGroup = cp5.addGroup(getName()+"SettingsGroup").hide().setPosition(10,195).setWidth(395).setHeight(30); controlGroup.disableCollapse(); diff --git a/MusicBeam/MusicBeam.pde b/MusicBeam/MusicBeam.pde index 346739f..69b4be3 100644 --- a/MusicBeam/MusicBeam.pde +++ b/MusicBeam/MusicBeam.pde @@ -34,16 +34,18 @@ Effect[] effectArray; DropdownList displays; -Toggle projectorToggle, randomToggle; +Toggle projectorToggle, randomToggle, blackoutOnSilenceToggle; Slider randomTimeSlider, beatDelaySlider, minLevelSlider; Button nextButton; RadioButton activeEffect, activeSetting; float randomTimer = 0; +int lastAudibleMillis = 0; + int randomEffect = 0; int width = 775; -int height = 670; +int height = 725; float maxLevel = 0; float goalMaxLevel=0; @@ -235,8 +237,11 @@ void initRandomControls() { nextButton = cp5.addButton("next").setSize(350, 45).setPosition(415, 60); nextButton.getCaptionLabel().set("Next Effect").align(ControlP5.CENTER, ControlP5.CENTER); - activeEffect = cp5.addRadioButton("activeEffects").setPosition(415, 115).setSize(250, 45).setItemsPerRow(1).setSpacingRow(5).setNoneSelectedAllowed(true); - activeSetting = cp5.addRadioButton("activeSettings").setPosition(720, 115).setSize(45, 45).setItemsPerRow(1).setSpacingRow(5); + blackoutOnSilenceToggle = cp5.addToggle("blackoutOnSilence").setSize(350, 45).setPosition(415, 110); + blackoutOnSilenceToggle.getCaptionLabel().set("Blackout on Silence").align(ControlP5.CENTER, ControlP5.CENTER); + + activeEffect = cp5.addRadioButton("activeEffects").setPosition(415, 170).setSize(250, 45).setItemsPerRow(1).setSpacingRow(5).setNoneSelectedAllowed(true); + activeSetting = cp5.addRadioButton("activeSettings").setPosition(720, 170).setSize(45, 45).setItemsPerRow(1).setSpacingRow(5); } void initEffects() @@ -272,6 +277,9 @@ void beatDetect() bdFreq.setSensitivity(int(beatDelaySlider.getValue())); bdSound.detect(in.mix); bdFreq.detect(in.mix); + + if (getLevel()>minLevelSlider.getValue()) + lastAudibleMillis = millis(); } void checkForUpdate() @@ -338,6 +346,18 @@ float getLevel() return in.mix.level(); } +// 1 while audible (or toggle off); after a 1.5s silence grace period, +// fades to 0 over the next second so the stage dims to black. +float silenceFade() +{ + if (!blackoutOnSilenceToggle.getState()) + return 1; + int quiet = millis()-lastAudibleMillis; + if (quiet <= 1500) + return 1; + return max(0, 1 - (quiet-1500)/1000.0); +} + private boolean hasEnoughScreenDevices() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); //<>// //<>// diff --git a/MusicBeam/Stage.pde b/MusicBeam/Stage.pde index b4d99d1..dd779d7 100644 --- a/MusicBeam/Stage.pde +++ b/MusicBeam/Stage.pde @@ -21,7 +21,7 @@ public class Stage extends PApplet { } public void setup() { - colorMode(HSB, 360, 100, 100); + colorMode(HSB, 360, 100, 100, 100); try { blendMode(ADD); } catch (Exception e) { @@ -41,9 +41,22 @@ public class Stage extends PApplet { } translate(width/2, height/2); + float fade = ctrl.silenceFade(); + if (fade <= 0) + return; for (int i = 0; i < effectArray.length; i++) if (effectArray[i].isActive()) effectArray[i].refresh(); + + if (fade < 1) { + // additive blending cannot darken, so switch to normal blending + // for a translucent black overlay while fading out + blendMode(BLEND); + noStroke(); + fill(0, 0, 0, (1-fade)*100); + rect(-width/2, -height/2, width, height); + blendMode(ADD); + } } public int getMaxRadius(){ From 81faf41086edb725f61adcfc311e18c07838dcf1 Mon Sep 17 00:00:00 2001 From: suplstfdo Date: Wed, 15 Jul 2026 18:57:24 +0200 Subject: [PATCH 2/2] Remove early returns --- MusicBeam/MusicBeam.pde | 14 ++++++++------ MusicBeam/Stage.pde | 26 +++++++++++++------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/MusicBeam/MusicBeam.pde b/MusicBeam/MusicBeam.pde index 69b4be3..74047fb 100644 --- a/MusicBeam/MusicBeam.pde +++ b/MusicBeam/MusicBeam.pde @@ -350,12 +350,14 @@ float getLevel() // fades to 0 over the next second so the stage dims to black. float silenceFade() { - if (!blackoutOnSilenceToggle.getState()) - return 1; - int quiet = millis()-lastAudibleMillis; - if (quiet <= 1500) - return 1; - return max(0, 1 - (quiet-1500)/1000.0); + float fade = 1; + if (blackoutOnSilenceToggle.getState()) + { + int quiet = millis()-lastAudibleMillis; + if (quiet > 1500) + fade = max(0, 1 - (quiet-1500)/1000.0); + } + return fade; } private boolean hasEnoughScreenDevices() diff --git a/MusicBeam/Stage.pde b/MusicBeam/Stage.pde index dd779d7..657d7a1 100644 --- a/MusicBeam/Stage.pde +++ b/MusicBeam/Stage.pde @@ -42,20 +42,20 @@ public class Stage extends PApplet { translate(width/2, height/2); float fade = ctrl.silenceFade(); - if (fade <= 0) - return; - for (int i = 0; i < effectArray.length; i++) - if (effectArray[i].isActive()) - effectArray[i].refresh(); + if (fade > 0) { + for (int i = 0; i < effectArray.length; i++) + if (effectArray[i].isActive()) + effectArray[i].refresh(); - if (fade < 1) { - // additive blending cannot darken, so switch to normal blending - // for a translucent black overlay while fading out - blendMode(BLEND); - noStroke(); - fill(0, 0, 0, (1-fade)*100); - rect(-width/2, -height/2, width, height); - blendMode(ADD); + if (fade < 1) { + // additive blending cannot darken, so switch to normal blending + // for a translucent black overlay while fading out + blendMode(BLEND); + noStroke(); + fill(0, 0, 0, (1-fade)*100); + rect(-width/2, -height/2, width, height); + blendMode(ADD); + } } }