Added VSTHost media add-on.
This commit is contained in:
parent
056e8f141b
commit
e5606e71cf
@ -18,4 +18,5 @@ SubInclude HAIKU_TOP src add-ons media media-add-ons video_producer_demo ;
|
||||
SubInclude HAIKU_TOP src add-ons media media-add-ons videowindow ;
|
||||
SubInclude HAIKU_TOP src add-ons media media-add-ons video_mixer ;
|
||||
SubInclude HAIKU_TOP src add-ons media media-add-ons equalizer ;
|
||||
SubInclude HAIKU_TOP src add-ons media media-add-ons vst_host ;
|
||||
|
||||
|
10
src/add-ons/media/media-add-ons/vst_host/Jamfile
Normal file
10
src/add-ons/media/media-add-ons/vst_host/Jamfile
Normal file
@ -0,0 +1,10 @@
|
||||
SubDir HAIKU_TOP src add-ons media media-add-ons vst_host ;
|
||||
|
||||
AddResources vst_host.media_addon : VSTHost.rdef ;
|
||||
|
||||
Addon vst_host.media_addon :
|
||||
VSTHost.cpp
|
||||
VSTAddOn.cpp
|
||||
VSTNode.cpp
|
||||
: be media
|
||||
;
|
145
src/add-ons/media/media-add-ons/vst_host/VSTAddOn.cpp
Normal file
145
src/add-ons/media/media-add-ons/vst_host/VSTAddOn.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <Entry.h>
|
||||
#include <Directory.h>
|
||||
#include <FindDirectory.h>
|
||||
|
||||
#include "VSTNode.h"
|
||||
#include "VSTAddOn.h"
|
||||
|
||||
extern "C" _EXPORT BMediaAddOn* make_media_addon(image_id image)
|
||||
{
|
||||
return new VSTAddOn(image);
|
||||
}
|
||||
|
||||
VSTAddOn::VSTAddOn(image_id image) : BMediaAddOn(image)
|
||||
{
|
||||
const char vst_subdir[]={"media/vstplugins"};
|
||||
|
||||
BPath addons_dir;
|
||||
fPluginsList.MakeEmpty();
|
||||
|
||||
find_directory(B_COMMON_ADDONS_DIRECTORY, &addons_dir);
|
||||
addons_dir.Append(vst_subdir);
|
||||
ScanPluginsFolders(addons_dir.Path(), true);
|
||||
|
||||
find_directory(B_USER_ADDONS_DIRECTORY, &addons_dir);
|
||||
addons_dir.Append(vst_subdir);
|
||||
ScanPluginsFolders(addons_dir.Path() ,true);
|
||||
|
||||
find_directory(B_BEOS_ADDONS_DIRECTORY, &addons_dir);
|
||||
addons_dir.Append(vst_subdir);
|
||||
ScanPluginsFolders(addons_dir.Path());
|
||||
}
|
||||
|
||||
VSTAddOn::~VSTAddOn()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTAddOn::InitCheck(const char **text)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int32
|
||||
VSTAddOn::CountFlavors()
|
||||
{
|
||||
return fPluginsList.CountItems();
|
||||
}
|
||||
|
||||
status_t VSTAddOn::GetFlavorAt( int32 idx, const flavor_info **info)
|
||||
{
|
||||
if(idx < 0 || idx >= fPluginsList.CountItems())
|
||||
return B_ERROR;
|
||||
|
||||
VSTPlugin *plugin = (VSTPlugin*)fPluginsList.ItemAt(idx);
|
||||
|
||||
flavor_info *f_info = new flavor_info;
|
||||
f_info->internal_id = idx;
|
||||
f_info->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER | B_CONTROLLABLE;
|
||||
f_info->possible_count = 0;
|
||||
f_info->flavor_flags = 0;
|
||||
f_info->name = (char *)plugin->ModuleName();
|
||||
f_info->info = (char *)plugin->Product();
|
||||
|
||||
media_format *format = new media_format;
|
||||
format->type = B_MEDIA_RAW_AUDIO;
|
||||
format->u.raw_audio = media_raw_audio_format::wildcard;
|
||||
format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
||||
|
||||
f_info->in_format_count = 1;
|
||||
f_info->in_formats = format;
|
||||
|
||||
format = new media_format;
|
||||
format->type = B_MEDIA_RAW_AUDIO;
|
||||
format->u.raw_audio = media_raw_audio_format::wildcard;
|
||||
format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
||||
|
||||
f_info->out_format_count = 1;
|
||||
f_info->out_formats = format;
|
||||
|
||||
*info = f_info;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
BMediaNode*
|
||||
VSTAddOn::InstantiateNodeFor(const flavor_info *info, BMessage *config,
|
||||
status_t *err)
|
||||
{
|
||||
VSTPlugin *plugin = (VSTPlugin*)fPluginsList.ItemAt(info->internal_id);
|
||||
VSTNode *node = new VSTNode(this, plugin->ModuleName(), plugin->Path());
|
||||
return node;
|
||||
}
|
||||
|
||||
int
|
||||
VSTAddOn::ScanPluginsFolders(const char *path, bool make_dir)
|
||||
{
|
||||
BEntry ent;
|
||||
|
||||
BDirectory dir(path);
|
||||
if(dir.InitCheck() != B_OK) {
|
||||
create_directory(path, 0755);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(dir.GetNextEntry(&ent) == B_OK) {
|
||||
BPath p(&ent);
|
||||
if(ent.IsDirectory()) {
|
||||
ScanPluginsFolders(p.Path());
|
||||
} else {
|
||||
VSTPlugin *plugin = new VSTPlugin();
|
||||
int ret = plugin->LoadModule(p.Path());
|
||||
if(ret == B_OK) {
|
||||
plugin->UnLoadModule();
|
||||
fPluginsList.AddItem(plugin);
|
||||
} else {
|
||||
delete plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTAddOn::GetConfigurationFor(BMediaNode *node, BMessage *message)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
VSTAddOn::WantsAutoStart()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTAddOn::AutoStart(int count, BMediaNode **node, int32 *id, bool *more)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
30
src/add-ons/media/media-add-ons/vst_host/VSTAddOn.h
Normal file
30
src/add-ons/media/media-add-ons/vst_host/VSTAddOn.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef __VST_ADDON_H__
|
||||
#define __VST_ADDON_H__
|
||||
|
||||
#include <MediaAddOn.h>
|
||||
#include "VSTHost.h"
|
||||
|
||||
class VSTAddOn : public BMediaAddOn
|
||||
{
|
||||
public:
|
||||
virtual ~VSTAddOn();
|
||||
explicit VSTAddOn(image_id image);
|
||||
virtual status_t InitCheck(const char **text);
|
||||
virtual int32 CountFlavors();
|
||||
virtual status_t GetFlavorAt(int32 idx, const flavor_info **info);
|
||||
virtual BMediaNode* InstantiateNodeFor(const flavor_info *info, BMessage *config,
|
||||
status_t *err);
|
||||
virtual status_t GetConfigurationFor(BMediaNode *node, BMessage *message);
|
||||
virtual bool WantsAutoStart();
|
||||
virtual status_t AutoStart(int count, BMediaNode **node, int32 *id, bool *more);
|
||||
private:
|
||||
int ScanPluginsFolders(const char *path, bool make_dir=false);
|
||||
BList fPluginsList;
|
||||
};
|
||||
|
||||
#endif //__VST_ADDON_H__
|
567
src/add-ons/media/media-add-ons/vst_host/VSTHost.cpp
Normal file
567
src/add-ons/media/media-add-ons/vst_host/VSTHost.cpp
Normal file
@ -0,0 +1,567 @@
|
||||
/*
|
||||
* Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <image.h>
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
#include "VSTHost.h"
|
||||
|
||||
static int32 VHostCallback(VSTEffect* effect, int32 opcode, int32 index,
|
||||
int32 value, void* ptr, float opt);
|
||||
|
||||
//Trim string
|
||||
static void
|
||||
TrimString(BString *string) {
|
||||
char *str = string->LockBuffer(256);
|
||||
uint32 k = 0;
|
||||
uint32 i = 0;
|
||||
for(i=0; str[i]!='\0';) {
|
||||
if (isspace(str[i])) {
|
||||
k = i;
|
||||
for(uint32 j = i; j < strlen(str) - 1; j++) {
|
||||
str[j] = str[j + 1];
|
||||
}
|
||||
str[strlen(str) - 1] = '\0';
|
||||
i = k;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
string->UnlockBuffer();
|
||||
}
|
||||
|
||||
//VST Parameter class
|
||||
VSTParameter::VSTParameter(VSTPlugin *plugin, int index)
|
||||
{
|
||||
fIndex = index;
|
||||
fEffect = plugin->Effect();
|
||||
fDropList.MakeEmpty();
|
||||
|
||||
char temp[256];
|
||||
//get parameter name
|
||||
temp[0] = 0;
|
||||
fEffect->dispatcher(fEffect, VST_GET_PARAM_NAME, index, 0, temp, 0);
|
||||
fName.SetTo(temp);
|
||||
TrimString(&fName);
|
||||
//get parameter label (unit)
|
||||
temp[0] = 0;
|
||||
fEffect->dispatcher(fEffect, VST_GET_PARAM_UNIT, index, 0, temp, 0);
|
||||
fUnit.SetTo(temp);
|
||||
ValidateValues(&fUnit);
|
||||
//store current value
|
||||
float val = fEffect->getParameter(fEffect, index);
|
||||
//test for minimum value
|
||||
fEffect->setParameter(fEffect, index, 0);
|
||||
temp[0] = 0;
|
||||
fEffect->dispatcher(fEffect, VST_GET_PARAM_STR, index, 0, temp, 0);
|
||||
fMinValue.SetTo(temp);
|
||||
ValidateValues(&fMinValue);
|
||||
//test for maximum value
|
||||
temp[0] = 0;
|
||||
fEffect->setParameter(fEffect, index, 1.0);
|
||||
fEffect->dispatcher(fEffect, VST_GET_PARAM_STR, index, 0, temp, 0);
|
||||
fMaxValue.SetTo(temp);
|
||||
ValidateValues(&fMaxValue);
|
||||
//test for discrete values
|
||||
char test_disp[VST_PARAM_TEST_COUNT][256];
|
||||
float test_values[VST_PARAM_TEST_COUNT];
|
||||
float delta = 1.0 / (float)VST_PARAM_TEST_COUNT;
|
||||
int test_cnt = 0;
|
||||
for(int tst_val = 0; tst_val < VST_PARAM_TEST_COUNT; tst_val++){
|
||||
float v = (float)tst_val / (float)VST_PARAM_TEST_COUNT;
|
||||
if(tst_val >= VST_PARAM_TEST_COUNT - 1) {
|
||||
v=1.0;
|
||||
}
|
||||
fEffect->setParameter(fEffect, index, v);
|
||||
float new_value = fEffect->getParameter(fEffect, index);
|
||||
bool valtest = false;
|
||||
for(int i = 0; i < test_cnt; i++) {
|
||||
if(fabs(test_values[i] - new_value) < delta) {
|
||||
valtest = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(valtest == false) {
|
||||
test_values[test_cnt] = new_value;
|
||||
fEffect->dispatcher(fEffect, VST_GET_PARAM_STR, index, 0, test_disp[test_cnt], 0);
|
||||
test_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
//restore value
|
||||
fEffect->setParameter(fEffect, index, val);
|
||||
|
||||
//detect param type
|
||||
if(test_cnt == 2) {
|
||||
fType = VST_PARAM_CHECKBOX;
|
||||
|
||||
DropListValue *min_item = new DropListValue();
|
||||
min_item->Value = 0.0;
|
||||
min_item->Index = 0;
|
||||
min_item->Name = fMinValue;
|
||||
fDropList.AddItem(min_item);
|
||||
|
||||
DropListValue *max_item = new DropListValue();
|
||||
max_item->Value = 1.0;
|
||||
max_item->Index = 1;
|
||||
max_item->Name = fMaxValue;
|
||||
fDropList.AddItem(max_item);
|
||||
} else if(test_cnt > 2 && test_cnt < VST_PARAM_TEST_COUNT / 2) {
|
||||
fType = VST_PARAM_DROPLIST;
|
||||
|
||||
for(int i = 0; i < test_cnt; i++) {
|
||||
DropListValue *item = new DropListValue();
|
||||
item->Value = test_values[i];
|
||||
item->Index = i;
|
||||
item->Name = test_disp[i];
|
||||
fDropList.AddItem(item);
|
||||
}
|
||||
} else {
|
||||
fType = VST_PARAM_SLIDER;
|
||||
}
|
||||
fChanged = 0LL;
|
||||
}
|
||||
|
||||
VSTParameter::~VSTParameter()
|
||||
{
|
||||
}
|
||||
|
||||
BString*
|
||||
VSTParameter::ValidateValues(BString *string)
|
||||
{
|
||||
if(string->Length() == 0) {
|
||||
return string;
|
||||
}
|
||||
|
||||
bool isNum = true;
|
||||
|
||||
const char *ptr = string->String();
|
||||
for(;*ptr!=0;ptr++) {
|
||||
char ch = *ptr;
|
||||
if(!((ch >= '0' && ch <= '9') || ch == '.' || ch == '-')) {
|
||||
isNum = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isNum) {
|
||||
float val = atof(string->String());
|
||||
|
||||
if(val <= -pow(2, 31)) {
|
||||
string->SetTo("-∞");
|
||||
} else if(val >= pow(2, 31)) {
|
||||
string->SetTo("∞");
|
||||
} else {
|
||||
char temp[256];
|
||||
sprintf(temp, "%g", val);
|
||||
string->SetTo(temp);
|
||||
}
|
||||
} else {
|
||||
TrimString(string);
|
||||
if(*string == "oo" || *string == "inf")
|
||||
string->SetTo("∞");
|
||||
if(*string == "-oo" || *string == "-inf")
|
||||
string->SetTo("-∞");
|
||||
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
int
|
||||
VSTParameter::ListCount(void)
|
||||
{
|
||||
return fDropList.CountItems();
|
||||
}
|
||||
|
||||
DropListValue*
|
||||
VSTParameter::ListItemAt(int index)
|
||||
{
|
||||
DropListValue *item = NULL;
|
||||
if(index >= 0 && index < fDropList.CountItems()) {
|
||||
item = (DropListValue*)fDropList.ItemAt(index);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
VSTParameter::Value()
|
||||
{
|
||||
float value = fEffect->getParameter(fEffect, fIndex);
|
||||
if(fType == VST_PARAM_DROPLIST) {
|
||||
//scan for near value
|
||||
int min_index = 0;
|
||||
float min_delta = 1.0;
|
||||
for(int i = 0; i < fDropList.CountItems(); i++) {
|
||||
DropListValue *item = (DropListValue*)fDropList.ItemAt(i);
|
||||
float delta = fabs(item->Value - value);
|
||||
if(delta <= min_delta) {
|
||||
min_delta = delta;
|
||||
min_index = i;
|
||||
}
|
||||
}
|
||||
value = min_index;
|
||||
}
|
||||
fLastValue = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
VSTParameter::SetValue(float value)
|
||||
{
|
||||
if(value == fLastValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(fType == VST_PARAM_DROPLIST) {
|
||||
//take value by index
|
||||
int index = (int)round(value);
|
||||
if(index >= 0 && index < fDropList.CountItems()) {
|
||||
DropListValue *item = (DropListValue*)fDropList.ItemAt(index);
|
||||
value = item->Value;
|
||||
fLastValue = index;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
fLastValue = value;
|
||||
}
|
||||
fChanged = system_time();
|
||||
fEffect->setParameter(fEffect, fIndex, value);
|
||||
}
|
||||
|
||||
bigtime_t
|
||||
VSTParameter::LastChangeTime(void)
|
||||
{
|
||||
return fChanged;
|
||||
}
|
||||
|
||||
const char*
|
||||
VSTParameter::MinimumValue(void)
|
||||
{
|
||||
return fMinValue.String();
|
||||
}
|
||||
|
||||
const char*
|
||||
VSTParameter::MaximumValue(void)
|
||||
{
|
||||
return fMaxValue.String();
|
||||
}
|
||||
|
||||
const char*
|
||||
VSTParameter::Unit(void)
|
||||
{
|
||||
return fUnit.String();
|
||||
}
|
||||
|
||||
int
|
||||
VSTParameter::Index(void)
|
||||
{
|
||||
return fIndex;
|
||||
}
|
||||
|
||||
int
|
||||
VSTParameter::Type(void)
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
const char*
|
||||
VSTParameter::Name(void)
|
||||
{
|
||||
return fName.String();
|
||||
}
|
||||
|
||||
//VST Plugin class
|
||||
VSTPlugin::VSTPlugin()
|
||||
{
|
||||
fActive = false;
|
||||
fEffect = NULL;
|
||||
VSTMainProc = NULL;
|
||||
fInputChannels = 0;
|
||||
fOutputChannels = 0;
|
||||
fSampleRate = 44100.f;
|
||||
fBlockSize = 0;
|
||||
inputs = NULL;
|
||||
outputs = NULL;
|
||||
fParameters.MakeEmpty();
|
||||
}
|
||||
|
||||
VSTPlugin::~VSTPlugin()
|
||||
{
|
||||
fParameters.MakeEmpty();
|
||||
UnLoadModule();
|
||||
}
|
||||
|
||||
int
|
||||
VSTPlugin::LoadModule(const char *path)
|
||||
{
|
||||
char effectName[256] = {0};
|
||||
char vendorString[256] = {0};
|
||||
char productString[256] = {0};
|
||||
|
||||
if(fActive) {
|
||||
return VST_ERR_ALREADY_LOADED;
|
||||
}
|
||||
|
||||
fPath = BPath(path);
|
||||
|
||||
fModule = load_add_on(path);
|
||||
if(fModule <= 0) {
|
||||
return VST_ERR_NOT_LOADED;
|
||||
}
|
||||
|
||||
if(get_image_symbol(fModule, "main_plugin", B_SYMBOL_TYPE_TEXT, (void**)&VSTMainProc) != B_OK) {
|
||||
unload_add_on(fModule);
|
||||
return VST_ERR_NO_MAINPROC;
|
||||
}
|
||||
|
||||
fEffect = VSTMainProc(VHostCallback);
|
||||
if(fEffect==NULL) {
|
||||
unload_add_on(fModule);
|
||||
return VST_ERR_NOT_LOADED;
|
||||
}
|
||||
|
||||
fEffect->dispatcher(fEffect, VST_OPEN, 0, 0, 0, 0);
|
||||
|
||||
fEffect->dispatcher(fEffect, VST_GET_EFFECT_NAME, 0, 0, effectName, 0);
|
||||
fEffectName.SetTo(effectName);
|
||||
TrimString(&fEffectName);
|
||||
|
||||
fModuleName.SetTo("VST:");
|
||||
fModuleName.Append(fPath.Leaf());
|
||||
|
||||
fEffect->dispatcher(fEffect, VST_GET_VENDOR_STR, 0, 0, vendorString, 0);
|
||||
fVendorString.SetTo(vendorString);
|
||||
TrimString(&fVendorString);
|
||||
|
||||
fEffect->dispatcher(fEffect, VST_GET_PRODUCT_STR, 0, 0, productString, 0);
|
||||
fProductString.SetTo(productString);
|
||||
TrimString(&fProductString);
|
||||
|
||||
fInputChannels = fEffect->numInputs;
|
||||
fOutputChannels = fEffect->numOutputs;
|
||||
|
||||
for(int i=0; i < fEffect->numParams; i++) {
|
||||
VSTParameter *param = new VSTParameter(this, i);
|
||||
fParameters.AddItem(param);
|
||||
}
|
||||
|
||||
fEffect->dispatcher(fEffect, VST_STATE_CHANGED, 0, 1, 0, 0);
|
||||
|
||||
ReAllocBuffers();
|
||||
|
||||
fActive = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int
|
||||
VSTPlugin::UnLoadModule(void)
|
||||
{
|
||||
if(!fActive || fModule <= 0) {
|
||||
return VST_ERR_NOT_LOADED;
|
||||
}
|
||||
fEffect->dispatcher(fEffect, VST_STATE_CHANGED, 0, 0, 0, 0);
|
||||
fEffect->dispatcher(fEffect, VST_CLOSE, 0, 0, 0, 0);
|
||||
|
||||
unload_add_on(fModule);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int
|
||||
VSTPlugin::Channels(int mode)
|
||||
{
|
||||
switch(mode) {
|
||||
case VST_INPUT_CHANNELS:
|
||||
return fInputChannels;
|
||||
case VST_OUTPUT_CHANNELS:
|
||||
return fOutputChannels;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
VSTPlugin::SetSampleRate(float rate)
|
||||
{
|
||||
fSampleRate = rate;
|
||||
fEffect->dispatcher(fEffect, VST_SET_SAMPLE_RATE, 0, 0, 0, rate);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
float
|
||||
VSTPlugin::SampleRate(void)
|
||||
{
|
||||
return fSampleRate;
|
||||
}
|
||||
|
||||
int
|
||||
VSTPlugin::SetBlockSize(size_t size)
|
||||
{
|
||||
fBlockSize = size;
|
||||
fEffect->dispatcher(fEffect, VST_SET_BLOCK_SIZE, 0, size, 0, 0);
|
||||
ReAllocBuffers();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
const char*
|
||||
VSTPlugin::Path(void)
|
||||
{
|
||||
return fPath.Path();
|
||||
}
|
||||
|
||||
int
|
||||
VSTPlugin::ReAllocBuffers(void)
|
||||
{
|
||||
if(inputs!=NULL) {
|
||||
for(int32 i = 0; i < fInputChannels; i++) {
|
||||
delete inputs[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(outputs!=NULL) {
|
||||
for(int32 i = 0; i < fOutputChannels; i++) {
|
||||
delete outputs[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(fInputChannels > 0) {
|
||||
inputs = new float*[fInputChannels];
|
||||
for(int32 i = 0; i < fInputChannels; i++) {
|
||||
inputs[i] = new float[fBlockSize];
|
||||
memset (inputs[i], 0, fBlockSize * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
if(fOutputChannels > 0) {
|
||||
outputs = new float*[fOutputChannels];
|
||||
for(int32_t i = 0; i < fOutputChannels; i++) {
|
||||
outputs[i] = new float[fBlockSize];
|
||||
memset (outputs[i], 0, fBlockSize * sizeof(float));
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
size_t
|
||||
VSTPlugin::BlockSize(void)
|
||||
{
|
||||
return fBlockSize;
|
||||
}
|
||||
|
||||
int
|
||||
VSTPlugin::ParametersCount(void)
|
||||
{
|
||||
return fParameters.CountItems();
|
||||
}
|
||||
|
||||
VSTParameter*
|
||||
VSTPlugin::Parameter(int index)
|
||||
{
|
||||
VSTParameter *param = NULL;
|
||||
|
||||
if(index >= 0 && index < fParameters.CountItems()) {
|
||||
param = (VSTParameter*)fParameters.ItemAt(index);
|
||||
}
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
VSTEffect*
|
||||
VSTPlugin::Effect(void)
|
||||
{
|
||||
return fEffect;
|
||||
}
|
||||
|
||||
const char*
|
||||
VSTPlugin::EffectName(void)
|
||||
{
|
||||
return fEffectName.String();
|
||||
}
|
||||
|
||||
const char*
|
||||
VSTPlugin::ModuleName(void)
|
||||
{
|
||||
return fModuleName.String();
|
||||
}
|
||||
|
||||
const char*
|
||||
VSTPlugin::Vendor(void)
|
||||
{
|
||||
return fVendorString.String();
|
||||
}
|
||||
|
||||
const char*
|
||||
VSTPlugin::Product(void)
|
||||
{
|
||||
return fProductString.String();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VSTPlugin::Process(float *buffer, int samples, int channels)
|
||||
{
|
||||
//todo: full channels remapping needed
|
||||
float *src = buffer;
|
||||
|
||||
if(channels == fInputChannels) { //channel to channel
|
||||
for(int j = 0; j < samples; j++) {
|
||||
for(int c = 0; c < fInputChannels; c++) {
|
||||
inputs[c][j] = *src++;
|
||||
}
|
||||
}
|
||||
} else if( channels == 1) { //from mone to multichannel
|
||||
for(int j = 0; j < samples; j++, src++) {
|
||||
for(int c = 0; c < fInputChannels; c++) {
|
||||
inputs[c][j] = *src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fEffect->processReplacing(fEffect, inputs, outputs, fBlockSize);
|
||||
|
||||
float *dst = buffer;
|
||||
|
||||
if(channels == fOutputChannels) { //channel to channel
|
||||
for(int j = 0; j < samples; j++) {
|
||||
for(int c = 0; c < fOutputChannels; c++) {
|
||||
*dst++ = outputs[c][j];
|
||||
}
|
||||
}
|
||||
} else if(channels == 1) { //from multichannel to mono
|
||||
for(int j = 0; j < samples; j++, dst++) {
|
||||
float mix = 0;
|
||||
for(int c = 0; c < fOutputChannels; c++) {
|
||||
mix += outputs[c][j];
|
||||
}
|
||||
*dst = mix / (float)fOutputChannels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32
|
||||
VHostCallback(VSTEffect* effect, int32 opcode, int32 index, int32 value, void* ptr, float opt)
|
||||
{
|
||||
intptr_t result = 0;
|
||||
|
||||
switch(opcode)
|
||||
{
|
||||
case VST_MASTER_PRODUCT:
|
||||
if(ptr) {
|
||||
strcpy((char*)ptr, "VSTHost Media AddOn");
|
||||
result = 1;
|
||||
}
|
||||
break;
|
||||
case VST_MASTER_VERSION :
|
||||
result = 2300;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
169
src/add-ons/media/media-add-ons/vst_host/VSTHost.h
Normal file
169
src/add-ons/media/media-add-ons/vst_host/VSTHost.h
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef __VST_HOST_H__
|
||||
#define __VST_HOST_H__
|
||||
|
||||
#include <String.h>
|
||||
#include <Entry.h>
|
||||
#include <Directory.h>
|
||||
#include <Path.h>
|
||||
#include <List.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <image.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define VST_PARAM_TEST_COUNT 100
|
||||
|
||||
//error codes
|
||||
#define VST_ERR_ALREADY_LOADED -1
|
||||
#define VST_ERR_NOT_LOADED -2
|
||||
#define VST_ERR_NO_MAINPROC -3
|
||||
|
||||
//param types
|
||||
#define VST_PARAM_SLIDER 1
|
||||
#define VST_PARAM_CHECKBOX 2
|
||||
#define VST_PARAM_DROPLIST 3
|
||||
|
||||
//channels
|
||||
#define VST_INPUT_CHANNELS 1
|
||||
#define VST_OUTPUT_CHANNELS 2
|
||||
|
||||
//vst callback opcodes
|
||||
#define VST_MASTER_AUTOMATE 0x00
|
||||
#define VST_MASTER_VERSION 0x01
|
||||
#define VST_MASTER_IDLE 0x03
|
||||
#define VST_MASTER_VENDOR 0x20
|
||||
#define VST_MASTER_PRODUCT 0x21
|
||||
|
||||
//vst actions
|
||||
#define VST_OPEN 0x00
|
||||
#define VST_CLOSE 0x01
|
||||
#define VST_GET_PARAM_UNIT 0x06
|
||||
#define VST_GET_PARAM_STR 0x07
|
||||
#define VST_GET_PARAM_NAME 0x08
|
||||
#define VST_SET_SAMPLE_RATE 0x0A
|
||||
#define VST_SET_BLOCK_SIZE 0x0B
|
||||
#define VST_STATE_CHANGED 0x0C
|
||||
#define VST_GET_EFFECT_NAME 0x2D
|
||||
#define VST_GET_VENDOR_STR 0x2F
|
||||
#define VST_GET_PRODUCT_STR 0x30
|
||||
#define VST_GET_VENDOR_VER 0x31
|
||||
|
||||
//vst plugin structure
|
||||
struct VSTEffect
|
||||
{
|
||||
int cookie;
|
||||
int32 (*dispatcher)(struct VSTEffect*, int32, int32, int32, void*, float);
|
||||
void (*process)(struct VSTEffect*, float**, float**, int32);
|
||||
void (*setParameter)(struct VSTEffect*, int32, float);
|
||||
float (*getParameter)(struct VSTEffect*, int32);
|
||||
int32 numPrograms;
|
||||
int32 numParams;
|
||||
int32 numInputs;
|
||||
int32 numOutputs;
|
||||
int32 flags;
|
||||
void* _notused_pointer1;
|
||||
void* _notused_pointer2;
|
||||
char _notused_block1[12];
|
||||
float _notused_float;
|
||||
void* _notused_pointer3;
|
||||
void* _notused_pointer4;
|
||||
int32 ID;
|
||||
char _notused_block2[4];
|
||||
void (*processReplacing)(struct VSTEffect*, float**, float**, int);
|
||||
};
|
||||
|
||||
//typedefs
|
||||
typedef int32 (*audioMasterCallback)(VSTEffect*, int32, int32, int32, void*, float);
|
||||
typedef VSTEffect* (*VSTEntryProc)(audioMasterCallback audioMaster);
|
||||
inline float round(float x) {return ceil(x-0.5);}
|
||||
|
||||
//structure for droplist parameters
|
||||
struct DropListValue {
|
||||
int Index;
|
||||
float Value;
|
||||
BString Name;
|
||||
};
|
||||
|
||||
class VSTPlugin;
|
||||
//vst parameter class adapter
|
||||
class VSTParameter {
|
||||
public:
|
||||
VSTParameter(VSTPlugin* plugin, int index);
|
||||
~VSTParameter();
|
||||
float Value(void);
|
||||
void SetValue(float value);
|
||||
const char* MinimumValue(void);
|
||||
const char* MaximumValue(void);
|
||||
const char* Unit(void);
|
||||
int Index(void);
|
||||
int Type(void);
|
||||
const char* Name(void);
|
||||
int ListCount(void);
|
||||
DropListValue* ListItemAt(int index);
|
||||
bigtime_t LastChangeTime(void);
|
||||
private:
|
||||
BString* ValidateValues(BString *string);
|
||||
VSTPlugin* fPlugin;
|
||||
VSTEffect* fEffect;
|
||||
int fIndex;
|
||||
int fType;
|
||||
BString fName;
|
||||
BString fUnit;
|
||||
BString fMinValue;
|
||||
BString fMaxValue;
|
||||
BList fDropList;
|
||||
bigtime_t fChanged;
|
||||
float fLastValue;
|
||||
};
|
||||
|
||||
//vst plugin interface
|
||||
class VSTPlugin {
|
||||
public:
|
||||
VSTPlugin();
|
||||
~VSTPlugin();
|
||||
int LoadModule(const char *path);
|
||||
int UnLoadModule(void);
|
||||
int SetSampleRate(float rate);
|
||||
float SampleRate(void);
|
||||
int SetBlockSize(size_t size);
|
||||
const char* Path(void);
|
||||
size_t BlockSize(void);
|
||||
VSTEffect* Effect(void);
|
||||
const char* EffectName(void);
|
||||
const char* ModuleName(void);
|
||||
const char* Vendor(void);
|
||||
const char* Product(void);
|
||||
int ParametersCount(void);
|
||||
VSTParameter* Parameter(int index);
|
||||
int Channels(int mode);
|
||||
int ReAllocBuffers(void);
|
||||
void Process(float *buffer, int samples, int channels);
|
||||
private:
|
||||
VSTEntryProc GetMainEntry();
|
||||
VSTEffect* fEffect;
|
||||
VSTEntryProc VSTMainProc;
|
||||
bool fActive;
|
||||
image_id fModule;
|
||||
BPath fPath;
|
||||
size_t fBlockSize;
|
||||
float fSampleRate;
|
||||
int fInputChannels;
|
||||
int fOutputChannels;
|
||||
BString fModuleName;
|
||||
BString fEffectName;
|
||||
BString fVendorString;
|
||||
BString fProductString;
|
||||
BList fParameters;
|
||||
float **inputs;
|
||||
float **outputs;
|
||||
};
|
||||
|
||||
#endif //__VST_HOST_H__
|
15
src/add-ons/media/media-add-ons/vst_host/VSTHost.rdef
Normal file
15
src/add-ons/media/media-add-ons/vst_host/VSTHost.rdef
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* VSTHost.rdef
|
||||
*/
|
||||
|
||||
resource app_signature "application/x-vnd.vst_host.media_addon";
|
||||
|
||||
resource app_version {
|
||||
major = 0,
|
||||
middle = 0,
|
||||
minor = 2,
|
||||
variety = 0,
|
||||
internal = 0,
|
||||
short_info = "0.0.2",
|
||||
long_info = "VST Loader media add-on."
|
||||
};
|
802
src/add-ons/media/media-add-ons/vst_host/VSTNode.cpp
Normal file
802
src/add-ons/media/media-add-ons/vst_host/VSTNode.cpp
Normal file
@ -0,0 +1,802 @@
|
||||
/*
|
||||
* Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <ByteOrder.h>
|
||||
#include <Buffer.h>
|
||||
#include <BufferGroup.h>
|
||||
#include <TimeSource.h>
|
||||
#include <ParameterWeb.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "VSTNode.h"
|
||||
|
||||
//VSTNode
|
||||
VSTNode::~VSTNode() {
|
||||
Quit();
|
||||
}
|
||||
|
||||
VSTNode::VSTNode(BMediaAddOn* addon, const char *name, const char* path) : BMediaNode(name),
|
||||
BBufferConsumer(B_MEDIA_RAW_AUDIO),
|
||||
BBufferProducer(B_MEDIA_RAW_AUDIO),
|
||||
BControllable(),
|
||||
BMediaEventLooper(),
|
||||
fAddOn(addon),
|
||||
fOutputMediaEnabled(true),
|
||||
fDownstreamLatency(0),
|
||||
fProcessLatency(0)
|
||||
{
|
||||
fPlugin = new VSTPlugin();
|
||||
fPlugin->LoadModule(path);
|
||||
}
|
||||
|
||||
//BMediaNode
|
||||
BMediaAddOn* VSTNode::AddOn(int32 *id) const
|
||||
{
|
||||
if(fAddOn) {
|
||||
*id = 0;
|
||||
}
|
||||
return fAddOn;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::HandleMessage(int32 message, const void *data, size_t size)
|
||||
{
|
||||
if((BControllable::HandleMessage(message, data, size)!=B_OK) &&
|
||||
(BBufferConsumer::HandleMessage(message, data, size) != B_OK) &&
|
||||
(BBufferProducer::HandleMessage(message, data, size) != B_OK) &&
|
||||
(BControllable::HandleMessage(message, data, size) != B_OK) ) {
|
||||
BMediaNode::HandleMessage(message, data, size);
|
||||
return B_OK;
|
||||
} else {
|
||||
BMediaNode::HandleBadMessage(message, data, size);
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::NodeRegistered()
|
||||
{
|
||||
SetPriority(B_REAL_TIME_PRIORITY);
|
||||
Run();
|
||||
|
||||
fPreferredFormat.type = B_MEDIA_RAW_AUDIO;
|
||||
fPreferredFormat.u.raw_audio.buffer_size = BUFF_SIZE;
|
||||
fPreferredFormat.u.raw_audio = media_raw_audio_format::wildcard;
|
||||
fPreferredFormat.u.raw_audio.channel_count = media_raw_audio_format::wildcard.channel_count;
|
||||
fPreferredFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
||||
|
||||
fFormat.type = B_MEDIA_RAW_AUDIO;
|
||||
fFormat.u.raw_audio = media_raw_audio_format::wildcard;
|
||||
|
||||
fInputMedia.destination.port = ControlPort();
|
||||
fInputMedia.destination.id = ID_AUDIO_INPUT;
|
||||
fInputMedia.node = Node();
|
||||
fInputMedia.source = media_source::null;
|
||||
fInputMedia.format = fFormat;
|
||||
strncpy(fInputMedia.name, "Audio Input", B_MEDIA_NAME_LENGTH);
|
||||
|
||||
fOutputMedia.source.port = ControlPort();
|
||||
fOutputMedia.source.id = ID_AUDIO_OUTPUT;
|
||||
fOutputMedia.node = Node();
|
||||
fOutputMedia.destination = media_destination::null;
|
||||
fOutputMedia.format = fFormat;
|
||||
strncpy(fOutputMedia.name, "Audio Output", B_MEDIA_NAME_LENGTH);
|
||||
|
||||
InitParameterValues();
|
||||
InitParameterWeb();
|
||||
}
|
||||
|
||||
//BControllable
|
||||
status_t
|
||||
VSTNode::GetParameterValue(int32 id, bigtime_t *lastChangeTime, void *value, size_t *size)
|
||||
{
|
||||
if(*size < sizeof(float) ||
|
||||
*size < sizeof(int32)) {
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
type_code v_type = B_FLOAT_TYPE;
|
||||
|
||||
BParameter *param;
|
||||
for(int i = 0; i < fWeb->CountParameters(); i++) {
|
||||
param = fWeb->ParameterAt(i);
|
||||
if(param->ID() == id) {
|
||||
v_type = param->ValueType();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*size = sizeof(float);
|
||||
|
||||
if(id == P_MUTE) {
|
||||
*(int32*)value = fMute;
|
||||
*lastChangeTime = fMuteLastChanged;
|
||||
return B_OK;
|
||||
} else if(id == P_BYPASS) {
|
||||
*(int32*)value = fByPass;
|
||||
*lastChangeTime = fByPassLastChanged;
|
||||
return B_OK;
|
||||
} else {
|
||||
int32 idx = id - P_PARAM;
|
||||
if(idx >= 0 && idx < fPlugin->ParametersCount()) {
|
||||
VSTParameter *param = fPlugin->Parameter(idx);
|
||||
if(v_type == B_FLOAT_TYPE) {
|
||||
*(float*)value = param->Value();
|
||||
}
|
||||
if(v_type == B_INT32_TYPE) {
|
||||
*(int32*)value = (int32)ceil(param->Value());
|
||||
}
|
||||
*lastChangeTime = param->LastChangeTime();
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::SetParameterValue(int32 id, bigtime_t time, const void *value, size_t size)
|
||||
{
|
||||
int32 idx = id - P_PARAM;
|
||||
if((idx >= 0 && idx < fPlugin->ParametersCount()) || id == P_MUTE || id == P_BYPASS) {
|
||||
media_timed_event ev(time, BTimedEventQueue::B_PARAMETER, (void*)value,
|
||||
BTimedEventQueue::B_NO_CLEANUP, size, id, "VSTParam");
|
||||
ParameterEventProcessing(&ev); //dirty hack for parameter processing (mediakit bug????)
|
||||
EventQueue()->AddEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
//BBufferConsumer
|
||||
void
|
||||
VSTNode::BufferReceived(BBuffer *buffer)
|
||||
{
|
||||
if(buffer->Header()->destination != fInputMedia.destination.id) {
|
||||
buffer->Recycle();
|
||||
return;
|
||||
}
|
||||
|
||||
if(fOutputMedia.destination == media_destination::null || !fOutputMediaEnabled) {
|
||||
buffer->Recycle();
|
||||
return;
|
||||
}
|
||||
|
||||
FilterBuffer(buffer);
|
||||
|
||||
status_t err = SendBuffer(buffer, fOutputMedia.source, fOutputMedia.destination);
|
||||
if (err < B_OK) {
|
||||
buffer->Recycle();
|
||||
}
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::AcceptFormat(const media_destination &dst, media_format *format)
|
||||
{
|
||||
if(dst != fInputMedia.destination) {
|
||||
return B_MEDIA_BAD_DESTINATION;
|
||||
}
|
||||
if(format->type != B_MEDIA_RAW_AUDIO) {
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
|
||||
ValidateFormat((fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
|
||||
fFormat : fPreferredFormat, *format);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::GetNextInput(int32* cookie, media_input* input)
|
||||
{
|
||||
if(*cookie) {
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
++*cookie;
|
||||
*input = fInputMedia;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::DisposeInputCookie(int32 cookie)
|
||||
{
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::FormatChanged(const media_source &src, const media_destination &dst,
|
||||
int32 changeTag, const media_format &format)
|
||||
{
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::ProducerDataStatus(const media_destination &dst, int32 status, bigtime_t when)
|
||||
{
|
||||
if(fOutputMedia.destination != media_destination::null) {
|
||||
SendDataStatus(status, fOutputMedia.destination, when);
|
||||
}
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::GetLatencyFor( const media_destination &dst, bigtime_t *latency,
|
||||
media_node_id* outTimeSource)
|
||||
{
|
||||
|
||||
if(dst != fInputMedia.destination) {
|
||||
return B_MEDIA_BAD_DESTINATION;
|
||||
}
|
||||
|
||||
*latency = fDownstreamLatency + fProcessLatency;
|
||||
*outTimeSource = TimeSource()->ID();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::Connected(const media_source& source,
|
||||
const media_destination& destination, const media_format& format,
|
||||
media_input* poInput)
|
||||
{
|
||||
if(destination != fInputMedia.destination) {
|
||||
return B_MEDIA_BAD_DESTINATION;
|
||||
}
|
||||
if(fInputMedia.source != media_source::null) {
|
||||
return B_MEDIA_ALREADY_CONNECTED;
|
||||
}
|
||||
|
||||
fInputMedia.source = source;
|
||||
fInputMedia.format = format;
|
||||
*poInput = fInputMedia;
|
||||
fFormat = format;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::Disconnected(const media_source &src, const media_destination &dst)
|
||||
{
|
||||
if(fInputMedia.source!=src || dst!=fInputMedia.destination) {
|
||||
return;
|
||||
}
|
||||
fInputMedia.source = media_source::null;
|
||||
if(fOutputMedia.destination == media_destination::null) {
|
||||
fFormat.u.raw_audio = media_raw_audio_format::wildcard;
|
||||
}
|
||||
fInputMedia.format = fFormat;
|
||||
}
|
||||
|
||||
//BBufferProducer
|
||||
status_t
|
||||
VSTNode::FormatSuggestionRequested(media_type type, int32 quality, media_format *format)
|
||||
{
|
||||
if(type != B_MEDIA_RAW_AUDIO) {
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
|
||||
if(fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) {
|
||||
*format = fFormat;
|
||||
} else {
|
||||
*format = fPreferredFormat;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::FormatProposal(const media_source &src, media_format* format)
|
||||
{
|
||||
if(src != fOutputMedia.source) {
|
||||
return B_MEDIA_BAD_SOURCE;
|
||||
}
|
||||
|
||||
if(format->type != B_MEDIA_RAW_AUDIO) {
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
|
||||
ValidateFormat((fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
|
||||
fFormat : fPreferredFormat, *format);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::FormatChangeRequested(const media_source &src, const media_destination &dst,
|
||||
media_format* format, int32* _deprecated_)
|
||||
{
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::LateNoticeReceived(const media_source &src, bigtime_t late, bigtime_t when)
|
||||
{
|
||||
if(src != fOutputMedia.source || fInputMedia.source == media_source::null) {
|
||||
return;
|
||||
}
|
||||
NotifyLateProducer( fInputMedia.source, late, when);
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::GetNextOutput(int32 *cookie, media_output* output)
|
||||
{
|
||||
if(*cookie) {
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
++*cookie;
|
||||
*output = fOutputMedia;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::DisposeOutputCookie(int32 cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::SetBufferGroup(const media_source &src, BBufferGroup *group)
|
||||
{
|
||||
int32 changeTag;
|
||||
|
||||
if(src != fOutputMedia.source) {
|
||||
return B_MEDIA_BAD_SOURCE;
|
||||
}
|
||||
if(fInputMedia.source == media_source::null) {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return SetOutputBuffersFor(fInputMedia.source, fInputMedia.destination, group, 0, &changeTag);
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::PrepareToConnect( const media_source &src, const media_destination &dst,
|
||||
media_format *format, media_source *out_source, char *name)
|
||||
{
|
||||
if(src != fOutputMedia.source) {
|
||||
return B_MEDIA_BAD_SOURCE;
|
||||
}
|
||||
|
||||
if(format->type != B_MEDIA_RAW_AUDIO) {
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
|
||||
if(fOutputMedia.destination != media_destination::null) {
|
||||
return B_MEDIA_ALREADY_CONNECTED;
|
||||
}
|
||||
|
||||
status_t err = ValidateFormat((fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
|
||||
fFormat : fPreferredFormat, *format);
|
||||
|
||||
if(err < B_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
SetOutputFormat(*format);
|
||||
|
||||
fOutputMedia.destination = dst;
|
||||
fOutputMedia.format = *format;
|
||||
|
||||
*out_source = fOutputMedia.source;
|
||||
strncpy(name, fOutputMedia.name, B_MEDIA_NAME_LENGTH);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::Connect(status_t status, const media_source &src, const media_destination &dst,
|
||||
const media_format &format, char *name)
|
||||
{
|
||||
status_t err;
|
||||
if(status < B_OK) {
|
||||
fOutputMedia.destination = media_destination::null;
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy(name, fOutputMedia.name, B_MEDIA_NAME_LENGTH);
|
||||
fOutputMedia.destination = dst;
|
||||
fFormat = format;
|
||||
|
||||
media_node_id timeSource;
|
||||
err = FindLatencyFor(fOutputMedia.destination, &fDownstreamLatency, &timeSource);
|
||||
|
||||
InitFilter();
|
||||
|
||||
fProcessLatency = GetFilterLatency();
|
||||
SetEventLatency(fDownstreamLatency + fProcessLatency);
|
||||
|
||||
if(fInputMedia.source != media_source::null) {
|
||||
SendLatencyChange(fInputMedia.source, fInputMedia.destination,
|
||||
EventLatency()+SchedulingLatency());
|
||||
}
|
||||
|
||||
bigtime_t duration = 0;
|
||||
|
||||
int sample_size = (fFormat.u.raw_audio.format & 0xf)*
|
||||
fFormat.u.raw_audio.channel_count;
|
||||
if(fFormat.u.raw_audio.buffer_size > 0 &&
|
||||
fFormat.u.raw_audio.frame_rate > 0 &&
|
||||
sample_size > 0) {
|
||||
duration = (bigtime_t)(((fFormat.u.raw_audio.buffer_size / sample_size) /
|
||||
fFormat.u.raw_audio.frame_rate) * 1000000.0);
|
||||
}
|
||||
|
||||
SetBufferDuration(duration);
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::Disconnect(const media_source &src, const media_destination &dst)
|
||||
{
|
||||
if(src != fOutputMedia.source) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(dst != fOutputMedia.destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
fOutputMedia.destination = media_destination::null;
|
||||
|
||||
if(fInputMedia.source == media_source::null) {
|
||||
fFormat.u.raw_audio = media_raw_audio_format::wildcard;
|
||||
}
|
||||
|
||||
fOutputMedia.format = fFormat;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::EnableOutput(const media_source &src, bool enabled, int32* _deprecated_)
|
||||
{
|
||||
if(src != fOutputMedia.source) {
|
||||
return;
|
||||
}
|
||||
fOutputMediaEnabled = enabled;
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::GetLatency(bigtime_t *latency)
|
||||
{
|
||||
*latency = EventLatency() + SchedulingLatency();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::LatencyChanged(const media_source &src, const media_destination &dst,
|
||||
bigtime_t latency, uint32 flags)
|
||||
{
|
||||
if(src != fOutputMedia.source || dst != fOutputMedia.destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
fDownstreamLatency = latency;
|
||||
SetEventLatency(fDownstreamLatency + fProcessLatency);
|
||||
|
||||
if(fInputMedia.source != media_source::null) {
|
||||
SendLatencyChange(fInputMedia.source,
|
||||
fInputMedia.destination,EventLatency() + SchedulingLatency());
|
||||
}
|
||||
}
|
||||
|
||||
//BMediaEventLooper
|
||||
bigtime_t
|
||||
VSTNode::OfflineTime()
|
||||
{
|
||||
return 0LL;
|
||||
}
|
||||
|
||||
//VSTNode
|
||||
void
|
||||
VSTNode::HandleEvent(const media_timed_event *event, bigtime_t late, bool realTime)
|
||||
{
|
||||
if(event->type == BTimedEventQueue::B_PARAMETER) {
|
||||
ParameterEventProcessing(event);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::ParameterEventProcessing(const media_timed_event* event)
|
||||
{
|
||||
float value = 0.0;
|
||||
int32 value32 = 0;
|
||||
|
||||
int32 id = event->bigdata;
|
||||
size_t size = event->data;
|
||||
bigtime_t now = TimeSource()->Now();
|
||||
|
||||
type_code v_type = B_FLOAT_TYPE;
|
||||
|
||||
BParameter *web_param;
|
||||
for(int i = 0; i < fWeb->CountParameters(); i++) {
|
||||
web_param = fWeb->ParameterAt(i);
|
||||
if(web_param->ID()==id) {
|
||||
v_type=web_param->ValueType();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(v_type == B_FLOAT_TYPE)
|
||||
value = *((float*)event->pointer);
|
||||
if(v_type == B_INT32_TYPE) {
|
||||
value32 = *((int32*)event->pointer);
|
||||
value = (float)value32;
|
||||
}
|
||||
|
||||
if(id == P_MUTE) {
|
||||
fMute = value32;
|
||||
fMuteLastChanged = now;
|
||||
BroadcastNewParameterValue(now, id, event->pointer, size);
|
||||
} else if(id == P_BYPASS) {
|
||||
fByPass = value32;
|
||||
fByPassLastChanged = now;
|
||||
BroadcastNewParameterValue(now, id, event->pointer, size);
|
||||
} else {
|
||||
int32 idx = id - P_PARAM;
|
||||
if(idx >= 0 && idx < fPlugin->ParametersCount()) {
|
||||
VSTParameter *param = fPlugin->Parameter(idx);
|
||||
param->SetValue(value);
|
||||
BroadcastNewParameterValue(now, id, &value, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status_t
|
||||
VSTNode::ValidateFormat(const media_format &preferredFormat,
|
||||
media_format &proposedFormat)
|
||||
{
|
||||
status_t ret = B_OK;
|
||||
|
||||
if(proposedFormat.type != B_MEDIA_RAW_AUDIO) {
|
||||
proposedFormat = preferredFormat;
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
|
||||
media_raw_audio_format &wild = media_raw_audio_format::wildcard;
|
||||
media_raw_audio_format &f = proposedFormat.u.raw_audio;
|
||||
const media_raw_audio_format &pref = preferredFormat.u.raw_audio;
|
||||
|
||||
if(pref.frame_rate != wild.frame_rate && f.frame_rate != pref.frame_rate) {
|
||||
if(f.frame_rate != wild.frame_rate) {
|
||||
ret = B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
f.frame_rate = pref.frame_rate;
|
||||
}
|
||||
|
||||
if(pref.channel_count != wild.channel_count && f.channel_count != pref.channel_count) {
|
||||
if(f.channel_count != wild.channel_count) {
|
||||
ret = B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
f.channel_count = pref.channel_count;
|
||||
}
|
||||
|
||||
if(pref.format != wild.format && f.format != pref.format) {
|
||||
if(f.format != wild.format) {
|
||||
ret = B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
f.format = pref.format;
|
||||
}
|
||||
|
||||
if(pref.byte_order != wild.byte_order && f.byte_order != pref.byte_order) {
|
||||
if(f.byte_order != wild.byte_order) {
|
||||
ret = B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
f.byte_order = pref.byte_order;
|
||||
}
|
||||
|
||||
if(pref.buffer_size != wild.buffer_size && f.buffer_size != pref.buffer_size) {
|
||||
if(f.buffer_size != wild.buffer_size) {
|
||||
ret = B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
f.buffer_size = pref.buffer_size;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VSTNode::SetOutputFormat(media_format &format)
|
||||
{
|
||||
media_raw_audio_format &f = format.u.raw_audio;
|
||||
media_raw_audio_format &w = media_raw_audio_format::wildcard;
|
||||
|
||||
if(f.frame_rate == w.frame_rate) {
|
||||
f.frame_rate = 44100.0;
|
||||
}
|
||||
if(f.channel_count == w.channel_count) {
|
||||
if(fInputMedia.source != media_source::null) {
|
||||
f.channel_count = fInputMedia.format.u.raw_audio.channel_count;
|
||||
} else {
|
||||
f.channel_count = fPlugin->Channels(VST_OUTPUT_CHANNELS);
|
||||
}
|
||||
}
|
||||
if(f.format == w.format) {
|
||||
f.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
||||
}
|
||||
if(f.byte_order == w.format) {
|
||||
f.byte_order = (B_HOST_IS_BENDIAN)?B_MEDIA_BIG_ENDIAN:B_MEDIA_LITTLE_ENDIAN;
|
||||
}
|
||||
if(f.buffer_size == w.buffer_size) {
|
||||
f.buffer_size = BUFF_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::InitParameterValues()
|
||||
{
|
||||
fMute = 0;
|
||||
fByPass = 0;
|
||||
fMuteLastChanged = 0LL;
|
||||
fByPassLastChanged = 0LL;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::InitParameterWeb()
|
||||
{
|
||||
fWeb = new BParameterWeb();
|
||||
|
||||
bool switch_group_needed = false;
|
||||
for(int i = 0; i < fPlugin->ParametersCount(); i++) {
|
||||
VSTParameter *param = fPlugin->Parameter(i);
|
||||
if(param->Type() == VST_PARAM_CHECKBOX ||
|
||||
param->Type() == VST_PARAM_DROPLIST) {
|
||||
switch_group_needed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BParameterGroup *fParamGroup = fWeb->MakeGroup("Parameters");
|
||||
BParameterGroup *fSwitchesGroup = switch_group_needed?fWeb->MakeGroup("Switches"):NULL;
|
||||
BParameterGroup *fAboutGroup = fWeb->MakeGroup("About");
|
||||
|
||||
BParameter *value;
|
||||
BNullParameter *label;
|
||||
BParameterGroup *group;
|
||||
|
||||
BParameterGroup *fFControlGroup = fParamGroup->MakeGroup("FilterControl");
|
||||
BParameterGroup *fCheckBoxGroup = switch_group_needed?fSwitchesGroup->MakeGroup("CheckBoxes") : NULL;
|
||||
BParameterGroup *fSelectorsGroup = switch_group_needed?fSwitchesGroup->MakeGroup("Selectors") : NULL;
|
||||
|
||||
fFControlGroup->MakeDiscreteParameter(P_MUTE, B_MEDIA_NO_TYPE,"Mute", B_ENABLE);
|
||||
fFControlGroup->MakeDiscreteParameter(P_BYPASS, B_MEDIA_NO_TYPE,"ByPass", B_ENABLE);
|
||||
|
||||
for(int i = 0; i < fPlugin->ParametersCount(); i++) {
|
||||
VSTParameter *param = fPlugin->Parameter(i);
|
||||
switch(param->Type()) {
|
||||
case VST_PARAM_CHECKBOX:
|
||||
{
|
||||
BString str;
|
||||
str << param->Name() << " (" << param->MinimumValue() << "/" << param->MaximumValue() << ")";
|
||||
value = fCheckBoxGroup->MakeDiscreteParameter(P_PARAM + param->Index(),
|
||||
B_MEDIA_NO_TYPE, str.String(), B_ENABLE);
|
||||
break;
|
||||
}
|
||||
case VST_PARAM_DROPLIST:
|
||||
{
|
||||
BDiscreteParameter *dvalue = fSelectorsGroup->MakeDiscreteParameter(P_PARAM + param->Index(),
|
||||
B_MEDIA_NO_TYPE, param->Name(), B_OUTPUT_MUX);
|
||||
for(int j = 0; j < param->ListCount(); j++) {
|
||||
dvalue->AddItem( param->ListItemAt(j)->Index, param->ListItemAt(j)->Name.String());
|
||||
}
|
||||
break;
|
||||
}
|
||||
//sliders
|
||||
default:
|
||||
{
|
||||
BString str;
|
||||
group = fParamGroup->MakeGroup(param->Name());
|
||||
label = group->MakeNullParameter(P_LABEL + param->Index(),
|
||||
B_MEDIA_NO_TYPE, param->Name(), B_GENERIC);
|
||||
|
||||
str.SetTo(param->MaximumValue());
|
||||
str << " " << param->Unit();
|
||||
|
||||
group->MakeNullParameter(P_LABEL2 + param->Index(),
|
||||
B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
|
||||
value = group->MakeContinuousParameter(P_PARAM + param->Index(),
|
||||
B_MEDIA_NO_TYPE, "", B_GAIN, "", 0.0, 1.0, 0.01);
|
||||
label->AddOutput(value);
|
||||
value->AddInput(label);
|
||||
|
||||
str.SetTo(param->MinimumValue());
|
||||
str << " " << param->Unit();
|
||||
|
||||
group->MakeNullParameter(P_LABEL3 + param->Index(),
|
||||
B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BString str("About plugin");
|
||||
label = fAboutGroup->MakeNullParameter(P_ABOUT + 0,
|
||||
B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
|
||||
|
||||
str.SetTo("Effect name: ");
|
||||
if(strlen(fPlugin->EffectName()) != 0) {
|
||||
str.Append(fPlugin->EffectName());
|
||||
} else {
|
||||
str.Append("not specified");
|
||||
}
|
||||
label = fAboutGroup->MakeNullParameter(P_ABOUT + 1,
|
||||
B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
|
||||
|
||||
str.SetTo("Vendor: ");
|
||||
if(strlen(fPlugin->Vendor()) != 0) {
|
||||
str.Append(fPlugin->Vendor());
|
||||
} else {
|
||||
str.Append("not specified");
|
||||
}
|
||||
label = fAboutGroup->MakeNullParameter(P_ABOUT + 2,
|
||||
B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
|
||||
|
||||
str.SetTo("Product: ");
|
||||
if(strlen(fPlugin->Product()) != 0) {
|
||||
str.Append(fPlugin->Product());
|
||||
} else {
|
||||
str.Append("not specified");
|
||||
}
|
||||
label = fAboutGroup->MakeNullParameter(P_ABOUT + 3,
|
||||
B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
|
||||
|
||||
str.SetTo("Input Channels: ");
|
||||
str<<fPlugin->Channels(VST_INPUT_CHANNELS);
|
||||
label = fAboutGroup->MakeNullParameter(P_ABOUT + 4,
|
||||
B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
|
||||
|
||||
str.SetTo("Output Channels: ");
|
||||
str<<fPlugin->Channels(VST_OUTPUT_CHANNELS);
|
||||
label = fAboutGroup->MakeNullParameter(P_ABOUT + 5,
|
||||
B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
|
||||
|
||||
SetParameterWeb(fWeb);
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::InitFilter()
|
||||
{
|
||||
fBlockSize = fFormat.u.raw_audio.buffer_size /
|
||||
(fFormat.u.raw_audio.channel_count * sizeof(float));
|
||||
|
||||
fPlugin->SetBlockSize(fBlockSize);
|
||||
fPlugin->SetSampleRate(fFormat.u.raw_audio.frame_rate);
|
||||
}
|
||||
|
||||
bigtime_t
|
||||
VSTNode::GetFilterLatency()
|
||||
{
|
||||
if(fOutputMedia.destination == media_destination::null) {
|
||||
return 0LL;
|
||||
}
|
||||
|
||||
BBufferGroup *temp_group = new BBufferGroup(fOutputMedia.format.u.raw_audio.buffer_size, 1);
|
||||
|
||||
BBuffer *buffer = temp_group->RequestBuffer(fOutputMedia.format.u.raw_audio.buffer_size);
|
||||
buffer->Header()->type = B_MEDIA_RAW_AUDIO;
|
||||
buffer->Header()->size_used = fOutputMedia.format.u.raw_audio.buffer_size;
|
||||
|
||||
bigtime_t begin = system_time();
|
||||
FilterBuffer(buffer);
|
||||
bigtime_t latency = system_time()-begin;
|
||||
|
||||
InitFilter();
|
||||
|
||||
buffer->Recycle();
|
||||
delete temp_group;
|
||||
|
||||
return latency;
|
||||
}
|
||||
|
||||
void
|
||||
VSTNode::FilterBuffer(BBuffer* buffer)
|
||||
{
|
||||
uint32 m_frameSize = (fFormat.u.raw_audio.format & 0x0f)*
|
||||
fFormat.u.raw_audio.channel_count;
|
||||
uint32 samples = buffer->Header()->size_used / m_frameSize;
|
||||
uint32 channels = fFormat.u.raw_audio.channel_count;
|
||||
|
||||
if(fMute != 0) {
|
||||
memset(buffer->Data(), 0, buffer->Header()->size_used);
|
||||
} else {
|
||||
if(fByPass == 0) {
|
||||
fPlugin->Process((float*)buffer->Data(), samples, channels);
|
||||
}
|
||||
}
|
||||
}
|
149
src/add-ons/media/media-add-ons/vst_host/VSTNode.h
Normal file
149
src/add-ons/media/media-add-ons/vst_host/VSTNode.h
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef __VST_NODE_H__
|
||||
#define __VST_NODE_H__
|
||||
|
||||
#include <Controllable.h>
|
||||
#include <BufferProducer.h>
|
||||
#include <BufferConsumer.h>
|
||||
#include <MediaEventLooper.h>
|
||||
|
||||
#include "VSTHost.h"
|
||||
|
||||
class BMediaAddOn;
|
||||
class BBufferGroup;
|
||||
|
||||
#define BUFF_SIZE 0x2000
|
||||
|
||||
#define ID_AUDIO_INPUT 1
|
||||
#define ID_AUDIO_OUTPUT 2
|
||||
|
||||
//parameter IDs
|
||||
enum param_id_t {
|
||||
P_MUTE = 50,
|
||||
P_BYPASS,
|
||||
|
||||
P_PARAM = 5000,
|
||||
P_ABOUT = 6000,
|
||||
P_LABEL = 7000,
|
||||
P_LABEL2 = 8000,
|
||||
P_LABEL3 = 9000,
|
||||
};
|
||||
|
||||
|
||||
class VSTNode : public BBufferConsumer,
|
||||
public BBufferProducer,
|
||||
public BControllable,
|
||||
public BMediaEventLooper {
|
||||
public:
|
||||
virtual ~VSTNode();
|
||||
VSTNode(BMediaAddOn *addon, const char *name, const char* path);
|
||||
//BMediaNode
|
||||
public:
|
||||
virtual BMediaAddOn *AddOn(int32 *id) const;
|
||||
virtual status_t HandleMessage(int32 code, const void *data, size_t size);
|
||||
protected:
|
||||
virtual void NodeRegistered();
|
||||
//BControllable
|
||||
public:
|
||||
virtual status_t GetParameterValue(int32 id, bigtime_t *lastChangeTime,
|
||||
void *value, size_t *size);
|
||||
virtual void SetParameterValue(int32 id, bigtime_t changeTime,
|
||||
const void *value, size_t size);
|
||||
//BBufferConsumer
|
||||
public:
|
||||
virtual void BufferReceived(BBuffer *buffer);
|
||||
virtual status_t AcceptFormat(const media_destination &dst,
|
||||
media_format *format);
|
||||
virtual status_t GetNextInput(int32 *cookie, media_input *input);
|
||||
virtual void DisposeInputCookie(int32 cookie);
|
||||
virtual status_t FormatChanged(const media_source &src,
|
||||
const media_destination &dst,
|
||||
int32 change_tag, const media_format &format);
|
||||
virtual void ProducerDataStatus(const media_destination &dst,
|
||||
int32 status,
|
||||
bigtime_t when);
|
||||
virtual status_t GetLatencyFor(const media_destination &dst,
|
||||
bigtime_t *latency,
|
||||
media_node_id *time_src);
|
||||
virtual status_t Connected(const media_source &src,
|
||||
const media_destination &dst,
|
||||
const media_format &format,
|
||||
media_input *input);
|
||||
virtual void Disconnected(const media_source &src,
|
||||
const media_destination &dst);
|
||||
//BBufferProducer
|
||||
public:
|
||||
virtual status_t FormatSuggestionRequested(media_type type,
|
||||
int32 quality, media_format *format);
|
||||
virtual status_t FormatProposal(const media_source &src,
|
||||
media_format *format);
|
||||
virtual status_t FormatChangeRequested(const media_source &src,
|
||||
const media_destination &dst,
|
||||
media_format *format,
|
||||
int32* _deprecated_);
|
||||
virtual void LateNoticeReceived(const media_source &src,
|
||||
bigtime_t late, bigtime_t when);
|
||||
virtual status_t GetNextOutput(int32 *cookie, media_output *output);
|
||||
virtual status_t DisposeOutputCookie(int32 cookie);
|
||||
virtual status_t SetBufferGroup(const media_source &src,
|
||||
BBufferGroup *group);
|
||||
virtual status_t PrepareToConnect(const media_source &src,
|
||||
const media_destination &dst,
|
||||
media_format *format, media_source *out_source,
|
||||
char *name);
|
||||
virtual void Connect(status_t status,
|
||||
const media_source &src,
|
||||
const media_destination &dst,
|
||||
const media_format &format,
|
||||
char* name);
|
||||
virtual void Disconnect(const media_source &src,
|
||||
const media_destination &dst);
|
||||
virtual void EnableOutput(const media_source &src,
|
||||
bool enabled, int32* _deprecated_);
|
||||
virtual status_t GetLatency(bigtime_t *outLatency);
|
||||
virtual void LatencyChanged( const media_source &src,
|
||||
const media_destination &dst,
|
||||
bigtime_t latency, uint32 flags);
|
||||
//BMediaEventLooper
|
||||
protected:
|
||||
virtual bigtime_t OfflineTime();
|
||||
//VSTNode
|
||||
protected:
|
||||
virtual void HandleEvent(const media_timed_event *event,
|
||||
bigtime_t late,
|
||||
bool realTimeEvent=false);
|
||||
void ParameterEventProcessing(const media_timed_event *event);
|
||||
status_t ValidateFormat(const media_format& preferredFormat,
|
||||
media_format &proposedFormat);
|
||||
void SetOutputFormat(media_format& ioFormat);
|
||||
virtual void InitParameterValues();
|
||||
virtual void InitParameterWeb();
|
||||
virtual void InitFilter();
|
||||
virtual bigtime_t GetFilterLatency();
|
||||
virtual void FilterBuffer(BBuffer* pBuffer);
|
||||
|
||||
private:
|
||||
BMediaAddOn *fAddOn;
|
||||
VSTPlugin *fPlugin;
|
||||
BParameterWeb *fWeb;
|
||||
|
||||
media_format fPreferredFormat;
|
||||
media_format fFormat;
|
||||
media_input fInputMedia;
|
||||
media_output fOutputMedia;
|
||||
bool fOutputMediaEnabled;
|
||||
bigtime_t fDownstreamLatency;
|
||||
bigtime_t fProcessLatency;
|
||||
|
||||
int32 fBlockSize;
|
||||
int32 fMute;
|
||||
int32 fByPass;
|
||||
bigtime_t fMuteLastChanged;
|
||||
bigtime_t fByPassLastChanged;
|
||||
};
|
||||
|
||||
#endif //__VST_NODE_H__
|
Loading…
Reference in New Issue
Block a user