hydrogen 1.2.6
Filesystem.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 <core/Basics/Drumkit.h>
24#include <core/config.h>
25#include <core/EventQueue.h>
27#include <core/Hydrogen.h>
29
30#include <QtCore/QDir>
31#include <QtCore/QFile>
32#include <QtCore/QFileInfo>
33#include <QtCore/QCoreApplication>
34#include <QDateTime>
35#include <QRegularExpression>
36
37#ifdef H2CORE_HAVE_OSC
38#include <core/NsmClient.h>
39#endif
40
41// directories
42#define LOCAL_DATA_PATH "data/"
43#define CACHE "cache/"
44#define DEMOS "demo_songs/"
45#define DOC "doc/"
46#define DRUMKITS "drumkits/"
47#define I18N "i18n/"
48#define IMG "img/"
49#define PATTERNS "patterns/"
50#define PLAYLISTS "playlists/"
51#define PLUGINS "plugins/"
52#define REPOSITORIES "repositories/"
53#define SCRIPTS "scripts/"
54#define SONGS "songs/"
55#define THEMES "themes/"
56#define TMP "hydrogen/"
57#define XSD "xsd/"
58
59
60// files
62#define CLICK_SAMPLE "click.wav"
63#define EMPTY_SAMPLE "emptySample.wav"
64#define DEFAULT_SONG "DefaultSong"
65#define EMPTY_SONG_BASE "emptySong"
66#define USR_CONFIG "hydrogen.conf"
67#define SYS_CONFIG "hydrogen.default.conf"
68#define LOG_FILE "hydrogen.log"
69#define DRUMKIT_XML "drumkit.xml"
70#define DRUMKIT_XSD "drumkit.xsd"
71#define DRUMPAT_XSD "drumkit_pattern.xsd"
72#define DRUMKIT_DEFAULT_KIT "GMRockKit"
73#define PLAYLIST_XSD "playlist.xsd"
74
75#define AUTOSAVE "autosave"
76
77#define UNTITLED_SONG "Untitled Song"
78#define UNTITLED_PLAYLIST "untitled.h2playlist"
79
80// filters
81#define PATTERN_FILTER "*.h2pattern"
82#define PLAYLIST_FILTER "*.h2playlist"
83#define SONG_FILTER "*.h2song"
84#define THEME_FILTER "*.h2theme"
85
86namespace H2Core
87{
88
89Logger* Filesystem::__logger = nullptr;
90
91const QString Filesystem::scripts_ext = ".sh";
92const QString Filesystem::songs_ext = ".h2song";
93const QString Filesystem::themes_ext = ".h2theme";
94const QString Filesystem::patterns_ext = ".h2pattern";
95const QString Filesystem::playlist_ext = ".h2playlist";
96const QString Filesystem::drumkit_ext = ".h2drumkit";
97const QString Filesystem::scripts_filter_name = "Hydrogen Scripts (*.sh)";
98const QString Filesystem::songs_filter_name = "Hydrogen Songs (*.h2song)";
99const QString Filesystem::themes_filter_name = "Hydrogen Theme (*.h2theme)";
100const QString Filesystem::patterns_filter_name = "Hydrogen Patterns (*.h2pattern)";
101const QString Filesystem::playlists_filter_name = "Hydrogen Playlists (*.h2playlist)";
102
106
107#ifdef Q_OS_MACX
108 QString Filesystem::__usr_log_path =QDir::homePath().append( "/Library/Application Support/Hydrogen/" LOG_FILE );
109#elif WIN32
110 QString Filesystem::__usr_log_path = QDir::homePath().append( "/.hydrogen/" LOG_FILE );
111#else
112 QString Filesystem::__usr_log_path = QDir::homePath().append( "/" H2_USR_PATH "/" LOG_FILE);
113#endif
114
115
117
119
120std::vector<Filesystem::AudioFormat> Filesystem::m_supportedAudioFormats = {
121 AudioFormat::Wav,
122 AudioFormat::Aif,
123 AudioFormat::Aifc,
124 AudioFormat::Aiff,
125 AudioFormat::Au,
126 AudioFormat::Caf,
127 AudioFormat::Voc,
128#ifdef H2CORE_HAVE_FLAC_SUPPORT
129 AudioFormat::Ogg,
130 AudioFormat::Flac,
131#endif
132#ifdef H2CORE_HAVE_OPUS_SUPPORT
133 AudioFormat::Opus,
134#endif
135#ifdef H2CORE_HAVE_MP3_SUPPORT
136 AudioFormat::Mp3,
137#endif
138 AudioFormat::W64
139};
140
141QString Filesystem::AudioFormatToSuffix( const AudioFormat& format, bool bSilent ) {
142 switch( format ) {
143 case AudioFormat::Aif:
146 return "aiff";
147 case AudioFormat::Au:
148 return "au";
149 case AudioFormat::Caf:
150 return "caf";
152 return "flac";
153 case AudioFormat::Mp3:
154 return "mp3";
155 case AudioFormat::Ogg:
156 return "ogg";
158 return "opus";
159 case AudioFormat::Voc:
160 return "voc";
161 case AudioFormat::W64:
162 return "w64";
163 case AudioFormat::Wav:
164 return "wav";
166 default:
167 if ( ! bSilent ) {
168 ERRORLOG( "Unknown audio format" );
169 }
170 return "";
171 }
172}
173
175 bool bSilent ) {
176 const QString sPathLower = sPath.toLower();
177 if ( sPathLower.endsWith( "aiff" ) ) {
178 return AudioFormat::Aif;
179 }
180 else if ( sPathLower.endsWith( "au" ) ) {
181 return AudioFormat::Au;
182 }
183 else if ( sPathLower.endsWith( "caf" ) ) {
184 return AudioFormat::Caf;
185 }
186 else if ( sPathLower.endsWith( "flac" ) ) {
187 return AudioFormat::Flac;
188 }
189 else if ( sPathLower.endsWith( "mp3" ) ) {
190 return AudioFormat::Mp3;
191 }
192 else if ( sPathLower.endsWith( "ogg" ) ) {
193 return AudioFormat::Ogg;
194 }
195 else if ( sPathLower.endsWith( "opus" ) ) {
196 return AudioFormat::Opus;
197 }
198 else if ( sPathLower.endsWith( "voc" ) ) {
199 return AudioFormat::Voc;
200 }
201 else if ( sPathLower.endsWith( "w64" ) ) {
202 return AudioFormat::W64;
203 }
204 else if ( sPathLower.endsWith( "wav" ) ) {
205 return AudioFormat::Wav;
206 } else {
207 if ( ! bSilent ) {
208 ERRORLOG( QString( "Unknown suffix in [%1]" ).arg( sPath ) );
209 }
211 }
212}
213
214bool Filesystem::bootstrap( Logger* logger, const QString& sSysDataPath,
215 const QString& sUsrDataPath,
216 const QString& sUserConfigPath,
217 const QString& sLogFile )
218{
219 if( __logger==nullptr && logger!=nullptr ) {
221 } else {
222 return false;
223 }
224
225 // A QCoreApplication instance is needed for applicationDirPath etc.
226 assert( QCoreApplication::instance() != nullptr );
227
228#ifdef Q_OS_MACX
229#ifdef H2CORE_HAVE_BUNDLE
230 // Bundle: Prepare hydrogen to use path names which are used in app bundles: http://en.wikipedia.org/wiki/Application_Bundle
231 __sys_data_path = QCoreApplication::applicationDirPath().append( "/../Resources/data/" ) ;
232#else
233 __sys_data_path = QCoreApplication::applicationDirPath().append( "/data/" ) ;
234#endif
235 __usr_data_path = QDir::homePath().append( "/Library/Application Support/Hydrogen/data/" );
236 __usr_cfg_path = QDir::homePath().append( "/Library/Application Support/Hydrogen/" USR_CONFIG );
237#elif WIN32
238 __sys_data_path = QCoreApplication::applicationDirPath().append( "/data/" ) ;
239 __usr_data_path = QDir::homePath().append( "/.hydrogen/data/" ) ;
240 __usr_cfg_path = QDir::homePath().append( "/.hydrogen/" USR_CONFIG ) ;
241#else
242#ifdef H2CORE_HAVE_APPIMAGE
243 __sys_data_path = absolute_path( QCoreApplication::applicationDirPath().append( "/../share/hydrogen/data/" ) ) ;
244#else
245 __sys_data_path = H2_SYS_PATH "/data/";
246#endif
247 __usr_data_path = QDir::homePath().append( "/" H2_USR_PATH "/data/" );
248 __usr_cfg_path = QDir::homePath().append( "/" H2_USR_PATH "/" USR_CONFIG );
249#endif
250 if ( ! sSysDataPath.isEmpty() ) {
251 INFOLOG( QString( "Using custom system data folder [%1]" )
252 .arg( sSysDataPath ) );
253 __sys_data_path = sSysDataPath;
254 // Sanity check
255 if ( ! __sys_data_path.endsWith( QDir::separator() ) ) {
256 __sys_data_path.append( QDir::separator() );
257 }
258 }
259
260 if ( ! sUsrDataPath.isEmpty() ) {
261 INFOLOG( QString( "Using custom user data folder [%1]" )
262 .arg( sUsrDataPath ) );
263 __usr_data_path = sUsrDataPath;
264 // Sanity check
265 if ( ! __usr_data_path.endsWith( QDir::separator() ) ) {
266 __usr_data_path.append( QDir::separator() );
267 }
268 }
269
270 if ( ! sUserConfigPath.isEmpty() ) {
271 INFOLOG( QString( "Using custom user-level config file [%1]" )
272 .arg( sUserConfigPath ) );
273 __usr_cfg_path = sUserConfigPath;
274 }
275
276 if ( ! sLogFile.isEmpty() ) {
277 // No need for an info log. This is done within the bootstrap of the
278 // logger.
280 }
281
282 if( !dir_readable( __sys_data_path ) ) {
283 __sys_data_path = QCoreApplication::applicationDirPath().append( "/" LOCAL_DATA_PATH );
284 ERRORLOG( QString( "will use local data path : %1" ).arg( __sys_data_path ) );
285 }
286
287 char* ladspaPath = getenv( "LADSPA_PATH" );
288 if ( ladspaPath ) {
289 INFOLOG( "Found LADSPA_PATH environment variable" );
290 QString sLadspaPath = QString::fromLocal8Bit( ladspaPath );
291 int pos;
292 while ( ( pos = sLadspaPath.indexOf( ":" ) ) != -1 ) {
293 QString sPath = sLadspaPath.left( pos );
294 __ladspa_paths << QFileInfo(sPath).canonicalFilePath();
295 sLadspaPath = sLadspaPath.mid( pos + 1, sLadspaPath.length() );
296 }
297 __ladspa_paths << QFileInfo( sLadspaPath ).canonicalFilePath();
298 } else {
299#ifdef Q_OS_MACX
300 __ladspa_paths << QFileInfo( QCoreApplication::applicationDirPath(), "/../Resources/plugins" ).canonicalFilePath();
301 __ladspa_paths << QFileInfo( "/Library/Audio/Plug-Ins/LADSPA/" ).canonicalFilePath();
302 __ladspa_paths << QFileInfo( QDir::homePath(), "/Library/Audio/Plug-Ins/LADSPA" ).canonicalFilePath();
303#else
304 __ladspa_paths << QFileInfo( "/usr/lib/ladspa" ).canonicalFilePath();
305 __ladspa_paths << QFileInfo( "/usr/local/lib/ladspa" ).canonicalFilePath();
306 __ladspa_paths << QFileInfo( "/usr/lib64/ladspa" ).canonicalFilePath();
307 __ladspa_paths << QFileInfo( "/usr/local/lib64/ladspa" ).canonicalFilePath();
308#endif
309 }
310 __ladspa_paths.sort();
311 __ladspa_paths.removeDuplicates();
312 if ( !__ladspa_paths.isEmpty() && __ladspa_paths.at( 0 ).isEmpty() ) {
313 __ladspa_paths.removeFirst();
314 }
315 // we want this first
317 __ladspa_paths.removeDuplicates();
318
319 bool ret = check_sys_paths();
320 ret &= check_usr_paths();
321 info();
322 return ret;
323}
324
325bool Filesystem::check_permissions( const QString& path, const int perms, bool silent )
326{
327 QFileInfo fi( path );
328 if( ( perms & is_file ) && ( perms & is_writable ) && !fi.exists() ) {
329 QFileInfo folder( path.left( path.lastIndexOf( "/" ) ) );
330 if( !folder.isDir() ) {
331 if( !silent ) {
332 ERRORLOG( QString( "%1 is not a directory" ).arg( folder.fileName() ) );
333 }
334 return false;
335 }
336 if( !folder.isWritable() ) {
337 if( !silent ) {
338 ERRORLOG( QString( "%1 is not writable" ).arg( folder.fileName() ) );
339 }
340 return false;
341 }
342 return true;
343 }
344 if( ( perms & is_dir ) && !fi.isDir() ) {
345 if( !silent ) {
346 ERRORLOG( QString( "%1 is not a directory" ).arg( path ) );
347 }
348 return false;
349 }
350 if( ( perms & is_file ) && !fi.isFile() ) {
351 if( !silent ) {
352 ERRORLOG( QString( "%1 is not a file" ).arg( path ) );
353 }
354 return false;
355 }
356 if( ( perms & is_readable ) && !fi.isReadable() ) {
357 if( !silent ) {
358 ERRORLOG( QString( "%1 is not readable" ).arg( path ) );
359 }
360 return false;
361 }
362 if( ( perms & is_writable ) && !fi.isWritable() ) {
363 if( !silent ) {
364 ERRORLOG( QString( "%1 is not writable" ).arg( path ) );
365 }
366 return false;
367 }
368 if( ( perms & is_executable ) && !fi.isExecutable() ) {
369 if( !silent ) {
370 ERRORLOG( QString( "%1 is not executable" ).arg( path ) );
371 }
372 return false;
373 }
374 return true;
375}
376
377bool Filesystem::file_exists( const QString& path, bool silent )
378{
379 return check_permissions( path, is_file, silent );
380}
381bool Filesystem::file_readable( const QString& path, bool silent )
382{
383 return check_permissions( path, is_file|is_readable, silent );
384}
385bool Filesystem::file_writable( const QString& path, bool silent )
386{
387 return check_permissions( path, is_file|is_readable|is_writable, silent );
388}
389bool Filesystem::file_executable( const QString& path, bool silent )
390{
391 return check_permissions( path, is_file|is_executable, silent );
392}
393bool Filesystem::dir_exists( const QString& path, bool silent )
394{
395 return check_permissions( path, is_dir, silent );
396}
397bool Filesystem::dir_readable( const QString& path, bool silent )
398{
399 return check_permissions( path, is_dir|is_readable|is_executable, silent );
400}
401bool Filesystem::dir_writable( const QString& path, bool silent )
402{
403 return check_permissions( path, is_dir|is_writable, silent );
404}
405
406bool Filesystem::mkdir( const QString& path )
407{
408 if ( !QDir( "/" ).mkpath( QDir( path ).absolutePath() ) ) {
409 ERRORLOG( QString( "unable to create directory : %1" ).arg( path ) );
410 return false;
411 }
412 return true;
413}
414
415bool Filesystem::path_usable( const QString& path, bool create, bool silent )
416{
417 if ( !QDir( path ).exists() ) {
418 if ( !silent ) {
419 INFOLOG( QString( "create user directory : %1" ).arg( path ) );
420 }
421 if ( create && !QDir( "/" ).mkpath( path ) ) {
422 ERRORLOG( QString( "unable to create user directory : %1" ).arg( path ) );
423 return false;
424 }
425 }
426 return dir_readable( path, silent ) && dir_writable( path, silent );
427}
428
429bool Filesystem::write_to_file( const QString& dst, const QString& content )
430{
431 if ( !file_writable( dst ) ) {
432 ERRORLOG( QString( "unable to write to %1" ).arg( dst ) );
433 return false;
434 }
435 QFile file( dst );
436 if ( !file.open( QIODevice::WriteOnly ) ) {
437 ERRORLOG( QString( "unable to write to %1" ).arg( dst ) );
438 return false;
439 }
440 const auto contentUtf8 = content.toUtf8();
441 file.write( contentUtf8.data() );
442 file.close();
443
444 return true;
445}
446
447bool Filesystem::file_copy( const QString& src, const QString& dst, bool overwrite, bool bSilent )
448{
449 if( !overwrite && file_exists( dst, true ) ) {
450 WARNINGLOG( QString( "do not overwrite %1 with %2 as it already exists" ).arg( dst ).arg( src ) );
451 return true;
452 }
453 if ( !file_readable( src ) ) {
454 ERRORLOG( QString( "unable to copy %1 to %2, %1 is not readable" ).arg( src ).arg( dst ) );
455 return false;
456 }
457 if ( !file_writable( dst ) ) {
458 ERRORLOG( QString( "unable to copy %1 to %2, %2 is not writable" ).arg( src ).arg( dst ) );
459 return false;
460 }
461 if ( ! bSilent ) {
462 INFOLOG( QString( "copy %1 to %2" ).arg( src ).arg( dst ) );
463 }
464
465 // Since QFile::copy does not overwrite, we have to make sure the
466 // destination does not exist.
467 if ( overwrite && file_exists( dst, true ) ) {
468 rm( dst, true, bSilent );
469 }
470
471 return QFile::copy( src, dst );
472}
473
474bool Filesystem::rm( const QString& path, bool recursive, bool bSilent )
475{
476 if ( check_permissions( path, is_file, true ) ) {
477 QFile file( path );
478 bool ret = file.remove();
479 if( !ret ) {
480 ERRORLOG( QString( "unable to remove file %1" ).arg( path ) );
481 }
482 return ret;
483 }
484 if ( !check_permissions( path, is_dir, true ) ) {
485 ERRORLOG( QString( "%1 is neither a file nor a directory ?!?!" ).arg( path ) );
486 return false;
487 }
488 if ( !recursive ) {
489 QDir dir;
490 bool ret = dir.rmdir( path );
491 if( !ret ) {
492 ERRORLOG( QString( "unable to remove dir %1 without recursive argument, maybe it is not empty?" ).arg( path ) );
493 }
494 return ret;
495 }
496 return rm_fr( path, bSilent );
497}
498
499bool Filesystem::rm_fr( const QString& path, bool bSilent )
500{
501 if ( ! bSilent ) {
502 INFOLOG( QString( "Removing [%1] recursively" ).arg( path ) );
503 }
504
505 bool ret = true;
506 QDir dir( path );
507 QFileInfoList entries = dir.entryInfoList( QDir::NoDotAndDotDot | QDir::AllEntries );
508 for ( int idx = 0; ( ( idx < entries.size() ) && ret ); idx++ ) {
509 QFileInfo entryInfo = entries[idx];
510 if ( entryInfo.isDir() && !entryInfo.isSymLink() ) {
511 ret = rm_fr( entryInfo.absoluteFilePath(), bSilent );
512 } else {
513 QFile file( entryInfo.absoluteFilePath() );
514 if ( !file.remove() ) {
515 ERRORLOG( QString( "unable to remove %1" ).arg( entryInfo.absoluteFilePath() ) );
516 ret = false;
517 }
518 }
519 }
520 if ( !dir.rmdir( dir.absolutePath() ) ) {
521 ERRORLOG( QString( "unable to remove %1" ).arg( dir.absolutePath() ) );
522 ret = false;
523 }
524 return ret;
525}
526
528{
529 bool ret = true;
530 if( !dir_readable( __sys_data_path ) ) ret = false;
531 if( !file_readable( click_file_path() ) ) ret = false;
532 if( !dir_readable( demos_dir() ) ) ret = false;
533 /* if( !dir_readable( doc_dir() ) ) ret = false; */ // FIXME
534 if( !dir_readable( sys_drumkits_dir() ) ) ret = false;
535 if( !file_readable( empty_sample_path() ) ) ret = false;
536 if( !file_readable( sys_config_path() ) ) ret = false;
537 if( !dir_readable( i18n_dir() ) ) ret = false;
538 if( !dir_readable( img_dir() ) ) ret = false;
539 if( !dir_readable( sys_theme_dir() ) ) ret = false;
540 if( !dir_readable( xsd_dir() ) ) ret = false;
541 if( !file_readable( pattern_xsd_path() ) ) ret = false;
542 if( !file_readable( drumkit_xsd_path() ) ) ret = false;
543 if( !file_readable( playlist_xsd_path() ) ) ret = false;
544
545 if ( ret ) {
546 INFOLOG( QString( "system wide data path %1 is usable." ).arg( __sys_data_path ) );
547 }
548
549 return ret;
550}
551
552
554{
555 bool ret = true;
556 if( !path_usable( tmp_dir() ) ) ret = false;
557 if( !path_usable( __usr_data_path ) ) ret = false;
558 if( !path_usable( cache_dir() ) ) ret = false;
559 if( !path_usable( repositories_cache_dir() ) ) ret = false;
560 if( !path_usable( usr_drumkits_dir() ) ) ret = false;
561 if( !path_usable( patterns_dir() ) ) ret = false;
562 if( !path_usable( playlists_dir() ) ) ret = false;
563 if( !path_usable( plugins_dir() ) ) ret = false;
564 if( !path_usable( scripts_dir() ) ) ret = false;
565 if( !path_usable( songs_dir() ) ) ret = false;
566 if( file_exists( empty_song_path(), true ) ) ret = false;
567 if( !path_usable( usr_theme_dir() ) ) ret = false;
568 if( !file_writable( usr_config_path() ) ) ret = false;
569
570 if ( ret ) {
571 INFOLOG( QString( "user path %1 is usable." ).arg( __usr_data_path ) );
572 }
573
574 return ret;
575}
576
578{
579 return __sys_data_path;
580}
582{
583 return __usr_data_path;
584}
585
587{
588 return __ladspa_paths;
589}
590
591// FILES
597{
598 if ( ! m_sPreferencesOverwritePath.isEmpty() ) {
600 } else {
601 return __usr_cfg_path;
602 }
603}
608
610 return DEFAULT_SONG;
611}
612
614 QString sPathBase( __usr_data_path + EMPTY_SONG_BASE );
615 QString sPath( sPathBase + Filesystem::songs_ext );
616
617 int nIterations = 0;
618 while ( file_exists( sPath, true ) ) {
619 sPath = sPathBase + QString::number( nIterations ) + Filesystem::songs_ext;
620 ++nIterations;
621
622 if ( nIterations > 1000 ) {
623 ERRORLOG( "That's a bit much. Something is wrong in here." );
626 }
627 }
628
629 return sPath;
630}
631
633{
634 return UNTITLED_SONG;
635}
650{
651 return DRUMKIT_XSD;
652}
654{
655 return xsd_dir() + DRUMKIT_XSD;
656}
658{
659 return xsd_dir() + DRUMPAT_XSD;
660}
662{
663 return xsd_dir() + PLAYLIST_XSD;
664}
666{
667 return __usr_log_path;
668}
669
670// DIRS
672{
673 return __sys_data_path + IMG;
674}
676{
677 return __sys_data_path + DOC;
678}
680{
681 return __sys_data_path + I18N;
682}
684{
685 return __usr_data_path + SCRIPTS;
686}
688{
689 return __usr_data_path + SONGS;
690}
692{
693 return __usr_data_path + THEMES;
694}
696{
697 return __sys_data_path + THEMES;
698}
699QString Filesystem::song_path( const QString& sg_name )
700{
701 return QString( songs_dir() + sg_name + songs_ext );
702}
704{
705 return __usr_data_path + PATTERNS;
706}
707QString Filesystem::patterns_dir( const QString& dk_name )
708{
709 return __usr_data_path + PATTERNS + dk_name + "/";
710}
711QString Filesystem::pattern_path( const QString& dk_name, const QString& p_name )
712{
713 if ( dk_name.isEmpty() ) {
714 return patterns_dir() + p_name + patterns_ext;
715 } else {
716 return patterns_dir( dk_name ) + p_name + patterns_ext;
717 }
718}
720{
721 return __usr_data_path + PLUGINS;
722}
724{
725 return __sys_data_path + DRUMKITS;
726}
728{
729 return __usr_data_path + DRUMKITS;
730}
732{
733 return __usr_data_path + PLAYLISTS;
734}
735QString Filesystem::playlist_path( const QString& pl_name )
736{
737 return patterns_dir() + pl_name + playlist_ext;
738}
740{
741 return __usr_data_path + CACHE;
742}
748{
749 return __sys_data_path + DEMOS;
750}
752{
753 return __sys_data_path + XSD;
754}
756{
757 return xsd_dir() + "legacy";
758}
760{
761 return QDir::tempPath() + "/" + TMP;
762}
763QString Filesystem::tmp_file_path( const QString &base )
764{
765 // Ensure template base will produce a valid filename
766 QString validBase = base;
767 validBase.remove(
768 QRegularExpression( "[\\\\|\\/|\\*|\\,|\\$|:|=|@|!|\\^|&|\\?|\"|'|>|<|\\||%|:]+" ) );
769
770 QFileInfo f( validBase );
771 QString templateName( tmp_dir() + "/" );
772 if ( f.suffix().isEmpty() ) {
773 templateName += validBase.left( 20 );
774 } else {
775 templateName += f.completeBaseName().left( 20 ) + "-XXXXXX." + f.suffix();
776 }
777 QTemporaryFile file( templateName);
778 file.setAutoRemove( false );
779 file.open();
780 file.close();
781 return file.fileName();
782}
783
784// DRUMKITS
785QStringList Filesystem::drumkit_list( const QString& path )
786{
787 QStringList ok;
788 QStringList possible = QDir( path ).entryList( QDir::Dirs | QDir::Readable | QDir::NoDotAndDotDot );
789 foreach ( const QString& dk, possible ) {
790 if ( drumkit_valid( path + dk ) ) {
791 ok << dk;
792 } else {
793 ERRORLOG( QString( "drumkit %1 is not usable" ).arg( dk ) );
794 }
795 }
796 return ok;
797}
799 QString sDefaultPath = sys_drumkits_dir() + DRUMKIT_DEFAULT_KIT;
800
801 // GMRockKit does not exist at system-level? Let's pick another
802 // one.
803 if ( ! drumkit_valid( sDefaultPath ) ) {
804 for ( const auto& sDrumkitName : Filesystem::sys_drumkit_list() ) {
805 if ( drumkit_valid( Filesystem::sys_drumkits_dir() + sDrumkitName ) ) {
806 sDefaultPath = Filesystem::sys_drumkits_dir() + sDrumkitName;
807 break;
808 }
809 }
810 }
811
812 // There is no drumkit at system-level? Let's pick one from user-space.
813 if ( ! drumkit_valid( sDefaultPath ) ) {
814 for ( const auto& sDrumkitName : Filesystem::usr_drumkit_list() ) {
815 if ( drumkit_valid( Filesystem::usr_drumkits_dir() + sDrumkitName ) ) {
816 sDefaultPath = Filesystem::usr_drumkits_dir() + sDrumkitName;
817 break;
818 }
819 }
820 }
821
822 return sDefaultPath;
823}
824
826{
827 return drumkit_list( sys_drumkits_dir() ) ;
828}
830{
831 return drumkit_list( usr_drumkits_dir() ) ;
832}
833
834QString Filesystem::prepare_sample_path( const QString& sSamplePath )
835{
836 // Check whether the provided absolute sample path is located within a
837 // known drumkit directory.
838 int nIndexMatch = -1;
839 // On Windows the provided system dir needs cleaning and looks like this
840 // [C:\\projects\\hydrogen/data/\\drumkits/]. For all other OSs this is not
841 // necessary. But it does no harm either and might be a live safer in some
842 // edge cases.
843 const auto drumkitFolders = QStringList()
844 << sys_drumkits_dir().replace( "\\", "/" ).replace( "//", "/" )
845 << usr_drumkits_dir().replace( "\\", "/" ).replace( "//", "/" );
846
847 QString sSamplePathCleaned( sSamplePath );
848#ifdef WIN32
849 // Qt uses posix separators `/` internally but things can easily mix up
850 // (maybe due to our code) and we end up with something like
851 // C:\projects\hydrogen/data/\drumkits/GMRockKit/Kick-Softest.wav .
852 // We have to ensure to work on a single separator.
853 sSamplePathCleaned = QString( sSamplePathCleaned ).replace( "\\", "/" );
854#endif
855
856 // When composing paths by combining different elements, two file separators
857 // can be used in a row. This is no problem in file access itself but would
858 // mess up our index-based approach in here.
859 sSamplePathCleaned = QString( sSamplePathCleaned ).replace( "//", "/" );
860
861 for ( const auto& ssFolder : drumkitFolders ) {
862 if ( sSamplePathCleaned.startsWith( ssFolder ) ) {
863 nIndexMatch = sSamplePathCleaned.indexOf(
864 "/", ssFolder.size() ) + 1;
865 break;
866 }
867 }
868
869 if ( nIndexMatch >= 0 ) {
870 // Sample is located in a drumkit folder. Just return basename.
871 QString sShortenedPath = sSamplePathCleaned.right(
872 sSamplePathCleaned.size() - nIndexMatch );
873
874 return std::move( sShortenedPath );
875 }
876
877 return sSamplePath;
878}
879
880bool Filesystem::drumkit_exists( const QString& dk_name )
881{
882 if( usr_drumkit_list().contains( dk_name ) ) return true;
883 return sys_drumkit_list().contains( dk_name );
884}
885QString Filesystem::drumkit_usr_path( const QString& dk_name )
886{
887 return usr_drumkits_dir() + dk_name;
888}
889QString Filesystem::drumkit_path_search( const QString& dk_name, Lookup lookup, bool bSilent )
890{
891
892#ifdef H2CORE_HAVE_OSC
893 // When under session management the drumkit can also be located
894 // in - apart from the user and system path - a particular session
895 // folder. If it couldn't be found in there (or the found drumkit
896 // does not match `dk_name`), the session folder is skipped and
897 // the user and system paths will be traversed instead.
898 if ( Hydrogen::get_instance()->isUnderSessionManagement() ) {
899
900 QString sDrumkitPath = QString( "%1/%2" )
901 .arg( NsmClient::get_instance()->getSessionFolderPath() )
902 .arg( "drumkit" );
903
904 // If the path is symbolic link, dereference it.
905 QFileInfo drumkitPathInfo( sDrumkitPath );
906 if ( drumkitPathInfo.isSymLink() ) {
907 sDrumkitPath = drumkitPathInfo.symLinkTarget();
908 }
909
910 // Check whether the local drumkit does hold the right
911 // drumkit (using its name).
912 QString sDrumkitXMLPath = QString( "%1/%2" )
913 .arg( sDrumkitPath ).arg( "drumkit.xml" );
914
915 QString sSessionDrumkitName( "seemsLikeTheKitCouldNotBeRetrievedFromTheDatabase" );
916 auto pSoundLibraryDatabase = Hydrogen::get_instance()->getSoundLibraryDatabase();
917 if ( pSoundLibraryDatabase != nullptr ) {
918 auto pDrumkit = pSoundLibraryDatabase->getDrumkit( sDrumkitPath );
919 if ( pDrumkit != nullptr ) {
920 sSessionDrumkitName = pDrumkit->get_name();
921 }
922 }
923
924 if ( dk_name == sSessionDrumkitName ) {
925 // The local drumkit seems legit.
926 return sDrumkitPath;
927 }
928 else if ( ! bSilent ) {
929 NsmClient::printError( QString( "Local drumkit [%1] name [%2] and the one stored in .h2song file [%3] do not match!" )
930 .arg( sDrumkitXMLPath )
931 .arg( sSessionDrumkitName )
932 .arg( dk_name ) );
933 }
934 }
935
936#endif
937
938 if ( lookup == Lookup::stacked || lookup == Lookup::user ) {
939 if ( usr_drumkit_list().contains( dk_name ) ){
940 return usr_drumkits_dir() + dk_name;
941 }
942 }
943
944 if ( lookup == Lookup::stacked || lookup == Lookup::system ) {
945 if( sys_drumkit_list().contains( dk_name ) ){
946 return sys_drumkits_dir() + dk_name;
947 }
948 }
949
950 if ( ! bSilent ) {
951 ERRORLOG( QString( "drumkit [%1] not found using lookup type [%2]" )
952 .arg( dk_name )
953 .arg( static_cast<int>(lookup)));
954 }
955
956 return QString("");
957}
958
959QString Filesystem::drumkit_dir_search( const QString& dk_name, Lookup lookup )
960{
961 if ( lookup == Lookup::user || lookup == Lookup::stacked ) {
962 if ( usr_drumkit_list().contains( dk_name ) ) {
963 return usr_drumkits_dir();
964 }
965 }
966 if ( lookup == Lookup::system || lookup == Lookup::stacked ) {
967 if( sys_drumkit_list().contains( dk_name ) ) {
968 return sys_drumkits_dir();
969 }
970 }
971 ERRORLOG( QString( "drumkit %1 not found with lookup mode [%2]" )
972 .arg( dk_name ).arg( static_cast<int>(lookup) ) );
973 return "";
974}
975bool Filesystem::drumkit_valid( const QString& dk_path )
976{
977#ifdef H2CORE_HAVE_OSC
978 auto pHydrogen = Hydrogen::get_instance();
979 if ( pHydrogen != nullptr &&
980 pHydrogen->isUnderSessionManagement() ) {
981
982 // Explicit handling for relative drumkit paths supported in
983 // the session management.
984 QFileInfo info( dk_path );
985 if ( info.isRelative() ) {
986 QString sAbsoluteDrumkitPath = QString( "%1%2" )
987 .arg( NsmClient::get_instance()->getSessionFolderPath() )
988 // remove the leading dot indicating that the path is relative.
989 .arg( dk_path.right( dk_path.size() - 1 ) );
990
991 QFileInfo infoAbs( sAbsoluteDrumkitPath );
992 if ( infoAbs.isSymLink() ) {
993 sAbsoluteDrumkitPath = infoAbs.symLinkTarget();
994 }
995
996 return file_readable( sAbsoluteDrumkitPath + "/" +
997 DRUMKIT_XML, true );
998 }
999 }
1000#endif
1001
1002 return file_readable( dk_path + "/" + DRUMKIT_XML, true);
1003}
1004QString Filesystem::drumkit_file( const QString& dk_path )
1005{
1006 return dk_path + "/" + DRUMKIT_XML;
1007}
1008
1010 return DRUMKIT_XML;
1011}
1012
1013QString Filesystem::drumkit_backup_path( const QString& dk_path ) {
1014 return dk_path + "." +
1015 QDateTime::currentDateTime().toString( "yyyy-MM-dd_hh-mm-ss" ) + ".bak";
1016}
1017
1018// PATTERNS
1020{
1021 return QDir( patterns_dir() ).entryList( QDir::Dirs | QDir::Readable | QDir::NoDotAndDotDot );
1022}
1023
1025{
1026 return pattern_list( patterns_dir() );
1027}
1028
1029QStringList Filesystem::pattern_list( const QString& path)
1030{
1031 return QDir( path ).entryList( QStringList( PATTERN_FILTER ), QDir::Files | QDir::Readable | QDir::NoDotAndDotDot );
1032}
1033
1034// SONGS
1036{
1037 return QDir( songs_dir() ).entryList( QStringList( SONG_FILTER ), QDir::Files | QDir::Readable | QDir::NoDotAndDotDot );
1038}
1039
1041{
1042 QStringList result;
1043 foreach ( const QString& str, song_list() ) {
1044 if ( !str.contains( AUTOSAVE ) ) {
1045 result += str;
1046 }
1047 }
1048 return result;
1049}
1050
1051bool Filesystem::song_exists( const QString& sg_name )
1052{
1053 return QDir( songs_dir() ).exists( sg_name );
1054}
1055
1056bool Filesystem::isSongPathValid( const QString& sSongPath, bool bCheckExistance ) {
1057
1058 QFileInfo songFileInfo = QFileInfo( sSongPath );
1059
1060 if ( !songFileInfo.isAbsolute() ) {
1061 ERRORLOG( QString( "Error: Unable to handle path [%1]. Please provide an absolute file path!" )
1062 .arg( sSongPath ));
1063 return false;
1064 }
1065
1066 if ( songFileInfo.exists() ) {
1067 if ( !songFileInfo.isReadable() ) {
1068 ERRORLOG( QString( "Unable to handle path [%1]. You must have permissions to read the file!" )
1069 .arg( sSongPath ));
1070 return false;
1071 }
1072 if ( !songFileInfo.isWritable() ) {
1073 WARNINGLOG( QString( "You don't have permissions to write to the Song found in path [%1]. It will be opened as read-only (no autosave)." )
1074 .arg( sSongPath ));
1076 }
1077 } else if ( bCheckExistance ) {
1078 ERRORLOG( QString( "Provided song [%1] does not exist" ).arg( sSongPath ) );
1079 return false;
1080 }
1081
1082 if ( songFileInfo.suffix() != "h2song" ) {
1083 ERRORLOG( QString( "Unable to handle path [%1]. The provided file must have the suffix '.h2song'!" )
1084 .arg( sSongPath ));
1085 return false;
1086 }
1087
1088 return true;
1089}
1090
1091QString Filesystem::validateFilePath( const QString& sPath ) {
1092
1093 // Ensure the name will be a valid filename
1094 QString sValidName( sPath );
1095 sValidName.replace( " ", "_" );
1096 sValidName.remove(
1097 QRegularExpression( "[\\\\|\\/|\\*|\\,|\\$|:|=|@|!|\\^|&|\\?|\"|'|>|<|\\||%|:]+" ) );
1098
1099 return sValidName;
1100}
1101
1103{
1104 return QDir( sys_theme_dir() ).entryList( QStringList( THEME_FILTER ), QDir::Files | QDir::Readable | QDir::NoDotAndDotDot ) +
1105 QDir( usr_theme_dir() ).entryList( QStringList( THEME_FILTER ), QDir::Files | QDir::Readable | QDir::NoDotAndDotDot );
1106}
1107
1108// PLAYLISTS
1110{
1111 return QDir( playlists_dir() ).entryList( QStringList( PLAYLIST_FILTER ), QDir::Files | QDir::Readable | QDir::NoDotAndDotDot );
1112}
1113
1115{
1116 INFOLOG( QString( "Tmp dir : %1" ).arg( tmp_dir() ) );
1117 // SYS
1118 INFOLOG( QString( "Click file : %1" ).arg( click_file_path() ) );
1119 INFOLOG( QString( "Empty song : %1" ).arg( empty_song_path() ) );
1120 INFOLOG( QString( "Demos dir : %1" ).arg( demos_dir() ) );
1121 INFOLOG( QString( "Documentation dir : %1" ).arg( doc_dir() ) ); // FIXME must be created even if no doc deployed
1122 INFOLOG( QString( "System drumkit dir : %1" ).arg( sys_drumkits_dir() ) );
1123 INFOLOG( QString( "Empty sample : %1" ).arg( empty_sample_path() ) );
1124 INFOLOG( QString( "Default config : %1" ).arg( sys_config_path() ) );
1125 INFOLOG( QString( "Internationalization dir : %1" ).arg( i18n_dir() ) );
1126 INFOLOG( QString( "Images dir : %1" ).arg( img_dir() ) );
1127 // new_tutorial
1128 INFOLOG( QString( "XSD dir : %1" ).arg( xsd_dir() ) );
1129 INFOLOG( QString( "drumkit pattern XSD : %1" ).arg( pattern_xsd_path() ) );
1130 INFOLOG( QString( "drumkit XSD : %1" ).arg( drumkit_xsd_path() ) );
1131 INFOLOG( QString( "drumkit XSD : %1" ).arg( playlist_xsd_path() ) );
1132 // USR
1133 INFOLOG( QString( "User config : %1" ).arg( usr_config_path() ) ); // FIXME
1134 INFOLOG( QString( "User Click file : %1" ).arg( usr_click_file_path() ) );
1135 INFOLOG( QString( "Cache dir : %1" ).arg( cache_dir() ) );
1136 INFOLOG( QString( "Reporitories Cache dir : %1" ).arg( repositories_cache_dir() ) );
1137 INFOLOG( QString( "User drumkit dir : %1" ).arg( usr_drumkits_dir() ) );
1138 INFOLOG( QString( "Patterns dir : %1" ).arg( patterns_dir() ) );
1139 INFOLOG( QString( "Playlist dir : %1" ).arg( playlists_dir() ) );
1140 INFOLOG( QString( "Plugins dir : %1" ).arg( plugins_dir() ) );
1141 INFOLOG( QString( "Scripts dir : %1" ).arg( scripts_dir() ) );
1142 INFOLOG( QString( "Songs dir : %1" ).arg( songs_dir() ) );
1143}
1144
1145QString Filesystem::absolute_path( const QString& sFilename, bool bSilent ) {
1146 if ( QFile( sFilename ).exists() ) {
1147 return QFileInfo( sFilename ).absoluteFilePath();
1148 }
1149 else if ( ! bSilent ) {
1150 ___ERRORLOG( QString( "File [%1] not found" ).arg( sFilename ) );
1151 }
1152
1153 return QString();
1154}
1155
1156QString Filesystem::ensure_session_compatibility( const QString& sPath ) {
1157#ifdef H2CORE_HAVE_OSC
1158 auto pHydrogen = Hydrogen::get_instance();
1159 if ( pHydrogen != nullptr &&
1160 pHydrogen->isUnderSessionManagement() ) {
1161
1162 QFileInfo info( sPath );
1163 if ( info.isRelative() ) {
1164 return QString( "%1%2" )
1165 .arg( NsmClient::get_instance()->getSessionFolderPath() )
1166 // remove the leading dot indicating that the path is relative.
1167 .arg( sPath.right( sPath.size() - 1 ) );
1168 }
1169 }
1170#endif
1171
1172 return sPath;
1173}
1174
1176 const QString sAbsolutePath = absolute_path( sPath );
1177 if ( sAbsolutePath.contains( Filesystem::sys_drumkits_dir() ) ) {
1178 return DrumkitType::System;
1179 }
1180 else if ( sAbsolutePath.contains( Filesystem::usr_drumkits_dir() ) ) {
1181 return DrumkitType::User;
1182 }
1183 else {
1184 if ( dir_writable( sAbsolutePath, true ) ) {
1186 } else {
1188 }
1189 }
1190}
1191
1193 const QDir legacyDir( xsd_legacy_dir() );
1194
1195 const QStringList legacyDirSubfolders =
1196 legacyDir.entryList( QDir::Dirs | QDir::NoDotAndDotDot,
1197 QDir::Name | QDir::Reversed );
1198
1199 QStringList drumkitXSDs;
1200 for ( const auto& ffolder : legacyDirSubfolders ) {
1201 const QDir folder( legacyDir.filePath( ffolder ) );
1202
1203 if ( folder.exists( drumkit_xsd() ) ) {
1204 drumkitXSDs << folder.filePath( drumkit_xsd() );
1205 }
1206 }
1207
1208 return std::move( drumkitXSDs );
1209}
1210
1211QString Filesystem::rerouteDrumkitPath( const QString& sDrumkitPath ) {
1212#ifdef H2CORE_HAVE_APPIMAGE
1213
1214 if ( sDrumkitPath.isEmpty() ) {
1215 ERRORLOG( "Can not reroute empty drumkit paths" );
1216 return "";
1217 }
1218
1219 // Since the path to a system kits of a previously mounted image
1220 // does most probably not exist anymore we can _not_ use
1221 // Filesystem::absolute_path in here.
1222 const QString sAbsolutePath = QDir( sDrumkitPath ).absolutePath();
1223 QString sResult = sAbsolutePath;
1224
1225 // Might be different ones depending on the mounting point of the
1226 // system.
1227 const QStringList systemPrefixes = { "/tmp" };
1228
1229 // Check whether the kit is a system drumkit from a previous
1230 // AppImage session.
1231 bool bIsForeignSystemKit = false;
1232 for ( const auto& ssPrefix : systemPrefixes ) {
1233 if ( sAbsolutePath.startsWith( ssPrefix ) &&
1234 ! sAbsolutePath.contains( Filesystem::sys_data_path() ) ) {
1235 bIsForeignSystemKit = true;
1236 }
1237 }
1238
1239 if ( bIsForeignSystemKit ) {
1240 const QStringList pathComponents = sAbsolutePath.split( "/" );
1241 if ( pathComponents.size() > 2 ) {
1242 const QString sNewPath = QString( "%1%2/%3" )
1244 .arg( pathComponents[ pathComponents.size() - 2 ] )
1245 .arg( pathComponents[ pathComponents.size() - 1 ] );
1246
1247 INFOLOG( QString( "Rerouting system kit: [%1] -> [%2]" )
1248 .arg( sDrumkitPath )
1249 .arg( Filesystem::absolute_path( sNewPath ) ) );
1250
1251 sResult = Filesystem::absolute_path( sNewPath );
1252 }
1253 else {
1254 ERRORLOG( QString( "Unable to replace drumkit path [%1]" )
1255 .arg( sDrumkitPath ) );
1256 }
1257 }
1258
1259 return sResult;
1260#else
1261 return sDrumkitPath;
1262#endif
1263}
1264
1265QString Filesystem::removeUtf8Characters( const QString &sEncodedString ) {
1266 QString sCleaned( sEncodedString );
1267 return sCleaned.remove(
1268 QRegularExpression( "[^a-zA-Z0-9._/\\s()\\[\\]\\&\\+\\-]" ) );
1269}
1270const std::vector<Filesystem::AudioFormat>& Filesystem::supportedAudioFormats() {
1272}
1273};
1274
1275/* vim: set softtabstop=4 noexpandtab: */
#define AUTOSAVE
#define CLICK_SAMPLE
Sound of metronome beat.
#define DRUMKITS
#define IMG
#define REPOSITORIES
#define XSD
#define DRUMKIT_DEFAULT_KIT
#define CACHE
#define DEFAULT_SONG
#define TMP
#define PLAYLIST_FILTER
#define SONG_FILTER
#define PATTERNS
#define LOG_FILE
#define EMPTY_SONG_BASE
#define THEMES
#define I18N
#define SCRIPTS
#define SYS_CONFIG
#define DRUMPAT_XSD
#define PLAYLIST_XSD
#define PLAYLISTS
#define LOCAL_DATA_PATH
#define UNTITLED_PLAYLIST
#define DRUMKIT_XSD
#define PATTERN_FILTER
#define PLUGINS
#define DRUMKIT_XML
#define DOC
#define USR_CONFIG
#define SONGS
#define THEME_FILTER
#define UNTITLED_SONG
#define DEMOS
#define EMPTY_SAMPLE
#define INFOLOG(x)
Definition Object.h:240
#define WARNINGLOG(x)
Definition Object.h:241
#define ERRORLOG(x)
Definition Object.h:242
#define ___ERRORLOG(x)
Definition Object.h:260
static Logger * logger()
return the logger instance
Definition Object.h:103
static EventQueue * get_instance()
Returns a pointer to the current EventQueue singleton stored in __instance.
Definition EventQueue.h:224
void push_event(const EventType type, const int nValue)
Queues the next event into the EventQueue.
static QStringList song_list()
returns a list of existing songs
static QString __usr_cfg_path
the path to the user config file
Definition Filesystem.h:584
static bool file_copy(const QString &src, const QString &dst, bool overwrite=false, bool bSilent=false)
copy a source file to a destination
static QString scripts_dir()
returns user scripts path
static const QString patterns_filter_name
Definition Filesystem.h:126
static QString playlist_xsd_path()
returns the path to the playlist pattern XSD (xml schema definition) file
static QString validateFilePath(const QString &sPath)
Takes an arbitrary path, replaces white spaces by underscores and removes all characters apart from l...
static QString demos_dir()
returns system demos path
static QString song_path(const QString &sg_name)
returns user song path, add file extension
static QString ensure_session_compatibility(const QString &sPath)
If Hydrogen is under session management, we support for paths relative to the session folder.
static QString sys_data_path()
returns system data path
static bool dir_readable(const QString &path, bool silent=false)
returns true if the given path is a readable regular directory
static std::vector< AudioFormat > m_supportedAudioFormats
Definition Filesystem.h:587
static QString cache_dir()
returns user cache path
static const QString patterns_ext
Definition Filesystem.h:119
static bool drumkit_exists(const QString &dk_name)
returns true if the drumkit exists within usable system or user drumkits
static bool check_usr_paths()
returns true if the user path is consistent
static const QString scripts_filter_name
Definition Filesystem.h:125
static QString removeUtf8Characters(const QString &sEncodedString)
Removes all characters not within the Latin-1 range of sEncodedString.
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 bool isSongPathValid(const QString &sSongPath, bool bCheckExistance=false)
Checks the path pointing to a .h2song.
static bool drumkit_valid(const QString &dk_path)
returns true if the path contains a usable drumkit
static QString playlist_path(const QString &pl_name)
returns user playlist path, add file extension
static QStringList drumkit_list(const QString &path)
static bool check_permissions(const QString &path, const int perms, bool silent)
static QString usr_config_path()
static QString songs_dir()
returns user songs path
static QString pattern_xsd_path()
returns the path to the pattern XSD (xml schema definition) file
static const QString themes_ext
Definition Filesystem.h:122
static QString playlists_dir()
returns user playlist path
static DrumkitType determineDrumkitType(const QString &sPath)
static QString usr_click_file_path()
returns click file path from user directory if exists, otherwise from system
static bool bootstrap(Logger *logger, const QString &sSysDataPath="", const QString &sUsrDataPath="", const QString &sUserConfigFile="", const QString &sLogFile="")
check user and system filesystem usability
static QString empty_sample_path()
returns system empty sample file path
static QStringList playlist_list()
returns a list of existing playlists
static QString absolute_path(const QString &sFilename, bool bSilent=false)
Convert a direct to an absolute path.
static QString plugins_dir()
returns user plugins path
static bool file_writable(const QString &path, bool silent=false)
returns true if the given path is a possibly writable file (may exist or not)
static QStringList theme_list()
static QString usr_drumkits_dir()
returns user drumkits path
static QString untitled_song_name()
returns untitled song name
static bool check_sys_paths()
returns true if the system path is consistent
static QStringList ladspa_paths()
returns user ladspa paths
static QStringList drumkit_xsd_legacy_paths()
static QStringList pattern_list()
returns a list of existing patterns
static QString sys_drumkits_dir()
returns system drumkits path
static bool rm(const QString &path, bool recursive=false, bool bSilent=false)
remove a path
static QString drumkit_backup_path(const QString &dk_path)
Create a backup path from a drumkit path.
static QStringList song_list_cleared()
returns a list of existing songs, excluding the autosaved one
static QString usr_theme_dir()
static QString drumkit_xsd_path()
returns the path to the drumkit XSD (xml schema definition) file
static QString doc_dir()
returns documentation path
static const QString scripts_ext
Definition Filesystem.h:118
static QStringList usr_drumkit_list()
returns list of usable user drumkits ( see Filesystem::drumkit_list )
static QString repositories_cache_dir()
returns user repository cache path
static QString prepare_sample_path(const QString &sFilePath)
Returns the basename if the given path is under an existing user or system drumkit path,...
static bool rm_fr(const QString &path, bool bSilent=false)
recursively remove a path
static bool dir_writable(const QString &path, bool silent=false)
returns true if the given path is a writable regular directory
static QString img_dir()
returns gui image path
static QString rerouteDrumkitPath(const QString &sDrumkitPath)
Reroutes stored drumkit paths pointing to a temporary AppImage system data folder to the current AppI...
static bool file_exists(const QString &path, bool silent=false)
returns true if the given path is an existing regular file
static QString __usr_data_path
the path to the user files
Definition Filesystem.h:583
static const std::vector< AudioFormat > & supportedAudioFormats()
Which format is supported is determined by the libsndfile version Hydrogen is linked against during c...
static QString empty_song_path()
Provides the full path to the current empty song.
AudioFormat
All audio file formats supported by Hydrogen.
Definition Filesystem.h:90
Lookup
Whenever a drumkit is loaded by name a collision between a user and a system drumkit carrying the sam...
Definition Filesystem.h:55
@ system
Only search the system drumkits.
Definition Filesystem.h:67
@ stacked
First, looks in the system drumkits and, afterwards, in the user drumkits.
Definition Filesystem.h:63
@ user
Only search the user drumkits.
Definition Filesystem.h:65
static QString drumkit_dir_search(const QString &dk_name, Lookup lookup)
returns the directory holding the named drumkit searching within user then system drumkits
static QString m_sPreferencesOverwritePath
If this variable is non-empty, its content will be used as an alternative to store and load the prefe...
Definition Filesystem.h:545
static QString click_file_path()
Returns a string containing the path to the click.wav file used in the metronome.
static QStringList sys_drumkit_list()
returns list of usable system drumkits ( see Filesystem::drumkit_list )
static QString drumkit_path_search(const QString &dk_name, Lookup lookup=Lookup::stacked, bool bSilent=false)
Returns the path to a H2Core::Drumkit folder.
static const QString playlists_filter_name
Definition Filesystem.h:127
static QString sys_config_path()
returns system config path
static bool mkdir(const QString &path)
create a path
static QString drumkit_file(const QString &dk_path)
returns the path to the xml file within a supposed drumkit path
static QStringList pattern_drumkits()
returns a list of existing drumkit sub dir into the patterns directory
static QString __sys_data_path
Path to the system files set in Filesystem::bootstrap().
Definition Filesystem.h:582
static QString pattern_path(const QString &dk_name, const QString &p_name)
returns user patterns path, add file extension
static QString __usr_log_path
the path to the log file
Definition Filesystem.h:585
static bool write_to_file(const QString &dst, const QString &content)
writes to a file
static Logger * __logger
a pointer to the logger
Definition Filesystem.h:537
static const QString playlist_ext
Definition Filesystem.h:120
static QString i18n_dir()
returns internationalization path
static const QString songs_filter_name
Definition Filesystem.h:123
static QString xsd_legacy_dir()
static QString tmp_dir()
returns temp path
DrumkitType
Determines were to find a kit and whether it is writable by the current user.
Definition Filesystem.h:72
@ SessionReadWrite
Kit was loaded via a NSM session, OSC command, or CLI option, only persist for the current Hydrogen s...
Definition Filesystem.h:86
@ User
Kit was installed by the user, is automatically loaded, and most probably writable.
Definition Filesystem.h:78
@ System
Kit was installed with Hydrogen, is automatically loaded, and most probably readonly.
Definition Filesystem.h:75
@ SessionReadOnly
Kit was loaded via a NSM session, OSC command, or CLI option, only persist for the current Hydrogen s...
Definition Filesystem.h:82
static void info()
send current settings information to logger with INFO severity
static QString usr_data_path()
returns user data path
static QString log_file_path()
returns the full path (including filename) of the logfile
static QString drumkit_usr_path(const QString &dk_name)
returns path for a drumkit within user drumkit path
static const QString drumkit_ext
Definition Filesystem.h:121
static const QString themes_filter_name
Definition Filesystem.h:124
static const QString songs_ext
Definition Filesystem.h:117
static QString sys_theme_dir()
static bool path_usable(const QString &path, bool create=true, bool silent=false)
returns true if the path is a readable and writable regular directory, create if it not exists
static QString AudioFormatToSuffix(const AudioFormat &format, bool bSilent=false)
Converts format to the default lower case suffix of the format.
static QString drumkit_xml()
Returns filename and extension of the expected drumkit file.
static QString drumkit_xsd()
returns the drumkit XSD (xml schema definition) name
static QString tmp_file_path(const QString &base)
touch a temporary file under tmp_dir() and return it's path.
static QString default_song_name()
Default option to offer the user when saving an empty song to disk.
static QString xsd_dir()
returns system xsd path
static bool song_exists(const QString &sg_name)
returns true if the song file exists
static QStringList __ladspa_paths
paths to laspa plugins
Definition Filesystem.h:586
static QString untitled_playlist_file_name()
returns untitled playlist file name
static bool file_readable(const QString &path, bool silent=false)
returns true if the given path is an existing readable regular file
static bool dir_exists(const QString &path, bool silent=false)
returns true if the given path is a regular directory
static QString drumkit_default_kit()
static QString patterns_dir()
returns user patterns path
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:84
SoundLibraryDatabase * getSoundLibraryDatabase() const
Definition Hydrogen.h:95
Class for writing logs to the console.
Definition Logger.h:41
static void printError(const QString &msg)
Custom function to print a colored error message.
static NsmClient * get_instance()
Definition NsmClient.h:84
#define H2_SYS_PATH
Path of the configuration files of Hydrogen in the system.
Definition config.dox:29
#define H2_USR_PATH
Path of the configuration files of Hydrogen in the user home.
Definition config.dox:24
@ EVENT_UPDATE_SONG
Event triggering HydrogenApp::updateSongEvent() whenever the Song was changed outside of the GUI,...
Definition EventQueue.h:128