Skip to content

Commit

Permalink
Implemented Audio Export
Browse files Browse the repository at this point in the history
  • Loading branch information
EX3exp committed Sep 23, 2024
1 parent 10f65d3 commit ba3f4fa
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 21 deletions.
5 changes: 5 additions & 0 deletions Mirivoice/Assets/Lang/strings-en-US.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@

<system:String x:Key="menu.files.export">Export</system:String>
<system:String x:Key="menu.files.export.perLine">Export audios per lines (.wav)</system:String>
<system:String x:Key="menu.files.export.failed">
An Error occured during export.
Please Check Log file for more informations.</system:String>
<system:String x:Key="menu.files.export.perLine.desc">Select Directory to export</system:String>
<system:String x:Key="menu.files.export.merged">Export audio merged (.wav)</system:String>
<system:String x:Key="menu.files.export.merged.desc">Set Filename to export</system:String>


<!--project...-->
Expand Down
2 changes: 1 addition & 1 deletion Mirivoice/Mirivoice.Core/Format/RecentFIles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void AddRecentFile(string filePath, MainViewModel v)
{
Files.RemoveAt(10);
}

Files.Reverse();
Save();
UpdateUI(v);
}
Expand Down
108 changes: 95 additions & 13 deletions Mirivoice/Mirivoice.Core/Managers/AudioManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ public string GetUniqueCachePath()
return cacheFilePath;
}

string SetSuffixToUnique(string filepath, int suffix)
{
if (File.Exists(filepath))
{
string dirPath = Path.GetDirectoryName(filepath);
string changedPath = Path.Combine(dirPath, Path.GetFileNameWithoutExtension(filepath) + $"({suffix})" + Path.GetExtension(filepath));
if (File.Exists(changedPath))
{
return SetSuffixToUnique(filepath, suffix + 1); // recursive call
}
else return changedPath;
}
else return filepath;
}

