2005-09-25 14:42:24 -04:00
|
|
|
/*
|
2012-05-30 10:32:27 -04:00
|
|
|
Copyright (C) 2001-2012 Paul Davis
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <cstdlib>
|
2008-09-10 17:27:39 -04:00
|
|
|
#include <signal.h>
|
2010-11-03 22:40:07 -04:00
|
|
|
#include <cerrno>
|
|
|
|
#include <fstream>
|
2012-05-05 10:16:13 -04:00
|
|
|
#include <vector>
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
#include <sigc++/bind.h>
|
2005-11-29 12:27:58 -05:00
|
|
|
#include <gtkmm/settings.h>
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "pbd/error.h"
|
2010-12-22 23:17:45 -05:00
|
|
|
#include "pbd/epa.h"
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "pbd/file_utils.h"
|
|
|
|
#include "pbd/textreceiver.h"
|
|
|
|
#include "pbd/failed_constructor.h"
|
|
|
|
#include "pbd/pthread_utils.h"
|
2011-02-10 12:44:33 -05:00
|
|
|
#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
|
|
|
|
#include "pbd/boost_debug.h"
|
|
|
|
#endif
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
#include <jack/jack.h>
|
|
|
|
|
2013-03-17 09:53:30 -04:00
|
|
|
#include "ardour/revision.h"
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "ardour/version.h"
|
|
|
|
#include "ardour/ardour.h"
|
|
|
|
#include "ardour/audioengine.h"
|
|
|
|
#include "ardour/session_utils.h"
|
|
|
|
#include "ardour/filesystem_paths.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-09-25 16:33:00 -04:00
|
|
|
#include <gtkmm/main.h>
|
2010-08-16 22:48:24 -04:00
|
|
|
#include <gtkmm2ext/application.h>
|
2005-09-25 16:33:00 -04:00
|
|
|
#include <gtkmm2ext/popup.h>
|
|
|
|
#include <gtkmm2ext/utils.h>
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2013-01-29 10:25:30 -05:00
|
|
|
#include <fontconfig/fontconfig.h>
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
#include "version.h"
|
2008-01-10 16:20:59 -05:00
|
|
|
#include "utils.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
#include "ardour_ui.h"
|
|
|
|
#include "opts.h"
|
2007-01-09 18:24:54 -05:00
|
|
|
#include "enums.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
#include "i18n.h"
|
|
|
|
|
2013-03-04 23:33:38 -05:00
|
|
|
#ifdef __APPLE__
|
2013-02-22 10:48:44 -05:00
|
|
|
#include <Carbon/Carbon.h>
|
|
|
|
#endif
|
|
|
|
|
2009-05-12 13:03:42 -04:00
|
|
|
using namespace std;
|
2005-09-25 14:42:24 -04:00
|
|
|
using namespace Gtk;
|
2007-10-11 18:07:47 -04:00
|
|
|
using namespace ARDOUR_COMMAND_LINE;
|
2005-09-25 14:42:24 -04:00
|
|
|
using namespace ARDOUR;
|
Large nasty commit in the form of a 5000 line patch chock-full of completely
unecessary changes. (Sorry, doing a "sprint" based thing, this is the end of the first one)
Achieved MIDI track and bus creation, associated Jack port and diskstream creation, and minimal GUI stuff for creating them. Should be set to start work on actually recording and playing midi to/from disk now.
Relevant (significant) changes:
- Creation of a Buffer class. Base class is type agnostic so things can point to a buffer but not care what kind it is (otherwise it'd be a template). Derived into AudioBuffer and MidiBuffer, with a type tag because checking type is necessary in parts of the code where dynamic_cast wouldn't be wise. Originally I considered this a hack, but passing around a type proved to be a very good solution to all the other problems (below). There is a 1:1 mapping between jack port data types and ardour Buffer types (with a conversion function), but that's easily removed if it ever becomes necessary. Having the type scoped in the Buffer class is maybe not the best spot for it, but whatever (this is proof of concept kinda stuff right now...)
- IO now has a "default" port type (passed to the constructor and stored as a member), used by ensure_io (and similar) to create n ports. IO::register_***_port has a type argument that defaults to the default type if not passed. Rationale: previous IO API is identical, no changes needed to existing code, but path is paved for multiple port types in one IO, which we will need for eg synth plugin inserts, among other things. This is not quite ideal (best would be to only have the two port register functions and have them take a type), but the alternative is a lot of work (namely destroying the 'ensure' functions and everything that uses them) for very little gain. (I am convinced after quite a few tries at the whiteboard that subclassing IO in any way is not a feasible option, look at it's inheritance diagram in Doxygen and you can see why)
- AudioEngine::register_audio_input_port is now register_input_port and takes a type argument. Ditto for output.
- (Most significant change) AudioDiskstream abstracted into Distream, and sibling MidiDiskstream created. Very much still a work in progress, but Diskstream is there to switch references over to (most already are), which is the important part. It is still unclear what the MIDI diskstream's relation to channels is, but I'm pretty sure they will be single channel only (so SMF Type 0) since noone can come up with a reason otherwise.
- MidiTrack creation. Same thing as AudioTrack but with a different default type basically. No big deal here.
- Random cleanups and variable renamings etc. because I have OCD and can't help myself. :)
Known broken: Loading of sessions containing MIDI tracks.
git-svn-id: svn://localhost/ardour2/branches/midi@641 d708f5d6-7413-0410-9779-e7cbd77b26cf
2006-06-26 12:01:34 -04:00
|
|
|
using namespace PBD;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
TextReceiver text_receiver ("ardour");
|
|
|
|
|
|
|
|
extern int curvetest (string);
|
|
|
|
|
|
|
|
static ARDOUR_UI *ui = 0;
|
2007-10-14 01:45:31 -04:00
|
|
|
static const char* localedir = LOCALEDIR;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
gui_jack_error ()
|
|
|
|
{
|
2010-03-14 22:31:27 -04:00
|
|
|
MessageDialog win (string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME),
|
2011-11-18 15:22:49 -05:00
|
|
|
false,
|
|
|
|
Gtk::MESSAGE_INFO,
|
|
|
|
Gtk::BUTTONS_NONE);
|
2013-02-05 13:18:35 -05:00
|
|
|
win.set_secondary_text(string_compose (_("There are several possible reasons:\n\
|
2005-09-25 14:42:24 -04:00
|
|
|
\n\
|
|
|
|
1) JACK is not running.\n\
|
|
|
|
2) JACK is running as another user, perhaps root.\n\
|
2013-02-05 13:18:35 -05:00
|
|
|
3) There is already another client called \"%1\".\n\
|
2005-09-25 14:42:24 -04:00
|
|
|
\n\
|
2013-02-05 13:18:35 -05:00
|
|
|
Please consider the possibilities, and perhaps (re)start JACK."), PROGRAM_NAME));
|
2006-04-19 16:42:17 -04:00
|
|
|
|
|
|
|
win.add_button (Stock::QUIT, RESPONSE_CLOSE);
|
|
|
|
win.set_default_response (RESPONSE_CLOSE);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
win.show_all ();
|
2005-10-27 16:51:57 -04:00
|
|
|
win.set_position (Gtk::WIN_POS_CENTER);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-08-30 22:28:42 -04:00
|
|
|
if (!no_splash) {
|
2006-11-19 11:45:16 -05:00
|
|
|
ui->hide_splash ();
|
2006-08-30 22:28:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* we just don't care about the result, but we want to block */
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-12-08 13:53:43 -05:00
|
|
|
win.run ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2011-04-04 18:46:48 -04:00
|
|
|
static void export_search_path (const string& base_dir, const char* varname, const char* dir)
|
2011-04-02 10:10:48 -04:00
|
|
|
{
|
2011-04-04 18:46:48 -04:00
|
|
|
string path;
|
2011-04-02 10:10:48 -04:00
|
|
|
const char * cstr = getenv (varname);
|
|
|
|
|
|
|
|
if (cstr) {
|
|
|
|
path = cstr;
|
|
|
|
path += ':';
|
|
|
|
} else {
|
|
|
|
path = "";
|
|
|
|
}
|
|
|
|
path += base_dir;
|
|
|
|
path += dir;
|
2011-04-04 18:46:48 -04:00
|
|
|
|
|
|
|
setenv (varname, path.c_str(), 1);
|
2011-04-02 10:10:48 -04:00
|
|
|
}
|
2006-05-24 14:41:52 -04:00
|
|
|
|
2007-10-11 18:07:47 -04:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
|
|
|
#include <mach-o/dyld.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
|
2010-08-16 20:28:20 -04:00
|
|
|
extern void set_language_preference (); // cocoacarbon.mm
|
|
|
|
|
2007-10-11 18:07:47 -04:00
|
|
|
void
|
2011-02-01 14:55:08 -05:00
|
|
|
fixup_bundle_environment (int, char* [])
|
2007-10-11 18:07:47 -04:00
|
|
|
{
|
|
|
|
if (!getenv ("ARDOUR_BUNDLED")) {
|
|
|
|
return;
|
2006-08-09 21:22:45 -04:00
|
|
|
}
|
2006-05-24 14:41:52 -04:00
|
|
|
|
2011-04-04 18:46:48 -04:00
|
|
|
EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
|
2011-01-05 19:42:01 -05:00
|
|
|
|
2010-08-16 20:28:20 -04:00
|
|
|
set_language_preference ();
|
|
|
|
|
2007-10-11 18:07:47 -04:00
|
|
|
char execpath[MAXPATHLEN+1];
|
|
|
|
uint32_t pathsz = sizeof (execpath);
|
2006-05-24 14:41:52 -04:00
|
|
|
|
2007-10-11 18:07:47 -04:00
|
|
|
_NSGetExecutablePath (execpath, &pathsz);
|
2006-05-24 14:41:52 -04:00
|
|
|
|
2010-09-14 12:51:02 -04:00
|
|
|
std::string path;
|
2012-05-30 10:58:39 -04:00
|
|
|
std::string exec_dir = Glib::path_get_dirname (execpath);
|
|
|
|
std::string bundle_dir;
|
2012-06-24 08:49:53 -04:00
|
|
|
std::string userconfigdir = user_config_directory();
|
2007-10-11 18:07:47 -04:00
|
|
|
|
2012-05-30 10:58:39 -04:00
|
|
|
bundle_dir = Glib::path_get_dirname (exec_dir);
|
2007-10-11 18:07:47 -04:00
|
|
|
|
2013-01-23 11:09:10 -05:00
|
|
|
#ifdef ENABLE_NLS
|
2013-01-23 13:44:16 -05:00
|
|
|
if (!ARDOUR::translations_are_enabled ()) {
|
2013-01-23 11:09:10 -05:00
|
|
|
localedir = "/this/cannot/exist";
|
|
|
|
} else {
|
|
|
|
/* force localedir into the bundle */
|
|
|
|
|
|
|
|
vector<string> lpath;
|
|
|
|
lpath.push_back (bundle_dir);
|
|
|
|
lpath.push_back ("share");
|
|
|
|
lpath.push_back ("locale");
|
|
|
|
localedir = strdup (Glib::build_filename (lpath).c_str());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-05-30 10:58:39 -04:00
|
|
|
export_search_path (bundle_dir, "ARDOUR_DLL_PATH", "/lib");
|
2007-10-11 18:07:47 -04:00
|
|
|
|
2012-05-20 08:51:38 -04:00
|
|
|
/* inside an OS X .app bundle, there is no difference
|
|
|
|
between DATA and CONFIG locations, since OS X doesn't
|
|
|
|
attempt to do anything to expose the notion of
|
|
|
|
machine-independent shared data.
|
|
|
|
*/
|
2007-10-11 18:07:47 -04:00
|
|
|
|
2012-05-30 10:58:39 -04:00
|
|
|
export_search_path (bundle_dir, "ARDOUR_DATA_PATH", "/Resources");
|
|
|
|
export_search_path (bundle_dir, "ARDOUR_CONFIG_PATH", "/Resources");
|
|
|
|
export_search_path (bundle_dir, "ARDOUR_INSTANT_XML_PATH", "/Resources");
|
|
|
|
export_search_path (bundle_dir, "LADSPA_PATH", "/Plugins");
|
|
|
|
export_search_path (bundle_dir, "VAMP_PATH", "/lib");
|
|
|
|
export_search_path (bundle_dir, "SUIL_MODULE_DIR", "/lib");
|
2013-02-13 14:38:47 -05:00
|
|
|
export_search_path (bundle_dir, "GTK_PATH", "/lib/gtkengines");
|
2006-05-24 14:41:52 -04:00
|
|
|
|
2013-06-10 16:24:19 -04:00
|
|
|
setenv ("PATH", (bundle_dir + "/MacOS:" + std::string(getenv ("PATH"))).c_str(), 1);
|
|
|
|
|
2011-04-04 18:46:48 -04:00
|
|
|
/* unset GTK_RC_FILES so that we only load the RC files that we define
|
|
|
|
*/
|
2011-02-02 11:25:16 -05:00
|
|
|
|
2011-04-04 18:46:48 -04:00
|
|
|
unsetenv ("GTK_RC_FILES");
|
2011-02-02 11:25:16 -05:00
|
|
|
|
2008-03-17 16:54:03 -04:00
|
|
|
/* write a pango.rc file and tell pango to use it. we'd love
|
2010-08-16 20:28:20 -04:00
|
|
|
to put this into the PROGRAM_NAME.app bundle and leave it there,
|
2009-10-14 12:10:01 -04:00
|
|
|
but the user may not have write permission. so ...
|
2006-08-09 21:22:45 -04:00
|
|
|
|
2008-03-17 16:54:03 -04:00
|
|
|
we also have to make sure that the user ardour directory
|
|
|
|
actually exists ...
|
|
|
|
*/
|
|
|
|
|
2012-05-30 10:58:39 -04:00
|
|
|
if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
|
2013-02-05 13:18:35 -05:00
|
|
|
error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
|
2012-05-30 10:58:39 -04:00
|
|
|
<< endmsg;
|
2007-10-11 18:07:47 -04:00
|
|
|
} else {
|
2012-06-18 17:33:55 -04:00
|
|
|
|
|
|
|
path = Glib::build_filename (userconfigdir, "pango.rc");
|
|
|
|
std::ofstream pangorc (path.c_str());
|
|
|
|
if (!pangorc) {
|
|
|
|
error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
|
|
|
|
} else {
|
|
|
|
pangorc << "[Pango]\nModuleFiles="
|
|
|
|
<< Glib::build_filename (bundle_dir, "Resources/pango.modules")
|
|
|
|
<< endl;
|
|
|
|
pangorc.close ();
|
|
|
|
|
|
|
|
setenv ("PANGO_RC_FILE", path.c_str(), 1);
|
|
|
|
}
|
2006-05-24 14:41:52 -04:00
|
|
|
}
|
2012-06-18 18:57:16 -04:00
|
|
|
|
|
|
|
setenv ("CHARSETALIASDIR", bundle_dir.c_str(), 1);
|
2012-05-30 10:58:39 -04:00
|
|
|
setenv ("FONTCONFIG_FILE", Glib::build_filename (bundle_dir, "Resources/fonts.conf").c_str(), 1);
|
|
|
|
setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (bundle_dir, "Resources/gdk-pixbuf.loaders").c_str(), 1);
|
2006-05-24 14:41:52 -04:00
|
|
|
}
|
|
|
|
|
2013-01-31 02:41:37 -05:00
|
|
|
static void load_custom_fonts() {
|
2013-03-08 11:41:45 -05:00
|
|
|
/* this code will only compile on OS X 10.6 and above, and we currently do not
|
2013-03-09 09:01:48 -05:00
|
|
|
* need it for earlier versions since we fall back on a non-monospace,
|
|
|
|
* non-custom font.
|
2013-03-08 11:41:45 -05:00
|
|
|
*/
|
2013-03-09 09:01:48 -05:00
|
|
|
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
2013-01-31 02:41:37 -05:00
|
|
|
std::string ardour_mono_file;
|
|
|
|
|
|
|
|
if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
|
|
|
|
cerr << _("Cannot find ArdourMono TrueType font") << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
CFStringRef ttf;
|
|
|
|
CFURLRef fontURL;
|
|
|
|
CFErrorRef error;
|
|
|
|
ttf = CFStringCreateWithBytes(
|
2013-02-22 10:48:44 -05:00
|
|
|
kCFAllocatorDefault, (UInt8*) ardour_mono_file.c_str(),
|
2013-01-31 02:41:37 -05:00
|
|
|
ardour_mono_file.length(),
|
|
|
|
kCFStringEncodingUTF8, FALSE);
|
|
|
|
fontURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, ttf, kCFURLPOSIXPathStyle, TRUE);
|
|
|
|
if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error) != true) {
|
|
|
|
cerr << _("Cannot load ArdourMono TrueType font.") << endl;
|
|
|
|
}
|
2013-03-07 22:39:58 -05:00
|
|
|
#endif
|
2013-01-31 02:41:37 -05:00
|
|
|
}
|
|
|
|
|
2010-11-03 22:40:07 -04:00
|
|
|
#else
|
|
|
|
|
|
|
|
void
|
2011-02-01 17:03:50 -05:00
|
|
|
fixup_bundle_environment (int /*argc*/, char* argv[])
|
2010-11-03 22:40:07 -04:00
|
|
|
{
|
2012-05-05 10:16:13 -04:00
|
|
|
/* THIS IS FOR LINUX - its just about the only place where its
|
|
|
|
* acceptable to build paths directly using '/'.
|
|
|
|
*/
|
|
|
|
|
2010-11-03 22:40:07 -04:00
|
|
|
if (!getenv ("ARDOUR_BUNDLED")) {
|
|
|
|
return;
|
|
|
|
}
|
2011-04-04 18:46:48 -04:00
|
|
|
|
|
|
|
EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
|
2010-12-22 23:17:45 -05:00
|
|
|
|
2012-05-30 10:58:39 -04:00
|
|
|
std::string path;
|
|
|
|
std::string dir_path = Glib::path_get_dirname (Glib::path_get_dirname (argv[0]));
|
2012-06-23 01:06:54 -04:00
|
|
|
std::string userconfigdir = user_config_directory();
|
2010-11-03 22:40:07 -04:00
|
|
|
|
2013-01-23 11:09:10 -05:00
|
|
|
#ifdef ENABLE_NLS
|
2013-01-23 13:44:16 -05:00
|
|
|
if (!ARDOUR::translations_are_enabled ()) {
|
2013-01-23 11:09:10 -05:00
|
|
|
localedir = "/this/cannot/exist";
|
|
|
|
} else {
|
|
|
|
/* force localedir into the bundle */
|
|
|
|
vector<string> lpath;
|
|
|
|
lpath.push_back (dir_path);
|
|
|
|
lpath.push_back ("share");
|
|
|
|
lpath.push_back ("locale");
|
|
|
|
localedir = realpath (Glib::build_filename (lpath).c_str(), NULL);
|
|
|
|
}
|
|
|
|
#endif
|
2013-01-21 18:14:00 -05:00
|
|
|
|
2011-04-04 18:46:48 -04:00
|
|
|
/* note that this function is POSIX/Linux specific, so using / as
|
|
|
|
a dir separator in this context is just fine.
|
|
|
|
*/
|
2010-11-03 22:40:07 -04:00
|
|
|
|
2012-05-20 08:51:38 -04:00
|
|
|
export_search_path (dir_path, "ARDOUR_DLL_PATH", "/lib");
|
|
|
|
export_search_path (dir_path, "ARDOUR_CONFIG_PATH", "/etc");
|
|
|
|
export_search_path (dir_path, "ARDOUR_INSTANT_XML_PATH", "/share");
|
|
|
|
export_search_path (dir_path, "ARDOUR_DATA_PATH", "/share");
|
2012-05-30 10:58:39 -04:00
|
|
|
export_search_path (dir_path, "LADSPA_PATH", "/plugins");
|
2011-04-04 18:46:48 -04:00
|
|
|
export_search_path (dir_path, "VAMP_PATH", "/lib");
|
2012-05-23 21:43:58 -04:00
|
|
|
export_search_path (dir_path, "SUIL_MODULE_DIR", "/lib");
|
2013-02-21 17:41:32 -05:00
|
|
|
export_search_path (dir_path, "GTK_PATH", "/lib/gtkengines");
|
2010-11-03 22:40:07 -04:00
|
|
|
|
2013-06-10 16:24:19 -04:00
|
|
|
setenv ("PATH", (dir_path + "/bin:" + std::string(getenv ("PATH"))).c_str(), 1);
|
|
|
|
|
2011-04-04 18:46:48 -04:00
|
|
|
/* unset GTK_RC_FILES so that we only load the RC files that we define
|
|
|
|
*/
|
2011-02-02 11:25:16 -05:00
|
|
|
|
2011-04-04 18:46:48 -04:00
|
|
|
unsetenv ("GTK_RC_FILES");
|
2011-02-02 11:25:16 -05:00
|
|
|
|
2012-05-05 11:36:28 -04:00
|
|
|
/* Tell fontconfig where to find fonts.conf. Use the system version
|
2012-05-20 08:51:38 -04:00
|
|
|
if it exists, otherwise use the stuff we included in the bundle
|
2012-05-05 11:36:28 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
if (Glib::file_test ("/etc/fonts/fonts.conf", Glib::FILE_TEST_EXISTS)) {
|
|
|
|
setenv ("FONTCONFIG_FILE", "/etc/fonts/fonts.conf", 1);
|
2012-05-05 14:14:50 -04:00
|
|
|
setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
|
2012-05-05 11:36:28 -04:00
|
|
|
} else {
|
2013-01-30 07:55:59 -05:00
|
|
|
error << _("No fontconfig file found on your system. Things may looked very odd or ugly") << endmsg;
|
2012-05-05 11:36:28 -04:00
|
|
|
}
|
2012-05-05 14:12:54 -04:00
|
|
|
|
2010-11-03 22:40:07 -04:00
|
|
|
/* write a pango.rc file and tell pango to use it. we'd love
|
|
|
|
to put this into the Ardour.app bundle and leave it there,
|
2011-04-04 18:46:48 -04:00
|
|
|
but the user may not have write permission. so ...
|
2010-11-03 22:40:07 -04:00
|
|
|
|
|
|
|
we also have to make sure that the user ardour directory
|
|
|
|
actually exists ...
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
|
2013-02-05 13:18:35 -05:00
|
|
|
error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
|
2010-11-03 22:40:07 -04:00
|
|
|
<< endmsg;
|
2012-05-05 10:16:13 -04:00
|
|
|
} else {
|
2012-06-18 17:33:55 -04:00
|
|
|
|
|
|
|
path = Glib::build_filename (userconfigdir, "pango.rc");
|
|
|
|
std::ofstream pangorc (path.c_str());
|
|
|
|
if (!pangorc) {
|
|
|
|
error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
|
|
|
|
} else {
|
|
|
|
pangorc << "[Pango]\nModuleFiles="
|
|
|
|
<< Glib::build_filename (userconfigdir, "pango.modules")
|
|
|
|
<< endl;
|
|
|
|
pangorc.close ();
|
|
|
|
}
|
|
|
|
|
|
|
|
setenv ("PANGO_RC_FILE", path.c_str(), 1);
|
|
|
|
|
|
|
|
/* similar for GDK pixbuf loaders, but there's no RC file required
|
|
|
|
to specify where it lives.
|
|
|
|
*/
|
|
|
|
|
|
|
|
setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders").c_str(), 1);
|
2012-05-05 10:16:13 -04:00
|
|
|
}
|
2010-11-03 22:40:07 -04:00
|
|
|
|
2012-06-18 17:33:55 -04:00
|
|
|
/* this doesn't do much but setting it should prevent various parts of the GTK/GNU stack
|
|
|
|
from looking outside the bundle to find the charset.alias file.
|
|
|
|
*/
|
|
|
|
setenv ("CHARSETALIASDIR", dir_path.c_str(), 1);
|
|
|
|
|
2010-11-03 22:40:07 -04:00
|
|
|
}
|
|
|
|
|
2013-01-29 10:25:30 -05:00
|
|
|
static void load_custom_fonts() {
|
|
|
|
std::string ardour_mono_file;
|
|
|
|
if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
|
|
|
|
cerr << _("Cannot find ArdourMono TrueType font") << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcConfig *config = FcInitLoadConfigAndFonts();
|
|
|
|
FcBool ret = FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(ardour_mono_file.c_str()));
|
2013-01-29 10:59:22 -05:00
|
|
|
if (ret == FcFalse) {
|
|
|
|
cerr << _("Cannot load ArdourMono TrueType font.") << endl;
|
|
|
|
}
|
2013-01-29 10:25:30 -05:00
|
|
|
ret = FcConfigSetCurrent(config);
|
2013-01-29 10:59:22 -05:00
|
|
|
if (ret == FcFalse) {
|
|
|
|
cerr << _("Failed to set fontconfig configuration.") << endl;
|
|
|
|
}
|
2013-01-29 10:25:30 -05:00
|
|
|
}
|
|
|
|
|
2013-01-31 02:41:37 -05:00
|
|
|
#endif
|
|
|
|
|
2010-03-16 11:33:04 -04:00
|
|
|
static gboolean
|
|
|
|
tell_about_jack_death (void* /* ignored */)
|
|
|
|
{
|
|
|
|
if (AudioEngine::instance()->processed_frames() == 0) {
|
|
|
|
/* died during startup */
|
2011-11-18 15:22:49 -05:00
|
|
|
MessageDialog msg (_("JACK exited"), false);
|
2010-03-16 11:33:04 -04:00
|
|
|
msg.set_position (Gtk::WIN_POS_CENTER);
|
2010-08-16 20:28:20 -04:00
|
|
|
msg.set_secondary_text (string_compose (_(
|
|
|
|
"JACK exited unexpectedly, and without notifying %1.\n\
|
2010-03-16 11:33:04 -04:00
|
|
|
\n\
|
|
|
|
This could be due to misconfiguration or to an error inside JACK.\n\
|
|
|
|
\n\
|
2010-08-16 20:28:20 -04:00
|
|
|
Click OK to exit %1."), PROGRAM_NAME));
|
2011-04-04 18:46:48 -04:00
|
|
|
|
2010-03-16 11:33:04 -04:00
|
|
|
msg.run ();
|
|
|
|
_exit (0);
|
2011-04-04 18:46:48 -04:00
|
|
|
|
2010-03-16 11:33:04 -04:00
|
|
|
} else {
|
|
|
|
|
|
|
|
/* engine has already run, so this is a mid-session JACK death */
|
2011-04-04 18:46:48 -04:00
|
|
|
|
2011-11-18 15:22:49 -05:00
|
|
|
MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false));
|
2010-08-16 20:28:20 -04:00
|
|
|
msg->set_secondary_text (string_compose (_(
|
|
|
|
"JACK exited unexpectedly, and without notifying %1.\n\
|
2010-03-16 11:33:04 -04:00
|
|
|
\n\
|
|
|
|
This is probably due to an error inside JACK. You should restart JACK\n\
|
2010-08-16 20:28:20 -04:00
|
|
|
and reconnect %1 to it, or exit %1 now. You cannot save your\n\
|
|
|
|
session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
|
2010-03-16 11:33:04 -04:00
|
|
|
msg->present ();
|
|
|
|
}
|
|
|
|
return false; /* do not call again */
|
|
|
|
}
|
|
|
|
|
2008-09-10 17:27:39 -04:00
|
|
|
static void
|
2010-11-13 00:14:48 -05:00
|
|
|
sigpipe_handler (int /*signal*/)
|
2008-09-10 17:27:39 -04:00
|
|
|
{
|
2011-04-04 18:46:48 -04:00
|
|
|
/* XXX fix this so that we do this again after a reconnect to JACK
|
|
|
|
*/
|
|
|
|
|
|
|
|
static bool done_the_jack_thing = false;
|
2010-03-16 11:33:04 -04:00
|
|
|
|
|
|
|
if (!done_the_jack_thing) {
|
|
|
|
AudioEngine::instance()->died ();
|
|
|
|
g_idle_add (tell_about_jack_death, 0);
|
|
|
|
done_the_jack_thing = true;
|
|
|
|
}
|
2008-09-10 17:27:39 -04:00
|
|
|
}
|
|
|
|
|
2011-11-21 12:42:29 -05:00
|
|
|
#ifdef WINDOWS_VST_SUPPORT
|
2009-02-27 12:11:21 -05:00
|
|
|
|
2011-11-21 12:42:29 -05:00
|
|
|
extern int windows_vst_gui_init (int* argc, char** argv[]);
|
2009-02-27 12:11:21 -05:00
|
|
|
|
Large nasty commit in the form of a 5000 line patch chock-full of completely
unecessary changes. (Sorry, doing a "sprint" based thing, this is the end of the first one)
Achieved MIDI track and bus creation, associated Jack port and diskstream creation, and minimal GUI stuff for creating them. Should be set to start work on actually recording and playing midi to/from disk now.
Relevant (significant) changes:
- Creation of a Buffer class. Base class is type agnostic so things can point to a buffer but not care what kind it is (otherwise it'd be a template). Derived into AudioBuffer and MidiBuffer, with a type tag because checking type is necessary in parts of the code where dynamic_cast wouldn't be wise. Originally I considered this a hack, but passing around a type proved to be a very good solution to all the other problems (below). There is a 1:1 mapping between jack port data types and ardour Buffer types (with a conversion function), but that's easily removed if it ever becomes necessary. Having the type scoped in the Buffer class is maybe not the best spot for it, but whatever (this is proof of concept kinda stuff right now...)
- IO now has a "default" port type (passed to the constructor and stored as a member), used by ensure_io (and similar) to create n ports. IO::register_***_port has a type argument that defaults to the default type if not passed. Rationale: previous IO API is identical, no changes needed to existing code, but path is paved for multiple port types in one IO, which we will need for eg synth plugin inserts, among other things. This is not quite ideal (best would be to only have the two port register functions and have them take a type), but the alternative is a lot of work (namely destroying the 'ensure' functions and everything that uses them) for very little gain. (I am convinced after quite a few tries at the whiteboard that subclassing IO in any way is not a feasible option, look at it's inheritance diagram in Doxygen and you can see why)
- AudioEngine::register_audio_input_port is now register_input_port and takes a type argument. Ditto for output.
- (Most significant change) AudioDiskstream abstracted into Distream, and sibling MidiDiskstream created. Very much still a work in progress, but Diskstream is there to switch references over to (most already are), which is the important part. It is still unclear what the MIDI diskstream's relation to channels is, but I'm pretty sure they will be single channel only (so SMF Type 0) since noone can come up with a reason otherwise.
- MidiTrack creation. Same thing as AudioTrack but with a different default type basically. No big deal here.
- Random cleanups and variable renamings etc. because I have OCD and can't help myself. :)
Known broken: Loading of sessions containing MIDI tracks.
git-svn-id: svn://localhost/ardour2/branches/midi@641 d708f5d6-7413-0410-9779-e7cbd77b26cf
2006-06-26 12:01:34 -04:00
|
|
|
/* this is called from the entry point of a wine-compiled
|
|
|
|
executable that is linked against gtk2_ardour built
|
|
|
|
as a shared library.
|
|
|
|
*/
|
|
|
|
extern "C" {
|
|
|
|
int ardour_main (int argc, char *argv[])
|
|
|
|
#else
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
#endif
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2011-02-01 14:55:08 -05:00
|
|
|
fixup_bundle_environment (argc, argv);
|
2007-10-11 18:07:47 -04:00
|
|
|
|
2013-01-29 10:25:30 -05:00
|
|
|
load_custom_fonts(); /* needs to happend before any gtk and pango init calls */
|
|
|
|
|
2011-02-10 12:44:33 -05:00
|
|
|
if (!Glib::thread_supported()) {
|
2009-10-27 14:00:45 -04:00
|
|
|
Glib::thread_init();
|
2011-04-04 18:46:48 -04:00
|
|
|
}
|
2009-10-27 14:00:45 -04:00
|
|
|
|
2013-01-23 11:09:10 -05:00
|
|
|
#ifdef ENABLE_NLS
|
2005-09-25 14:42:24 -04:00
|
|
|
gtk_set_locale ();
|
2013-01-23 11:09:10 -05:00
|
|
|
#endif
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-11-21 12:42:29 -05:00
|
|
|
#ifdef WINDOWS_VST_SUPPORT
|
2009-10-27 14:00:45 -04:00
|
|
|
/* this does some magic that is needed to make GTK and Wine's own
|
|
|
|
X11 client interact properly.
|
|
|
|
*/
|
2011-11-21 12:42:29 -05:00
|
|
|
windows_vst_gui_init (&argc, &argv);
|
2009-02-27 12:11:21 -05:00
|
|
|
#endif
|
|
|
|
|
2013-01-21 22:29:28 -05:00
|
|
|
#ifdef ENABLE_NLS
|
2013-01-22 10:18:16 -05:00
|
|
|
cerr << "bnd txt domain [" << PACKAGE << "] to " << localedir << endl;
|
2013-01-21 22:29:28 -05:00
|
|
|
|
2007-10-11 18:07:47 -04:00
|
|
|
(void) bindtextdomain (PACKAGE, localedir);
|
2007-01-28 12:44:13 -05:00
|
|
|
/* our i18n translations are all in UTF-8, so make sure
|
|
|
|
that even if the user locale doesn't specify UTF-8,
|
|
|
|
we use that when handling them.
|
|
|
|
*/
|
|
|
|
(void) bind_textdomain_codeset (PACKAGE,"UTF-8");
|
2013-01-21 22:29:28 -05:00
|
|
|
#endif
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
|
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
// catch error message system signals ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
text_receiver.listen_to (error);
|
|
|
|
text_receiver.listen_to (info);
|
|
|
|
text_receiver.listen_to (fatal);
|
|
|
|
text_receiver.listen_to (warning);
|
|
|
|
|
2011-02-10 12:44:33 -05:00
|
|
|
#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
|
2011-04-04 18:46:48 -04:00
|
|
|
if (getenv ("BOOST_DEBUG")) {
|
|
|
|
boost_debug_shared_ptr_show_live_debugging (true);
|
|
|
|
}
|
2011-02-10 12:44:33 -05:00
|
|
|
#endif
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (parse_opts (argc, argv)) {
|
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (curvetest_file) {
|
|
|
|
return curvetest (curvetest_file);
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-03-14 22:31:27 -04:00
|
|
|
cout << PROGRAM_NAME
|
2005-09-25 14:42:24 -04:00
|
|
|
<< VERSIONSTRING
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 02:30:50 -04:00
|
|
|
<< _(" (built using ")
|
2013-03-17 09:53:30 -04:00
|
|
|
<< revision
|
2005-09-25 14:42:24 -04:00
|
|
|
#ifdef __GNUC__
|
2009-10-14 12:10:01 -04:00
|
|
|
<< _(" and GCC version ") << __VERSION__
|
2005-09-25 14:42:24 -04:00
|
|
|
#endif
|
|
|
|
<< ')'
|
|
|
|
<< endl;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (just_version) {
|
|
|
|
exit (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (no_splash) {
|
2012-01-03 16:13:05 -05:00
|
|
|
cerr << _("Copyright (C) 1999-2012 Paul Davis") << endl
|
2012-11-13 10:11:07 -05:00
|
|
|
<< _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker, Robin Gareus") << endl
|
2005-09-25 14:42:24 -04:00
|
|
|
<< endl
|
2010-03-14 22:31:27 -04:00
|
|
|
<< string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
|
2005-09-25 14:42:24 -04:00
|
|
|
<< _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
|
|
|
|
<< _("This is free software, and you are welcome to redistribute it ") << endl
|
|
|
|
<< _("under certain conditions; see the source for copying conditions.")
|
|
|
|
<< endl;
|
|
|
|
}
|
|
|
|
|
2007-03-18 02:07:08 -04:00
|
|
|
/* some GUI objects need this */
|
|
|
|
|
|
|
|
PBD::ID::init ();
|
|
|
|
|
2008-09-10 17:27:39 -04:00
|
|
|
if (::signal (SIGPIPE, sigpipe_handler)) {
|
2010-09-20 11:12:44 -04:00
|
|
|
cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
|
2008-09-10 17:27:39 -04:00
|
|
|
}
|
|
|
|
|
2009-10-27 14:00:45 -04:00
|
|
|
try {
|
2013-01-21 18:14:00 -05:00
|
|
|
ui = new ARDOUR_UI (&argc, &argv, localedir);
|
2006-08-30 22:28:42 -04:00
|
|
|
} catch (failed_constructor& err) {
|
2013-02-05 13:18:35 -05:00
|
|
|
error << string_compose (_("could not create %1 GUI"), PROGRAM_NAME) << endmsg;
|
2005-09-25 14:42:24 -04:00
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
|
2007-10-11 18:07:47 -04:00
|
|
|
ui->run (text_receiver);
|
2011-04-04 18:46:48 -04:00
|
|
|
Gtkmm2ext::Application::instance()->cleanup();
|
2007-10-11 18:07:47 -04:00
|
|
|
ui = 0;
|
2007-03-18 02:07:08 -04:00
|
|
|
|
2007-10-11 18:07:47 -04:00
|
|
|
ARDOUR::cleanup ();
|
2009-12-09 13:37:06 -05:00
|
|
|
pthread_cancel_all ();
|
2009-12-08 22:05:14 -05:00
|
|
|
|
Large nasty commit in the form of a 5000 line patch chock-full of completely
unecessary changes. (Sorry, doing a "sprint" based thing, this is the end of the first one)
Achieved MIDI track and bus creation, associated Jack port and diskstream creation, and minimal GUI stuff for creating them. Should be set to start work on actually recording and playing midi to/from disk now.
Relevant (significant) changes:
- Creation of a Buffer class. Base class is type agnostic so things can point to a buffer but not care what kind it is (otherwise it'd be a template). Derived into AudioBuffer and MidiBuffer, with a type tag because checking type is necessary in parts of the code where dynamic_cast wouldn't be wise. Originally I considered this a hack, but passing around a type proved to be a very good solution to all the other problems (below). There is a 1:1 mapping between jack port data types and ardour Buffer types (with a conversion function), but that's easily removed if it ever becomes necessary. Having the type scoped in the Buffer class is maybe not the best spot for it, but whatever (this is proof of concept kinda stuff right now...)
- IO now has a "default" port type (passed to the constructor and stored as a member), used by ensure_io (and similar) to create n ports. IO::register_***_port has a type argument that defaults to the default type if not passed. Rationale: previous IO API is identical, no changes needed to existing code, but path is paved for multiple port types in one IO, which we will need for eg synth plugin inserts, among other things. This is not quite ideal (best would be to only have the two port register functions and have them take a type), but the alternative is a lot of work (namely destroying the 'ensure' functions and everything that uses them) for very little gain. (I am convinced after quite a few tries at the whiteboard that subclassing IO in any way is not a feasible option, look at it's inheritance diagram in Doxygen and you can see why)
- AudioEngine::register_audio_input_port is now register_input_port and takes a type argument. Ditto for output.
- (Most significant change) AudioDiskstream abstracted into Distream, and sibling MidiDiskstream created. Very much still a work in progress, but Diskstream is there to switch references over to (most already are), which is the important part. It is still unclear what the MIDI diskstream's relation to channels is, but I'm pretty sure they will be single channel only (so SMF Type 0) since noone can come up with a reason otherwise.
- MidiTrack creation. Same thing as AudioTrack but with a different default type basically. No big deal here.
- Random cleanups and variable renamings etc. because I have OCD and can't help myself. :)
Known broken: Loading of sessions containing MIDI tracks.
git-svn-id: svn://localhost/ardour2/branches/midi@641 d708f5d6-7413-0410-9779-e7cbd77b26cf
2006-06-26 12:01:34 -04:00
|
|
|
return 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2011-11-21 12:42:29 -05:00
|
|
|
#ifdef WINDOWS_VST_SUPPORT
|
Large nasty commit in the form of a 5000 line patch chock-full of completely
unecessary changes. (Sorry, doing a "sprint" based thing, this is the end of the first one)
Achieved MIDI track and bus creation, associated Jack port and diskstream creation, and minimal GUI stuff for creating them. Should be set to start work on actually recording and playing midi to/from disk now.
Relevant (significant) changes:
- Creation of a Buffer class. Base class is type agnostic so things can point to a buffer but not care what kind it is (otherwise it'd be a template). Derived into AudioBuffer and MidiBuffer, with a type tag because checking type is necessary in parts of the code where dynamic_cast wouldn't be wise. Originally I considered this a hack, but passing around a type proved to be a very good solution to all the other problems (below). There is a 1:1 mapping between jack port data types and ardour Buffer types (with a conversion function), but that's easily removed if it ever becomes necessary. Having the type scoped in the Buffer class is maybe not the best spot for it, but whatever (this is proof of concept kinda stuff right now...)
- IO now has a "default" port type (passed to the constructor and stored as a member), used by ensure_io (and similar) to create n ports. IO::register_***_port has a type argument that defaults to the default type if not passed. Rationale: previous IO API is identical, no changes needed to existing code, but path is paved for multiple port types in one IO, which we will need for eg synth plugin inserts, among other things. This is not quite ideal (best would be to only have the two port register functions and have them take a type), but the alternative is a lot of work (namely destroying the 'ensure' functions and everything that uses them) for very little gain. (I am convinced after quite a few tries at the whiteboard that subclassing IO in any way is not a feasible option, look at it's inheritance diagram in Doxygen and you can see why)
- AudioEngine::register_audio_input_port is now register_input_port and takes a type argument. Ditto for output.
- (Most significant change) AudioDiskstream abstracted into Distream, and sibling MidiDiskstream created. Very much still a work in progress, but Diskstream is there to switch references over to (most already are), which is the important part. It is still unclear what the MIDI diskstream's relation to channels is, but I'm pretty sure they will be single channel only (so SMF Type 0) since noone can come up with a reason otherwise.
- MidiTrack creation. Same thing as AudioTrack but with a different default type basically. No big deal here.
- Random cleanups and variable renamings etc. because I have OCD and can't help myself. :)
Known broken: Loading of sessions containing MIDI tracks.
git-svn-id: svn://localhost/ardour2/branches/midi@641 d708f5d6-7413-0410-9779-e7cbd77b26cf
2006-06-26 12:01:34 -04:00
|
|
|
} // end of extern C block
|
|
|
|
#endif
|
2007-10-16 17:01:12 -04:00
|
|
|
|