hydrogen 1.2.3
ExportSongDialog.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 <QProgressBar>
24#include <QLabel>
25
26#include "CommonStrings.h"
27#include "ExportSongDialog.h"
28#include "HydrogenApp.h"
29#include "Mixer/Mixer.h"
30#include "Widgets/FileDialog.h"
31
32#include <core/Basics/Note.h>
33#include <core/Basics/Pattern.h>
40#include <core/Basics/Song.h>
41#include <core/Hydrogen.h>
43#include <core/Timeline.h>
44#include <core/IO/AudioOutput.h>
48#include <core/EventQueue.h>
49
50#include <memory>
51
52#ifdef WIN32
53#include <time.h>
54#endif
55
56using namespace H2Core;
57
59
61{
62 int Index = 0;
63
64 switch ( interpolateMode ) {
65 case Interpolation::InterpolateMode::Linear:
66 Index = 0;
67 break;
68 case Interpolation::InterpolateMode::Cosine:
69 Index = 1;
70 break;
71 case Interpolation::InterpolateMode::Third:
72 Index = 2;
73 break;
74 case Interpolation::InterpolateMode::Cubic:
75 Index = 3;
76 break;
77 case Interpolation::InterpolateMode::Hermite:
78 Index = 4;
79 break;
80 }
81
82 return Index;
83}
84
85// Here we are going to store export filename
87
89 : QDialog(parent)
90 , m_bExporting( false )
91 , m_pHydrogen( Hydrogen::get_instance() )
92 , m_pPreferences( Preferences::get_instance() )
93{
94 setupUi( this );
95 setModal( true );
96 setWindowTitle( tr( "Export song" ) );
97
98 exportTypeCombo->addItem(tr("Export to a single track"));
99 exportTypeCombo->addItem(tr("Export to separate tracks"));
100 exportTypeCombo->addItem(tr("Both"));
101
103
104 m_pProgressBar->setValue( 0 );
105
106 m_bQfileDialog = false;
107 m_bExportTrackouts = false;
108 m_nInstrument = 0;
109 m_sExtension = ".wav";
110 m_bOverwriteFiles = false;
112
113 // use of rubberband batch
114 if( checkUseOfRubberband() ) {
115 toggleRubberbandCheckBox->setChecked( m_bOldRubberbandBatchMode );
116 connect(toggleRubberbandCheckBox, SIGNAL(toggled(bool)), this, SLOT(toggleRubberbandBatchMode( bool )));
117 } else {
118 toggleRubberbandCheckBox->setEnabled( false );
119 toggleRubberbandCheckBox->setToolTip( tr( "No sample in the current song uses Rubberband" ) );
120 }
121
122 // use of timeline
123 auto pSong = H2Core::Hydrogen::get_instance()->getSong();
124 toggleTimeLineBPMCheckBox->setChecked( pSong->getIsTimelineActivated());
125 m_bOldTimeLineBPMMode = pSong->getIsTimelineActivated();
126 connect(toggleTimeLineBPMCheckBox, SIGNAL(toggled(bool)), this, SLOT(toggleTimeLineBPMMode( bool )));
127
128 // use of interpolation mode
130 resampleComboBox->setCurrentIndex( interpolateModeToComboBoxIndex( m_OldInterpolationMode ) );
131 connect(resampleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resampleComboBoIndexChanged(int)));
132
133 //Load the other settings..
135
136 // Have the dialog find the best size
137 adjustSize();
138}
139
141{
142 if ( auto pH2App = HydrogenApp::get_instance() ) {
143 pH2App->removeEventListener( this );
144 }
145}
146
148{
149 QString sDefaultFilename = m_pHydrogen->getSong()->getFilename();
150
151 // If song is not saved then use song name otherwise use the song filename
152 if( sDefaultFilename.isEmpty() ){
153 sDefaultFilename = m_pHydrogen->getSong()->getName();
154 } else {
155 // extracting filename from full path
156 QFileInfo qDefaultFile( sDefaultFilename );
157 sDefaultFilename = qDefaultFile.fileName();
158 }
159
160 sDefaultFilename.replace( '*', "_" );
161 sDefaultFilename.replace( Filesystem::songs_ext, "" );
162 sDefaultFilename += m_sExtension;
163 return sDefaultFilename;
164}
165
167{
168 // extracting dirname from export box
169 QString sFilename = exportNameTxt->text();
170 QFileInfo info( sFilename );
171 QDir dir = info.absoluteDir();
172 if ( !dir.exists() ) {
173 // very strange if it happens but better to check for it anyway
174 return;
175 }
176
177 // saving filename for this session
178 sLastFilename = info.fileName();
180
181 // saving other options
182 m_pPreferences->setExportModeIdx( exportTypeCombo->currentIndex() );
183 m_pPreferences->setExportTemplateIdx( templateCombo->currentIndex() );
184 m_pPreferences->setExportSampleRateIdx( sampleRateCombo->currentIndex() );
185 m_pPreferences->setExportSampleDepthIdx( sampleDepthCombo->currentIndex() );
186}
187
189{
190 // loading previous directory and filling filename text field
191
192 // loading default filename on a first run and storing it in static field
193 if( sLastFilename.isEmpty() ) {
195 }
196
197 QString sDirPath = m_pPreferences->getLastExportSongDirectory();
198 QDir qd = QDir( sDirPath );
199
200 // joining filepath with dirname
201 QString sFullPath = qd.absoluteFilePath( sLastFilename );
202 exportNameTxt->setText( sFullPath );
203
204 // loading rest of the options
205 templateCombo->setCurrentIndex( m_pPreferences->getExportTemplateIdx() );
206 exportTypeCombo->setCurrentIndex( m_pPreferences->getExportModeIdx() );
207
208 int nExportSampleRateIdx = m_pPreferences->getExportSampleRateIdx();
209 if( nExportSampleRateIdx > 0 ) {
210 sampleRateCombo->setCurrentIndex( nExportSampleRateIdx );
211 } else {
212 sampleRateCombo->setCurrentIndex( 0 );
213 }
214
215
216 int nExportBithDepthIdx = m_pPreferences->getExportSampleDepthIdx();
217 if( nExportBithDepthIdx > 0 ) {
218 sampleDepthCombo->setCurrentIndex( nExportBithDepthIdx );
219 } else {
220 sampleDepthCombo->setCurrentIndex( 0 );
221 }
222}
223
225{
227 if ( ! Filesystem::dir_writable( sPath, false ) ){
228 sPath = QDir::homePath();
229 }
230
231 FileDialog fd(this);
232 fd.setFileMode(QFileDialog::AnyFile);
233
234 if( templateCombo->currentIndex() <= 4 ) {
235 fd.setNameFilter("Microsoft WAV (*.wav *.WAV)");
236 } else if ( templateCombo->currentIndex() > 4 && templateCombo->currentIndex() < 8 ) {
237 fd.setNameFilter( "Apple AIFF (*.aiff *.AIFF)");
238 } else if ( templateCombo->currentIndex() == 8 ) {
239 fd.setNameFilter( "Lossless Flac (*.flac *.FLAC)");
240 } else if ( templateCombo->currentIndex() == 9 ) {
241 fd.setNameFilter( "Compressed Ogg (*.ogg *.OGG)");
242 }
243
244 fd.setDirectory( sPath );
245 fd.setAcceptMode( QFileDialog::AcceptSave );
246 fd.setWindowTitle( tr( "Export song" ) );
247
248 QString defaultFilename = exportNameTxt->text();
249
250 fd.selectFile(defaultFilename);
251
252 QString filename = "";
253 if (fd.exec()) {
254 filename = fd.selectedFiles().first();
255 m_bQfileDialog = true;
256 }
257
258 if ( !filename.isEmpty() ) {
259 //this second extension check is mostly important if you leave a dot
260 //without a regular extionsion in a filename
261 if( !filename.endsWith( m_sExtension ) ){
262 filename.append(m_sExtension);
263 }
264
265 exportNameTxt->setText(filename);
266 }
267
268 if( filename.endsWith( ".ogg" ) || filename.endsWith( ".OGG" ) ){
269 sampleRateCombo->hide();
270 sampleDepthCombo->hide();
271 sampleRateLable->hide();
272 sampleDepthLable->hide();
273 }
274
275}
276
278{
279 // check if directory exists otherwise error
280 QString filename = exportNameTxt->text();
281 QFileInfo file( filename );
282 QDir dir = file.dir();
283 if( !dir.exists() ) {
284 QMessageBox::warning(
285 this, "Hydrogen",
286 tr( "Directory %1 does not exist").arg( dir.absolutePath() ),
287 QMessageBox::Ok
288 );
289 return false;
290 }
291
292 return true;
293}
294
296{
297 if ( m_bExporting ) {
298 return;
299 }
300
301 if( !validateUserInput() ) {
302 return;
303 }
304
306
307 auto pCommonStrings = HydrogenApp::get_instance()->getCommonStrings();
308
309 QFileInfo fileInfo( exportNameTxt->text() );
310 if ( ! Filesystem::dir_writable( fileInfo.absoluteDir().absolutePath(), false ) ) {
311 QMessageBox::warning( this, "Hydrogen",
312 pCommonStrings->getFileDialogMissingWritePermissions(),
313 QMessageBox::Ok );
314 return;
315 }
316
317 auto pPref = Preferences::get_instance();
318 std::shared_ptr<Song> pSong = m_pHydrogen->getSong();
319 auto pInstrumentList = pSong->getInstrumentList();
320
321 // License related export warnings
322 if ( pPref->m_bShowExportSongLicenseWarning ) {
323
324 QMessageBox licenseWarning( this );
325
326 auto drumkitContent =
327 pSong->getInstrumentList()->summarizeContent( pSong->getComponents() );
328
329 bool bHasAttribution = false;
330 bool bIsCopyleft = false;
331 QStringList licenses;
332 QString sLicense;
333 for ( const auto& ccontent : drumkitContent ) {
334 if ( ccontent->m_license.hasAttribution() ) {
335 sLicense = QString( "%1 (by %2)" )
336 .arg( ccontent->m_license.getLicenseString() )
337 .arg( ccontent->m_license.getCopyrightHolder() );
338 bHasAttribution = true;
339 }
340 else {
341 sLicense = ccontent->m_license.getLicenseString();
342 }
343
344 if ( ! licenses.contains( sLicense ) ) {
345 licenses << sLicense;
346
347 if ( ccontent->m_license.isCopyleft() ) {
348 bIsCopyleft = true;
349 }
350 }
351 }
352 QString sMsg = QString( tr( "Your song uses samples of the following license:" ) )
353 .append( "<ul>" );
354 for ( const auto& llicense : licenses ) {
355 sMsg.append( QString( "<li>%1</li>" ).arg( llicense ) );
356 }
357 sMsg.append( "</ul>" );
358
359 if ( bIsCopyleft ) {
360 sMsg.append( QString( "<p>%1</p>" )
361 .arg( pCommonStrings->getLicenseCopyleftWarning() ) );
362 }
363
364 if ( bHasAttribution ) {
365 sMsg.append( QString( "<p>%1</p>" )
366 .arg( pCommonStrings->getLicenseAttributionWarning() ) );
367 }
368
369 sMsg.append( "\n" ).append( tr( "Be sure you satisfy all license conditions and give the required attribution." ) );
370
371 licenseWarning.setWindowTitle( pCommonStrings->getLicenseWarningWindowTitle() );
372 licenseWarning.setText( sMsg );
373 licenseWarning.setTextFormat( Qt::RichText );
374
375 licenseWarning.addButton( pCommonStrings->getButtonOk(),
376 QMessageBox::AcceptRole );
377 auto pMuteButton =
378 licenseWarning.addButton( pCommonStrings->getMutableDialog(),
379 QMessageBox::YesRole );
380 auto pRejectButton =
381 licenseWarning.addButton( pCommonStrings->getButtonCancel(),
382 QMessageBox::RejectRole );
383 licenseWarning.exec();
384
385 if ( licenseWarning.clickedButton() == pMuteButton ) {
386 pPref->m_bShowExportSongLicenseWarning = false;
387 }
388 else if ( licenseWarning.clickedButton() == pRejectButton ) {
389 return;
390 }
391 }
392
393 m_bOverwriteFiles = false;
394
395 if( exportTypeCombo->currentIndex() == EXPORT_TO_SINGLE_TRACK || exportTypeCombo->currentIndex() == EXPORT_TO_BOTH ){
396 m_bExportTrackouts = false;
397
398 QString filename = exportNameTxt->text();
399 if ( fileInfo.exists() == true && m_bQfileDialog == false ) {
400
401 int res;
402 if( exportTypeCombo->currentIndex() == EXPORT_TO_SINGLE_TRACK ){
403 res = QMessageBox::information( this, "Hydrogen", tr( "The file %1 exists. \nOverwrite the existing file?").arg(filename), QMessageBox::Yes | QMessageBox::No );
404 } else {
405 res = QMessageBox::information( this, "Hydrogen", tr( "The file %1 exists. \nOverwrite the existing file?").arg(filename), QMessageBox::Yes | QMessageBox::No | QMessageBox::YesToAll);
406 }
407
408 if (res == QMessageBox::YesToAll ){
409 m_bOverwriteFiles = true;
410 }
411
412 if (res == QMessageBox::No ) {
413 return;
414 }
415 }
416
417 if( exportTypeCombo->currentIndex() == EXPORT_TO_BOTH ){
418 m_bExportTrackouts = true;
419 }
420
421 /* arm all tracks for export */
422 for (auto i = 0; i < pInstrumentList->size(); i++) {
423 pInstrumentList->get(i)->set_currently_exported( true );
424 }
425
426 if ( ! m_pHydrogen->startExportSession( sampleRateCombo->currentText().toInt(),
427 sampleDepthCombo->currentText().toInt()) ) {
428 QMessageBox::critical( this, "Hydrogen", tr( "Unable to export song" ) );
429 return;
430 }
431 m_pHydrogen->startExportSong( filename );
432 return;
433 }
434
435 if( exportTypeCombo->currentIndex() == EXPORT_TO_SEPARATE_TRACKS ){
436 m_bExportTrackouts = true;
437 m_pHydrogen->startExportSession(sampleRateCombo->currentText().toInt(), sampleDepthCombo->currentText().toInt());
438 exportTracks();
439 return;
440 }
441
442}
443
445{
446 std::shared_ptr<Song> pSong = m_pHydrogen->getSong();
447 unsigned nPatterns = pSong->getPatternList()->size();
448
449 bool bInstrumentHasNotes = false;
450
451 for ( unsigned i = 0; i < nPatterns; i++ ) {
452 Pattern *pPattern = pSong->getPatternList()->get( i );
453 const Pattern::notes_t* notes = pPattern->get_notes();
454 FOREACH_NOTE_CST_IT_BEGIN_LENGTH(notes,it,pPattern) {
455 Note *pNote = it->second;
456 assert( pNote );
457
458 if( pNote->get_instrument()->get_id() == pSong->getInstrumentList()->get(m_nInstrument)->get_id() ){
459 bInstrumentHasNotes = true;
460 break;
461 }
462 }
463 }
464
465 return bInstrumentHasNotes;
466}
467
468QString ExportSongDialog::findUniqueExportFilenameForInstrument( std::shared_ptr<Instrument> pInstrument )
469{
470 std::shared_ptr<Song> pSong = m_pHydrogen->getSong();
471 QString uniqueInstrumentName;
472
473 int instrumentOccurence = 0;
474 for(int i=0; i < pSong->getInstrumentList()->size(); i++ ){
475 if( pSong->getInstrumentList()->get(m_nInstrument)->get_name() == pInstrument->get_name()){
476 instrumentOccurence++;
477 }
478 }
479
480 if(instrumentOccurence >= 2){
481 uniqueInstrumentName = pInstrument->get_name() + QString("_") + QString::number( pInstrument->get_id() );
482 } else {
483 uniqueInstrumentName = pInstrument->get_name();
484 }
485
486 return uniqueInstrumentName;
487}
488
490{
491 std::shared_ptr<Song> pSong = m_pHydrogen->getSong();
492 auto pInstrumentList = pSong->getInstrumentList();
493
494 if( m_nInstrument < pInstrumentList->size() ){
495
496 //if a instrument contains no notes we jump to the next instrument
497 bool bInstrumentHasNotes = currentInstrumentHasNotes();
498
499 if( !bInstrumentHasNotes ){
500 if( m_nInstrument == pInstrumentList->size() -1 ){
501 m_bExportTrackouts = false;
502 m_nInstrument = 0;
503 return;
504 } else {
506 exportTracks();
507 return;
508 }
509 }
510
511 QStringList filenameList = exportNameTxt->text().split( m_sExtension );
512
513 QString firstItem;
514 if( !filenameList.isEmpty() ){
515 firstItem = filenameList.first();
516 }
517 QString newItem = firstItem + "-" + findUniqueExportFilenameForInstrument( pInstrumentList->get( m_nInstrument ) );
518
519 QString filename = newItem.append( m_sExtension );
520
521 if ( QFile( filename ).exists() == true && m_bQfileDialog == false && !m_bOverwriteFiles) {
522 int res = QMessageBox::information( this, "Hydrogen", tr( "The file %1 exists. \nOverwrite the existing file?").arg(filename), QMessageBox::Yes | QMessageBox::No | QMessageBox::YesToAll );
523 if (res == QMessageBox::No ) return;
524 if (res == QMessageBox::YesToAll ) m_bOverwriteFiles = true;
525 }
526
527 if( m_nInstrument > 0 ){
529 m_bExporting = false;
530 }
531
532 for (auto i = 0; i < pInstrumentList->size(); i++) {
533 pInstrumentList->get(i)->set_currently_exported( false );
534 }
535
536 pSong->getInstrumentList()->get(m_nInstrument)->set_currently_exported( true );
537
538 m_pHydrogen->startExportSong( filename );
539
540 if(! (m_nInstrument == pInstrumentList->size()) ){
542 }
543 }
544
545}
546
547void ExportSongDialog::closeEvent( QCloseEvent *event ) {
548 UNUSED( event );
549 closeExport();
550}
573
574
576{
590 QString filename;
591 QStringList splitty;
592
593 filename = exportNameTxt->text();
594 splitty = filename.split(".");
595 splitty.removeLast();
596 filename = splitty.join( "." );
597
598 switch ( index ) {
599 case 0:
600 sampleRateCombo->show();
601 sampleDepthCombo->show();
602 sampleRateCombo->setCurrentIndex ( 1 ); //44100hz
603 sampleDepthCombo->setCurrentIndex ( 1 ); //16bit
604 filename += ".wav";
605 m_sExtension = ".wav";
606 break;
607 case 1:
608 sampleRateCombo->show();
609 sampleDepthCombo->show();
610 sampleRateCombo->setCurrentIndex ( 2 ); //48000hz
611 sampleDepthCombo->setCurrentIndex ( 1 ); //16bit
612 filename += ".wav";
613 m_sExtension = ".wav";
614 break;
615 case 2:
616 sampleRateCombo->show();
617 sampleDepthCombo->show();
618 sampleRateCombo->setCurrentIndex ( 2 ); //48000hz
619 sampleDepthCombo->setCurrentIndex ( 2 ); //24bit
620 filename += ".wav";
621 m_sExtension = ".wav";
622 break;
623 case 3:
624 sampleRateCombo->show();
625 sampleDepthCombo->show();
626 sampleRateCombo->setCurrentIndex ( 0 ); //22050hz
627 sampleDepthCombo->setCurrentIndex ( 0 ); //8bit
628 filename += ".wav";
629 m_sExtension = ".wav";
630 break;
631 case 4:
632 sampleRateCombo->show();
633 sampleDepthCombo->show();
634 sampleRateCombo->setCurrentIndex ( 4 ); //96000hz
635 sampleDepthCombo->setCurrentIndex ( 3 ); //32bit
636 filename += ".wav";
637 m_sExtension = ".wav";
638 break;
639 case 5:
640 sampleRateCombo->show();
641 sampleDepthCombo->show();
642 sampleRateCombo->setCurrentIndex ( 1 ); //44100hz
643 sampleDepthCombo->setCurrentIndex ( 1 ); //16bit
644 filename += ".aiff";
645 m_sExtension = ".aiff";
646 break;
647 case 6:
648 sampleRateCombo->show();
649 sampleDepthCombo->show();
650 sampleRateCombo->setCurrentIndex ( 2 ); //48000hz
651 sampleDepthCombo->setCurrentIndex ( 1 ); //16bit
652 filename += ".aiff";
653 m_sExtension = ".aiff";
654 break;
655 case 7:
656 sampleRateCombo->show();
657 sampleDepthCombo->show();
658 sampleRateCombo->setCurrentIndex ( 2 ); //48000hz
659 sampleDepthCombo->setCurrentIndex ( 2 ); //24bit
660 filename += ".aiff";
661 m_sExtension = ".aiff";
662 break;
663 case 8:
664 sampleRateCombo->show();
665 sampleDepthCombo->show();
666 sampleRateCombo->setCurrentIndex ( 2 ); //48000hz
667 sampleDepthCombo->setCurrentIndex ( 2 ); //24bit
668 filename += ".flac";
669 m_sExtension = ".flac";
670 break;
671 case 9:
672 sampleRateCombo->hide();
673 sampleDepthCombo->hide();
674 sampleRateLable->hide();
675 sampleDepthLable->hide();
676 filename += ".ogg";
677 m_sExtension = ".ogg";
678 break;
679
680 default:
681 sampleRateCombo->show();
682 sampleDepthCombo->show();
683 sampleRateCombo->setCurrentIndex ( 1 ); //44100hz
684 sampleDepthCombo->setCurrentIndex ( 1 ); //16bit
685 filename += ".wav";
686 m_sExtension = ".wav";
687 }
688
689 exportNameTxt->setText(filename);
690
691}
692
693
695{
696 QString filename = exportNameTxt->text();
697 if ( ! filename.isEmpty() ) {
698 okBtn->setEnabled(true);
699 }
700 else {
701 okBtn->setEnabled(false);
702 }
703
704 if( filename.endsWith( ".ogg" ) || filename.endsWith( ".OGG" ) ){
705 if( templateCombo->currentIndex() != 9 ){
706 templateCombo->setCurrentIndex( 9 );//ogg
707 }
708 }
709 else if( filename.endsWith( ".flac" ) || filename.endsWith( ".FLAC" ) ){
710 sampleRateLable->show();
711 sampleDepthLable->show();
712 if( templateCombo->currentIndex() != 8 ){
713 templateCombo->setCurrentIndex( 8 );//flac
714 }
715 }
716 else if( filename.endsWith( ".aiff" ) || filename.endsWith( ".AIFF" ) ){
717 sampleRateLable->show();
718 sampleDepthLable->show();
719 if( templateCombo->currentIndex() < 5 || templateCombo->currentIndex() > 7 ){
720 templateCombo->setCurrentIndex( 5 );//aiff
721 }
722 }
723 else if( filename.endsWith( ".wav" ) || filename.endsWith( ".WAV" ) ){
724 sampleRateLable->show();
725 sampleDepthLable->show();
726 if( templateCombo->currentIndex() > 4 ){
727 templateCombo->setCurrentIndex( 0 );//wav
728
729 }
730 }
731}
732
734{
735 m_pProgressBar->setValue( nValue );
736 if ( nValue == 100 ) {
737
738 m_bExporting = false;
739
740 if( m_nInstrument == Hydrogen::get_instance()->getSong()->getInstrumentList()->size()){
741 m_nInstrument = 0;
742 m_bExportTrackouts = false;
743 }
744
745 if( m_bExportTrackouts ){
746 exportTracks();
747 }
748 }
749
750 if ( nValue < 100 ) {
751 closeBtn->setEnabled(false);
752 resampleComboBox->setEnabled(false);
753
754 }else
755 {
756 closeBtn->setEnabled(true);
757 resampleComboBox->setEnabled(true);
758 }
759}
760
765
770
775
777{
778 switch ( index ){
779 case 0:
780 m_pHydrogen->getAudioEngine()->getSampler()->setInterpolateMode( Interpolation::InterpolateMode::Linear );
781 break;
782 case 1:
783 m_pHydrogen->getAudioEngine()->getSampler()->setInterpolateMode( Interpolation::InterpolateMode::Cosine );
784 break;
785 case 2:
786 m_pHydrogen->getAudioEngine()->getSampler()->setInterpolateMode( Interpolation::InterpolateMode::Third );
787 break;
788 case 3:
789 m_pHydrogen->getAudioEngine()->getSampler()->setInterpolateMode( Interpolation::InterpolateMode::Cubic );
790 break;
791 case 4:
792 m_pHydrogen->getAudioEngine()->getSampler()->setInterpolateMode( Interpolation::InterpolateMode::Hermite );
793 break;
794 }
795}
796
798{
799 std::shared_ptr<Song> pSong = m_pHydrogen->getSong();
800 assert(pSong);
801
802 if(pSong){
803 auto pSongInstrList = pSong->getInstrumentList();
804 assert(pSongInstrList);
805 for ( unsigned nInstr = 0; nInstr < pSongInstrList->size(); ++nInstr ) {
806 auto pInstr = pSongInstrList->get( nInstr );
807 assert( pInstr );
808 if ( pInstr ){
809 for ( const auto& pCompo : *pInstr->get_components() ) {
810 for ( int nLayer = 0; nLayer < InstrumentComponent::getMaxLayers(); nLayer++ ) {
811 auto pLayer = pCompo->get_layer( nLayer );
812 if ( pLayer ) {
813 auto pSample = pLayer->get_sample();
814 if ( pSample != nullptr ) {
815 if( pSample->get_rubberband().use ) {
816 return true;
817 }
818 }
819 }
820 }
821 }
822 }
823 }
824 }
825 return false;
826}
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
Definition AudioEngine.h:59
@ EXPORT_TO_BOTH
@ EXPORT_TO_SEPARATE_TRACKS
@ EXPORT_TO_SINGLE_TRACK
static int interpolateModeToComboBoxIndex(Interpolation::InterpolateMode interpolateMode)
#define FOREACH_NOTE_CST_IT_BEGIN_LENGTH(_notes, _it, _pattern)
Iterate over all accessible notes between position 0 and length of _pattern in an immutable way.
Definition Pattern.h:285
static QString sLastFilename
virtual void progressEvent(int nValue) override
void toggleRubberbandBatchMode(bool toggled)
void setResamplerMode(int index)
void on_templateCombo_currentIndexChanged(int index)
H2Core::Preferences * m_pPreferences
QString createDefaultFilename()
QString findUniqueExportFilenameForInstrument(std::shared_ptr< H2Core::Instrument > pInstrument)
void closeEvent(QCloseEvent *event) override
void on_exportNameTxt_textChanged(const QString &text)
void restoreSettingsFromPreferences()
ExportSongDialog(QWidget *parent)
InterpolateMode m_OldInterpolationMode
void resampleComboBoIndexChanged(int index)
void toggleTimeLineBPMMode(bool toggled)
H2Core::Hydrogen * m_pHydrogen
Custom file dialog checking whether the user has write access to the selected folder before allowing ...
Definition FileDialog.h:33
void unlock()
Mutex unlocking of the AudioEngine.
void lock(const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
Sampler * getSampler() const
const std::shared_ptr< TransportPosition > getTransportPosition() const
static bool dir_writable(const QString &path, bool silent=false)
returns true if the given path is a writable regular directory
static const QString songs_ext
Definition Filesystem.h:87
Hydrogen Audio Engine.
Definition Hydrogen.h:54
bool startExportSession(int rate, int depth)
Definition Hydrogen.cpp:631
std::shared_ptr< Song > getSong() const
Get the current song.
Definition Hydrogen.h:122
void setIsTimelineActivated(bool bEnabled)
Wrapper around both Song::setIsTimelineActivated (recent) and Preferences::setUseTimelinebpm() (forme...
void stopExportSession()
Definition Hydrogen.cpp:699
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:83
void startExportSong(const QString &filename)
Export a song to a wav file.
Definition Hydrogen.cpp:680
AudioEngine * getAudioEngine() const
Definition Hydrogen.h:649
void stopExportSong()
Definition Hydrogen.cpp:692
void recalculateRubberband(float fBpm)
Recalculates all Samples using RubberBand for a specific tempo fBpm.
A note plays an associated instrument with a velocity left and right pan.
Definition Note.h:102
std::shared_ptr< Instrument > get_instrument()
__instrument accessor
Definition Note.h:500
Pattern class is a Note container.
Definition Pattern.h:46
const notes_t * get_notes() const
get the virtual pattern set
Definition Pattern.h:355
std::multimap< int, Note * > notes_t
< multimap note type
Definition Pattern.h:50
Manager for User Preferences File (singleton)
Definition Preferences.h:78
int getExportSampleDepthIdx() const
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
void setExportTemplateIdx(int nExportTemplateIdx)
int getExportSampleRateIdx() const
int getExportModeIdx() const
void setExportModeIdx(int nExportMode)
int getExportTemplateIdx() const
void setRubberBandBatchMode(int val)
void setExportSampleDepthIdx(int nExportSampleDepthIdx)
void setLastExportSongDirectory(QString sPath)
void setExportSampleRateIdx(int nExportSampleRateIdx)
QString getLastExportSongDirectory() const
Interpolation::InterpolateMode getInterpolateMode()
Definition Sampler.h:212
void setInterpolateMode(Interpolation::InterpolateMode mode)
Definition Sampler.h:200
void addEventListener(EventListener *pListener)
static HydrogenApp * get_instance()
Returns the instance of HydrogenApp class.
std::shared_ptr< CommonStrings > getCommonStrings()
#define UNUSED(v)
Definition Globals.h:42