mirror of
https://github.com/4sval/FModel.git
synced 2026-08-25 02:44:29 -05:00
Add save audio option to context menus
This commit is contained in:
@@ -114,5 +114,6 @@ public enum EBulkType
|
||||
Textures = 1 << 2,
|
||||
Meshes = 1 << 3,
|
||||
Skeletons = 1 << 4,
|
||||
Animations = 1 << 5
|
||||
Animations = 1 << 5,
|
||||
Audio = 1 << 6
|
||||
}
|
||||
|
||||
@@ -376,6 +376,15 @@
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Save Folder's Packages Audio" Click="OnFolderAudioClick">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="Favorite Directory" Click="OnFavoriteDirectoryClick">
|
||||
<MenuItem.Icon>
|
||||
@@ -608,6 +617,21 @@
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Save Audio" Command="{Binding DataContext.RightClickMenuCommand}">
|
||||
<MenuItem.CommandParameter>
|
||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
||||
<Binding Source="Assets_Save_Audio" />
|
||||
<Binding Path="SelectedItems" />
|
||||
</MultiBinding>
|
||||
</MenuItem.CommandParameter>
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="Copy">
|
||||
<MenuItem.Icon>
|
||||
|
||||
@@ -238,6 +238,19 @@ public partial class MainWindow
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnFolderAudioClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (AssetsFolderName.SelectedItem is TreeItem folder)
|
||||
{
|
||||
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.AudioFolder(cancellationToken, folder); });
|
||||
FLogger.Append(ELog.Information, () =>
|
||||
{
|
||||
FLogger.Text("Successfully saved audio from ", Constants.WHITE);
|
||||
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.ModelDirectory, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFavoriteDirectoryClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (AssetsFolderName.SelectedItem is not TreeItem folder) return;
|
||||
|
||||
@@ -583,6 +583,9 @@ public class CUE4ParseViewModel : ViewModel
|
||||
public void AnimationFolder(CancellationToken cancellationToken, TreeItem folder)
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, EBulkType.Animations | EBulkType.Auto));
|
||||
|
||||
public void AudioFolder(CancellationToken cancellationToken, TreeItem folder)
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, EBulkType.Audio | EBulkType.Auto));
|
||||
|
||||
public void Extract(CancellationToken cancellationToken, GameFile entry, bool addNewTab = false, EBulkType bulk = EBulkType.None)
|
||||
{
|
||||
Log.Information("User DOUBLE-CLICKED to extract '{FullPath}'", entry.Path);
|
||||
@@ -594,6 +597,7 @@ public class CUE4ParseViewModel : ViewModel
|
||||
var updateUi = !HasFlag(bulk, EBulkType.Auto);
|
||||
var saveProperties = HasFlag(bulk, EBulkType.Properties);
|
||||
var saveTextures = HasFlag(bulk, EBulkType.Textures);
|
||||
var saveAudio = HasFlag(bulk, EBulkType.Audio);
|
||||
switch (entry.Extension)
|
||||
{
|
||||
case "uasset":
|
||||
@@ -738,7 +742,7 @@ public class CUE4ParseViewModel : ViewModel
|
||||
var medias = WwiseProvider.ExtractBankSounds(wwise);
|
||||
foreach (var media in medias)
|
||||
{
|
||||
SaveAndPlaySound(media.OutputPath, media.Extension, media.Data);
|
||||
SaveAndPlaySound(media.OutputPath, media.Extension, media.Data, saveAudio);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -753,7 +757,7 @@ public class CUE4ParseViewModel : ViewModel
|
||||
// todo: CSCore.MediaFoundation.MediaFoundationException The byte stream type of the given URL is unsupported. case "aif":
|
||||
{
|
||||
var data = Provider.SaveAsset(entry);
|
||||
SaveAndPlaySound(entry.PathWithoutExtension, entry.Extension, data);
|
||||
SaveAndPlaySound(entry.PathWithoutExtension, entry.Extension, data, saveAudio);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -868,6 +872,7 @@ public class CUE4ParseViewModel : ViewModel
|
||||
var isNone = bulk == EBulkType.None;
|
||||
var updateUi = !HasFlag(bulk, EBulkType.Auto);
|
||||
var saveTextures = HasFlag(bulk, EBulkType.Textures);
|
||||
var saveAudio = HasFlag(bulk, EBulkType.Audio);
|
||||
|
||||
var pointer = new FPackageIndex(pkg, index + 1).ResolvedObject;
|
||||
if (pointer?.Object is null) return false;
|
||||
@@ -938,37 +943,37 @@ public class CUE4ParseViewModel : ViewModel
|
||||
TabControl.SelectedTab.AddImage(sourceFile.SubstringAfterLast('/'), false, bitmap, false, updateUi);
|
||||
return false;
|
||||
}
|
||||
case UAkAudioEvent when isNone && pointer.Object.Value is UAkAudioEvent audioEvent:
|
||||
case UAkAudioEvent when (isNone || saveAudio) && pointer.Object.Value is UAkAudioEvent audioEvent:
|
||||
{
|
||||
var extractedSounds = WwiseProvider.ExtractAudioEventSounds(audioEvent);
|
||||
foreach (var sound in extractedSounds)
|
||||
{
|
||||
SaveAndPlaySound(sound.OutputPath, sound.Extension, sound.Data);
|
||||
SaveAndPlaySound(sound.OutputPath, sound.Extension, sound.Data, saveAudio);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case UFMODEvent when isNone && pointer.Object.Value is UFMODEvent fmodEvent:
|
||||
case UFMODEvent when (isNone || saveAudio) && pointer.Object.Value is UFMODEvent fmodEvent:
|
||||
{
|
||||
var extractedSounds = FmodProvider.ExtractEventSounds(fmodEvent);
|
||||
var directory = Path.GetDirectoryName(fmodEvent.Owner?.Name) ?? "/FMOD/Desktop/";
|
||||
foreach (var sound in extractedSounds)
|
||||
{
|
||||
SaveAndPlaySound(Path.Combine(directory, sound.Name), sound.Extension, sound.Data);
|
||||
SaveAndPlaySound(Path.Combine(directory, sound.Name), sound.Extension, sound.Data, saveAudio);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case UFMODBank when isNone && pointer.Object.Value is UFMODBank fmodBank:
|
||||
case UFMODBank when (isNone || saveAudio) && pointer.Object.Value is UFMODBank fmodBank:
|
||||
{
|
||||
var extractedSounds = FmodProvider.ExtractBankSounds(fmodBank);
|
||||
var directory = Path.GetDirectoryName(fmodBank.Owner?.Name) ?? "/FMOD/Desktop/";
|
||||
foreach (var sound in extractedSounds)
|
||||
{
|
||||
SaveAndPlaySound(Path.Combine(directory, sound.Name), sound.Extension, sound.Data);
|
||||
SaveAndPlaySound(Path.Combine(directory, sound.Name), sound.Extension, sound.Data, saveAudio);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case UAkMediaAssetData when isNone:
|
||||
case USoundWave when isNone:
|
||||
case UAkMediaAssetData when isNone || saveAudio:
|
||||
case USoundWave when isNone || saveAudio:
|
||||
{
|
||||
var shouldDecompress = UserSettings.Default.CompressedAudioMode == ECompressedAudio.PlayDecompressed;
|
||||
pointer.Object.Value.Decode(shouldDecompress, out var audioFormat, out var data);
|
||||
@@ -979,7 +984,7 @@ public class CUE4ParseViewModel : ViewModel
|
||||
return false;
|
||||
}
|
||||
|
||||
SaveAndPlaySound(TabControl.SelectedTab.Entry.PathWithoutExtension.Replace('\\', '/'), audioFormat, data);
|
||||
SaveAndPlaySound(TabControl.SelectedTab.Entry.PathWithoutExtension.Replace('\\', '/'), audioFormat, data, saveAudio);
|
||||
return false;
|
||||
}
|
||||
case UWorld when isNone && UserSettings.Default.PreviewWorlds:
|
||||
@@ -1100,13 +1105,13 @@ public class CUE4ParseViewModel : ViewModel
|
||||
TabControl.SelectedTab.SetDocumentText(cpp, false, false);
|
||||
}
|
||||
|
||||
private void SaveAndPlaySound(string fullPath, string ext, byte[] data)
|
||||
private void SaveAndPlaySound(string fullPath, string ext, byte[] data, bool isBulk)
|
||||
{
|
||||
if (fullPath.StartsWith('/')) fullPath = fullPath[1..];
|
||||
var savedAudioPath = Path.Combine(UserSettings.Default.AudioDirectory,
|
||||
UserSettings.Default.KeepDirectoryStructure ? fullPath : fullPath.SubstringAfterLast('/')).Replace('\\', '/') + $".{ext.ToLowerInvariant()}";
|
||||
|
||||
if (!UserSettings.Default.IsAutoOpenSounds)
|
||||
if (!UserSettings.Default.IsAutoOpenSounds || isBulk)
|
||||
{
|
||||
Directory.CreateDirectory(savedAudioPath.SubstringBeforeLast('/'));
|
||||
using var stream = new FileStream(savedAudioPath, FileMode.Create, FileAccess.Write);
|
||||
@@ -1188,4 +1193,4 @@ public class CUE4ParseViewModel : ViewModel
|
||||
{
|
||||
return (a & b) == b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,14 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, EBulkType.Animations | updateUi);
|
||||
}
|
||||
break;
|
||||
case "Assets_Save_Audio":
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
Thread.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, EBulkType.Audio | updateUi);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Windows;
|
||||
using System.Windows;
|
||||
using AdonisUI.Controls;
|
||||
using FModel.Framework;
|
||||
using FModel.Services;
|
||||
@@ -58,6 +58,12 @@ public class TabCommand : ViewModelCommand<TabItem>
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Animations);
|
||||
});
|
||||
break;
|
||||
case "Asset_Save_Audio":
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Audio);
|
||||
});
|
||||
break;
|
||||
case "Open_Properties":
|
||||
if (tabViewModel.Header == "New Tab" || tabViewModel.Document == null) return;
|
||||
Helper.OpenWindow<AdonisWindow>(tabViewModel.Header + " (Properties)", () =>
|
||||
|
||||
@@ -909,6 +909,15 @@
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Save Audio" Command="{Binding TabCommand}" CommandParameter="Asset_Save_Audio">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="Open Properties" Command="{Binding TabCommand}" CommandParameter="Open_Properties">
|
||||
<MenuItem.Icon>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<adonisControls:AdonisWindow x:Class="FModel.Views.SearchView"
|
||||
<adonisControls:AdonisWindow x:Class="FModel.Views.SearchView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
|
||||
@@ -254,6 +254,21 @@
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Save Audio" Command="{Binding DataContext.RightClickMenuCommand}">
|
||||
<MenuItem.CommandParameter>
|
||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
||||
<Binding Source="Assets_Save_Audio" />
|
||||
<Binding Path="SelectedItems" />
|
||||
</MultiBinding>
|
||||
</MenuItem.CommandParameter>
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="Copy">
|
||||
<MenuItem.Icon>
|
||||
|
||||
Reference in New Issue
Block a user