Skip to content

Commit

Permalink
...
Browse files Browse the repository at this point in the history
  • Loading branch information
cannam committed Aug 17, 2004
1 parent 4f32a1f commit afc7d23
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 315 deletions.
5 changes: 5 additions & 0 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ install:: dssi-vst.so dssi-vst-scanner.exe.so dssi-vst-server.exe.so dssi-vst_gu
$(MKDIR) $(TARGET_DSSI_DIR)/dssi-vst
$(INSTALL) dssi-vst-scanner.exe.so dssi-vst-server.exe.so dssi-vst_gui.exe.so apploader $(TARGET_DSSI_DIR)/dssi-vst/
( cd $(TARGET_DSSI_DIR)/dssi-vst/ ; rm -f dssi-vst-scanner dssi-vst-server dssi-vst_gui ; ln -s apploader dssi-vst-scanner ; ln -s apploader dssi-vst-server ; ln -s apploader dssi-vst_gui ; chmod a+x * ../dssi-vst.so )
@echo
@echo 'You have installed a new version of dssi-vst. If you have any'
@echo 'existing cache data files from previous versions in $$HOME/.dssi-vst/,'
@echo 'you are advised to delete them now to avoid any confusion.'
@echo

uninstall::
$(RM) $(TARGET_DSSI_DIR)/dssi-vst.so
Expand Down
72 changes: 47 additions & 25 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,30 @@ dssi-vst doesn't use libfst because libfst is just too serious a thing
to start messing about with in a plugin whose host doesn't know about
it (because it involves introducing Wine threads into the host).

Architecturally dssi-vst is a bit like vstserver. The main reason it
doesn't use vstserver is simply that I wrote most of this code quite a
while ago as an exercise, and I've just got used to my own code. I
don't know vstserver well enough to know what the real differences
are.
Architecturally dssi-vst is a little bit like vstserver in that it
runs the plugin in a separate process and communicates with it via
some IPC mechanism (here shared memory and POSIX FIFOs, where
vstserver uses shared memory and Unix domain sockets). The big
difference is that dssi-vst spawns a separate process per plugin
rather than using a single server. To be honest, the only practical
reason dssi-vst doesn't use vstserver is that I wrote most of this
code quite a while ago as an exercise, and I've just got used to my
own code.

These are some of the theoretical good points of dssi-vst's
architecture:

* Bugs in dssi-vst aside, it ought to be impossible for a misbehaving
VST plugin to crash its host, and for a misbehaving plugin GUI to
VST plugin to crash its host, for a misbehaving plugin GUI to
disrupt either the host or the audio part of the plugin (because
the GUI and audio parts are in separate processes). It's therefore
theoretically possible for it to be more stable for audio use than
either an fst host or vstserver.
the GUI and audio parts are in separate processes), or for one
misbehaving plugin or plugin GUI to disrupt another. It's therefore
theoretically possible for dssi-vst to be more stable for audio use
than either an fst host or vstserver.

* Because there is no real audio work done in the GUI process and
no requirement for an audio thread, the GUI code is less likely to
experience problems from thread mismanagement.

* DSSI provides a closer match to the VST feature set than LADSPA
does -- apart from the synth stuff, this plugin handles VST programs
Expand All @@ -65,37 +74,50 @@ architecture:

* Obviously, dssi-vst allows any DSSI host to become a VST host
without having to know anything about VST or to have a code (or
licencing) dependency on the VST SDK, which is not true of fst.

Bad points:
licence) dependency on the VST SDK, which is not the case with fst.

* A plugin with a visible GUI actually has to be instantiated twice.
The GUI instantiation doesn't do the full audio processing work,
but of course it still takes up resources.
* Marginally simpler than vstserver to use, because you don't have to
start the server yourself.

* Any plugin GUI that uses its own back channel to communicate
directly with the plugin (for example to tell it to load sample
sets, or whatever) will fail -- this simply can't be mapped into
the DSSI model. Complex plugins with complex GUIs might be better
run as standalone jack_fst or vstserver applications plumbed into
the JACK graph anyway.
Bad points:

