Multi-track + shaped/raw recording (per-peer split tracks) — held for next release
Recording Settings gains two per-profile toggles (Ed's request): * "Split recording into separate tracks" — each recording becomes a folder with one file per connected peer (their received audio only) plus one for your own send. * "Bypass pan and EQ when recording" — record the RAW audio (before pan/EQ) instead of the shaped audio you hear; applies to single and split. Engine: a per-peer record tap in SessionPlayout hands each peer's block to the recorder RAW (before pan/EQ) or SHAPED (after) per the bypass flag; PlayoutEngine propagates the tap to all sessions (+ inherits on reconnect) and fires OnRecordBlockComplete each render; AudioReceiver exposes SetPeerRecordTap / OnRecordBlockComplete. AudioRecorder now accepts an explicit path and exposes ExtensionFor. RecordingController composes one AudioRecorder per track: multi-track = a recorder per connected peer + a "me" recorder; single-track shaped = the existing mixed tap; single-track raw (bypass) = sum each peer's raw block per render, flushed on the block boundary. Naming (Ed's scheme, sortable): <recordings>/<yyyy-MM-dd>/ then, single-track, "<HH-mm-ss> RemSound recording.<ext>"; multi-track, a folder "<HH-mm-ss> RemSound recording multi track/" containing "<machine name> <HH-mm-ss>.<ext>" per peer (name or IP) and for your own send. Known edge (noted): a peer using sender-side BothIndependent (two lanes) records both lanes to one file in a split recording; single-track bypass sums per render in the Mixed path. Off by default (both toggles unticked = today's behaviour). Builds clean; pending Ed's hands-on test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
703e6a022d
commit
de55230048
@@ -135,19 +135,29 @@ internal sealed class AudioRecorder : IDisposable
|
||||
/// <summary>Constructs the recorder, opens the output file, and starts the writer
|
||||
/// thread. If anything fails the constructor throws and no cleanup is needed (no
|
||||
/// file has been opened yet).</summary>
|
||||
public AudioRecorder(RecordingSettings settings, Action<string>? onDiagnostic, Action<string, long>? onFinished)
|
||||
public AudioRecorder(RecordingSettings settings, Action<string>? onDiagnostic, Action<string, long>? onFinished, string? explicitPath = null)
|
||||
{
|
||||
this.settings = settings.Clone();
|
||||
this.onDiagnostic = onDiagnostic;
|
||||
this.onFinished = onFinished;
|
||||
|
||||
var folder = settings.ResolvedFolder();
|
||||
if (string.IsNullOrWhiteSpace(folder)) folder = RecordingSettings.DefaultFolder();
|
||||
Directory.CreateDirectory(folder);
|
||||
if (explicitPath is not null)
|
||||
{
|
||||
// The RecordingController drives the folder/file naming (date folders, per-peer split
|
||||
// tracks). Honour the path it hands us, creating the containing folder.
|
||||
resolvedPath = explicitPath;
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(explicitPath) ?? RecordingSettings.DefaultFolder());
|
||||
}
|
||||
else
|
||||
{
|
||||
var folder = settings.ResolvedFolder();
|
||||
if (string.IsNullOrWhiteSpace(folder)) folder = RecordingSettings.DefaultFolder();
|
||||
Directory.CreateDirectory(folder);
|
||||
|
||||
var ext = ExtensionFor(settings.FileFormat);
|
||||
var stamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||
resolvedPath = Path.Combine(folder, $"RemSound-{stamp}.{ext}");
|
||||
var ext = ExtensionFor(settings.FileFormat);
|
||||
var stamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||
resolvedPath = Path.Combine(folder, $"RemSound-{stamp}.{ext}");
|
||||
}
|
||||
|
||||
// Writer creation happens on the constructor thread so any open errors are surfaced
|
||||
// synchronously to the caller.
|
||||
@@ -565,7 +575,7 @@ internal sealed class AudioRecorder : IDisposable
|
||||
private float[] recvDirectionScratch = new float[DrainChunkFrames * MixChannels];
|
||||
private float[] monoScratch = new float[DrainChunkFrames];
|
||||
|
||||
private static string ExtensionFor(RecordingFileFormat format) => format switch
|
||||
public static string ExtensionFor(RecordingFileFormat format) => format switch
|
||||
{
|
||||
RecordingFileFormat.Wav => "wav",
|
||||
RecordingFileFormat.Mp3 => "mp3",
|
||||
|
||||
Reference in New Issue
Block a user