diff --git a/dist/SciFiAmbientDisplay_v4.html b/dist/SciFiAmbientDisplay_v4.html
index 8a92537..9bc3f70 100644
--- a/dist/SciFiAmbientDisplay_v4.html
+++ b/dist/SciFiAmbientDisplay_v4.html
@@ -3560,6 +3560,23 @@ class TelemetrySynth {
];
}
+ /**
+ * Lazily creates the telemetry gain node so soundboard one-shots (LCARS
+ * chirps, era-specific one-shots) work standalone even before the ambient
+ * bed has been engaged via start(). Mirrors the init() self-heal pattern
+ * used by ExpandedSciFiAudioSynth and WhoniverseAudioSynth. start() below
+ * still unconditionally rebuilds the node on every engage so a fresh
+ * preset's volume takes effect immediately; this only fills the gap
+ * before that has ever happened.
+ */
+ init() {
+ if (this.gainNode || !this.am.ctx) return;
+ const ctx = this.am.ctx;
+ this.gainNode = ctx.createGain();
+ this.gainNode.gain.setValueAtTime(this.isMuted ? 0 : this.params.volume, ctx.currentTime);
+ this.gainNode.connect(this.am.compressor);
+ }
+
start() {
this.stop();
const ctx = this.am.ctx;
@@ -3663,6 +3680,7 @@ class TelemetrySynth {
* Star Trek Comm Badge Confirmation Chirp
*/
synthesizeCommBadge() {
+ this.init();
if (window.expandedAudio) {
window.expandedAudio.synthesizeCommBadge();
return;
@@ -3690,6 +3708,7 @@ class TelemetrySynth {
* TNG/Voyager Single LCARS Touch Tone (Soft sine with gentle attack and rapid exponential decay)
*/
synthesizeLCARSSingleChirp(pitch = null) {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -3725,6 +3744,7 @@ class TelemetrySynth {
* TNG LCARS Double Chirp (Iconic standard confirmation tone)
*/
synthesizeLCARSDoubleChirp() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx) return;
const idx = Math.floor(Math.random() * (this.lcarsPitches.length - 2));
@@ -3741,6 +3761,7 @@ class TelemetrySynth {
* TNG LCARS Multi-Tone Data Acknowledgment Sequence
*/
synthesizeLCARSSequence() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx) return;
const notes = [
@@ -3760,6 +3781,7 @@ class TelemetrySynth {
* High-tech Sensor Sweep Tone (Voyager/TNG Long-Range Sensor telemetry)
*/
synthesizeSensorSweep() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -3790,6 +3812,7 @@ class TelemetrySynth {
* Two detuned square/triangle oscillators modulated by high-speed vibrato LFO
*/
synthesizeTOSWarble() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -3846,6 +3869,7 @@ class TelemetrySynth {
* TOS Mechanical Relay Solenoid Click
*/
synthesizeTOSRelayClick() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -3872,6 +3896,7 @@ class TelemetrySynth {
* DS9 / Cardassian Cavernous Sensor Tone (Resonant metallic ring)
*/
synthesizeCardassianSensor() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -3906,6 +3931,7 @@ class TelemetrySynth {
* NX-01 Industrial Hydraulic Relay Click
*/
synthesizeNXRelay() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -3932,6 +3958,7 @@ class TelemetrySynth {
* NX-01 Indicator Beep (Early 22nd century industrial tone)
*/
synthesizeNXIndicatorBeep() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -3959,6 +3986,7 @@ class TelemetrySynth {
* Iconic TNG 2-Tone Door Chime ("Come in")
*/
synthesizeDoorChime() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -4005,6 +4033,7 @@ class TelemetrySynth {
* the single scheduler timeout can never orphan nodes.
*/
synthesizeWhoMechanicalTelemetry_() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -4088,6 +4117,7 @@ class TelemetrySynth {
* One 0.5-1.1 s phrase of 2-4 events on absolute ctx time.
*/
synthesizeBioshipOrganicTelemetry_() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -4198,6 +4228,7 @@ class TelemetrySynth {
* occasional late sub-cluster to mimic an unsteady clock.
*/
synthesizeBelterJuryRiggedTelemetry_() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
diff --git a/js/audio.js b/js/audio.js
index d39ee79..e8668ec 100644
--- a/js/audio.js
+++ b/js/audio.js
@@ -826,6 +826,23 @@ class TelemetrySynth {
];
}
+ /**
+ * Lazily creates the telemetry gain node so soundboard one-shots (LCARS
+ * chirps, era-specific one-shots) work standalone even before the ambient
+ * bed has been engaged via start(). Mirrors the init() self-heal pattern
+ * used by ExpandedSciFiAudioSynth and WhoniverseAudioSynth. start() below
+ * still unconditionally rebuilds the node on every engage so a fresh
+ * preset's volume takes effect immediately; this only fills the gap
+ * before that has ever happened.
+ */
+ init() {
+ if (this.gainNode || !this.am.ctx) return;
+ const ctx = this.am.ctx;
+ this.gainNode = ctx.createGain();
+ this.gainNode.gain.setValueAtTime(this.isMuted ? 0 : this.params.volume, ctx.currentTime);
+ this.gainNode.connect(this.am.compressor);
+ }
+
start() {
this.stop();
const ctx = this.am.ctx;
@@ -929,6 +946,7 @@ class TelemetrySynth {
* Star Trek Comm Badge Confirmation Chirp
*/
synthesizeCommBadge() {
+ this.init();
if (window.expandedAudio) {
window.expandedAudio.synthesizeCommBadge();
return;
@@ -956,6 +974,7 @@ class TelemetrySynth {
* TNG/Voyager Single LCARS Touch Tone (Soft sine with gentle attack and rapid exponential decay)
*/
synthesizeLCARSSingleChirp(pitch = null) {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -991,6 +1010,7 @@ class TelemetrySynth {
* TNG LCARS Double Chirp (Iconic standard confirmation tone)
*/
synthesizeLCARSDoubleChirp() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx) return;
const idx = Math.floor(Math.random() * (this.lcarsPitches.length - 2));
@@ -1007,6 +1027,7 @@ class TelemetrySynth {
* TNG LCARS Multi-Tone Data Acknowledgment Sequence
*/
synthesizeLCARSSequence() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx) return;
const notes = [
@@ -1026,6 +1047,7 @@ class TelemetrySynth {
* High-tech Sensor Sweep Tone (Voyager/TNG Long-Range Sensor telemetry)
*/
synthesizeSensorSweep() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -1056,6 +1078,7 @@ class TelemetrySynth {
* Two detuned square/triangle oscillators modulated by high-speed vibrato LFO
*/
synthesizeTOSWarble() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -1112,6 +1135,7 @@ class TelemetrySynth {
* TOS Mechanical Relay Solenoid Click
*/
synthesizeTOSRelayClick() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -1138,6 +1162,7 @@ class TelemetrySynth {
* DS9 / Cardassian Cavernous Sensor Tone (Resonant metallic ring)
*/
synthesizeCardassianSensor() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -1172,6 +1197,7 @@ class TelemetrySynth {
* NX-01 Industrial Hydraulic Relay Click
*/
synthesizeNXRelay() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -1198,6 +1224,7 @@ class TelemetrySynth {
* NX-01 Indicator Beep (Early 22nd century industrial tone)
*/
synthesizeNXIndicatorBeep() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -1225,6 +1252,7 @@ class TelemetrySynth {
* Iconic TNG 2-Tone Door Chime ("Come in")
*/
synthesizeDoorChime() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -1271,6 +1299,7 @@ class TelemetrySynth {
* the single scheduler timeout can never orphan nodes.
*/
synthesizeWhoMechanicalTelemetry_() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -1354,6 +1383,7 @@ class TelemetrySynth {
* One 0.5-1.1 s phrase of 2-4 events on absolute ctx time.
*/
synthesizeBioshipOrganicTelemetry_() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;
@@ -1464,6 +1494,7 @@ class TelemetrySynth {
* occasional late sub-cluster to mimic an unsteady clock.
*/
synthesizeBelterJuryRiggedTelemetry_() {
+ this.init();
const ctx = this.am.ctx;
if (!ctx || !this.gainNode) return;