Звуки Midi-dot-net воспроизводятся дважды

Во-первых, я не профессиональный программист, а всего лишь студент, у которого есть небольшая проблема с отличной библиотекой 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));
    }
}

Итак, я поместил новую String и назвал ее nutka, а nutka получит имя нажатой ноты на моей USB MIDI клавиатуре. Затем я поставил статус IF и сравнил нутку с «A0» (первая нота на клавиатуре).

Затем, если это «A0», я нажал, что мое устройство outputDevice воспроизводит определенную ноту. И он играет, но играет два раза, один раз - когда я нажимаю клавишу (с нотой А0) на клавиатуре и второй раз - когда я отпускаю эту клавишу.

Я сделал точку останова на public void NoteOn(NoteOnMessage msg) и заметил, что приложение возвращается сюда дважды и дважды воспроизводит эту ноту, до сих пор не знаю, почему.

Еще один момент, есть способ public void NoteOff(NoteOffMessage message), но он вроде не работает.

Я действительно не могу понять это, и я ищу любую помощь.

ОБНОВЛЕНИЕ ... ОБНОВЛЕНИЕ... ОБНОВЛЕНИЕ

Возникает еще одна проблема (первая часть была решена благодаря совету CL и Криса Данауэя и пошаговому объяснению Джастина).

Спасибо Джастин :) я вижу жизнь без проблем невозможна :)

С 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;

Прямо сейчас я понятия не имею, что я могу сделать снова и снова - мне нужна помощь опытного человека :)


person Martin    schedule 19.06.2015    source источник
comment
Я не понимаю часть Invoke, не следует ли вызвать NoteOn? Что такое noteOnHandler? Как вы называете NoteOn? Откуда?   -  person Sinatr    schedule 19.06.2015
comment
Я использую полный источник: link Я отредактировал form1.cs, и проект зависит от папки Midi, также размещенной по ссылке выше.   -  person Martin    schedule 19.06.2015
comment
Программа, которую вы редактируете, ожидает, что пользователь нажмет кнопку воспроизведения в форме Windows. Используя миди-клавиатуру, вы эффективно играете ноту, но также отправляете событие методу NoteOn, который затем запускает вторую ноту при вызове clock.Schedule. Таким образом, программа, которую вы редактируете, вероятно, не является правильной отправной точкой для того, чего вы пытаетесь достичь.   -  person Paul    schedule 19.06.2015
comment
Могу я попросить вас, Пол, помочь с текущим кодом? Можете ли вы показать мне связь между 1) я нажал внешнюю миди-клавишу и 2) playButton_click? Пытаюсь понять код, но не могу найти связь, которая удваивает звуки   -  person Martin    schedule 19.06.2015


Ответы (2)


Расширяя ответ CL., вот последовательность событий, которые вероятно происходят:

  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 с той же высотой тона, но с Velocity, равной 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.

Поскольку Note On с Velocity 0 также является Note Off, то происходит то, что ваш код превращает «Note Off» вашей клавиатуры обратно в Note On, таким образом, звук воспроизводится дважды.

Как предложил Крис Данауэй, вам нужно определить, является ли Note On на самом деле «Примечание выключено» путем проверки скорости, равной 0.

    if (nutka == "A0" && msg.Velocity != 0) {
        clock.Schedule(new NoteOnMessage(outputDevice, Channel.Channel1, Pitch.A0, 80, 2));
    }
person Justin Ryan    schedule 19.06.2015
comment
Я хотел бы поблагодарить всех вас, ребята, и CL за спецификацию! Но Дорогой Джастин, я хотел бы искренне поблагодарить вас! Вы объяснили мне точно и очень подробно мою проблему, и вы решили ее удивительно. Теперь я понимаю шаг за шагом, почему он воспроизводит звук дважды, и благодаря вам теперь я могу с этим справиться. Как здорово, что есть люди с большими практическими знаниями, которыми они делятся с такими же новичками, как я :) - person Martin; 22.06.2015
comment
Можно ли воспроизводить звук из ресурсов с помощью clock.Schedule? - person Martin; 26.06.2015
comment
@Мартин, извини, я не совсем понимаю, что ты собираешься делать. Пожалуйста, не стесняйтесь опубликовать еще один вопрос со всеми подробностями вашего нового выпуска и пометить его как [midi]. - person Justin Ryan; 26.06.2015

Подробная спецификация MIDI 1.0 гласит:

MIDI предоставляет два примерно эквивалентных средства отключения ноты (голоса). Нота может быть отключена либо путем отправки сообщения Note-Off для того же номера ноты и канала, либо путем отправки сообщения Note-On для этой ноты и канала с нулевым значением скорости нажатия. Преимущество использования «Note-On при нулевой скорости» заключается в том, что можно избежать отправки дополнительных байтов состояния при использовании состояния выполнения.

Из-за этой эффективности отправка сообщений Note-On с нулевыми значениями скорости является наиболее часто используемым методом. Однако некоторые клавишные инструменты реализуют скорость восстановления, в которой используется код Note-Off (8nH), сопровождаемый байтом «velocity off». Получатель должен уметь распознавать любой метод выключения ноты и относиться к ним одинаково.

person CL.    schedule 19.06.2015
comment
до сих пор не могу понять, к сожалению, я не логический ум :( нужна рука помощи :) - person Martin; 19.06.2015
comment
@Martin - я думаю, вам нужно проверить msg.Velocity в вашем методе NoteOn, и если скорость равна 0, то это примечание выключено (если я понимаю, что опубликовал CL). - person Chris Dunaway; 19.06.2015