5 #if defined(TARGET_LINUX)
14 #include <alsa/asoundlib.h>
15 #include "JucePluginCharacteristics.h"
22 #define OSCPKT_OSTREAM_OUTPUT
23 #include "oscpkt/oscpkt.hh"
24 #include "oscpkt/udp.hh"
27 /* conveniency functions for debugging ..*/
28 inline std::ostream
&operator<<(std::ostream
&os
, const juce::String
&s
) {
35 extern Display
* display
;
36 extern bool juce_postMessageToSystemQueue (void* message
);
38 class DssiSharedMessageThread
: public Thread
41 DssiSharedMessageThread()
42 : Thread (JUCE_T("DssiMessageThread")),
50 ~DssiSharedMessageThread()
52 signalThreadShouldExit();
53 JUCEApplication::quit();
54 waitForThreadToExit (5000);
55 clearSingletonInstance();
62 MessageManager::getInstance()->setCurrentThreadAsMessageThread();
64 while ((! threadShouldExit()) && MessageManager::getInstance()->runDispatchLoopUntil (250))
69 juce_DeclareSingleton (DssiSharedMessageThread
, false)
75 juce_ImplementSingleton (DssiSharedMessageThread
);
83 class JuceDSSIWrapper
;
85 class DssiEditorCompWrapper
: public DocumentWindow
87 JuceDSSIWrapper
* wrapper
;
90 DssiEditorCompWrapper (JuceDSSIWrapper
* const wrapper_
,
91 AudioProcessorEditor
* const editor
, const String
&title
,
93 : DocumentWindow(title
, Colours::white
, DocumentWindow::allButtons
, false)
98 setUsingNativeTitleBar(true);
99 editor
->setOpaque (true);
100 setDropShadowEnabled(false);
101 setContentComponent(editor
, true, true);
103 if (xpos
!= -10000 && ypos
!= -10000) {
104 setTopLeftPosition(xpos
, ypos
-20 /* position bug? */ );
105 } else setCentreRelative(.5f
, .5f
);
107 Component::addToDesktop(getDesktopWindowStyleFlags());
111 AudioProcessorEditor
* getEditorComp() const
113 return dynamic_cast <AudioProcessorEditor
*> (getContentComponent());
116 BorderSize
getBorderThickness() const { return BorderSize(0); }
117 BorderSize
getContentComponentBorder() const { return BorderSize(0); }
119 void closeButtonPressed();
121 juce_UseDebuggingNewOperator
;
125 struct OscAction
: public juce::Message
{
129 class DssiMinimalOscServer
: public Thread
{
131 MessageListener
*listener
;
133 DssiMinimalOscServer() : Thread(JUCE_T("osc")), listener(0) {}
134 ~DssiMinimalOscServer() {
135 jassert(!isThreadRunning());
138 void setListener(MessageListener
*l
) { listener
= l
; }
139 void sendMessageTo(const String
&osc_url
, const String
&message_path
,
140 const String
&arg1
= String::empty
, const String
&arg2
= String::empty
) {
141 char *url_hostname
= lo_url_get_hostname(osc_url
.toUTF8());
142 char *url_port
= lo_url_get_port(osc_url
.toUTF8());
143 char *url_path
= lo_url_get_path(osc_url
.toUTF8());
146 path
<< url_path
<< message_path
; path
= path
.replace("//","/");
147 lo_address hostaddr
= lo_address_new(url_hostname
, url_port
);
149 if (!arg1
.isNotEmpty()) {
150 lo_send(hostaddr
, path
.toUTF8(), "");
151 } else if (!arg2
.isNotEmpty()) {
152 lo_send(hostaddr
, path
.toUTF8(), "s", arg1
.toUTF8());
154 lo_send(hostaddr
, path
.toUTF8(), "ss", arg1
.toUTF8(), arg2
.toUTF8());
156 lo_address_free(hostaddr
);
162 if (isThreadRunning()) return;
163 serv
= lo_server_new(NULL
, NULL
);
164 lo_server_add_method(serv
, NULL
, NULL
, &osc_callback
, this);
168 if (!isThreadRunning()) return;
169 signalThreadShouldExit();
171 lo_server_free(serv
);
174 char *s
= lo_server_get_url(serv
);
175 String url
; url
<< s
; free(s
);
179 while (!threadShouldExit()) {
180 lo_server_recv_noblock(serv
, 50);
183 static int osc_callback(const char *path
, const char *types
,
184 lo_arg
**argv
, int argc
, lo_message
, void *user_data
) {
185 OscAction
*a
= new OscAction
;
187 if (argc
> 0 && types
[0] == 's') {
188 a
->arg
<< &argv
[0]->s
;
190 ((DssiMinimalOscServer
*)user_data
)->listener
->postMessage(a
);
195 // ad-hoc server that implements only what we need for dssi..
196 class DssiMinimalOscServer
: public Thread
{
197 oscpkt::UdpSocket serv
;
198 MessageListener
*listener
;
200 DssiMinimalOscServer() : Thread(JUCE_T("osc")), listener(0) {}
201 void setListener(MessageListener
*l
) { listener
= l
; }
202 void sendMessageTo(const String
&osc_url
, const String
&message_path
,
203 const String
&arg1
= String::empty
, const String
&arg2
= String::empty
) {
204 oscpkt::Url
url(osc_url
.toUTF8());
205 if (!url
.isOk()) return;
207 oscpkt::PacketWriter pw
;
209 std::string path
= url
.path
;
210 if (!path
.empty() && path
[path
.size()-1] == '/') path
.resize(path
.size()-1);
211 path
+= message_path
.toUTF8();
214 if (arg1
.isNotEmpty()) msg
.pushStr(arg1
.toUTF8());
215 if (arg2
.isNotEmpty()) msg
.pushStr(arg2
.toUTF8());
218 oscpkt::UdpSocket sock
; sock
.connectTo(url
.hostname
, url
.port
);
219 bool ok
= sock
.sendPacket(pw
.packetData(), pw
.packetSize());
221 cerr
<< "Could not send " << msg
.addressPattern() << " message to "
222 << url
.hostname
<< ":" << url
.port
<< " '" << sock
.errorMessage() << "'\n";
226 if (isThreadRunning()) return;
227 serv
.bindTo(0 /* any port */);
229 cerr
<< "cannot start osc server: " << serv
.errorMessage() << "\n"; return;
234 if (!isThreadRunning()) return;
235 signalThreadShouldExit();
240 String s
; s
<< ("osc.udp://" + serv
.localHostNameWithPort() + "/").c_str();
244 while (!threadShouldExit() && serv
.isOk()) {
245 if (serv
.receiveNextPacket(50 /* timeout, in ms */)) {
246 oscpkt::PacketReader
pr(serv
.packetData(), serv
.packetSize());
248 oscpkt::Message
*msg
;
249 while ((msg
= pr
.popMessage())) {
250 OscAction
*a
= new OscAction
;
251 a
->msg
<< msg
->addressPattern().c_str();
252 if (msg
->arg().nbArgRemaining() && msg
->arg().isStr()) {
253 std::string s
; msg
->arg().popStr(s
);
256 listener
->postMessage(a
);
270 static Array
<void*> activePlugins
;
272 extern AudioProcessor
* JUCE_CALLTYPE
createPluginFilter();
274 static LADSPA_Descriptor
*ladspa_desc
= 0;
275 static DSSI_Descriptor
*dssi_desc
= 0;
277 struct JuceDSSIWrapper
: public Timer
, public MessageListener
{
279 static LADSPA_Descriptor
*getLadspaDescriptor() {
280 if (!ladspa_desc
) initialiseDescriptors();
284 static DSSI_Descriptor
*getDssiDescriptor() {
285 if (!dssi_desc
) initialiseDescriptors();
289 static void initialiseDescriptors();
291 static void destroyDescriptors() {
293 for (size_t i
=0; i
< ladspa_desc
->PortCount
; ++i
) {
294 free((void*)ladspa_desc
->PortNames
[i
]);
296 delete[] ladspa_desc
->PortDescriptors
;
297 delete[] ladspa_desc
->PortNames
;
298 delete[] ladspa_desc
->PortRangeHints
;
308 static void callbackCleanup(LADSPA_Handle instance
) {
310 MessageManagerLock mmLock
;
311 delete (JuceDSSIWrapper
*)instance
;
313 if (activePlugins
.size() == 0) {
314 DssiSharedMessageThread::deleteInstance();
319 static LADSPA_Handle
callbackInstantiate(const LADSPA_Descriptor
*,
320 unsigned long s_rate
) {
321 if (activePlugins
.size() == 0) {
322 DssiSharedMessageThread::getInstance();
324 MessageManagerLock mmLock
;
325 return new JuceDSSIWrapper(s_rate
);
329 static void callbackConnectPort(LADSPA_Handle instance
, unsigned long port
,
330 LADSPA_Data
* data
) {
331 MessageManagerLock mmLock
;
332 ((JuceDSSIWrapper
*)instance
)->connectPort(port
, data
);
335 static void callbackActivate(LADSPA_Handle instance
) {
336 MessageManagerLock mmLock
;
337 ((JuceDSSIWrapper
*)instance
)->activate();
340 static void callbackDeactivate(LADSPA_Handle instance
) {
341 MessageManagerLock mmLock
;
342 ((JuceDSSIWrapper
*)instance
)->deactivate();
345 static void callbackRunAsEffect(LADSPA_Handle instance
,
346 unsigned long sample_count
) {
347 ((JuceDSSIWrapper
*)instance
)->run(sample_count
, 0, 0);
350 static void callbackRun(LADSPA_Handle instance
, unsigned long sample_count
,
351 snd_seq_event_t
*events
, unsigned long event_count
) {
352 ((JuceDSSIWrapper
*)instance
)->run(sample_count
, events
, event_count
);
355 static char* callbackConfigure(LADSPA_Handle instance
,
356 const char *key
, const char *value
) {
357 MessageManagerLock mmLock
;
358 return ((JuceDSSIWrapper
*)instance
)->configure(key
, value
);
361 static const DSSI_Program_Descriptor
*callbackGetProgram(LADSPA_Handle instance
,
362 unsigned long index
) {
363 MessageManagerLock mmLock
;
364 return ((JuceDSSIWrapper
*)instance
)->getProgram(index
);
367 static void callbackSelectProgram(LADSPA_Handle instance
,
369 unsigned long program
) {
370 MessageManagerLock mmLock
;
371 return ((JuceDSSIWrapper
*)instance
)->selectProgram(bank
, program
);
376 MidiBuffer midi_buffer
;
378 float *output_port
[JucePlugin_MaxNumOutputChannels
];
380 #define UNSET_PARAMETER_VALUE 1e10
381 Array
<float*> param_port
;
382 Array
<float> param_saved
; // value of the parameters saved at previous callback, to detect param value change
384 AudioProcessor
*filter
;
386 DssiEditorCompWrapper
* editorComp
;
387 bool shouldDeleteEditor
;
390 int x_editor
, y_editor
;
392 DssiMinimalOscServer osc_server
; // used only for comminucation with the gui
396 JuceDSSIWrapper(unsigned long s_rate
) {
399 shouldDeleteEditor
= false;
400 x_editor
= y_editor
= -10000;
401 osc_server
.setListener(this);
403 for (int c
=0; c
< JucePlugin_MaxNumOutputChannels
; ++c
) output_port
[c
] = 0;
404 sample_rate
= s_rate
;
405 filter
= createPluginFilter();
406 param_port
.insertMultiple(0, 0, filter
->getNumParameters());
407 param_saved
.insertMultiple(0, UNSET_PARAMETER_VALUE
, filter
->getNumParameters());
408 activePlugins
.add (this);
413 osc_server
.stopServer();
417 deleteAndZero(filter
);
418 jassert (activePlugins
.contains (this));
419 activePlugins
.removeValue (this);
422 AudioProcessor
*getFilter() { return filter
; }
424 void connectPort(unsigned long port
, LADSPA_Data
*data
) {
425 if (port
< JucePlugin_MaxNumOutputChannels
) {
426 output_port
[port
] = data
;
428 int param
= (int)port
- JucePlugin_MaxNumOutputChannels
;
429 if (param
< param_port
.size()) {
430 param_port
.set(param
, (float*)data
);
431 param_saved
.set(param
, UNSET_PARAMETER_VALUE
);
437 unsigned block_size
= 512;
438 filter
->setNonRealtime(false);
439 filter
->setPlayConfigDetails (0, JucePlugin_MaxNumOutputChannels
,
440 sample_rate
, block_size
);
441 filter
->prepareToPlay(sample_rate
, block_size
);
444 snd_midi_event_new(sizeof midi_parser_buffer
, &midi_parser
);
448 filter
->releaseResources();
450 snd_midi_event_free(midi_parser
);
453 DSSI_Program_Descriptor latest_program_descriptor
;
454 std::string latest_program_descriptor_name
;
455 const DSSI_Program_Descriptor
*getProgram(unsigned long index
) {
456 if (index
< (unsigned long)filter
->getNumPrograms()) {
457 latest_program_descriptor
.Bank
= 0;
458 latest_program_descriptor
.Program
= index
;
459 latest_program_descriptor_name
= filter
->getProgramName((int)index
).toUTF8();
460 latest_program_descriptor
.Name
= latest_program_descriptor_name
.c_str();
461 return &latest_program_descriptor
;
466 void selectProgram(unsigned long bank
, unsigned long program
) {
467 if (bank
== 0) filter
->setCurrentProgram((int)program
);
471 // update the port values from the plugin parameter values
472 void updateParameters() {
473 for (int i
=0; i
< param_port
.size(); ++i
) {
475 float v
= filter
->getParameter(i
);
477 param_saved
.set(i
,v
);
482 void run(unsigned long sample_count
, snd_seq_event_t
*events
, unsigned long event_count
) {
483 /* handle incoming midi events */
485 for (size_t i
=0; i
< event_count
; ++i
) {
486 const int num_bytes
= snd_midi_event_decode(midi_parser
, midi_parser_buffer
, sizeof midi_parser_buffer
, &events
[i
]);
487 snd_midi_event_reset_decode(midi_parser
);
489 midi_buffer
.addEvent(midi_parser_buffer
, num_bytes
, events
[i
].time
.tick
);
494 /* handle parameter changes initiated by the host */
495 for (int i
=0; i
< param_port
.size(); ++i
) {
497 if (param_saved
[i
] != *param_port
[i
]) {
498 filter
->setParameter(i
, *param_port
[i
]);
504 const ScopedLock
sl (filter
->getCallbackLock());
505 if (filter
->isSuspended()) {
506 for (int i
= 0; i
< JucePlugin_MaxNumOutputChannels
; ++i
)
507 zeromem (output_port
[i
], sizeof (float) * sample_count
);
509 AudioSampleBuffer
chans (output_port
, JucePlugin_MaxNumOutputChannels
, sample_count
);
510 filter
->processBlock (chans
, midi_buffer
);
514 /* read back parameter values */
517 if (!midi_buffer
.isEmpty()) { midi_buffer
.clear(); }
520 struct FakeGuiConnectMessage
: public Message
{
522 FakeGuiConnectMessage(const String
&s
) { arg
= s
; }
523 ~FakeGuiConnectMessage() throw() {}
526 char *configure(const char *key
, const char *value
) {
527 if (strcmp(key
, "guiVisible") == 0) {
528 postMessage(new FakeGuiConnectMessage(String(value
)));
533 void handleMessage(const Message
&msg
) {
534 const FakeGuiConnectMessage
*fmsg
;
535 if ((fmsg
= dynamic_cast<const FakeGuiConnectMessage
*>(&msg
))) {
536 bool show
= fmsg
->arg
.isNotEmpty();
538 StringArray arg
; arg
.addTokens(fmsg
->arg
, JUCE_T("|"), JUCE_T(""));
539 if (arg
.size() == 2) {
540 gui_osc_url
= arg
[0];
541 String window_title
= arg
[1];
543 /* only 1 gui will be opened at once, request for new guis will automatically close the older ones */
545 createEditorComp(window_title
);
552 const OscAction
*osc
;
553 if ((osc
= dynamic_cast<const OscAction
*>(&msg
))) {
554 if (osc
->msg
== "/internal_gui_hide") {
556 } else if (osc
->msg
== "/exiting") {
558 gui_osc_url
= String::empty
;
563 static AudioProcessor
*initialiseAndCreateFilter() {
564 initialiseJuce_GUI();
565 AudioProcessor
* filter
= createPluginFilter();
569 void createEditorComp(const String
&title
);
570 void deleteEditor (bool canDeleteLaterIfModal
);
572 void notifyRemoteProcess(bool b
) {
574 osc_server
.startServer();
575 osc_server
.sendMessageTo(gui_osc_url
, JUCE_T("/internal_gui_status"), osc_server
.getOscUrl());
577 osc_server
.sendMessageTo(gui_osc_url
, JUCE_T("/internal_gui_status"), JUCE_T(""));
578 osc_server
.stopServer();
582 void timerCallback() {
583 if (shouldDeleteEditor
) {
584 shouldDeleteEditor
= false;
587 if (osc_server
.isThreadRunning() && gui_osc_url
.isNotEmpty()) {
588 // perdiodically ping the gui process, so that it now it has not been abandonned as an orphan process...
589 notifyRemoteProcess(editorComp
!=0 );
593 snd_midi_event_t
* midi_parser
;
594 uint8_t midi_parser_buffer
[16384];
596 }; // end of class JuceDSSIWrapper
598 void DssiEditorCompWrapper::closeButtonPressed() {
599 wrapper
->deleteEditor(true);
602 void JuceDSSIWrapper::createEditorComp(const String
&title
) {
603 if (hasShutdown
|| filter
== 0)
606 if (editorComp
== 0) {
607 AudioProcessorEditor
* const ed
= filter
->createEditorIfNeeded();
609 editorComp
= new DssiEditorCompWrapper(this, ed
, title
, x_editor
, y_editor
);
610 notifyRemoteProcess(true);
613 shouldDeleteEditor
= false;
616 void JuceDSSIWrapper::deleteEditor (bool canDeleteLaterIfModal
)
618 PopupMenu::dismissAllActiveMenus();
620 if (editorComp
!= 0) {
621 Component
* const modalComponent
= Component::getCurrentlyModalComponent();
622 if (modalComponent
!= 0) {
623 modalComponent
->exitModalState (0);
625 if (canDeleteLaterIfModal
) {
626 shouldDeleteEditor
= true;
631 filter
->editorBeingDeleted (editorComp
->getEditorComp());
632 x_editor
= editorComp
->getX();
633 y_editor
= editorComp
->getY();
634 deleteAndZero (editorComp
);
636 notifyRemoteProcess(false);
638 // there's some kind of component currently modal, but the host
639 // is trying to delete our plugin. You should try to avoid this happening..
640 jassert (Component::getCurrentlyModalComponent() == 0);
644 void JuceDSSIWrapper::initialiseDescriptors() {
645 initialiseJuce_GUI();
646 AudioProcessor
*plugin
= createPluginFilter();
649 LADSPA_PortDescriptor
*port_descriptors
;
650 LADSPA_PortRangeHint
*port_range_hints
;
652 ladspa_desc
= new LADSPA_Descriptor
; assert(ladspa_desc
);
653 ladspa_desc
->UniqueID
= JucePlugin_VSTUniqueID
; // not used by dssi hosts anyway..
654 ladspa_desc
->Label
= "Main"; // must not contain white spaces
655 ladspa_desc
->Properties
= LADSPA_PROPERTY_REALTIME
; //LADSPA_PROPERTY_HARD_RT_CAPABLE;
656 ladspa_desc
->Name
= JucePlugin_Name
" DSSI Synth";
657 ladspa_desc
->Maker
= JucePlugin_Manufacturer
;
658 ladspa_desc
->Copyright
= "Copyright (c) " JucePlugin_Manufacturer
" 2010";
659 ladspa_desc
->PortCount
= JucePlugin_MaxNumOutputChannels
+ plugin
->getNumParameters();
662 port_descriptors
= new LADSPA_PortDescriptor
[ladspa_desc
->PortCount
];
663 memset(port_descriptors
, 0, sizeof(LADSPA_PortDescriptor
)*ladspa_desc
->PortCount
);
664 ladspa_desc
->PortDescriptors
= port_descriptors
;
666 port_range_hints
= new LADSPA_PortRangeHint
[ladspa_desc
->PortCount
];
667 memset(port_range_hints
, 0, sizeof(LADSPA_PortRangeHint
)*ladspa_desc
->PortCount
);
668 ladspa_desc
->PortRangeHints
= port_range_hints
;
670 port_names
= new char *[ladspa_desc
->PortCount
];
671 ladspa_desc
->PortNames
= port_names
;
673 unsigned long port
= 0;
674 for (int channel
=0; channel
< JucePlugin_MaxNumOutputChannels
; ++channel
, ++port
) {
675 char s
[100]; snprintf(s
, 100, "Output%d", channel
+1);
676 port_names
[port
] = strdup(s
);
678 port_descriptors
[port
] = LADSPA_PORT_OUTPUT
|LADSPA_PORT_AUDIO
;
679 port_range_hints
[port
].HintDescriptor
= 0;
681 for (int param
=0; param
< plugin
->getNumParameters(); ++param
, ++port
) {
682 port_names
[port
] = strdup(plugin
->getParameterName(param
).toUTF8());
683 port_descriptors
[port
] = LADSPA_PORT_INPUT
| LADSPA_PORT_CONTROL
;
684 port_range_hints
[port
].HintDescriptor
= LADSPA_HINT_BOUNDED_BELOW
| LADSPA_HINT_BOUNDED_ABOVE
;
685 port_range_hints
[port
].LowerBound
= 0;
686 port_range_hints
[port
].UpperBound
= 1;
688 jassert(port
== ladspa_desc
->PortCount
);
690 ladspa_desc
->activate
= &callbackActivate
;
691 ladspa_desc
->cleanup
= &callbackCleanup
;
692 ladspa_desc
->connect_port
= &callbackConnectPort
;
693 ladspa_desc
->deactivate
= &callbackDeactivate
;
694 ladspa_desc
->instantiate
= &callbackInstantiate
;
695 ladspa_desc
->run
= &callbackRunAsEffect
;
696 ladspa_desc
->run_adding
= NULL
;
697 ladspa_desc
->set_run_adding_gain
= NULL
;
700 dssi_desc
= new DSSI_Descriptor
;
701 dssi_desc
->DSSI_API_Version
= 1;
702 dssi_desc
->LADSPA_Plugin
= ladspa_desc
;
703 dssi_desc
->configure
= &callbackConfigure
;
704 dssi_desc
->get_program
= callbackGetProgram
;
705 dssi_desc
->get_midi_controller_for_port
= NULL
;
706 dssi_desc
->select_program
= callbackSelectProgram
;
707 dssi_desc
->run_synth
= &callbackRun
;
708 dssi_desc
->run_synth_adding
= NULL
;
709 dssi_desc
->run_multiple_synths
= NULL
;
710 dssi_desc
->run_multiple_synths_adding
= NULL
;
716 __attribute__((destructor
)) void dssi_destructor()
718 jassert(activePlugins
.size() == 0);
719 JuceDSSIWrapper::destroyDescriptors();
722 extern "C" __attribute__ ((visibility("default"))) const LADSPA_Descriptor
*ladspa_descriptor(unsigned long index
)
724 return (index
== 0 ? JuceDSSIWrapper::getLadspaDescriptor() : 0);
727 extern "C" __attribute__ ((visibility("default"))) const DSSI_Descriptor
*dssi_descriptor(unsigned long index
)
729 return (index
== 0 ? JuceDSSIWrapper::getDssiDescriptor() : 0);
732 /* ---------- the fake gui process starts below ---------- */
734 struct FakeExternalGUI
: public MessageListener
, public Timer
{
737 String plugin_osc_url
;
738 DssiMinimalOscServer osc_server
;
739 juce::Time time_last_ping
;
741 FakeExternalGUI() { osc_server
.setListener(this); startTimer(1000); }
742 ~FakeExternalGUI() { osc_server
.stopServer(); }
744 // notify the plugin via the host, using the '/configure' callback
745 void show(bool do_show
) {
748 conf
<< osc_server
.getOscUrl() << "|" << window_title
;
750 osc_server
.sendMessageTo(host_osc_url
, "/configure", "guiVisible", conf
);
751 if (!do_show
&& plugin_osc_url
.isNotEmpty())
752 osc_server
.sendMessageTo(plugin_osc_url
, "/internal_gui_hide", "0");
756 MessageManager::getInstance()->stopDispatchLoop();
759 void init(const char *host_osc_url_
, const char *plugin_so_name
,
760 const char *label
, const char *friendlyname
) {
761 (void)plugin_so_name
;
762 host_osc_url
<< host_osc_url_
;
763 window_title
<< label
<< " - " << friendlyname
;
764 osc_server
.startServer();
765 osc_server
.sendMessageTo(host_osc_url
, "/update", osc_server
.getOscUrl() + "dssi");
768 void handleMessage(const Message
&msg
) {
769 const OscAction
*osc
;
770 if ((osc
= dynamic_cast<const OscAction
*>(&msg
))) {
771 if (osc
->msg
== "/dssi/hide") show(false);
772 else if (osc
->msg
== "/dssi/show") show(true);
773 else if (osc
->msg
== "/dssi/quit") quit();
774 else if (osc
->msg
== "/internal_gui_status") {
775 plugin_osc_url
= osc
->arg
;
776 time_last_ping
= juce::Time::getCurrentTime();
777 if (!plugin_osc_url
.isNotEmpty()) quit();
782 void timerCallback() {
783 juce::Time t
= juce::Time::getCurrentTime();
784 if (plugin_osc_url
.isNotEmpty() && (t
-time_last_ping
).inMilliseconds() > 5000) {
785 /* no ping for 5 seconds, the fake gui process kills itself.. */
791 osc_server
.sendMessageTo(host_osc_url
, "/exiting");
792 if (plugin_osc_url
) osc_server
.sendMessageTo(plugin_osc_url
, "/exiting");
796 FakeExternalGUI
*fake
= 0;
798 void handle_sigterm(int) {
799 static int count
= 0;
806 extern "C" __attribute__ ((visibility("default"))) int dssi_gui_main(const char *osc_host_url
, const char *plugin_so_name
,
807 const char *label
, const char *friendlyname
) {
808 initialiseJuce_GUI();
809 signal(SIGTERM
, &handle_sigterm
);
811 fake
= new FakeExternalGUI();
812 fake
->init(osc_host_url
, plugin_so_name
, label
, friendlyname
);
814 MessageManager::getInstance()->runDispatchLoop();