Skip to content

Commit

Permalink
Merge branch 'preview' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
paralleltree committed Jul 23, 2021
2 parents 07d095e + 66aef7f commit 00a1216
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 33 deletions.
1 change: 1 addition & 0 deletions Ched/Ched.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@
</Compile>
<Compile Include="UI\Windows\Converters\BitmapImageSourceConverter.cs" />
<Compile Include="UI\Windows\Converters\ShortcutKeyTextConverter.cs" />
<Compile Include="UI\Windows\Converters\VolumeConverter.cs" />
<Compile Include="UI\Windows\DiagnosticsWindow.xaml.cs">
<DependentUpon>DiagnosticsWindow.xaml</DependentUpon>
</Compile>
Expand Down
8 changes: 8 additions & 0 deletions Ched/Configuration/ApplicationSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,13 @@ public bool IsPreviewAbortAtLastNote
get { return ((bool)(this["IsPreviewAbortAtLastNote"])); }
set { this["IsPreviewAbortAtLastNote"] = value; }
}

[UserScopedSetting]
[DefaultSettingValue("False")]
public bool IsSlowDownPreviewEnabled
{
get => (bool)this["IsSlowDownPreviewEnabled"];
set => this["IsSlowDownPreviewEnabled"] = value;
}
}
}
7 changes: 7 additions & 0 deletions Ched/Configuration/SoundSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,12 @@ public Dictionary<string, SoundSource> ScoreSound
get { return (Dictionary<string, SoundSource>)this["ScoreSound"]; }
set { this["ScoreSound"] = value; }
}

[UserScopedSetting]
public SoundSource GuideSound
{
get => (SoundSource)this["GuideSound"] ?? new SoundSource("guide.mp3", 0.036);
set => this["GuideSound"] = value;
}
}
}
27 changes: 27 additions & 0 deletions Ched/Localization/MainFormStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions Ched/Localization/MainFormStrings.en.resx
Original file line number Diff line number Diff line change
Expand Up @@ -333,4 +333,13 @@
<data name="ResetAll" xml:space="preserve">
<value>Reset All</value>
</data>
<data name="GuideVolume" xml:space="preserve">
<value>Guide Volume (Global)</value>
</data>
<data name="MusicVolume" xml:space="preserve">
<value>Music Volume</value>
</data>
<data name="SlowDownPreview" xml:space="preserve">
<value>Slow Down Preview</value>
</data>
</root>
9 changes: 9 additions & 0 deletions Ched/Localization/MainFormStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -333,4 +333,13 @@
<data name="ResetAll" xml:space="preserve">
<value>初期化</value>
</data>
<data name="GuideVolume" xml:space="preserve">
<value>ガイド音音量(共通)</value>
</data>
<data name="MusicVolume" xml:space="preserve">
<value>楽曲音量</value>
</data>
<data name="SlowDownPreview" xml:space="preserve">
<value>スロー再生</value>
</data>
</root>
31 changes: 21 additions & 10 deletions Ched/UI/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,11 @@ protected void LoadBook(ScoreBook book)
if (!string.IsNullOrEmpty(book.Path))
{
SoundSettings.Default.ScoreSound.TryGetValue(book.Path, out SoundSource src);
if (src != null) CurrentMusicSource = src;
if (src != null)
{
if (src.Volume == 0) src.Volume = 1;
CurrentMusicSource = src;
}
}
}

