hydrogen 1.2.3
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-2024 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 setWindowTitle ( tr ( "Audio File Browser" ) );
53 adjustSize();
54 setFixedSize ( width(), height() );
55
56 if ( sDefaultPath.isEmpty() ) {
57 sDefaultPath = QDir::homePath();
58 }
59 m_sSelectedDirectory = sDefaultPath;
60
61 m_bAllowMultiSelect = bAllowMultiSelect;
62 m_bShowInstrumentManipulationControls = bShowInstrumentManipulationControls;
63
64 m_pDirModel = new QFileSystemModel();
65 m_pDirModel->setRootPath(""); //see https://forum.qt.io/topic/99513/qfilesystemmodel-qtreeview-doesn-t-sort/2
66 m_pDirModel->setFilter( QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot );
67 m_pDirModel->setNameFilters( QStringList() << "*.ogg" << "*.OGG" << "*.wav" << "*.WAV" << "*.flac"<< "*.FLAC" << "*.aiff" << "*.AIFF"<< "*.au" << "*.AU" );
68 m_pDirModel->setNameFilterDisables(false);
69
70 m_ModelIndex = m_pDirModel->index( QDir::currentPath() );
71
72 m_pPlayBtn->setEnabled( false );
73 m_pStopBtn->setEnabled( false );
74 openBTN->setEnabled( false );
75
76 m_pTree = new QTreeView( treeView );
77 m_pTree->setModel( m_pDirModel );
78 m_pTree->resize( 799, 310 );
79 m_pTree->header()->resizeSection( 0, 405 );
80 m_pTree->setAlternatingRowColors( true );
81 m_pTree->setRootIndex( m_pDirModel->index( sDefaultPath ) );
82
83 pathLineEdit->setText( sDefaultPath );
85 m_pSelectedFile << "false" << "false";
86
88
89 m_pPathUptoolButton->setIcon( QIcon( Skin::getSvgImagePath() + "/icons/white/go-up.svg"));
90 m_pPathUptoolButton->setToolTip( QString( tr( "Parent Folder" )));
91 m_pPathHometoolButton->setIcon( QIcon( Skin::getSvgImagePath() + "/icons/white/home.svg"));
92 m_pPathHometoolButton->setToolTip( QString( tr( "Home" )));
93
94 m_pPlayBtn->setIcon( QIcon( Skin::getSvgImagePath() + "/icons/white/play.svg"));
95 m_pPlayBtn->setToolTip( QString( tr( "Play selected" ) ));
96 m_pStopBtn->setIcon( QIcon( Skin::getSvgImagePath() + "/icons/white/stop.svg"));
97 m_pStopBtn->setToolTip( QString( tr( "Stop" )));
98
99 m_pSampleWaveDisplay = new SampleWaveDisplay( waveformview );
101 m_pSampleWaveDisplay->move( 3, 3 );
102
103 playSamplescheckBox->setChecked( Preferences::get_instance()->__playsamplesonclicking );
104 //get the kde or gnome environment variable for mouse double or single clicking
105 m_SingleClick = false;
107
109 useNameCheckBox->hide();
110 autoVelCheckBox->hide();
111 }
112
113 if ( ! sFilename.isEmpty() ) {
114 m_pTree->setCurrentIndex( m_pDirModel->index( sFilename ) );
115 browseTree( m_pDirModel->index( sFilename ) );
116
117 // Right now in the constructor of AudioFileBrowser m_pTree is
118 // still busy doing something different or maybe some update
119 // is triggered afterwards. Either way, calling scrollTo()
120 // directly won't cut it. We have to wait a short amount of
121 // time till the dust has settled.
122 //
123 // The 50 is a heuristic that worked on my machine. This might
124 // need a little more tweaking.
125 QTimer::singleShot( 50, [this]{
126 m_pTree->scrollTo( m_pDirModel->index( m_sFilename ),
127 QAbstractItemView::PositionAtCenter);} );
128 }
129
130 connect( m_pTree, SIGNAL( clicked( const QModelIndex&) ), SLOT( clicked( const QModelIndex& ) ) );
131 connect( m_pTree, SIGNAL( doubleClicked( const QModelIndex&) ), SLOT( doubleClicked( const QModelIndex& ) ) );
132 connect( pathLineEdit, SIGNAL( returnPressed() ), SLOT( updateModelIndex() ) );
133}
134
135
136
143
144
145bool AudioFileBrowser::isFileSupported( QString filename )
146{
147 if (
148 ( filename.endsWith( ".ogg" ) ) ||
149 ( filename.endsWith( ".OGG" ) ) ||
150 ( filename.endsWith( ".wav" ) ) ||
151 ( filename.endsWith( ".WAV" ) ) ||
152 ( filename.endsWith( ".au" ) ) ||
153 ( filename.endsWith( ".AU" ) ) ||
154 ( filename.endsWith( ".aiff" ) ) ||
155 ( filename.endsWith( ".AIFF" ) ) ||
156 ( filename.endsWith( ".flac" ) ) ||
157 ( filename.endsWith( ".FLAC" ) )
158 ){
159 return true;
160 } else {
161 return false;
162 }
163}
164
165
167{
168 QString desktopSession = getenv("DESKTOP_SESSION");
169//kde
170 if( desktopSession == "kde" ) {
171 QFile envfile( QDir::homePath() + "/.kde/share/config/kdeglobals");
172
173 if ( !envfile.open(QIODevice::ReadOnly | QIODevice::Text) ) {
174 return;
175 }
176
177 QTextStream envin( &envfile );
178 while ( !envin.atEnd() ) {
179 QString envLine = envin.readLine();
180 if( envLine == QString("SingleClick=true" ) ) {
181 m_SingleClick = true;
182 break;
183 }
184 }
185 }
186
187//for gnome, xfce and all others we use double click as default
188}
189
190
191
193{
194 if( ( ev->modifiers()==Qt::ControlModifier ||
195 ev->modifiers()==Qt::ShiftModifier )
197 m_pTree->setSelectionMode( QAbstractItemView::ExtendedSelection );
198 openBTN->setEnabled( true );
199 }
200}
201
202
203
205{
206 m_pTree->setSelectionMode( QAbstractItemView::SingleSelection );
207}
208
209
210
212{
213 QString toRemove;
214 QString newPath = pathLineEdit->text();
215
216 if( QDir( newPath ).exists() ) {
217 m_pTree->setRootIndex( m_pDirModel->index( newPath ) );
218 } else {
219 toRemove = newPath.section( '/', -1 );
220// QMessageBox::information ( this, "Hydrogen", newpath + toremove);
221 newPath.replace( toRemove, "" );
222 m_pTree->setRootIndex( m_pDirModel->index( newPath ) );
223 }
224}
225
226
227
228void AudioFileBrowser::clicked( const QModelIndex& index )
229{
230 QString path = m_pDirModel->filePath( index );
231
232 if( m_SingleClick ) {
233 browseTree( index );
234 }
235
236 if( isFileSupported( path ) ) {
237 browseTree( index );
238 }
239}
240
241
242
243void AudioFileBrowser::doubleClicked( const QModelIndex& index )
244{
245 if(!m_SingleClick) {
246 browseTree( index );
247 }
248}
249
250
251
252void AudioFileBrowser::browseTree( const QModelIndex& index )
253{
254
255 QString path = m_pDirModel->filePath( index );
256 pathLineEdit->setText( path );
258
259 updateModelIndex(); //with this you have a navigation like konqueror
260
261 if ( m_pDirModel->isDir( index ) ){
262 m_pPlayBtn->setEnabled( false );
263 openBTN->setEnabled( false );
264 return;
265 }
266
267 QString name = path.section( '/', -1 );
268
269 QString path2 = path;
270 QString onlyPath = path;
271 if ( name != "" ){
272 onlyPath = path.replace( name, "" );
273 }
274
275 name = name.left( '.' );
276
277 QString message = QString( tr( "Name: " ) ).append( name );
278 pathLineEdit->setText( onlyPath );
279
280 QStringList path2List = path2.split("/");
281 QString fleTxt = path2List.last();
282
283 QApplication::setOverrideCursor(Qt::WaitCursor);
284
285 if( isFileSupported( path2 ) )
286 {
287
288 filelineedit->setText( fleTxt );
289 auto pNewSample = Sample::load( path2 );
290
291 if ( pNewSample != nullptr ) {
292 m_pNBytesLable->setText( tr( "Size: %1 bytes" ).arg( pNewSample->get_size() / 2 ) );
293 m_pSamplerateLable->setText( tr( "Samplerate: %1" ).arg( pNewSample->get_sample_rate() ) );
294 float sec = ( float )( pNewSample->get_frames() / (float)pNewSample->get_sample_rate() );
295 QString qsec;
296 qsec = QString::asprintf( "%2.2f", sec );
297 m_pLengthLable->setText( tr( "Sample length: " ) + qsec + tr( " s" ) );
298
299 m_pSampleFilename = path2;
300
302 m_pPlayBtn->setEnabled( true );
303 openBTN->setEnabled( true );
304
305 //important this will only working correct if m_pSampleWaveDisplay->updateDisplay( file )
306 //is ready with painting the wav file. else the playing sample get crackled sound!!
307 if (playSamplescheckBox->isChecked()){
308 if ( sec <= 600.00){
310 }else
311 {
312 QMessageBox::information ( this, "Hydrogen", tr( "Please do not preview samples which are longer than 10 minutes!" ) );
313 }
314 }
315 m_pNameLabel->setText( message );
316 } else {
317 openBTN->setEnabled( false );
318 QMessageBox::information ( this, "Hydrogen", tr( "Unable to load that sample file." ) );
319 }
320
321 }else{
322 m_pNameLabel->setText( tr( "Name:"));
323 m_pNBytesLable->setText( tr( "Size:" ) );
324 m_pSamplerateLable->setText( tr( "Samplerate:" ) );
325 m_pLengthLable->setText( tr( "Sample length:" ) );
327 m_pPlayBtn->setEnabled( false );
328 m_pStopBtn->setEnabled( false );
329 openBTN->setEnabled( false );
331 }
332 QApplication::restoreOverrideCursor();
333}
334
335
336
338{
339
340 if( QFile( m_pSampleFilename ).exists() == false ) {
341 return;
342 }
343
344 m_pStopBtn->setEnabled( true );
345
346 auto pNewSample = Sample::load( m_pSampleFilename );
347 if ( pNewSample ) {
348 assert(pNewSample->get_sample_rate() != 0);
349
350 int length = ( ( pNewSample->get_frames() / pNewSample->get_sample_rate() + 1) * 100 );
352 }
353}
354
355
356
358{
359 auto pNewSample = Sample::load( m_sEmptySampleFilename );
361 m_pStopBtn->setEnabled( false );
362}
363
364
365
367{
368 m_sSelectedDirectory = pathLineEdit->text();
369 m_pSelectedFile << "false" << "false" << "";
370 reject();
371}
372
373
374
376{
377 if( m_pTree->selectionModel()->selectedRows().size() > 0) {
378 QList<QModelIndex>::iterator i;
379 QList<QModelIndex> list = m_pTree->selectionModel()->selectedRows();
380
381 for (i = list.begin(); i != list.end(); ++i) {
382 QString path2 = (*i).data().toString();
383 if( isFileSupported( path2 ) ){
384 QString path = pathLineEdit->text();
385
386 if(! path.endsWith("/")) {
387 path = path + "/";
388 }
389
390 QString act_filename = path + path2;
391 m_pSelectedFile << act_filename ;
392 }
393 }
394 }
395
396 m_sSelectedDirectory = pathLineEdit->text();
397 accept();
398}
399
400
401
406
407
408
410{
411 if ( useNameCheckBox->isChecked() ) {
412 m_pSelectedFile[0] = "true";
413 }
414 if ( autoVelCheckBox->isChecked() ) {
415 m_pSelectedFile[1] = "true";
416 }
417 return m_pSelectedFile;
418}
419
423
425{
426
427 QString path = pathLineEdit->text();
428 QStringList pathlist = path.split("/");
429
430 while( path != QDir::rootPath() ){
431
432 if( pathlist.isEmpty () ) {
433 break;
434 }
435
436 pathlist.removeLast();
437 QString updir = pathlist.join("/");
438
439 pathLineEdit->setText( updir );
440 m_pTree->setRootIndex( m_pDirModel->index( updir ) );
441 m_pTree->collapse( m_pDirModel->index( updir ) );
442 m_pTree->setExpanded( m_pDirModel->index(updir), false );
443 path = pathLineEdit->text();
444 }
445
446 pathLineEdit->setText( QDir::homePath() );
447 m_pTree->setRootIndex( m_pDirModel->index( QDir::homePath() ) );
448
449 m_pTree->collapse( m_pDirModel->index( QDir::homePath()) );
450}
451
452
453
455{
456 QString path = pathLineEdit->text();
457 QStringList pathlist = path.split("/");
458
459 if( pathlist.isEmpty () ) {
460 return;
461 }
462
463 if( path.endsWith( "/" ) ) {
464 pathlist.removeLast();
465 QString tmpupdir = pathlist.join("/");
466 m_pTree->setRootIndex( m_pDirModel->index( tmpupdir ) );
467 m_pTree->collapse( m_pDirModel->index( tmpupdir ) );
468 m_pTree->setExpanded( m_pDirModel->index( tmpupdir ), false );
469 }
470
471 pathlist.removeLast();
472
473 QString updir = pathlist.join("/");
474 if ( updir == "" ) {
475 pathLineEdit->setText( QString("/") );
476 } else {
477 pathLineEdit->setText( updir );
478 }
479
480 m_pTree->setRootIndex( m_pDirModel->index( updir ) );
481 m_pTree->collapse( m_pDirModel->index( updir ) );
482 m_pTree->setExpanded( m_pDirModel->index(updir), false );
483}
484
485
486
488{
489 if ( hiddenCB->isChecked() ) {
490 m_pDirModel->setFilter( QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden );
491 } else {
492 m_pDirModel->setFilter( QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot );
493 m_pTree->setRootIndex( m_pDirModel->index( pathLineEdit->text() ) );
494 }
495}
#define INFOLOG(x)
Definition Object.h:237
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 QString empty_sample_path()
returns system empty sample file path
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:83
AudioEngine * getAudioEngine() const
Definition Hydrogen.h:649
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:1368
void updateDisplay(QString filename)
static QString getSvgImagePath()
Definition Skin.h:40