diff --git a/GenshinLyreMidiPlayer.Data/App.config b/GenshinLyreMidiPlayer.Data/App.config
new file mode 100644
index 0000000..cf44900
--- /dev/null
+++ b/GenshinLyreMidiPlayer.Data/App.config
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+ True
+
+
+ False
+
+
+ True
+
+
+ False
+
+
+ False
+
+
+ -1
+
+
+ 0
+
+
+ 3
+
+
+ 0
+
+
+ 0
+
+
+ True
+
+
+ GenshinImpact.exe
+
+
+ 0
+
+
+
+
+
+
+ https://github.com/sabihoshi/GenshinLyreMidiPlayer/blob/main/LICENSE.md
+
+
+ https://github.com/sabihoshi/GenshinLyreMidiPlayer/blob/main/THIRD-PARTY-NOTICES.md
+
+
+
+
\ No newline at end of file
diff --git a/GenshinLyreMidiPlayer.Data/GenshinLyreMidiPlayer.Data.csproj b/GenshinLyreMidiPlayer.Data/GenshinLyreMidiPlayer.Data.csproj
index 408b03a..10463bf 100644
--- a/GenshinLyreMidiPlayer.Data/GenshinLyreMidiPlayer.Data.csproj
+++ b/GenshinLyreMidiPlayer.Data/GenshinLyreMidiPlayer.Data.csproj
@@ -1,7 +1,7 @@
- net6.0-windows10.0.22000.0
+ net6.0-windows10.0.22621.0
latest
enable
true
diff --git a/GenshinLyreMidiPlayer.Data/Git/GitVersion.cs b/GenshinLyreMidiPlayer.Data/Git/GitVersion.cs
index 547d0f7..66eaeb8 100644
--- a/GenshinLyreMidiPlayer.Data/Git/GitVersion.cs
+++ b/GenshinLyreMidiPlayer.Data/Git/GitVersion.cs
@@ -13,7 +13,7 @@ public class GitVersion
[JsonPropertyName("name")] public string Name { get; set; } = "Unknown";
- [JsonPropertyName("tag_name")] public string TagName { get; set; } = "0";
+ [JsonPropertyName("tag_name")] public string TagName { get; set; } = "0.0";
[JsonPropertyName("html_url")] public string Url { get; set; } = null!;
diff --git a/GenshinLyreMidiPlayer.Data/Properties/Settings.Designer.cs b/GenshinLyreMidiPlayer.Data/Properties/Settings.Designer.cs
index c58545b..3f4d7d9 100644
--- a/GenshinLyreMidiPlayer.Data/Properties/Settings.Designer.cs
+++ b/GenshinLyreMidiPlayer.Data/Properties/Settings.Designer.cs
@@ -12,7 +12,7 @@ namespace GenshinLyreMidiPlayer.Data.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.0.3.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")]
public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -46,8 +46,8 @@ public string LicenseUri {
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.WebServiceUrl)]
- [global::System.Configuration.DefaultSettingValueAttribute("\r\n https://github.com/sabihoshi/GenshinLyreMidiPlayer/blob/main/TH" +
- "IRD-PARTY-NOTICES.md\r\n ")]
+ [global::System.Configuration.DefaultSettingValueAttribute("https://github.com/sabihoshi/GenshinLyreMidiPlayer/blob/main/THIRD-PARTY-NOTICES." +
+ "md")]
public string ThirdPartyLicenseUri {
get {
return ((string)(this["ThirdPartyLicenseUri"]));
@@ -209,5 +209,17 @@ public string GenshinLocation {
this["GenshinLocation"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("0")]
+ public int SelectedInstrument {
+ get {
+ return ((int)(this["SelectedInstrument"]));
+ }
+ set {
+ this["SelectedInstrument"] = value;
+ }
+ }
}
}
diff --git a/GenshinLyreMidiPlayer.Data/Properties/Settings.settings b/GenshinLyreMidiPlayer.Data/Properties/Settings.settings
index 69069c1..e02dbf7 100644
--- a/GenshinLyreMidiPlayer.Data/Properties/Settings.settings
+++ b/GenshinLyreMidiPlayer.Data/Properties/Settings.settings
@@ -1,64 +1,63 @@
-
-
-
-
- <?xml version="1.0" encoding="utf-16"?>
+
+
+
+
+ <?xml version="1.0" encoding="utf-16"?>
<SerializableConnectionString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ConnectionString>history.db</ConnectionString>
<ProviderName />
- </SerializableConnectionString>
-
- history.db
-
-
- https://github.com/sabihoshi/GenshinLyreMidiPlayer/blob/main/LICENSE.md
-
-
-
- https://github.com/sabihoshi/GenshinLyreMidiPlayer/blob/main/THIRD-PARTY-NOTICES.md
-
-
-
- True
-
-
- True
-
-
- False
-
-
- True
-
-
- False
-
-
- False
-
-
- -1
-
-
- 0
-
-
- 3
-
-
- 0
-
-
- 0
-
-
- True
-
-
- GenshinImpact.exe
-
-
+ </SerializableConnectionString>
+ history.db
+
+
+ https://github.com/sabihoshi/GenshinLyreMidiPlayer/blob/main/LICENSE.md
+
+
+ https://github.com/sabihoshi/GenshinLyreMidiPlayer/blob/main/THIRD-PARTY-NOTICES.md
+
+
+ True
+
+
+ True
+
+
+ False
+
+
+ True
+
+
+ False
+
+
+ False
+
+
+ -1
+
+
+ 0
+
+
+ 3
+
+
+ 0
+
+
+ 0
+
+
+ True
+
+
+ GenshinImpact.exe
+
+
+ 0
+
+
\ No newline at end of file
diff --git a/GenshinLyreMidiPlayer.WPF/Core/Keyboard.cs b/GenshinLyreMidiPlayer.WPF/Core/Keyboard.cs
index b9b47cd..3ba7358 100644
--- a/GenshinLyreMidiPlayer.WPF/Core/Keyboard.cs
+++ b/GenshinLyreMidiPlayer.WPF/Core/Keyboard.cs
@@ -10,6 +10,13 @@ namespace GenshinLyreMidiPlayer.WPF.Core;
[SuppressMessage("ReSharper", "CollectionNeverQueried.Global")]
public static class Keyboard
{
+ public enum Instrument
+ {
+ WindsongLyre,
+ FloralZither,
+ VintageLyre
+ }
+
public enum Layout
{
QWERTY,
@@ -21,6 +28,13 @@ public enum Layout
Colemak
}
+ public static readonly Dictionary InstrumentNames = new()
+ {
+ [Instrument.WindsongLyre] = "Windsong Lyre",
+ [Instrument.FloralZither] = "Floral Zither",
+ [Instrument.VintageLyre] = "Vintage Lyre"
+ };
+
public static readonly Dictionary LayoutNames = new()
{
[Layout.QWERTY] = "QWERTY",
@@ -32,17 +46,17 @@ public enum Layout
[Layout.Colemak] = "Colemak"
};
- private static readonly IReadOnlyList QWERTY = new List
+ private static readonly IReadOnlyList AZERTY = new List
{
- VirtualKeyCode.VK_Z,
+ VirtualKeyCode.VK_W,
VirtualKeyCode.VK_X,
VirtualKeyCode.VK_C,
VirtualKeyCode.VK_V,
VirtualKeyCode.VK_B,
VirtualKeyCode.VK_N,
- VirtualKeyCode.VK_M,
+ VirtualKeyCode.OEM_COMMA,
- VirtualKeyCode.VK_A,
+ VirtualKeyCode.VK_Q,
VirtualKeyCode.VK_S,
VirtualKeyCode.VK_D,
VirtualKeyCode.VK_F,
@@ -50,8 +64,8 @@ public enum Layout
VirtualKeyCode.VK_H,
VirtualKeyCode.VK_J,
- VirtualKeyCode.VK_Q,
- VirtualKeyCode.VK_W,
+ VirtualKeyCode.VK_A,
+ VirtualKeyCode.VK_Z,
VirtualKeyCode.VK_E,
VirtualKeyCode.VK_R,
VirtualKeyCode.VK_T,
@@ -59,58 +73,31 @@ public enum Layout
VirtualKeyCode.VK_U
};
- private static readonly IReadOnlyList QWERTZ = new List
+ private static readonly IReadOnlyList Colemak = new List
{
- VirtualKeyCode.VK_Y,
+ VirtualKeyCode.VK_Z,
VirtualKeyCode.VK_X,
VirtualKeyCode.VK_C,
VirtualKeyCode.VK_V,
VirtualKeyCode.VK_B,
- VirtualKeyCode.VK_N,
+ VirtualKeyCode.VK_J,
VirtualKeyCode.VK_M,
VirtualKeyCode.VK_A,
- VirtualKeyCode.VK_S,
VirtualKeyCode.VK_D,
- VirtualKeyCode.VK_F,
VirtualKeyCode.VK_G,
- VirtualKeyCode.VK_H,
- VirtualKeyCode.VK_J,
-
- VirtualKeyCode.VK_Q,
- VirtualKeyCode.VK_W,
VirtualKeyCode.VK_E,
- VirtualKeyCode.VK_R,
VirtualKeyCode.VK_T,
- VirtualKeyCode.VK_Z,
- VirtualKeyCode.VK_U
- };
-
- private static readonly IReadOnlyList AZERTY = new List
- {
- VirtualKeyCode.VK_W,
- VirtualKeyCode.VK_X,
- VirtualKeyCode.VK_C,
- VirtualKeyCode.VK_V,
- VirtualKeyCode.VK_B,
- VirtualKeyCode.VK_N,
- VirtualKeyCode.OEM_COMMA,
+ VirtualKeyCode.VK_H,
+ VirtualKeyCode.VK_Y,
VirtualKeyCode.VK_Q,
+ VirtualKeyCode.VK_W,
+ VirtualKeyCode.VK_K,
VirtualKeyCode.VK_S,
- VirtualKeyCode.VK_D,
VirtualKeyCode.VK_F,
- VirtualKeyCode.VK_G,
- VirtualKeyCode.VK_H,
- VirtualKeyCode.VK_J,
-
- VirtualKeyCode.VK_A,
- VirtualKeyCode.VK_Z,
- VirtualKeyCode.VK_E,
- VirtualKeyCode.VK_R,
- VirtualKeyCode.VK_T,
- VirtualKeyCode.VK_Y,
- VirtualKeyCode.VK_U
+ VirtualKeyCode.VK_O,
+ VirtualKeyCode.VK_I
};
private static readonly IReadOnlyList DVORAK = new List
@@ -194,34 +181,115 @@ public enum Layout
VirtualKeyCode.VK_I
};
- private static readonly IReadOnlyList Colemak = new List
+ private static readonly IReadOnlyList QWERTY = new List
{
VirtualKeyCode.VK_Z,
VirtualKeyCode.VK_X,
VirtualKeyCode.VK_C,
VirtualKeyCode.VK_V,
VirtualKeyCode.VK_B,
- VirtualKeyCode.VK_J,
+ VirtualKeyCode.VK_N,
VirtualKeyCode.VK_M,
VirtualKeyCode.VK_A,
+ VirtualKeyCode.VK_S,
VirtualKeyCode.VK_D,
+ VirtualKeyCode.VK_F,
VirtualKeyCode.VK_G,
- VirtualKeyCode.VK_E,
- VirtualKeyCode.VK_T,
VirtualKeyCode.VK_H,
- VirtualKeyCode.VK_Y,
+ VirtualKeyCode.VK_J,
VirtualKeyCode.VK_Q,
VirtualKeyCode.VK_W,
- VirtualKeyCode.VK_K,
+ VirtualKeyCode.VK_E,
+ VirtualKeyCode.VK_R,
+ VirtualKeyCode.VK_T,
+ VirtualKeyCode.VK_Y,
+ VirtualKeyCode.VK_U
+ };
+
+ private static readonly IReadOnlyList QWERTZ = new List
+ {
+ VirtualKeyCode.VK_Y,
+ VirtualKeyCode.VK_X,
+ VirtualKeyCode.VK_C,
+ VirtualKeyCode.VK_V,
+ VirtualKeyCode.VK_B,
+ VirtualKeyCode.VK_N,
+ VirtualKeyCode.VK_M,
+
+ VirtualKeyCode.VK_A,
VirtualKeyCode.VK_S,
+ VirtualKeyCode.VK_D,
VirtualKeyCode.VK_F,
- VirtualKeyCode.VK_O,
- VirtualKeyCode.VK_I
+ VirtualKeyCode.VK_G,
+ VirtualKeyCode.VK_H,
+ VirtualKeyCode.VK_J,
+
+ VirtualKeyCode.VK_Q,
+ VirtualKeyCode.VK_W,
+ VirtualKeyCode.VK_E,
+ VirtualKeyCode.VK_R,
+ VirtualKeyCode.VK_T,
+ VirtualKeyCode.VK_Z,
+ VirtualKeyCode.VK_U
+ };
+
+ private static readonly List DefaultNotes = new()
+ {
+ 48, // C3
+ 50, // D3
+ 52, // E3
+ 53, // F3
+ 55, // G3
+ 57, // A3
+ 59, // B3
+
+ 60, // C4
+ 62, // D4
+ 64, // E4
+ 65, // F4
+ 67, // G4
+ 69, // A4
+ 71, // B4
+
+ 72, // C5
+ 74, // D5
+ 76, // E5
+ 77, // F5
+ 79, // G5
+ 81, // A5
+ 83 // B5
+ };
+
+ private static readonly List VintageNotes = new()
+ {
+ 48, // C3
+ 50, // D3
+ 51, // Eb3
+ 53, // F3
+ 55, // G3
+ 57, // A3
+ 58, // Bb3
+
+ 60, // C4
+ 62, // D4
+ 63, // Eb4
+ 65, // F4
+ 67, // G4
+ 69, // A4
+ 70, // Bb4
+
+ 72, // C5
+ 74, // Db5
+ 76, // Eb5
+ 77, // F5
+ 79, // G5
+ 80, // Ab5
+ 82 // Bb5
};
- public static IReadOnlyList GetLayout(Layout layout) => layout switch
+ public static IEnumerable GetLayout(Layout layout) => layout switch
{
Layout.QWERTY => QWERTY,
Layout.QWERTZ => QWERTZ,
@@ -232,4 +300,12 @@ public enum Layout
Layout.Colemak => Colemak,
_ => QWERTY
};
+
+ public static IList GetNotes(Instrument instrument) => instrument switch
+ {
+ Instrument.WindsongLyre => DefaultNotes,
+ Instrument.FloralZither => DefaultNotes,
+ Instrument.VintageLyre => VintageNotes,
+ _ => DefaultNotes
+ };
}
\ No newline at end of file
diff --git a/GenshinLyreMidiPlayer.WPF/Core/LyrePlayer.cs b/GenshinLyreMidiPlayer.WPF/Core/LyrePlayer.cs
index 04f2287..f70adfb 100644
--- a/GenshinLyreMidiPlayer.WPF/Core/LyrePlayer.cs
+++ b/GenshinLyreMidiPlayer.WPF/Core/LyrePlayer.cs
@@ -12,58 +12,20 @@ public static class LyrePlayer
{
private static readonly IInputSimulator Input = new InputSimulator();
- private static readonly List LyreNotes = new()
- {
- 48, // C3
- 50, // D3
- 52, // E3
- 53, // F3
- 55, // G3
- 57, // A3
- 59, // B3
-
- 60, // C4
- 62, // D4
- 64, // E4
- 65, // F4
- 67, // G4
- 69, // A4
- 71, // B4
-
- 72, // C5
- 74, // D5
- 76, // E5
- 77, // F5
- 79, // G5
- 81, // A5
- 83 // B5
- };
-
- public static bool TryGetKey(this Layout layout, int noteId, out VirtualKeyCode key)
- {
- var keys = GetLayout(layout);
- return TryGetKey(keys, noteId, out key);
- }
-
- public static bool TryGetKey(this IEnumerable keys, int noteId, out VirtualKeyCode key)
- {
- var keyIndex = LyreNotes.IndexOf(noteId);
- key = keys.ElementAtOrDefault(keyIndex);
-
- return keyIndex != -1;
- }
-
- public static int TransposeNote(int noteId,
+ public static int TransposeNote(
+ Instrument instrument, ref int noteId,
Transpose direction = Transpose.Ignore)
{
+ if (direction is Transpose.Ignore) return noteId;
+ var notes = GetNotes(instrument);
while (true)
{
- if (LyreNotes.Contains(noteId))
+ if (notes.Contains(noteId))
return noteId;
- if (noteId < LyreNotes.First())
+ if (noteId < notes.First())
noteId += 12;
- else if (noteId > LyreNotes.Last())
+ else if (noteId > notes.Last())
noteId -= 12;
else
{
@@ -77,19 +39,37 @@ public static int TransposeNote(int noteId,
}
}
- public static void InteractNote(int noteId, Layout selectedLayout,
- Func action)
+ public static void NoteDown(int noteId, Layout layout, Instrument instrument)
+ => InteractNote(noteId, layout, instrument, Input.Keyboard.KeyDown);
+
+ public static void NoteUp(int noteId, Layout layout, Instrument instrument)
+ => InteractNote(noteId, layout, instrument, Input.Keyboard.KeyUp);
+
+ public static void PlayNote(int noteId, Layout layout, Instrument instrument)
+ => InteractNote(noteId, layout, instrument, Input.Keyboard.KeyPress);
+
+ public static bool TryGetKey(Layout layout, Instrument instrument, int noteId, out VirtualKeyCode key)
{
- if (selectedLayout.TryGetKey(noteId, out var key))
- action.Invoke(key);
+ var keys = GetLayout(layout);
+ var notes = GetNotes(instrument);
+ return TryGetKey(keys, notes, noteId, out key);
}
- public static void NoteDown(int noteId, Layout selectedLayout)
- => InteractNote(noteId, selectedLayout, Input.Keyboard.KeyDown);
+ private static bool TryGetKey(
+ this IEnumerable keys, IList notes,
+ int noteId, out VirtualKeyCode key)
+ {
+ var keyIndex = notes.IndexOf(noteId);
+ key = keys.ElementAtOrDefault(keyIndex);
- public static void NoteUp(int noteId, Layout selectedLayout)
- => InteractNote(noteId, selectedLayout, Input.Keyboard.KeyUp);
+ return keyIndex != -1;
+ }
- public static void PlayNote(int noteId, Layout selectedLayout)
- => InteractNote(noteId, selectedLayout, Input.Keyboard.KeyPress);
+ private static void InteractNote(
+ int noteId, Layout layout, Instrument instrument,
+ Func action)
+ {
+ if (TryGetKey(layout, instrument, noteId, out var key))
+ action.Invoke(key);
+ }
}
\ No newline at end of file
diff --git a/GenshinLyreMidiPlayer.WPF/GenshinLyreMidiPlayer - Backup.WPF.csproj b/GenshinLyreMidiPlayer.WPF/GenshinLyreMidiPlayer - Backup.WPF.csproj
new file mode 100644
index 0000000..c253332
--- /dev/null
+++ b/GenshinLyreMidiPlayer.WPF/GenshinLyreMidiPlayer - Backup.WPF.csproj
@@ -0,0 +1,51 @@
+
+
+
+ WinExe
+ net6.0-windows10.0.22621.0
+ true
+ GenshinLyreMidiPlayer.WPF.App
+ app.manifest
+ 3.1.2
+ item_windsong_lyre.ico
+ enable
+ https://github.com/sabihoshi/GenshinLyreMidiPlayer
+ sabihoshi
+ Genshin Lyre MIDI Player
+
+ sabihoshi
+ A music player that plays MIDI files into Genshin Impact's Windsong Lyre.
+ latest
+ LICENSE.md
+ true
+ 7.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GenshinLyreMidiPlayer.WPF/GenshinLyreMidiPlayer.WPF.csproj b/GenshinLyreMidiPlayer.WPF/GenshinLyreMidiPlayer.WPF.csproj
index 9b9dc1a..3a94bf4 100644
--- a/GenshinLyreMidiPlayer.WPF/GenshinLyreMidiPlayer.WPF.csproj
+++ b/GenshinLyreMidiPlayer.WPF/GenshinLyreMidiPlayer.WPF.csproj
@@ -2,11 +2,11 @@
WinExe
- net6.0-windows10.0.22000.0
+ net6.0-windows10.0.22621.0
true
GenshinLyreMidiPlayer.WPF.App
app.manifest
- 3.1.2
+ 3.2.0
item_windsong_lyre.ico
enable
https://github.com/sabihoshi/GenshinLyreMidiPlayer
@@ -18,7 +18,7 @@
latest
LICENSE.md
true
- 10.0.18362.0
+ 10.0.17763.0
diff --git a/GenshinLyreMidiPlayer.WPF/ModernWPF/Errors/MissingNotesException.cs b/GenshinLyreMidiPlayer.WPF/ModernWPF/Errors/MissingNotesException.cs
new file mode 100644
index 0000000..84785cc
--- /dev/null
+++ b/GenshinLyreMidiPlayer.WPF/ModernWPF/Errors/MissingNotesException.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace GenshinLyreMidiPlayer.WPF.ModernWPF.Errors;
+
+public class MissingNotesException : Exception
+{
+ public MissingNotesException(string message) : base(message) { }
+}
\ No newline at end of file
diff --git a/GenshinLyreMidiPlayer.WPF/ViewModels/LyrePlayerViewModel.cs b/GenshinLyreMidiPlayer.WPF/ViewModels/LyrePlayerViewModel.cs
index 6416372..a2e5e2c 100644
--- a/GenshinLyreMidiPlayer.WPF/ViewModels/LyrePlayerViewModel.cs
+++ b/GenshinLyreMidiPlayer.WPF/ViewModels/LyrePlayerViewModel.cs
@@ -10,6 +10,7 @@
using GenshinLyreMidiPlayer.Data.Properties;
using GenshinLyreMidiPlayer.WPF.Core;
using GenshinLyreMidiPlayer.WPF.ModernWPF.Errors;
+using Melanchall.DryWetMidi.Common;
using Melanchall.DryWetMidi.Core;
using Melanchall.DryWetMidi.Interaction;
using Melanchall.DryWetMidi.Multimedia;
@@ -72,7 +73,7 @@ public LyrePlayerViewModel(IContainer ioc, MainWindowViewModel main)
{
new ErrorContentDialog(e, closeText: "Ignore").ShowAsync();
- SettingsView.CanUseSpeakers = false;
+ SettingsPage.CanUseSpeakers = false;
Settings.UseSpeakers = false;
}
}
@@ -133,7 +134,7 @@ public double SongPosition
private MusicDisplayProperties? Display =>
_player?.SystemMediaTransportControls.DisplayUpdater.MusicProperties;
- private SettingsPageViewModel SettingsView => _main.SettingsView;
+ private SettingsPageViewModel SettingsPage => _main.SettingsView;
private static string PauseIcon => "\xEDB4";
@@ -353,14 +354,12 @@ public void UpdateButtons()
}
}
- private int ApplyNoteSettings(int noteId)
+ private int ApplyNoteSettings(Keyboard.Instrument instrument, int noteId)
{
- noteId -= Playlist.OpenedFile?.History.Key ?? 0;
-
- if (Settings.TransposeNotes)
- noteId = LyrePlayer.TransposeNote(noteId, SettingsView.Transpose.Key);
-
- return noteId;
+ noteId -= Playlist.OpenedFile?.History.Key ?? SettingsPage.KeyOffset;
+ return Settings.TransposeNotes
+ ? LyrePlayer.TransposeNote(instrument, ref noteId, SettingsPage.Transpose.Key)
+ : noteId;
}
private async Task InitializePlayback()
@@ -387,8 +386,10 @@ private async Task InitializePlayback()
}
// Check for notes that cannot be played even after transposing.
- var outOfRange = midi.GetNotes().Where(note =>
- !SettingsView.SelectedLayout.Key.TryGetKey(ApplyNoteSettings(note.NoteNumber), out _));
+ var outOfRange = midi.GetNotes().Where(n => !LyrePlayer.TryGetKey(
+ SettingsPage.SelectedLayout.Key,
+ SettingsPage.SelectedInstrument.Key,
+ ApplyNoteSettings(SettingsPage.SelectedInstrument.Key, n.NoteNumber), out _));
if (Playlist.OpenedFile.History.Transpose is null && outOfRange.Any())
{
@@ -396,14 +397,14 @@ await Application.Current.Dispatcher.Invoke(async () =>
{
var options = new Enum[] { Transpose.Up, Transpose.Down };
var exceptionDialog = new ErrorContentDialog(
- new IndexOutOfRangeException(
- "Some notes cannot be played by the Lyre because it is missing Sharps & Flats. " +
+ new MissingNotesException(
+ "Some notes cannot be played by this instrument, and may play incorrectly. " +
"This can be solved by snapping to the nearest semitone."),
options, "Ignore");
var result = await exceptionDialog.ShowAsync();
- SettingsView.Transpose = result switch
+ SettingsPage.Transpose = result switch
{
ContentDialogResult.Primary => TransposeNames.ElementAt(1),
ContentDialogResult.Secondary => TransposeNames.ElementAt(2),
@@ -415,7 +416,7 @@ await Application.Current.Dispatcher.Invoke(async () =>
var playback = midi.GetPlayback();
Playback = playback;
- playback.Speed = SettingsView.SelectedSpeed.Speed;
+ playback.Speed = SettingsPage.SelectedSpeed.Speed;
playback.InterruptNotesOnStop = true;
playback.Finished += (_, _) => { Next(); };
playback.EventPlayed += OnNoteEvent;
@@ -474,8 +475,13 @@ private void OnNoteEvent(object? sender, MidiEventReceivedEventArgs e)
private void PlayNote(NoteEvent noteEvent)
{
+ var layout = SettingsPage.SelectedLayout.Key;
+ var instrument = SettingsPage.SelectedInstrument.Key;
+ var note = ApplyNoteSettings(instrument, noteEvent.NoteNumber);
+
if (Settings.UseSpeakers)
{
+ noteEvent.NoteNumber = new((byte) note);
_speakers?.SendEvent(noteEvent);
return;
}
@@ -486,21 +492,18 @@ private void PlayNote(NoteEvent noteEvent)
return;
}
- var layout = SettingsView.SelectedLayout.Key;
- var note = ApplyNoteSettings(noteEvent.NoteNumber);
-
switch (noteEvent.EventType)
{
case MidiEventType.NoteOff:
- LyrePlayer.NoteUp(note, layout);
+ LyrePlayer.NoteUp(note, layout, instrument);
break;
case MidiEventType.NoteOn when noteEvent.Velocity <= 0:
return;
case MidiEventType.NoteOn when Settings.HoldNotes:
- LyrePlayer.NoteDown(note, layout);
+ LyrePlayer.NoteDown(note, layout, instrument);
break;
case MidiEventType.NoteOn:
- LyrePlayer.PlayNote(note, layout);
+ LyrePlayer.PlayNote(note, layout, instrument);
break;
}
}
diff --git a/GenshinLyreMidiPlayer.WPF/ViewModels/PianoSheetViewModel.cs b/GenshinLyreMidiPlayer.WPF/ViewModels/PianoSheetViewModel.cs
index 7d18a07..3bc16da 100644
--- a/GenshinLyreMidiPlayer.WPF/ViewModels/PianoSheetViewModel.cs
+++ b/GenshinLyreMidiPlayer.WPF/ViewModels/PianoSheetViewModel.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using GenshinLyreMidiPlayer.Data.Properties;
using GenshinLyreMidiPlayer.WPF.Core;
using Melanchall.DryWetMidi.Interaction;
using PropertyChanged;
@@ -11,6 +12,8 @@ namespace GenshinLyreMidiPlayer.WPF.ViewModels;
public class PianoSheetViewModel : Screen
{
+ private static readonly Settings Settings = Settings.Default;
+
private readonly MainWindowViewModel _main;
private uint _bars = 1;
private uint _beats;
@@ -63,6 +66,7 @@ public void Update()
return;
var layout = SettingsPage.SelectedLayout.Key;
+ var instrument = SettingsPage.SelectedInstrument.Key;
// Ticks is too small so it is not included
var split = PlaylistView.OpenedFile.Split(Bars, Beats, 0);
@@ -78,11 +82,12 @@ public void Update()
foreach (var note in notes)
{
- var offset = note.NoteNumber - SettingsPage.KeyOffset;
+ var id = note.NoteNumber - SettingsPage.KeyOffset;
var transpose = SettingsPage.Transpose.Key;
- var id = LyrePlayer.TransposeNote(offset, transpose);
+ if (Settings.TransposeNotes)
+ LyrePlayer.TransposeNote(instrument, ref id, transpose);
- if (!layout.TryGetKey(id, out var key)) continue;
+ if (!LyrePlayer.TryGetKey(layout, instrument, id, out var key)) continue;
var difference = note.Time - last;
var dotCount = difference / Shorten;
diff --git a/GenshinLyreMidiPlayer.WPF/ViewModels/SettingsPageViewModel.cs b/GenshinLyreMidiPlayer.WPF/ViewModels/SettingsPageViewModel.cs
index 028f4db..8967ab1 100644
--- a/GenshinLyreMidiPlayer.WPF/ViewModels/SettingsPageViewModel.cs
+++ b/GenshinLyreMidiPlayer.WPF/ViewModels/SettingsPageViewModel.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
+using System.Net.Http.Json;
using System.Reflection;
using System.Text.Json;
using System.Threading;
@@ -30,8 +31,6 @@ namespace GenshinLyreMidiPlayer.WPF.ViewModels;
public class SettingsPageViewModel : Screen
{
- private static readonly Settings Settings = Settings.Default;
-
public static readonly Dictionary TransposeNames = new()
{
[Ignore] = "Ignore notes",
@@ -39,6 +38,7 @@ public class SettingsPageViewModel : Screen
[Down] = "Shift one semitone down"
};
+ private static readonly Settings Settings = Settings.Default;
private readonly IContainer _ioc;
private readonly IEventAggregator _events;
private readonly MainWindowViewModel _main;
@@ -152,6 +152,8 @@ public int KeyOffset
public int MinOffset => KeyOffsets.Keys.Min();
+ public KeyValuePair SelectedInstrument { get; set; }
+
public KeyValuePair SelectedLayout { get; set; }
public KeyValuePair Transpose { get; set; } = TransposeNames.First();
@@ -338,15 +340,14 @@ private bool TrySetLocation(string? location)
"https://api.github.com/repos/sabihoshi/GenshinLyreMidiPlayer/releases");
var productInfo = new ProductInfoHeaderValue("GenshinLyreMidiPlayer", ProgramVersion.ToString());
-
request.Headers.UserAgent.Add(productInfo);
var response = await client.SendAsync(request);
- var versions = JsonSerializer.Deserialize>(await response.Content.ReadAsStringAsync());
+ var versions = await response.Content.ReadFromJsonAsync>();
return versions?
.OrderByDescending(v => v.Version)
- .FirstOrDefault(v => !v.Draft && !v.Prerelease || IncludeBetaUpdates);
+ .FirstOrDefault(v => (!v.Draft && !v.Prerelease) || IncludeBetaUpdates);
}
[UsedImplicitly]
@@ -396,6 +397,13 @@ private void OnSelectedLayoutIndexChanged()
Settings.Modify(s => s.SelectedLayout = layout);
}
+ [UsedImplicitly]
+ private void OnSelectedInstrumentIndexChanged()
+ {
+ var instrument = (int) SelectedInstrument.Key;
+ Settings.Modify(s => s.SelectedInstrument = instrument);
+ }
+
[UsedImplicitly]
private void OnSelectedSpeedChanged() => _events.Publish(this);
diff --git a/GenshinLyreMidiPlayer.WPF/Views/SettingsPageView.xaml b/GenshinLyreMidiPlayer.WPF/Views/SettingsPageView.xaml
index 9f80fea..4ac11ee 100644
--- a/GenshinLyreMidiPlayer.WPF/Views/SettingsPageView.xaml
+++ b/GenshinLyreMidiPlayer.WPF/Views/SettingsPageView.xaml
@@ -52,14 +52,6 @@
-
-
-
-
+
+
+
+
@@ -76,6 +76,14 @@
SelectedItem="{Binding Transpose}"
DisplayMemberPath="Value" />
+
+
+
+