Skip to content

Commit 570bdd6

Browse files
committed
Add save audio option to context menus
1 parent b51d539 commit 570bdd6

File tree

8 files changed

+98
-17
lines changed

8 files changed

+98
-17
lines changed

FModel/Enums.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,6 @@ public enum EBulkType
114114
Textures = 1 << 2,
115115
Meshes = 1 << 3,
116116
Skeletons = 1 << 4,
117-
Animations = 1 << 5
117+
Animations = 1 << 5,
118+
Audio = 1 << 6
118119
}

FModel/MainWindow.xaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,15 @@
376376
</Viewbox>
377377
</MenuItem.Icon>
378378
</MenuItem>
379+
<MenuItem Header="Save Folder's Packages Audio" Click="OnFolderAudioClick">
380+
<MenuItem.Icon>
381+
<Viewbox Width="16" Height="16">
382+
<Canvas Width="24" Height="24">
383+
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
384+
</Canvas>
385+
</Viewbox>
386+
</MenuItem.Icon>
387+
</MenuItem>
379388
<Separator />
380389
<MenuItem Header="Favorite Directory" Click="OnFavoriteDirectoryClick">
381390
<MenuItem.Icon>
@@ -608,6 +617,21 @@
608617
</Viewbox>
609618
</MenuItem.Icon>
610619
</MenuItem>
620+
<MenuItem Header="Save Audio" Command="{Binding DataContext.RightClickMenuCommand}">
621+
<MenuItem.CommandParameter>
622+
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
623+
<Binding Source="Assets_Save_Audio" />
624+
<Binding Path="SelectedItems" />
625+
</MultiBinding>
626+
</MenuItem.CommandParameter>
627+
<MenuItem.Icon>
628+
<Viewbox Width="16" Height="16">
629+
<Canvas Width="24" Height="24">
630+
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
631+
</Canvas>
632+
</Viewbox>
633+
</MenuItem.Icon>
634+
</MenuItem>
611635
<Separator />
612636
<MenuItem Header="Copy">
613637
<MenuItem.Icon>

FModel/MainWindow.xaml.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,19 @@ private async void OnFolderAnimationClick(object sender, RoutedEventArgs e)
238238
}
239239
}
240240

241+
private async void OnFolderAudioClick(object sender, RoutedEventArgs e)
242+
{
243+
if (AssetsFolderName.SelectedItem is TreeItem folder)
244+
{
245+
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.AudioFolder(cancellationToken, folder); });
246+
FLogger.Append(ELog.Information, () =>
247+
{
248+
FLogger.Text("Successfully saved audio from ", Constants.WHITE);
249+
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.ModelDirectory, true);
250+
});
251+
}
252+
}
253+
241254
private void OnFavoriteDirectoryClick(object sender, RoutedEventArgs e)
242255
{
243256
if (AssetsFolderName.SelectedItem is not TreeItem folder) return;

FModel/ViewModels/CUE4ParseViewModel.cs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,9 @@ public void ModelFolder(CancellationToken cancellationToken, TreeItem folder)
583583
public void AnimationFolder(CancellationToken cancellationToken, TreeItem folder)
584584
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, EBulkType.Animations | EBulkType.Auto));
585585