List<string> GetAllCacheFiles()
{
return Directory.GetFiles(MainManager.Instance.PathM.CachePath, "*.wav").ToList();
Expand All @@ -53,29 +68,37 @@ List<string> GetAllCacheFiles()
private double OffsetBeforePlay;
private int offset = 0;
private int currentLine;
public async void PlayAllCacheFiles(int startIndex)
/// <summary>
/// Note that startIndex is same as lineNo (starts from 1, not 0)
/// </summary>
/// <param name="startIndex"></param>
/// <param name="exportOnlyAndDoNotPlay"></param>
/// <param name="exportPerTrack"></param>
/// <param name="fileName"></param>
/// <param name="DirPath"></param>
public async void PlayAllCacheFiles(int startIndex, bool exportOnlyAndDoNotPlay=false, bool exportPerTrack=true, string fileName="", string DirPath="")
{
if ( _waveOut != null && _waveOut.PlaybackState == PlaybackState.Paused)
{
_waveOut.Play();
return;
}
List<string> caches = new List<string>();
ObservableCollection<LineBoxView> lineBoxViews = v.LineBoxCollection;

int index = 0;
v.SingleTextBoxEditorEnabled = false;
v.CurrentEdit.IsEnabled = false;
var tasks = new List<Task>();

caches.Clear();
for (int i = startIndex - 1; i < lineBoxViews.Count; ++i)
for (int i = startIndex - 1; i < v.LineBoxCollection.Count; ++i)
{
caches.Add(lineBoxViews[i].CurrentCacheName);
caches.Add(v.LineBoxCollection[i].CurrentCacheName);
}

for (int i = 0; i < lineBoxViews.Count; ++i)
v.MainWindowGetInput = false;
for (int i = 0; i < v.LineBoxCollection.Count; ++i)
{
LineBoxView l = lineBoxViews[i];
LineBoxView l = v.LineBoxCollection[i];

if (i < startIndex - 1)
{
Expand All @@ -85,7 +108,7 @@ public async void PlayAllCacheFiles(int startIndex)

if (i == startIndex - 1)
{
l.v.StartProgress(0, lineBoxViews.Count - startIndex + 1, "Inference");
l.v.StartProgress(0, v.LineBoxCollection.Count - startIndex + 1, "Inference");
}

Log.Debug($"[Generating Cache]");
Expand All @@ -103,15 +126,74 @@ public async void PlayAllCacheFiles(int startIndex)
await Task.WhenAll(tasks);

// Finalize progress
if (lineBoxViews.Count - 1 >= startIndex - 1)
if (v.LineBoxCollection.Count - 1 >= startIndex - 1)
{
lineBoxViews[lineBoxViews.Count - 1].v.EndProgress();
v.LineBoxCollection[v.LineBoxCollection.Count - 1].v.EndProgress();
}

if (exportOnlyAndDoNotPlay)
{

Log.Information("Exporting cache files.");
if (exportPerTrack)
{
// export per track
int no = 1;
foreach (string cacheName in caches)
{
string exportPath = Path.Combine(DirPath, $"{no}_{fileName}.wav");

exportPath = SetSuffixToUnique(exportPath, 1);
Log.Debug($"Exporting {cacheName} to {exportPath}");
// resample to 48000kHz
using (var reader = new AudioFileReader(cacheName))
{
using (var resampler = new MediaFoundationResampler(reader, new WaveFormat(48000, reader.WaveFormat.Channels)))
{
resampler.ResamplerQuality = 60;

WaveFileWriter.CreateWaveFile(exportPath, resampler);
}
}
no++;
}

}
else
{
// export mixdown
string exportPath = Path.Combine(DirPath, $"{fileName}"); // no suffix, because file extension is already included
exportPath = SetSuffixToUnique(exportPath, 1);
using (var outputWaveFile = new WaveFileWriter(exportPath, new WaveFormat(48000, 1)))
{
foreach (string cacheName in caches)
{
using (var reader = new AudioFileReader(cacheName))
{
// resample to 48000kHz
using (var resampler = new MediaFoundationResampler(reader, new WaveFormat(48000, reader.WaveFormat.Channels)))
{
resampler.ResamplerQuality = 60;
byte[] buffer = new byte[8192];
int read;
while ((read = resampler
.Read(buffer, 0, buffer.Length)) > 0)
{
outputWaveFile.Write(buffer, 0, read);
}

}
}
}
}
}
v.MainWindowGetInput = true;
return;
}


foreach (string cacheName in caches)
{
Log.Debug($"[Playing Cache] {cacheName}");
//Log.Debug($"[Playing Cache] {cacheName}");
var reader = new AudioFileReader(cacheName);
_audioReaders.Add(reader);

Expand All @@ -124,7 +206,7 @@ public async void PlayAllCacheFiles(int startIndex)
SelectedBtnIndexBeforePlay = startIndex - 1;
v.LinesViewerOffset = new Avalonia.Vector(0, 104 * (startIndex - 1));
currentLine = startIndex - 1;
v.MainWindowGetInput = false;

PlayNextFile();
}

Expand Down
83 changes: 79 additions & 4 deletions Mirivoice/ViewModels/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ public class MainViewModel : VoicerSelectingViewModelBase
MimeTypes = new[] { "MiriVoiceProject/*" }
};


public static FilePickerFileType MiriVoiceExportAudio { get; } = new("Wav File")
{
Patterns = new[] { "*.wav" }
};
Mrp initMrp;
Version version = System.Reflection.Assembly.GetEntryAssembly()?.GetName().Version;

Expand Down Expand Up @@ -387,15 +390,87 @@ public void OnPlayButtonClick()
Log.Information("Pause Button Clicked");
}
}

public void OnExportAudioPerLineClick()
IStorageFolder LastExportPath;
public async void OnExportAudioPerLineClick()
{
if (LineBoxCollection.Count == 0)
{
return;
}

var topLevel = TopLevel.GetTopLevel(mainWindow);
if (LastExportPath is null)
{
LastExportPath = topLevel.StorageProvider.TryGetWellKnownFolderAsync(WellKnownFolder.Downloads).Result;
}
var directory = await topLevel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
Title = (string)mainWindow.FindResource("menu.files.export.perLine.desc"),
AllowMultiple = false,
SuggestedStartLocation = LastExportPath,
SuggestedFileName = LastExportPath.Path.LocalPath

});



