44 */
55
66let ctx : AudioContext | null = null ;
7+ let muted = false ;
78
8- function getCtx ( ) : AudioContext {
9+ export function isMuted ( ) : boolean {
10+ return muted ;
11+ }
12+
13+ export function setMuted ( m : boolean ) {
14+ muted = m ;
15+ // Persist preference
16+ try { localStorage . setItem ( 'delta-v-mute' , m ? '1' : '0' ) ; } catch { }
17+ }
18+
19+ function getCtx ( ) : AudioContext | null {
20+ if ( muted ) return null ;
921 if ( ! ctx ) {
1022 ctx = new AudioContext ( ) ;
1123 }
@@ -14,6 +26,12 @@ function getCtx(): AudioContext {
1426
1527/** Resume audio context after user gesture (required by browsers). */
1628export function initAudio ( ) {
29+ // Load saved mute preference
30+ try {
31+ const saved = localStorage . getItem ( 'delta-v-mute' ) ;
32+ if ( saved === '1' ) muted = true ;
33+ } catch { }
34+
1735 const resume = ( ) => {
1836 if ( ctx ?. state === 'suspended' ) {
1937 ctx . resume ( ) ;
@@ -28,6 +46,7 @@ export function initAudio() {
2846/** Short blip for UI interactions (button clicks, selections). */
2947export function playSelect ( ) {
3048 const ac = getCtx ( ) ;
49+ if ( ! ac ) return ;
3150 const osc = ac . createOscillator ( ) ;
3251 const gain = ac . createGain ( ) ;
3352 osc . connect ( gain ) ;
@@ -44,6 +63,7 @@ export function playSelect() {
4463/** Confirm/submit sound — ascending tone. */
4564export function playConfirm ( ) {
4665 const ac = getCtx ( ) ;
66+ if ( ! ac ) return ;
4767 const osc = ac . createOscillator ( ) ;
4868 const gain = ac . createGain ( ) ;
4969 osc . connect ( gain ) ;
@@ -60,6 +80,7 @@ export function playConfirm() {
6080/** Thruster sound for movement. */
6181export function playThrust ( ) {
6282 const ac = getCtx ( ) ;
83+ if ( ! ac ) return ;
6384 const bufSize = ac . sampleRate * 0.3 ;
6485 const buf = ac . createBuffer ( 1 , bufSize , ac . sampleRate ) ;
6586 const data = buf . getChannelData ( 0 ) ;
@@ -84,6 +105,7 @@ export function playThrust() {
84105/** Laser/beam sound for combat. */
85106export function playCombat ( ) {
86107 const ac = getCtx ( ) ;
108+ if ( ! ac ) return ;
87109 const osc = ac . createOscillator ( ) ;
88110 const gain = ac . createGain ( ) ;
89111 osc . connect ( gain ) ;
@@ -100,6 +122,7 @@ export function playCombat() {
100122/** Explosion sound for ship destruction or detonation. */
101123export function playExplosion ( ) {
102124 const ac = getCtx ( ) ;
125+ if ( ! ac ) return ;
103126 const bufSize = ac . sampleRate * 0.5 ;
104127 const buf = ac . createBuffer ( 1 , bufSize , ac . sampleRate ) ;
105128 const data = buf . getChannelData ( 0 ) ;
@@ -124,6 +147,7 @@ export function playExplosion() {
124147/** Alert tone for phase changes. */
125148export function playPhaseChange ( ) {
126149 const ac = getCtx ( ) ;
150+ if ( ! ac ) return ;
127151 const osc = ac . createOscillator ( ) ;
128152 const gain = ac . createGain ( ) ;
129153 osc . connect ( gain ) ;
@@ -150,6 +174,7 @@ export function playPhaseChange() {
150174/** Victory fanfare. */
151175export function playVictory ( ) {
152176 const ac = getCtx ( ) ;
177+ if ( ! ac ) return ;
153178 const notes = [ 523 , 659 , 784 , 1047 ] ; // C5, E5, G5, C6
154179 notes . forEach ( ( freq , i ) => {
155180 const osc = ac . createOscillator ( ) ;
@@ -169,6 +194,7 @@ export function playVictory() {
169194/** Defeat sound. */
170195export function playDefeat ( ) {
171196 const ac = getCtx ( ) ;
197+ if ( ! ac ) return ;
172198 const notes = [ 400 , 350 , 300 , 200 ] ; // Descending
173199 notes . forEach ( ( freq , i ) => {
174200 const osc = ac . createOscillator ( ) ;
0 commit comments