From 85cb6e9812e90bb281b77b1b2f11e8275317dc79 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Wed, 28 Apr 2010 00:33:49 +0000 Subject: See ChangeLog --- muse/muse/osc.cpp | 1386 +++++++++++++++++++++++++++++++++++++++++++++ muse/muse/osc.h | 212 +++++++ muse/muse/stringparam.cpp | 113 ++++ muse/muse/stringparam.h | 49 ++ 4 files changed, 1760 insertions(+) create mode 100644 muse/muse/osc.cpp create mode 100644 muse/muse/osc.h create mode 100644 muse/muse/stringparam.cpp create mode 100644 muse/muse/stringparam.h diff --git a/muse/muse/osc.cpp b/muse/muse/osc.cpp new file mode 100644 index 00000000..c659dbf5 --- /dev/null +++ b/muse/muse/osc.cpp @@ -0,0 +1,1386 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id: osc.cpp,v 1.0.0.0 2010/04/22 03:39:58 terminator356 Exp $ +// +// Copyright (C) 1999-2010 by Werner Schweer and others +// OSC module added by Tim. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// 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 "config.h" + +#ifdef OSC_SUPPORT + +// Turn on debugging messages +//#define OSC_DEBUG + +#include +//#include +//#include +#include +#include +#include +//#include +//#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include + +#ifdef DSSI_SUPPORT +#include "dssihost.h" +#endif + +#include "stringparam.h" +#include "plugin.h" +#include "track.h" +#include "song.h" +#include "synth.h" +//#include "audio.h" +//#include "jackaudio.h" +//#include "midi.h" +//#include "midiport.h" +//#include "al/al.h" +//#include "al/xml.h" +//#include "xml.h" +//#include "midictrl.h" +//#include "ladspaplugin.h" + +#include "app.h" +#include "globals.h" +#include "globaldefs.h" +//#include "al/dsp.h" + +static lo_server_thread serverThread = 0; +///static char osc_path_tmp[1024]; +static char* url = 0; +static bool oscServerRunning = false; + +//--------------------------------------------------------- +// oscError +//--------------------------------------------------------- + +static void oscError(int num, const char *msg, const char *path) + { + fprintf(stderr, "MusE: liblo server error %d in path %s: %s\n", + num, path, msg); + } + +//--------------------------------------------------------- +// oscDebugHandler +//--------------------------------------------------------- + +static int oscDebugHandler(const char* path, const char* types, lo_arg** argv, + int argc, void*, void*) + { + printf("MusE: got unhandled OSC message:\n path: <%s>\n", path); + for (int i = 0; i < argc; i++) { + printf(" arg %d '%c' ", i, types[i]); + lo_arg_pp(lo_type(types[i]), argv[i]); + printf("\n"); + } + return 1; + } + +//--------------------------------------------------------- +// oscMessageHandler +//--------------------------------------------------------- + +int oscMessageHandler(const char* path, const char* types, lo_arg** argv, + int argc, void* data, void* user_data) +{ + const char* p = path; + + #ifdef OSC_DEBUG + if(argc) + { + printf("oscMessageHandler: path:%s argc:%d\n", path, argc); + for(int i = 0; i < argc; ++i) + { + printf(" "); + lo_arg_pp((lo_type)types[i], argv[i]); + } + printf("\n"); + } + else + { + printf("%s\n", path); + printf("oscMessageHandler: no args, path:%s\n", path); + } + #endif + + bool isSynth = false; + + #ifdef DSSI_SUPPORT + if(strncmp(p, "/dssi_synth/", 12) == 0) + { + isSynth = true; + p += 12; + } + else + #endif + if(strncmp(p, "/ladspa_efx/", 12) == 0) + { + p += 12; + } + else + return oscDebugHandler(path, types, argv, argc, data, user_data); + + TrackList* tl = song->tracks(); + + + #ifdef OSC_DEBUG + if(isSynth) + fprintf(stderr, "oscMessageHandler: got message for dssi synth...\n"); + else + fprintf(stderr, "oscMessageHandler: got message for ladspa effect...\n"); + #endif + + // FIXME: Slowdowns: Shouldn't need these retries but they are needed, only upon creation of the synth. + // Need to fix the real source of the problem! The instance is taking too long to appear after creation. + // + ///for(int retry = 0; retry < 5000; ++retry) + { + ///#ifdef OSC_DEBUG + ///fprintf(stderr, "oscMessageHandler: search retry number:%d ...\n", retry); + ///#endif + + //if(_uiOscPath) + // break; + + #ifdef DSSI_SUPPORT + if(isSynth) + { + // Message is meant for a dssi synth. Check dssi synth instances... + SynthIList* sl = song->syntis(); + for(iSynthI si = sl->begin(); si != sl->end(); ++si) + { + SynthI* synti = *si; + + #ifdef OSC_DEBUG + fprintf(stderr, "oscMessageHandler: searching for:%s checking synth instance:%s\n", p, synti->name().latin1()); + #endif + + const char* sub = strstr(p, synti->name().latin1()); + if(sub == NULL) + continue; + + //DssiSynthIF* instance = (DssiSynthIF*)synti->sif(); + DssiSynthIF* instance = dynamic_cast(synti->sif()); + if(!instance) + break; + + p = sub + strlen(synti->name().latin1()); + + if (*p != '/' || *(p + 1) == 0) + { + fprintf(stderr, "oscMessageHandler error: synth: end of path or no /\n"); + return oscDebugHandler(path, types, argv, argc, data, user_data); + } + + ++p; + + #ifdef OSC_DEBUG + fprintf(stderr, "oscMessageHandler: synth track:%s method:%s\n", synti->name().latin1(), p); + #endif + + OscIF& oscif = instance->oscIF(); + + if (!strcmp(p, "configure") && argc == 2 && !strcmp(types, "ss")) + return oscif.oscConfigure(argv); + else if (!strcmp(p, "control") && argc == 2 && !strcmp(types, "if")) + return oscif.oscControl(argv); + else if (!strcmp(p, "midi") && argc == 1 && !strcmp(types, "m")) + return oscif.oscMidi(argv); + else if (!strcmp(p, "program") && argc == 2 && !strcmp(types, "ii")) + return oscif.oscProgram(argv); + else if (!strcmp(p, "update") && argc == 1 && !strcmp(types, "s")) + return oscif.oscUpdate(argv); + else if (!strcmp(p, "exiting") && argc == 0) + return oscif.oscExiting(argv); + return oscDebugHandler(path, types, argv, argc, data, user_data); + } + } + else + #endif //DSSI_SUPPORT + // Message is meant for a ladspa effect. Check all ladspa effect instances... + for(ciTrack it = tl->begin(); it != tl->end(); ++it) + { + if((*it)->isMidiTrack()) + continue; + + Pipeline* efxPipe = ((AudioTrack*)*it)->efxPipe(); + if(efxPipe) + { + for(ciPluginI ip = efxPipe->begin(); ip != efxPipe->end(); ++ip) + { + PluginI* instance = *ip; + if(!instance) + continue; + + #ifdef OSC_DEBUG + fprintf(stderr, "oscMessageHandler: searching for:%s checking effect instance:%s label:%s lib:%s\n", + p, instance->name().latin1(), instance->label().latin1(), instance->lib().latin1()); + #endif + + //const char* sub = strstr(p, instance->name().latin1()); + const char* sub = strstr(p, instance->label().latin1()); + if(sub == NULL) + continue; + + Plugin* plugin = instance->plugin(); + if(!plugin) + break; + + //p = sub + strlen(instance->name().latin1()); + p = sub + strlen(instance->label().latin1()); + + if (*p != '/' || *(p + 1) == 0) + { + fprintf(stderr, "oscMessageHandler: error: effect: end of path or no /\n"); + return oscDebugHandler(path, types, argv, argc, data, user_data); + } + + ++p; + + #ifdef OSC_DEBUG + //fprintf(stderr, "oscMessageHandler: effect:%s method:%s\n", instance->name().latin1(), p); + fprintf(stderr, "oscMessageHandler: effect:%s method:%s\n", instance->label().latin1(), p); + #endif + + OscIF& oscif = instance->oscIF(); + + if (!strcmp(p, "configure") && argc == 2 && !strcmp(types, "ss")) + return oscif.oscConfigure(argv); + else if (!strcmp(p, "control") && argc == 2 && !strcmp(types, "if")) + return oscif.oscControl(argv); + else if (!strcmp(p, "midi") && argc == 1 && !strcmp(types, "m")) + return oscif.oscMidi(argv); + else if (!strcmp(p, "program") && argc == 2 && !strcmp(types, "ii")) + return oscif.oscProgram(argv); + else if (!strcmp(p, "update") && argc == 1 && !strcmp(types, "s")) + return oscif.oscUpdate(argv); + else if (!strcmp(p, "exiting") && argc == 0) + return oscif.oscExiting(argv); + return oscDebugHandler(path, types, argv, argc, data, user_data); + } + } + } + + ///usleep(1000); + } + + fprintf(stderr, "oscMessageHandler: timeout error: no synth or effect instance found for given path\n"); + return oscDebugHandler(path, types, argv, argc, data, user_data); +} + + +//--------------------------------------------------------- +// initOSC +//--------------------------------------------------------- + +void initOSC() +{ + if(url) + free(url); + url = 0; + + // Create OSC thread + // Only if not created yet. + if(!serverThread) + { + serverThread = lo_server_thread_new(0, oscError); + if(!serverThread) + { + printf("initOSC() Failed to create OSC server!\n"); + return; + } + } + + ///snprintf(osc_path_tmp, 31, "/dssi"); + // Test: Clear the temp path: + //snprintf(osc_path_tmp, 31, ""); + + ///char* tmp = lo_server_thread_get_url(serverThread); + + url = lo_server_thread_get_url(serverThread); + if(!url) + { + lo_server_thread_free(serverThread); + printf("initOSC() Failed to get OSC server thread url !\n"); + return; + } + + ///url = (char *)malloc(strlen(tmp) + strlen(osc_path_tmp)); + //url = (char *)malloc(strlen(tmp)); + + ///sprintf(url, "%s%s", tmp, osc_path_tmp + 1); + //sprintf(url, "%s", tmp, osc_path_tmp + 1); + + ///free(tmp); + + lo_method meth = 0; + meth = lo_server_thread_add_method(serverThread, 0, 0, oscMessageHandler, 0); + if(!meth) + { + printf("initOSC() Failed to add oscMessageHandler method to OSC server!\n"); + // Does not return a value. + lo_server_thread_free(serverThread); + serverThread = 0; + free(url); + url = 0; + return; + } + + // Does not return a value. + lo_server_thread_start(serverThread); +} + +//--------------------------------------------------------- +// exitOSC +//--------------------------------------------------------- + +void exitOSC() +{ + oscServerRunning = false; + if(serverThread) + { + // Does not return a value. + lo_server_thread_stop(serverThread); + lo_server_thread_free(serverThread); + } + serverThread = 0; +} + +//--------------------------------------------------------- +// startOSC +//--------------------------------------------------------- + +void startOSC() +{ + if(serverThread) + // Does not return a value. + lo_server_thread_start(serverThread); + oscServerRunning = true; +} + +//--------------------------------------------------------- +// stopOSC +//--------------------------------------------------------- + +void stopOSC() +{ + if(serverThread) + // Does not return a value. + lo_server_thread_stop(serverThread); + oscServerRunning = false; +} + + + +//--------------------------------------------------------- +// OscControlFifo +// put +// return true on fifo overflow +//--------------------------------------------------------- + +bool OscControlFifo::put(const OscControlValue& event) + { + if (size < OSC_FIFO_SIZE) { + fifo[wIndex] = event; + wIndex = (wIndex + 1) % OSC_FIFO_SIZE; + // q_atomic_increment(&size); + ++size; + return false; + } + return true; + } + +//--------------------------------------------------------- +// get +//--------------------------------------------------------- + +OscControlValue OscControlFifo::get() + { + OscControlValue event(fifo[rIndex]); + rIndex = (rIndex + 1) % OSC_FIFO_SIZE; + // q_atomic_decrement(&size); + --size; + return event; + } + +//--------------------------------------------------------- +// peek +//--------------------------------------------------------- + +const OscControlValue& OscControlFifo::peek(int n) + { + int idx = (rIndex + n) % OSC_FIFO_SIZE; + return fifo[idx]; + } + +//--------------------------------------------------------- +// remove +//--------------------------------------------------------- + +void OscControlFifo::remove() + { + rIndex = (rIndex + 1) % OSC_FIFO_SIZE; + // q_atomic_decrement(&size); + --size; + } + + + +//--------------------------------------------------------- +// OscIF +// Open Sound Control Interface +//--------------------------------------------------------- + +OscIF::OscIF() +{ + //_oscPluginI = 0; + + //#ifdef DSSI_SUPPORT + //_oscSynthIF = 0; + //#endif + + _uiOscTarget = 0; + _uiOscSampleRatePath = 0; + _uiOscShowPath = 0; + _uiOscControlPath = 0; + _uiOscConfigurePath = 0; + _uiOscProgramPath = 0; + _uiOscPath = 0; + //guiPid = -1; + _oscGuiQProc = 0; + _oscGuiVisible = false; + + _oscControlFifos = 0; +} + +OscIF::~OscIF() +{ + //if (guiPid != -1) + // kill(guiPid, SIGHUP); + if(_oscGuiQProc) + { + if(_oscGuiQProc->isRunning()) + { + #ifdef OSC_DEBUG + printf("OscIF::~OscIF terminating _oscGuiQProc\n"); + #endif + + //_oscGuiQProc->kill(); + // "This tries to terminate the process the nice way. If the process is still running after 5 seconds, + // it terminates the process the hard way. The timeout should be chosen depending on the time the + // process needs to do all its cleanup: use a higher value if the process is likely to do a lot of + // computation or I/O on cleanup." + _oscGuiQProc->tryTerminate(); + QTimer::singleShot( 5000, _oscGuiQProc, SLOT( kill() ) ); + } + //delete _oscGuiQProc; + } + + if(_uiOscTarget) + lo_address_free(_uiOscTarget); + if(_uiOscSampleRatePath) + free(_uiOscSampleRatePath); + if(_uiOscShowPath) + free(_uiOscShowPath); + if(_uiOscControlPath) + free(_uiOscControlPath); + if(_uiOscConfigurePath) + free(_uiOscConfigurePath); + if(_uiOscProgramPath) + free(_uiOscProgramPath); + if(_uiOscPath) + free(_uiOscPath); + + if(_oscControlFifos) + delete[] _oscControlFifos; +} + +//--------------------------------------------------------- +// oscFifo +//--------------------------------------------------------- + +OscControlFifo* OscIF::oscFifo(unsigned long i) const +{ + if(!_oscControlFifos) + return 0; + return &_oscControlFifos[i]; +} + +//--------------------------------------------------------- +// oscUpdate +//--------------------------------------------------------- + +int OscIF::oscUpdate(lo_arg **argv) +{ + const char *purl = (char *)&argv[0]->s; + + if(_uiOscTarget) + lo_address_free(_uiOscTarget); + _uiOscTarget = 0; + char* host = lo_url_get_hostname(purl); + char* port = lo_url_get_port(purl); + _uiOscTarget = lo_address_new(host, port); + free(host); + free(port); + if(!_uiOscTarget) + return 0; + + if (_uiOscPath) + free(_uiOscPath); + _uiOscPath = lo_url_get_path(purl); + int pl = strlen(_uiOscPath); + + if(_uiOscSampleRatePath) + free(_uiOscSampleRatePath); + _uiOscSampleRatePath = (char *)malloc(pl + 14); + sprintf(_uiOscSampleRatePath, "%s/sample-rate", _uiOscPath); + + if (_uiOscControlPath) + free(_uiOscControlPath); + _uiOscControlPath = (char *)malloc(pl + 10); + sprintf(_uiOscControlPath, "%s/control", _uiOscPath); + + if (_uiOscConfigurePath) + free(_uiOscConfigurePath); + _uiOscConfigurePath = (char *)malloc(pl + 12); + sprintf(_uiOscConfigurePath, "%s/configure", _uiOscPath); + + if (_uiOscProgramPath) + free(_uiOscProgramPath); + _uiOscProgramPath = (char *)malloc(pl + 10); + sprintf(_uiOscProgramPath, "%s/program", _uiOscPath); + + if (_uiOscShowPath) + free(_uiOscShowPath); + _uiOscShowPath = (char *)malloc(pl + 10); + sprintf(_uiOscShowPath, "%s/show", _uiOscPath); + + /* At this point a more substantial host might also call + * configure() on the UI to set any state that it had remembered + * for the plugin instance. But we don't remember state for + * plugin instances (see our own configure() implementation in + * osc_configure_handler), and so we have nothing to send except + * the optional project directory. + */ + + #ifdef OSC_DEBUG + printf("OscIF::oscUpdate: _uiOscTarget:%p\n", _uiOscTarget); + if(url) + printf(" server url:%s\n", url); + else + printf(" no server url!\n"); + printf(" update path:%s\n", purl); + printf(" _uiOscPath:%s\n", _uiOscPath); + printf(" _uiOscSampleRatePath:%s\n", _uiOscSampleRatePath); + printf(" _uiOscConfigurePath:%s\n", _uiOscConfigurePath); + printf(" _uiOscProgramPath:%s\n", _uiOscProgramPath); + printf(" _uiOscControlPath:%s\n",_uiOscControlPath); + printf(" _uiOscShowPath:%s\n", _uiOscShowPath); + printf(" museProject:%s\n", museProject.latin1()); + #endif + + // Send sample rate. + lo_send(_uiOscTarget, _uiOscSampleRatePath, "i", sampleRate); + + // Send project directory. + //lo_send(_uiOscTarget, _uiOscConfigurePath, "ss", + // DSSI_PROJECT_DIRECTORY_KEY, museProject.latin1()); // song->projectPath() + + // Done in sub-classes. + /* + #ifdef DSSI_SUPPORT + //lo_send(_uiOscTarget, _uiOscConfigurePath, "ss", + //DSSI_PROJECT_DIRECTORY_KEY, song->projectPath().toAscii().data()); + lo_send(_uiOscTarget, _uiOscConfigurePath, "ss", + DSSI_PROJECT_DIRECTORY_KEY, museProject.latin1()); + + if(_oscSynthIF) + { + for(ciStringParamMap r = _oscSynthIF->synthI->_stringParamMap.begin(); r != synti->_stringParamMap.end(); ++r) + { + rv = 0; + rv = dssi->configure(handle, r->first.c_str(), r->second.c_str()); + if(rv) + { + fprintf(stderr, "MusE: Warning: plugin config key: %s value: %s \"%s\"\n", r->first.c_str(), r->second.c_str(), rv); + free(rv); + } + } + } + #endif + */ + + /* + char uiOscGuiPath[strlen(_uiOscPath)+6]; + sprintf(uiOscGuiPath, "%s/%s", _uiOscPath, "show"); + + #ifdef OSC_DEBUG + printf("OscIF::oscUpdate Sending show uiOscGuiPath:%s\n", uiOscGuiPath); + #endif + + lo_send(_uiOscTarget, uiOscGuiPath, ""); + + sprintf(uiOscGuiPath, "%s/%s", _uiOscPath, "hide"); + + #ifdef OSC_DEBUG + printf("OscIF::oscUpdate Sending hide uiOscGuiPath:%s\n", uiOscGuiPath); + #endif + + lo_send(_uiOscTarget, uiOscGuiPath, ""); + */ + +#if 0 + /* Send current bank/program (-FIX- another race...) */ + if (instance->pendingProgramChange < 0) { + unsigned long bank = instance->currentBank; + unsigned long program = instance->currentProgram; + instance->uiNeedsProgramUpdate = 0; + if (instance->uiTarget) { + lo_send(instance->uiTarget, instance->ui_osc_program_path, "ii", bank, program); + } + } + + /* Send control ports */ + for (i = 0; i < instance->plugin->controlIns; i++) { + int in = i + instance->firstControlIn; + int port = pluginControlInPortNumbers[in]; + lo_send(instance->uiTarget, instance->ui_osc_control_path, "if", port, + pluginControlIns[in]); + /* Avoid overloading the GUI if there are lots and lots of ports */ + if ((i+1) % 50 == 0) + usleep(300000); + } +#endif + return 0; +} + +//--------------------------------------------------------- +// oscExiting +//--------------------------------------------------------- + +int OscIF::oscExiting(lo_arg**) +{ + // The gui is gone now, right? + _oscGuiVisible = false; + + if(_oscGuiQProc) + { + if(_oscGuiQProc->isRunning()) + { + #ifdef OSC_DEBUG + printf("OscIF::oscExiting terminating _oscGuiQProc\n"); + #endif + + //_oscGuiQProc->kill(); + // "This tries to terminate the process the nice way. If the process is still running after 5 seconds, + // it terminates the process the hard way. The timeout should be chosen depending on the time the + // process needs to do all its cleanup: use a higher value if the process is likely to do a lot of + // computation or I/O on cleanup." + _oscGuiQProc->tryTerminate(); + QTimer::singleShot( 5000, _oscGuiQProc, SLOT( kill() ) ); + } + //delete _oscGuiQProc; + } + + if(_uiOscTarget) + lo_address_free(_uiOscTarget); + _uiOscTarget = 0; + if(_uiOscSampleRatePath) + free(_uiOscSampleRatePath); + _uiOscSampleRatePath = 0; + if(_uiOscShowPath) + free(_uiOscShowPath); + _uiOscShowPath = 0; + if(_uiOscControlPath) + free(_uiOscControlPath); + _uiOscControlPath = 0; + if(_uiOscConfigurePath) + free(_uiOscConfigurePath); + _uiOscConfigurePath = 0; + if(_uiOscProgramPath) + free(_uiOscProgramPath); + _uiOscProgramPath = 0; + if(_uiOscPath) + free(_uiOscPath); + _uiOscPath = 0; + + //if(_oscControlFifos) + // delete[] _oscControlFifos; + + //const DSSI_Descriptor* dssi = synth->dssi; + //const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin; + //if(ld->deactivate) + // ld->deactivate(handle); + + /* + if (_uiOscPath == 0) { + printf("OscIF::oscExiting(): no _uiOscPath\n"); + return 1; + } + char uiOscGuiPath[strlen(_uiOscPath)+6]; + + sprintf(uiOscGuiPath, "%s/%s", _uiOscPath, "quit"); + #ifdef OSC_DEBUG + printf("OscIF::oscExiting(): sending quit to uiOscGuiPath:%s\n", uiOscGuiPath); + #endif + + lo_send(_uiOscTarget, uiOscGuiPath, ""); + */ + +#if 0 + int i; + + if (verbose) { + printf("MusE: OSC: got exiting notification for instance %d\n", + instance->number); + } + + if (instance->plugin) { + + /*!!! No, this isn't safe -- plugins deactivated in this way + would still be included in a run_multiple_synths call unless + we re-jigged the instance array at the same time -- leave it + for now + if (instance->plugin->descriptor->LADSPA_Plugin->deactivate) { + instance->plugin->descriptor->LADSPA_Plugin->deactivate + (instanceHandles[instance->number]); + } + */ + /* Leave this flag though, as we need it to determine when to exit */ + instance->inactive = 1; + } + + /* Do we have any plugins left running? */ + + for (i = 0; i < instance_count; ++i) { + if (!instances[i].inactive) + return 0; + } + + if (verbose) { + printf("MusE: That was the last remaining plugin, exiting...\n"); + } + exiting = 1; +#endif + return 0; +} + +//--------------------------------------------------------- +// oscSendProgram +//--------------------------------------------------------- + +void OscIF::oscSendProgram(unsigned long prog, unsigned long bank) +{ + if(_uiOscTarget && _uiOscProgramPath) + lo_send(_uiOscTarget, _uiOscProgramPath, "ii", bank, prog); +} + +//--------------------------------------------------------- +// oscSendControl +//--------------------------------------------------------- + +void OscIF::oscSendControl(unsigned long dssiPort, float v) +{ + if(_uiOscTarget && _uiOscControlPath) + lo_send(_uiOscTarget, _uiOscControlPath, "if", dssiPort, v); +} + +//--------------------------------------------------------- +// oscSendConfigure +//--------------------------------------------------------- + +void OscIF::oscSendConfigure(const char *key, const char *val) +{ + if(_uiOscTarget && _uiOscConfigurePath) + lo_send(_uiOscTarget, _uiOscConfigurePath, "ss", key, val); +} + +//--------------------------------------------------------- +// oscInitGui +//--------------------------------------------------------- + +//bool OscIF::oscInitGui() +bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QString& name, + const QString& label, const QString& filePath, const QString& dirPath) +{ + // Are we already running? We don't want to allow another process do we... + if((_oscGuiQProc != 0) && (_oscGuiQProc->isRunning())) + return true; + + if(!url) + { + fprintf(stderr, "OscIF::oscInitGui no server url!\n"); + return false; + } + + // + // start gui + // + //static char oscUrl[1024]; + //char oscUrl[1024]; + QString oscUrl; + + /* + QString typ; + QString baseName; + QString name; + QString label; + QString filePath; + QString dirPath; + #ifdef DSSI_SUPPORT + if(_oscSynthIF) + { + //snprintf(oscUrl, 1024, "%s/%s", url, synti->name().toAscii().data()); + //snprintf(oscUrl, 1024, "%s/%s", url, synti->name().ascii()); + //snprintf(oscUrl, 1024, "%s/%s/%s", url, synth->info.baseName().ascii(), synti->name().ascii()); + typ = QT_TR_NOOP("dssi_synth"); + baseName = _oscSynthIF->dssiSynth()->baseName(false); + label = _oscSynthIF->dssiSynthI()->name(); + name = _oscSynthIF->dssiSynth()->name(); + + dirPath = _oscSynthIF->dssiSynth()->dirPath(false); + filePath = _oscSynthIF->dssiSynth()->filePath(); + } + else + #endif + if(_oscPluginI) + { + typ = QT_TR_NOOP("ladspa_efx"); + baseName = _oscPluginI->plugin()->lib(false); + //name = _oscPluginI->name(); + name = _oscPluginI->plugin()->label(); + label = _oscPluginI->label(); + + dirPath = _oscPluginI->plugin()->dirPath(false); + //dirPath.replace("ladspa", "dssi", true); + + filePath = _oscPluginI->plugin()->filePath(); + //filePath.replace("ladspa", "dssi", true); + } + else + return false; + */ + + //snprintf(oscUrl, 1024, "%s/%s/%s", url, baseName.ascii(), name.ascii()); + //snprintf(oscUrl, 1024, "%s%s/%s/%s", url, typ.latin1(), baseName.latin1(), name.latin1()); + //oscUrl = QString("%1%2/%3/%4").arg(QString(QT_TR_NOOP(url))).arg(typ).arg(baseName).arg(name); + oscUrl = QString("%1%2/%3/%4").arg(QString(QT_TR_NOOP(url))).arg(typ).arg(baseName).arg(label); + + //QString guiPath(info.path() + "/" + info.baseName()); + //QString guiPath(synth->info.dirPath() + "/" + synth->info.baseName()); + QString guiPath(dirPath + "/" + baseName); + + #ifdef OSC_DEBUG + fprintf(stderr, "OscIF::oscInitGui guiPath:%s\n", guiPath.latin1()); + #endif + + QDir guiDir(guiPath, "*", QDir::Unsorted, QDir::Files); + if (guiDir.exists()) + { + //const QFileInfoList list = guiDir.entryInfoList(); + QStringList list = guiDir.entryList(); + + //for (int i = 0; i < list.size(); ++i) { + for (unsigned int i = 0; i < list.count(); ++i) + { + + //QFileInfo fi = list.at(i); + QFileInfo fi(guiPath + QString("/") + list[i]); + + QString gui(fi.filePath()); + if (gui.contains('_') == 0) + continue; + struct stat buf; + + //if (stat(gui.toAscii().data(), &buf)) { + if (stat(gui.latin1(), &buf)) { + + perror("stat failed"); + continue; + } + + #ifdef OSC_DEBUG + fprintf(stderr, "OscIF::oscInitGui %s %s %s %s\n", + //fi.filePath().toAscii().data(), + //fi.fileName().toAscii().data(), + fi.filePath().latin1(), + //fi.fileName().ascii(), + + oscUrl.latin1(), + + //synth->info.filePath().ascii(), + filePath.latin1(), + + //name().toAscii().data(), + //synth->name().ascii()); + name.latin1()); + #endif + + if ((S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) && + (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + { + // Changed by T356. + // fork + execlp were causing the processes to remain after closing gui, requiring manual kill. + // Changed to QProcess, works OK now. + //if((guiPid = fork()) == 0) + { + // No QProcess created yet? Do it now. Only once per SynthIF instance. Exists until parent destroyed. + if(_oscGuiQProc == 0) + _oscGuiQProc = new QProcess(muse); + + // Don't forget this, he he... + _oscGuiQProc->clearArguments(); + + _oscGuiQProc->addArgument(fi.filePath()); + //_oscGuiQProc->addArgument(fi.fileName()); // No conventional 'Arg0' here. + //_oscGuiQProc->addArgument(QString(oscUrl)); + _oscGuiQProc->addArgument(oscUrl); + //_oscGuiQProc->addArgument(synth->info.filePath()); + _oscGuiQProc->addArgument(filePath); + //_oscGuiQProc->addArgument(synth->name()); + _oscGuiQProc->addArgument(name); + _oscGuiQProc->addArgument(QString("channel-1")); + + #ifdef OSC_DEBUG + fprintf(stderr, "OscIF::oscInitGui starting QProcess\n"); + #endif + + if(_oscGuiQProc->start() == TRUE) + { + #ifdef OSC_DEBUG + fprintf(stderr, "OscIF::oscInitGui started QProcess\n"); + #endif + + //guiPid = _oscGuiQProc->processIdentifier(); + } + else + { + + /* + execlp( + //fi.filePath().toAscii().data(), + //fi.fileName().toAscii().data(), + fi.filePath().ascii(), + fi.fileName().ascii(), + + oscUrl, + + //info.filePath().toAscii().data(), + //name().toAscii().data(), + synth->info.filePath().ascii(), + synth->name().ascii(), + + "channel 1", (void*)0); + */ + + fprintf(stderr, "exec %s %s %s %s failed: %s\n", + //fi.filePath().toAscii().data(), + //fi.fileName().toAscii().data(), + fi.filePath().latin1(), + fi.fileName().latin1(), + + oscUrl.latin1(), + + //name().toAscii().data(), + //synth->name().ascii(), + name.latin1(), + + strerror(errno)); + + // It's Ok, Keep going. So nothing happens. So what. The timeout in showGui will just leave. + // Maybe it's a 'busy' issue somewhere - allow to try again later + save work now. + //exit(1); + + } + + #ifdef OSC_DEBUG + fprintf(stderr, "OscIF::oscInitGui after QProcess\n"); + #endif + } + } + } + //synth->_hasGui = true; + } + else { + printf("OscIF::oscInitGui %s: no dir for gui found: %s\n", + //name().toAscii().data(), guiPath.toAscii().data()); + //synth->name().ascii(), guiPath.ascii()); + name.latin1(), guiPath.latin1()); + + //synth->_hasGui = false; + } + + return true; +} + + +//--------------------------------------------------------- +// oscShowGui +//--------------------------------------------------------- + +void OscIF::oscShowGui(bool v) +{ + #ifdef OSC_DEBUG + printf("OscIF::oscShowGui(): v:%d visible:%d\n", v, oscGuiVisible()); + #endif + + if (v == oscGuiVisible()) + return; + + //if(guiPid == -1) + if((_oscGuiQProc == 0) || (!_oscGuiQProc->isRunning())) + { + // We need an indicator that update was called - update must have been called to get new path etc... + // If the process is not running this path is invalid, right? + if(_uiOscPath) + free(_uiOscPath); + _uiOscPath = 0; + + #ifdef OSC_DEBUG + printf("OscIF::oscShowGui(): No QProcess or process not running. Starting gui...\n"); + #endif + + if(!oscInitGui()) + { + printf("OscIF::oscShowGui(): failed to initialize gui on oscInitGui()\n"); + return; + } + } + + //for (int i = 0; i < 5; ++i) { + for (int i = 0; i < 10; ++i) { // Give it a wee bit more time? + if (_uiOscPath) + break; + sleep(1); + } + if (_uiOscPath == 0) { + printf("OscIF::oscShowGui(): no _uiOscPath. Error: Timeout - synth gui did not start within 10 seconds.\n"); + return; + } + + char uiOscGuiPath[strlen(_uiOscPath)+6]; + sprintf(uiOscGuiPath, "%s/%s", _uiOscPath, v ? "show" : "hide"); + + #ifdef OSC_DEBUG + printf("OscIF::oscShowGui(): Sending show/hide uiOscGuiPath:%s\n", uiOscGuiPath); + #endif + + lo_send(_uiOscTarget, uiOscGuiPath, ""); + _oscGuiVisible = v; +} + +//--------------------------------------------------------- +// oscGuiVisible +//--------------------------------------------------------- + +bool OscIF::oscGuiVisible() const +{ + return _oscGuiVisible; +} + +#ifdef DSSI_SUPPORT + +//--------------------------------------------------------- +// OscDssiIF:: +// oscSetSynthIF +//--------------------------------------------------------- + +//void OscIF::oscSetSynthIF(DssiSynthIF* s) +void OscDssiIF::oscSetSynthIF(DssiSynthIF* s) +{ + _oscSynthIF = s; + if(_oscControlFifos) + delete[] _oscControlFifos; + _oscControlFifos = 0; + + if(_oscSynthIF && _oscSynthIF->dssiSynth()) + { + unsigned long ports = _oscSynthIF->dssiSynth()->inControls(); + _oscControlFifos = new OscControlFifo[ports]; + } +} + +//--------------------------------------------------------- +// oscUpdate +//--------------------------------------------------------- + +int OscDssiIF::oscUpdate(lo_arg **argv) +{ + // Make sure to call base method. + OscIF::oscUpdate(argv); + + // Send sample rate. No, done in base class. + //lo_send(_uiOscTarget, _uiOscSampleRatePath, "i", sampleRate); + + // Send project directory. No, done in DssiSynthIF. + //lo_send(_uiOscTarget, _uiOscConfigurePath, "ss", + // DSSI_PROJECT_DIRECTORY_KEY, museProject.latin1()); // song->projectPath() + + if(_oscSynthIF) + _oscSynthIF->oscUpdate(); + + /* + if(_oscSynthIF) + { + // Send current string configuration parameters. + StringParamMap& map = _oscSynthIF->dssiSynthI()->stringParameters(); + int i = 0; + for(ciStringParamMap r = map.begin(); r != map.end(); ++r) + { + lo_send(_uiOscTarget, _uiOscConfigurePath, "ss", r->first.c_str(), r->second.c_str()); + // Avoid overloading the GUI if there are lots and lots of params. + if((i+1) % 50 == 0) + usleep(300000); + ++i; + } + + // Send current bank and program. + unsigned long bank, prog; + _oscSynthIF->dssiSynthI()->currentProg(&prog, &bank, 0); + lo_send(_uiOscTarget, _uiOscProgramPath, "ii", bank, prog); + + // Send current control values. + unsigned long ports = _oscSynthIF->dssiSynth()->inControls(); + for(unsigned long i = 0; i < ports; ++i) + { + unsigned long k = _oscSynthIF->dssiSynth()->inControlPortIdx(i); + lo_send(_uiOscTarget, _uiOscControlPath, "if", k, _oscSynthIF->getParameter(i)); + // Avoid overloading the GUI if there are lots and lots of ports. + if((i+1) % 50 == 0) + usleep(300000); + } + } + */ + + /* + char uiOscGuiPath[strlen(_uiOscPath)+6]; + sprintf(uiOscGuiPath, "%s/%s", _uiOscPath, "show"); + + #ifdef OSC_DEBUG + printf("OscIF::oscUpdate Sending show uiOscGuiPath:%s\n", uiOscGuiPath); + #endif + + lo_send(_uiOscTarget, uiOscGuiPath, ""); + + sprintf(uiOscGuiPath, "%s/%s", _uiOscPath, "hide"); + + #ifdef OSC_DEBUG + printf("OscIF::oscUpdate Sending hide uiOscGuiPath:%s\n", uiOscGuiPath); + #endif + + lo_send(_uiOscTarget, uiOscGuiPath, ""); + */ + +#if 0 + /* Send current bank/program (-FIX- another race...) */ + if (instance->pendingProgramChange < 0) { + unsigned long bank = instance->currentBank; + unsigned long program = instance->currentProgram; + instance->uiNeedsProgramUpdate = 0; + if (instance->uiTarget) { + lo_send(instance->uiTarget, instance->ui_osc_program_path, "ii", bank, program); + } + } + + /* Send control ports */ + for (i = 0; i < instance->plugin->controlIns; i++) { + int in = i + instance->firstControlIn; + int port = pluginControlInPortNumbers[in]; + lo_send(instance->uiTarget, instance->ui_osc_control_path, "if", port, + pluginControlIns[in]); + /* Avoid overloading the GUI if there are lots and lots of ports */ + if ((i+1) % 50 == 0) + usleep(300000); + } +#endif + return 0; +} + + +//--------------------------------------------------------- +// oscConfigure +//--------------------------------------------------------- + +int OscDssiIF::oscConfigure(lo_arg** argv) +{ + //OscIF::oscConfigure(argv); + + if(_oscSynthIF) + _oscSynthIF->oscConfigure((const char*)&argv[0]->s, (const char*)&argv[1]->s); + return 0; +} + +//--------------------------------------------------------- +// oscMidi +//--------------------------------------------------------- + +int OscDssiIF::oscMidi(lo_arg** argv) +{ + //OscIF::oscMidi(argv); + + if(_oscSynthIF) + _oscSynthIF->oscMidi(argv[0]->m[1], argv[0]->m[2], argv[0]->m[3]); + + return 0; +} + +//--------------------------------------------------------- +// oscProgram +//--------------------------------------------------------- + +int OscDssiIF::oscProgram(lo_arg** argv) +{ + //OscIF::oscProgram(argv); + + if(_oscSynthIF) + _oscSynthIF->oscProgram(argv[1]->i, argv[0]->i); + + return 0; +} + +//--------------------------------------------------------- +// oscControl +//--------------------------------------------------------- + +int OscDssiIF::oscControl(lo_arg** argv) +{ + //OscIF::oscControl(argv); + + int port = argv[0]->i; + if(port < 0) + return 0; + + if(_oscSynthIF) + _oscSynthIF->oscControl(argv[0]->i, argv[1]->f); + + return 0; +} + +//--------------------------------------------------------- +// oscInitGui +//--------------------------------------------------------- +bool OscDssiIF::oscInitGui() +{ + if(!_oscSynthIF) + return false; + + return OscIF::oscInitGui(QT_TR_NOOP("dssi_synth"), _oscSynthIF->dssiSynth()->baseName(false), + _oscSynthIF->dssiSynth()->name(), _oscSynthIF->dssiSynthI()->name(), + _oscSynthIF->dssiSynth()->filePath(), _oscSynthIF->dssiSynth()->dirPath(false)); +} + +#endif // DSSI_SUPPORT + + +//--------------------------------------------------------- +// OscEffectIF:: +// oscSetPluginI +//--------------------------------------------------------- + +void OscEffectIF::oscSetPluginI(PluginI* s) +{ + _oscPluginI = s; + if(_oscControlFifos) + delete[] _oscControlFifos; + _oscControlFifos = 0; + + if(_oscPluginI && _oscPluginI->plugin()) + { + unsigned long ports = _oscPluginI->plugin()->controlInPorts(); + _oscControlFifos = new OscControlFifo[ports]; + } +} + +//--------------------------------------------------------- +// oscUpdate +//--------------------------------------------------------- + +int OscEffectIF::oscUpdate(lo_arg** argv) +{ + // Make sure to call base method. + OscIF::oscUpdate(argv); + + // Send project directory. No, done in PluginI. + //lo_send(_uiOscTarget, _uiOscConfigurePath, "ss", + // DSSI_PROJECT_DIRECTORY_KEY, museProject.latin1()); // song->projectPath() + + if(_oscPluginI) + _oscPluginI->oscUpdate(); + + return 0; +} + +//--------------------------------------------------------- +// oscConfigure +//--------------------------------------------------------- + +int OscEffectIF::oscConfigure(lo_arg** argv) +{ + //OscIF::oscConfigure(argv); + + if(_oscPluginI) + _oscPluginI->oscConfigure((const char*)&argv[0]->s, (const char*)&argv[1]->s); + + return 0; +} + +//--------------------------------------------------------- +// oscControl +//--------------------------------------------------------- + +int OscEffectIF::oscControl(lo_arg** argv) +{ + //OscIF::oscControl(argv); + + int port = argv[0]->i; + if(port < 0) + return 0; + + if(_oscPluginI) + _oscPluginI->oscControl(argv[0]->i, argv[1]->f); + + return 0; +} + +//--------------------------------------------------------- +// oscInitGui +//--------------------------------------------------------- +bool OscEffectIF::oscInitGui() +{ + if(!_oscPluginI) + return false; + + return OscIF::oscInitGui(QT_TR_NOOP("ladspa_efx"), _oscPluginI->plugin()->lib(false), + _oscPluginI->plugin()->label(), _oscPluginI->label(), + _oscPluginI->plugin()->filePath(), _oscPluginI->plugin()->dirPath(false)); +} + + +#else //OSC_SUPPORT +void initOSC() {} +void exitOSC() {} + +#endif diff --git a/muse/muse/osc.h b/muse/muse/osc.h new file mode 100644 index 00000000..bf0ec1d5 --- /dev/null +++ b/muse/muse/osc.h @@ -0,0 +1,212 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id: osc.h,v 1.0.0.0 2010/04/22 10:05:00 terminator356 Exp $ +// +// Copyright (C) 1999-2010 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// 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. +//============================================================================= + +#ifndef __OSC_H__ +#define __OSC_H__ + +#include + +#include "config.h" + +#ifdef DSSI_SUPPORT +class DssiSynthIF; +#endif + +class QProcess; +class PluginI; +class OscIF; + +// Keep the OSC fifo small. There may be thousands of controls, and each control needs a fifo. +// Oops, no, if the user keeps adjusting a slider without releasing the mouse button, then all of the +// events are sent at once upon releasing the button, meaning there might be thousands of events at once. +#define OSC_FIFO_SIZE 512 + +//--------------------------------------------------------- +// OscControlValue +// Item struct for OscGuiControlFifo. +//--------------------------------------------------------- + +struct OscControlValue +{ + //int idx; + float value; + // maybe timestamp, too ? +}; + +//--------------------------------------------------------- +// OscControlFifo +// A fifo for each of the OSC controls. +//--------------------------------------------------------- + +class OscControlFifo +{ + OscControlValue fifo[OSC_FIFO_SIZE]; + volatile int size; + int wIndex; + int rIndex; + + public: + OscControlFifo() { clear(); } + bool put(const OscControlValue& event); // returns true on fifo overflow + OscControlValue get(); + const OscControlValue& peek(int n = 0); + void remove(); + bool isEmpty() const { return size == 0; } + void clear() { size = 0, wIndex = 0, rIndex = 0; } + int getSize() const { return size; } +}; + +//--------------------------------------------------------- +// OscIF +// Open Sound Control Interface +//--------------------------------------------------------- + +/* +class OscIF +{ + private: + PluginI* _oscPluginI; + + #ifdef DSSI_SUPPORT + DssiSynthIF* _oscSynthIF; + #endif + + QProcess* _oscGuiQProc; + void* _uiOscTarget; + char* _uiOscShowPath; + char* _uiOscControlPath; + char* _uiOscConfigurePath; + char* _uiOscProgramPath; + char* _uiOscPath; + bool _oscGuiVisible; + + OscControlFifo* _oscControlFifos; + + public: + OscIF(); + ~OscIF(); + + void oscSetPluginI(PluginI*); + + #ifdef DSSI_SUPPORT + void oscSetSynthIF(DssiSynthIF*); + #endif + + int oscUpdate(lo_arg**); + int oscProgram(lo_arg**); + int oscControl(lo_arg**); + int oscExiting(lo_arg**); + int oscMidi(lo_arg**); + int oscConfigure(lo_arg**); + + bool oscInitGui(); + void oscShowGui(bool); + bool oscGuiVisible() const; + OscControlFifo* oscFifo(unsigned long) const; +}; +*/ + +class OscIF +{ + protected: + QProcess* _oscGuiQProc; + void* _uiOscTarget; + char* _uiOscPath; + char* _uiOscSampleRatePath; + char* _uiOscConfigurePath; + char* _uiOscProgramPath; + char* _uiOscControlPath; + char* _uiOscShowPath; + bool _oscGuiVisible; + + OscControlFifo* _oscControlFifos; + + virtual bool oscInitGui(const QString& /*typ*/, const QString& /*baseName*/, const QString& /*name*/, + const QString& /*label*/, const QString& /*filePath*/, const QString& /*dirPath*/); + + public: + OscIF(); + virtual ~OscIF(); + + OscControlFifo* oscFifo(unsigned long) const; + + virtual int oscUpdate(lo_arg**); + virtual int oscProgram(lo_arg**) { return 0; } + virtual int oscControl(lo_arg**) { return 0; } + virtual int oscExiting(lo_arg**); + virtual int oscMidi(lo_arg**) { return 0; } + virtual int oscConfigure(lo_arg**) { return 0; } + + virtual void oscSendProgram(unsigned long /*prog*/, unsigned long /*bank*/); + virtual void oscSendControl(unsigned long /*dssiPort*/, float /*val*/); + virtual void oscSendConfigure(const char */*key*/, const char */*val*/); + + virtual bool oscInitGui() { return false; } + virtual void oscShowGui(bool); + virtual bool oscGuiVisible() const; +}; + +class OscEffectIF : public OscIF +{ + protected: + PluginI* _oscPluginI; + + public: + OscEffectIF() {} + //~OscEffectIF(); + + void oscSetPluginI(PluginI*); + + virtual int oscUpdate(lo_arg**); + //virtual int oscProgram(lo_arg**); + virtual int oscControl(lo_arg**); + //virtual int oscExiting(lo_arg**); + //virtual int oscMidi(lo_arg**); + virtual int oscConfigure(lo_arg**); + + virtual bool oscInitGui(); +}; + +#ifdef DSSI_SUPPORT +class OscDssiIF : public OscIF +{ + protected: + DssiSynthIF* _oscSynthIF; + + public: + OscDssiIF() {} + //~OscDssiIF(); + + void oscSetSynthIF(DssiSynthIF*); + + virtual int oscUpdate(lo_arg**); + virtual int oscProgram(lo_arg**); + virtual int oscControl(lo_arg**); + //virtual int oscExiting(lo_arg**); + virtual int oscMidi(lo_arg**); + virtual int oscConfigure(lo_arg**); + + virtual bool oscInitGui(); +}; +#endif // DSSI_SUPPORT + +extern void initOSC(); + +#endif diff --git a/muse/muse/stringparam.cpp b/muse/muse/stringparam.cpp new file mode 100644 index 00000000..b3b5104e --- /dev/null +++ b/muse/muse/stringparam.cpp @@ -0,0 +1,113 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id: stringparam.cpp,v 1.0.0.0 2010/04/24 01:01:01 terminator356 Exp $ +// +// Copyright (C) 1999-2010 by Werner Schweer and others +// String parameter module added by Tim. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// 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 +#include "stringparam.h" +#include "xml.h" + +//--------------------------------------------------------- +// findKey +//--------------------------------------------------------- + +iStringParamMap StringParamMap::findKey(const char* key) +{ + iStringParamMap icm = find(std::string(key)); + return icm; +} + +//--------------------------------------------------------- +// set +//--------------------------------------------------------- + +void StringParamMap::set(const char* key, const char* value) +{ + iStringParamMap icm = find(std::string(key)); + if(icm == end()) + insert(std::pair(key, value)); + else + icm->second = std::string(value); +} + +//--------------------------------------------------------- +// remove +//--------------------------------------------------------- + +void StringParamMap::remove(const char* key) +{ + erase(std::string(key)); +} + +//--------------------------------------------------------- +// read +//--------------------------------------------------------- + +void StringParamMap::read(Xml& xml, const QString& name) +{ + QString n; + QString value; + + for (;;) + { + Xml::Token token = xml.parse(); + const QString tag = xml.s1(); + switch (token) + { + case Xml::Error: + case Xml::End: + return; + case Xml::TagStart: + xml.unknown(name); + break; + case Xml::Attribut: + if(tag == "name") + n = xml.s2(); + else + if(tag == "val") + value = xml.s2(); + else + xml.unknown(name); + break; + case Xml::TagEnd: + if(tag == name) + { + // Add or modify the item. + set(n.latin1(), value.latin1()); + return; + } + default: + break; + } + } +} + +//--------------------------------------------------------- +// write +//--------------------------------------------------------- + +void StringParamMap::write(int level, Xml& xml, const char* name) const +{ + if(empty()) + return; + + for(ciStringParamMap r = begin(); r != end(); ++r) + xml.tag(level, "%s name=\"%s\" val=\"%s\"/", name, r->first.c_str(), r->second.c_str()); +} + diff --git a/muse/muse/stringparam.h b/muse/muse/stringparam.h new file mode 100644 index 00000000..0e05c987 --- /dev/null +++ b/muse/muse/stringparam.h @@ -0,0 +1,49 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id: stringparam.h,v 1.0.0.0 2010/04/24 01:01:01 terminator356 Exp $ +// +// Copyright (C) 1999-2010 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// 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. +//============================================================================= + + +#ifndef __STRINGPARAM_H__ +#define __STRINGPARAM_H__ + +#include +#include + +class QString; +class Xml; + +//typedef std::pair StringParamMapItem; +typedef std::map::iterator iStringParamMap; +typedef std::map::const_iterator ciStringParamMap; + +class StringParamMap : public std::map +{ + public: + void set(const char* /*key*/, const char* /*value*/); + void remove(const char* /*key*/); + + iStringParamMap findKey(const char* /*key*/); + //int index(char* /*key*/); + + void read(Xml& /*xml*/, const QString& /*name*/); + void write(int /*level*/, Xml& /*xml*/, const char* /*name*/) const; +}; + + +#endif //__STRINGPARAM_H__ \ No newline at end of file -- cgit v1.2.3