1 /*
2 ** configuration.cpp
3 ** Handle zmusic's configuration.
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 2019 Christoph Oelckers
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34
35 #ifdef _WIN32
36 #include <Windows.h>
37 #include <mmsystem.h>
38 #endif
39 #include <algorithm>
40 #include "critsec.h"
41 #include "dumb.h"
42
43 #include "zmusic_internal.h"
44 #include "musinfo.h"
45 #include "midiconfig.h"
46 #include "mididevices/music_alsa_state.h"
47
48 #ifdef HAVE_TIMIDITY
49 #include "timidity/timidity.h"
50 #include "timiditypp/timidity.h"
51 #endif
52 #ifdef HAVE_OPL
53 #include "oplsynth/oplio.h"
54 #endif
55
56 struct Dummy
57 {
ChangeSettingIntDummy58 void ChangeSettingInt(const char*, int) {}
ChangeSettingNumDummy59 void ChangeSettingNum(const char*, double) {}
ChangeSettingStringDummy60 void ChangeSettingString(const char*, const char*) {}
61 };
62
63 #define devType() ((currSong)? (currSong)->GetDeviceType() : MDEV_DEFAULT)
64
65
66 MiscConfig miscConfig;
67 ZMusicCallbacks musicCallbacks;
68
69 class SoundFontWrapperInterface : public MusicIO::SoundFontReaderInterface
70 {
71 void* handle;
72
73 public:
SoundFontWrapperInterface(void * h)74 SoundFontWrapperInterface(void* h)
75 {
76 handle = h;
77 }
78
open_file(const char * fn)79 struct MusicIO::FileInterface* open_file(const char* fn) override
80 {
81 auto rd = musicCallbacks.SF_OpenFile(handle, fn);
82 if (rd)
83 {
84 auto fr = new CustomFileReader(rd);
85 if (fr) fr->filename = fn? fn : "timidity.cfg";
86 return fr;
87 }
88 else return nullptr;
89 }
add_search_path(const char * path)90 void add_search_path(const char* path) override
91 {
92 musicCallbacks.SF_AddToSearchPath(handle, path);
93 }
close()94 void close() override
95 {
96 musicCallbacks.SF_Close(handle);
97 delete this;
98 }
99 };
100
101 namespace MusicIO {
ClientOpenSoundFont(const char * name,int type)102 SoundFontReaderInterface* ClientOpenSoundFont(const char* name, int type)
103 {
104 if (!musicCallbacks.OpenSoundFont) return nullptr;
105 auto iface = musicCallbacks.OpenSoundFont(name, type);
106 if (!iface) return nullptr;
107 return new SoundFontWrapperInterface(iface);
108 }
109 }
110
111
ZMusic_Print(int type,const char * msg,va_list args)112 void ZMusic_Print(int type, const char* msg, va_list args)
113 {
114 static char printbuf[4096];
115 vsnprintf(printbuf, 4096, msg, args);
116 if (musicCallbacks.MessageFunc)
117 {
118 musicCallbacks.MessageFunc(type, printbuf);
119 }
120 else fputs(printbuf, type >= ZMUSIC_MSG_WARNING ? stderr : stdout);
121 }
122
ZMusic_Printf(int type,const char * msg,...)123 void ZMusic_Printf(int type, const char* msg, ...)
124 {
125 va_list ap;
126 va_start(ap, msg);
127 ZMusic_Print(type, msg, ap);
128 va_end(ap);
129 }
130
ZMusic_SetCallbacks(const ZMusicCallbacks * cb)131 DLL_EXPORT void ZMusic_SetCallbacks(const ZMusicCallbacks* cb)
132 {
133 musicCallbacks = *cb;
134 // If not all these are set the sound font interface is not usable.
135 if (!cb->SF_AddToSearchPath || !cb->SF_OpenFile || !cb->SF_Close)
136 musicCallbacks.OpenSoundFont = nullptr;
137 }
138
ZMusic_SetGenMidi(const uint8_t * data)139 DLL_EXPORT void ZMusic_SetGenMidi(const uint8_t* data)
140 {
141 #ifdef HAVE_OPL
142 memcpy(oplConfig.OPLinstruments, data, 175 * 36);
143 oplConfig.genmidiset = true;
144 #endif
145 }
146
ZMusic_SetWgOpn(const void * data,unsigned len)147 DLL_EXPORT void ZMusic_SetWgOpn(const void* data, unsigned len)
148 {
149 #ifdef HAVE_OPN
150 opnConfig.default_bank.resize(len);
151 memcpy(opnConfig.default_bank.data(), data, len);
152 #endif
153 }
154
ZMusic_SetDmxGus(const void * data,unsigned len)155 DLL_EXPORT void ZMusic_SetDmxGus(const void* data, unsigned len)
156 {
157 #ifdef HAVE_GUS
158 gusConfig.dmxgus.resize(len);
159 memcpy(gusConfig.dmxgus.data(), data, len);
160 #endif
161 }
162
ZMusic_EnumerateMidiDevices()163 int ZMusic_EnumerateMidiDevices()
164 {
165 #ifdef HAVE_SYSTEM_MIDI
166 #ifdef __linux__
167 auto & sequencer = AlsaSequencer::Get();
168 return sequencer.EnumerateDevices();
169 #elif _WIN32
170 // TODO: move the weird stuff from music_midi_base.cpp here, or at least to this lib and call it here
171 return {};
172 #endif
173 #else
174 return {};
175 #endif
176 }
177
178
179 struct MidiDeviceList
180 {
181 std::vector<ZMusicMidiOutDevice> devices;
~MidiDeviceListMidiDeviceList182 ~MidiDeviceList()
183 {
184 for (auto& device : devices)
185 {
186 free(device.Name);
187 }
188 }
BuildMidiDeviceList189 void Build()
190 {
191 #ifdef HAVE_OPN
192 devices.push_back({ strdup("libOPN"), -8, MIDIDEV_FMSYNTH });
193 #endif
194 #ifdef HAVE_ADL
195 devices.push_back({ strdup("libADL"), -7, MIDIDEV_FMSYNTH });
196 #endif
197 #ifdef HAVE_WILDMIDI
198 devices.push_back({ strdup("WildMidi"), -6, MIDIDEV_SWSYNTH });
199 #endif
200 #ifdef HAVE_FLUIDSYNTH
201 devices.push_back({ strdup("FluidSynth"), -5, MIDIDEV_SWSYNTH });
202 #endif
203 #ifdef HAVE_GUS
204 devices.push_back({ strdup("GUS Emulation"), -4, MIDIDEV_SWSYNTH });
205 #endif
206 #ifdef HAVE_OPL
207 devices.push_back({ strdup("OPL Synth Emulation"), -3, MIDIDEV_FMSYNTH });
208 #endif
209 #ifdef HAVE_TIMIDITY
210 devices.push_back({ strdup("TiMidity++"), -2, MIDIDEV_SWSYNTH });
211 #endif
212
213 #ifdef HAVE_SYSTEM_MIDI
214 #ifdef __linux__
215 auto& sequencer = AlsaSequencer::Get();
216 sequencer.EnumerateDevices();
217 auto& dev = sequencer.GetInternalDevices();
218 for (auto& d : dev)
219 {
220 ZMusicMidiOutDevice mdev = { strdup(d.Name.c_str()), d.ID, MIDIDEV_MAPPER }; // fixme: Correctly determine the type of the device.
221 devices.push_back(mdev);
222 }
223 #elif _WIN32
224 UINT nummididevices = midiOutGetNumDevs();
225 for (uint32_t id = 0; id < nummididevices; ++id)
226 {
227 MIDIOUTCAPSW caps;
228 MMRESULT res;
229
230 res = midiOutGetDevCapsW(id, &caps, sizeof(caps));
231 if (res == MMSYSERR_NOERROR)
232 {
233 auto len = wcslen(caps.szPname);
234 int size_needed = WideCharToMultiByte(CP_UTF8, 0, caps.szPname, (int)len, nullptr, 0, nullptr, nullptr);
235 char* outbuf = (char*)malloc(size_needed + 1);
236 WideCharToMultiByte(CP_UTF8, 0, caps.szPname, (int)len, outbuf, size_needed, nullptr, nullptr);
237 outbuf[size_needed] = 0;
238
239 ZMusicMidiOutDevice mdev = { outbuf, int(id), caps.wTechnology };
240 devices.push_back(mdev);
241 }
242 }
243 #endif
244 #endif
245 }
246
247 };
248
249 static MidiDeviceList devlist;
250
ZMusic_GetMidiDevices(int * pAmount)251 DLL_EXPORT const ZMusicMidiOutDevice* ZMusic_GetMidiDevices(int* pAmount)
252 {
253 if (devlist.devices.size() == 0) devlist.Build();
254 if (pAmount) *pAmount = (int)devlist.devices.size();
255 return devlist.devices.data();
256 }
257
258
259
260 template<class valtype>
ChangeAndReturn(valtype & variable,valtype value,valtype * realv)261 void ChangeAndReturn(valtype &variable, valtype value, valtype *realv)
262 {
263 variable = value;
264 if (realv) *realv = value;
265 }
266
267 #define FLUID_CHORUS_MOD_SINE 0
268 #define FLUID_CHORUS_MOD_TRIANGLE 1
269 #define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE
270
271 #ifdef HAVE_TIMIDITY
272
273 //==========================================================================
274 //
275 // Timidity++ uses a static global set of configuration variables.
276 // THese can be changed live while the synth is playing but need synchronization.
277 //
278 // Currently the synth is not reentrant due to this and a handful
279 // of other global variables.
280 //
281 //==========================================================================
282
ChangeVarSync(T & var,T value)283 template<class T> void ChangeVarSync(T& var, T value)
284 {
285 std::lock_guard<FCriticalSection> lock(TimidityPlus::ConfigMutex);
286 var = value;
287 }
288
289 //==========================================================================
290 //
291 // Timidity++ reverb is a bit more complicated because it is two properties in one value.
292 //
293 //==========================================================================
294
295 /*
296 * reverb=0 no reverb 0
297 * reverb=1 old reverb 1
298 * reverb=1,n set reverb level to n (-1 to -127)
299 * reverb=2 "global" old reverb 2
300 * reverb=2,n set reverb level to n (-1 to -127) - 128
301 * reverb=3 new reverb 3
302 * reverb=3,n set reverb level to n (-1 to -127) - 256
303 * reverb=4 "global" new reverb 4
304 * reverb=4,n set reverb level to n (-1 to -127) - 384
305 */
306 static int local_timidity_reverb_level;
307 static int local_timidity_reverb;
308
TimidityPlus_SetReverb()309 static void TimidityPlus_SetReverb()
310 {
311 int value = 0;
312 int mode = local_timidity_reverb;
313 int level = local_timidity_reverb_level;
314
315 if (mode == 0 || level == 0) value = mode;
316 else value = (mode - 1) * -128 - level;
317 ChangeVarSync(TimidityPlus::timidity_reverb, value);
318 }
319 #endif
320
321
322 //==========================================================================
323 //
324 // change an integer value
325 //
326 //==========================================================================
327
ChangeMusicSettingInt(EIntConfigKey key,MusInfo * currSong,int value,int * pRealValue)328 DLL_EXPORT zmusic_bool ChangeMusicSettingInt(EIntConfigKey key, MusInfo *currSong, int value, int *pRealValue)
329 {
330 switch (key)
331 {
332 default:
333 return false;
334
335 #ifdef HAVE_ADL
336 case zmusic_adl_chips_count:
337 ChangeAndReturn(adlConfig.adl_chips_count, value, pRealValue);
338 return devType() == MDEV_ADL;
339
340 case zmusic_adl_emulator_id:
341 ChangeAndReturn(adlConfig.adl_emulator_id, value, pRealValue);
342 return devType() == MDEV_ADL;
343
344 case zmusic_adl_run_at_pcm_rate:
345 ChangeAndReturn(adlConfig.adl_run_at_pcm_rate, value, pRealValue);
346 return devType() == MDEV_ADL;
347
348 case zmusic_adl_fullpan:
349 ChangeAndReturn(adlConfig.adl_fullpan, value, pRealValue);
350 return devType() == MDEV_ADL;
351
352 case zmusic_adl_bank:
353 ChangeAndReturn(adlConfig.adl_bank, value, pRealValue);
354 return devType() == MDEV_ADL;
355
356 case zmusic_adl_use_custom_bank:
357 ChangeAndReturn(adlConfig.adl_use_custom_bank, value, pRealValue);
358 return devType() == MDEV_ADL;
359
360 case zmusic_adl_volume_model:
361 ChangeAndReturn(adlConfig.adl_volume_model, value, pRealValue);
362 return devType() == MDEV_ADL;
363 #endif
364
365 case zmusic_fluid_reverb:
366 if (currSong != NULL)
367 currSong->ChangeSettingInt("fluidsynth.synth.reverb.active", value);
368
369 ChangeAndReturn(fluidConfig.fluid_reverb, value, pRealValue);
370 return false;
371
372 case zmusic_fluid_chorus:
373 if (currSong != NULL)
374 currSong->ChangeSettingInt("fluidsynth.synth.chorus.active", value);
375
376 ChangeAndReturn(fluidConfig.fluid_chorus, value, pRealValue);
377 return false;
378
379 case zmusic_fluid_voices:
380 if (value < 16)
381 value = 16;
382 else if (value > 4096)
383 value = 4096;
384
385 if (currSong != NULL)
386 currSong->ChangeSettingInt("fluidsynth.synth.polyphony", value);
387
388 ChangeAndReturn(fluidConfig.fluid_voices, value, pRealValue);
389 return false;
390
391 case zmusic_fluid_interp:
392 // Values are: 0 = FLUID_INTERP_NONE
393 // 1 = FLUID_INTERP_LINEAR
394 // 4 = FLUID_INTERP_4THORDER (the FluidSynth default)
395 // 7 = FLUID_INTERP_7THORDER
396 // (And here I thought it was just a linear list.)
397 // Round undefined values to the nearest valid one.
398 if (value < 0)
399 value = 0;
400 else if (value == 2)
401 value = 1;
402 else if (value == 3 || value == 5)
403 value = 4;
404 else if (value == 6 || value > 7)
405 value = 7;
406
407 if (currSong != NULL)
408 currSong->ChangeSettingInt("fluidsynth.synth.interpolation", value);
409
410 ChangeAndReturn(fluidConfig.fluid_interp, value, pRealValue);
411 return false;
412
413 case zmusic_fluid_samplerate:
414 // This will only take effect for the next song. (Q: Is this even needed?)
415 ChangeAndReturn(fluidConfig.fluid_samplerate, std::max<int>(value, 0), pRealValue);
416 return false;
417
418 // I don't know if this setting even matters for us, since we aren't letting
419 // FluidSynth drives its own output.
420 case zmusic_fluid_threads:
421 if (value < 1)
422 value = 1;
423 else if (value > 256)
424 value = 256;
425
426 ChangeAndReturn(fluidConfig.fluid_threads, value, pRealValue);
427 return false;
428
429 case zmusic_fluid_chorus_voices:
430 if (value < 0)
431 value = 0;
432 else if (value > 99)
433 value = 99;
434
435 if (currSong != NULL)
436 currSong->ChangeSettingNum("fluidsynth.z.chorus", value);
437
438 ChangeAndReturn(fluidConfig.fluid_chorus_voices, value, pRealValue);
439 return false;
440
441 case zmusic_fluid_chorus_type:
442 if (value != FLUID_CHORUS_MOD_SINE && value != FLUID_CHORUS_MOD_TRIANGLE)
443 value = FLUID_CHORUS_DEFAULT_TYPE;
444
445 if (currSong != NULL)
446 currSong->ChangeSettingNum("fluidsynth.z.chorus", value); // Uses float to simplify the checking code in the renderer.
447
448 ChangeAndReturn(fluidConfig.fluid_chorus_type, value, pRealValue);
449 return false;
450
451 #ifdef HAVE_OPL
452 case zmusic_opl_numchips:
453 if (value <= 0)
454 value = 1;
455 else if (value > MAXOPL2CHIPS)
456 value = MAXOPL2CHIPS;
457
458 if (currSong != NULL)
459 currSong->ChangeSettingInt("opl.numchips", value);
460
461 ChangeAndReturn(oplConfig.numchips, value, pRealValue);
462 return false;
463
464 case zmusic_opl_core:
465 if (value < 0) value = 0;
466 else if (value > 3) value = 3;
467 ChangeAndReturn(oplConfig.core, value, pRealValue);
468 return devType() == MDEV_OPL;
469
470 case zmusic_opl_fullpan:
471 ChangeAndReturn(oplConfig.fullpan, value, pRealValue);
472 return false;
473 #endif
474 #ifdef HAVE_OPN
475 case zmusic_opn_chips_count:
476 ChangeAndReturn(opnConfig.opn_chips_count, value, pRealValue);
477 return devType() == MDEV_OPN;
478
479 case zmusic_opn_emulator_id:
480 ChangeAndReturn(opnConfig.opn_emulator_id, value, pRealValue);
481 return devType() == MDEV_OPN;
482
483 case zmusic_opn_run_at_pcm_rate:
484 ChangeAndReturn(opnConfig.opn_run_at_pcm_rate, value, pRealValue);
485 return devType() == MDEV_OPN;
486
487 case zmusic_opn_fullpan:
488 ChangeAndReturn(opnConfig.opn_fullpan, value, pRealValue);
489 return devType() == MDEV_OPN;
490
491 case zmusic_opn_use_custom_bank:
492 ChangeAndReturn(opnConfig.opn_use_custom_bank, value, pRealValue);
493 return devType() == MDEV_OPN;
494 #endif
495 #ifdef HAVE_GUS
496 case zmusic_gus_dmxgus:
497 ChangeAndReturn(gusConfig.gus_dmxgus, value, pRealValue);
498 return devType() == MDEV_GUS;
499
500 case zmusic_gus_midi_voices:
501 ChangeAndReturn(gusConfig.midi_voices, value, pRealValue);
502 return devType() == MDEV_GUS;
503
504 case zmusic_gus_memsize:
505 ChangeAndReturn(gusConfig.gus_memsize, value, pRealValue);
506 return devType() == MDEV_GUS && gusConfig.gus_dmxgus;
507 #endif
508 #ifdef HAVE_TIMIDITY
509 case zmusic_timidity_modulation_wheel:
510 ChangeVarSync(TimidityPlus::timidity_modulation_wheel, value);
511 if (pRealValue) *pRealValue = value;
512 return false;
513
514 case zmusic_timidity_portamento:
515 ChangeVarSync(TimidityPlus::timidity_portamento, value);
516 if (pRealValue) *pRealValue = value;
517 return false;
518
519 case zmusic_timidity_reverb:
520 if (value < 0 || value > 4) value = 0;
521 else TimidityPlus_SetReverb();
522 local_timidity_reverb = value;
523 if (pRealValue) *pRealValue = value;
524 return false;
525
526 case zmusic_timidity_reverb_level:
527 if (value < 0 || value > 127) value = 0;
528 else TimidityPlus_SetReverb();
529 local_timidity_reverb_level = value;
530 if (pRealValue) *pRealValue = value;
531 return false;
532
533 case zmusic_timidity_chorus:
534 ChangeVarSync(TimidityPlus::timidity_chorus, value);
535 if (pRealValue) *pRealValue = value;
536 return false;
537
538 case zmusic_timidity_surround_chorus:
539 ChangeVarSync(TimidityPlus::timidity_surround_chorus, value);
540 if (pRealValue) *pRealValue = value;
541 return devType() == MDEV_TIMIDITY;
542
543 case zmusic_timidity_channel_pressure:
544 ChangeVarSync(TimidityPlus::timidity_channel_pressure, value);
545 if (pRealValue) *pRealValue = value;
546 return false;
547
548 case zmusic_timidity_lpf_def:
549 ChangeVarSync(TimidityPlus::timidity_lpf_def, value);
550 if (pRealValue) *pRealValue = value;
551 return false;
552
553 case zmusic_timidity_temper_control:
554 ChangeVarSync(TimidityPlus::timidity_temper_control, value);
555 if (pRealValue) *pRealValue = value;
556 return false;
557
558 case zmusic_timidity_modulation_envelope:
559 ChangeVarSync(TimidityPlus::timidity_modulation_envelope, value);
560 if (pRealValue) *pRealValue = value;
561 return devType() == MDEV_TIMIDITY;
562
563 case zmusic_timidity_overlap_voice_allow:
564 ChangeVarSync(TimidityPlus::timidity_overlap_voice_allow, value);
565 if (pRealValue) *pRealValue = value;
566 return false;
567
568 case zmusic_timidity_drum_effect:
569 ChangeVarSync(TimidityPlus::timidity_drum_effect, value);
570 if (pRealValue) *pRealValue = value;
571 return false;
572
573 case zmusic_timidity_pan_delay:
574 ChangeVarSync(TimidityPlus::timidity_pan_delay, value);
575 if (pRealValue) *pRealValue = value;
576 return false;
577
578 case zmusic_timidity_key_adjust:
579 if (value < -24) value = -24;
580 else if (value > 24) value = 24;
581 ChangeVarSync(TimidityPlus::timidity_key_adjust, value);
582 if (pRealValue) *pRealValue = value;
583 return false;
584 #endif
585 #ifdef HAVE_WILDMIDI
586 case zmusic_wildmidi_reverb:
587 if (currSong != NULL)
588 currSong->ChangeSettingInt("wildmidi.reverb", value);
589 wildMidiConfig.reverb = value;
590 if (pRealValue) *pRealValue = value;
591 return false;
592
593 case zmusic_wildmidi_enhanced_resampling:
594 if (currSong != NULL)
595 currSong->ChangeSettingInt("wildmidi.resampling", value);
596 wildMidiConfig.enhanced_resampling = value;
597 if (pRealValue) *pRealValue = value;
598 return false;
599 #endif
600 case zmusic_snd_midiprecache:
601 ChangeAndReturn(miscConfig.snd_midiprecache, value, pRealValue);
602 return false;
603
604 case zmusic_snd_streambuffersize:
605 if (value < 16)
606 {
607 value = 16;
608 }
609 else if (value > 1024)
610 {
611 value = 1024;
612 }
613 ChangeAndReturn(miscConfig.snd_streambuffersize, value, pRealValue);
614 return false;
615
616 case zmusic_mod_samplerate:
617 ChangeAndReturn(dumbConfig.mod_samplerate, value, pRealValue);
618 return false;
619
620 case zmusic_mod_volramp:
621 ChangeAndReturn(dumbConfig.mod_volramp, value, pRealValue);
622 return false;
623
624 case zmusic_mod_interp:
625 ChangeAndReturn(dumbConfig.mod_interp, value, pRealValue);
626 return false;
627
628 case zmusic_mod_autochip:
629 ChangeAndReturn(dumbConfig.mod_autochip, value, pRealValue);
630 return false;
631
632 case zmusic_mod_autochip_size_force:
633 ChangeAndReturn(dumbConfig.mod_autochip_size_force, value, pRealValue);
634 return false;
635
636 case zmusic_mod_autochip_size_scan:
637 ChangeAndReturn(dumbConfig.mod_autochip_size_scan, value, pRealValue);
638 return false;
639
640 case zmusic_mod_autochip_scan_threshold:
641 ChangeAndReturn(dumbConfig.mod_autochip_scan_threshold, value, pRealValue);
642 return false;
643
644 case zmusic_snd_mididevice:
645 {
646 bool change = miscConfig.snd_mididevice != value;
647 miscConfig.snd_mididevice = value;
648 return change;
649 }
650
651 case zmusic_snd_outputrate:
652 miscConfig.snd_outputrate = value;
653 return false;
654
655 }
656 return false;
657 }
658
ChangeMusicSettingFloat(EFloatConfigKey key,MusInfo * currSong,float value,float * pRealValue)659 DLL_EXPORT zmusic_bool ChangeMusicSettingFloat(EFloatConfigKey key, MusInfo* currSong, float value, float *pRealValue)
660 {
661 switch (key)
662 {
663 default:
664 return false;
665
666 case zmusic_fluid_gain:
667 if (value < 0)
668 value = 0;
669 else if (value > 10)
670 value = 10;
671
672 if (currSong != NULL)
673 currSong->ChangeSettingNum("fluidsynth.synth.gain", value);
674
675 ChangeAndReturn(fluidConfig.fluid_gain, value, pRealValue);
676 return false;
677
678 case zmusic_fluid_reverb_roomsize:
679 if (value < 0)
680 value = 0;
681 else if (value > 1.2f)
682 value = 1.2f;
683
684 if (currSong != NULL)
685 currSong->ChangeSettingNum("fluidsynth.z.reverb", value);
686
687 ChangeAndReturn(fluidConfig.fluid_reverb_roomsize, value, pRealValue);
688 return false;
689
690 case zmusic_fluid_reverb_damping:
691 if (value < 0)
692 value = 0;
693 else if (value > 1)
694 value = 1;
695
696 if (currSong != NULL)
697 currSong->ChangeSettingNum("fluidsynth.z.reverb", value);
698
699 ChangeAndReturn(fluidConfig.fluid_reverb_damping, value, pRealValue);
700 return false;
701
702 case zmusic_fluid_reverb_width:
703 if (value < 0)
704 value = 0;
705 else if (value > 100)
706 value = 100;
707
708 if (currSong != NULL)
709 currSong->ChangeSettingNum("fluidsynth.z.reverb", value);
710
711 ChangeAndReturn(fluidConfig.fluid_reverb_width, value, pRealValue);
712 return false;
713
714 case zmusic_fluid_reverb_level:
715 if (value < 0)
716 value = 0;
717 else if (value > 1)
718 value = 1;
719
720 if (currSong != NULL)
721 currSong->ChangeSettingNum("fluidsynth.z.reverb", value);
722
723 ChangeAndReturn(fluidConfig.fluid_reverb_level, value, pRealValue);
724 return false;
725
726 case zmusic_fluid_chorus_level:
727 if (value < 0)
728 value = 0;
729 else if (value > 1)
730 value = 1;
731
732 if (currSong != NULL)
733 currSong->ChangeSettingNum("fluidsynth.z.chorus", value);
734
735 ChangeAndReturn(fluidConfig.fluid_chorus_level, value, pRealValue);
736 return false;
737
738 case zmusic_fluid_chorus_speed:
739 if (value < 0.29f)
740 value = 0.29f;
741 else if (value > 5)
742 value = 5;
743
744 if (currSong != NULL)
745 currSong->ChangeSettingNum("fluidsynth.z.chorus", value);
746
747 ChangeAndReturn(fluidConfig.fluid_chorus_speed, value, pRealValue);
748 return false;
749
750 // depth is in ms and actual maximum depends on the sample rate
751 case zmusic_fluid_chorus_depth:
752 if (value < 0)
753 value = 0;
754 else if (value > 21)
755 value = 21;
756
757 if (currSong != NULL)
758 currSong->ChangeSettingNum("fluidsynth.z.chorus", value);
759
760 ChangeAndReturn(fluidConfig.fluid_chorus_depth, value, pRealValue);
761 return false;
762
763 #ifdef HAVE_TIMIDITY
764 case zmusic_timidity_drum_power:
765 if (value < 0) value = 0;
766 else if (value > MAX_AMPLIFICATION / 100.f) value = MAX_AMPLIFICATION / 100.f;
767 ChangeVarSync(TimidityPlus::timidity_drum_power, value);
768 if (pRealValue) *pRealValue = value;
769 return false;
770
771 // For testing mainly.
772 case zmusic_timidity_tempo_adjust:
773 if (value < 0.25) value = 0.25;
774 else if (value > 10) value = 10;
775 ChangeVarSync(TimidityPlus::timidity_tempo_adjust, value);
776 if (pRealValue) *pRealValue = value;
777 return false;
778
779 case zmusic_timidity_min_sustain_time:
780 if (value < 0) value = 0;
781 ChangeVarSync(TimidityPlus::min_sustain_time, value);
782 if (pRealValue) *pRealValue = value;
783 return false;
784 #endif
785
786 case zmusic_gme_stereodepth:
787 if (currSong != nullptr)
788 currSong->ChangeSettingNum("GME.stereodepth", value);
789 ChangeAndReturn(miscConfig.gme_stereodepth, value, pRealValue);
790 return false;
791
792 case zmusic_mod_dumb_mastervolume:
793 if (value < 0) value = 0;
794 ChangeAndReturn(dumbConfig.mod_dumb_mastervolume, value, pRealValue);
795 return false;
796
797 case zmusic_snd_musicvolume:
798 miscConfig.snd_musicvolume = value;
799 return false;
800
801 case zmusic_relative_volume:
802 miscConfig.relative_volume = value;
803 return false;
804
805 case zmusic_snd_mastervolume:
806 miscConfig.snd_mastervolume = value;
807 return false;
808
809 }
810 return false;
811 }
812
ChangeMusicSettingString(EStringConfigKey key,MusInfo * currSong,const char * value)813 DLL_EXPORT zmusic_bool ChangeMusicSettingString(EStringConfigKey key, MusInfo* currSong, const char *value)
814 {
815 switch (key)
816 {
817 default:
818 return false;
819
820 #ifdef HAVE_ADL
821 case zmusic_adl_custom_bank:
822 adlConfig.adl_custom_bank = value;
823 return devType() == MDEV_ADL;
824 #endif
825 case zmusic_fluid_lib:
826 fluidConfig.fluid_lib = value;
827 return false; // only takes effect for next song.
828
829 case zmusic_fluid_patchset:
830 fluidConfig.fluid_patchset = value;
831 #ifdef HAVE_TIMIDITY
832 if (timidityConfig.timidity_config.empty()) timidityConfig.timidity_config = value; // Also use for Timidity++ if nothing has been set.
833 #endif
834 return devType() == MDEV_FLUIDSYNTH;
835
836 #ifdef HAVE_OPN
837 case zmusic_opn_custom_bank:
838 opnConfig.opn_custom_bank = value;
839 return devType() == MDEV_OPN && opnConfig.opn_use_custom_bank;
840 #endif
841 #ifdef HAVE_GUS
842 case zmusic_gus_config:
843 gusConfig.gus_config = value;
844 return devType() == MDEV_GUS;
845 #endif
846 #ifdef HAVE_GUS
847 case zmusic_gus_patchdir:
848 gusConfig.gus_patchdir = value;
849 return devType() == MDEV_GUS && gusConfig.gus_dmxgus;
850 #endif
851 #ifdef HAVE_TIMIDITY
852 case zmusic_timidity_config:
853 timidityConfig.timidity_config = value;
854 return devType() == MDEV_TIMIDITY;
855 #endif
856 #ifdef HAVE_WILDMIDI
857 case zmusic_wildmidi_config:
858 wildMidiConfig.config = value;
859 return devType() == MDEV_WILDMIDI;
860 #endif
861 }
862 return false;
863 }
864
865 static ZMusicConfigurationSetting config[] = {
866 #ifdef HAVE_ADL
867 {"zmusic_adl_chips_count", zmusic_adl_chips_count, ZMUSIC_VAR_INT, 5},
868 {"zmusic_adl_emulator_id", zmusic_adl_emulator_id, ZMUSIC_VAR_INT, 0},
869 {"zmusic_adl_run_at_pcm_rate", zmusic_adl_run_at_pcm_rate, ZMUSIC_VAR_BOOL, 0},
870 {"zmusic_adl_fullpan", zmusic_adl_fullpan, ZMUSIC_VAR_BOOL, 1},
871 {"zmusic_adl_bank", zmusic_adl_bank, ZMUSIC_VAR_INT, 14},
872 {"zmusic_adl_use_custom_bank", zmusic_adl_use_custom_bank, ZMUSIC_VAR_BOOL, 0},
873 {"zmusic_adl_volume_model", zmusic_adl_volume_model, ZMUSIC_VAR_INT, 3},
874 {"zmusic_adl_custom_bank", zmusic_adl_custom_bank, ZMUSIC_VAR_STRING, 0},
875 #endif
876 {"zmusic_fluid_reverb", zmusic_fluid_reverb, ZMUSIC_VAR_BOOL, 0},
877 {"zmusic_fluid_chorus", zmusic_fluid_chorus, ZMUSIC_VAR_BOOL, 0},
878 {"zmusic_fluid_voices", zmusic_fluid_voices, ZMUSIC_VAR_INT, 128},
879 {"zmusic_fluid_interp", zmusic_fluid_interp, ZMUSIC_VAR_INT, 1},
880 {"zmusic_fluid_samplerate", zmusic_fluid_samplerate, ZMUSIC_VAR_INT, 0},
881 {"zmusic_fluid_threads", zmusic_fluid_threads, ZMUSIC_VAR_INT, 1},
882 {"zmusic_fluid_chorus_voices", zmusic_fluid_chorus_voices, ZMUSIC_VAR_INT, 3},
883 {"zmusic_fluid_chorus_type", zmusic_fluid_chorus_type, ZMUSIC_VAR_INT, 0},
884 {"zmusic_fluid_gain", zmusic_fluid_gain, ZMUSIC_VAR_FLOAT, 0},
885 {"zmusic_fluid_reverb_roomsize", zmusic_fluid_reverb_roomsize, ZMUSIC_VAR_FLOAT, 0.75f},
886 {"zmusic_fluid_reverb_damping", zmusic_fluid_reverb_damping, ZMUSIC_VAR_FLOAT, 0.23f},
887 {"zmusic_fluid_reverb_width", zmusic_fluid_reverb_width, ZMUSIC_VAR_FLOAT, 0.75f},
888 {"zmusic_fluid_reverb_level", zmusic_fluid_reverb_level, ZMUSIC_VAR_FLOAT, 0.57f},
889 {"zmusic_fluid_chorus_level", zmusic_fluid_chorus_level, ZMUSIC_VAR_FLOAT, 1.2f},
890 {"zmusic_fluid_chorus_speed", zmusic_fluid_chorus_speed, ZMUSIC_VAR_FLOAT, 0.3f},
891 {"zmusic_fluid_chorus_depth", zmusic_fluid_chorus_depth, ZMUSIC_VAR_FLOAT, 8},
892 {"zmusic_fluid_lib", zmusic_fluid_lib, ZMUSIC_VAR_STRING, 0},
893 #ifdef HAVE_OPL
894 {"zmusic_opl_numchips", zmusic_opl_numchips, ZMUSIC_VAR_INT, 2},
895 {"zmusic_opl_core", zmusic_opl_core, ZMUSIC_VAR_INT, 0},
896 {"zmusic_opl_fullpan", zmusic_opl_fullpan, ZMUSIC_VAR_BOOL, 1},
897 #endif
898 #ifdef HAVE_OPN
899 {"zmusic_opn_chips_count", zmusic_opn_chips_count, ZMUSIC_VAR_INT, 8},
900 {"zmusic_opn_emulator_id", zmusic_opn_emulator_id, ZMUSIC_VAR_INT, 0},
901 {"zmusic_opn_run_at_pcm_rate", zmusic_opn_run_at_pcm_rate, ZMUSIC_VAR_BOOL, 0},
902 {"zmusic_opn_fullpan", zmusic_opn_fullpan, ZMUSIC_VAR_BOOL, 2},
903 {"zmusic_opn_use_custom_bank", zmusic_opn_use_custom_bank, ZMUSIC_VAR_BOOL, 0},
904 {"zmusic_opn_custom_bank", zmusic_opn_custom_bank, ZMUSIC_VAR_STRING, 0},
905 #endif
906 #ifdef HAVE_GUS
907 {"zmusic_gus_dmxgus", zmusic_gus_dmxgus, ZMUSIC_VAR_BOOL, 0},
908 {"zmusic_gus_midi_voices", zmusic_gus_midi_voices, ZMUSIC_VAR_INT, 32},
909 {"zmusic_gus_memsize", zmusic_gus_memsize, ZMUSIC_VAR_INT, 0},
910 {"zmusic_gus_config", zmusic_gus_config, ZMUSIC_VAR_STRING, 0},
911 {"zmusic_gus_patchdir", zmusic_gus_patchdir, ZMUSIC_VAR_STRING, 0},
912 #endif
913 #ifdef HAVE_TIMIDITY
914 {"zmusic_timidity_modulation_wheel", zmusic_timidity_modulation_wheel, ZMUSIC_VAR_BOOL, 1},
915 {"zmusic_timidity_portamento", zmusic_timidity_portamento, ZMUSIC_VAR_BOOL, 0},
916 {"zmusic_timidity_reverb", zmusic_timidity_reverb, ZMUSIC_VAR_INT, 0},
917 {"zmusic_timidity_reverb_level", zmusic_timidity_reverb_level, ZMUSIC_VAR_INT, 0},
918 {"zmusic_timidity_chorus", zmusic_timidity_chorus, ZMUSIC_VAR_BOOL, 0},
919 {"zmusic_timidity_surround_chorus", zmusic_timidity_surround_chorus, ZMUSIC_VAR_BOOL, 0},
920 {"zmusic_timidity_channel_pressure", zmusic_timidity_channel_pressure, ZMUSIC_VAR_BOOL, 0},
921 {"zmusic_timidity_lpf_def", zmusic_timidity_lpf_def, ZMUSIC_VAR_BOOL, 1},
922 {"zmusic_timidity_temper_control", zmusic_timidity_temper_control, ZMUSIC_VAR_BOOL, 1},
923 {"zmusic_timidity_modulation_envelope", zmusic_timidity_modulation_envelope, ZMUSIC_VAR_BOOL, 1},
924 {"zmusic_timidity_overlap_voice_allow", zmusic_timidity_overlap_voice_allow, ZMUSIC_VAR_BOOL, 1},
925 {"zmusic_timidity_drum_effect", zmusic_timidity_drum_effect, ZMUSIC_VAR_BOOL, 0},
926 {"zmusic_timidity_pan_delay", zmusic_timidity_pan_delay, ZMUSIC_VAR_BOOL, 0},
927 {"zmusic_timidity_key_adjust", zmusic_timidity_key_adjust, ZMUSIC_VAR_INT, 0},
928 {"zmusic_timidity_drum_power", zmusic_timidity_drum_power, ZMUSIC_VAR_FLOAT, 1},
929 {"zmusic_timidity_tempo_adjust", zmusic_timidity_tempo_adjust, ZMUSIC_VAR_FLOAT, 1},
930 {"zmusic_timidity_min_sustain_time", zmusic_timidity_min_sustain_time, ZMUSIC_VAR_FLOAT, 5000},
931 {"zmusic_timidity_config", zmusic_timidity_config, ZMUSIC_VAR_STRING, 0},
932 #endif
933 #ifdef HAVE_WILDMIDI
934 {"zmusic_wildmidi_reverb", zmusic_wildmidi_reverb, ZMUSIC_VAR_BOOL, 0},
935 {"zmusic_wildmidi_enhanced_resampling", zmusic_wildmidi_enhanced_resampling, ZMUSIC_VAR_BOOL, 1},
936 {"zmusic_wildmidi_config", zmusic_wildmidi_config, ZMUSIC_VAR_STRING, 0},
937 #endif
938 {"zmusic_mod_samplerate", zmusic_mod_samplerate, ZMUSIC_VAR_INT, 0},
939 {"zmusic_mod_volramp", zmusic_mod_volramp, ZMUSIC_VAR_INT, 2},
940 {"zmusic_mod_interp", zmusic_mod_interp, ZMUSIC_VAR_BOOL, 2},
941 {"zmusic_mod_autochip", zmusic_mod_autochip, ZMUSIC_VAR_BOOL, 0},
942 {"zmusic_mod_autochip_size_force", zmusic_mod_autochip_size_force, ZMUSIC_VAR_INT, 100},
943 {"zmusic_mod_autochip_size_scan", zmusic_mod_autochip_size_scan, ZMUSIC_VAR_INT, 500},
944 {"zmusic_mod_autochip_scan_threshold", zmusic_mod_autochip_scan_threshold, ZMUSIC_VAR_INT, 12},
945 {"zmusic_mod_dumb_mastervolume", zmusic_mod_dumb_mastervolume, ZMUSIC_VAR_FLOAT, 1},
946
947 {"zmusic_gme_stereodepth", zmusic_gme_stereodepth, ZMUSIC_VAR_FLOAT, 0},
948
949 {"zmusic_snd_midiprecache", zmusic_snd_midiprecache, ZMUSIC_VAR_BOOL, 1},
950 {"zmusic_snd_streambuffersize", zmusic_snd_streambuffersize, ZMUSIC_VAR_INT, 64},
951 {"zmusic_snd_mididevice", zmusic_snd_mididevice, ZMUSIC_VAR_INT, 0},
952 {"zmusic_snd_outputrate", zmusic_snd_outputrate, ZMUSIC_VAR_INT, 44100},
953 {"zmusic_snd_musicvolume", zmusic_snd_musicvolume, ZMUSIC_VAR_FLOAT, 1},
954 {"zmusic_relative_volume", zmusic_relative_volume, ZMUSIC_VAR_FLOAT, 1},
955 {"zmusic_snd_mastervolume", zmusic_snd_mastervolume, ZMUSIC_VAR_FLOAT, 1},
956 {}
957 };
958
ZMusic_GetConfiguration()959 DLL_EXPORT const ZMusicConfigurationSetting* ZMusic_GetConfiguration()
960 {
961 return config;
962 }
963