Midi-dot-net 声音播放了两次

Midi-dot-net sounds played twice

首先,我不是 PRO 程序员,只是一个对优秀的 Midi-Dot-Net 库有一点问题的学生。

我使用 Midi-Dot-Net 库在 Visual Studio 中用 C# 语言编写了一个简单的应用程序。但是我遇到了一个非常令人困惑的问题。

我在 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));
    }
}

所以,我放置了新的字符串并将其命名为 nutka,nutka 将收到我的 USB MIDI 键盘上按下的音符的名称。然后我放置 IF 语句,并将 nutka 与 "A0"(键盘上的第一个音符)进行比较。

然后如果它是 "A0" 我按下我的 outputDevice 播放特定音符。它会播放,但会播放两次,一次 - 当我按下键盘上的键(带有音符 A0)时,第二次 - 当我释放该键时。

我在 public void NoteOn(NoteOnMessage msg) 上做了一个断点,发现一个应用程序 returns 在这里播放了两次,并播放了两次那个音符,仍然不知道为什么。

还有一点,有一个方法public void NoteOff(NoteOffMessage message),但好像不行。

实在想不通,正在寻求帮助。

更新 ... 更新 ... 更新

出现另一个问题(第一部分已解决,感谢 CLChris Dunaway 的建议和逐步 Justin解释)。

谢谢贾斯汀 :) 我认为没有任何问题的生活是不可能的 :)

使用 clock.Schedule 我只能演奏 MIDI 声音,但我想演奏示例钢琴音符(wav 文件格式)和 4-5 几周我的大学将帮助我为每个音符录制自己的钢琴声音。我也想同时玩

我以为一切都会好起来的,但现在...同时播放有问题。我试图检查三种可能性:

1) 我试图从我拥有的基本音符库中演奏钢琴音色,并为此使用了 SoundPlayer:

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

我将它用于每个具有不同 SoundPlayer 名称(取决于音符名称)的音符语句,我注意到的是 - 我无法同时播放音符。

2) 所以我使用了下一个 WMP 库和 WindowsMediaPlayer:

例如:

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

好的...它同时播放,但看起来我演奏的音符越多或我只是播放一首歌,我得到的延迟就越大,最后我的程序卡在播放任何东西...

3) 我正在尝试使用 Microsoft.DirectX.AudioVideoPlayback:

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

我启动了我的程序,按下一个键,砰!崩溃并显示错误消息:

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)

当然我没有忘记使用:

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

现在我不知道我能做些什么 - 我需要有经验的人的帮助:)

MIDI 1.0 详细规范说:

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.

上展开,这是 可能 发生的一系列事件:

  1. 您按下 MIDI 键盘上的一个键,它会发出 Note On message, with a Pitch of A0, and a velocity(确切的速度可能每次都不同)。
  2. 您的代码收到此消息,并且由于它与您的 if 语句匹配,因此发出 Note On message, with a pitch of A0, and a velocity of 80.

这就是它变得棘手的地方。某些 MIDI 设备会在您释放按键时发送具有相同音高的相应 Note Off 消息。其他设备将发送第二个 Note On 具有相同音高但速度为 0 的消息。这两种类型的消息在(或应该)功能上是等效的,并且每个设备都可以停止播放音符(甚至两者)。所以,

  1. 您松开键盘上的键,发出 Note On message, with a Pitch of A0, and a Velocity of 0
  2. 您的代码收到此消息,并且由于它也与您的 if 语句匹配,因此发出 Note On message, with a pich of A0, and a velocity of 80.

由于力度为 0 的音符开启也是音符关闭,发生的情况是您的代码将键盘的 "Note Off" 变回音符开启,从而播放两次声音。

作为 ,您需要通过测试力度为 0 来确定音符开启是否实际上是 "Note Off"。

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