mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-10 23:46:20 +01:00
a lot of VST support odds-and-ends, including preset discovery and support, extending vestige header a bit, some new thread stuff (may break compilation against JACK, and deliver partial tempo/meter info to VST plugins
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@4824 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
6a869dfb7a
commit
82da4fa3ac
13 changed files with 298 additions and 40 deletions
|
|
@ -38,6 +38,8 @@
|
|||
#include <gtkmm/adjustment.h>
|
||||
#include <gtkmm/togglebutton.h>
|
||||
#include <gtkmm/socket.h>
|
||||
#include <gtkmm/combobox.h>
|
||||
#include <gtkmm/liststore.h>
|
||||
#include <gtkmm/comboboxtext.h>
|
||||
#include <gtkmm/socket.h>
|
||||
|
||||
|
|
@ -264,6 +266,22 @@ class VSTPluginUI : public PlugUIBase, public Gtk::VBox
|
|||
|
||||
bool configure_handler (GdkEventConfigure*, Gtk::Socket*);
|
||||
void save_plugin_setting ();
|
||||
|
||||
struct PresetModelColumns : public Gtk::TreeModel::ColumnRecord {
|
||||
PresetModelColumns() {
|
||||
add (name);
|
||||
add (number);
|
||||
}
|
||||
Gtk::TreeModelColumn<Glib::ustring> name;
|
||||
Gtk::TreeModelColumn<int> number;
|
||||
};
|
||||
|
||||
PresetModelColumns preset_columns;
|
||||
Glib::RefPtr<Gtk::ListStore> preset_model;
|
||||
Gtk::ComboBox vst_preset_combo;
|
||||
|
||||
void create_preset_store ();
|
||||
void preset_chosen ();
|
||||
};
|
||||
#endif // VST_SUPPORT
|
||||
|
||||
|
|
|
|||
|
|
@ -35,11 +35,17 @@ VSTPluginUI::VSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<
|
|||
: PlugUIBase (pi),
|
||||
vst (vp)
|
||||
{
|
||||
create_preset_store ();
|
||||
|
||||
fst_run_editor (vst->fst());
|
||||
|
||||
preset_box.set_spacing (6);
|
||||
preset_box.set_border_width (6);
|
||||
preset_box.pack_end (bypass_button, false, false, 10);
|
||||
preset_box.pack_end (save_button, false, false);
|
||||
preset_box.pack_end (preset_combo, false, false);
|
||||
preset_box.pack_end (vst_preset_combo, false, false);
|
||||
|
||||
vst_preset_combo.signal_changed().connect (mem_fun (*this, &VSTPluginUI::preset_chosen));
|
||||
|
||||
bypass_button.set_active (!insert->active());
|
||||
|
||||
|
|
@ -52,6 +58,17 @@ VSTPluginUI::~VSTPluginUI ()
|
|||
// nothing to do here - plugin destructor destroys the GUI
|
||||
}
|
||||
|
||||
void
|
||||
VSTPluginUI::preset_chosen ()
|
||||
{
|
||||
int program = vst_preset_combo.get_active_row_number ();
|
||||
cerr << "switch to program " << program << endl;
|
||||
// cant be done here. plugin only expects one GUI thread.
|
||||
//jvst->fst->plugin->dispatcher( jvst->fst->plugin, effSetProgram, 0, program, NULL, 0.0 );
|
||||
vst->fst()->want_program = program;
|
||||
socket.grab_focus ();
|
||||
}
|
||||
|
||||
int
|
||||
VSTPluginUI::get_preferred_height ()
|
||||
{
|
||||
|
|
@ -121,6 +138,44 @@ VSTPluginUI::configure_handler (GdkEventConfigure* ev, Gtk::Socket *socket)
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
VSTPluginUI::create_preset_store ()
|
||||
{
|
||||
FST *fst = vst->fst();
|
||||
int vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, NULL, 0.0f);
|
||||
|
||||
preset_model = ListStore::create (preset_columns);
|
||||
|
||||
cerr << "There are " << fst->plugin->numPrograms << " programs\n";
|
||||
|
||||
for (int i = 0; i < fst->plugin->numPrograms; ++i) {
|
||||
char buf[100];
|
||||
TreeModel::Row row = *(preset_model->append());
|
||||
|
||||
snprintf (buf, 90, "preset %d", i);
|
||||
|
||||
if (vst_version >= 2) {
|
||||
fst->plugin->dispatcher (fst->plugin, 29, i, 0, buf, 0.0);
|
||||
}
|
||||
|
||||
row[preset_columns.name] = buf;
|
||||
row[preset_columns.number] = i;
|
||||
|
||||
cerr << "Preset " << i << " => " << buf << endl;
|
||||
}
|
||||
|
||||
if (fst->plugin->numPrograms > 0) {
|
||||
fst->plugin->dispatcher( fst->plugin, effSetProgram, 0, 0, NULL, 0.0 );
|
||||
}
|
||||
|
||||
vst_preset_combo.set_model (preset_model);
|
||||
|
||||
CellRenderer* renderer = manage (new CellRendererText());
|
||||
vst_preset_combo.pack_start (*renderer, true);
|
||||
vst_preset_combo.add_attribute (*renderer, "text", 0);
|
||||
vst_preset_combo.set_active (0);
|
||||
}
|
||||
|
||||
typedef int (*error_handler_t)( Display *, XErrorEvent *);
|
||||
static Display *the_gtk_display;
|
||||
static error_handler_t wine_error_handler;
|
||||
|
|
@ -146,3 +201,4 @@ gui_init (int *argc, char **argv[])
|
|||
the_gtk_display = gdk_x11_display_get_xdisplay (gdk_display_get_default());
|
||||
gtk_error_handler = XSetErrorHandler( fst_xerror_handler );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1308,6 +1308,8 @@ Session::disable_record (bool rt_context, bool force)
|
|||
|
||||
if ((rs = (RecordState) g_atomic_int_get (&_record_status)) != Disabled) {
|
||||
|
||||
cerr << "disable record is doing something\n";
|
||||
|
||||
if ((!Config->get_latched_record_enable () && !play_loop) || force) {
|
||||
g_atomic_int_set (&_record_status, Disabled);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ using namespace ARDOUR;
|
|||
using namespace sigc;
|
||||
using namespace PBD;
|
||||
|
||||
#define DEBUG_TRANSPORT
|
||||
|
||||
void
|
||||
Session::request_input_change_handling ()
|
||||
{
|
||||
|
|
@ -77,6 +79,9 @@ void
|
|||
Session::request_transport_speed (float speed)
|
||||
{
|
||||
Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, speed);
|
||||
#ifdef DEBUG_TRANSPORT
|
||||
cerr << "Queued transport speed request @ " << speed << endl;
|
||||
#endif
|
||||
queue_event (ev);
|
||||
}
|
||||
|
||||
|
|
@ -136,11 +141,13 @@ Session::realtime_stop (bool abort)
|
|||
{
|
||||
/* assume that when we start, we'll be moving forwards */
|
||||
|
||||
#if 1
|
||||
if (_transport_speed < 0.0f) {
|
||||
post_transport_work = PostTransportWork (post_transport_work | PostTransportStop | PostTransportReverse);
|
||||
} else {
|
||||
post_transport_work = PostTransportWork (post_transport_work | PostTransportStop);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (actively_recording()) {
|
||||
|
||||
|
|
@ -162,21 +169,25 @@ Session::realtime_stop (bool abort)
|
|||
post_transport_work = PostTransportWork (post_transport_work | PostTransportAbort);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
_clear_event_type (Event::StopOnce);
|
||||
_clear_event_type (Event::RangeStop);
|
||||
_clear_event_type (Event::RangeLocate);
|
||||
|
||||
disable_record (true);
|
||||
|
||||
reset_slave_state ();
|
||||
|
||||
// disable_record (true);
|
||||
|
||||
// reset_slave_state ();
|
||||
#endif
|
||||
_transport_speed = 0;
|
||||
|
||||
#if 0
|
||||
if (Config->get_use_video_sync()) {
|
||||
waiting_for_sync_offset = true;
|
||||
}
|
||||
|
||||
transport_sub_state = ((Config->get_slave_source() == None && Config->get_auto_return()) ? AutoReturning : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -190,6 +201,8 @@ Session::butler_transport_work ()
|
|||
int on_entry = g_atomic_int_get (&butler_should_do_transport_work);
|
||||
finished = true;
|
||||
|
||||
cerr << "PTW = " << hex << post_transport_work << dec << endl;
|
||||
|
||||
if (post_transport_work & PostTransportCurveRealloc) {
|
||||
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
||||
(*i)->curve_reallocate();
|
||||
|
|
@ -235,11 +248,12 @@ Session::butler_transport_work ()
|
|||
}
|
||||
|
||||
if (post_transport_work & (PostTransportStop|PostTransportLocate)) {
|
||||
non_realtime_stop (post_transport_work & PostTransportAbort, on_entry, finished);
|
||||
if (!finished) {
|
||||
g_atomic_int_dec_and_test (&butler_should_do_transport_work);
|
||||
goto restart;
|
||||
}
|
||||
// cerr << "call NRS\n";
|
||||
// non_realtime_stop (post_transport_work & PostTransportAbort, on_entry, finished);
|
||||
// if (!finished) {
|
||||
// g_atomic_int_dec_and_test (&butler_should_do_transport_work);
|
||||
// goto restart;
|
||||
// }
|
||||
}
|
||||
|
||||
if (post_transport_work & PostTransportOverWrite) {
|
||||
|
|
@ -294,6 +308,8 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
|
|||
did_record = false;
|
||||
saved = false;
|
||||
|
||||
cerr << "NRS\n";
|
||||
|
||||
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
|
||||
|
||||
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
|
||||
|
|
@ -351,6 +367,8 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
|
|||
_have_captured = true;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
|
||||
(*i)->transport_stopped (*now, xnow, abort);
|
||||
}
|
||||
|
|
@ -377,6 +395,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
|
|||
synced_to_jack()) {
|
||||
|
||||
if (pending_locate_flush) {
|
||||
cerr << "Flush all redirects\n";
|
||||
flush_all_redirects ();
|
||||
}
|
||||
|
||||
|
|
@ -480,7 +499,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
|
|||
}
|
||||
|
||||
if (post_transport_work & PostTransportStop) {
|
||||
_play_range = false;
|
||||
// _play_range = false;
|
||||
|
||||
/* do not turn off autoloop on stop */
|
||||
|
||||
|
|
@ -778,6 +797,10 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
|
|||
void
|
||||
Session::set_transport_speed (float speed, bool abort)
|
||||
{
|
||||
#ifdef DEBUG_TRANSPORT
|
||||
cerr << "Session::set_trasport_speed, new = " << speed
|
||||
<< " cur = " << _transport_speed << endl;
|
||||
#endif
|
||||
if (_transport_speed == speed) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -886,6 +909,10 @@ Session::set_transport_speed (float speed, bool abort)
|
|||
void
|
||||
Session::stop_transport (bool abort)
|
||||
{
|
||||
#ifdef DEBUG_TRANSPORT
|
||||
cerr << "Session::stop_transport @ " << _transport_frame << endl;
|
||||
#endif
|
||||
|
||||
if (_transport_speed == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -921,12 +948,16 @@ Session::stop_transport (bool abort)
|
|||
}
|
||||
|
||||
realtime_stop (abort);
|
||||
schedule_butler_transport_work ();
|
||||
// schedule_butler_transport_work ();
|
||||
}
|
||||
|
||||
void
|
||||
Session::start_transport ()
|
||||
{
|
||||
#ifdef DEBUG_TRANSPORT
|
||||
cerr << "Session::start_transport @ " << _transport_frame << endl;
|
||||
#endif
|
||||
|
||||
_last_roll_location = _transport_frame;
|
||||
have_looped = false;
|
||||
|
||||
|
|
@ -977,7 +1008,7 @@ Session::post_transport ()
|
|||
|
||||
if (post_transport_work & PostTransportStop) {
|
||||
|
||||
transport_sub_state = 0;
|
||||
// transport_sub_state = 0;
|
||||
}
|
||||
|
||||
if (post_transport_work & PostTransportLocate) {
|
||||
|
|
|
|||
|
|
@ -24,11 +24,12 @@
|
|||
#include <fst/vestige/aeffectx.h>
|
||||
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/tempo.h>
|
||||
#include <ardour/vst_plugin.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
// #define DEBUG_CALLBACKS
|
||||
#define DEBUG_CALLBACKS
|
||||
|
||||
#ifdef DEBUG_CALLBACKS
|
||||
#define SHOW_CALLBACK printf
|
||||
|
|
@ -49,14 +50,15 @@ long Session::vst_callback (AEffect* effect,
|
|||
VSTPlugin* plug;
|
||||
Session* session;
|
||||
|
||||
SHOW_CALLBACK ("am callback, opcode = %d", opcode);
|
||||
|
||||
if (effect && effect->user) {
|
||||
plug = (VSTPlugin*) (effect->user);
|
||||
session = &plug->session();
|
||||
SHOW_CALLBACK ("am callback %d, opcode = %ld, plugin = \"%s\" ", pthread_self(), opcode, plug->name());
|
||||
} else {
|
||||
plug = 0;
|
||||
session = 0;
|
||||
SHOW_CALLBACK ("am callback %d, opcode = %ld", pthread_self(), opcode);
|
||||
}
|
||||
|
||||
switch(opcode){
|
||||
|
|
@ -113,7 +115,30 @@ long Session::vst_callback (AEffect* effect,
|
|||
if (session) {
|
||||
_timeInfo.samplePos = session->transport_frame();
|
||||
_timeInfo.sampleRate = session->frame_rate();
|
||||
_timeInfo.flags = 0;
|
||||
|
||||
cerr << "pos = " << _timeInfo.samplePos << " SR = " << _timeInfo.sampleRate
|
||||
<< " asked for " << std::hex << value << std::dec << endl;
|
||||
|
||||
if (value & (kVstTempoValid)) {
|
||||
const Tempo& t (session->tempo_map().tempo_at (session->transport_frame()));
|
||||
_timeInfo.tempo = t.beats_per_minute ();
|
||||
_timeInfo.flags |= (kVstTempoValid);
|
||||
cerr << "Tempo = " << _timeInfo.tempo << endl;
|
||||
}
|
||||
if (value & (kVstBarsValid)) {
|
||||
const Meter& m (session->tempo_map().meter_at (session->transport_frame()));
|
||||
_timeInfo.timeSigNumerator = m.beats_per_bar ();
|
||||
_timeInfo.timeSigDenominator = m.note_divisor ();
|
||||
_timeInfo.flags |= (kVstBarsValid);
|
||||
cerr << "Meter = " << _timeInfo.timeSigNumerator << '/' << _timeInfo.timeSigDenominator << endl;
|
||||
}
|
||||
|
||||
if (session->transport_speed() != 0.0f) {
|
||||
_timeInfo.flags |= kVstTransportPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
return (long)&_timeInfo;
|
||||
|
||||
case audioMasterProcessEvents:
|
||||
|
|
@ -128,7 +153,13 @@ long Session::vst_callback (AEffect* effect,
|
|||
case audioMasterTempoAt:
|
||||
SHOW_CALLBACK ("amc: audioMasterTempoAt\n");
|
||||
// returns tempo (in bpm * 10000) at sample frame location passed in <value>
|
||||
return 0;
|
||||
if (session) {
|
||||
const Tempo& t (session->tempo_map().tempo_at (value));
|
||||
return t.beats_per_minute() * 1000;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case audioMasterGetNumAutomatableParameters:
|
||||
SHOW_CALLBACK ("amc: audioMasterGetNumAutomatableParameters\n");
|
||||
|
|
@ -306,7 +337,7 @@ long Session::vst_callback (AEffect* effect,
|
|||
return 0;
|
||||
|
||||
default:
|
||||
SHOW_CALLBACK ("VST master dispatcher: undefed: %d, %d\n", opcode, effKeysRequired);
|
||||
SHOW_CALLBACK ("VST master dispatcher: undefed: %d\n", opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,13 +70,16 @@ VSTPlugin::VSTPlugin (AudioEngine& e, Session& session, FSTHandle* h)
|
|||
|
||||
/* set rate and blocksize */
|
||||
|
||||
cerr << name() << " dispatch effSetSampleRate\n";
|
||||
_plugin->dispatcher (_plugin, effSetSampleRate, 0, 0, NULL,
|
||||
(float) session.frame_rate());
|
||||
cerr << name() << " dispatch effSetBlockSize\n";
|
||||
_plugin->dispatcher (_plugin, effSetBlockSize, 0,
|
||||
session.get_block_size(), NULL, 0.0f);
|
||||
|
||||
/* set program to zero */
|
||||
|
||||
cerr << name() << " dispatch effSetProgram\n";
|
||||
_plugin->dispatcher (_plugin, effSetProgram, 0, 0, NULL, 0.0f);
|
||||
|
||||
Plugin::setup_controls ();
|
||||
|
|
@ -106,6 +109,7 @@ void
|
|||
VSTPlugin::set_block_size (nframes_t nframes)
|
||||
{
|
||||
deactivate ();
|
||||
cerr << name() << " dispatch effSetBlockSize\n";
|
||||
_plugin->dispatcher (_plugin, effSetBlockSize, 0, nframes, NULL, 0.0f);
|
||||
activate ();
|
||||
}
|
||||
|
|
@ -150,6 +154,7 @@ VSTPlugin::get_state()
|
|||
void* data;
|
||||
long data_size;
|
||||
|
||||
cerr << name() << " dispatch = GetChunk\n";
|
||||
if ((data_size = _plugin->dispatcher (_plugin, 23 /* effGetChunk */, 0, 0, &data, false)) == 0) {
|
||||
return *root;
|
||||
}
|
||||
|
|
@ -253,6 +258,7 @@ VSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
|
|||
desc.min_unbound = false;
|
||||
desc.max_unbound = false;
|
||||
|
||||
cerr << name() << " dispatch ParamProps\n";
|
||||
if (_plugin->dispatcher (_plugin, effGetParameterProperties, which, 0, &prop, 0)) {
|
||||
|
||||
#ifdef VESTIGE_COMPLETE
|
||||
|
|
@ -300,6 +306,7 @@ VSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
|
|||
char label[64];
|
||||
label[0] = '\0';
|
||||
|
||||
cerr << name() << " dispatch effGetParamName\n";
|
||||
_plugin->dispatcher (_plugin, effGetParamName, which, 0, label, 0);
|
||||
|
||||
desc.label = label;
|
||||
|
|
@ -345,6 +352,7 @@ string
|
|||
VSTPlugin::describe_parameter (uint32_t param)
|
||||
{
|
||||
char name[64];
|
||||
cerr << this->name() << " dispatch effGetParamName\n";
|
||||
_plugin->dispatcher (_plugin, effGetParamName, param, 0, name, 0);
|
||||
return name;
|
||||
}
|
||||
|
|
@ -378,6 +386,7 @@ VSTPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in_
|
|||
float *outs[_plugin->numOutputs];
|
||||
int32_t i;
|
||||
|
||||
|
||||
for (i = 0; i < (int32_t) _plugin->numInputs; ++i) {
|
||||
ins[i] = bufs[min((uint32_t) in_index,maxbuf - 1)] + offset;
|
||||
in_index++;
|
||||
|
|
@ -398,20 +407,24 @@ VSTPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in_
|
|||
|
||||
/* we already know it can support processReplacing */
|
||||
|
||||
cerr << "++++++++++ " << name() << " RUN in " << pthread_self() << endl;
|
||||
_plugin->processReplacing (_plugin, ins, outs, nframes);
|
||||
|
||||
cerr << "\tdone\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
VSTPlugin::deactivate ()
|
||||
{
|
||||
cerr << "\n\n\n ************ " << name() << " DEACTIVATE in " << pthread_self() << endl;
|
||||
_plugin->dispatcher (_plugin, effMainsChanged, 0, 0, NULL, 0.0f);
|
||||
}
|
||||
|
||||
void
|
||||
VSTPlugin::activate ()
|
||||
{
|
||||
cerr << "\n\n\n ************ " << name() << " ACTIVATE in " << pthread_self() << endl;
|
||||
_plugin->dispatcher (_plugin, effMainsChanged, 0, 1, NULL, 0.0f);
|
||||
}
|
||||
|
||||
|
|
@ -463,6 +476,7 @@ VSTPlugin::print_parameter (uint32_t param, char *buf, uint32_t len) const
|
|||
{
|
||||
char *first_nonws;
|
||||
|
||||
cerr << name() << " dispatch paramDisplay\n";
|
||||
_plugin->dispatcher (_plugin, 7 /* effGetParamDisplay */, param, 0, buf, 0);
|
||||
|
||||
if (buf[0] == '\0') {
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ if fst['VST']:
|
|||
b = fst.Object ('fstinfofile', 'fstinfofile.c')
|
||||
c = fst.Object ('vstwin', 'vstwin.c')
|
||||
d = fst.Object ('vsti', 'vsti.c')
|
||||
e = fst.Object ('thread', 'thread.c')
|
||||
|
||||
Default([a,b,c,d])
|
||||
Default([a,b,c,d,e])
|
||||
|
||||
env.Alias('tarball', env.Distribute (env['DISTTREE'],
|
||||
fst_src + ['SConscript',
|
||||
|
|
|
|||
|
|
@ -133,6 +133,9 @@ extern int fst_load_state (FST * fst, char * filename);
|
|||
*/
|
||||
extern int fst_save_state (FST * fst, char * filename);
|
||||
|
||||
extern int wine_pthread_create (pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
89
libs/fst/thread.c
Normal file
89
libs/fst/thread.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
void* (*thread_function)(void*);
|
||||
void* thread_arg;
|
||||
pthread_t thread_id;
|
||||
pthread_mutex_t init_lock;
|
||||
pthread_cond_t init_cond;
|
||||
pthread_attr_t attr;
|
||||
} real_thread_info_t;
|
||||
|
||||
static DWORD WINAPI
|
||||
fake_thread_proxy (LPVOID parameter)
|
||||
{
|
||||
real_thread_info_t* rti = (real_thread_info_t*) parameter;
|
||||
|
||||
fprintf (stderr, "WINDOWS THREAD, @ pthread = %p\n", pthread_self());
|
||||
|
||||
pthread_mutex_lock (&rti->init_lock);
|
||||
rti->thread_id = pthread_self();
|
||||
pthread_cond_signal (&rti->init_cond);
|
||||
pthread_mutex_unlock (&rti->init_lock);
|
||||
|
||||
#if 0
|
||||
if (pthread_attr_get_schedparam (&rti->attr)) {
|
||||
pthread_set_schedparam (pthread_self(), policy, sched_param);
|
||||
}
|
||||
#endif
|
||||
/* XXX no way to use pthread API to set contention scope,
|
||||
because that has to be done before a thread is created.
|
||||
But ... its only meaningful for an M:N thread implemenation
|
||||
so its not important for the only platform where
|
||||
this code matters (Linux running Wine) because Linux
|
||||
uses a 1:1 thread design.
|
||||
*/
|
||||
|
||||
return (DWORD) rti->thread_function (rti->thread_arg);
|
||||
}
|
||||
|
||||
int
|
||||
wine_pthread_create (pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg)
|
||||
{
|
||||
DWORD tid;
|
||||
size_t stack_size;
|
||||
|
||||
fprintf (stderr, "****** Lets make a windows pthread\n");
|
||||
|
||||
real_thread_info_t* rti = (real_thread_info_t*) malloc (sizeof (real_thread_info_t));
|
||||
|
||||
rti->thread_function = function;
|
||||
rti->thread_arg = arg;
|
||||
if (attr) {
|
||||
rti->attr = *attr;
|
||||
}
|
||||
|
||||
fprintf (stderr, "\tset up the locks\n");
|
||||
|
||||
pthread_mutex_init (&rti->init_lock, NULL);
|
||||
pthread_cond_init (&rti->init_cond, NULL);
|
||||
|
||||
pthread_mutex_lock (&rti->init_lock);
|
||||
|
||||
fprintf (stderr, "\tget the stacksize\n");
|
||||
|
||||
if (attr) {
|
||||
if (pthread_attr_getstacksize (attr, &stack_size) != 0) {
|
||||
stack_size = 0;
|
||||
}
|
||||
} else {
|
||||
stack_size = 0;
|
||||
}
|
||||
|
||||
fprintf (stderr, "\tget that sucker started in the proxy, stacksize = %u\n", stack_size);
|
||||
|
||||
if (CreateThread (0, stack_size, fake_thread_proxy, rti, 0, &tid) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_cond_wait (&rti->init_cond, &rti->init_lock);
|
||||
pthread_mutex_unlock (&rti->init_lock);
|
||||
fprintf (stderr, "\tlet it run\n");
|
||||
|
||||
*thread_id = rti->thread_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -129,8 +129,18 @@
|
|||
#define kVstMidiType 1
|
||||
#define kVstTransportPlaying (1 << 1)
|
||||
#define kVstParameterUsesFloatStep (1 << 2)
|
||||
|
||||
/* validity flags for a VstTimeINfo structure this info comes from the web */
|
||||
|
||||
#define kVstNanosValid (1 << 8)
|
||||
#define kVstPpqPosValid (1 << 9)
|
||||
#define kVstTempoValid (1 << 10)
|
||||
#define kVstBarsValid (1 << 11)
|
||||
#define kVstCyclePosValid (1 << 12)
|
||||
#define kVstTimeSigValid (1 << 13)
|
||||
#define kVstSmpteValid (1 << 14)
|
||||
#define kVstClockValid (1 << 15)
|
||||
|
||||
#define kVstTransportChanged 1
|
||||
|
||||
typedef struct VstMidiEvent
|
||||
|
|
@ -253,30 +263,26 @@ typedef struct AEffect
|
|||
|
||||
typedef struct VstTimeInfo
|
||||
{
|
||||
// 00
|
||||
double samplePos;
|
||||
// 08
|
||||
double sampleRate;
|
||||
// unconfirmed 10 18
|
||||
char empty1[8 + 8];
|
||||
// 20?
|
||||
double tempo;
|
||||
// unconfirmed 28 30 38
|
||||
char empty2[8 + 8 + 8];
|
||||
// 40?
|
||||
int timeSigNumerator;
|
||||
// 44?
|
||||
int timeSigDenominator;
|
||||
// unconfirmed 48 4c 50
|
||||
char empty3[4 + 4 + 4];
|
||||
// 54
|
||||
int flags;
|
||||
/* info from online documentation of VST provided by Steinberg */
|
||||
|
||||
double samplePos;
|
||||
double sampleRate;
|
||||
double nanoSeconds;
|
||||
double ppqPos;
|
||||
double tempo;
|
||||
double barStartPos;
|
||||
double cycleStartPos;
|
||||
double cycleEndPos;
|
||||
double timeSigNumerator;
|
||||
double timeSigDenominator;
|
||||
long smpteOffset;
|
||||
long smpteFrameRate;
|
||||
long samplesToNextClock;
|
||||
long flags;
|
||||
|
||||
} VstTimeInfo;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef long int (* audioMasterCallback)( AEffect * , long int , long int ,
|
||||
long int , void * , float );
|
||||
// we don't use it, may be noise
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <jack/jack.h>
|
||||
#include <jack/thread.h>
|
||||
#include <libgen.h>
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
|
|
@ -182,6 +184,7 @@ again:
|
|||
/* condition/unlock: it was signalled & unlocked in fst_create_editor() */
|
||||
}
|
||||
if(fst->want_program != -1 ) {
|
||||
fprintf (stderr, "switching to program %d\n", fst->want_program);
|
||||
fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
|
||||
fst->want_program = -1;
|
||||
}
|
||||
|
|
@ -263,6 +266,9 @@ fst_init (void* possible_hmodule)
|
|||
fst_error ("could not create new thread proxy");
|
||||
return -1;
|
||||
}
|
||||
|
||||
jack_set_thread_creator (wine_pthread_create);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ winmain.c
|
|||
#libs/fst/fstinfofile.o
|
||||
#libs/fst/vstwin.o
|
||||
#libs/fst/vsti.o
|
||||
#libs/fst/thread.o
|
||||
"""
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@
|
|||
. ../gtk2_ardour/ardev_common.sh
|
||||
|
||||
export LD_LIBRARY_PATH=gtk2_ardour:$LD_LIBRARY_PATH
|
||||
exec wine ./vst/ardour_vst.exe.so "$@"
|
||||
wine-pthread ./vst/ardour_vst.exe.so "$@"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue