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