@@ -291,6 +291,10 @@ private async Task<int> CalculateTotalSmartAsync(IEnumerable<FileSystemNodeModel
291291 {
292292 if ( eventNode . IsTechnicalNode ) continue ;
293293 soundsCount += eventNode . Sounds . Count ;
294+ foreach ( var containerNode in eventNode . Containers )
295+ {
296+ soundsCount += containerNode . Sounds . Count ;
297+ }
294298 }
295299
296300 count += ( soundsCount > 0 ) ? soundsCount : 1 ;
@@ -318,7 +322,7 @@ private int CountSoundsInAudioTree(IEnumerable<FileSystemNodeModel> nodes)
318322 foreach ( var node in nodes )
319323 {
320324 if ( node . Type == NodeType . WemFile ) count ++ ;
321- else count += CountSoundsInAudioTree ( node . Children ) ;
325+ else if ( node . Children != null ) count += CountSoundsInAudioTree ( node . Children ) ;
322326 }
323327 return count ;
324328 }
@@ -358,14 +362,25 @@ private async Task ExportSmartAsync(FileSystemNodeModel node, string destination
358362 string eventPath = Path . Combine ( destinationPath , PathUtils . SanitizeName ( node . Name ) ) ;
359363 _directoriesCreator . CreateDirectory ( eventPath ) ;
360364
361- foreach ( var soundNode in node . Children )
365+ async Task ExportSoundsRecursiveAsync ( FileSystemNodeModel parentNode , string currentPath )
362366 {
363- cancellationToken . ThrowIfCancellationRequested ( ) ;
364- if ( soundNode . Type == NodeType . WemFile )
367+ foreach ( var childNode in parentNode . Children )
365368 {
366- await HandleWemFileAsync ( soundNode , eventPath , cancellationToken , onFileSavedCallback ) ;
369+ cancellationToken . ThrowIfCancellationRequested ( ) ;
370+ if ( childNode . Type == NodeType . WemFile )
371+ {
372+ await HandleWemFileAsync ( childNode , currentPath , cancellationToken , onFileSavedCallback ) ;
373+ }
374+ else if ( childNode . Type == NodeType . VirtualDirectory )
375+ {
376+ string subFolderPath = Path . Combine ( currentPath , PathUtils . SanitizeName ( childNode . Name ) ) ;
377+ _directoriesCreator . CreateDirectory ( subFolderPath ) ;
378+ await ExportSoundsRecursiveAsync ( childNode , subFolderPath ) ;
379+ }
367380 }
368381 }
382+
383+ await ExportSoundsRecursiveAsync ( node , eventPath ) ;
369384 return ;
370385 }
371386
@@ -560,36 +575,53 @@ private async Task HandleAudioBankFile(FileSystemNodeModel node, string destinat
560575 else
561576 audioTree = _audioBankService . ParseGenericAudioBank ( wpkData , audioBnkFileData , eventsData ) ;
562577
578+ async Task ExportSoundNodeAsync ( WemFileNode soundNode , string eventPath )
579+ {
580+ byte [ ] wemData = null ;
581+ if ( soundNode . Source == AudioSourceType . Wpk && wpkData != null )
582+ {
583+ wemData = wpkData . AsSpan ( ( int ) soundNode . Offset , ( int ) soundNode . Size ) . ToArray ( ) ;
584+ }
585+ else if ( audioBnkFileData != null )
586+ {
587+ wemData = audioBnkFileData . AsSpan ( ( int ) soundNode . Offset , ( int ) soundNode . Size ) . ToArray ( ) ;
588+ }
589+
590+ if ( wemData != null )
591+ {
592+ var format = _appSettings . AudioExportFormat ;
593+ byte [ ] convertedData = await _audioConversionService . ConvertAudioToFormatAsync ( wemData , ".wem" , format , cancellationToken ) ;
594+ if ( convertedData != null )
595+ {
596+ string extension = format switch { AudioExportFormat . Wav => ".wav" , AudioExportFormat . Mp3 => ".mp3" , _ => ".ogg" } ;
597+ string filePath = PathUtils . GetUniqueFilePath ( eventPath , Path . ChangeExtension ( soundNode . Name , extension ) ) ;
598+ await File . WriteAllBytesAsync ( filePath , convertedData , cancellationToken ) ;
599+ onFileSavedCallback ? . Invoke ( filePath ) ;
600+ }
601+ }
602+ }
603+
563604 foreach ( var eventNode in audioTree )
564605 {
565606 if ( eventNode . IsTechnicalNode ) continue ;
566607
567608 string eventPath = Path . Combine ( audioBankPath , PathUtils . SanitizeName ( eventNode . Name ) ) ;
568609 _directoriesCreator . CreateDirectory ( eventPath ) ;
569610
611+ // Export root-level sounds
570612 foreach ( var soundNode in eventNode . Sounds )
571613 {
572- byte [ ] wemData = null ;
573- if ( soundNode . Source == AudioSourceType . Wpk && wpkData != null )
574- {
575- wemData = wpkData . AsSpan ( ( int ) soundNode . Offset , ( int ) soundNode . Size ) . ToArray ( ) ;
576- }
577- else if ( audioBnkFileData != null )
578- {
579- wemData = audioBnkFileData . AsSpan ( ( int ) soundNode . Offset , ( int ) soundNode . Size ) . ToArray ( ) ;
580- }
614+ await ExportSoundNodeAsync ( soundNode , eventPath ) ;
615+ }
581616
582- if ( wemData != null )
617+ // Export sounds in sub-containers (families)
618+ foreach ( var containerNode in eventNode . Containers )
619+ {
620+ string containerPath = Path . Combine ( eventPath , PathUtils . SanitizeName ( containerNode . Name ) ) ;
621+ _directoriesCreator . CreateDirectory ( containerPath ) ;
622+ foreach ( var soundNode in containerNode . Sounds )
583623 {
584- var format = _appSettings . AudioExportFormat ;
585- byte [ ] convertedData = await _audioConversionService . ConvertAudioToFormatAsync ( wemData , ".wem" , format , cancellationToken ) ;
586- if ( convertedData != null )
587- {
588- string extension = format switch { AudioExportFormat . Wav => ".wav" , AudioExportFormat . Mp3 => ".mp3" , _ => ".ogg" } ;
589- string filePath = PathUtils . GetUniqueFilePath ( eventPath , Path . ChangeExtension ( soundNode . Name , extension ) ) ;
590- await File . WriteAllBytesAsync ( filePath , convertedData , cancellationToken ) ;
591- onFileSavedCallback ? . Invoke ( filePath ) ;
592- }
624+ await ExportSoundNodeAsync ( soundNode , containerPath ) ;
593625 }
594626 }
595627 }
0 commit comments