Skip to content

Commit 6d728ad

Browse files
committed
Added SoundFonts support and sustain pedal button state
1 parent f54d624 commit 6d728ad

18 files changed

Lines changed: 453 additions & 35 deletions

Openthesia/Drawings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ public class Drawings
99
public static IntPtr C;
1010
public static IntPtr CSharp;
1111
public static IntPtr CSharpWhite;
12+
public static IntPtr SustainPedalOff;
13+
public static IntPtr SustainPedalOn;
1214

1315
public static void RenderMatrixBackground()
1416
{

Openthesia/IOHandle.cs

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using Melanchall.DryWetMidi.Common;
2-
using Melanchall.DryWetMidi.Core;
1+
using Melanchall.DryWetMidi.Core;
32
using Melanchall.DryWetMidi.Multimedia;
43

54
namespace Openthesia;
@@ -9,6 +8,12 @@ public class IOHandle
98
public static List<int> PressedKeys { get; private set; } = new();
109

1110
public static List<NoteRect> NoteRects = new();
11+
12+
private static HashSet<int> _sustainedNotes = new(); // Keeps track of sustained notes
13+
14+
private static bool _sustainPedalActive = false;
15+
public static bool SustainPedalActive => _sustainPedalActive;
16+
1217
public struct NoteRect
1318
{
1419
public int KeyNum;
@@ -22,6 +27,13 @@ public struct NoteRect
2227

2328
private static void OnKeyPress(NoteOnEvent ev)
2429
{
30+
// Check if sustain pedal is active
31+
if (_sustainPedalActive)
32+
{
33+
// add to sustained notes
34+
_sustainedNotes.Add(ev.NoteNumber);
35+
}
36+
2537
if (Router.Route == Router.Routes.PlayMode)
2638
{
2739
bool isBlack = ev.GetNoteName().ToString().EndsWith("Sharp");
@@ -36,26 +48,55 @@ private static void OnKeyPress(NoteOnEvent ev)
3648
};
3749
NoteRects.Add(note);
3850
}
39-
51+
//MidiPlayer.RealTimeSoundFontPlayer.Synthesizer.ProcessMidiMessage(0, 144 /*NOTE ON*/, ev.NoteNumber, ev.Velocity);
52+
MidiPlayer.SoundFontEngine?.PlayNote(0, ev.NoteNumber, ev.Velocity);
4053
PressedKeys.Add(ev.NoteNumber);
4154
}
4255

4356
private static void OnKeyRelease(NoteOffEvent ev)
4457
{
58+
if (_sustainPedalActive)
59+
{
60+
// If sustain pedal is active, don't stop the note immediately
61+
_sustainedNotes.Add(ev.NoteNumber);
62+
}
63+
else
64+
{
65+
// If sustain pedal is not active, stop the note immediately
66+
//MidiPlayer.RealTimeSoundFontPlayer.Synthesizer.ProcessMidiMessage(0, 128, ev.NoteNumber, ev.Velocity);
67+
MidiPlayer.SoundFontEngine?.StopNote(0, ev.NoteNumber);
68+
}
69+
4570
if (Router.Route == Router.Routes.PlayMode)
4671
{
4772
int index = NoteRects.FindIndex(x => x.KeyNum == ev.NoteNumber && !x.WasReleased);
4873
var n = NoteRects[index];
4974
//var n = NoteRects.Find(x => x.KeyNum == ev.NoteNumber && !x.WasReleased);
5075
//var n = NoteRects[NoteRects.Count - 1];
5176
n.WasReleased = true;
52-
n.FinalTime = n.Time;
77+
n.FinalTime = n.Time;
5378
NoteRects[index] = n;
5479
}
55-
80+
5681
PressedKeys.Remove(ev.NoteNumber);
5782
}
5883

84+
private static void OnSustainPedalOn()
85+
{
86+
_sustainPedalActive = true;
87+
}
88+
89+
private static void OnSustainPedalOff()
90+
{
91+
_sustainPedalActive = false;
92+
// Stop all sustained notes when the sustain pedal is released
93+
foreach (var note in _sustainedNotes)
94+
{
95+
MidiPlayer.SoundFontEngine?.StopNote(0, note);
96+
}
97+
_sustainedNotes.Clear();
98+
}
99+
59100
public static void OnEventReceived(object sender, MidiEventReceivedEventArgs e)
60101
{
61102
var eType = e.Event.EventType;
@@ -68,6 +109,20 @@ public static void OnEventReceived(object sender, MidiEventReceivedEventArgs e)
68109
case MidiEventType.NoteOff:
69110
OnKeyRelease((NoteOffEvent)e.Event);
70111
break;
112+
case MidiEventType.ControlChange:
113+
var controlChangeEvent = (ControlChangeEvent)e.Event;
114+
if (controlChangeEvent.ControlNumber == 64) // 64 is the sustain pedal
115+
{
116+
if (controlChangeEvent.ControlValue > 63) // Sustain pedal ON (value greater than 63)
117+
{
118+
OnSustainPedalOn();
119+
}
120+
else // Sustain pedal OFF (value <= 63)
121+
{
122+
OnSustainPedalOff();
123+
}
124+
}
125+
break;
71126
}
72127
}
73128

@@ -87,6 +142,20 @@ public static void OnEventReceived(object sender, MidiEventPlayedEventArgs e)
87142
case MidiEventType.NoteOff:
88143
OnKeyRelease((NoteOffEvent)e.Event);
89144
break;
145+
case MidiEventType.ControlChange:
146+
var controlChangeEvent = (ControlChangeEvent)e.Event;
147+
if (controlChangeEvent.ControlNumber == 64) // 64 is the sustain pedal
148+
{
149+
if (controlChangeEvent.ControlValue > 63) // Sustain pedal ON (value greater than 63)
150+
{
151+
OnSustainPedalOn();
152+
}
153+
else // Sustain pedal OFF (value <= 63)
154+
{
155+
OnSustainPedalOff();
156+
}
157+
}
158+
break;
90159
}
91160
}
92161