586+
public void AudioFolder(CancellationToken cancellationToken, TreeItem folder)
587+
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, EBulkType.Audio | EBulkType.Auto));
588+
586589
public void Extract(CancellationToken cancellationToken, GameFile entry, bool addNewTab = false, EBulkType bulk = EBulkType.None)
587590
{
588591
Log.Information("User DOUBLE-CLICKED to extract '{FullPath}'", entry.Path);
@@ -594,6 +597,7 @@ public void Extract(CancellationToken cancellationToken, GameFile entry, bool ad
594597
var updateUi = !HasFlag(bulk, EBulkType.Auto);
595598
var saveProperties = HasFlag(bulk, EBulkType.Properties);
596599
var saveTextures = HasFlag(bulk, EBulkType.Textures);
600+
var saveAudio = HasFlag(bulk, EBulkType.Audio);
597601
switch (entry.Extension)
598602
{
599603
case "uasset":
@@ -738,7 +742,7 @@ public void Extract(CancellationToken cancellationToken, GameFile entry, bool ad
738742
var medias = WwiseProvider.ExtractBankSounds(wwise);
739743
foreach (var media in medias)
740744
{
741-
SaveAndPlaySound(media.OutputPath, media.Extension, media.Data);
745+
SaveAndPlaySound(media.OutputPath, media.Extension, media.Data, saveAudio);
742746
}
743747

744748
break;
@@ -753,7 +757,7 @@ public void Extract(CancellationToken cancellationToken, GameFile entry, bool ad
753757
// todo: CSCore.MediaFoundation.MediaFoundationException The byte stream type of the given URL is unsupported. case "aif":
754758
{
755759
var data = Provider.SaveAsset(entry);
756-
SaveAndPlaySound(entry.PathWithoutExtension, entry.Extension, data);
760+
SaveAndPlaySound(entry.PathWithoutExtension, entry.Extension, data, saveAudio);
757761

758762
break;
759763
}
@@ -868,6 +872,7 @@ public void ExtractAndScroll(CancellationToken cancellationToken, string fullPat
868872
var isNone = bulk == EBulkType.None;
869873
var updateUi = !HasFlag(bulk, EBulkType.Auto);
870874
var saveTextures = HasFlag(bulk, EBulkType.Textures);
875+
var saveAudio = HasFlag(bulk, EBulkType.Audio);
871876

872877
var pointer = new FPackageIndex(pkg, index + 1).ResolvedObject;
873878
if (pointer?.Object is null) return false;
@@ -938,37 +943,37 @@ public void ExtractAndScroll(CancellationToken cancellationToken, string fullPat
938943
TabControl.SelectedTab.AddImage(sourceFile.SubstringAfterLast('/'), false, bitmap, false, updateUi);
939944
return false;
940945
}
941-
case UAkAudioEvent when isNone && pointer.Object.Value is UAkAudioEvent audioEvent:
946+
case UAkAudioEvent when (isNone || saveAudio) && pointer.Object.Value is UAkAudioEvent audioEvent:
942947
{
943948
var extractedSounds = WwiseProvider.ExtractAudioEventSounds(audioEvent);
944949
foreach (var sound in extractedSounds)
945950
{
946-
SaveAndPlaySound(sound.OutputPath, sound.Extension, sound.Data);
951+
SaveAndPlaySound(sound.OutputPath, sound.Extension, sound.Data, saveAudio);
947952
}
948953
return false;
949954
}
950-
case UFMODEvent when isNone && pointer.Object.Value is UFMODEvent fmodEvent:
955+
case UFMODEvent when (isNone || saveAudio) && pointer.Object.Value is UFMODEvent fmodEvent:
951956
{
952957
var extractedSounds = FmodProvider.ExtractEventSounds(fmodEvent);
953958
var directory = Path.GetDirectoryName(fmodEvent.Owner?.Name) ?? "/FMOD/Desktop/";
954959
foreach (var sound in extractedSounds)
955960
{
956-
SaveAndPlaySound(Path.Combine(directory, sound.Name), sound.Extension, sound.Data);
961+
SaveAndPlaySound(Path.Combine(directory, sound.Name), sound.Extension, sound.Data, saveAudio);
957962
}
958963
return false;
959964
}
960-
case UFMODBank when isNone && pointer.Object.Value is UFMODBank fmodBank:
965+
case UFMODBank when (isNone || saveAudio) && pointer.Object.Value is UFMODBank fmodBank:
961966
{
962967
var extractedSounds = FmodProvider.ExtractBankSounds(fmodBank);
963968
var directory = Path.GetDirectoryName(fmodBank.Owner?.Name) ?? "/FMOD/Desktop/";
964969
foreach (var sound in extractedSounds)
965970
{
966-
SaveAndPlaySound(Path.Combine(directory, sound.Name), sound.Extension, sound.Data);
971+
SaveAndPlaySound(Path.Combine(directory, sound.Name), sound.Extension, sound.Data, saveAudio);
967972
}
968973
return false;
969974
}
970-
case UAkMediaAssetData when isNone:
971-
case USoundWave when isNone:
975+
case UAkMediaAssetData when isNone || saveAudio:
976+
case USoundWave when isNone || saveAudio:
972977
{
973978
var shouldDecompress = UserSettings.Default.CompressedAudioMode == ECompressedAudio.PlayDecompressed;
974979
pointer.Object.Value.Decode(shouldDecompress, out var audioFormat, out var data);
@@ -979,7 +984,7 @@ public void ExtractAndScroll(CancellationToken cancellationToken, string fullPat
979984
return false;
980985
}
981986

982-
SaveAndPlaySound(TabControl.SelectedTab.Entry.PathWithoutExtension.Replace('\\', '/'), audioFormat, data);
987+
SaveAndPlaySound(TabControl.SelectedTab.Entry.PathWithoutExtension.Replace('\\', '/'), audioFormat, data, saveAudio);
983988
return false;
984989
}
985990
case UWorld when isNone && UserSettings.Default.PreviewWorlds:
@@ -1100,13 +1105,13 @@ public void Decompile(GameFile entry)
11001105
TabControl.SelectedTab.SetDocumentText(cpp, false, false);
11011106
}
11021107

1103-
private void SaveAndPlaySound(string fullPath, string ext, byte[] data)
1108+
private void SaveAndPlaySound(string fullPath, string ext, byte[] data, bool isBulk)
11041109
{
11051110
if (fullPath.StartsWith('/')) fullPath = fullPath[1..];
11061111
var savedAudioPath = Path.Combine(UserSettings.Default.AudioDirectory,
11071112
UserSettings.Default.KeepDirectoryStructure ? fullPath : fullPath.SubstringAfterLast('/')).Replace('\\', '/') + $".{ext.ToLowerInvariant()}";
11081113

1109-
if (!UserSettings.Default.IsAutoOpenSounds)
1114+
if (!UserSettings.Default.IsAutoOpenSounds || isBulk)
11101115
{
11111116
Directory.CreateDirectory(savedAudioPath.SubstringBeforeLast('/'));
11121117
using var stream = new FileStream(savedAudioPath, FileMode.Create, FileAccess.Write);
@@ -1188,4 +1193,4 @@ private static bool HasFlag(EBulkType a, EBulkType b)
11881193
{
11891194
return (a & b) == b;
11901195
}
1191-
}
1196+
}

FModel/ViewModels/Commands/RightClickMenuCommand.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ await _threadWorkerView.Begin(cancellationToken =>
9292
contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, EBulkType.Animations | updateUi);
9393
}
9494
break;
95+
case "Assets_Save_Audio":
96+
foreach (var entry in entries)
97+
{
98+
Thread.Yield();
99+
cancellationToken.ThrowIfCancellationRequested();
100+
contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, EBulkType.Audio | updateUi);
101+
}
102+
break;
95103
}
96104
});
97105
}

