1 /*
2 * Copyright (C) 2002 - David W. Durham
3 *
4 * This file is part of ReZound, an audio editing application.
5 *
6 * ReZound is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License,
9 * or (at your option) any later version.
10 *
11 * ReZound is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #include "settings.h"
22
23 #include <stddef.h>
24 #include <stdlib.h> // for getenv
25
26 #include <istring>
27
28 CNestedDataFile *gSettingsRegistry=NULL;
29
30 CNestedDataFile *gUserMacroStore=NULL;
31
32 CNestedDataFile *gKeyBindingsStore=NULL;
33 const CNestedDataFile *gDefaultKeyBindingsStore=NULL;
34
35
36 string gPromptDialogDirectory="";
37
38
39 string gUserDataDirectory="";
40 string gSysDataDirectory="";
41
encodeFilenamePresetParameter(const string _filename)42 const string encodeFilenamePresetParameter(const string _filename)
43 {
44 string filename=_filename;
45 if(gSysDataDirectory!="" && filename.find(gSysDataDirectory+"/")==0)
46 filename.replace(0,gSysDataDirectory.size(),"$share");
47 return filename;
48 }
49
decodeFilenamePresetParameter(const string _filename)50 const string decodeFilenamePresetParameter(const string _filename)
51 {
52 string filename=_filename;
53 if(gSysDataDirectory!="" && filename.find("$share/")==0)
54 filename.replace(0,6,gSysDataDirectory);
55 return filename;
56 }
57
58
59 string gUserPresetsFilename="";
60 CNestedDataFile *gUserPresetsFile=NULL;
61
62 string gSysPresetsFilename="";
63 CNestedDataFile *gSysPresetsFile=NULL;
64
65
66 string gDefaultAudioMethod="";
67
68 unsigned gDesiredOutputSampleRate=44100;
69 unsigned gDesiredOutputChannelCount=2;
70 int gDesiredOutputBufferCount=2;
71 unsigned gDesiredOutputBufferSize=2048; // in frames (must be a power of 2)
72
73
74 #ifdef ENABLE_OSS
75 string gOSSOutputDevice="/dev/dsp";
76 string gOSSInputDevice="/dev/dsp";
77 #endif
78 #ifdef ENABLE_ALSA
79 string gALSAOutputDevice="hw:0";
80 string gALSAInputDevice="hw:0";
81 #endif
82 #ifdef ENABLE_PORTAUDIO
83 int gPortAudioOutputDevice=0;
84 int gPortAudioInputDevice=0;
85 #endif
86 #ifdef ENABLE_JACK
87 string gJACKOutputPortNames[64];
88 string gJACKInputPortNames[64];
89 #endif
90
91
92 string gLADSPAPath="";
93
94
95 string gFallbackWorkDir="/tmp"; // ??? would be something else on non-unix platforms
96 string gPrimaryWorkDir="";
97
98
99 string gClipboardDir="/tmp"; // ??? would be something else on non-unix platforms
100 string gClipboardFilenamePrefix="rezclip";
101 size_t gWhichClipboard=0;
102
103
104 size_t gMaxReopenHistory=16;
105
106
107 float gSkipMiddleMarginSeconds=2.0;
108 float gLoopGapLengthSeconds=0.75;
109
110 float gPlayPositionShift=-0.08; // a guess at latency between hearing and where it would place the cue
111
112 string gAddCueWhilePlaying_CueName="";
113 bool gAddCueWhilePlaying_Anchored=false;
114
115 string gAddCueAtClick_CueName="";
116 bool gAddCueAtClick_Anchored=false;
117
118
119 unsigned gMeterUpdateTime=50;
120
121 bool gLevelMetersEnabled=true;
122 unsigned gMeterRMSWindowTime=200;
123 unsigned gMaxPeakFallDelayTime=500;
124 double gMaxPeakFallRate=0.02;
125
126 bool gStereoPhaseMetersEnabled=true;
127 unsigned gStereoPhaseMeterPointCount=100;
128 bool gStereoPhaseMeterUnrotate=true;
129
130 bool gFrequencyAnalyzerEnabled=true;
131 unsigned gAnalyzerPeakFallDelayTime=400;
132 double gAnalyzerPeakFallRate=0.025;
133
134
135 CrossfadeEdgesTypes gCrossfadeEdges=cetInner;
136 float gCrossfadeStartTime=10.0; // default 20ms crossfade time
137 float gCrossfadeStopTime=10.0;
138 CrossfadeFadeMethods gCrossfadeFadeMethod=cfmLinear;
139
140
141
142 map<string,AActionFactory *> gRegisteredActionFactories;
143
144 // ----------------------------------------------------------------------------
145
146 #include "AStatusComm.h"
147 #include "AFrontendHooks.h"
148 #include "CSound_defs.h"
149
150 #include <stdio.h>
151
152 #include <stdexcept>
153
154 #include <CPath.h>
155 #include <CNestedDataFile/CNestedDataFile.h>
156
157 /* read backend setting variables with the exception of gUserDataDir */
readBackendSettings()158 void readBackendSettings()
159 {
160 // determine where the share data is located
161 {
162 // first try env var
163 const char *rezShareEnvVar=getenv("REZ_SHARE_DIR");
164 if(rezShareEnvVar!=NULL && CPath(rezShareEnvVar).exists())
165 {
166 printf("using environment variable $REZ_SHARE_DIR='%s' to override normal setting for share data direcory\n",rezShareEnvVar);
167 gSysDataDirectory=rezShareEnvVar;
168 }
169 // next try the source directory where the code was built
170 else if(CPath(SOURCE_DIR"/share").exists())
171 gSysDataDirectory=SOURCE_DIR"/share";
172 // next try the registry setting
173 else if(gSettingsRegistry->keyExists("shareDirectory") && CPath(gSettingsRegistry->getValue<string>("shareDirectory")).exists())
174 gSysDataDirectory=gSettingsRegistry->getValue<string>("shareDirectory");
175 // finally fall back on the #define set by configure saying where ReZound will be installed
176 else
177 gSysDataDirectory=DATA_DIR"/rezound";
178
179 recheckShareDataDir:
180
181 string checkFile=gSysDataDirectory+istring(CPath::dirDelim)+"presets.dat";
182
183 // now, if the presets.dat file doesn't exist in the share data dir, ask for a setting
184 if(!CPath(checkFile).exists())
185 {
186 if(Question("presets.dat not found in share data dir, '"+gSysDataDirectory+"'.\n Would you like to manually select the share data directory directory?",yesnoQues)==yesAns)
187 {
188 gFrontendHooks->promptForDirectory(gSysDataDirectory,"Select Share Data Directory");
189 goto recheckShareDataDir;
190 }
191 }
192
193 // fully qualify the share data directory
194 gSysDataDirectory=CPath(gSysDataDirectory).realPath();
195
196 printf("using path '%s' for share data directory\n",gSysDataDirectory.c_str());
197 }
198
199
200 // parse the system presets
201 gSysPresetsFilename=gSysDataDirectory+istring(CPath::dirDelim)+"presets.dat";
202 gSysPresetsFile=new CNestedDataFile("",false);
203 try
204 {
205 gSysPresetsFile->parseFile(gSysPresetsFilename);
206 }
207 catch(exception &e)
208 {
209 Error(e.what());
210 }
211
212
213 // parse the user presets
214 gUserPresetsFilename=gUserDataDirectory+istring(CPath::dirDelim)+"presets.dat";
215 CPath(gUserPresetsFilename).touch();
216 gUserPresetsFile=new CNestedDataFile("",false);
217 try
218 {
219 gUserPresetsFile->parseFile(gUserPresetsFilename);
220 }
221 catch(exception &e)
222 {
223 Error(e.what());
224 }
225
226 GET_SETTING("promptDialogDirectory",gPromptDialogDirectory,string)
227
228
229 GET_SETTING("DesiredOutputSampleRate",gDesiredOutputSampleRate,unsigned)
230 GET_SETTING("DesiredOutputChannelCount",gDesiredOutputChannelCount,unsigned)
231 GET_SETTING("DesiredOutputBufferCount",gDesiredOutputBufferCount,int)
232 gDesiredOutputBufferCount=max(2,gDesiredOutputBufferCount);
233 GET_SETTING("DesiredOutputBufferSize",gDesiredOutputBufferSize,unsigned)
234 if(gDesiredOutputBufferSize<256 || (gDesiredOutputBufferSize & (gDesiredOutputBufferSize-1)))
235 throw runtime_error(string(__func__)+" -- DesiredOutputBufferSize in "+gSettingsRegistry->getFilename()+" must be a power of 2 and >= than 256");
236
237
238 #ifdef ENABLE_OSS
239 GET_SETTING("OSSOutputDevice",gOSSOutputDevice,string)
240 GET_SETTING("OSSInputDevice",gOSSInputDevice,string)
241 #endif
242
243 #ifdef ENABLE_ALSA
244 GET_SETTING("ALSAOutputDevice",gALSAOutputDevice,string)
245 GET_SETTING("ALSAInputDevice",gALSAInputDevice,string)
246 #endif
247
248 #ifdef ENABLE_PORTAUDIO
249 GET_SETTING("PortAudioOutputDevice",gPortAudioOutputDevice,int)
250 GET_SETTING("PortAudioInputDevice",gPortAudioInputDevice,int)
251 #endif
252
253 #ifdef ENABLE_JACK
254 // ??? could do these with vector values I suppose
255 for(unsigned t=0;t<MAX_CHANNELS;t++)
256 {
257 GET_SETTING("JACKOutputPortName"+istring(t+1),gJACKOutputPortNames[t],string)
258 else
259 break;
260 }
261
262 for(unsigned t=0;t<MAX_CHANNELS;t++)
263 {
264 GET_SETTING("JACKInputPortName"+istring(t+1),gJACKInputPortNames[t],string)
265 else
266 break;
267 }
268 #endif
269
270 GET_SETTING("LADSPA_PATH",gLADSPAPath,string)
271 if(gLADSPAPath=="")
272 {
273 if(getenv("LADSPA_PATH")==NULL)
274 {
275 fprintf(stderr,"Notice: You do not have a LADSPA_PATH environment variable set. Defaulting to \"/usr/local/lib/ladspa:/usr/lib/ladspa\"\n");
276 gLADSPAPath="/usr/local/lib/ladspa:/usr/lib/ladspa";
277 }
278 else
279 gLADSPAPath=mnn(getenv("LADSPA_PATH"));
280 }
281
282 // where ReZound should fallback to put working files if it can't write to where it loaded a file from
283 // ??? This could be a vector where it would try multiple locations finding one that isn't full or close to full relative to the loaded file size
284 GET_SETTING("primaryWorkDir",gPrimaryWorkDir,string)
285 GET_SETTING("fallbackWorkDir",gFallbackWorkDir,string)
286
287 GET_SETTING("clipboardDir",gClipboardDir,string)
288
289 GET_SETTING("clipboardFilenamePrefix",gClipboardFilenamePrefix,string)
290
291 GET_SETTING("whichClipboard",gWhichClipboard,size_t)
292
293 GET_SETTING("ReopenHistory" DOT "maxReopenHistory",gMaxReopenHistory,size_t)
294
295 GET_SETTING("skipMiddleMarginSeconds",gSkipMiddleMarginSeconds,float)
296
297 GET_SETTING("loopGapLengthSeconds",gLoopGapLengthSeconds,float)
298
299 GET_SETTING("playPositionShift",gPlayPositionShift,float)
300
301 GET_SETTING("addCueWhilePlaying_CueName",gAddCueWhilePlaying_CueName,string)
302 GET_SETTING("addCueWhilePlaying_Anchored",gAddCueWhilePlaying_Anchored,bool)
303
304 GET_SETTING("addCueAtClick_CueName",gAddCueAtClick_CueName,string)
305 GET_SETTING("addCueAtClick_Anchored",gAddCueAtClick_Anchored,bool)
306
307 GET_SETTING("Meters" DOT "meterUpdateTime",gMeterUpdateTime,unsigned)
308
309 GET_SETTING("Meters" DOT "Level" DOT "enabled",gLevelMetersEnabled,bool)
310 GET_SETTING("Meters" DOT "Level" DOT "RMSWindowTime",gMeterRMSWindowTime,unsigned)
311 GET_SETTING("Meters" DOT "Level" DOT "maxPeakFallDelayTime",gMaxPeakFallDelayTime,unsigned)
312 GET_SETTING("Meters" DOT "Level" DOT "maxPeakFallRate",gMaxPeakFallRate,double)
313
314 GET_SETTING("Meters" DOT "StereoPhase" DOT "enabled",gStereoPhaseMetersEnabled,bool)
315 GET_SETTING("Meters" DOT "StereoPhase" DOT "pointCount",gStereoPhaseMeterPointCount,unsigned)
316 GET_SETTING("Meters" DOT "StereoPhase" DOT "unrotate",gStereoPhaseMeterUnrotate,bool)
317
318 GET_SETTING("Meters" DOT "Analyzer" DOT "enabled",gFrequencyAnalyzerEnabled,bool)
319 GET_SETTING("Meters" DOT "Analyzer" DOT "peakFallDelayTime",gAnalyzerPeakFallDelayTime,unsigned)
320 GET_SETTING("Meters" DOT "Analyzer" DOT "peakFallRate",gAnalyzerPeakFallRate,double)
321
322
323 if(gSettingsRegistry->keyExists("crossfadeEdges"))
324 {
325 gCrossfadeEdges= (CrossfadeEdgesTypes)gSettingsRegistry->getValue<int>("crossfadeEdges");
326 gCrossfadeStartTime= gSettingsRegistry->getValue<float>("crossfadeStartTime");
327 gCrossfadeStopTime= gSettingsRegistry->getValue<float>("crossfadeStopTime");
328 gCrossfadeFadeMethod= (CrossfadeFadeMethods)gSettingsRegistry->getValue<int>("crossfadeFadeMethod");
329 }
330 }
331
writeBackendSettings()332 void writeBackendSettings()
333 {
334 gSettingsRegistry->setValue<string>("shareDirectory",gSysDataDirectory);
335 gSettingsRegistry->setValue<string>("promptDialogDirectory",gPromptDialogDirectory);
336
337
338 gSettingsRegistry->setValue<unsigned>("DesiredOutputSampleRate",gDesiredOutputSampleRate);
339 gSettingsRegistry->setValue<unsigned>("DesiredOutputChannelCount",gDesiredOutputChannelCount);
340 gSettingsRegistry->setValue<int>("DesiredOutputBufferCount",gDesiredOutputBufferCount);
341 gSettingsRegistry->setValue<unsigned>("DesiredOutputBufferSize",gDesiredOutputBufferSize);
342
343
344 #ifdef ENABLE_OSS
345 gSettingsRegistry->setValue<string>("OSSOutputDevice",gOSSOutputDevice);
346 gSettingsRegistry->setValue<string>("OSSInputDevice",gOSSInputDevice);
347 #endif
348
349 #ifdef ENABLE_PORTAUDIO
350 gSettingsRegistry->setValue<int>("PortAudioOutputDevice",gPortAudioOutputDevice);
351 gSettingsRegistry->setValue<int>("PortAudioInputDevice",gPortAudioInputDevice);
352 #endif
353
354 #ifdef ENABLE_JACK
355 // ??? could do these with vector<string> values I suppose
356 for(unsigned t=0;t<MAX_CHANNELS;t++)
357 {
358 if(gJACKOutputPortNames[t]!="")
359 gSettingsRegistry->setValue<string>("JACKOutputPortName"+istring(t+1),gJACKOutputPortNames[t]);
360 else
361 {
362 gSettingsRegistry->removeKey("JACKOutputPortName"+istring(t+2));
363 break;
364 }
365 }
366 for(unsigned t=0;t<MAX_CHANNELS;t++)
367 {
368 if(gJACKInputPortNames[t]!="")
369 gSettingsRegistry->setValue<string>("JACKInputPortName"+istring(t+1),gJACKInputPortNames[t]);
370 else
371 {
372 gSettingsRegistry->removeKey("JACKInputPortName"+istring(t+2));
373 break;
374 }
375 }
376 #endif
377
378 gSettingsRegistry->setValue<string>("LADSPA_PATH",gLADSPAPath);
379
380 gSettingsRegistry->setValue<string>("primaryWorkDir",gPrimaryWorkDir);
381 gSettingsRegistry->setValue<string>("fallbackWorkDir",gFallbackWorkDir);
382
383 gSettingsRegistry->setValue<string>("clipboardDir",gClipboardDir);
384 gSettingsRegistry->setValue<string>("clipboardFilenamePrefix",gClipboardFilenamePrefix);
385 gSettingsRegistry->setValue<size_t>("whichClipboard",gWhichClipboard);
386
387 gSettingsRegistry->setValue<size_t>("ReopenHistory" DOT "maxReopenHistory",gMaxReopenHistory);
388
389 gSettingsRegistry->setValue<float>("skipMiddleMarginSeconds",gSkipMiddleMarginSeconds);
390 gSettingsRegistry->setValue<float>("loopGapLengthSeconds",gLoopGapLengthSeconds);
391
392 gSettingsRegistry->setValue<float>("playPositionShift",gPlayPositionShift);
393
394 gSettingsRegistry->setValue<string>("addCueWhilePlaying_CueName",gAddCueWhilePlaying_CueName);
395 gSettingsRegistry->setValue<bool>("addCueWhilePlaying_Anchored",gAddCueWhilePlaying_Anchored);
396
397 gSettingsRegistry->setValue<string>("addCueAtClick_CueName",gAddCueAtClick_CueName);
398 gSettingsRegistry->setValue<bool>("addCueAtClick_Anchored",gAddCueAtClick_Anchored);
399
400 gSettingsRegistry->setValue<unsigned>("Meters" DOT "meterUpdateTime",gMeterUpdateTime);
401
402 gSettingsRegistry->setValue<bool>("Meters" DOT "Level" DOT "enabled",gLevelMetersEnabled);
403 gSettingsRegistry->setValue<unsigned>("Meters" DOT "Level" DOT "RMSWindowTime",gMeterRMSWindowTime);
404 gSettingsRegistry->setValue<unsigned>("Meters" DOT "Level" DOT "maxPeakFallDelayTime",gMaxPeakFallDelayTime);
405 gSettingsRegistry->setValue<double>("Meters" DOT "Level" DOT "maxPeakFallRate",gMaxPeakFallRate);
406
407 gSettingsRegistry->setValue<bool>("Meters" DOT "StereoPhase" DOT "enabled",gStereoPhaseMetersEnabled);
408 gSettingsRegistry->setValue<unsigned>("Meters" DOT "StereoPhase" DOT "pointCount",gStereoPhaseMeterPointCount);
409 gSettingsRegistry->setValue<bool>("Meters" DOT "StereoPhase" DOT "unrotate",gStereoPhaseMeterUnrotate);
410
411 gSettingsRegistry->setValue<bool>("Meters" DOT "Analyzer" DOT "enabled",gFrequencyAnalyzerEnabled);
412 gSettingsRegistry->setValue<unsigned>("Meters" DOT "Analyzer" DOT "peakFallDelayTime",gAnalyzerPeakFallDelayTime);
413 gSettingsRegistry->setValue<double>("Meters" DOT "Analyzer" DOT "peakFallRate",gAnalyzerPeakFallRate);
414
415 gSettingsRegistry->setValue<int>("crossfadeEdges",(int)gCrossfadeEdges);
416 gSettingsRegistry->setValue<float>("crossfadeStartTime",gCrossfadeStartTime);
417 gSettingsRegistry->setValue<float>("crossfadeStopTime",gCrossfadeStopTime);
418 gSettingsRegistry->setValue<int>("crossfadeFadeMethod",(int)gCrossfadeFadeMethod);
419 }
420
421