* Processes everywhere. Besides your host process, you get a
server process to do the actual audio processing, a scanner
process to identify the available VST plugins, and a GUI process
to run the GUI -- and all of these are winelib applications that
are run under Wine.
are run under Wine. dssi-vst is useful for running the odd synth
or effect on a fast machine, not for doing all your effects work.

* A plugin with a visible GUI actually has to be instantiated twice.
The GUI instantiation doesn't do the full audio processing work,
and it isn't created unless you actually want to see the GUI, but
this is still wasteful of resources.

* Any plugin GUI that uses its own back channel to communicate
directly with the plugin will fail, because there's no way to
intercept this information, which is necessary for the DSSI GUI
separation model. The most obvious example where this causes
failures is for synth plugins with miniature keyboards or test
buttons built into their GUIs: these gizmos cannot work with
dssi-vst, although that doesn't usually prevent the plugin
itself from working. More complex plugins with complex GUIs
that do patch management in the plugin GUI also suffer, though
they might be better run as standalone jack_fst or vstserver
applications plumbed into the JACK graph anyway.

* It's hard to make sure things like the communications FIFOs are
tidied up when exiting. Apart from anything else it requires
that the host call cleanup() on its plugins when exiting from
ctrl-C or whatever. This isn't quite handled satisfactorily yet
either in this code or in the existing hosts.
either in this code or in the existing hosts. A vstserver model
can cope better with this by having the server take ownership
of such resources instead of the plugin.

* The comms model dssi-vst uses introduces a fixed latency equal to
the JACK period size, as well as any existing latency in the VST
plugin. (This should be exposed through an output control port,
but it isn't yet. Patches welcome)
plugin. (The fixed latency is exposed through the _latency output
control port. Does anyone know how to find out the latency of a
VST plugin?)


Licence
Expand Down
9 changes: 0 additions & 9 deletions dssi-vst-scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)
}

struct dirent *entry;
int count = 0;

char *home = getenv("HOME");
std::string cacheDir = std::string(home) + "/.dssi-vst";
bool haveCacheDir = false;
Expand All @@ -173,7 +171,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)

// For each plugin, we write:
//
// unique id (unsigned long)
// dll name (64 chars)
// name (64 chars)
// vendor (64 chars)
Expand Down Expand Up @@ -287,9 +284,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)
goto done;
}

uniqueId = 6666 + count;
write(fd, &uniqueId, sizeof(unsigned long));

memset(buffer, 0, 65);
snprintf(buffer, 64, "%s", libname.c_str());
write(fd, buffer, 64);
Expand Down Expand Up @@ -326,7 +320,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)
memset(buffer, 0, 65);
plugin->dispatcher(plugin, effGetParamName, i, 0, buffer, 0);
write(fd, buffer, 64);
//!!! do I need mains changed before this?:
float f = plugin->getParameter(plugin, i);
write(fd, &f, sizeof(float));
}
Expand Down Expand Up @@ -366,8 +359,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)
close(fd);
}
}

++count;
}

closedir(directory);
Expand Down
99 changes: 14 additions & 85 deletions dssi-vst-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,14 +525,17 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)
exit(2);
}

// LADSPA labels can't contain spaces so dssi-vst replaces spaces
// with asterisks.
for (int ci = 0; libname[ci]; ++ci) {
if (libname[ci] == '*') libname[ci] = ' ';
}

cout << "Loading \"" << libname << "\"... ";
if (debugLevel > 0) cout << endl;

// char libPath[1024];
HINSTANCE libHandle = 0;



std::vector<std::string> vstPath = Paths::getPath
("VST_PATH", "/usr/local/lib/vst:/usr/lib/vst", "/vst");

Expand Down Expand Up @@ -569,80 +572,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)
if (libHandle) break;
}

#ifdef NOT_DEFINED



char *vstDir = getenv("VSTI_DIR");

