1 /*
2 * RemoteZynAddSubFx.cpp - ZynAddSubFx-embedding plugin
3 *
4 * Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
5 *
6 * This file is part of LMMS - https://lmms.io
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program (see COPYING); if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA.
22 *
23 */
24
25 #include <lmmsconfig.h>
26 #ifdef LMMS_BUILD_WIN32
27 #include <winsock2.h>
28 #endif
29
30 #include <queue>
31
32 #define BUILD_REMOTE_PLUGIN_CLIENT
33 #include "Note.h"
34 #include "RemotePlugin.h"
35 #include "RemoteZynAddSubFx.h"
36 #include "LocalZynAddSubFx.h"
37
38 #include "zynaddsubfx/src/Nio/Nio.h"
39 #include "zynaddsubfx/src/UI/MasterUI.h"
40
41 #include <FL/x.H>
42
43
44 class RemoteZynAddSubFx : public RemotePluginClient, public LocalZynAddSubFx
45 {
46 public:
47 #ifdef SYNC_WITH_SHM_FIFO
RemoteZynAddSubFx(int _shm_in,int _shm_out)48 RemoteZynAddSubFx( int _shm_in, int _shm_out ) :
49 RemotePluginClient( _shm_in, _shm_out ),
50 #else
51 RemoteZynAddSubFx( const char * socketPath ) :
52 RemotePluginClient( socketPath ),
53 #endif
54 LocalZynAddSubFx(),
55 m_guiSleepTime( 100 ),
56 m_guiExit( false )
57 {
58 Nio::start();
59
60 setInputCount( 0 );
61 sendMessage( IdInitDone );
62 waitForMessage( IdInitDone );
63
64 pthread_mutex_init( &m_guiMutex, NULL );
65 pthread_create( &m_messageThreadHandle, NULL, messageLoop, this );
66 }
67
~RemoteZynAddSubFx()68 virtual ~RemoteZynAddSubFx()
69 {
70 Nio::stop();
71 }
72
updateSampleRate()73 virtual void updateSampleRate()
74 {
75 LocalZynAddSubFx::setSampleRate( sampleRate() );
76 }
77
updateBufferSize()78 virtual void updateBufferSize()
79 {
80 LocalZynAddSubFx::setBufferSize( bufferSize() );
81 }
82
messageLoop()83 void messageLoop()
84 {
85 message m;
86 while( ( m = receiveMessage() ).id != IdQuit )
87 {
88 pthread_mutex_lock( &m_master->mutex );
89 processMessage( m );
90 pthread_mutex_unlock( &m_master->mutex );
91 }
92 m_guiExit = true;
93 }
94
processMessage(const message & _m)95 virtual bool processMessage( const message & _m )
96 {
97 switch( _m.id )
98 {
99 case IdQuit:
100 break;
101
102 case IdShowUI:
103 case IdHideUI:
104 case IdLoadSettingsFromFile:
105 case IdLoadPresetFile:
106 pthread_mutex_lock( &m_guiMutex );
107 m_guiMessages.push( _m );
108 pthread_mutex_unlock( &m_guiMutex );
109 break;
110
111 case IdSaveSettingsToFile:
112 {
113 LocalZynAddSubFx::saveXML( _m.getString() );
114 sendMessage( IdSaveSettingsToFile );
115 break;
116 }
117
118 case IdZasfPresetDirectory:
119 LocalZynAddSubFx::setPresetDir( _m.getString() );
120 break;
121
122 case IdZasfLmmsWorkingDirectory:
123 LocalZynAddSubFx::setLmmsWorkingDir( _m.getString() );
124 break;
125
126 case IdZasfSetPitchWheelBendRange:
127 LocalZynAddSubFx::setPitchWheelBendRange( _m.getInt() );
128 break;
129
130 default:
131 return RemotePluginClient::processMessage( _m );
132 }
133 return true;
134 }
135
136 // all functions are called while m_master->mutex is held
processMidiEvent(const MidiEvent & event,const f_cnt_t)137 virtual void processMidiEvent( const MidiEvent& event, const f_cnt_t /* _offset */ )
138 {
139 LocalZynAddSubFx::processMidiEvent( event );
140 }
141
142
process(const sampleFrame * _in,sampleFrame * _out)143 virtual void process( const sampleFrame * _in, sampleFrame * _out )
144 {
145 LocalZynAddSubFx::processAudio( _out );
146 }
147
messageLoop(void * _arg)148 static void * messageLoop( void * _arg )
149 {
150 RemoteZynAddSubFx * _this =
151 static_cast<RemoteZynAddSubFx *>( _arg );
152
153 _this->messageLoop();
154
155 return NULL;
156 }
157
158 void guiLoop();
159
160 private:
161 const int m_guiSleepTime;
162
163 pthread_t m_messageThreadHandle;
164 pthread_mutex_t m_guiMutex;
165 std::queue<RemotePluginClient::message> m_guiMessages;
166 bool m_guiExit;
167
168 } ;
169
170
171
172
guiLoop()173 void RemoteZynAddSubFx::guiLoop()
174 {
175 int exitProgram = 0;
176 MasterUI * ui = NULL;
177
178 while( !m_guiExit )
179 {
180 if( ui )
181 {
182 Fl::wait( m_guiSleepTime / 1000.0 );
183 }
184 else
185 {
186 #ifdef LMMS_BUILD_WIN32
187 Sleep( m_guiSleepTime );
188 #else
189 usleep( m_guiSleepTime*1000 );
190 #endif
191 }
192 if( exitProgram == 1 )
193 {
194 pthread_mutex_lock( &m_master->mutex );
195 sendMessage( IdHideUI );
196 exitProgram = 0;
197 pthread_mutex_unlock( &m_master->mutex );
198 }
199 pthread_mutex_lock( &m_guiMutex );
200 while( m_guiMessages.size() )
201 {
202 RemotePluginClient::message m = m_guiMessages.front();
203 m_guiMessages.pop();
204 switch( m.id )
205 {
206 case IdShowUI:
207 // we only create GUI
208 if( !ui )
209 {
210 Fl::scheme( "plastic" );
211 ui = new MasterUI( m_master, &exitProgram );
212 }
213 ui->showUI();
214 ui->refresh_master_ui();
215 break;
216
217 case IdLoadSettingsFromFile:
218 {
219 LocalZynAddSubFx::loadXML( m.getString() );
220 if( ui )
221 {
222 ui->refresh_master_ui();
223 }
224 pthread_mutex_lock( &m_master->mutex );
225 sendMessage( IdLoadSettingsFromFile );
226 pthread_mutex_unlock( &m_master->mutex );
227 break;
228 }
229
230 case IdLoadPresetFile:
231 {
232 LocalZynAddSubFx::loadPreset( m.getString(), ui ?
233 ui->npartcounter->value()-1 : 0 );
234 if( ui )
235 {
236 ui->npartcounter->do_callback();
237 ui->updatepanel();
238 ui->refresh_master_ui();
239 }
240 pthread_mutex_lock( &m_master->mutex );
241 sendMessage( IdLoadPresetFile );
242 pthread_mutex_unlock( &m_master->mutex );
243 break;
244 }
245
246 default:
247 break;
248 }
249 }
250 pthread_mutex_unlock( &m_guiMutex );
251 }
252 Fl::flush();
253
254 delete ui;
255 }
256
257
258
259
main(int _argc,char ** _argv)260 int main( int _argc, char * * _argv )
261 {
262 #ifdef SYNC_WITH_SHM_FIFO
263 if( _argc < 3 )
264 #else
265 if( _argc < 2 )
266 #endif
267 {
268 fprintf( stderr, "not enough arguments\n" );
269 return -1;
270 }
271
272 #ifdef LMMS_BUILD_WIN32
273 #ifndef __WINPTHREADS_VERSION
274 // (non-portable) initialization of statically linked pthread library
275 pthread_win32_process_attach_np();
276 pthread_win32_thread_attach_np();
277 #endif
278 #endif
279
280
281 #ifdef SYNC_WITH_SHM_FIFO
282 RemoteZynAddSubFx * remoteZASF =
283 new RemoteZynAddSubFx( atoi( _argv[1] ), atoi( _argv[2] ) );
284 #else
285 RemoteZynAddSubFx * remoteZASF = new RemoteZynAddSubFx( _argv[1] );
286 #endif
287
288 remoteZASF->guiLoop();
289
290 delete remoteZASF;
291
292
293 #ifdef LMMS_BUILD_WIN32
294 #ifndef __WINPTHREADS_VERSION
295 pthread_win32_thread_detach_np();
296 pthread_win32_process_detach_np();
297 #endif
298 #endif
299
300 return 0;
301 }
302
303
304 #ifdef NTK_GUI
305 static Fl_Tiled_Image *module_backdrop;
306 #endif
307
set_module_parameters(Fl_Widget * o)308 void set_module_parameters ( Fl_Widget *o )
309 {
310 #ifdef NTK_GUI
311 o->box( FL_DOWN_FRAME );
312 o->align( o->align() | FL_ALIGN_IMAGE_BACKDROP );
313 o->color( FL_BLACK );
314 o->image( module_backdrop );
315 o->labeltype( FL_SHADOW_LABEL );
316 #else
317 o->box( FL_PLASTIC_UP_BOX );
318 o->color( FL_CYAN );
319 o->labeltype( FL_EMBOSSED_LABEL );
320 #endif
321 }
322
323