Midi-dot-net声音播放两次

时间:2015-06-19 08:02:28

标签: c# midi midi-instrument

Firstable我不是一名专业程序员,而只是一名学生,他在一个优秀的图书馆Midi-Dot-Net上遇到了一点问题。

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

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

所以,我放置了新的String并将其称为nutka,而nutka将在我的USB MIDI键盘上收到按下的音符的名称。然后我放置了IF声明,并将nutka与" A0" (键盘上的第一个音符)。

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

我在public void NoteOn(NoteOnMessage msg)上做了一个断点,并注意到一个应用程序在这里返回两次并播放两次该注释,但仍然不知道为什么。

还有一件事,有一种方法public void NoteOff(NoteOffMessage message),但似乎没有用。

我真的无法理解,而且我正在寻找任何帮助。

更新 ... UPDATE ... 更新

出现了另一个问题(第一部分由于 CL Chris 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;

现在我不知道我能做多少次 - 我需要有经验的人帮助:)

2 个答案:

答案 0 :(得分:1)

MIDI 1.0详细规范说:

  

MIDI提供两种大致相同的关闭音符(声音)的方法。可以通过为相同的音符编号和通道发送音符关闭消息,或者通过为该音符和通道发送速度值为零的音符开启消息来关闭音符。在零速度下使用" Note-On的优势"是运行状态时可以避免发送额外的状态字节。

     

由于这种效率,发送速度值为零的Note-On消息是最常用的方法。然而,一些键盘乐器实现释放速度,其中音符关闭代码(8nH)伴随着"速度关闭"使用字节。接收器必须能够识别关闭音符的任何一种方法,并且应该对它们进行相同的处理。

答案 1 :(得分:1)

展开CL.'s answer,以下是可能发生的事件序列:

  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
  3. 这是它变得棘手的地方。释放密钥时,某些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
    3. 由于速度为0的Note On也是Note Off,所以你的代码将键盘的“Note Off”变回Note On,从而播放声音两次。

      作为Chris Dunaway suggested,您需要通过测试速度为0来确定Note On是否实际上是“Note Off”。

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