From 7fd6b904f6819abb49dad9f6e18576e814adbee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Sun, 8 Mar 2026 14:47:27 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20[sound-logo]=20=EC=98=A4=EB=94=94?= =?UTF-8?q?=EC=98=A4=20=ED=95=A9=EC=84=B1=20=EC=8B=9C=20=ED=81=B4=EB=A6=AC?= =?UTF-8?q?=ED=95=91=20=EC=86=8C=EC=9D=8C=20=EB=B0=A9=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DynamicsCompressor 마스터 노드 추가 (threshold:-6dB, ratio:12) - 모든 오디오 출력(시퀀서/음성/BGM)을 컴프레서 경유로 변경 - 다중 소스 합산 시 진폭 초과로 인한 디지털 클리핑 방지 --- resources/views/rd/sound-logo/index.blade.php | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/resources/views/rd/sound-logo/index.blade.php b/resources/views/rd/sound-logo/index.blade.php index 77de33bb..6eac4f14 100644 --- a/resources/views/rd/sound-logo/index.blade.php +++ b/resources/views/rd/sound-logo/index.blade.php @@ -1383,10 +1383,26 @@ function soundLogo() { }, getAudioCtx() { - if (!this.audioCtx) this.audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + if (!this.audioCtx) { + this.audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + // 마스터 컴프레서 (클리핑 방지) + const comp = this.audioCtx.createDynamicsCompressor(); + comp.threshold.value = -6; + comp.knee.value = 10; + comp.ratio.value = 12; + comp.attack.value = 0.003; + comp.release.value = 0.15; + comp.connect(this.audioCtx.destination); + this._masterNode = comp; + } return this.audioCtx; }, + getMasterNode() { + const ctx = this.getAudioCtx(); + return this._masterNode || ctx.destination; + }, + // ===== Note helpers ===== getNoteLabel(n) { if (n.type === 'rest') return '쉼표'; @@ -1461,7 +1477,7 @@ function soundLogo() { gain.gain.setValueAtTime(vel * s, startTime + dur); gain.gain.exponentialRampToValueAtTime(0.001, startTime + dur + r); - osc.connect(gain).connect(ctx.destination); + osc.connect(gain).connect(this.getMasterNode()); osc.start(startTime); osc.stop(startTime + dur + r + 0.05); }); @@ -1501,7 +1517,7 @@ function soundLogo() { voiceSrc.buffer = this.voiceBuffer; const voiceGain = ctx.createGain(); voiceGain.gain.value = this.voiceVolume; - voiceSrc.connect(voiceGain).connect(ctx.destination); + voiceSrc.connect(voiceGain).connect(this.getMasterNode()); voiceSrc.start(startTime + this.voiceDelay); } @@ -1511,7 +1527,7 @@ function soundLogo() { bgmSrc.buffer = this.bgmBuffer; const bgmGain = ctx.createGain(); bgmGain.gain.value = this.bgmVolume; - bgmSrc.connect(bgmGain).connect(ctx.destination); + bgmSrc.connect(bgmGain).connect(this.getMasterNode()); bgmSrc.start(startTime); } @@ -1532,6 +1548,7 @@ function soundLogo() { if (this.audioCtx) { this.audioCtx.close(); this.audioCtx = null; + this._masterNode = null; } this.isPlaying = false; this.playingIdx = -1; @@ -1765,7 +1782,7 @@ function soundLogo() { src.buffer = this.voiceBuffer; const gain = ctx.createGain(); gain.gain.value = this.voiceVolume; - src.connect(gain).connect(ctx.destination); + src.connect(gain).connect(this.getMasterNode()); src.start(); }, @@ -2010,7 +2027,7 @@ function soundLogo() { src.buffer = this.bgmBuffer; const gain = ctx.createGain(); gain.gain.value = this.bgmVolume; - src.connect(gain).connect(ctx.destination); + src.connect(gain).connect(this.getMasterNode()); src.start(); },