FModel/ViewModels/Commands/TabCommand.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Windows;
1+
using System.Windows;
22
using AdonisUI.Controls;
33
using FModel.Framework;
44
using FModel.Services;
@@ -58,6 +58,12 @@ await _threadWorkerView.Begin(cancellationToken =>
5858
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Animations);
5959
});
6060
break;
61+
case "Asset_Save_Audio":
62+
await _threadWorkerView.Begin(cancellationToken =>
63+
{
64+
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Audio);
65+
});
66+
break;
6167
case "Open_Properties":
6268
if (tabViewModel.Header == "New Tab" || tabViewModel.Document == null) return;
6369
Helper.OpenWindow<AdonisWindow>(tabViewModel.Header + " (Properties)", () =>

FModel/Views/Resources/Resources.xaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,15 @@
909909
</Viewbox>
910910
</MenuItem.Icon>
911911
</MenuItem>
912+
<MenuItem Header="Save Audio" Command="{Binding TabCommand}" CommandParameter="Asset_Save_Audio">
913+
<MenuItem.Icon>
914+
<Viewbox Width="16" Height="16">
915+
<Canvas Width="24" Height="24">
916+
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
917+
</Canvas>
918+
</Viewbox>
919+
</MenuItem.Icon>
920+
</MenuItem>
912921
<Separator />
913922
<MenuItem Header="Open Properties" Command="{Binding TabCommand}" CommandParameter="Open_Properties">
914923
<MenuItem.Icon>

FModel/Views/SearchView.xaml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<adonisControls:AdonisWindow x:Class="FModel.Views.SearchView"
1+
<adonisControls:AdonisWindow x:Class="FModel.Views.SearchView"
22
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
@@ -254,6 +254,21 @@
254254
</Viewbox>
255255
</MenuItem.Icon>
256256
</MenuItem>
257+
<MenuItem Header="Save Audio" Command="{Binding DataContext.RightClickMenuCommand}">
258+
<MenuItem.CommandParameter>
259+
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
260+
<Binding Source="Assets_Save_Audio" />
261+
<Binding Path="SelectedItems" />
262+
</MultiBinding>
263+
</MenuItem.CommandParameter>
264+
<MenuItem.Icon>
265+
<Viewbox Width="16" Height="16">
266+
<Canvas Width="24" Height="24">
267+
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
268+
</Canvas>
269+
</Viewbox>
270+
</MenuItem.Icon>
271+
</MenuItem>
257272
<Separator />
258273
<MenuItem Header="Copy">
259274
<MenuItem.Icon>

0 commit comments

Comments
 (0)