if (vstDir) {
if (vstDir[strlen(vstDir) - 1] == '/') {
snprintf(libPath, 1024, "%s%s", vstDir, libname);
} else {
snprintf(libPath, 1024, "%s/%s", vstDir, libname);
}
std::string libpathstr(libPath);

if (home && home[0] != '\0') {
if (libpathstr.substr(0, strlen(home)) == std::string(home)) {
libpathstr = libpathstr.substr(strlen(home) + 1);
}
}

libHandle = LoadLibrary(libpathstr.c_str());

libHandle = LoadLibrary(libPath);
if (debugLevel > 0) {
cerr << "dssi-vst-server[1]: " << (libHandle ? "" : "not ")
<< "found in " << vstDir << " (from $VSTI_DIR)" << endl;
}
} else if (debugLevel > 0) {
cerr << "dssi-vst-server[1]: $VSTI_DIR not set" << endl;
}

std::cerr << "home is " << getenv("HOME") << std::endl;

if (!libHandle) {
vstDir = getenv("VST_DIR");
if (vstDir) {
snprintf(libPath, 1024, "%s/%s", vstDir, libname);
std::string libpathstr(libPath);

if (home && home[0] != '\0') {
if (libpathstr.substr(0, strlen(home)) == std::string(home)) {
libpathstr = libpathstr.substr(strlen(home) + 1);
}
}

libHandle = LoadLibrary(libpathstr.c_str());

if (debugLevel > 0) {
cerr << "dssi-vst-server[1]: " << (libHandle ? "" : "not ")
<< "found in " << libPath << " (from $VST_DIR)" << endl;

LPVOID lpMsgBuf;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL )) {
std::cerr << (const char *)lpMsgBuf << std::endl;
}

LocalFree( lpMsgBuf );
}
} else if (debugLevel > 0) {
cerr << "dssi-vst-server[1]: $VST_DIR not set" << endl;
}
}

#endif

if (!libHandle) {
libHandle = LoadLibrary(libname);
if (debugLevel > 0) {
Expand All @@ -663,8 +592,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)

//!!! better debug level support

//!!! look for _main as well?

AEffect *(__stdcall* getInstance)(audioMasterCallback);
getInstance = (AEffect*(__stdcall*)(audioMasterCallback))
GetProcAddress(libHandle, PLUGIN_ENTRY_POINT);
Expand All @@ -689,27 +616,27 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)
}

if (plugin->magic != kEffectMagic) {
cerr << "dssi-vst-server: ERROR: Not a VST effect in DLL \"" << libname << "\"" << endl;
cerr << "dssi-vst-server: ERROR: Not a VST plugin in DLL \"" << libname << "\"" << endl;
return 1;
} else if (debugLevel > 0) {
cerr << "dssi-vst-server[1]: plugin is a VST" << endl;
}

#ifdef SHOW_GUI
if (!(plugin->flags & effFlagsHasEditor)) {
cerr << "dssi-vst-server: ERROR: Instrument has no GUI (required)" << endl;
cerr << "dssi-vst-server: ERROR: Plugin has no GUI (required)" << endl;
return 1;
} else if (debugLevel > 0) {
cerr << "dssi-vst-server[1]: synth has a GUI" << endl;
cerr << "dssi-vst-server[1]: plugin has a GUI" << endl;
}
#endif

if (!plugin->flags & effFlagsCanReplacing) {
cerr << "dssi-vst-server: ERROR: Instrument does not support processReplacing (required)"
cerr << "dssi-vst-server: ERROR: Plugin does not support processReplacing (required)"
<< endl;
return 1;
} else if (debugLevel > 0) {
cerr << "dssi-vst-server[1]: synth supports processReplacing" << endl;
cerr << "dssi-vst-server[1]: plugin supports processReplacing" << endl;
}

try {
Expand Down Expand Up @@ -796,7 +723,9 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow)
HANDLE threadHandle = CreateThread(0, 0, AudioThreadMain, 0, 0, &threadId);
if (!threadHandle) {
cerr << "Failed to create audio thread!" << endl;
return 1; //!!!tidy
delete remoteVSTServerInstance;
FreeLibrary(libHandle);
return 1;
} else if (debugLevel > 0) {
cerr << "dssi-vst-server[1]: created audio thread" << endl;
}
Expand Down
Loading

0 comments on commit afc7d23

Please sign in to comment.