直接玩MidiEventCollection

时间:2018-03-17 15:19:47

标签: c# naudio

使用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();

2 个答案:

答案 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数据的更多信息。