Midi-dot-net sounds played twice

506 views Asked by At

Firstable I am not a PRO programmer but only a student who hava a little problem with an excelent library Midi-Dot-Net.

I use a Midi-Dot-Net library to write a simple application in Visual Studio in C# language. But I stuck on a very confusing problem.

I placed a little code into Form1.cs

public void NoteOn(NoteOnMessage msg) {
    if (InvokeRequired) {
        BeginInvoke(noteOnHandler, msg);
        return;
    }

     inputStatusLabel.Text = String.Format("{0}", msg.Pitch);
     String nutka = inputStatusLabel.Text;

    if (nutka == "A0") {
        clock.Schedule(new NoteOnMessage(outputDevice, Channel.Channel1, Pitch.A0, 80, 2));
    }
}

So, I placed new String and called it nutka, and nutka will receive name of the pressed note on my USB MIDI Keyboard. Then I placed IF statment, and compared nutka to "A0" (first note on the keyboard).

Then if it's "A0" I pressed my outputDevice plays specific note. And it plays but it plays twice, one - when I press key (with note A0) on keyboard and second time - when I release that key.

I did a breakpoint on public void NoteOn(NoteOnMessage msg) and noticed that an application returns here twice and plays twice that note, still don't know why.

One more thing, there is a method public void NoteOff(NoteOffMessage message), but it seems not working.

I really can't figure it out, and I'm looking for any help.

UPDATE ... UPDATE ... UPDATE

Another problem appears (the first part was resolved thanks to CL and Chris Dunaway advice and step-by-step Justin explanation).

Thank you Justin :) i see life without any problems is not possible :)

With clock.Schedule i can play only the MIDI sound but i want to play example piano notes (wav file format) and in 4-5 weeks my college will help me recording my own piano sounds for every note. I also want to play them simultaneous.

I thought everything will be just fine and now... got problem with simultaneous playing. I was trying to check three possibilities:

1) I was trying to play piano sounds from basic notes library i have and use SoundPlayer for it:

SoundPlayer noteA0 = new SoundPlayer(Properties.Resources.A0);
noteA0.Play();

i use it for every note statement with different SoundPlayer name (depend on note name) and what i noticed is - i can't play notes simultaneously.

2) so i used next WMP library and WindowsMediaPlayer:

for example:

var noteA0 = new WMPLib.WindowsMediaPlayer();
noteA0.URL = @"c:\sounds\piano\A0.wav";

Ok... it plays simultaneous but it looks like the more notes i play or i just play a song the bigger latency i got and finnaly my programm stuck on playing anything...

3) i was trying to use Microsoft.DirectX.AudioVideoPlayback:

Audio noteA1 = new Audio(@"C:\sounds\piano\A1.wav");
noteA1.Play();

i started my programm, pressed a key and boom! crashed with an error message:

An unhandled exception of type 'System.BadImageFormatException' occurred in Midi.dll
Additional information: Could not load file or assembly 'Microsoft.DirectX.AudioVideoPlayback.dll' or one of its dependencies. 
It is not a valid Win32 application. (Exception from HRESULT: 0x800700C1)

Of course i didn't forget to use:

using System.Media;
using Microsoft.DirectX.AudioVideoPlayback;
using Microsoft.DirectX;

Right now i have no idea what can i do more and again - i need a help of an experienced person :)

2

There are 2 answers

3
Justin Ryan On BEST ANSWER

Expanding on CL.'s answer, here is the sequence of events that is probably happening:

  1. You push a key on your MIDI keyboard which sends out a Note On message, with a Pitch of A0, and a velocity (the exact velocity may vary every time).
  2. Your code receives this and, since it matches your if statement, sends out a Note On message, with a pitch of A0, and a velocity of 80.

Here's where it gets tricky. Some MIDI devices send a corresponding Note Off message with the same Pitch when you release the key. Other devices will send a second Note On message with the same Pitch, but with a Velocity of 0. These two types of message are (or should be) functionally equivalent, and each device can do either to stop a note playing (or even both). So,

  1. You release the key on your keyboard which sends out a Note On message, with a Pitch of A0, and a Velocity of 0.
  2. Your code receives this and, since it also matches your if statement, sends out a Note On message, with a pich of A0, and a velocity of 80.

Since a Note On with a Velocity of 0 is also a Note Off, what happens is your code is turning your keyboard's "Note Off" back into a Note On, thus playing the sound twice.

As Chris Dunaway suggested, you need to determine if a Note On is actually a "Note Off" by testing for a Velocity of 0.

    if (nutka == "A0" && msg.Velocity != 0) {
        clock.Schedule(new NoteOnMessage(outputDevice, Channel.Channel1, Pitch.A0, 80, 2));
    }
2
CL. On

The MIDI 1.0 Detailed Specification says:

MIDI provides two roughly equivalent means of turning off a note (voice). A note may be turned off either by sending a Note-Off message for the same note number and channel, or by sending a Note-On message for that note and channel with a velocity value of zero. The advantage to using "Note-On at zero velocity" is that it can avoid sending additional status bytes when Running Status is employed.

Due to this efficiency, sending Note-On messages with velocity values of zero is the most commonly used method. However, some keyboard instruments implement release velocity where a Note-Off code (8nH) accompanied by a "velocity off" byte is used. A receiver must be capable of recognizing either method of turning off a note, and should treat them identically.