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" /> + + + +