使用NAudio框架,我编写了这样的代码来播放一些midi音符:
// Guts of a play note method which takes a cancellation token, a note
// a channel and a duration - CurrentVolume is a property of the class
// that plays the notes
midiOut.Send(MidiMessage.StartNote(note, CurrentVolume, channel).RawData);
try
{
await Task.Delay(duration, cancellationToken);
}
finally
{
midiOut.Send(MidiMessage.StopNote(note, CurrentVolume, channel).RawData);
}
这个工作正常,但是每次经常会有一些跳过/延迟的渲染,我假设它来自Task.Delay并不总是准确的。我想做的只是生成一个midi集合并将整个集合发送到midi out设备,但我似乎无法找到一种方法来做到这一点。我已经知道如何生成一个集合,我知道如何将其保存到文件中 - 所以如果解决方案是创建一个文件,然后以某种方式发送文件,这也是可以接受的。
var collection = new MidiEventCollection(0, 120);
collection.AddEvent(new NoteOnEvent(0, 1, 64, 127, 15), 1);
collection.AddEvent(new NoteOnEvent(15, 1, 65, 127, 15), 1);
collection.AddEvent(new NoteOnEvent(30, 1, 66, 127, 15), 1);
collection.AddEvent(new NoteOnEvent(45, 1, 67, 127, 15), 1);
collection.AddEvent(new NoteOnEvent(60, 1, 68, 127, 15), 1);
collection.PrepareForExport();
答案 0 :(得分:1)
有一个Windows API允许您发出批量的MIDI事件(例如,请参阅midiStreamOut),这对于这种情况是理想的,但不幸的是NAudio不包含此包装器。 NAudio的MIDI功能更专注于读取和写入MIDI文件。您可以选择为我提到的MIDI API创建p / invoke包装器,或尝试使用其他音频库,例如MIDI.NET
答案 1 :(得分:0)
使用DryWetMIDI,您可以编写以下代码:
using Melanchall.DryWetMidi.Common;
using Melanchall.DryWetMidi.Devices;
using Melanchall.DryWetMidi.Smf;
using Melanchall.DryWetMidi.Smf.Interaction;
// ...
var eventsToPlay = new MidiEvent[]
{
new NoteOnEvent((SevenBitNumber)100, SevenBitNumber.MaxValue) { Channel = (FourBitNumber)10 },
new NoteOffEvent((SevenBitNumber)100, SevenBitNumber.MinValue) { Channel = (FourBitNumber)10 },
// ...
};
using (var outputDevice = OutputDevice.GetByName("Microsoft GS Wavetable Synth"))
using (var playback = new Playback(eventsToPlay, TempoMap.Default, outputDevice))
{
playback.Play();
}
或者,如果您只需要在单个通道上演奏音符,则可以使用Pattern:
using MusicTheory = Melanchall.DryWetMidi.MusicTheory;
// ...
var pattern = new PatternBuilder()
.Note(MusicTheory.Octave.Get(3).ASharp, length: MusicalTimeSpan.Quarter)
.Note(MusicTheory.Octave.Get(3).C, length: MusicalTimeSpan.Eighth)
// ...
.Build();
using (var outputDevice = OutputDevice.GetByName("Microsoft GS Wavetable Synth"))
{
pattern.Play(TempoMap.Default, (FourBitNumber)10, outputDevice);
}
请注意,Play
将阻塞调用线程,直到播放所有MIDI数据为止。对于非阻塞播放,请使用Start
类的Playback
方法:
var playback = pattern.GetPlayback(TempoMap.Default, (FourBitNumber)10, outputDevice);
playback.Start();
您可以在Wiki库的Playback页上了解有关播放MIDI数据的更多信息。