Skip to content

Commit f09a482

Browse files
Stop music before generating PCM files
1 parent 45aa571 commit f09a482

10 files changed

+161
-145
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace MSUScripter.Models;
2+
3+
public class GeneratePcmFileResponse(bool successful, bool generatedPcmFile, string? message, string? outputPath)
4+
{
5+
public bool Successful => successful;
6+
public bool GeneratedPcmFile => generatedPcmFile;
7+
public string? Message => message;
8+
public string? OutputPath => outputPath;
9+
}

MSUScripter/Services/AudioAnalysisService.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public async Task AnalyzePcmFile(MsuProject project, AudioAnalysisSongViewModel
6161
if (project.BasicInfo.IsMsuPcmProject && song.OriginalViewModel != null && song.OriginalViewModel.HasFiles() && (song.OriginalViewModel.HasChangesSince(song.OriginalViewModel.LastGeneratedDate) || !File.Exists(song.Path)))
6262
{
6363
logger.LogInformation("PCM file {File} out of date, regenerating", song.Path);
64-
if (!GeneratePcmFile(project, song.OriginalViewModel))
64+
if (!await GeneratePcmFile(project, song.OriginalViewModel))
6565
{
6666
song.WarningMessage = "Could not generate new PCM file";
6767
}
@@ -72,23 +72,23 @@ public async Task AnalyzePcmFile(MsuProject project, AudioAnalysisSongViewModel
7272
logger.LogInformation("Analysis for pcm file {File} complete", song.Path);
7373
}
7474

75-
private bool GeneratePcmFile(MsuProject project, MsuSongInfoViewModel songModel)
75+
private async Task<bool> GeneratePcmFile(MsuProject project, MsuSongInfoViewModel songModel)
7676
{
7777
var song = new MsuSongInfo();
7878
converterService.ConvertViewModel(songModel, song);
7979
converterService.ConvertViewModel(songModel.MsuPcmInfo, song.MsuPcmInfo);
80-
msuPcmService.CreatePcm(false, project, song, out var message, out var generated);
81-
if (!generated)
80+
var response = await msuPcmService.CreatePcm(false, project, song);
81+
if (!response.GeneratedPcmFile)
8282
{
83-
logger.LogInformation("PCM file {File} failed to regenerate: {Error}", song.OutputPath, message);
83+
logger.LogInformation("PCM file {File} failed to regenerate: {Error}", song.OutputPath, response.Message);
8484
}
8585
else
8686
{
8787
songModel.LastGeneratedDate = DateTime.Now;
8888
logger.LogInformation("PCM file {File} regenerated successfully", song.OutputPath);
8989
}
9090

91-
return generated;
91+
return response.GeneratedPcmFile;
9292
}
9393

9494
public int GetAudioSampleRate(string? path)

MSUScripter/Services/ControlServices/AddSongWindowService.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public async Task PlaySong(bool fromEnd)
8585
return;
8686
}
8787

88-
var outputPath = CreateTempPcm();
88+
var outputPath = await CreateTempPcm();
8989

9090
if (string.IsNullOrEmpty(outputPath))
9191
{
@@ -111,11 +111,13 @@ public void UpdateFromPyMusicLooper(PyMusicLooperResultViewModel? result)
111111
_model.TrimEnd = result.LoopEnd;
112112
}
113113

114-
private string? CreateTempPcm()
114+
private async Task<string?> CreateTempPcm()
115115
{
116-
msuPcmService.CreateTempPcm(false, _model.MsuProject, _model.FilePath, out var outputPath, out _,
117-
out var generated, _model.LoopPoint, _model.TrimEnd, _model.Normalization ?? _model.MsuProjectViewModel.BasicInfo.Normalization, _model.TrimStart);
118-
return generated ? outputPath : null;
116+
var response = await msuPcmService.CreateTempPcm(false, _model.MsuProject, _model.FilePath, _model.LoopPoint,
117+
_model.TrimEnd, _model.Normalization ?? _model.MsuProjectViewModel.BasicInfo.Normalization,
118+
_model.TrimStart);
119+
120+
return response.GeneratedPcmFile ? response.OutputPath : null;
119121
}
120122

121123
public async Task<MsuSongInfoViewModel?> AddSongToProject(AddSongWindow parent)
@@ -126,19 +128,20 @@ public void UpdateFromPyMusicLooper(PyMusicLooperResultViewModel? result)
126128
}
127129

