hydrogen 1.2.6
Preferences.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (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
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#include <stdlib.h>
25
26#ifndef WIN32
27#include <pwd.h>
28#include <unistd.h>
29#endif
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <stdlib.h>
33#include <fstream>
34#include <iostream>
35#include <cstdio>
36#include <list>
37#include <algorithm>
38#include <memory>
39
40#include <core/MidiMap.h>
41#include <core/Version.h>
43#include <core/Helpers/Xml.h>
45
46#include <QDir>
47#include <QProcess>
48//#include <QApplication>
49
50namespace H2Core
51{
52
54
56{
57 if ( __instance == nullptr ) {
59 }
60}
61
63{
64 __instance = this;
65 m_pTheme = std::make_shared<Theme>();
66
67 // switch to enable / disable lash, only on h2 startup
68 m_brestartLash = false;
69 m_bsetLash = false;
70
71 //rubberband bpm change queue
73
74 QString rubberBandCLIPath = getenv( "PATH" );
75 QStringList rubberBandCLIPathList = rubberBandCLIPath.split(":");//linux use ":" as separator. maybe windows and osx use other separators
76
77 //find the Rubberband-CLI in system env
78 //if this fails a second test will check individual user settings
79 for(int i = 0; i < rubberBandCLIPathList.size(); ++i){
80 m_rubberBandCLIexecutable = rubberBandCLIPathList[i] + "/rubberband";
81 if ( QFile( m_rubberBandCLIexecutable ).exists() == true ){
83 break;
84 }else
85 {
86 m_rubberBandCLIexecutable = "Path to Rubberband-CLI";
88 }
89 }
90
91 m_sPreferredLanguage = QString();
92 __playsamplesonclicking = false; // audio file browser
93 __playselectedinstrument = false; // midi keyboard and keyboard play only selected instrument
94
95 recordEvents = false; // not recording by default
96 punchInPos = 0;
97 punchOutPos = -1;
98
99 __expandSongItem = true; //SoundLibraryPanel
100 __expandPatternItem = true; //SoundLibraryPanel
101 __useTimelineBpm = false; // use timeline
102
103 m_sLastExportPatternAsDirectory = QDir::homePath();
104 m_sLastExportSongDirectory = QDir::homePath();
105 m_sLastSaveSongAsDirectory = QDir::homePath();
108 m_sLastExportLilypondDirectory = QDir::homePath();
109 m_sLastExportMidiDirectory = QDir::homePath();
110 m_sLastImportDrumkitDirectory = QDir::homePath();
111 m_sLastExportDrumkitDirectory = QDir::homePath();
112 m_sLastOpenLayerDirectory = QDir::homePath();
113 m_sLastOpenPlaybackTrackDirectory = QDir::homePath();
117
118 //export dialog
128
129 //export midi dialog
134 m_bFollowPlayhead = true;
135 // SEE ABOVE: m_brestartLash
136 // SEE ABOVE: m_bsetLash
137
138 m_bbc = false;
139 m_mmcsetplay = false;
140
141 m_countOffset = 0; // beatcounter
142 m_startOffset = 0; // beatcounter
143
144 sServerList.push_back( QString("http://hydrogen-music.org/feeds/drumkit_list.php") );
146 m_patternCategories.push_back( QString("not_categorized") );
147
148 //___ audio engine properties ___
150 m_bUseMetronome = false;
151 m_fMetronomeVolume = 0.5;
152 m_nMaxNotes = 256;
153 m_nBufferSize = 1024;
154 m_nSampleRate = 44100;
155
156 //___ oss driver properties ___
157 m_sOSSDevice = QString("/dev/dsp");
158
159 //___ MIDI Driver properties
160#if defined(H2CORE_HAVE_ALSA)
161 m_sMidiDriver = QString("ALSA");
162#elif defined(H2CORE_HAVE_PORTMIDI)
163 m_sMidiDriver = QString("PortMidi");
164#elif defined(H2CORE_HAVE_COREMIDI)
165 m_sMidiDriver = QString("CoreMIDI");
166#elif defined(H2CORE_HAVE_JACK)
167 m_sMidiDriver = QString("JACK-MIDI");
168#else
169 // Set ALSA as fallback if none of the above options are available
170 // (although MIDI won't work in this case).
171 m_sMidiDriver = QString( "ALSA" );
172#endif
176 m_bMidiNoteOffIgnore = false;
177 m_bMidiFixedMapping = false;
179
180 // PortAudio properties
181 m_sPortAudioDevice = QString();
182 m_sPortAudioHostAPI = QString();
184
185 // CoreAudio
186 m_sCoreAudioDevice = QString();
187
188 //___ alsa audio driver properties ___
189
190#ifdef H2CORE_HAVE_ALSA
191 // Ensure the device read from the local preferences does
192 // exist. If not, we try to replace it with a valid one.
193 QStringList alsaDevices = AlsaAudioDriver::getDevices();
194 if ( alsaDevices.size() == 0 ||
195 alsaDevices.contains( "hw:0" ) ) {
196 m_sAlsaAudioDevice = "hw:0";
197 } else {
198 // Fall back to a device found on the system (but not the
199 // "null" one).
200 if ( alsaDevices[ 0 ] != "null" ) {
201 m_sAlsaAudioDevice = alsaDevices[ 0 ];
202 } else if ( alsaDevices.size() > 1 ) {
203 m_sAlsaAudioDevice = alsaDevices[ 1 ];
204 } else {
205 m_sAlsaAudioDevice = "hw:0";
206 }
207 }
208#else
209 m_sAlsaAudioDevice = "hw:0";
210#endif
211
212 //___ jack driver properties ___
213 m_sJackPortName1 = QString("alsa_pcm:playback_1");
214 m_sJackPortName2 = QString("alsa_pcm:playback_2");
217 m_bJackTrackOuts = false;
221
222 // OSC configuration
223 m_bOscServerEnabled = false;
225 m_nOscServerPort = 9000;
227
228 //___ General properties ___
229 m_brestoreLastSong = true;
231 m_bUseLash = false;
232 m_bShowDevelWarning = false;
234 // NONE: lastSongFilename;
235 hearNewNotes = true;
236 // NONE: m_recentFiles;
237 // NONE: m_recentFX;
238 quantizeEvents = true;
239 recordEvents = false;
241 m_bHideKeyboardCursor = false;
242
243 //___ GUI properties ___
247 m_bIsFXTabVisible = true;
248 m_bShowAutomationArea = false;
249 m_bShowPlaybackTrack = false;
254 mainFormProperties.set(0, 0, 1000, 700, true);
255 mixerProperties.set(10, 350, 829, 276, true);
256 patternEditorProperties.set(280, 100, 706, 439, true);
257 songEditorProperties.set(10, 10, 600, 250, true);
258 instrumentRackProperties.set(500, 20, 526, 437, true);
259 audioEngineInfoProperties.set(720, 120, 0, 0, false);
260 m_playlistDialogProperties.set(200, 300, 921, 703, false);
261 m_directorProperties.set(200, 300, 423, 377, false);
262 m_ladspaProperties[0].set(2, 20, 0, 0, false);
263 m_ladspaProperties[1].set(2, 20, 0, 0, false);
264 m_ladspaProperties[2].set(2, 20, 0, 0, false);
265 m_ladspaProperties[3].set(2, 20, 0, 0, false);
266 m_nMaxBars = 400;
267 m_nMaxLayers = 16;
268
272
273 const bool bGlobalPrefLoaded = loadPreferences( true );
274 const bool bUserPrefLoaded = loadPreferences( false );
275 if ( bGlobalPrefLoaded || bUserPrefLoaded ) {
277 } else {
278 m_bLoadingSuccessful = false;
279 }
280
281}
282
283
284
286{
287 INFOLOG( "DESTROY" );
288 __instance = nullptr;
289}
290
295{
296 // We do not required the recently used variables to be
297 // accumulated throughout various configuration files.
298 m_recentFiles.clear();
299 m_recentFX.clear();
300
301 bool bRecreate = false; // configuration file must be recreated?
302
303 QString sPreferencesFilename =
305 INFOLOG( QString( "Loading preferences file [%1]" )
306 .arg( sPreferencesFilename ) );
307
308 if ( ! Filesystem::file_readable( sPreferencesFilename, true ) ) {
309 if ( bGlobal ) {
310 ERRORLOG( QString( "Global preferences file [%1] is not readable!" )
311 .arg( sPreferencesFilename ) );
312 return false;
313 }
314 else {
315 WARNINGLOG( QString( "User-level preferences file [%1] is not readable! It will be recreated." )
316 .arg( sPreferencesFilename ) );
317 bRecreate = true;
318 }
319 }
320 else {
321 // Preferences is readable.
322
323 XMLDoc doc;
324 doc.read( sPreferencesFilename, false );
325 XMLNode rootNode = doc.firstChildElement( "hydrogen_preferences" );
326
327 if ( !rootNode.isNull() ) {
328
329 // version
330 QString version = rootNode.read_string( "version", "", false, false );
331 if ( version.isEmpty() ) {
332 bRecreate = true;
333 }
334
336 m_sPreferredLanguage = rootNode.read_string( "preferredLanguage", m_sPreferredLanguage, false, "" );
337 __playselectedinstrument = rootNode.read_bool( "instrumentInputMode", __playselectedinstrument, false, false );
338 m_bShowDevelWarning = rootNode.read_bool( "showDevelWarning", m_bShowDevelWarning, false, false );
339 m_bShowNoteOverwriteWarning = rootNode.read_bool( "showNoteOverwriteWarning", m_bShowNoteOverwriteWarning, false, false );
340 m_brestoreLastSong = rootNode.read_bool( "restoreLastSong", m_brestoreLastSong, false, false );
341 m_brestoreLastPlaylist = rootNode.read_bool( "restoreLastPlaylist", m_brestoreLastPlaylist, false, false );
342 m_bUseLash = rootNode.read_bool( "useLash", false, false, false );
343 __useTimelineBpm = rootNode.read_bool( "useTimeLine", __useTimelineBpm, false, false );
344 m_nMaxBars = rootNode.read_int( "maxBars", 400, false, false );
345 m_nMaxLayers = rootNode.read_int( "maxLayers", 16, false, false );
347 rootNode.read_int( "defaultUILayout",
348 static_cast<int>(InterfaceTheme::Layout::SinglePane), false, false )) );
350 rootNode.read_int( "uiScalingPolicy",
351 static_cast<int>(InterfaceTheme::ScalingPolicy::Smaller), false, false )) );
352 m_nLastOpenTab = rootNode.read_int( "lastOpenTab", 0, false, false );
353 m_bUseRelativeFilenamesForPlaylists = rootNode.read_bool( "useRelativeFilenamesForPlaylists", false, false, false );
354 m_bHideKeyboardCursor = rootNode.read_bool( "hideKeyboardCursorWhenUnused", false, false, false );
355
356 //restore the right m_bsetlash value
358 m_useTheRubberbandBpmChangeEvent = rootNode.read_bool( "useTheRubberbandBpmChangeEvent", m_useTheRubberbandBpmChangeEvent, false, false );
359
360 hearNewNotes = rootNode.read_bool( "hearNewNotes", hearNewNotes, false, false );
361 quantizeEvents = rootNode.read_bool( "quantizeEvents", quantizeEvents, false, false );
362
363 //rubberband
365 //this scond test will check individual user settings
366 QString test = rootNode.read_string( "path_to_rubberband", "", false, false );
367 if ( QFile( test ).exists() == true ){
369 }else
370 {
371 m_rubberBandCLIexecutable = "Path to Rubberband-CLI";
372 }
373 }
374
375 XMLNode recentUsedSongsNode = rootNode.firstChildElement( "recentUsedSongs" );
376 if ( ! recentUsedSongsNode.isNull() ) {
377 QDomElement songElement = recentUsedSongsNode.firstChildElement( "song" );
378 while( !songElement.isNull() && ! songElement.text().isEmpty() ){
379 m_recentFiles.push_back( songElement.text() );
380 songElement = songElement.nextSiblingElement( "song" );
381 }
382
383 } else {
384 WARNINGLOG( "recentUsedSongs node not found" );
385 }
386
387 XMLNode recentFXNode = rootNode.firstChildElement( "recentlyUsedEffects" );
388 if ( ! recentFXNode.isNull() ) {
389 QDomElement fxElement = recentFXNode.firstChildElement( "FX" );
390 while ( !fxElement.isNull() && ! fxElement.text().isEmpty()) {
391 m_recentFX.push_back( fxElement.text() );
392 fxElement = fxElement.nextSiblingElement( "FX" );
393 }
394 } else {
395 WARNINGLOG( "recentlyUsedEffects node not found" );
396 }
397
398 sServerList.clear();
399 XMLNode serverListNode = rootNode.firstChildElement( "serverList" );
400 if ( ! serverListNode.isNull() ) {
401 QDomElement serverElement = serverListNode.firstChildElement( "server" );
402 while ( !serverElement.isNull() && !serverElement.text().isEmpty() ) {
403 sServerList.push_back( serverElement.text() );
404 serverElement = serverElement.nextSiblingElement( "server" );
405 }
406 } else {
407 WARNINGLOG( "serverList node not found" );
408 }
409
410 m_patternCategories.clear();
411 XMLNode patternCategoriesNode = rootNode.firstChildElement( "patternCategories" );
412 if ( ! patternCategoriesNode.isNull() ) {
413 QDomElement patternCategoriesElement = patternCategoriesNode.firstChildElement( "categories" );
414 while ( !patternCategoriesElement.isNull() && !patternCategoriesElement.text().isEmpty() ) {
415 m_patternCategories.push_back( patternCategoriesElement.text() );
416 patternCategoriesElement = patternCategoriesElement.nextSiblingElement( "categories" );
417 }
418 } else {
419 WARNINGLOG( "patternCategories node not found" );
420 }
421
422
424 XMLNode audioEngineNode = rootNode.firstChildElement( "audio_engine" );
425 if ( audioEngineNode.isNull() ) {
426 WARNINGLOG( "audio_engine node not found" );
427 bRecreate = true;
428 } else {
429 const QString sAudioDriver = audioEngineNode.read_string(
430 "audio_driver", Preferences::audioDriverToQString(
432 false, false );
433 m_audioDriver = parseAudioDriver( sAudioDriver );
435 WARNINGLOG( "Falling back to 'Auto' audio driver" );
437 }
438 m_bUseMetronome = audioEngineNode.read_bool( "use_metronome", m_bUseMetronome, false, false );
439 m_fMetronomeVolume = audioEngineNode.read_float( "metronome_volume", 0.5f, false, false );
440 m_nMaxNotes = audioEngineNode.read_int( "maxNotes", m_nMaxNotes, false, false );
441 m_nBufferSize = audioEngineNode.read_int( "buffer_size", m_nBufferSize, false, false );
442 m_nSampleRate = audioEngineNode.read_int( "samplerate", m_nSampleRate, false, false );
443
445 XMLNode ossDriverNode = audioEngineNode.firstChildElement( "oss_driver" );
446 if ( ossDriverNode.isNull() ) {
447 WARNINGLOG( "oss_driver node not found" );
448 bRecreate = true;
449 } else {
450 m_sOSSDevice = ossDriverNode.read_string( "ossDevice", m_sOSSDevice, false, false );
451 }
452
454 XMLNode portAudioDriverNode = audioEngineNode.firstChildElement( "portaudio_driver" );
455 if ( portAudioDriverNode.isNull() ) {
456 WARNINGLOG( "portaudio_driver node not found" );
457 bRecreate = true;
458 } else {
459 m_sPortAudioDevice = portAudioDriverNode.read_string( "portAudioDevice", m_sPortAudioDevice, false, true );
460 m_sPortAudioHostAPI = portAudioDriverNode.read_string( "portAudioHostAPI", m_sPortAudioHostAPI, false, true );
461 m_nLatencyTarget = portAudioDriverNode.read_int( "latencyTarget", m_nLatencyTarget, false, false );
462 }
463
465 XMLNode coreAudioDriverNode = audioEngineNode.firstChildElement( "coreaudio_driver" );
466 if ( coreAudioDriverNode.isNull() ) {
467 WARNINGLOG( "coreaudio_driver node not found" );
468 bRecreate = true;
469 } else {
470 m_sCoreAudioDevice = coreAudioDriverNode.read_string( "coreAudioDevice", m_sCoreAudioDevice, false, true );
471 }
472
474 XMLNode jackDriverNode = audioEngineNode.firstChildElement( "jack_driver" );
475 if ( jackDriverNode.isNull() ) {
476 WARNINGLOG( "jack_driver node not found" );
477 bRecreate = true;
478 } else {
479 m_sJackPortName1 = jackDriverNode.read_string( "jack_port_name_1", m_sJackPortName1, false, false );
480 m_sJackPortName2 = jackDriverNode.read_string( "jack_port_name_2", m_sJackPortName2, false, false );
481 QString sMode = jackDriverNode.read_string( "jack_transport_mode", "NO_JACK_TRANSPORT", false, false );
482 if ( sMode == "NO_JACK_TRANSPORT" ) {
484 } else if ( sMode == "USE_JACK_TRANSPORT" ) {
486 }
487
488 // We stick to the old Timebase strings (? why strings for a
489 // boolean option?) for backward and forward compatibility
490 // of old versions still in use.
491 m_bJackTimebaseEnabled = jackDriverNode.read_bool( "jack_timebase_enabled", false, false, false );
492 QString tmMode = jackDriverNode.read_string( "jack_transport_mode_master", "NO_JACK_TIME_MASTER", false, false );
493 if ( tmMode == "NO_JACK_TIME_MASTER" ) {
495 } else if ( tmMode == "USE_JACK_TIME_MASTER" ) {
497 }
498
499 m_bJackTrackOuts = jackDriverNode.read_bool( "jack_track_outs", m_bJackTrackOuts, false, false );
500 m_bJackConnectDefaults = jackDriverNode.read_bool( "jack_connect_defaults", m_bJackConnectDefaults, false, false );
501
502 int nJackTrackOutputMode = jackDriverNode.read_int( "jack_track_output_mode", 0, false, false );
503 switch ( nJackTrackOutputMode ) {
504 case 0:
506 break;
507 case 1:
509 break;
510 default:
511 WARNINGLOG( QString( "Unknown jack_track_output_mode value [%1]. Using JackTrackOutputMode::postFader instead." )
512 .arg( nJackTrackOutputMode ) );
514 }
515 }
516
517
519 XMLNode alsaAudioDriverNode = audioEngineNode.firstChildElement( "alsa_audio_driver" );
520 if ( alsaAudioDriverNode.isNull() ) {
521 WARNINGLOG( "alsa_audio_driver node not found" );
522 bRecreate = true;
523 } else {
524 m_sAlsaAudioDevice = alsaAudioDriverNode.read_string( "alsa_audio_device", m_sAlsaAudioDevice, false, false );
525 }
526
528 XMLNode midiDriverNode = audioEngineNode.firstChildElement( "midi_driver" );
529 if ( midiDriverNode.isNull() ) {
530 WARNINGLOG( "midi_driver node not found" );
531 bRecreate = true;
532 } else {
533 m_sMidiDriver = midiDriverNode.read_string(
534 "driverName", m_sMidiDriver, false, false );
535 // Ensure compatibility will older versions of the
536 // files after capitalization in the GUI
537 // (2021-02-05). This can be dropped in releases
538 // >= 1.2
539 if ( m_sMidiDriver == "JackMidi" ) {
540 m_sMidiDriver = "JACK-MIDI";
541 } else if ( m_sMidiDriver == "CoreMidi" ) {
542 m_sMidiDriver = "CoreMIDI";
543 }
544 m_sMidiPortName = midiDriverNode.read_string(
545 "port_name", Preferences::getNullMidiPort(), false, false );
546 m_sMidiOutputPortName = midiDriverNode.read_string(
547 "output_port_name", Preferences::getNullMidiPort(), false, false );
548 m_nMidiChannelFilter = midiDriverNode.read_int( "channel_filter", -1, false, false );
549 m_bMidiNoteOffIgnore = midiDriverNode.read_bool( "ignore_note_off", true, false, false );
550 m_bMidiDiscardNoteAfterAction = midiDriverNode.read_bool( "discard_note_after_action", true, false, false );
551 m_bMidiFixedMapping = midiDriverNode.read_bool( "fixed_mapping", false, false, true );
552 m_bEnableMidiFeedback = midiDriverNode.read_bool( "enable_midi_feedback", false, false, true );
553 }
554
556 XMLNode oscServerNode = audioEngineNode.firstChildElement( "osc_configuration" );
557 if ( oscServerNode.isNull() ) {
558 WARNINGLOG( "osc_configuration node not found" );
559 bRecreate = true;
560 } else {
561 m_bOscServerEnabled = oscServerNode.read_bool( "oscEnabled", false, false, false );
562 m_bOscFeedbackEnabled = oscServerNode.read_bool( "oscFeedbackEnabled", true, false, false );
563 m_nOscServerPort = oscServerNode.read_int( "oscServerPort", 9000, false, false );
564 }
565 }
566
568 XMLNode guiNode = rootNode.firstChildElement( "gui" );
569 if ( guiNode.isNull() ) {
570 WARNINGLOG( "gui node not found" );
571 bRecreate = true;
572 } else {
573 // QT Style
574 setQTStyle( guiNode.read_string( "QTStyle", "Fusion", false, true ) );
575
576 if ( getQTStyle() == "Plastique" ){
577 setQTStyle( "Fusion" );
578 }
579
580 // Font fun
581 setApplicationFontFamily( guiNode.read_string( "application_font_family", getApplicationFontFamily(), false, false ) );
582 // The value defaults to m_sApplicationFontFamily on
583 // purpose to provide backward compatibility.
584 setLevel2FontFamily( guiNode.read_string( "level2_font_family", getLevel2FontFamily(), false, false ) );
585 setLevel3FontFamily( guiNode.read_string( "level3_font_family", getLevel3FontFamily(), false, false ) );
586 setFontSize( static_cast<FontTheme::FontSize>(
587 guiNode.read_int( "font_size",
588 static_cast<int>(FontTheme::FontSize::Medium), false, false ) ) );
589
590 // Mixer falloff speed
591 setMixerFalloffSpeed( guiNode.read_float( "mixer_falloff_speed",
592 InterfaceTheme::FALLOFF_NORMAL, false, false ) );
593
594 // pattern editor grid resolution
595 m_nPatternEditorGridResolution = guiNode.read_int( "patternEditorGridResolution", m_nPatternEditorGridResolution, false, false );
596 m_bPatternEditorUsingTriplets = guiNode.read_bool( "patternEditorUsingTriplets", m_bPatternEditorUsingTriplets, false, false );
597
598 m_bShowInstrumentPeaks = guiNode.read_bool( "showInstrumentPeaks", m_bShowInstrumentPeaks, false, false );
599 m_bIsFXTabVisible = guiNode.read_bool( "isFXTabVisible", m_bIsFXTabVisible, false, false );
600 m_bShowAutomationArea = guiNode.read_bool( "showAutomationArea", m_bShowAutomationArea, false, false );
601 m_bShowPlaybackTrack = guiNode.read_bool( "showPlaybackTrack", m_bShowPlaybackTrack, false, false );
602
603
604 // pattern editor grid geometry
605 m_nPatternEditorGridHeight = guiNode.read_int( "patternEditorGridHeight", m_nPatternEditorGridHeight, false, false );
606 m_nPatternEditorGridWidth = guiNode.read_int( "patternEditorGridWidth", m_nPatternEditorGridWidth, false, false );
607
608 // song editor grid geometry
609 m_nSongEditorGridHeight = guiNode.read_int( "songEditorGridHeight", m_nSongEditorGridHeight, false, false );
610 m_nSongEditorGridWidth = guiNode.read_int( "songEditorGridWidth", m_nSongEditorGridWidth, false, false );
611
612 // mainForm window properties
613 setMainFormProperties( readWindowProperties( guiNode, "mainForm_properties", mainFormProperties ) );
614 setMixerProperties( readWindowProperties( guiNode, "mixer_properties", mixerProperties ) );
615 setPatternEditorProperties( readWindowProperties( guiNode, "patternEditor_properties", patternEditorProperties ) );
616 setSongEditorProperties( readWindowProperties( guiNode, "songEditor_properties", songEditorProperties ) );
617 setInstrumentRackProperties( readWindowProperties( guiNode, "instrumentRack_properties", instrumentRackProperties ) );
618 setAudioEngineInfoProperties( readWindowProperties( guiNode, "audioEngineInfo_properties", audioEngineInfoProperties ) );
619 // In order to be backward compatible we still call the XML node
620 // "playlistDialog". For some time we had playlistEditor and
621 // playlistDialog coexisting.
622 setPlaylistDialogProperties( readWindowProperties( guiNode, "playlistDialog_properties", m_playlistDialogProperties ) );
623 setDirectorProperties( readWindowProperties( guiNode, "director_properties", m_directorProperties ) );
624
625 // last used file dialog folders
626 m_sLastExportPatternAsDirectory = guiNode.read_string( "lastExportPatternAsDirectory", QDir::homePath(), true, false, true );
627 m_sLastExportSongDirectory = guiNode.read_string( "lastExportSongDirectory", QDir::homePath(), true, false, true );
628 m_sLastSaveSongAsDirectory = guiNode.read_string( "lastSaveSongAsDirectory", QDir::homePath(), true, false, true );
629 m_sLastOpenSongDirectory = guiNode.read_string( "lastOpenSongDirectory", Filesystem::songs_dir(), true, false, true );
630 m_sLastOpenPatternDirectory = guiNode.read_string( "lastOpenPatternDirectory", Filesystem::patterns_dir(), true, false, true );
631 m_sLastExportLilypondDirectory = guiNode.read_string( "lastExportLilypondDirectory", QDir::homePath(), true, false, true );
632 m_sLastExportMidiDirectory = guiNode.read_string( "lastExportMidiDirectory", QDir::homePath(), true, false, true );
633 m_sLastImportDrumkitDirectory = guiNode.read_string( "lastImportDrumkitDirectory", QDir::homePath(), true, false, true );
634 m_sLastExportDrumkitDirectory = guiNode.read_string( "lastExportDrumkitDirectory", QDir::homePath(), true, false, true );
635 m_sLastOpenLayerDirectory = guiNode.read_string( "lastOpenLayerDirectory", QDir::homePath(), true, false, true );
636 m_sLastOpenPlaybackTrackDirectory = guiNode.read_string( "lastOpenPlaybackTrackDirectory", QDir::homePath(), true, false, true );
637 m_sLastAddSongToPlaylistDirectory = guiNode.read_string( "lastAddSongToPlaylistDirectory", Filesystem::songs_dir(), true, false, true );
638 m_sLastPlaylistDirectory = guiNode.read_string( "lastPlaylistDirectory", Filesystem::playlists_dir(), true, false, true );
639 m_sLastPlaylistScriptDirectory = guiNode.read_string( "lastPlaylistScriptDirectory", Filesystem::scripts_dir(), true, false, true );
640 m_sLastImportThemeDirectory = guiNode.read_string( "lastImportThemeDirectory", QDir::homePath(), true, false, true );
641 m_sLastExportThemeDirectory = guiNode.read_string( "lastExportThemeDirectory", QDir::homePath(), true, false, true );
642
643 //export dialog properties
645 guiNode.read_string( "exportDialogFormat", "flac", true, true ) );
647 "exportDialogCompressionLevel", 0.0, true, true );
648 m_nExportModeIdx = guiNode.read_int( "exportDialogMode", 0, false, false );
649 m_nExportSampleRateIdx = guiNode.read_int( "exportDialogSampleRate", 0, false, false );
650 m_nExportSampleDepthIdx = guiNode.read_int( "exportDialogSampleDepth", 0, false, false );
652 guiNode.read_bool( "showExportSongLicenseWarning", true,
653 true, false );
654
656 guiNode.read_bool( "showExportDrumkitLicenseWarning", true,
657 true, false );
659 guiNode.read_bool( "showExportDrumkitCopyleftWarning", true,
660 true, false );
662 guiNode.read_bool( "showExportDrumkitAttributionWarning", true,
663 true, false );
664
665 m_bFollowPlayhead = guiNode.read_bool( "followPlayhead", true, false, false );
666
667 // midi export dialog properties
668 m_nMidiExportMode = guiNode.read_int( "midiExportDialogMode", 0, false, false );
669
670 //beatcounter
671 QString bcMode = guiNode.read_string( "bc", "BC_OFF", false, false );
672 if ( bcMode == "BC_OFF" ) {
673 m_bbc = BC_OFF;
674 } else if ( bcMode == "BC_ON" ) {
675 m_bbc = BC_ON;
676 }
677
678
679 QString setPlay = guiNode.read_string( "setplay", "SET_PLAY_OFF", false, false );
680 if ( setPlay == "SET_PLAY_OFF" ) {
682 } else if ( setPlay == "SET_PLAY_ON" ) {
684 }
685
686 m_countOffset = guiNode.read_int( "countoffset", 0, false, false );
687 m_startOffset = guiNode.read_int( "playoffset", 0, false, false );
688
689 // ~ beatcounter
690
691 m_nAutosavesPerHour = guiNode.read_int( "autosavesPerHour", 60, false, false );
692
693 //SoundLibraryPanel expand items
694 __expandSongItem = guiNode.read_bool( "expandSongItem", __expandSongItem, false, false );
695 __expandPatternItem = guiNode.read_bool( "expandPatternItem", __expandPatternItem, false, false );
696
697 for ( unsigned nFX = 0; nFX < MAX_FX; nFX++ ) {
698 QString sNodeName = QString("ladspaFX_properties%1").arg( nFX );
699 setLadspaProperties( nFX, readWindowProperties( guiNode, sNodeName, m_ladspaProperties[nFX] ) );
700 }
701
702 XMLNode pColorThemeNode = guiNode.firstChildElement( "colorTheme" );
703 if ( !pColorThemeNode.isNull() ) {
704 Theme::readColorTheme( pColorThemeNode, m_pTheme );
705 } else {
706 WARNINGLOG( "colorTheme node not found" );
707 bRecreate = true;
708 }
709
710 //SongEditor coloring
712 guiNode.read_int("SongEditor_ColoringMethod",
713 static_cast<int>(InterfaceTheme::ColoringMethod::Custom), false, false )) );
714 std::vector<QColor> colors( getMaxPatternColors() );
715 for ( int ii = 0; ii < getMaxPatternColors(); ii++ ) {
716 colors[ ii ] = guiNode.read_color( QString( "SongEditor_pattern_color_%1" ).arg( ii ),
717 m_pTheme->getColorTheme()->m_accentColor, false, false );
718 }
719 setPatternColors( colors );
720 setVisiblePatternColors( guiNode.read_int( "SongEditor_visible_pattern_colors", 1, false, false ) );
721 if ( getVisiblePatternColors() > 50 ) {
723 } else if ( getVisiblePatternColors() < 0 ) {
725 }
726 }
727
729 XMLNode filesNode = rootNode.firstChildElement( "files" );
730 if ( filesNode.isNull() ) {
731 WARNINGLOG( "files node not found" );
732 bRecreate = true;
733 } else {
734 // last used song
735 m_lastSongFilename = filesNode.read_string( "lastSongFilename", m_lastSongFilename, false, true );
736 m_lastPlaylistFilename = filesNode.read_string( "lastPlaylistFilename", m_lastPlaylistFilename, false, true );
737 m_sDefaultEditor = filesNode.read_string( "defaulteditor", m_sDefaultEditor, false, true );
738 }
739
742
743
744 XMLNode pMidiEventMapNode = rootNode.firstChildElement( "midiEventMap" );
745 if ( !pMidiEventMapNode.isNull() ) {
746 XMLNode pMidiEventNode = pMidiEventMapNode.firstChildElement( "midiEvent" );
747 while ( !pMidiEventNode.isNull() ) {
748 if( pMidiEventNode.firstChildElement().nodeName() == QString("mmcEvent")){
749 QString event = pMidiEventNode.firstChildElement("mmcEvent").text();
750 QString sAction = pMidiEventNode.firstChildElement("action").text();
751 QString sParam = pMidiEventNode.firstChildElement("parameter").text();
752 QString sParam2 = pMidiEventNode.firstChildElement("parameter2").text();
753 QString sParam3 = pMidiEventNode.firstChildElement("parameter3").text();
754
755 std::shared_ptr<Action> pAction = std::make_shared<Action>( sAction );
756 pAction->setParameter1( sParam );
757 pAction->setParameter2( sParam2 );
758 pAction->setParameter3( sParam3 );
759 mM->registerMMCEvent(event, pAction);
760 }
761
762 if( pMidiEventNode.firstChildElement().nodeName() == QString("noteEvent")){
763 QString event = pMidiEventNode.firstChildElement("noteEvent").text();
764 QString sAction = pMidiEventNode.firstChildElement("action").text();
765 QString sParam = pMidiEventNode.firstChildElement("parameter").text();
766 QString sParam2 = pMidiEventNode.firstChildElement("parameter2").text();
767 QString sParam3 = pMidiEventNode.firstChildElement("parameter3").text();
768 QString s_eventParameter = pMidiEventNode.firstChildElement("eventParameter").text();
769 std::shared_ptr<Action> pAction = std::make_shared<Action>( sAction );
770 pAction->setParameter1( sParam );
771 pAction->setParameter2( sParam2 );
772 pAction->setParameter3( sParam3 );
773 mM->registerNoteEvent(s_eventParameter.toInt(), pAction);
774 }
775
776 if( pMidiEventNode.firstChildElement().nodeName() == QString("ccEvent") ){
777 QString event = pMidiEventNode.firstChildElement("ccEvent").text();
778 QString sAction = pMidiEventNode.firstChildElement("action").text();
779 QString sParam = pMidiEventNode.firstChildElement("parameter").text();
780 QString sParam2 = pMidiEventNode.firstChildElement("parameter2").text();
781 QString sParam3 = pMidiEventNode.firstChildElement("parameter3").text();
782 QString s_eventParameter = pMidiEventNode.firstChildElement("eventParameter").text();
783 std::shared_ptr<Action> pAction = std::make_shared<Action>( sAction );
784 pAction->setParameter1( sParam );
785 pAction->setParameter2( sParam2 );
786 pAction->setParameter3( sParam3 );
787 mM->registerCCEvent( s_eventParameter.toInt(), pAction );
788 }
789
790 if( pMidiEventNode.firstChildElement().nodeName() == QString("pcEvent") ){
791 QString event = pMidiEventNode.firstChildElement("pcEvent").text();
792 QString sAction = pMidiEventNode.firstChildElement("action").text();
793 QString sParam = pMidiEventNode.firstChildElement("parameter").text();
794 QString sParam2 = pMidiEventNode.firstChildElement("parameter2").text();
795 QString sParam3 = pMidiEventNode.firstChildElement("parameter3").text();
796 std::shared_ptr<Action> pAction = std::make_shared<Action>( sAction );
797 pAction->setParameter1( sParam );
798 pAction->setParameter2( sParam2 );
799 pAction->setParameter3( sParam3 );
800 mM->registerPCEvent( pAction );
801 }
802
803 pMidiEventNode = pMidiEventNode.nextSiblingElement( "midiEvent" );
804 }
805
806 } else {
807 WARNINGLOG( "midiMap node not found" );
808 }
809 } // rootNode
810 else {
811 WARNINGLOG( "hydrogen_preferences node not found" );
812 bRecreate = true;
813 }
814 }
815
816 if ( m_nMaxLayers < 16 ) {
817 m_nMaxLayers = 16;
818 }
819
820 // The preferences file should be recreated?
821 if ( bRecreate && ! bGlobal ) {
822 WARNINGLOG( "Recreating configuration file." );
824 return false;
825 }
826
827 return true;
828}
829
830
831
836{
837 QString sPreferencesFilename;
838 const QString sPreferencesOverwritePath = Filesystem::getPreferencesOverwritePath();
839 if ( sPreferencesOverwritePath.isEmpty() ) {
840 sPreferencesFilename = Filesystem::usr_config_path();
841 } else {
842 sPreferencesFilename = sPreferencesOverwritePath;
843 }
844
845 INFOLOG( QString( "Saving preferences file %1" ).arg( sPreferencesFilename ) );
846
847 XMLDoc doc;
848 XMLNode rootNode = doc.set_root( "hydrogen_preferences" );
849
850 // hydrogen version
851 rootNode.write_string( "version", QString( get_version().c_str() ) );
852
854 rootNode.write_string( "preferredLanguage", m_sPreferredLanguage );
855 rootNode.write_bool( "restoreLastSong", m_brestoreLastSong );
856 rootNode.write_bool( "restoreLastPlaylist", m_brestoreLastPlaylist );
857
858 rootNode.write_bool( "useLash", m_bsetLash );
859 rootNode.write_bool( "useTimeLine", __useTimelineBpm );
860
861 rootNode.write_int( "maxBars", m_nMaxBars );
862 rootNode.write_int( "maxLayers", m_nMaxLayers );
863
864 rootNode.write_int( "defaultUILayout", static_cast<int>(getDefaultUILayout()) );
865 rootNode.write_int( "uiScalingPolicy", static_cast<int>(getUIScalingPolicy()) );
866 rootNode.write_int( "lastOpenTab", m_nLastOpenTab );
867
868 rootNode.write_bool( "useTheRubberbandBpmChangeEvent", m_useTheRubberbandBpmChangeEvent );
869
870 rootNode.write_bool( "useRelativeFilenamesForPlaylists", m_bUseRelativeFilenamesForPlaylists );
871 rootNode.write_bool( "hideKeyboardCursorWhenUnused", m_bHideKeyboardCursor );
872
873 // instrument input mode
874 rootNode.write_bool( "instrumentInputMode", __playselectedinstrument );
875
876 //show development version warning
877 rootNode.write_bool( "showDevelWarning", m_bShowDevelWarning );
878
879 // Warn about overwriting notes
880 rootNode.write_bool( "showNoteOverwriteWarning", m_bShowNoteOverwriteWarning );
881
882 // hear new notes in the pattern editor
883 rootNode.write_bool( "hearNewNotes", hearNewNotes );
884
885 // key/midi event prefs
886 rootNode.write_bool( "quantizeEvents", quantizeEvents );
887
888 //extern executables
889 if ( !Filesystem::file_executable( m_rubberBandCLIexecutable , true /* silent */) ) {
890 m_rubberBandCLIexecutable = "Path to Rubberband-CLI";
891 }
892 rootNode.write_string( "path_to_rubberband", m_rubberBandCLIexecutable );
893
894 // Recent used songs
895 XMLNode recentUsedSongsNode = rootNode.createNode( "recentUsedSongs" );
896 {
897 unsigned nSongs = 5;
898 if ( m_recentFiles.size() < 5 ) {
899 nSongs = m_recentFiles.size();
900 }
901 for ( unsigned i = 0; i < nSongs; i++ ) {
902 recentUsedSongsNode.write_string( "song", m_recentFiles[ i ] );
903 }
904 }
905
906 XMLNode recentFXNode = rootNode.createNode( "recentlyUsedEffects" );
907 {
908 int nFX = 0;
909 QString FXname;
910 foreach( FXname, m_recentFX ) {
911 recentFXNode.write_string( "FX", FXname );
912 if ( ++nFX > 10 ) break;
913 }
914 }
915
916
917 std::list<QString>::const_iterator cur_Server;
918
919 XMLNode serverListNode = rootNode.createNode( "serverList" );
920 for( cur_Server = sServerList.begin(); cur_Server != sServerList.end(); ++cur_Server ){
921 serverListNode.write_string( QString("server") , QString( *cur_Server ) );
922 }
923
924
925 std::list<QString>::const_iterator cur_patternCategories;
926
927 XMLNode patternCategoriesNode = rootNode.createNode( "patternCategories" );
928 for( cur_patternCategories = m_patternCategories.begin(); cur_patternCategories != m_patternCategories.end(); ++cur_patternCategories ){
929 patternCategoriesNode.write_string( QString("categories") , QString( *cur_patternCategories ) );
930 }
931
932 //---- AUDIO ENGINE ----
933 XMLNode audioEngineNode = rootNode.createNode( "audio_engine" );
934 {
935 // audio driver
936 audioEngineNode.write_string( "audio_driver",
938
939 // use metronome
940 audioEngineNode.write_bool( "use_metronome", m_bUseMetronome );
941 audioEngineNode.write_float( "metronome_volume", m_fMetronomeVolume );
942 audioEngineNode.write_int( "maxNotes", m_nMaxNotes );
943 audioEngineNode.write_int( "buffer_size", m_nBufferSize );
944 audioEngineNode.write_int( "samplerate", m_nSampleRate );
945
947 XMLNode ossDriverNode = audioEngineNode.createNode( "oss_driver" );
948 {
949 ossDriverNode.write_string( "ossDevice", m_sOSSDevice );
950 }
951
953 XMLNode portAudioDriverNode = audioEngineNode.createNode( "portaudio_driver" );
954 {
955 portAudioDriverNode.write_string( "portAudioDevice", m_sPortAudioDevice );
956 portAudioDriverNode.write_string( "portAudioHostAPI", m_sPortAudioHostAPI );
957 portAudioDriverNode.write_int( "latencyTarget", m_nLatencyTarget );
958 }
959
961 XMLNode coreAudioDriverNode = audioEngineNode.createNode( "coreaudio_driver" );
962 {
963 coreAudioDriverNode.write_string( "coreAudioDevice", m_sCoreAudioDevice );
964 }
965
967 XMLNode jackDriverNode = audioEngineNode.createNode( "jack_driver" );
968 {
969 jackDriverNode.write_string( "jack_port_name_1", m_sJackPortName1 ); // jack port name 1
970 jackDriverNode.write_string( "jack_port_name_2", m_sJackPortName2 ); // jack port name 2
971
972 // jack transport client
973 QString sMode;
975 sMode = "NO_JACK_TRANSPORT";
977 sMode = "USE_JACK_TRANSPORT";
978 }
979 jackDriverNode.write_string( "jack_transport_mode", sMode );
980
981 jackDriverNode.write_bool( "jack_timebase_enabled", m_bJackTimebaseEnabled );
982 // We stick to the old Timebase strings (? why strings for a boolean
983 // option?) for backward and forward compatibility of old versions
984 // still in use.
985 QString tmMode;
987 tmMode = "NO_JACK_TIME_MASTER";
989 tmMode = "USE_JACK_TIME_MASTER";
990 }
991 jackDriverNode.write_string( "jack_transport_mode_master", tmMode );
992
993 // jack default connection
994 jackDriverNode.write_bool( "jack_connect_defaults", m_bJackConnectDefaults );
995
996 int nJackTrackOutputMode;
998 nJackTrackOutputMode = 0;
1000 nJackTrackOutputMode = 1;
1001 }
1002 jackDriverNode.write_int( "jack_track_output_mode", nJackTrackOutputMode );
1003
1004 // jack track outs
1005 jackDriverNode.write_bool( "jack_track_outs", m_bJackTrackOuts );
1006 }
1007
1009 XMLNode alsaAudioDriverNode = audioEngineNode.createNode( "alsa_audio_driver" );
1010 {
1011 alsaAudioDriverNode.write_string( "alsa_audio_device", m_sAlsaAudioDevice );
1012 }
1013
1015 XMLNode midiDriverNode = audioEngineNode.createNode( "midi_driver" );
1016 {
1017 midiDriverNode.write_string( "driverName", m_sMidiDriver );
1018 midiDriverNode.write_string( "port_name", m_sMidiPortName );
1019 midiDriverNode.write_string( "output_port_name", m_sMidiOutputPortName );
1020 midiDriverNode.write_int( "channel_filter", m_nMidiChannelFilter );
1021 midiDriverNode.write_bool( "ignore_note_off", m_bMidiNoteOffIgnore );
1022 midiDriverNode.write_bool( "enable_midi_feedback", m_bEnableMidiFeedback );
1023 midiDriverNode.write_bool( "discard_note_after_action", m_bMidiDiscardNoteAfterAction );
1024 midiDriverNode.write_bool( "fixed_mapping", m_bMidiFixedMapping );
1025 }
1026
1028 XMLNode oscNode = audioEngineNode.createNode( "osc_configuration" );
1029 {
1030 oscNode.write_int( "oscServerPort", m_nOscServerPort );
1031 oscNode.write_bool( "oscEnabled", m_bOscServerEnabled );
1032 oscNode.write_bool( "oscFeedbackEnabled", m_bOscFeedbackEnabled );
1033 }
1034
1035 }
1036
1037 //---- GUI ----
1038 XMLNode guiNode = rootNode.createNode( "gui" );
1039 {
1040 guiNode.write_string( "QTStyle", getQTStyle() );
1041 guiNode.write_string( "application_font_family", getApplicationFontFamily() );
1042 guiNode.write_string( "level2_font_family", getLevel2FontFamily() );
1043 guiNode.write_string( "level3_font_family", getLevel3FontFamily() );
1044 guiNode.write_int( "font_size", static_cast<int>(getFontSize()) );
1045 guiNode.write_float( "mixer_falloff_speed", getMixerFalloffSpeed() );
1046 guiNode.write_int( "patternEditorGridResolution", m_nPatternEditorGridResolution );
1047 guiNode.write_int( "patternEditorGridHeight", m_nPatternEditorGridHeight );
1048 guiNode.write_int( "patternEditorGridWidth", m_nPatternEditorGridWidth );
1049 guiNode.write_bool( "patternEditorUsingTriplets", m_bPatternEditorUsingTriplets );
1050 guiNode.write_int( "songEditorGridHeight", m_nSongEditorGridHeight );
1051 guiNode.write_int( "songEditorGridWidth", m_nSongEditorGridWidth );
1052 guiNode.write_bool( "showInstrumentPeaks", m_bShowInstrumentPeaks );
1053 guiNode.write_bool( "isFXTabVisible", m_bIsFXTabVisible );
1054 guiNode.write_bool( "showAutomationArea", m_bShowAutomationArea );
1055 guiNode.write_bool( "showPlaybackTrack", m_bShowPlaybackTrack );
1056
1057 // MainForm window properties
1058 writeWindowProperties( guiNode, "mainForm_properties", mainFormProperties );
1059 writeWindowProperties( guiNode, "mixer_properties", mixerProperties );
1060 writeWindowProperties( guiNode, "patternEditor_properties", patternEditorProperties );
1061 writeWindowProperties( guiNode, "songEditor_properties", songEditorProperties );
1062 writeWindowProperties( guiNode, "instrumentRack_properties", instrumentRackProperties );
1063 writeWindowProperties( guiNode, "audioEngineInfo_properties", audioEngineInfoProperties );
1064 writeWindowProperties( guiNode, "playlistDialog_properties", m_playlistDialogProperties );
1065 writeWindowProperties( guiNode, "director_properties", m_directorProperties );
1066 for ( unsigned nFX = 0; nFX < MAX_FX; nFX++ ) {
1067 QString sNode = QString("ladspaFX_properties%1").arg( nFX );
1068 writeWindowProperties( guiNode, sNode, m_ladspaProperties[nFX] );
1069 }
1070
1071 // last used file dialog folders
1072 guiNode.write_string( "lastExportPatternAsDirectory", m_sLastExportPatternAsDirectory );
1073 guiNode.write_string( "lastExportSongDirectory", m_sLastExportSongDirectory );
1074 guiNode.write_string( "lastSaveSongAsDirectory", m_sLastSaveSongAsDirectory );
1075 guiNode.write_string( "lastOpenSongDirectory", m_sLastOpenSongDirectory );
1076 guiNode.write_string( "lastOpenPatternDirectory", m_sLastOpenPatternDirectory );
1077 guiNode.write_string( "lastExportLilypondDirectory", m_sLastExportLilypondDirectory );
1078 guiNode.write_string( "lastExportMidiDirectory", m_sLastExportMidiDirectory );
1079 guiNode.write_string( "lastImportDrumkitDirectory", m_sLastImportDrumkitDirectory );
1080 guiNode.write_string( "lastExportDrumkitDirectory", m_sLastExportDrumkitDirectory );
1081 guiNode.write_string( "lastOpenLayerDirectory", m_sLastOpenLayerDirectory );
1082 guiNode.write_string( "lastOpenPlaybackTrackDirectory", m_sLastOpenPlaybackTrackDirectory );
1083 guiNode.write_string( "lastAddSongToPlaylistDirectory", m_sLastAddSongToPlaylistDirectory );
1084 guiNode.write_string( "lastPlaylistDirectory", m_sLastPlaylistDirectory );
1085 guiNode.write_string( "lastPlaylistScriptDirectory", m_sLastPlaylistScriptDirectory );
1086 guiNode.write_string( "lastImportThemeDirectory", m_sLastImportThemeDirectory );
1087 guiNode.write_string( "lastExportThemeDirectory", m_sLastExportThemeDirectory );
1088
1089 //ExportSongDialog
1090 guiNode.write_int( "exportDialogMode", m_nExportModeIdx );
1091 guiNode.write_string( "exportDialogFormat",
1093 guiNode.write_float( "exportDialogCompressionLevel",
1095 guiNode.write_int( "exportDialogSampleRate", m_nExportSampleRateIdx );
1096 guiNode.write_int( "exportDialogSampleDepth", m_nExportSampleDepthIdx );
1097 guiNode.write_bool( "showExportSongLicenseWarning", m_bShowExportSongLicenseWarning );
1098 guiNode.write_bool( "showExportDrumkitLicenseWarning", m_bShowExportDrumkitLicenseWarning );
1099 guiNode.write_bool( "showExportDrumkitCopyleftWarning", m_bShowExportDrumkitCopyleftWarning );
1100 guiNode.write_bool( "showExportDrumkitAttributionWarning", m_bShowExportDrumkitAttributionWarning );
1101
1102 guiNode.write_bool( "followPlayhead", m_bFollowPlayhead );
1103
1104 //ExportMidiDialog
1105 guiNode.write_int( "midiExportDialogMode", m_nMidiExportMode );
1106
1107 //beatcounter
1108 QString bcMode;
1109
1110 if ( m_bbc == BC_OFF ) {
1111 bcMode = "BC_OFF";
1112 } else if ( m_bbc == BC_ON ) {
1113 bcMode = "BC_ON";
1114 }
1115 guiNode.write_string( "bc", bcMode );
1116
1117 QString setPlay;
1118 if ( m_mmcsetplay == SET_PLAY_OFF ) {
1119 setPlay = "SET_PLAY_OFF";
1120 } else if ( m_mmcsetplay == SET_PLAY_ON ) {
1121 setPlay = "SET_PLAY_ON";
1122 }
1123 guiNode.write_string( "setplay", setPlay );
1124
1125 guiNode.write_int( "countoffset", m_countOffset );
1126 guiNode.write_int( "playoffset", m_startOffset );
1127 // ~ beatcounter
1128
1129 guiNode.write_int( "autosavesPerHour", m_nAutosavesPerHour );
1130
1131 //SoundLibraryPanel expand items
1132 guiNode.write_bool( "expandSongItem", __expandSongItem );
1133 guiNode.write_bool( "expandPatternItem", __expandPatternItem );
1134
1135 // User interface style
1136 Theme::writeColorTheme( &guiNode, m_pTheme );
1137
1138 //SongEditor coloring method
1139 guiNode.write_int( "SongEditor_ColoringMethod", static_cast<int>(getColoringMethod()) );
1140 for ( int ii = 0; ii < getMaxPatternColors(); ii++ ) {
1141 guiNode.write_color( QString( "SongEditor_pattern_color_%1" ).arg( ii ), getPatternColors()[ ii ] );
1142 }
1143 guiNode.write_int( "SongEditor_visible_pattern_colors", getVisiblePatternColors() );
1144 }
1145
1146 //---- FILES ----
1147 XMLNode filesNode = rootNode.createNode( "files" );
1148 {
1149 // last used song
1150 filesNode.write_string( "lastSongFilename", m_lastSongFilename );
1151 filesNode.write_string( "lastPlaylistFilename", m_lastPlaylistFilename );
1152 filesNode.write_string( "defaulteditor", m_sDefaultEditor );
1153 }
1154
1155 // In case the Preferences in both system and user space are
1156 // bricked Hydrogen attempts to recreate the Preferences before
1157 // the core is properly initialized. That's why we assure for the
1158 // MidiMap to be initialized.
1161
1162 //---- MidiMap ----
1163 XMLNode midiEventMapNode = rootNode.createNode( "midiEventMap" );
1164
1165 for( const auto& [ssType, ppAction] : mM->getMMCActionMap() ){
1166 if ( ppAction != nullptr && ! ppAction->isNull() ){
1167 XMLNode midiEventNode = midiEventMapNode.createNode( "midiEvent" );
1168
1169 midiEventNode.write_string( "mmcEvent" , ssType );
1170 midiEventNode.write_string( "action" , ppAction->getType());
1171 midiEventNode.write_string( "parameter" , ppAction->getParameter1() );
1172 midiEventNode.write_string( "parameter2" , ppAction->getParameter2() );
1173 midiEventNode.write_string( "parameter3" , ppAction->getParameter3() );
1174 }
1175 }
1176
1177 for ( const auto& [nnPitch, ppAction] : mM->getNoteActionMap() ){
1178 if ( ppAction != nullptr && ! ppAction->isNull() ){
1179 XMLNode midiEventNode = midiEventMapNode.createNode( "midiEvent" );
1180
1181 midiEventNode.write_string(
1183 midiEventNode.write_int( "eventParameter" , nnPitch );
1184 midiEventNode.write_string( "action" , ppAction->getType() );
1185 midiEventNode.write_string( "parameter" , ppAction->getParameter1() );
1186 midiEventNode.write_string( "parameter2" , ppAction->getParameter2() );
1187 midiEventNode.write_string( "parameter3" , ppAction->getParameter3() );
1188 }
1189 }
1190
1191 for ( const auto& [nnParam, ppAction] : mM->getCCActionMap() ){
1192 if ( ppAction != nullptr && ! ppAction->isNull() ){
1193 XMLNode midiEventNode = midiEventMapNode.createNode( "midiEvent" );
1194
1195 midiEventNode.write_string(
1197 midiEventNode.write_int( "eventParameter" , nnParam );
1198 midiEventNode.write_string( "action" , ppAction->getType() );
1199 midiEventNode.write_string( "parameter" , ppAction->getParameter1() );
1200 midiEventNode.write_string( "parameter2" , ppAction->getParameter2() );
1201 midiEventNode.write_string( "parameter3" , ppAction->getParameter3() );
1202 }
1203 }
1204
1205 for ( const auto& ppAction : mM->getPCActions() ) {
1206 if ( ppAction != nullptr && ! ppAction->isNull() ){
1207 XMLNode midiEventNode = midiEventMapNode.createNode( "midiEvent" );
1208
1209 midiEventNode.write_string(
1211 midiEventNode.write_string( "action" , ppAction->getType() );
1212 midiEventNode.write_string( "parameter" , ppAction->getParameter1() );
1213 midiEventNode.write_string( "parameter2" , ppAction->getParameter2() );
1214 midiEventNode.write_string( "parameter3" , ppAction->getParameter3() );
1215 }
1216 }
1217
1218 return doc.write( sPreferencesFilename );
1219}
1220
1222 const QString s = QString( sDriver ).toLower();
1223 if ( s == "auto" ) {
1224 return AudioDriver::Auto;
1225 }
1226 else if ( s == "jack" || s == "jackaudio") {
1227 return AudioDriver::Jack;
1228 }
1229 else if ( s == "oss" ) {
1230 return AudioDriver::Oss;
1231 }
1232 else if ( s == "alsa" ) {
1233 return AudioDriver::Alsa;
1234 }
1235 else if ( s == "pulseaudio" || s == "pulse" ) {
1237 }
1238 else if ( s == "coreaudio" || s == "core" ) {
1240 }
1241 else if ( s == "portaudio" || s == "port" ) {
1243 }
1244 else {
1245 if ( Logger::isAvailable() ) {
1246 ERRORLOG( QString( "Unable to parse driver [%1]" ). arg( sDriver ) );
1247 }
1248 return AudioDriver::None;
1249 }
1250}
1251
1253 switch ( driver ) {
1254 case AudioDriver::Auto:
1255 return "Auto";
1256 case AudioDriver::Jack:
1257 return "JACK";
1258 case AudioDriver::Oss:
1259 return "OSS";
1260 case AudioDriver::Alsa:
1261 return "ALSA";
1263 return "PulseAudio";
1265 return "CoreAudio";
1267 return "PortAudio";
1268 case AudioDriver::Disk:
1269 return "Disk";
1270 case AudioDriver::Fake:
1271 return "Fake";
1272 case AudioDriver::Null:
1273 return "Null";
1274 case AudioDriver::None:
1275 return "nullptr";
1276 default:
1277 return "Unhandled driver type";
1278 }
1279}
1280
1282 // Check whether the Logger is already available.
1283 const bool bUseLogger = Logger::isAvailable();
1284
1285#ifndef H2CORE_HAVE_JACK
1286 if ( bUseLogger ) {
1287 INFOLOG( "Hydrogen was compiled without JACK support." );
1288 }
1289 return false;
1290#else
1291 #ifndef H2CORE_HAVE_DYNAMIC_JACK_CHECK
1292 if ( bUseLogger ) {
1293 INFOLOG( "JACK support enabled." );
1294 }
1295 return true;
1296 #else
1304 auto checkExecutable = [&]( const QString& sExecutable,
1305 const QString& sOption ) {
1306 QProcess process;
1307 process.start( sExecutable, QStringList( sOption ) );
1308 process.waitForFinished( -1 );
1309
1310 if ( process.exitCode() != 0 ) {
1311 return QString( "" );
1312 }
1313
1314 QString sStdout = process.readAllStandardOutput();
1315 if ( sStdout.isEmpty() ) {
1316 return QString( "No output" );
1317 }
1318
1319 return QString( sStdout.trimmed() );
1320 };
1321
1322
1323 bool bJackSupport = false;
1324
1325 // Classic JACK
1326 QString sCapture = checkExecutable( "jackd", "--version" );
1327 if ( ! sCapture.isEmpty() ) {
1328 bJackSupport = true;
1329 if ( bUseLogger ) {
1330 INFOLOG( QString( "'jackd' of version [%1] found." )
1331 .arg( sCapture ) );
1332 }
1333 }
1334
1335 // JACK compiled with DBus support (maybe this one is packaged but
1336 // the classical one isn't).
1337 //
1338 // `jackdbus` is supposed to be run by the DBus message daemon and
1339 // does not have proper CLI options. But it does not fail by
1340 // passing a `-h` either and this will serve for checking its
1341 // presence.
1342 sCapture = checkExecutable( "jackdbus", "-h" );
1343 if ( ! sCapture.isEmpty() ) {
1344 bJackSupport = true;
1345 if ( bUseLogger ) {
1346 INFOLOG( "'jackdbus' found." );
1347 }
1348 }
1349
1350 // Pipewire JACK interface
1351 //
1352 // `pw-jack` has no version query CLI option (yet). But showing
1353 // the help will serve for checking its presence.
1354 sCapture = checkExecutable( "pw-jack", "-h" );
1355 if ( ! sCapture.isEmpty() ) {
1356 bJackSupport = true;
1357 if ( bUseLogger ) {
1358 INFOLOG( "'pw-jack' found." );
1359 }
1360 }
1361
1362 if ( bUseLogger ) {
1363 if ( bJackSupport ) {
1364 INFOLOG( "Dynamic JACK discovery succeeded. JACK support enabled." );
1365 }
1366 else {
1367 WARNINGLOG( "Dynamic JACK discovery failed. JACK support disabled." );
1368 }
1369 }
1370
1371 return bJackSupport;
1372 #endif
1373#endif
1374}
1375
1376std::vector<Preferences::AudioDriver> Preferences::getSupportedAudioDrivers() {
1377
1378 std::vector<AudioDriver> drivers;
1379
1380 // We always do a fresh check. Maybe dynamical discovery will yield a
1381 // different result this time.
1382 bool bJackSupported = checkJackSupport();
1383
1384 // The order of the assigned drivers is important as Hydrogen uses
1385 // it when trying different drivers in case "Auto" was selected.
1386#if defined(WIN32)
1387 #ifdef H2CORE_HAVE_PORTAUDIO
1388 drivers.push_back( AudioDriver::PortAudio );
1389 #endif
1390 if ( bJackSupported ) {
1391 drivers.push_back( AudioDriver::Jack );
1392 }
1393#elif defined(__APPLE__)
1394 #ifdef H2CORE_HAVE_COREAUDIO
1395 drivers.push_back( AudioDriver::CoreAudio );
1396 #endif
1397 if ( bJackSupported ) {
1398 drivers.push_back( AudioDriver::Jack );
1399 }
1400 #ifdef H2CORE_HAVE_PULSEAUDIO
1401 drivers.push_back( AudioDriver::PulseAudio );
1402 #endif
1403 #ifdef H2CORE_HAVE_PORTAUDIO
1404 drivers.push_back( AudioDriver::PortAudio );
1405 #endif
1406#else /* Linux */
1407 if ( bJackSupported ) {
1408 drivers.push_back( AudioDriver::Jack );
1409 }
1410 #ifdef H2CORE_HAVE_PULSEAUDIO
1411 drivers.push_back( AudioDriver::PulseAudio );
1412 #endif
1413 #ifdef H2CORE_HAVE_ALSA
1414 drivers.push_back( AudioDriver::Alsa );
1415 #endif
1416 #ifdef H2CORE_HAVE_OSS
1417 drivers.push_back( AudioDriver::Oss );
1418 #endif
1419 #ifdef H2CORE_HAVE_PORTAUDIO
1420 drivers.push_back( AudioDriver::PortAudio );
1421 #endif
1422#endif
1423
1424 return drivers;
1425}
1426
1427
1428void Preferences::setMostRecentFX( QString FX_name )
1429{
1430 int pos = m_recentFX.indexOf( FX_name );
1431
1432 if ( pos != -1 ) {
1433 m_recentFX.removeAt( pos );
1434 }
1435
1436 m_recentFX.push_front( FX_name );
1437}
1438
1440WindowProperties Preferences::readWindowProperties( XMLNode parent, const QString& windowName, WindowProperties defaultProp )
1441{
1442 WindowProperties prop = defaultProp;
1443
1444 XMLNode windowPropNode = parent.firstChildElement( windowName );
1445 if ( windowPropNode.isNull() ) {
1446 WARNINGLOG( "Error reading configuration file: " + windowName + " node not found" );
1447 } else {
1448 prop.visible = windowPropNode.read_bool( "visible", true, false, false );
1449 prop.x = windowPropNode.read_int( "x", prop.x, false, false );
1450 prop.y = windowPropNode.read_int( "y", prop.y, false, false );
1451 prop.width = windowPropNode.read_int( "width", prop.width, false, false );
1452 prop.height = windowPropNode.read_int( "height", prop.height, false, false );
1453 prop.m_geometry = QByteArray::fromBase64( windowPropNode.read_string( "geometry",
1454 prop.m_geometry.toBase64(), false, true )
1455 .toUtf8() );
1456 }
1457
1458 return prop;
1459}
1460
1461
1462
1464void Preferences::writeWindowProperties( XMLNode parent, const QString& windowName, const WindowProperties& prop )
1465{
1466 XMLNode windowPropNode = parent.createNode( windowName );
1467
1468 windowPropNode.write_bool( "visible", prop.visible );
1469 windowPropNode.write_int( "x", prop.x );
1470 windowPropNode.write_int( "y", prop.y );
1471 windowPropNode.write_int( "width", prop.width );
1472 windowPropNode.write_int( "height", prop.height );
1473 windowPropNode.write_string( "geometry", QString( prop.m_geometry.toBase64() ) );
1474}
1475
1476// -----------------------
1477
1478
1479
1481{
1482// infoLog( "INIT" );
1483 x = 0;
1484 y = 0;
1485 width = 0;
1486 height = 0;
1487 visible = true;
1488}
1489
1490
1492 : x(other.x),
1493 y(other.y),
1494 width(other.width),
1495 height(other.height),
1496 visible(other.visible)
1497{
1498// infoLog( "INIT" );
1499}
1500
1501
1502
1504{
1505// infoLog( "DESTROY" );
1506}
1507
1508};
#define INFOLOG(x)
Definition Object.h:240
#define WARNINGLOG(x)
Definition Object.h:241
#define ERRORLOG(x)
Definition Object.h:242
static QStringList getDevices()
Use the name hints to build a list of potential device names.
static QString scripts_dir()
returns user scripts path
static bool file_executable(const QString &path, bool silent=false)
returns true if the given path is an existing executable regular file
static AudioFormat AudioFormatFromSuffix(const QString &sFile, bool bSilent=false)
Determines the audio format of the provided filename or path based on its suffix.
static QString usr_config_path()
static QString songs_dir()
returns user songs path
static QString playlists_dir()
returns user playlist path
static const QString & getPreferencesOverwritePath()
Definition Filesystem.h:590
static QString sys_config_path()
returns system config path
static QString AudioFormatToSuffix(const AudioFormat &format, bool bSilent=false)
Converts format to the default lower case suffix of the format.
static bool file_readable(const QString &path, bool silent=false)
returns true if the given path is an existing readable regular file
static QString patterns_dir()
returns user patterns path
FontSize
Enables custom scaling of the font size in the GUI.
Definition Theme.h:184
static float FALLOFF_NORMAL
Definition Theme.h:139
static bool isAvailable()
Checks whether the Logger instances was already created and can be used by other parts of Hydrogen.
Definition Logger.h:88
static QString EventToQString(Event event)
Manager for User Preferences File (singleton)
Definition Preferences.h:79
WindowProperties audioEngineInfoProperties
void writeWindowProperties(XMLNode parent, const QString &windowName, const WindowProperties &prop)
Write the xml nodes related to window properties.
QString m_sLastExportPatternAsDirectory
static AudioDriver parseAudioDriver(const QString &sDriver)
int m_bJackTimebaseMode
Specifies if Hydrogen support the of JACK Timebase protocol.
Filesystem::AudioFormat m_exportFormat
bool m_bShowExportDrumkitAttributionWarning
WindowProperties m_playlistDialogProperties
QString m_sDefaultEditor
Default text editor (used by Playlisteditor)
void setPatternColors(std::vector< QColor > patternColors)
bool __useTimelineBpm
Whether to use local speeds specified along the Timeline or a constant tempo for the whole Song in Hy...
JackTrackOutputMode m_JackTrackOutputMode
Specifies which audio settings will be applied to the sample supplied in the JACK per track output po...
bool m_bUseRelativeFilenamesForPlaylists
void setLadspaProperties(unsigned nFX, const WindowProperties &prop)
WindowProperties songEditorProperties
void setMixerProperties(const WindowProperties &prop)
void setPatternEditorProperties(const WindowProperties &prop)
bool m_bOscFeedbackEnabled
Whether to send the current state of Hydrogen to the OSC clients.
void setQTStyle(const QString &sStyle)
const QString & getApplicationFontFamily() const
void setMostRecentFX(QString)
void setSongEditorProperties(const WindowProperties &prop)
std::vector< QString > m_recentFiles
const QString & getQTStyle()
WindowProperties mixerProperties
unsigned m_nPatternEditorGridWidth
unsigned m_nSampleRate
Sample rate of the audio.
bool m_bShowNoteOverwriteWarning
Last song used.
WindowProperties instrumentRackProperties
QString m_sPortAudioHostAPI
static std::vector< AudioDriver > getSupportedAudioDrivers()
bool savePreferences()
Save the preferences file.
bool m_bPatternEditorUsingTriplets
void setVisiblePatternColors(int nValue)
void setColoringMethod(InterfaceTheme::ColoringMethod coloringMethod)
const QString & getLevel3FontFamily() const
void setInstrumentRackProperties(const WindowProperties &prop)
InterfaceTheme::Layout getDefaultUILayout()
bool m_bOscServerEnabled
Whether to start the OscServer thread.
QString m_sMidiOutputPortName
unsigned m_nSongEditorGridHeight
void setApplicationFontFamily(const QString &family)
QString m_sLastImportDrumkitDirectory
QString m_sLastExportSongDirectory
QString m_sLastOpenPatternDirectory
static void create_instance()
If __instance equals 0, a new Preferences singleton will be created and stored in it.
int m_nMaxLayers
Maximum number of layers to be used in the Instrument editor.
unsigned m_nPatternEditorGridHeight
int getMaxPatternColors() const
WindowProperties m_directorProperties
void setLevel3FontFamily(const QString &family)
void setDirectorProperties(const WindowProperties &prop)
void setPlaylistDialogProperties(const WindowProperties &prop)
static QString audioDriverToQString(const AudioDriver &driver)
QString m_sMidiDriver
MIDI driver.
unsigned m_nSongEditorGridWidth
bool m_bShowExportDrumkitCopyleftWarning
QString m_lastPlaylistFilename
QString m_sLastExportThemeDirectory
void setMainFormProperties(const WindowProperties &prop)
void setAudioEngineInfoProperties(const WindowProperties &prop)
std::list< QString > sServerList
@ postFader
Applies layer, component, and instrument gain, note and instrument pan, note velocity,...
@ preFader
Only layer gain and note velocity will be applied to the samples.
bool loadPreferences(bool bGlobal)
Load the preferences file.
QString m_sLastExportDrumkitDirectory
QString m_sLastExportMidiDirectory
AudioDriver m_audioDriver
Audio driver.
QString m_sLastImportThemeDirectory
std::list< QString > m_patternCategories
FontTheme::FontSize getFontSize() const
bool m_bJackConnectDefaults
Toggles auto-connecting of the main stereo output ports to the system's default ports when starting t...
unsigned m_nMaxNotes
max notes
bool m_bUseLash
Show development version warning?
void setFontSize(FontTheme::FontSize fontSize)
InterfaceTheme::ColoringMethod getColoringMethod() const
bool m_bMidiDiscardNoteAfterAction
bool m_useTheRubberbandBpmChangeEvent
rubberband bpm change queue
bool m_bUseMetronome
If set to true, samples of the metronome will be added to H2Core::AudioEngine::m_songNoteQueue and th...
QString m_sLastOpenLayerDirectory
WindowProperties mainFormProperties
QString m_sOSSDevice
Device used for output.
InterfaceTheme::ScalingPolicy getUIScalingPolicy()
std::vector< QColor > getPatternColors() const
QString m_sLastSaveSongAsDirectory
QString m_rubberBandCLIexecutable
Rubberband CLI.
QString m_sLastAddSongToPlaylistDirectory
WindowProperties patternEditorProperties
bool m_bJackTimebaseEnabled
External applications with a faulty JACK Timebase implementation can mess up the transport within Hyd...
void setDefaultUILayout(InterfaceTheme::Layout layout)
const QString & getLevel2FontFamily() const
int m_nMaxBars
Maximum number of bars shown in the Song Editor at once.
QString m_sLastPlaylistScriptDirectory
bool m_bShowExportSongLicenseWarning
int getVisiblePatternColors() const
float m_fMetronomeVolume
Metronome volume FIXME: remove this volume!!
static bool checkJackSupport()
Attempts to call several JACK executables in order to check for existing JACK support.
QString m_sLastExportLilypondDirectory
void setMixerFalloffSpeed(float value)
int m_nOscTemporaryPort
In case m_nOscServerPort is already occupied by another client, the alternative - random - port numbe...
WindowProperties readWindowProperties(XMLNode parent, const QString &windowName, WindowProperties defaultProp)
Read the xml nodes related to window properties.
bool m_bShowExportDrumkitLicenseWarning
static QString getNullMidiPort()
Choice of m_sMidiPortName and m_sMidiOutputPortName in case no port/device was selected.
QStringList m_recentFX
float m_fExportCompressionLevel
static Preferences * __instance
Object holding the current Preferences singleton.
int m_nOscServerPort
Port number the OscServer will be started at.
bool m_bJackTrackOuts
If set to true, JackAudioDriver::makeTrackOutputs() will create two individual left and right output ...
void setLevel2FontFamily(const QString &family)
int m_bJackTransportMode
Specifies whether or not Hydrogen will use the JACK transport system.
QString m_sPreferredLanguage
QString m_sLastOpenSongDirectory
@ NO_JACK_TRANSPORT
Specifies whether or not to use JACK transport capabilities.
@ USE_JACK_TRANSPORT
Specifies whether or not to use JACK transport capabilities.
Definition Preferences.h:90
@ NO_JACK_TIMEBASE_CONTROL
Specifies that Hydrogen should not be in control of JACK Timebase information.
@ USE_JACK_TIMEBASE_CONTROL
Specifies that Hydrogen should attempt to acquire JACK Timebase control.
std::shared_ptr< Theme > m_pTheme
unsigned m_nBufferSize
Buffer size of the audio.
QString m_sLastPlaylistDirectory
void setUIScalingPolicy(InterfaceTheme::ScalingPolicy policy)
QString m_sLastOpenPlaybackTrackDirectory
WindowProperties m_ladspaProperties[MAX_FX]
static void readColorTheme(XMLNode parent, std::shared_ptr< Theme > pTheme)
Definition Theme.cpp:405
static void writeColorTheme(XMLNode *parent, std::shared_ptr< Theme > pTheme)
Definition Theme.cpp:312
XMLDoc is a subclass of QDomDocument with read and write methods.
Definition Xml.h:182
XMLNode set_root(const QString &node_name, const QString &xmlns=nullptr)
create the xml header and root node
Definition Xml.cpp:336
bool read(const QString &filepath, bool bSilent=false)
read the content of an xml file
Definition Xml.cpp:277
bool write(const QString &filepath)
write itself into a file
Definition Xml.cpp:311
XMLNode is a subclass of QDomNode with read and write values methods.
Definition Xml.h:39
int read_int(const QString &node, int default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads an integer stored into a child node
Definition Xml.cpp:151
bool read_bool(const QString &node, bool default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads a boolean stored into a child node
Definition Xml.cpp:165
QColor read_color(const QString &node, const QColor &defaultValue=QColor(97, 167, 251), bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
Definition Xml.cpp:88
QString read_string(const QString &node, const QString &default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads a string stored into a child node
Definition Xml.cpp:76
float read_float(const QString &node, float default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads a float stored into a child node
Definition Xml.cpp:120
void write_color(const QString &node, const QColor &color)
Definition Xml.cpp:254
void write_float(const QString &node, const float value)
write a float into a child node
Definition Xml.cpp:261
XMLNode createNode(const QString &name)
create a new XMLNode that has to be appended into de XMLDoc
Definition Xml.cpp:44
void write_string(const QString &node, const QString &value)
write a string into a child node
Definition Xml.cpp:250
void write_bool(const QString &node, const bool value)
write a boolean into a child node
Definition Xml.cpp:269
void write_int(const QString &node, const int value)
write an integer into a child node
Definition Xml.cpp:265
The MidiMap maps MidiActions to MidiEvents.
Definition MidiMap.h:38
void registerMMCEvent(QString, std::shared_ptr< Action >)
Sets up the relation between a mmc event and an action.
Definition MidiMap.cpp:96
void registerNoteEvent(int, std::shared_ptr< Action >)
Sets up the relation between a note event and an action.
Definition MidiMap.cpp:130
std::multimap< int, std::shared_ptr< Action > > getCCActionMap() const
Definition MidiMap.h:128
void registerPCEvent(std::shared_ptr< Action >)
Sets up the relation between a program change and an action.
Definition MidiMap.cpp:190
std::vector< std::shared_ptr< Action > > getPCActions() const
Returns the pc action which was linked to the given event.
Definition MidiMap.h:131
std::multimap< QString, std::shared_ptr< Action > > getMMCActionMap() const
Definition MidiMap.h:122
static void create_instance()
If __instance equals 0, a new MidiMap singleton will be created and stored in it.
Definition MidiMap.cpp:64
std::multimap< int, std::shared_ptr< Action > > getNoteActionMap() const
Definition MidiMap.h:125
static MidiMap * get_instance()
Returns a pointer to the current MidiMap singleton stored in __instance.
Definition MidiMap.h:65
static void reset_instance()
Convenience function calling reset() on the current MidiMap __instance.
Definition MidiMap.cpp:71
void registerCCEvent(int, std::shared_ptr< Action >)
Sets up the relation between a cc event and an action.
Definition MidiMap.cpp:161
#define MAX_FX
Maximum number of effects.
Definition config.dox:83
std::string get_version()
Returns the current Hydrogen version string.
Definition Version.cpp:30
static const std::string version
Definition Version.cpp:28