-
-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add feature for outputting MIDI to a Piano Sheet
- Loading branch information
Showing
8 changed files
with
185 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
GenshinLyreMidiPlayer.WPF/ViewModels/PianoSheetViewModel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Text; | ||
using GenshinLyreMidiPlayer.WPF.Core; | ||
using Melanchall.DryWetMidi.Interaction; | ||
using PropertyChanged; | ||
using Stylet; | ||
|
||
namespace GenshinLyreMidiPlayer.WPF.ViewModels | ||
{ | ||
public class PianoSheetViewModel : Screen | ||
{ | ||
private uint _bars = 1; | ||
private uint _beats; | ||
private uint _shorten = 1; | ||
|
||
public PianoSheetViewModel(SettingsPageViewModel settingsPage, | ||
PlaylistViewModel playlistView) | ||
{ | ||
SettingsPage = settingsPage; | ||
PlaylistView = playlistView; | ||
} | ||
|
||
[OnChangedMethod(nameof(Update))] public char Delimeter { get; set; } = '.'; | ||
|
||
public PlaylistViewModel PlaylistView { get; } | ||
|
||
public SettingsPageViewModel SettingsPage { get; } | ||
|
||
public string Result { get; private set; } | ||
|
||
[OnChangedMethod(nameof(Update))] | ||
public uint Bars | ||
{ | ||
get => _bars; | ||
set => SetAndNotify(ref _bars, Math.Max(value, 0)); | ||
} | ||
|
||
[OnChangedMethod(nameof(Update))] | ||
public uint Beats | ||
{ | ||
get => _beats; | ||
set => SetAndNotify(ref _beats, Math.Max(value, 0)); | ||
} | ||
|
||
[OnChangedMethod(nameof(Update))] | ||
public uint Shorten | ||
{ | ||
get => _shorten; | ||
set => SetAndNotify(ref _shorten, Math.Max(value, 1)); | ||
} | ||
|
||
protected override void OnActivate() { Update(); } | ||
|
||
public void Update() | ||
{ | ||
if (PlaylistView.OpenedFile is null) | ||
return; | ||
|
||
if (Bars == 0 && Beats == 0) | ||
return; | ||
|
||
var layout = SettingsPage.SelectedLayout.Key; | ||
|
||
// Ticks is too small so it is not included | ||
var split = PlaylistView.OpenedFile.Split(Bars, Beats, 0); | ||
|
||
var sb = new StringBuilder(); | ||
foreach (var bar in split) | ||
{ | ||
var notes = bar.GetNotes(); | ||
if (notes.Count == 0) | ||
continue; | ||
|
||
var last = 0; | ||
|
||
foreach (var note in notes) | ||
{ | ||
var id = LyrePlayer.TransposeNote(note.NoteNumber); | ||
if (layout.TryGetKey(id, out var key)) | ||
{ | ||
var difference = note.Time - last; | ||
var dotCount = difference / Shorten; | ||
|
||
sb.Append(new string(Delimeter, (int) dotCount)); | ||
sb.Append(key.ToString().Last()); | ||
|
||
last = (int) note.Time; | ||
} | ||
} | ||
|
||
sb.AppendLine(); | ||
} | ||
|
||
Result = sb.ToString(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<UserControl | ||
x:Class="GenshinLyreMidiPlayer.WPF.Views.PianoSheetView" | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
|
||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" | ||
|
||
xmlns:ui="http://schemas.modernwpf.com/2019" | ||
xmlns:s="https://github.com/canton7/Stylet" | ||
|
||
xmlns:viewModels="clr-namespace:GenshinLyreMidiPlayer.WPF.ViewModels" | ||
xmlns:core="clr-namespace:GenshinLyreMidiPlayer.WPF.Core" | ||
xmlns:properties="clr-namespace:GenshinLyreMidiPlayer.Data.Properties;assembly=GenshinLyreMidiPlayer.Data" | ||
|
||
d:DataContext="{d:DesignInstance Type=viewModels:PianoSheetViewModel}"> | ||
|
||
<UserControl.Resources> | ||
<properties:Settings x:Key="Settings" /> | ||
</UserControl.Resources> | ||
|
||
<Grid> | ||
<Grid.RowDefinitions> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="*" /> | ||
<RowDefinition Height="Auto" /> | ||
</Grid.RowDefinitions> | ||
|
||
<ui:SimpleStackPanel Grid.Row="0"> | ||
<TextBlock VerticalAlignment="Center"> | ||
Current song: <Run Text="{Binding PlaylistView.OpenedFile.Title, Mode=OneWay, FallbackValue=Nothing}" /> | ||
</TextBlock> | ||
|
||
<ui:SimpleStackPanel Orientation="Horizontal"> | ||
<GroupBox Header="Delimeter"> | ||
<TextBox Text="{Binding Delimeter, UpdateSourceTrigger=PropertyChanged}" /> | ||
</GroupBox> | ||
|
||
<GroupBox Header="Layout"> | ||
<ComboBox | ||
ItemsSource="{x:Static core:Keyboard.LayoutNames}" | ||
SelectedItem="{Binding SettingsPage.SelectedLayout}" | ||
SelectedIndex="{Binding Default.SelectedLayout, Source={StaticResource Settings}}" | ||
DisplayMemberPath="Value" /> | ||
</GroupBox> | ||
</ui:SimpleStackPanel> | ||
|
||
<ui:SimpleStackPanel Orientation="Horizontal"> | ||
<GroupBox Header="Split Size"> | ||
<ui:SimpleStackPanel Orientation="Horizontal"> | ||
<ui:NumberBox Header="Bars" Value="{Binding Bars}" /> | ||
<ui:NumberBox Header="Beats" Value="{Binding Beats}" /> | ||
<ui:NumberBox Header="Shorten every" ToolTip="This will divide the delimiter by this number" | ||
Minimum="1" Value="{Binding Shorten}" /> | ||
</ui:SimpleStackPanel> | ||
</GroupBox> | ||
</ui:SimpleStackPanel> | ||
</ui:SimpleStackPanel> | ||
|
||
<TextBox Grid.Row="1" Text="{Binding Result, Mode=OneWay}" IsReadOnly="True" Margin="0,10" /> | ||
|
||
<ui:SimpleStackPanel Grid.Row="2" Orientation="Horizontal"> | ||
<Button Content="Copy" /> | ||
<Button Content="Refresh" Command="{s:Action Update}" /> | ||
</ui:SimpleStackPanel> | ||
</Grid> | ||
</UserControl> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters