Звуки миди-дот-сети играют дважды
Я не программист 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 IFment и сравнил нутку с "A0" (первая нота на клавиатуре).
Затем, если это "A0", я нажал на свой outputDevice воспроизводит конкретную ноту. И он играет, но играет дважды: один - когда я нажимаю клавишу (с примечанием A0) на клавиатуре, и второй раз - когда я отпускаю эту клавишу.
Я сделал точку останова на 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;
Сейчас я понятия не имею, что я могу сделать еще и еще - мне нужна помощь опытного человека:)
2 ответа
Расширяя ответ CL., Вот последовательность событий, которые, вероятно, происходят:
- Вы нажимаете клавишу на клавиатуре MIDI, которая отправляет
Note On message, with a Pitch of A0, and a velocity
(точная скорость может меняться каждый раз). - Ваш код получает это и, так как он соответствует вашему
if
заявление, рассылаетNote On message, with a pitch of A0, and a velocity of 80
,
Вот где это становится сложным. Некоторые MIDI-устройства отправляют соответствующие Note Off
сообщение с той же высотой тона, когда вы отпустите клавишу. Другие устройства отправят секунду Note On
сообщение с тем же Pitch, но с Velocity, равным 0. Эти два типа сообщений являются (или должны быть) функционально эквивалентными, и каждое устройство может либо остановить воспроизведение ноты (либо даже оба). Так,
- Вы отпускаете клавишу на клавиатуре, которая отправляет
Note On message, with a Pitch of A0, and a Velocity of 0
, - Ваш код получает это и, так как он также соответствует вашему
if
заявление, рассылаетNote On message, with a pich of A0, and a velocity of 80
,
Поскольку Note On со скоростью 0 также является Note Off, то происходит то, что ваш код превращает "Note Off" вашей клавиатуры обратно в Note On, таким образом воспроизводя звук дважды.
Как предположил Крис Данауэй, вам нужно определить, действительно ли Note On является "Note Off", проверив скорость 0.
if (nutka == "A0" && msg.Velocity != 0) {
clock.Schedule(new NoteOnMessage(outputDevice, Channel.Channel1, Pitch.A0, 80, 2));
}
Подробная спецификация MIDI 1.0 гласит:
MIDI предоставляет два примерно эквивалентных средства отключения ноты (голоса). Заметка может быть отключена либо путем отправки сообщения об отключении для того же номера и канала, либо путем отправки сообщения о включении для этой заметки и канала со значением скорости, равным нулю. Преимущество использования "Note-On при нулевой скорости" состоит в том, что он может избежать отправки дополнительных байтов состояния, когда используется статус выполнения.
Благодаря этой эффективности отправка сообщений Note-On со значениями скорости, равными нулю, является наиболее часто используемым методом. Тем не менее, некоторые клавишные инструменты реализуют скорость высвобождения, когда используется код Note-Off (8nH), сопровождаемый байтом "speed off". Получатель должен быть в состоянии распознать любой метод отключения заметки и должен относиться к ним одинаково.