mirror of
https://github.com/unclshura/ABStemPlayer.git
synced 2026-08-07 00:43:38 +00:00
Added resampling for mp3 with bitrate that differs to 44100.
This commit is contained in:
parent
7efd223a6c
commit
21e1f1e3f5
@ -19,6 +19,8 @@ public partial class WaveformBandViewModel : ObservableObject
|
|||||||
private readonly StemTrack _stem;
|
private readonly StemTrack _stem;
|
||||||
public string BandName => _stem.Name;
|
public string BandName => _stem.Name;
|
||||||
|
|
||||||
|
public override string ToString() => $"{Duration} {BandName} X:{PlaybackX}";
|
||||||
|
|
||||||
[ObservableProperty] private double _canvasWidth;
|
[ObservableProperty] private double _canvasWidth;
|
||||||
[ObservableProperty] private double _canvasHeight;
|
[ObservableProperty] private double _canvasHeight;
|
||||||
[ObservableProperty] private Geometry? _waveformGeometry;
|
[ObservableProperty] private Geometry? _waveformGeometry;
|
||||||
|
|||||||
@ -39,9 +39,7 @@
|
|||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="8">
|
Margin="8">
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="1"
|
<ScrollViewer Margin="8"
|
||||||
Grid.Column="0"
|
|
||||||
Margin="8"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
|
||||||
<ItemsControl ItemsSource="{Binding Bands}"
|
<ItemsControl ItemsSource="{Binding Bands}"
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public sealed class FfmpegProcess : IDisposable
|
|||||||
|
|
||||||
public void StartProcess()
|
public void StartProcess()
|
||||||
{
|
{
|
||||||
Debug.WriteLine($"{_name}: Starting ffmpeg process");
|
Debug.WriteLine($"{_name}: Starting ffmpeg process: {_commandLine.Replace("\r", "").Replace("\n", " ").Replace("\t", " ")}");
|
||||||
|
|
||||||
var psi = new ProcessStartInfo
|
var psi = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
|
|||||||
@ -26,11 +26,12 @@ public sealed class Htdemucs6sSeparator : IStemSeparator
|
|||||||
if (existingStems != null)
|
if (existingStems != null)
|
||||||
return existingStems;
|
return existingStems;
|
||||||
|
|
||||||
var mix = LoadStereoFloatWave(request.SourceFilePath, out var sr);
|
var probe = FfprobeProcess.ProbeAudio(request.SourceFilePath);
|
||||||
//if (sr != _sampleRate)
|
|
||||||
// throw new InvalidOperationException($"Input must be {_sampleRate} Hz");
|
|
||||||
|
|
||||||
var totalSamples = mix.GetLength(1);
|
int totalSamples = (int)(probe.Duration.TotalSeconds * _sampleRate);
|
||||||
|
|
||||||
|
// Decode whole file to stereo float array via ffmpeg, resampled to 44.1kHz.
|
||||||
|
var mix = LoadStereoFloatWave(request.SourceFilePath, totalSamples);
|
||||||
|
|
||||||
var opts = new SessionOptions();
|
var opts = new SessionOptions();
|
||||||
opts.AppendExecutionProvider_CPU();
|
opts.AppendExecutionProvider_CPU();
|
||||||
@ -134,12 +135,12 @@ public sealed class Htdemucs6sSeparator : IStemSeparator
|
|||||||
|
|
||||||
result.Add(new StemTrack
|
result.Add(new StemTrack
|
||||||
{
|
{
|
||||||
Type = Enum.Parse<StemType>(_stemNames[i]),
|
Type = Enum.Parse<StemType>(_stemNames[i]),
|
||||||
Name = name,
|
Name = name,
|
||||||
FilePath = path,
|
FilePath = path,
|
||||||
SampleRate = _sampleRate,
|
SampleRate = _sampleRate,
|
||||||
Channels = _channels,
|
Channels = _channels,
|
||||||
Duration = TimeSpan.FromSeconds((double)totalSamples / _sampleRate)
|
Duration = TimeSpan.FromSeconds((double)totalSamples / _sampleRate)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,36 +151,49 @@ public sealed class Htdemucs6sSeparator : IStemSeparator
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private StemSet? CheckExistingStems(StemSeparationRequest request)
|
private static float[,] LoadStereoFloatWave(string path, int totalSamples)
|
||||||
{
|
{
|
||||||
var filesToCheck = Enum.GetNames(typeof(StemType))
|
var result = new float[_channels, totalSamples];
|
||||||
.Select(stemType => (stemType, Path.Combine(request.OutputDirectory,
|
|
||||||
$"{Path.GetFileNameWithoutExtension(request.SourceFilePath)}_{stemType}.flac")))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var stems = new List<StemTrack>();
|
var cmd =
|
||||||
var set = new StemSet
|
"-hide_banner -loglevel error " +
|
||||||
|
$"-i \"{path}\" " +
|
||||||
|
"-map a:0 " +
|
||||||
|
"-af aresample " +
|
||||||
|
"-f f32le -ac 2 -ar 44100 pipe:1";
|
||||||
|
|
||||||
|
using var ff = new FfmpegProcess(
|
||||||
|
name: $"decode:{Path.GetFileName(path)}",
|
||||||
|
commandLine: cmd,
|
||||||
|
redirectOutput: true,
|
||||||
|
redirectInput: false);
|
||||||
|
|
||||||
|
ff.StartProcess();
|
||||||
|
|
||||||
|
var buffer = new float[4096 * _channels];
|
||||||
|
var pos = 0;
|
||||||
|
|
||||||
|
const float SCALE = 2f;
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
OriginalFilePath = request.SourceFilePath,
|
var readFloats = ff.ReadAsync(buffer.AsMemory(), CancellationToken.None).GetAwaiter().GetResult();
|
||||||
Stems = stems
|
if (readFloats <= 0)
|
||||||
};
|
break;
|
||||||
|
|
||||||
foreach (var f in filesToCheck.Where(f => File.Exists(f.Item2)))
|
var framesRead = readFloats / _channels;
|
||||||
{
|
for (var f = 0; f < framesRead && pos < totalSamples; f++, pos++)
|
||||||
using var reader = new AudioFileReader(f.Item2);
|
|
||||||
|
|
||||||
stems.Add(new StemTrack
|
|
||||||
{
|
{
|
||||||
Type = Enum.Parse<StemType>(f.Item1),
|
var baseIndex = f * _channels;
|
||||||
Name = Path.GetFileName(f.Item2),
|
result[0, pos] = buffer[baseIndex + 0] * SCALE;
|
||||||
FilePath = f.Item2,
|
result[1, pos] = buffer[baseIndex + 1] * SCALE;
|
||||||
SampleRate = reader.WaveFormat.SampleRate,
|
}
|
||||||
Channels = reader.WaveFormat.Channels,
|
|
||||||
Duration = reader.TotalTime
|
if (pos >= totalSamples)
|
||||||
});
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stems.Count > 0 ? set : null;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] MakeWindow(int n, int overlap)
|
private static float[] MakeWindow(int n, int overlap)
|
||||||
@ -196,29 +210,6 @@ public sealed class Htdemucs6sSeparator : IStemSeparator
|
|||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[,] LoadStereoFloatWave(string path, out int sampleRate)
|
|
||||||
{
|
|
||||||
using var reader = new AudioFileReader(path);
|
|
||||||
sampleRate = reader.WaveFormat.SampleRate;
|
|
||||||
|
|
||||||
var samples = new List<float>();
|
|
||||||
var buffer = new float[reader.WaveFormat.SampleRate * 4];
|
|
||||||
int read;
|
|
||||||
while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
|
|
||||||
samples.AddRange(buffer.AsSpan(0, read));
|
|
||||||
|
|
||||||
var total = samples.Count / 2;
|
|
||||||
var result = new float[2, total];
|
|
||||||
|
|
||||||
for (var i = 0; i < total; i++)
|
|
||||||
{
|
|
||||||
result[0, i] = samples[2 * i];
|
|
||||||
result[1, i] = samples[2 * i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void WriteFlac(string path, float[,,] stems, int stemIndex, int totalSamples)
|
private static void WriteFlac(string path, float[,,] stems, int stemIndex, int totalSamples)
|
||||||
{
|
{
|
||||||
var cmd =
|
var cmd =
|
||||||
@ -253,4 +244,36 @@ public sealed class Htdemucs6sSeparator : IStemSeparator
|
|||||||
|
|
||||||
ff.Proc!.WaitForExit();
|
ff.Proc!.WaitForExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private StemSet? CheckExistingStems(StemSeparationRequest request)
|
||||||
|
{
|
||||||
|
var filesToCheck = Enum.GetNames(typeof(StemType))
|
||||||
|
.Select(stemType => (stemType, Path.Combine(request.OutputDirectory,
|
||||||
|
$"{Path.GetFileNameWithoutExtension(request.SourceFilePath)}_{stemType}.flac")))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var stems = new List<StemTrack>();
|
||||||
|
var set = new StemSet
|
||||||
|
{
|
||||||
|
OriginalFilePath = request.SourceFilePath,
|
||||||
|
Stems = stems
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var f in filesToCheck.Where(f => File.Exists(f.Item2)))
|
||||||
|
{
|
||||||
|
using var reader = new AudioFileReader(f.Item2);
|
||||||
|
|
||||||
|
stems.Add(new StemTrack
|
||||||
|
{
|
||||||
|
Type = Enum.Parse<StemType>(f.Item1),
|
||||||
|
Name = Path.GetFileName(f.Item2),
|
||||||
|
FilePath = f.Item2,
|
||||||
|
SampleRate = reader.WaveFormat.SampleRate,
|
||||||
|
Channels = reader.WaveFormat.Channels,
|
||||||
|
Duration = reader.TotalTime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return stems.Count > 0 ? set : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,4 +11,6 @@ public sealed class StemTrack
|
|||||||
public float[] Waveform { get; set; } = [];
|
public float[] Waveform { get; set; } = [];
|
||||||
|
|
||||||
public long TotalFrames => (long)(Duration.TotalMilliseconds * SampleRate / 1000.0);
|
public long TotalFrames => (long)(Duration.TotalMilliseconds * SampleRate / 1000.0);
|
||||||
|
|
||||||
|
public override string ToString() => $"{Duration} {SampleRate}*{Channels} {Type}: {FilePath}";
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user