hydrogen 1.2.6
AudioFileBrowser.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 "AudioFileBrowser.h"
24#include "../HydrogenApp.h"
26#include "SampleWaveDisplay.h"
27#include "../Widgets/Button.h"
28#include "../Skin.h"
29
31#include <core/Basics/Sample.h>
32#include <core/Hydrogen.h>
34
35#include <QFileSystemModel>
36#include <QModelIndex>
37#include <QTreeWidget>
38#include <QMessageBox>
39
40using namespace H2Core;
41
42AudioFileBrowser::AudioFileBrowser ( QWidget* pParent, bool bAllowMultiSelect,
43 bool bShowInstrumentManipulationControls,
44 QString sDefaultPath,
45 const QString& sFilename )
46 : QDialog ( pParent )
47 , Object ()
48 , m_sFilename( sFilename )
49{
50 setupUi ( this );
51
52 // Show and enable maximize button. This is key when enlarging the
53 // application using a scaling factor and allows the OS to force its size
54 // beyond the minimum and make the scrollbars appear.
55 setWindowFlags( windowFlags() | Qt::CustomizeWindowHint |
56 Qt::WindowMinMaxButtonsHint );
57
58 setWindowTitle ( tr ( "Audio File Browser" ) );
59
60 if ( sDefaultPath.isEmpty() ) {
61 sDefaultPath = QDir::homePath();
62 }
63 m_sSelectedDirectory = sDefaultPath;
64
65 m_bAllowMultiSelect = bAllowMultiSelect;
66 m_bShowInstrumentManipulationControls = bShowInstrumentManipulationControls;
67
68 QStringList nameFilters;
69 for ( const auto& fformat : Filesystem::supportedAudioFormats() ) {
70 const QString ssFilter = QString( "*.%1" )
71 .arg( Filesystem::AudioFormatToSuffix( fformat ) );
72 nameFilters << ssFilter << ssFilter.toUpper();
73 }
74
75 m_pDirModel = new QFileSystemModel();
76 m_pDirModel->setRootPath(""); //see https://forum.qt.io/topic/99513/qfilesystemmodel-qtreeview-doesn-t-sort/2
77 m_pDirModel->setFilter( QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot );
78 m_pDirModel->setNameFilters( nameFilters );
79 m_pDirModel->setNameFilterDisables(false);
80
81 m_ModelIndex = m_pDirModel->index( QDir::currentPath() );
82
83 m_pPlayBtn->setEnabled( false );
84 m_pStopBtn->setEnabled( false );
85 openBTN->setEnabled( false );
86
87 m_pTree->setModel( m_pDirModel );
88 m_pTree->header()->resizeSection( 0, 405 );
89 m_pTree->setAlternatingRowColors( true );
90 m_pTree->setRootIndex( m_pDirModel->index( sDefaultPath ) );
91
92 pathLineEdit->setText( sDefaultPath );
94 m_pSelectedFile << "false" << "false";
95
97
98 m_pPathUptoolButton->setIcon( QIcon( Skin::getSvgImagePath() + "/icons/white/go-up.svg"));
99 m_pPathUptoolButton->setToolTip( QString( tr( "Parent Folder" )));
100 m_pPathHometoolButton->setIcon( QIcon( Skin::getSvgImagePath() + "/icons/white/home.svg"));
101 m_pPathHometoolButton->setToolTip( QString( tr( "Home" )));
102
103 m_pPlayBtn->setIcon( QIcon( Skin::getSvgImagePath() + "/icons/white/play.svg"));
104 m_pPlayBtn->setToolTip( QString( tr( "Play selected" ) ));
105 m_pStopBtn->setIcon( QIcon( Skin::getSvgImagePath() + "/icons/white/stop.svg"));
106 m_pStopBtn->setToolTip( QString( tr( "Stop" )));
107
108 m_pSampleWaveDisplay = new SampleWaveDisplay( waveformview );
110 m_pSampleWaveDisplay->move( 3, 3 );
111
112 playSamplescheckBox->setChecked( Preferences::get_instance()->__playsamplesonclicking );
113 //get the kde or gnome environment variable for mouse double or single clicking
114 m_SingleClick = false;
116
118 useNameCheckBox->hide();
119 autoVelCheckBox->hide();
120 }
121
122 if ( ! sFilename.isEmpty() ) {
123 m_pTree->setCurrentIndex( m_pDirModel->index( sFilename ) );
124 browseTree( m_pDirModel->index( sFilename ) );
125
126 // Right now in the constructor of AudioFileBrowser m_pTree is
127 // still busy doing something different or maybe some update
128 // is triggered afterwards. Either way, calling scrollTo()
129 // directly won't cut it. We have to wait a short amount of
130 // time till the dust has settled.
131 //
132 // The 50 is a heuristic that worked on my machine. This might
133 // need a little more tweaking.
134 QTimer::singleShot( 50, [this]{
135 m_pTree->scrollTo( m_pDirModel->index( m_sFilename ),
136 QAbstractItemView::PositionAtCenter);} );
137 }
138
139 connect( m_pTree, SIGNAL( clicked( const QModelIndex&) ), SLOT( clicked( const QModelIndex& ) ) );
140 connect( m_pTree, SIGNAL( doubleClicked( const QModelIndex&) ), SLOT( doubleClicked( const QModelIndex& ) ) );
141 connect( pathLineEdit, SIGNAL( returnPressed() ), SLOT( updateModelIndex() ) );
142}
143
144
145
152
153
154bool AudioFileBrowser::isFileSupported( QString filename )
155{
156 return Filesystem::AudioFormatFromSuffix( filename ) !=
158}
159
160
162{
163 QString desktopSession = getenv("DESKTOP_SESSION");
164//kde
165 if( desktopSession == "kde" ) {
166 QFile envfile( QDir::homePath() + "/.kde/share/config/kdeglobals");
167
168 if ( !envfile.open(QIODevice::ReadOnly | QIODevice::Text) ) {
169 return;
170 }
171
172 QTextStream envin( &envfile );
173 while ( !envin.atEnd() ) {
174 QString envLine = envin.readLine();
175 if( envLine == QString("SingleClick=true" ) ) {
176 m_SingleClick = true;
177 break;
178 }
179 }
180 }
181
182//for gnome, xfce and all others we use double click as default
183}
184
185
186
188{
189 if( ( ev->modifiers()==Qt::ControlModifier ||
190 ev->modifiers()==Qt::ShiftModifier )
192 m_pTree->setSelectionMode( QAbstractItemView::ExtendedSelection );
193 openBTN->setEnabled( true );
194 }
195}
196
197
198
200{
201 m_pTree->setSelectionMode( QAbstractItemView::SingleSelection );
202}
203
204
205
207{
208 QString toRemove;
209 QString newPath = pathLineEdit->text();
210
211 if( QDir( newPath ).exists() ) {
212 m_pTree->setRootIndex( m_pDirModel->index( newPath ) );
213 } else {
214 toRemove = newPath.section( '/', -1 );
215// QMessageBox::information ( this, "Hydrogen", newpath + toremove);
216 newPath.replace( toRemove, "" );
217 m_pTree->setRootIndex( m_pDirModel->index( newPath ) );
218 }
219}
220
221
222
223void AudioFileBrowser::clicked( const QModelIndex& index )
224{
225 QString path = m_pDirModel->filePath( index );
226
227 if ( m_SingleClick ) {
228 browseTree( index );
229 }
230
231 if ( Filesystem::file_exists( path, true ) && isFileSupported( path ) ) {
232 browseTree( index );
233 }
234}
235
236
237
238void AudioFileBrowser::doubleClicked( const QModelIndex& index )
239{
240 if(!m_SingleClick) {
241 browseTree( index );
242 }
243}
244
245
246
247void AudioFileBrowser::browseTree( const QModelIndex& index )
248{
249
250 QString path = m_pDirModel->filePath( index );
251 pathLineEdit->setText( path );
253
254 updateModelIndex(); //with this you have a navigation like konqueror
255
256 if ( m_pDirModel->isDir( index ) ){
257 m_pPlayBtn->setEnabled( false );
258 openBTN->setEnabled( false );
259 return;
260 }
261
262 QString name = path.section( '/', -1 );
263
264 QString path2 = path;
265 QString onlyPath = path;
266 if ( name != "" ){
267 onlyPath = path.replace( name, "" );
268 }
269
270 name = name.left( '.' );
271
272 QString message = QString( tr( "Name: " ) ).append( name );
273 pathLineEdit->setText( onlyPath );
274
275 QStringList path2List = path2.split("/");
276 QString fleTxt = path2List.last();
277
278 QApplication::setOverrideCursor(Qt::WaitCursor);
279
280 if ( isFileSupported( path2 ) ) {
281
282 filelineedit->setText( fleTxt );
283 auto pNewSample = Sample::load( path2 );
284
285 if ( pNewSample != nullptr ) {
286 m_pNBytesLable->setText( tr( "Size: %1 bytes" ).arg( pNewSample->get_size() / 2 ) );
287 m_pSamplerateLable->setText( tr( "Samplerate: %1" ).arg( pNewSample->get_sample_rate() ) );
288 float sec = ( float )( pNewSample->get_frames() / (float)pNewSample->get_sample_rate() );
289 QString qsec;
290 qsec = QString::asprintf( "%2.2f", sec );
291 m_pLengthLable->setText( tr( "Sample length: " ) + qsec + tr( " s" ) );
292
293 m_pSampleFilename = path2;
294
295 m_pSampleWaveDisplay->updateDisplay( path2 );
296 m_pPlayBtn->setEnabled( true );
297 openBTN->setEnabled( true );
298
299 //important this will only working correct if m_pSampleWaveDisplay->updateDisplay( file )
300 //is ready with painting the wav file. else the playing sample get crackled sound!!
301 if (playSamplescheckBox->isChecked()){
302 if ( sec <= 600.00){
304 }else
305 {
306 QMessageBox::information ( this, "Hydrogen", tr( "Please do not preview samples which are longer than 10 minutes!" ) );
307 }
308 }
309 m_pNameLabel->setText( message );
310 } else {
311 openBTN->setEnabled( false );
312 QMessageBox::information ( this, "Hydrogen", tr( "Unable to load that sample file." ) );
313 }
314
315 }else{
316 m_pNameLabel->setText( tr( "Name:"));
317 m_pNBytesLable->setText( tr( "Size:" ) );
318 m_pSamplerateLable->setText( tr( "Samplerate:" ) );
319 m_pLengthLable->setText( tr( "Sample length:" ) );
321 m_pPlayBtn->setEnabled( false );
322 m_pStopBtn->setEnabled( false );
323 openBTN->setEnabled( false );
325 }
326 QApplication::restoreOverrideCursor();
327}
328
329
330
332{
333
334 if( QFile( m_pSampleFilename ).exists() == false ) {
335 return;
336 }
337
338 m_pStopBtn->setEnabled( true );
339
340 auto pNewSample = Sample::load( m_pSampleFilename );
341 if ( pNewSample ) {
342 assert(pNewSample->get_sample_rate() != 0);
343
344 int length = ( ( pNewSample->get_frames() / pNewSample->get_sample_rate() + 1) * 100 );
346 }
347}
348
349
350
352{
353 auto pNewSample = Sample::load( m_sEmptySampleFilename );
355 m_pStopBtn->setEnabled( false );
356}
357
358
359
361{
362 m_sSelectedDirectory = pathLineEdit->text();
363 m_pSelectedFile << "false" << "false" << "";
364 reject();
365}
366
367
368
370{
371 if ( m_pTree->selectionModel()->selectedRows().size() > 0 ) {
372 QList<QModelIndex>::iterator i;
373 QList<QModelIndex> list = m_pTree->selectionModel()->selectedRows();
374
375 for (i = list.begin(); i != list.end(); ++i) {
376 QString path2 = (*i).data().toString();
377 if ( isFileSupported( path2 ) ){
378 QString path = pathLineEdit->text();
379
380 if (! path.endsWith("/") ) {
381 path = path + "/";
382 }
383
384 QString act_filename = path + path2;
385 m_pSelectedFile << act_filename ;
386 }
387 }
388 }
389
390 m_sSelectedDirectory = pathLineEdit->text();
391 accept();
392}
393
394
395
400
401
402
404{
405 if ( useNameCheckBox->isChecked() ) {
406 m_pSelectedFile[0] = "true";
407 }
408 if ( autoVelCheckBox->isChecked() ) {
409 m_pSelectedFile[1] = "true";
410 }
411 return m_pSelectedFile;
412}
413
417
419{
420
421 QString path = pathLineEdit->text();
422 QStringList pathlist = path.split("/");
423
424 while( path != QDir::rootPath() ){
425
426 if( pathlist.isEmpty () ) {
427 break;
428 }
429
430 pathlist.removeLast();
431 QString updir = pathlist.join("/");
432
433 pathLineEdit->setText( updir );
434 m_pTree->setRootIndex( m_pDirModel->index( updir ) );
435 m_pTree->collapse( m_pDirModel->index( updir ) );
436 m_pTree->setExpanded( m_pDirModel->index(updir), false );
437 path = pathLineEdit->text();
438 }
439
440 pathLineEdit->setText( QDir::homePath() );
441 m_pTree->setRootIndex( m_pDirModel->index( QDir::homePath() ) );
442
443 m_pTree->collapse( m_pDirModel->index( QDir::homePath()) );
444}
445
446
447
449{
450 QString path = pathLineEdit->text();
451 QStringList pathlist = path.split("/");
452
453 if( pathlist.isEmpty () ) {
454 return;
455 }
456
457 if( path.endsWith( "/" ) ) {
458 pathlist.removeLast();
459 QString tmpupdir = pathlist.join("/");
460 m_pTree->setRootIndex( m_pDirModel->index( tmpupdir ) );
461 m_pTree->collapse( m_pDirModel->index( tmpupdir ) );
462 m_pTree->setExpanded( m_pDirModel->index( tmpupdir ), false );
463 }
464
465 pathlist.removeLast();
466
467 QString updir = pathlist.join("/");
468 if ( updir == "" ) {
469 pathLineEdit->setText( QString("/") );
470 } else {
471 pathLineEdit->setText( updir );
472 }
473
474 m_pTree->setRootIndex( m_pDirModel->index( updir ) );
475 m_pTree->collapse( m_pDirModel->index( updir ) );
476 m_pTree->setExpanded( m_pDirModel->index(updir), false );
477}
478
479
480
482{
483 if ( hiddenCB->isChecked() ) {
484 m_pDirModel->setFilter( QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden );
485 } else {
486 m_pDirModel->setFilter( QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot );
487 m_pTree->setRootIndex( m_pDirModel->index( pathLineEdit->text() ) );
488 }
489}
#define INFOLOG(x)
Definition Object.h:240
void doubleClicked(const QModelIndex &index)
virtual void keyReleaseEvent(QKeyEvent *ev) override
QFileSystemModel * m_pDirModel
AudioFileBrowser(QWidget *pParent, bool bAllowMultiSelect, bool bShowInstrumentManipulationControls, QString sDefaultPath="", const QString &sFilename="")
QStringList getSelectedFiles()
void clicked(const QModelIndex &index)
void on_m_pPathUptoolButton_clicked()
virtual void keyPressEvent(QKeyEvent *ev) override
QString m_sEmptySampleFilename
bool isFileSupported(QString filename)
bool m_bShowInstrumentManipulationControls
void on_playSamplescheckBox_clicked()
void on_m_pPathHometoolButton_clicked()
QModelIndex m_ModelIndex
SampleWaveDisplay * m_pSampleWaveDisplay
void browseTree(const QModelIndex &index)
QStringList m_pSelectedFile
Sampler * getSampler() const
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 empty_sample_path()
returns system empty sample file path
static bool file_exists(const QString &path, bool silent=false)
returns true if the given path is an existing regular file
static const std::vector< AudioFormat > & supportedAudioFormats()
Which format is supported is determined by the libsndfile version Hydrogen is linked against during c...
static QString AudioFormatToSuffix(const AudioFormat &format, bool bSilent=false)
Converts format to the default lower case suffix of the format.
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:84
AudioEngine * getAudioEngine() const
Definition Hydrogen.h:663
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
static std::shared_ptr< Sample > load(const QString &filepath, const License &license=License())
Definition Sample.cpp:136
void preview_sample(std::shared_ptr< Sample > pSample, int length)
Preview, uses only the first layer.
Definition Sampler.cpp:1362
static QString getSvgImagePath()
Definition Skin.h:40