diff --git a/OpenUtau.Core/PlaybackManager.cs b/OpenUtau.Core/PlaybackManager.cs
index 863571c40..c25c8d427 100644
--- a/OpenUtau.Core/PlaybackManager.cs
+++ b/OpenUtau.Core/PlaybackManager.cs
@@ -12,7 +12,6 @@
using OpenUtau.Core.Ustx;
using OpenUtau.Core.Util;
using Serilog;
-using System.Collections.Concurrent;
namespace OpenUtau.Core {
public class SineGenerator : ISampleProvider {
@@ -265,6 +264,7 @@ private PlaybackManager() {
double startMs;
public int StartTick => DocManager.Inst.Project.timeAxis.MsPosToTickPos(startMs);
+ public int returnPosition = 0;
// One cancellation source per render lane so starting playback, pre-rendering
// or exporting no longer cancel each other in flight.
CancellationTokenSource renderCancellation;
@@ -435,6 +435,11 @@ public void StopPlayback() {
}
public void PausePlayback() {
+ if (Preferences.Default.LockStartTime != 0) {
+ StopPlayback();
+ DocManager.Inst.ExecuteCmd(new SetPlayPosTickNotification(returnPosition, pause: true));
+ return;
+ }
AudioOutput.Pause();
StartingToPlay = false;
PlayingMaster = false;
@@ -468,14 +473,19 @@ private void Render(UProject project, int tick, int endTick, int trackNo) {
RenderEngine engine = new RenderEngine(project, startTick: tick, endTick: endTick, trackNo: trackNo);
var result = engine.RenderMixdown(DocManager.Inst.MainScheduler, ref renderCancellation, wait: false, applyMixFx: true, planner: MixPlanner);
playbackMix = new PlaybackMix(result.Item1, metronomeEngine);
+ this.returnPosition = tick;
+ var startTick = tick;
+ if (Preferences.Default.PreRoll) {
+ startTick = Math.Max(0, tick - (480 * 4 * Preferences.Default.PreRollMeasure));
+ }
var playbackAdapter = new MasterAdapter(playbackMix);
// Hold mode: wait for pending phrases (today's behaviour), except
// in loop mode where a pending phrase must not stall the clock.
// Failed phrases never hold in either mode.
playbackAdapter.HoldWhenUnready = !LoopPlayback;
- playbackAdapter.SetPosition((int)(project.timeAxis.TickPosToMsPos(tick) * 44100 / 1000) * 2);
+ playbackAdapter.SetPosition((int)(project.timeAxis.TickPosToMsPos(startTick) * 44100 / 1000) * 2);
faders = result.Item2;
- StartPlayback(project.timeAxis.TickPosToMsPos(tick), playbackAdapter);
+ StartPlayback(project.timeAxis.TickPosToMsPos(startTick), playbackAdapter);
Task.Factory.StartNew(() => {
DocManager.Inst.ExecuteCmd(new WaveformReadyNotification());
diff --git a/OpenUtau.Core/Util/Preferences.cs b/OpenUtau.Core/Util/Preferences.cs
index e7d94c521..1d24ca879 100644
--- a/OpenUtau.Core/Util/Preferences.cs
+++ b/OpenUtau.Core/Util/Preferences.cs
@@ -215,6 +215,10 @@ public class SerializablePreferences {
public int MetronomeVolume = 60;
public int MetronomeHighFrequency = 2200;
public int MetronomeLowFrequency = 1320;
+ public bool AutoMovePlayhead = false;
+ public bool PreRoll = false;
+ public int PreRollMeasure = 1;
+ /// On Pausing; 0 = Do nothing, 1 = Move cursor and scroll, 2 = Move cursor only
public int LockStartTime = 0;
public int PlaybackAutoScroll = 2;
public bool ReverseLogOrder = true;
diff --git a/OpenUtau/Controls/PianoRoll.axaml b/OpenUtau/Controls/PianoRoll.axaml
index ff287a7eb..5af94b3ff 100644
--- a/OpenUtau/Controls/PianoRoll.axaml
+++ b/OpenUtau/Controls/PianoRoll.axaml
@@ -327,6 +327,11 @@
+