Openthesia/ImGuiController.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,26 @@ public static void LoadImages(GraphicsDevice _gd, ImGuiController _controller)
174174
var img4 = new ImageSharpTexture(stream4);
175175
var dimg4 = img4.CreateDeviceTexture(_gd, _gd.ResourceFactory);
176176
Drawings.CSharpWhite = _controller.GetOrCreateImGuiBinding(_gd.ResourceFactory, dimg4);
177+
178+
// Sustain pedal off
179+
TryGetEmbeddedResourceBytes("SustainPedalOff", out var sustainPedalOff);
180+
Stream stream5 = new MemoryStream();
181+
stream5.Write(sustainPedalOff);
182+
stream5.Position = 0;
183+
184+
var img5 = new ImageSharpTexture(stream5);
185+
var dimg5 = img5.CreateDeviceTexture(_gd, _gd.ResourceFactory);
186+
Drawings.SustainPedalOff = _controller.GetOrCreateImGuiBinding(_gd.ResourceFactory, dimg5);
187+
188+
// Sustain pedal on
189+
TryGetEmbeddedResourceBytes("SustainPedalOn", out var sustainPedalOn);
190+
Stream stream6 = new MemoryStream();
191+
stream6.Write(sustainPedalOn);
192+
stream6.Position = 0;
193+
194+
var img6 = new ImageSharpTexture(stream6);
195+
var dimg6 = img6.CreateDeviceTexture(_gd, _gd.ResourceFactory);
196+
Drawings.SustainPedalOn = _controller.GetOrCreateImGuiBinding(_gd.ResourceFactory, dimg6);
177197
}
178198

179199
public void WindowResized(int width, int height)

Openthesia/LeftRightData.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
6-
using System.Xml.Serialization;
7-
using Vanara.PInvoke;
1+
using System.Xml.Serialization;
82

93
namespace Openthesia;
104

Openthesia/MidiEditing.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
using Melanchall.DryWetMidi.Interaction;
2-
using System;
3-
using System.Collections.Generic;
4-
using System.Linq;
5-
using System.Text;
6-
using System.Text.Json.Nodes;
7-
using System.Threading.Tasks;
8-
using System.Xml.Serialization;
1+
using System.Xml.Serialization;
92
using Vanara.PInvoke;
103

114
namespace Openthesia;

Openthesia/MidiFileView.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
using IconFonts;
22
using ImGuiNET;
3-
using Melanchall.DryWetMidi.Interaction;
4-
using System;
5-
using System.Collections.Generic;
6-
using System.Linq;
73
using System.Numerics;
8-
using System.Text;
9-
using System.Threading.Tasks;
10-
using Vulkan.Xlib;
114

125
namespace Openthesia;
136

Openthesia/MidiList.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using IconFonts;
22
using ImGuiNET;
3-
using Melanchall.DryWetMidi.Core;
4-
using Melanchall.DryWetMidi.Interaction;
53
using System.Numerics;
64

75
namespace Openthesia;

Openthesia/MidiPlayer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace Openthesia;
55

66
public class MidiPlayer
77
{
8+
public static SoundFontPlayer SoundFontEngine;
89
public static Playback Playback;
910
public static MetricTimeSpan Time;
1011
public static float Seconds;

Openthesia/MidiSampleProvider.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using MeltySynth;
2+
using NAudio.Wave;
3+
4+
namespace Openthesia;
5+
6+
public class MidiSampleProvider : ISampleProvider
7+
{
8+
private static WaveFormat format = WaveFormat.CreateIeeeFloatWaveFormat(44100, 2);
9+
private Synthesizer _synthesizer;
10+
11+
public MidiSampleProvider(Synthesizer synthesizer)
12+
{
13+
_synthesizer = synthesizer;
14+
}
15+
16+
public int Read(float[] buffer, int offset, int count)
17+
{
18+
_synthesizer.RenderInterleaved(buffer.AsSpan(offset, count));
19+
return count;
20+
}
21+
public WaveFormat WaveFormat => format;
22+
}

Openthesia/Openthesia.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
<None Remove="Resources\imgui-vertex.hlsl.bytes" />
1919
<None Remove="Resources\Keys\wsharp.png" />
2020
<None Remove="Resources\logoimg.png" />
21+
<None Remove="Resources\SustainPedalOff.png" />
22+
<None Remove="Resources\SustainPedalOn.png" />
2123
</ItemGroup>
2224

2325
<ItemGroup>
@@ -33,11 +35,15 @@
3335
<EmbeddedResource Include="Resources\imgui-vertex.hlsl.bytes" />
3436
<EmbeddedResource Include="Resources\Keys\wsharp.png" />
3537
<EmbeddedResource Include="Resources\logoimg.png" />
38+
<EmbeddedResource Include="Resources\SustainPedalOff.png" />
39+
<EmbeddedResource Include="Resources\SustainPedalOn.png" />
3640
</ItemGroup>
3741

3842
<ItemGroup>
3943
<PackageReference Include="ImGui.NET" Version="1.90.1.1" />
4044
<PackageReference Include="Melanchall.DryWetMidi" Version="7.1.0" />
45+
<PackageReference Include="MeltySynth" Version="2.4.1" />
46+
<PackageReference Include="NAudio" Version="2.2.1" />
4147
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
4248
<PackageReference Include="Syroot.Windows.IO.KnownFolders" Version="1.3.0" />
4349
<PackageReference Include="Vanara.PInvoke.User32" Version="3.4.17" />

0 commit comments

Comments
 (0)