@@ -31,6 +31,10 @@ function exportFileName(name) {
3131 return `${ baseName || "audio-sfx" } -tool-state.json` ;
3232}
3333
34+ function activeSoundFromToolState ( toolState ) {
35+ return toolState . payload . sounds . find ( ( entry ) => entry . id === toolState . payload . activeSoundId ) ?. sound || null ;
36+ }
37+
3438export class AudioSfxPlaygroundV2App {
3539 constructor ( { accordions, actionNav, audioEngine, controls, inspector, preview, serializer, shell, statusLog, tileList, windowRef = window } ) {
3640 this . accordions = accordions ;
@@ -89,7 +93,6 @@ export class AudioSfxPlaygroundV2App {
8993 }
9094 const toolState = this . serializer . createToolState ( {
9195 activeSoundId : this . activeSoundId ,
92- sound : validation . value ,
9396 soundEntries : this . soundEntries
9497 } ) ;
9598 this . controls . showMessage ( "Ready to audition." , false ) ;
@@ -104,19 +107,43 @@ export class AudioSfxPlaygroundV2App {
104107 this . actionNav . setToolActionsEnabled ( false ) ;
105108 return ;
106109 }
107- this . preview . render ( toolState . payload . sound ) ;
110+ this . preview . render ( validation . value ) ;
108111 this . inspector . showObject ( toolState ) ;
109112 this . actionNav . setToolActionsEnabled ( true ) ;
110113 }
111114
112115 handleEditorChange ( ) {
113- if ( this . activeSoundId ) {
114- this . activeSoundId = "" ;
116+ const validation = this . controls . validate ( ) ;
117+ if ( validation . valid && this . updateActiveSound ( validation . value ) ) {
115118 this . renderSoundList ( ) ;
116119 }
117120 this . refreshPreview ( ) ;
118121 }
119122
123+ createSoundEntry ( sound ) {
124+ const entry = {
125+ id : `sfx-${ this . nextSoundNumber } ` ,
126+ sound : cloneSound ( sound )
127+ } ;
128+ this . nextSoundNumber += 1 ;
129+ this . soundEntries . push ( entry ) ;
130+ this . activeSoundId = entry . id ;
131+ return entry ;
132+ }
133+
134+ updateActiveSound ( sound ) {
135+ const entry = this . soundEntries . find ( ( candidate ) => candidate . id === this . activeSoundId ) ;
136+ if ( ! entry ) {
137+ return null ;
138+ }
139+ entry . sound = cloneSound ( sound ) ;
140+ return entry ;
141+ }
142+
143+ ensureActiveSoundEntry ( sound ) {
144+ return this . updateActiveSound ( sound ) || this . createSoundEntry ( sound ) ;
145+ }
146+
120147 addCurrentSound ( ) {
121148 const validation = this . controls . validate ( ) ;
122149 if ( ! validation . valid ) {
@@ -125,13 +152,7 @@ export class AudioSfxPlaygroundV2App {
125152 return ;
126153 }
127154
128- const entry = {
129- id : `sfx-${ this . nextSoundNumber } ` ,
130- sound : cloneSound ( validation . value )
131- } ;
132- this . nextSoundNumber += 1 ;
133- this . soundEntries . push ( entry ) ;
134- this . activeSoundId = entry . id ;
155+ const entry = this . createSoundEntry ( validation . value ) ;
135156 this . renderSoundList ( ) ;
136157 this . refreshPreview ( ) ;
137158 this . statusLog . write ( `Added ${ entry . sound . name } .` ) ;
@@ -159,15 +180,15 @@ export class AudioSfxPlaygroundV2App {
159180 }
160181
161182 async play ( ) {
162- const { toolState , validation } = this . currentToolState ( ) ;
183+ const { validation } = this . currentToolState ( ) ;
163184 if ( ! validation . valid ) {
164185 this . statusLog . error ( validation . message ) ;
165186 this . refreshPreview ( ) ;
166187 return ;
167188 }
168189 try {
169- await this . audioEngine . play ( toolState . payload . sound ) ;
170- this . statusLog . write ( `Played ${ toolState . payload . name } .` ) ;
190+ await this . audioEngine . play ( validation . value ) ;
191+ this . statusLog . write ( `Played ${ validation . value . name } .` ) ;
171192 } catch ( error ) {
172193 this . statusLog . error ( `Audio playback failed: ${ error . message } ` ) ;
173194 }
@@ -182,17 +203,27 @@ export class AudioSfxPlaygroundV2App {
182203 return ;
183204 }
184205 const [ entry ] = this . soundEntries . splice ( entryIndex , 1 ) ;
185- this . activeSoundId = "" ;
206+ const nextEntry = this . soundEntries [ Math . min ( entryIndex , this . soundEntries . length - 1 ) ] || null ;
207+ this . activeSoundId = nextEntry ?. id || "" ;
208+ if ( nextEntry ) {
209+ this . controls . loadSound ( nextEntry . sound ) ;
210+ }
186211 this . renderSoundList ( ) ;
187212 this . refreshPreview ( ) ;
188213 this . statusLog . write ( `Deleted ${ entry . sound . name } .` ) ;
189214 }
190215
191216 exportPayload ( ) {
192- const { toolState , validation } = this . currentToolState ( ) ;
217+ const validation = this . controls . validate ( ) ;
193218 if ( ! validation . valid ) {
194219 return { valid : false , message : validation . message , toolState : null , json : "" } ;
195220 }
221+ this . ensureActiveSoundEntry ( validation . value ) ;
222+ this . renderSoundList ( ) ;
223+ const toolState = this . serializer . createToolState ( {
224+ activeSoundId : this . activeSoundId ,
225+ soundEntries : this . soundEntries
226+ } ) ;
196227
197228 const exportValidation = this . serializer . readToolState ( toolState ) ;
198229 if ( ! exportValidation . valid ) {
@@ -217,7 +248,7 @@ export class AudioSfxPlaygroundV2App {
217248 try {
218249 this . downloadJson ( exportResult ) ;
219250 this . inspector . showObject ( exportResult . toolState ) ;
220- this . statusLog . write ( `Exported JSON for ${ exportResult . toolState . payload . name } .` ) ;
251+ this . statusLog . write ( `Exported JSON for ${ activeSoundFromToolState ( exportResult . toolState ) ?. name || "audio-sfx" } .` ) ;
221252 } catch ( error ) {
222253 this . statusLog . error ( `Export JSON failed: ${ error . message } ` ) ;
223254 }
@@ -282,7 +313,7 @@ export class AudioSfxPlaygroundV2App {
282313 const url = urlApi . createObjectURL ( blob ) ;
283314 const link = documentRef . createElement ( "a" ) ;
284315 link . href = url ;
285- link . download = exportFileName ( exportResult . toolState . payload . name ) ;
316+ link . download = exportFileName ( activeSoundFromToolState ( exportResult . toolState ) ?. name || "audio-sfx" ) ;
286317 try {
287318 documentRef . body . append ( link ) ;
288319 link . click ( ) ;
0 commit comments