Expand Down Expand Up @@ -482,7 +486,7 @@ void lambda(object p, EventArgs q)
try
{
CommitChanges();
var context = new SoundPreviewContext(ScoreBook.Score, CurrentMusicSource);
var context = new SoundPreviewContext(ScoreBook.Score, CurrentMusicSource, SoundSettings.Default.GuideSound);
if (!PreviewManager.Start(context, startTick)) return;
PreviewManager.Finished += lambda;
NoteView.Editable = CanEdit;
Expand Down Expand Up @@ -851,6 +855,20 @@ void updateScore(Score newScore)

var insertMenuItems = new ToolStripItem[] { insertBpmItem, insertHighSpeedItem, insertTimeSignatureItem };

var playItem = shortcutItemBuilder.BuildItem(Commands.PlayPreview, MainFormStrings.Play);

var stopItem = new ToolStripMenuItem(MainFormStrings.Stop, null, (s, e) => PreviewManager.Stop());

var slowDownPreviewItem = new ToolStripMenuItem(MainFormStrings.SlowDownPreview, null, (s, e) =>
{
var item = s as ToolStripMenuItem;
item.Checked = !item.Checked;
ApplicationSettings.Default.IsSlowDownPreviewEnabled = item.Checked;
})
{
Checked = ApplicationSettings.Default.IsSlowDownPreviewEnabled
};

var isAbortAtLastNoteItem = new ToolStripMenuItem(MainFormStrings.AbortAtLastNote, null, (s, e) =>
{
var item = s as ToolStripMenuItem;
Expand All @@ -864,17 +882,10 @@ void updateScore(Score newScore)
PreviewManager.Started += (s, e) => isAbortAtLastNoteItem.Enabled = false;
PreviewManager.Finished += (s, e) => isAbortAtLastNoteItem.Enabled = true;

var playItem = shortcutItemBuilder.BuildItem(Commands.PlayPreview, MainFormStrings.Play);

var stopItem = new ToolStripMenuItem(MainFormStrings.Stop, null, (s, e) =>
{
PreviewManager.Stop();
});

var playMenuItems = new ToolStripItem[]
{
playItem, stopItem, new ToolStripSeparator(),
isAbortAtLastNoteItem
slowDownPreviewItem, isAbortAtLastNoteItem
};

var helpMenuItems = new ToolStripItem[]
Expand Down
31 changes: 24 additions & 7 deletions Ched/UI/SoundManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Threading.Tasks;

using Un4seen.Bass;
using Un4seen.Bass.AddOn.Fx;

namespace Ched.UI
{
Expand Down Expand Up @@ -52,20 +53,22 @@ public void Register(string path)

protected int GetHandle(string filepath)
{
int handle = Bass.BASS_StreamCreateFile(filepath, 0, 0, BASSFlag.BASS_DEFAULT);
if (handle == 0) throw new ArgumentException("cannot create a stream.");
return handle;
int rawHandle = Bass.BASS_StreamCreateFile(filepath, 0, 0, BASSFlag.BASS_STREAM_DECODE);
if (rawHandle == 0) throw new ArgumentException("cannot create a stream.");
int tempoHandle = BassFx.BASS_FX_TempoCreate(rawHandle, BASSFlag.BASS_FX_FREESOURCE);
if (tempoHandle == 0) throw new ArgumentException("cannot create a stream.");
return tempoHandle;
}

public void Play(string path)
{
Play(path, 0);
Play(path, 0, 1.0, 1.0);
}

public void Play(string path, double offset)
public void Play(string path, double offset, double volume = 1.0, double speed = 1.0)
{
CheckSupported();
Task.Run(() => PlayInternal(path, offset))
Task.Run(() => PlayInternal(path, offset, volume, speed))
.ContinueWith(p =>
{
if (p.Exception != null)
Expand All @@ -76,7 +79,7 @@ public void Play(string path, double offset)
});
}

private void PlayInternal(string path, double offset)
private void PlayInternal(string path, double offset, double volume, double speed)
{
Queue<int> freelist;
lock (handles)
Expand Down Expand Up @@ -107,6 +110,8 @@ private void PlayInternal(string path, double offset)

lock (playing) playing.Add(handle);
Bass.BASS_ChannelSetPosition(handle, offset);
Bass.BASS_ChannelSetAttribute(handle, BASSAttribute.BASS_ATTRIB_VOL, (float)volume);
Bass.BASS_ChannelSetAttribute(handle, BASSAttribute.BASS_ATTRIB_TEMPO, (float)((speed - 1.0) * 100));
Bass.BASS_ChannelPlay(handle, false);
}

Expand Down Expand Up @@ -152,6 +157,18 @@ public class SoundSource

public string FilePath { get; set; }

private double volume = 1.0;
public double Volume
{
get => volume;
set
{
if (volume < 0 || volume > 1.0)
throw new ArgumentOutOfRangeException("value");
volume = value;
}
}

public SoundSource()
{
}
Expand Down
30 changes: 15 additions & 15 deletions Ched/UI/SoundPreviewManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public class SoundPreviewManager : IDisposable
public event EventHandler ExceptionThrown;

private int CurrentTick { get; set; }
private SoundSource ClapSource { get; set; }
private SoundManager SoundManager { get; } = new SoundManager();
private ISoundPreviewContext PreviewContext { get; set; }
private LinkedListNode<int?> TickElement;
Expand All @@ -42,7 +41,6 @@ public class SoundPreviewManager : IDisposable
public SoundPreviewManager(Control syncControl)
{
SyncControl = syncControl;
ClapSource = new SoundSource("guide.mp3", 0.036);
Timer.Tick += Tick;
SoundManager.ExceptionThrown += (s, e) => SyncControl.InvokeIfRequired(() =>
{
Expand All @@ -56,7 +54,7 @@ public bool Start(ISoundPreviewContext context, int startTick)
if (Playing) throw new InvalidOperationException();
if (context == null) throw new ArgumentNullException("context");
PreviewContext = context;
SoundManager.Register(ClapSource.FilePath);
SoundManager.Register(context.ClapSource.FilePath);
SoundManager.Register(context.MusicSource.FilePath);

var timeCalculator = new TimeCalculator(context.TicksPerBeat, context.BpmDefinitions);
Expand All @@ -71,26 +69,22 @@ public bool Start(ISoundPreviewContext context, int startTick)
while (TickElement != null && TickElement.Value < startTick) TickElement = TickElement.Next;
while (BpmElement.Next != null && BpmElement.Next.Value.Tick <= startTick) BpmElement = BpmElement.Next;

int clapLatencyTick = GetLatencyTick(ClapSource.Latency, BpmElement.Value.Bpm);
int clapLatencyTick = GetLatencyTick(context.ClapSource.Latency, BpmElement.Value.Bpm);
InitialTick = startTick - clapLatencyTick;
CurrentTick = InitialTick;
StartTick = startTick;

double startTime = timeCalculator.GetTimeFromTick(startTick);
double headGap = -context.MusicSource.Latency - startTime;
double headGap = Math.Max(-context.MusicSource.Latency - startTime, 0);
elapsedTick = 0;
Task.Run(() =>
{
LastSystemTick = Environment.TickCount;
SyncControl.Invoke((MethodInvoker)(() => Timer.Start()));

System.Threading.Thread.Sleep(TimeSpan.FromSeconds(Math.Max(ClapSource.Latency, 0)));
if (headGap > 0)
{
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(headGap));
}
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(Math.Max((context.ClapSource.Latency + headGap) / context.Speed, 0)));
if (!Playing) return;
SoundManager.Play(context.MusicSource.FilePath, startTime + context.MusicSource.Latency);
SoundManager.Play(context.MusicSource.FilePath, startTime + context.MusicSource.Latency, context.MusicSource.Volume, context.Speed);
})
.ContinueWith(p =>
{
Expand Down Expand Up @@ -120,7 +114,7 @@ private void Tick(object sender, EventArgs e)
int elapsed = now - LastSystemTick;
LastSystemTick = now;

elapsedTick += PreviewContext.TicksPerBeat * BpmElement.Value.Bpm * elapsed / 60 / 1000;
elapsedTick += PreviewContext.TicksPerBeat * BpmElement.Value.Bpm * elapsed * PreviewContext.Speed / 60 / 1000;
CurrentTick = (int)(InitialTick + elapsedTick);
if (CurrentTick >= StartTick)
TickUpdated?.Invoke(this, new TickUpdatedEventArgs(Math.Max(CurrentTick, 0)));
Expand All @@ -132,14 +126,14 @@ private void Tick(object sender, EventArgs e)
Stop();
}

int latencyTick = GetLatencyTick(ClapSource.Latency, BpmElement.Value.Bpm);
int latencyTick = GetLatencyTick(PreviewContext.ClapSource.Latency, BpmElement.Value.Bpm);
if (TickElement == null || TickElement.Value - latencyTick > CurrentTick) return;
while (TickElement != null && TickElement.Value - latencyTick <= CurrentTick)
{
TickElement = TickElement.Next;
}

SoundManager.Play(ClapSource.FilePath);
SoundManager.Play(PreviewContext.ClapSource.FilePath, 0, PreviewContext.ClapSource.Volume, PreviewContext.Speed);
}

private int GetLatencyTick(double latency, double bpm)
Expand All @@ -156,23 +150,29 @@ public void Dispose()
public interface ISoundPreviewContext
{
int TicksPerBeat { get; }
double Speed { get; }
IEnumerable<int> GetGuideTicks();
IEnumerable<BpmChangeEvent> BpmDefinitions { get; }
SoundSource MusicSource { get; }
SoundSource ClapSource { get; }
}

public class SoundPreviewContext : ISoundPreviewContext
{
private Core.Score score;

public int TicksPerBeat => score.TicksPerBeat;
public double Speed { get; private set; } = 1.0;
public IEnumerable<BpmChangeEvent> BpmDefinitions => score.Events.BpmChangeEvents;
public SoundSource MusicSource { get; }
public SoundSource ClapSource { get; }

public SoundPreviewContext(Core.Score score, SoundSource musicSource)
public SoundPreviewContext(Core.Score score, SoundSource musicSource, SoundSource clapSource)
{
this.score = score;
MusicSource = musicSource;
ClapSource = clapSource;
Speed = Configuration.ApplicationSettings.Default.IsSlowDownPreviewEnabled ? 0.5 : 1.0;
}

public IEnumerable<int> GetGuideTicks() => GetGuideTicks(score.Notes);
Expand Down
Loading

0 comments on commit 00a1216

Please sign in to comment.