When I press the keys on the MIDI keyboard very quickly, my application is unstable, silence may occur and all WAV-files will be played at once in a few seconds. It works well if you don't play too fast.
What's wrong with my C# code? What I need to change to make the program stable with fast playing on a MIDI keyboard?
using NAudio.Wave;
using NAudio.Midi;
namespace MidiReader
{
public class MidiPlayer
{
private string folder;
private Dictionary<int, string> noteMappings;
private MidiIn midiIn;
private Dictionary<int, WaveOutEvent> players;
public void SetMessageText(string text)
{
folder = text;
}
public MidiPlayer(Dictionary<int, string> noteMappings, string folder)
{
this.noteMappings = noteMappings;
this.midiIn = new MidiIn(3);
this.midiIn.MessageReceived += MidiIn_MessageReceived;
this.folder = folder;
this.players = new Dictionary<int, WaveOutEvent>();
}
public void Start()
{
this.midiIn.Start();
Console.WriteLine("Press any key to stop.");
Console.ReadKey();
}
private void MidiIn_MessageReceived(object sender, MidiInMessageEventArgs e)
{
var midiMessage = e.MidiEvent;
if (midiMessage.CommandCode == MidiCommandCode.NoteOn)
{
var noteOnEvent = (NoteOnEvent)midiMessage;
int noteNumber = noteOnEvent.NoteNumber;
if (noteMappings.ContainsKey(noteNumber))
{
folder = TelegramBot.SetFolder();
string fileName = Path.Combine(folder, noteMappings[noteNumber]);
Console.WriteLine(fileName);
PlayWavFileAsync(fileName);
}
}
}
public async Task PlayWavFileAsync(string fileName, int noteNumber)
{
Console.WriteLine("Logged into PlayWavFile");
await Task.Run(async () =>
{
using (var audioFile = new AudioFileReader(fileName))
{
var player = new WaveOutEvent();
player.Init(audioFile);
try
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Logged into try");
player.Play();
Console.ResetColor();
}
catch
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(new InvalidOperationException("Must call Init first"));
Console.ResetColor();
}
Task.Delay(1000).Wait();
}
});
}
}
}
I will be glad to see your tips.
You are opening a separate WaveOut device for every sound you play. It is much better to have a single audio output device and mix in sounds as you need to play them. You could use an approach like I describe here, which mixes the audio with
MixingSampleProvider: https://www.markheath.net/post/fire-and-forget-audio-playback-with