128130
var track = _model.SelectedTrack;
129-
130-
var successful = msuPcmService.CreateTempPcm(true, _model.MsuProject, _model.FilePath, out var tempPcmPath, out var message,
131-
out var generated, _model.LoopPoint, _model.TrimEnd, _model.Normalization ?? _model.MsuProjectViewModel.BasicInfo.Normalization, _model.TrimStart);
132131

133-
if (!generated)
132+
var response = await msuPcmService.CreateTempPcm(true, _model.MsuProject, _model.FilePath, _model.LoopPoint,
133+
_model.TrimEnd, _model.Normalization ?? _model.MsuProjectViewModel.BasicInfo.Normalization,
134+
_model.TrimStart);
135+
136+
if (!response.GeneratedPcmFile)
134137
{
135-
await MessageWindow.ShowErrorDialog(message ?? "Unknown error", "Error", parent);
138+
await MessageWindow.ShowErrorDialog(response.Message ?? "Unknown error", "Error", parent);
136139
return null;
137140
}
138141

139-
if (!successful)
142+
if (!response.Successful)
140143
{
141-
if (!await MessageWindow.ShowYesNoDialog($"{message}\r\nDo you want to continue adding this song?",
144+
if (!await MessageWindow.ShowYesNoDialog($"{response.Message}\r\nDo you want to continue adding this song?",
142145
"Continue?", parent))
143146
{
144147
return null;
@@ -208,7 +211,7 @@ public void AnalyzeAudio()
208211
{
209212
await StopSong(false);
210213

211-
var outputPath = CreateTempPcm();
214+
var outputPath = await CreateTempPcm();
212215

213216
if (!string.IsNullOrEmpty(outputPath))
214217
{

MSUScripter/Services/ControlServices/MsuPcmGenerationWindowService.cs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Linq;
5-
using System.Management;
65
using System.Threading;
76
using System.Threading.Tasks;
87
using AvaloniaControls.ControlServices;
98
using AvaloniaControls.Services;
109
using MSUScripter.Configs;
1110
using MSUScripter.Events;
12-
using MSUScripter.Models;
1311
using MSUScripter.ViewModels;
1412

1513
namespace MSUScripter.Services.ControlServices;
@@ -52,26 +50,20 @@ public MsuPcmGenerationViewModel InitializeModel(MsuProjectViewModel project, bo
5250

5351
public void RunGeneration()
5452
{
55-
_ = ITaskService.Run(() => {
53+
_ = ITaskService.Run(async () => {
5654

5755
var start = DateTime.Now;
5856

5957
List<MsuPcmGenerationSongViewModel> toRetry = [];
6058

6159
Parallel.ForEach(_model.Rows,
6260
new ParallelOptions { MaxDegreeOfParallelism = 10, CancellationToken = _cts.Token },
63-
songDetails =>
64-
{
65-
if (!ProcessSong(songDetails, false))
66-
{
67-
toRetry.Add(songDetails);
68-
}
69-
});
61+
ParallelAction);
7062

7163
// For retries, try again linearly
7264
foreach (var songDetails in toRetry)
7365
{
74-
ProcessSong(songDetails, true);
66+
await ProcessSong(songDetails, true);
7567
}
7668

7769
if (_model.ExportYaml)
@@ -98,7 +90,15 @@ public void RunGeneration()
9890
_model.SongsCompleted = _model.Rows.Count;
9991
statusBarService.UpdateStatusBar("MSU Generated");
10092
PcmGenerationComplete?.Invoke(this, new ValueEventArgs<MsuPcmGenerationViewModel>(_model));
93+
return;
10194

95+
async void ParallelAction(MsuPcmGenerationSongViewModel songDetails)
96+
{
97+
if (!await ProcessSong(songDetails, false))
98+
{
99+
toRetry.Add(songDetails);
100+
}
101+
}
102102
}, _cts.Token);
103103
}
104104

@@ -110,7 +110,7 @@ public void Cancel()
110110
}
111111
}
112112

113-
private bool ProcessSong(MsuPcmGenerationSongViewModel songDetails, bool isRetry)
113+
private async Task<bool> ProcessSong(MsuPcmGenerationSongViewModel songDetails, bool isRetry)
114114
{
115115
if (_cts.IsCancellationRequested)
116116
{
@@ -121,24 +121,27 @@ private bool ProcessSong(MsuPcmGenerationSongViewModel songDetails, bool isRetry
121121
var song = new MsuSongInfo();
122122
converterService.ConvertViewModel(songViewModel, song);
123123
converterService.ConvertViewModel(songViewModel!.MsuPcmInfo, song.MsuPcmInfo);
124-
if (!msuPcmService.CreatePcm(false, _model.MsuProject, song, out var error, out var generated))
124+
125+
var generationResponse = await msuPcmService.CreatePcm(false, _model.MsuProject, song);
126+
127+
if (!generationResponse.Successful)
125128
{
126129
// If this is an error for the sox temp file for the first run, ignore so it can be retried
127-
if (!isRetry && error?.Contains("__sox_wrapper_temp") == true &&
128-
error.Contains("Permission denied"))
130+
if (!isRetry && generationResponse.Message?.Contains("__sox_wrapper_temp") == true &&
131+
generationResponse.Message.Contains("Permission denied"))
129132
{
130133
return false;
131134
}
132135
// Partially ignore empty pcms with no input files
133-
else if (error?.EndsWith("No input files specified") == true && File.Exists(song.OutputPath) && new FileInfo(song.OutputPath).Length <= 44500)
136+
else if (generationResponse.Message?.EndsWith("No input files specified") == true && File.Exists(song.OutputPath) && new FileInfo(song.OutputPath).Length <= 44500)
134137
{
135138
songDetails.HasWarning = true;
136-
songDetails.Message = error;
139+
songDetails.Message = generationResponse.Message;
137140
}
138141
else
139142
{
140143
songDetails.HasWarning = true;
141-
songDetails.Message = error ?? "Unknown error";
144+
songDetails.Message = generationResponse.Message ?? "Unknown error";
142145
_model.NumErrors++;
143146
}
144147

MSUScripter/Services/ControlServices/MsuSongInfoPanelService.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using AvaloniaControls.ControlServices;
66
using AvaloniaControls.Services;
77
using MSUScripter.Configs;
8+
using MSUScripter.Models;
89
using MSUScripter.ViewModels;
910

1011
namespace MSUScripter.Services.ControlServices;
@@ -42,9 +43,13 @@ public void DeleteSong()
4243

4344
public async Task PauseSong()
4445
{
45-
4646
await sharedPcmService.PauseSong();
4747
}
48+
49+
public async Task StopSong()
50+
{
51+
await sharedPcmService.StopSong();
52+
}
4853

4954
public string? GetOpenMusicFilePath()
5055
{
@@ -143,9 +148,9 @@ public void IgnoreMsuPcmError()
143148
_model.Project.IgnoreWarnings.Add(_model.OutputPath);
144149
}
145150

146-
public bool GeneratePcmFile(bool asPrimary, bool asEmpty, out string error, out bool msuPcmError)
151+
public Task<GeneratePcmFileResponse> GeneratePcmFile(bool asPrimary, bool asEmpty)
147152
{
148-
return sharedPcmService.GeneratePcmFile(_model, asPrimary, asEmpty, out error, out msuPcmError);
153+
return sharedPcmService.GeneratePcmFile(_model, asPrimary, asEmpty);
149154
}
150155

151156
public void AnalyzeAudio()
@@ -157,9 +162,11 @@ public void AnalyzeAudio()
157162
{
158163
await PauseSong();
159164

160-
if (!GeneratePcmFile(false, false, out var error, out var msuPcmError))
165+
var generateResponse = await GeneratePcmFile(false, false);
166+
if (!generateResponse.Successful)
161167
{
162-
_model.AverageAudio = "Error";
168+
_model.AverageAudio = "Error generating PCM";
169+
_model.PeakAudio = null;
163170
}
164171

165172
if (!string.IsNullOrEmpty(_model.OutputPath))

MSUScripter/Services/ControlServices/PyMusicLooperPanelService.cs

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ await ITaskService.Run(async () =>
8888
var playSong = true;
8989
if (!File.Exists(result.TempPath))
9090
{
91-
msuPcmService.CreateTempPcm(false, _model.MsuProject, _model.MsuSongMsuPcmInfoViewModel.File!,
92-
out var outputPath,
93-
out var message, out var generated, result.LoopStart, result.LoopEnd, skipCleanup: false);
94-
if (generated)
91+
var response = await msuPcmService.CreateTempPcm(false, _model.MsuProject,
92+
_model.MsuSongMsuPcmInfoViewModel.File!, result.LoopStart, result.LoopEnd, skipCleanup: false);
93+
94+
if (response.GeneratedPcmFile)
9595
{
96-
songPath = outputPath;
96+
songPath = response.OutputPath;
9797
}
9898
else
9999
{
@@ -259,38 +259,40 @@ private void RunMsuPcm(bool fullReload = true)
259259

260260
try
261261
{
262-
Parallel.ForEach(_model.CurrentPageResults.Where(x => !x.Generated), new ParallelOptions()
263-
{
264-
CancellationToken = _cts?.Token ?? CancellationToken.None
265-
},
266-
result =>
262+
async void GenerateTempPcm(PyMusicLooperResultViewModel result)
263+
{
264+
result.Status = "Generating Preview .pcm File";
265+
266+
var response = await msuPcmService.CreateTempPcm(false, _model.MsuProject, _model.MsuSongMsuPcmInfoViewModel.File!, result.LoopStart, result.LoopEnd, skipCleanup: true);
267+
268+
if (!response.Successful)
267269
{
268-
result.Status = "Generating Preview .pcm File";
269-
270-
if (!msuPcmService.CreateTempPcm(false, _model.MsuProject, _model.MsuSongMsuPcmInfoViewModel.File!, out var outputPath,
271-
out var message, out var generated, result.LoopStart, result.LoopEnd, skipCleanup: true))
270+
if (response.GeneratedPcmFile)
272271
{
273-
if (generated)
274-
{
275-
result.Status = $"Generated with message: {message}";
276-
result.TempPath = outputPath;
277-
GetLoopDuration(result);
278-
result.Generated = true;
279-
}
280-
else
281-
{
282-
result.Status = $"Error: {message}";
283-
}
272+
result.Status = $"Generated with message: {response.Message}";
273+
result.TempPath = response.OutputPath ?? throw new InvalidOperationException("GeneratePcmFileResponse for generated PCM missing output path");
274+
GetLoopDuration(result);
275+
result.Generated = true;
284276
}
285277
else
286278
{
287-
result.Status = "Generated";
288-
result.TempPath = outputPath;
289-
GetLoopDuration(result);
290-
result.Generated = true;
279+
result.Status = $"Error: {response.Message}";
291280
}
292-
293-
});
281+
}
282+
else
283+
{
284+
result.Status = "Generated";
285+
result.TempPath = response.OutputPath ?? throw new InvalidOperationException("GeneratePcmFileResponse for generated PCM missing output path");
286+
GetLoopDuration(result);
287+
result.Generated = true;
288+
}
289+
}
290+
291+
Parallel.ForEach(_model.CurrentPageResults.Where(x => !x.Generated), new ParallelOptions()
292+
{
293+
CancellationToken = _cts?.Token ?? CancellationToken.None
294+
},
295+
GenerateTempPcm);
294296
}
295297
catch
296298
{

0 commit comments

Comments
 (0)