1 /*
2 * LocalZynAddSubFx.cpp - local implementation of ZynAddSubFx plugin
3 *
4 * Copyright (c) 2009-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
27 #include "zynaddsubfx/src/Misc/Util.h"
28 #include <unistd.h>
29 #include <ctime>
30
31 #include "LocalZynAddSubFx.h"
32
33 #include "zynaddsubfx/src/Nio/NulEngine.h"
34 #include "zynaddsubfx/src/Misc/Master.h"
35 #include "zynaddsubfx/src/Misc/Part.h"
36 #include "zynaddsubfx/src/Misc/Dump.h"
37
38
39 SYNTH_T* synth = NULL;
40
41 int LocalZynAddSubFx::s_instanceCount = 0;
42
43
LocalZynAddSubFx()44 LocalZynAddSubFx::LocalZynAddSubFx() :
45 m_master( NULL ),
46 m_ioEngine( NULL )
47 {
48 for( int i = 0; i < NumKeys; ++i )
49 {
50 m_runningNotes[i] = 0;
51 }
52
53 if( s_instanceCount == 0 )
54 {
55 #ifdef LMMS_BUILD_WIN32
56 #ifndef __WINPTHREADS_VERSION
57 // (non-portable) initialization of statically linked pthread library
58 pthread_win32_process_attach_np();
59 pthread_win32_thread_attach_np();
60 #endif
61 #endif
62
63 initConfig();
64
65 synth = new SYNTH_T;
66 synth->oscilsize = config.cfg.OscilSize;
67 synth->alias();
68
69 srand( time( NULL ) );
70
71 denormalkillbuf = new float[synth->buffersize];
72 for( int i = 0; i < synth->buffersize; ++i )
73 {
74 denormalkillbuf[i] = (RND-0.5)*1e-16;
75 }
76 }
77
78 ++s_instanceCount;
79
80 m_ioEngine = new NulEngine;
81
82 m_master = new Master();
83 m_master->swaplr = 0;
84 }
85
86
87
88
~LocalZynAddSubFx()89 LocalZynAddSubFx::~LocalZynAddSubFx()
90 {
91 delete m_master;
92 delete m_ioEngine;
93
94 if( --s_instanceCount == 0 )
95 {
96 delete[] denormalkillbuf;
97 }
98 }
99
100
101
102
initConfig()103 void LocalZynAddSubFx::initConfig()
104 {
105 config.init();
106
107 config.cfg.GzipCompression = 0;
108 }
109
110
111
112
setSampleRate(int sampleRate)113 void LocalZynAddSubFx::setSampleRate( int sampleRate )
114 {
115 synth->samplerate = sampleRate;
116 synth->alias();
117 }
118
119
120
121
setBufferSize(int bufferSize)122 void LocalZynAddSubFx::setBufferSize( int bufferSize )
123 {
124 synth->buffersize = bufferSize;
125 synth->alias();
126 }
127
128
129
130
saveXML(const std::string & _filename)131 void LocalZynAddSubFx::saveXML( const std::string & _filename )
132 {
133 char * name = strdup( _filename.c_str() );
134 m_master->saveXML( name );
135 free( name );
136 }
137
138
139
140
loadXML(const std::string & _filename)141 void LocalZynAddSubFx::loadXML( const std::string & _filename )
142 {
143 char * f = strdup( _filename.c_str() );
144
145 pthread_mutex_lock( &m_master->mutex );
146 m_master->defaults();
147 m_master->loadXML( f );
148 pthread_mutex_unlock( &m_master->mutex );
149
150 m_master->applyparameters();
151
152 unlink( f );
153 free( f );
154 }
155
156
157
158
loadPreset(const std::string & _filename,int _part)159 void LocalZynAddSubFx::loadPreset( const std::string & _filename, int _part )
160 {
161 char * f = strdup( _filename.c_str() );
162
163 pthread_mutex_lock( &m_master->mutex );
164 m_master->part[_part]->defaultsinstrument();
165 m_master->part[_part]->loadXMLinstrument( f );
166 pthread_mutex_unlock( &m_master->mutex );
167
168 m_master->applyparameters();
169
170 free( f );
171 }
172
173
174
175
setPresetDir(const std::string & _dir)176 void LocalZynAddSubFx::setPresetDir( const std::string & _dir )
177 {
178 m_presetsDir = _dir;
179 for( int i = 0; i < MAX_BANK_ROOT_DIRS; ++i )
180 {
181 if( config.cfg.bankRootDirList[i].empty() )
182 {
183 config.cfg.bankRootDirList[i] = m_presetsDir;
184 break;
185 }
186 else if( config.cfg.bankRootDirList[i] == m_presetsDir )
187 {
188 break;
189 }
190 }
191 }
192
193
194
195
setLmmsWorkingDir(const std::string & _dir)196 void LocalZynAddSubFx::setLmmsWorkingDir( const std::string & _dir )
197 {
198 if( config.workingDir != NULL )
199 {
200 free( config.workingDir );
201 }
202 config.workingDir = strdup( _dir.c_str() );
203
204 initConfig();
205 }
206
207
208
setPitchWheelBendRange(int semitones)209 void LocalZynAddSubFx::setPitchWheelBendRange( int semitones )
210 {
211 for( int i = 0; i < NUM_MIDI_PARTS; ++i )
212 {
213 m_master->part[i]->ctl.setpitchwheelbendrange( semitones * 100 );
214 }
215 }
216
217
218
processMidiEvent(const MidiEvent & event)219 void LocalZynAddSubFx::processMidiEvent( const MidiEvent& event )
220 {
221 switch( event.type() )
222 {
223 case MidiNoteOn:
224 if( event.velocity() > 0 )
225 {
226 if( event.key() < 0 || event.key() > MidiMaxKey )
227 {
228 break;
229 }
230 if( m_runningNotes[event.key()] > 0 )
231 {
232 m_master->noteOff( event.channel(), event.key() );
233 }
234 ++m_runningNotes[event.key()];
235 m_master->noteOn( event.channel(), event.key(), event.velocity() );
236 break;
237 }
238 case MidiNoteOff:
239 if( event.key() < 0 || event.key() > MidiMaxKey )
240 {
241 break;
242 }
243 if( --m_runningNotes[event.key()] <= 0 )
244 {
245 m_master->noteOff( event.channel(), event.key() );
246 }
247 break;
248 case MidiPitchBend:
249 m_master->setController( event.channel(), C_pitchwheel, event.pitchBend()-8192 );
250 break;
251 case MidiControlChange:
252 m_master->setController( event.channel(), event.controllerNumber(), event.controllerValue() );
253 break;
254 default:
255 break;
256 }
257 }
258
259
260
261
processAudio(sampleFrame * _out)262 void LocalZynAddSubFx::processAudio( sampleFrame * _out )
263 {
264 float outputl[synth->buffersize];
265 float outputr[synth->buffersize];
266
267 m_master->GetAudioOutSamples( synth->buffersize, synth->samplerate, outputl, outputr );
268
269 // TODO: move to MixHelpers
270 for( int f = 0; f < synth->buffersize; ++f )
271 {
272 _out[f][0] = outputl[f];
273 _out[f][1] = outputr[f];
274 }
275 }
276
277
278