Delphi :如何发送MIDI到一个托管的VST插件?

wgmfuz8q  于 2022-12-18  发布在  其他
关注(0)|答案(3)|浏览(121)

我想在我的 Delphi 程序中使用VST插件作为VST主机。我已经尝试了tobybear的例子,使用了delphiasiovst stuf,得到了一些它甚至工作,但...我不知道如何发送MIDI消息到插件(我知道大多数插件不会处理MIDI,但我有一个例子插件可以)。
更具体地说:我希望当我发送一个MIDI消息时,我必须使用VST插件中的一个或另一个方法,或者重新路由MIDI输出。
有人能告诉我如何做这件事的文档或代码吗?提前感谢。
阿诺
我使用两个测试插件:从DelphiAsioVst包和PolyIblit编译的那个。都在Finale和LMMS中工作。加载到我的测试程序中都显示了他们的VST编辑器。
我确实插入了TvstEvent记录并初始化了它,我插入了MIDIData和AddMIDIData过程以及一个计时器来提供测试数据并执行插件的ProcessEvents例程。ProcessEvents获得了正确的测试数据,但没有听到声音。当我直接将其发送到midi输出端口时,我听到了一些声音。
在下面的代码中,PropcessEvents应该足够了,额外的代码是一个测试MIDI信息是否正确发送的代码。VstHost [0]是第一个插件,根据测试的不同,可以是PolyIblit或VSTPlugin。

procedure TMain_VST_Demo.TimerTimer (Sender: TObject);
var i: Int32;
begin
//   MIDIOutput.PutShort ($90, 60, 127);
   MIDIData (0, $90, 60, 127);

   if FMDataCnt > 0 then
   begin
      FMyEvents.numEvents := FMDataCnt;
      VSTHost[0].ProcessEvents(@FMyEvents);
//    if (FCurrentMIDIOut > 0) and MIMidiThru.Checked then
//     begin
      for i := 0 to FMDataCnt - 1 do
      MIDIOutput.PutShort (PVstMidiEvent (FMyEvents.events[i])^.midiData[0],
                           PVstMidiEvent (FMyEvents.events[i])^.midiData[1],
                           PVstMidiEvent (FMyEvents.events[i])^.midiData[2]);
//       FMidiOutput.Send(//FCurrentMIDIOut - 1,
//                   PVstMidiEvent(FMyEvents.events[i])^.midiData[0],
//                   PVstMidiEvent(FMyEvents.events[i])^.midiData[1],
//                   PVstMidiEvent(FMyEvents.events[i])^.midiData[2]);
//     end;
     FMDataCnt := 0;
   end;
end; // TimerTimer //

所以我没有得到插件中的事件。知道我错在哪里吗?

drkbr07n

drkbr07n1#

您真的应该看看微型主机核心示例( Delphi 项目,v1.4)。
有一个使用midi事件。基本上
1.你有一个TVstEvents变量(比如说MyMidiEvents:电视台事件)。
1.在整个运行时,您为该变量分配内存(在exmaple的app构造函数中)
1.如果MIDI回调中有事件,则将其复制到TVstEvents堆栈中。
1.在TVstHost中调用进程之前,先调用MyVstHost.ProcessEvents(@MyMidiEvents)。
以下是示例(微型主机核心)中针对前面每个步骤的执行方式:
1/第215行,声明

FMyEvents: TVstEvents;

2第376行,分配:

for i := 0 to 2047 do
begin
 GetMem(FMyEvents.Events[i], SizeOf(TVSTMidiEvent));
 FillChar(FMyEvents.Events[i]^, SizeOf(TVSTMidiEvent), 0);
 with PVstMidiEvent(FMyEvents.Events[i])^ do
  begin
   EventType := etMidi;
   ByteSize := 24;
  end;
end;

3/在行986,然后在行1782,从回调复制midi事件:
回叫

procedure TFmMiniHost.MidiData(const aDeviceIndex: Integer; const aStatus, aData1, aData2: Byte);
begin
 if aStatus = $FE then exit; // ignore active sensing
 if (not Player.CbOnlyChannel1.Checked) or ((aStatus and $0F) = 0) then
  begin
   if (aStatus and $F0) = $90
    then NoteOn(aStatus, aData1, aData2) //ok
    else
   if (aStatus and $F0) = $80
    then NoteOff(aStatus, aData1)
    else AddMidiData(aStatus, aData1, aData2);
  end;
end;


事件副本

procedure TFmMiniHost.AddMIDIData(d1, d2, d3: byte; pos: Integer = 0);
begin
 FDataSection.Acquire; 
 try
  if FMDataCnt > 2046 
   then exit;                 

  inc(FMDataCnt);
  with PVstMidiEvent(FMyEvents.events[FMDataCnt - 1])^ do
   begin
    EventType := etMidi;
    deltaFrames := pos;
    midiData[0] := d1;
    midiData[1] := d2;
    midiData[2] := d3;
   end;
 finally 
  FDataSection.Release;
 end; 
end;

4/在第2322行,在TASioHost.Bufferswitch中,调用TVstHost.ProcessEvents

FDataSection.Acquire;
try
  if FMDataCnt > 0 then
   begin
    FMyEvents.numEvents := FMDataCnt;

    VSTHost[0].ProcessEvents(FMyEvents);

    if (FCurrentMIDIOut > 0) and MIMidiThru.Checked then
     begin
      for i := 0 to FMDataCnt - 1 do
       FMidiOutput.Send(FCurrentMIDIOut - 1,
                   PVstMidiEvent(FMyEvents.events[i])^.midiData[0],
                   PVstMidiEvent(FMyEvents.events[i])^.midiData[1],
                   PVstMidiEvent(FMyEvents.events[i])^.midiData[2]);
     end;
     FMDataCnt := 0;
   end;
 finally  
  FDataSection.Release;
 end;

如果你不能分析所使用的方法,这将对你有很大帮助。

mdfafbf1

mdfafbf12#

如果您正在托管VST 2.x插件,则可以使用AudioEffectX.ProcessEvents()将MIDI事件发送到插件。
来自VST文档。

  • 事件始终与当前音频块相关。
  • 对于每个进程周期,processEvents()在processReplacing()调用之前调用一次(如果有新事件可用)。

我不知道任何代码示例。可能在DelphiAsiovST中有一些。

5cg8jx4n

5cg8jx4n3#

如果你想换一种编程语言,你可以试试VST.NET,它允许你用C#和VB.NET编写插件和宿主。
希望有帮助。

相关问题