MIDI-события в реальном времени с NAudio и VST.NET
У меня есть следующий код, прекрасно работающий с VST Effects, передавая синусоидальную волну и получая результат без сбоев. Однако мне нужно передать пользовательское MIDI-событие (с помощью VST.NET или NAudio MIDI Helpers), и мне не повезло. Это потому, что абсолют и дельтафреймы равны нулю? Я не знаю, куда еще повернуть, и уже некоторое время стучу головой о клавиатуру.
Наблюдая за окном отладки, я вижу, что VST Events подхватывает плагин. Я также пошел дальше и создал собственный плагин, чтобы убедиться, что я получаю информацию о событии, и она проходит должным образом. Я просто не получаю аудиовыход!
В примере кода все, что вам нужно будет сделать, чтобы сделать эту работу, это: A. Поместите dll VSTi (которая имеет два аудиовыхода и принимает вход VST MIDI) в папку bin\debug при отладке этого B. изменения имя VSTi dll от cobalt.dll до любого имени VST, которое вы используете для тестирования.
Это универсальная XML-страница Windows с одной кнопкой, btnTest
Imports NAudio.Wave
Imports NAudio.Midi
Imports Jacobi.Vst.Core
Imports Jacobi.Vst.Interop.Host
Class MidiTestPage
Private waveOut As WaveOut
Private ctx As VstPluginContext
Private Sub btnTest_Click(sender As Object, e As EventArgs) Handles btnTest.Click
Dim pluginPath As String = System.AppDomain.CurrentDomain.BaseDirectory & "VSTPlugins\" & "cobalt.dll"
ctx = InitPlugin(pluginPath, 1)
Dim midiWaveProvider As New MidiSampleProvider(ctx)
If waveOut Is Nothing Then
waveOut = New WaveOut(WaveCallbackInfo.FunctionCallback())
waveOut.Init(midiWaveProvider)
waveOut.Volume = 1.0
waveOut.Play()
End If
End Sub
Private Sub HostCmdStub_PluginCalled(sender As Object, e As PluginCalledEventArgs)
Dim hostCmdStub As HostCommandStub = DirectCast(sender, HostCommandStub)
Try
' can be null when called from inside the plugin main entry point.
If hostCmdStub.PluginContext.PluginInfo IsNot Nothing Then
Debug.WriteLine("Plugin " & hostCmdStub.PluginContext.PluginInfo.PluginID & " called:" & e.Message)
Else
Debug.WriteLine("The loading Plugin called:" & e.Message)
End If
Catch ex As Exception
Debug.WriteLine("The loading Plugin called:" & e.Message)
End Try
End Sub
Private Function InitPlugin(pluginPath As String, programIndex As Integer) As VstPluginContext
Dim hostCmdStub As New HostCommandStub()
AddHandler hostCmdStub.PluginCalled, AddressOf HostCmdStub_PluginCalled
Dim ctx As VstPluginContext = VstPluginContext.Create(pluginPath, hostCmdStub)
'plugins.Add(ctx)
' add custom data to the context
ctx.Set(Of String)("PluginPath", pluginPath)
ctx.Set(Of HostCommandStub)("HostCmdStub", hostCmdStub)
'' actually open the plugin itself
ctx.PluginCommandStub.Open()
ctx.PluginCommandStub.MainsChanged(True)
ctx.PluginCommandStub.BeginSetProgram()
ctx.PluginCommandStub.SetProgram(programIndex)
ctx.PluginCommandStub.EndSetProgram()
ctx.PluginCommandStub.StartProcess()
Return ctx
End Function
End Class
Public Class MidiSampleProvider
Implements ISampleProvider
Private pluginContext As VstPluginContext
Public Shadows ReadOnly Property WaveFormat As WaveFormat Implements ISampleProvider.WaveFormat
Get
Return WaveFormat.CreateIeeeFloatWaveFormat(44100, 2)
End Get
End Property
Private BlockSize As Integer = 0
Private inputBuffers As VstAudioBuffer()
Private outputBuffers As VstAudioBuffer()
Dim vEvents As List(Of VstEvent)
Public Sub New(ctx As VstPluginContext)
pluginContext = ctx
vEvents = New List(Of VstEvent)
CreateMidiEvent(pluginContext)
End Sub
Private Sub UpdateBlockSize(blockSize__1 As Integer)
BlockSize = blockSize__1
Dim inputCount As Integer = pluginContext.PluginInfo.AudioInputCount
Dim outputCount As Integer = pluginContext.PluginInfo.AudioOutputCount
Dim inputMgr = New VstAudioBufferManager(inputCount, blockSize__1)
Dim outputMgr = New VstAudioBufferManager(outputCount, blockSize__1)
pluginContext.PluginCommandStub.SetBlockSize(blockSize__1)
pluginContext.PluginCommandStub.SetSampleRate(WaveFormat.SampleRate)
pluginContext.PluginCommandStub.SetProcessPrecision(VstProcessPrecision.Process32)
inputBuffers = inputMgr.ToArray()
outputBuffers = outputMgr.ToArray()
End Sub
Public Function Read(buffer() As Single, offset As Integer, count As Integer) As Integer Implements ISampleProvider.Read
Dim samplesRequired As Double = count / 2
If samplesRequired <> BlockSize Then
UpdateBlockSize(samplesRequired)
End If
Dim samplesRead As Double = 0
If vEvents.Count > 0 Then
pluginContext.PluginCommandStub.ProcessEvents(vEvents.ToArray)
pluginContext.HostCommandStub.ProcessEvents(vEvents.ToArray)
pluginContext.PluginCommandStub.ProcessReplacing(inputBuffers, outputBuffers)
'vEvents.Clear()
End If
For j As Integer = 0 To BlockSize - 1
buffer(samplesRead + offset) = outputBuffers(0)(j)
samplesRead += 2
Next
Return samplesRead
End Function
Public Sub CreateMidiEvent(ctx As VstPluginContext)
Dim noteOffset As Integer = 0
Dim detune As Short = 0
Dim Velocity As Integer = 127
'Dim noteOn As New NAudio.Midi.NoteEvent(AbsoluteTime, note.MidiChannel, NAudio.Midi.MidiCommandCode.NoteOn, note.Note.BaseNote, Velocity)
Dim noteOnStream As New System.IO.MemoryStream()
Dim noteOnData As New System.IO.BinaryWriter(noteOnStream)
'noteOn.Export(AbsoluteTime, noteOnData)
noteOnData.Write(MidiMessage.StartNote(60, Velocity, 1).RawData)
Dim noteOnEvent As New VstMidiEvent(0, 400, 0, noteOnStream.ToArray, detune, Velocity, True)
vEvents.Add(noteOnEvent)
End Sub
End Class