if (directory.Count > 0)
{
if (directory[0] is null)
{
return;
}
string path = directory[0].Path.LocalPath;
if (path == string.Empty)
{
path = LastExportPath.Path.LocalPath;
}
try
{
Log.Information($"Exporting audio per line to {path}");
string filename = CurrentProjectPath.Split(System.IO.Path.PathSeparator).Last();
MainManager.Instance.AudioM.PlayAllCacheFiles(1, true, true, System.IO.Path.GetFileNameWithoutExtension(filename) , path);
LastExportPath = directory[0];
}
catch (Exception e)
{
Log.Error($"[Failed to export audio per line]{e.ToString}: {e.Message} \n>> traceback: \n\t{e.StackTrace}");
var res = await ShowConfirmWindow("menu.files.export.failed");
}
}


}

public void OnExportAudioMergedClick()
public async void OnExportAudioMergedClick()
{
if (LineBoxCollection.Count == 0)
{
return;
}
var topLevel = TopLevel.GetTopLevel(mainWindow);
var file = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
{
Title = (string)mainWindow.FindResource("menu.files.export.merged.desc"),
DefaultExtension = "wav",
ShowOverwritePrompt = true,
FileTypeChoices = new[] { MiriVoiceExportAudio },
SuggestedFileName = System.IO.Path.GetFileNameWithoutExtension(CurrentProjectPath) + ".wav"
});

if (file is not null)
{
string path = file.Path.LocalPath;
try
{
MainManager.Instance.AudioM.PlayAllCacheFiles(1, true, false, System.IO.Path.GetFileNameWithoutExtension(path), System.IO.Path.GetDirectoryName(path) );
}
catch (Exception e)
{
Log.Error($"[Failed to export audio merged]{e.ToString}: {e.Message} \n>> traceback: \n\t{e.StackTrace}");
var res = await ShowConfirmWindow("menu.files.export.failed");
}
}
}

public void OnGlobalSettingButtonClick()
Expand Down
1 change: 1 addition & 0 deletions Mirivoice/Views/GlobalSettingWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
xmlns:vm="using:Mirivoice.ViewModels"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="Mirivoice.GlobalSettingWindow"
Icon="/Assets/mirivoice-logo.ico"

WindowStartupLocation="CenterScreen"
MinWidth="500" MinHeight="600" Width="500" Height="450"
Expand Down
6 changes: 3 additions & 3 deletions Mirivoice/Views/SingleLineEditorView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ private async void LineTextChanged(object sender, TextChangedEventArgs e)
string textChanged = textBox.Text;
if (l is null)
{
Log.Debug("LineBoxView is null");
//Log.Debug("LineBoxView is null");
return;
}
if (l.viewModel.LineText == textBox.Text)
{
Log.Debug($"No need to phonemize ---- SingleLineTBox '{textBox.Text}' // linePreview '{l.viewModel.LineText}' "); ;
//Log.Debug($"No need to phonemize ---- SingleLineTBox '{textBox.Text}' // linePreview '{l.viewModel.LineText}' "); ;
l.DeActivatePhonemizer = true; // no need to phonemize
}
else
{
Log.Debug($"SingleLineTBox '{textBox.Text}' // linePreview '{l.viewModel.LineText}' "); ;
//Log.Debug($"SingleLineTBox '{textBox.Text}' // linePreview '{l.viewModel.LineText}' "); ;
l.viewModel.LineText = textChanged;
l.DeActivatePhonemizer = false;
if (FirstUpdate)
Expand Down

0 comments on commit ba3f4fa

Please sign in to comment.