From 508dcb4c7a87f849cce3aa960692ef25d72dce10 Mon Sep 17 00:00:00 2001 From: Masusder <59669685+Masusder@users.noreply.github.com> Date: Sun, 8 Feb 2026 12:49:50 +0100 Subject: [PATCH] Wwise media assets + .adx fallback --- CUE4Parse | 2 +- FModel/ViewModels/AudioPlayerViewModel.cs | 10 +++++++ FModel/ViewModels/CUE4ParseViewModel.cs | 36 ++++++++++++++++++++++- FModel/ViewModels/GameFileViewModel.cs | 6 ++-- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 4935ec79..ad9836e6 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 4935ec79a1d2c801b0735d84cb42322475231359 +Subproject commit ad9836e6bc106bedfd525d1a63c46e297f42388c diff --git a/FModel/ViewModels/AudioPlayerViewModel.cs b/FModel/ViewModels/AudioPlayerViewModel.cs index 9ffada58..edd717b4 100644 --- a/FModel/ViewModels/AudioPlayerViewModel.cs +++ b/FModel/ViewModels/AudioPlayerViewModel.cs @@ -617,6 +617,16 @@ public class AudioPlayerViewModel : ViewModel, ISource, IDisposable _ => throw new NotSupportedException() }; + if (wavData.Length is 0) + { + if (TryConvert(out var wavFilePathFallback)) + { + var newAudioFallback = new AudioFile(SelectedAudioFile.Id, new FileInfo(wavFilePathFallback)); + Replace(newAudioFallback); + return true; + } + } + string wavFilePath = Path.Combine( UserSettings.Default.AudioDirectory, SelectedAudioFile.FilePath.TrimStart('/')); diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index b4db2ad5..77910234 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -1108,7 +1108,7 @@ public class CUE4ParseViewModel : ViewModel TabControl.SelectedTab.AddImage(sourceFile.SubstringAfterLast('/'), false, bitmap, false, updateUi); return false; } - // The Dark Pictures Anthology + // Supermassive Games (for example - The Dark Pictures Anthology: House of Ashes etc.) case UExternalSource when (isNone || saveAudio) && pointer.Object.Value is UExternalSource externalSource: { var audioName = Path.GetFileNameWithoutExtension(externalSource.ExternalSourcePath); @@ -1166,6 +1166,10 @@ public class CUE4ParseViewModel : ViewModel case UAkMediaAssetData when isNone || saveAudio: case USoundWave when isNone || saveAudio: { + // If UAkMediaAsset exists in the same package it should be used to handle the audio instead (because it contains actual audio name) + if (pointer.Object.Value is UAkMediaAssetData dataObj && dataObj.Outer is UAkMediaAsset) + return false; + var shouldDecompress = UserSettings.Default.CompressedAudioMode == ECompressedAudio.PlayDecompressed; pointer.Object.Value.Decode(shouldDecompress, out var audioFormat, out var data); var hasAf = !string.IsNullOrEmpty(audioFormat); @@ -1178,6 +1182,36 @@ public class CUE4ParseViewModel : ViewModel SaveAndPlaySound(TabControl.SelectedTab.Entry.PathWithoutExtension.Replace('\\', '/'), audioFormat, data, saveAudio); return false; } + case UAkMediaAsset when (isNone || saveAudio) && pointer.Object.Value is UAkMediaAsset akMediaAsset: + { + var audioName = akMediaAsset.MediaName; + if (akMediaAsset.CurrentMediaAssetData?.TryLoad(out var akMediaAssetData) is true) + { + var shouldDecompress = UserSettings.Default.CompressedAudioMode is ECompressedAudio.PlayDecompressed; + akMediaAssetData.Decode(shouldDecompress, out var audioFormat, out var data); + + SaveAndPlaySound(audioName, audioFormat, data, saveAudio); + } + return false; + } + case UAkAudioEventData when (isNone || saveAudio) && pointer.Object.Value is UAkAudioEventData akAudioEventData: + { + var shouldDecompress = UserSettings.Default.CompressedAudioMode is ECompressedAudio.PlayDecompressed; + foreach (var mediaIndex in akAudioEventData.MediaList) + { + if (mediaIndex.TryLoad(out var akMediaAsset)) + { + if (akMediaAsset.CurrentMediaAssetData?.TryLoad(out var akMediaAssetData) is true) + { + var audioName = akMediaAsset.MediaName ?? $"{akAudioEventData.Outer.Name} ({akMediaAsset.ID})"; + akMediaAssetData.Decode(shouldDecompress, out var audioFormat, out var data); + + SaveAndPlaySound(audioName, audioFormat, data, saveAudio); + } + } + } + return false; + } case UWorld when isNone && UserSettings.Default.PreviewWorlds: case UBlueprintGeneratedClass when isNone && UserSettings.Default.PreviewWorlds && TabControl.SelectedTab.ParentExportType switch { diff --git a/FModel/ViewModels/GameFileViewModel.cs b/FModel/ViewModels/GameFileViewModel.cs index 3e97b075..f7c6d30d 100644 --- a/FModel/ViewModels/GameFileViewModel.cs +++ b/FModel/ViewModels/GameFileViewModel.cs @@ -235,12 +235,14 @@ public class GameFileViewModel(GameFile asset) : ViewModel UObjectRedirector => (EAssetCategory.ObjectRedirector, EBulkType.None), UPhysicalMaterial => (EAssetCategory.PhysicalMaterial, EBulkType.None), - USoundAtomCue or UAkAudioEvent or USoundCue or UFMODEvent => (EAssetCategory.AudioEvent, EBulkType.Audio), + USoundAtomCue or UAkAudioEvent or USoundCue or UFMODEvent + or UAkAssetData or UAkAssetPlatformData => (EAssetCategory.AudioEvent, EBulkType.Audio), UFMODBank or UAkAudioBank or UAtomWaveBank or UAkInitBank => (EAssetCategory.SoundBank, EBulkType.Audio), UWwiseAssetLibrary or USoundBase or UAkMediaAssetData or UAtomCueSheet - or USoundAtomCueSheet or UAkAudioType or UExternalSource or UExternalSourceBank => (EAssetCategory.Audio, EBulkType.Audio), + or USoundAtomCueSheet or UAkAudioType or UExternalSource or UExternalSourceBank + or UAkMediaAsset => (EAssetCategory.Audio, EBulkType.Audio), UFileMediaSource => (EAssetCategory.Video, EBulkType.None), UFont or UFontFace or USMGLocaleFontUMG => (EAssetCategory.Font, EBulkType.None),