Delphi: Как отправить MIDI на подключаемый плагин VST? - PullRequest
3 голосов
/ 17 сентября 2011

Я хочу использовать плагины VST в моей программе Delphi, которая действует как хост VST. Я попробовал примеры tobybear, использовал delphiasiovst Stuf, некоторые из них даже работали, но ... я не знаю, как отправлять MIDI-сообщения на плагин (я знаю, что большинство плагинов не будет обрабатывать MIDI, но я есть пример плагина, который делает).

Чтобы быть более конкретным: я ожидаю, что когда я отправляю сообщение MIDI, я должен либо использовать тот или иной метод в плагине VST, либо перенаправить выход MIDI. Я просто не знаю как.

Может кто-нибудь указать мне на документацию или код о том, как это сделать? Заранее спасибо.

Арнольд


Я использую два тестовых плагина: один скомпилированный из пакета DelphiAsioVst и PolyIblit. Оба работают в Финале и LMMS. Загруженные в мою тестовую программу оба показывают свой VST редактор.

Я вставил запись TvstEvent и инициализировал ее, я вставил процедуры MIDIData и AddMIDIData и таймер для предоставления тестовых данных и выполнения процедуры ProcessEvents плагина. ProcessEvents получает правильные тестовые данные, но звук не слышен. Я что-то слышу, когда отправляю прямо на выходной порт midi.

В коде ниже PropcessEvents должно быть достаточно imho, дополнительный код является проверкой правильности отправки 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 //

Так что я не получаю события в плагине. Есть идеи, что я не прав?

Ответы [ 3 ]

4 голосов
/ 18 сентября 2011

Вам действительно стоит взглянуть на пример ядра minihost (проект Delphi ASIO, версия 1.4).

Существует использование событий миди.В основном

  1. у вас есть переменная TVstEvents (скажем, MyMidiEvents: TvstEvents).
  2. для всей среды выполнения, которую вы выделяете память для этой переменной (в конструкторе приложения, например)
  3. Когда у вас есть событие в вашем обратном вызове MIDI, вы копируете его в стек TVstEvents.
  4. Перед вызовом процесса в 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; 

, это должно вам очень помочь, если вы не смоглипроанализировать используемый метод.

2 голосов
/ 18 сентября 2011

Если вы размещаете плагины VST 2.x, вы можете отправлять MIDI-события в плагин с помощью AudioEffectX.ProcessEvents ().

Из документов VST.

  • События всегда связаны с текущим аудиоблоком.

  • Для каждого цикла процесса processEvents () вызывается один раз перед вызовом processReplacing () (если доступны новые события).

Я не знаю ни одного примера кода. Там может быть что-то в DelphiAsioVST.

1 голос
/ 18 сентября 2011

Если вы хотите сменить язык программирования, попробуйте VST.NET , который позволяет писать плагины и хосты в C # и VB.NET.

Надеюсь, это поможет.

...