hydrogen 1.2.3
SampleEditor.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 "SampleEditor.h"
24#include "../HydrogenApp.h"
25#include "../CommonStrings.h"
28
30#include "DetailWaveDisplay.h"
31#include "TargetWaveDisplay.h"
32
33#include <core/H2Exception.h>
35#include <core/Basics/Sample.h>
36#include <core/Basics/Note.h>
43#include <core/Hydrogen.h>
44
45#include <QModelIndex>
46#include <QTreeWidget>
47#include <QMessageBox>
48#include <algorithm>
49#include <memory>
50
51using namespace H2Core;
52
53
54SampleEditor::SampleEditor ( QWidget* pParent, int nSelectedComponent, int nSelectedLayer, QString sSampleFilename )
55 : QDialog ( pParent )
56 , Object ()
57{
58 setupUi ( this );
59
60
61 m_pTimer = new QTimer(this);
62 connect(m_pTimer, SIGNAL(timeout()), this, SLOT(updateMainsamplePositionRuler()));
63 m_pTargetDisplayTimer = new QTimer(this);
64 connect(m_pTargetDisplayTimer, SIGNAL(timeout()), this, SLOT(updateTargetsamplePositionRuler()));
65
66 setClean();
67 m_nSelectedLayer = nSelectedLayer;
68 m_nSelectedComponent = nSelectedComponent;
69 m_sSampleName = sSampleFilename;
70 m_fZoomfactor = 1;
72 m_sLineColor = "default";
73 m_bOnewayStart = false;
74 m_bOnewayLoop = false;
75 m_bOnewayEnd = false;
76 m_nSlframes = 0;
77 m_pPositionsRulerPath = nullptr;
78 m_bPlayButton = false;
79 m_fRatio = 1.0f;
81
82 QString newfilename = sSampleFilename.section( '/', -1 );
83
84 //init Displays
85 m_pMainSampleWaveDisplay = new MainSampleWaveDisplay( mainSampleview );
86 m_pSampleAdjustView = new DetailWaveDisplay( mainSampleAdjustView );
87 m_pTargetSampleView = new TargetWaveDisplay( targetSampleView );
88
89 setWindowTitle ( QString( tr( "SampleEditor " ) + newfilename) );
90 setModal ( true );
91
92 //this new sample give us the not changed real samplelength
93 m_pSampleFromFile = Sample::load( sSampleFilename );
94 if ( m_pSampleFromFile == nullptr ) {
95 reject();
96 }
97
98 unsigned slframes = m_pSampleFromFile->get_frames();
99
100 LoopCountSpinBox->setRange(0, 20000 );
101 StartFrameSpinBox->setRange(0, slframes );
102 LoopFrameSpinBox->setRange(0, slframes );
103 EndFrameSpinBox->setRange(0, slframes );
104 EndFrameSpinBox->setValue( slframes );
105 rubberbandCsettingscomboBox->setCurrentIndex( 4 );
106 rubberComboBox->setCurrentIndex( 0 );
107
108 // Make things consistent with the LCDDisplay and LCDSpinBox classes.
109 pitchdoubleSpinBox->setLocale( QLocale( QLocale::C, QLocale::AnyCountry ) );
110
111 __rubberband.use = false;
112 __rubberband.divider = 1.0;
113 openDisplays();
115
116 adjustSize();
117 setFixedSize ( width(), height() );
118
119#ifndef H2CORE_HAVE_RUBBERBAND
120 if ( !Filesystem::file_executable( Preferences::get_instance()->m_rubberBandCLIexecutable , true /* silent */) ) {
121 RubberbandCframe->setDisabled ( true );
122 setClean();
123 }
124#else
125 RubberbandCframe->setDisabled ( false );
126 setClean();
127#endif
128
129 __rubberband.pitch = 0.0;
130
131 m_bAdjusting = false;
133}
134
135
136
138{
141 m_pMainSampleWaveDisplay = nullptr;
142
143 m_pSampleAdjustView->close();
144 delete m_pSampleAdjustView;
145 m_pSampleAdjustView = nullptr;
146
147 m_pTargetSampleView->close();
148 delete m_pTargetSampleView;
149 m_pTargetSampleView = nullptr;
150
151 INFOLOG ( "DESTROY" );
152}
153
154
155void SampleEditor::closeEvent(QCloseEvent *event)
156{
157 if ( !m_bSampleEditorClean ) {
158 auto pCommonStrings = HydrogenApp::get_instance()->getCommonStrings();
159 int err = QMessageBox::information( this, "Hydrogen",
160 pCommonStrings->getUnsavedChanges(),
161 pCommonStrings->getButtonOk(),
162 pCommonStrings->getButtonCancel(),
163 nullptr, 1 );
164 if ( err == 0 ) {
165 setClean();
166 accept();
167 } else {
168 event->ignore();
169 return;
170 }
171 } else {
172 accept();
173 }
174}
175
176std::shared_ptr<Sample> SampleEditor::retrieveSample() const {
177
178 auto pInstrument = Hydrogen::get_instance()->getSelectedInstrument();
179 if ( pInstrument == nullptr ) {
180 ERRORLOG( "No instrument selected" );
181 return nullptr;
182 }
183
184 auto pCompo = pInstrument->get_component( m_nSelectedComponent );
185 if ( pCompo == nullptr ) {
186 ERRORLOG( QString( "Invalid component [%1]" ).arg( m_nSelectedComponent ) );
187 assert( pCompo );
188 return nullptr;
189 }
190
191 auto pLayer = pCompo->get_layer( m_nSelectedLayer );
192 if ( pLayer == nullptr ) {
193 ERRORLOG( QString( "Invalid layer [%1]" ).arg( m_nSelectedLayer ) );
194 assert( pLayer );
195 return nullptr;
196 }
197
198 return pLayer->get_sample();
199}
200
202{
203 auto pInstrument = Hydrogen::get_instance()->getSelectedInstrument();
204 if ( pInstrument == nullptr ) {
205 ERRORLOG( "No instrument selected" );
206 return;
207 }
208
209 auto pCompo = pInstrument->get_component( m_nSelectedComponent );
210 if ( pCompo == nullptr ) {
211 ERRORLOG( QString( "Invalid component [%1]" ).arg( m_nSelectedComponent ) );
212 assert( pCompo );
213 return;
214 }
215
216 auto pLayer = pCompo->get_layer( m_nSelectedLayer );
217 if ( pLayer == nullptr ) {
218 ERRORLOG( QString( "Invalid layer [%1]" ).arg( m_nSelectedLayer ) );
219 assert( pLayer );
220 return;
221 }
222
223 auto pSample = pLayer->get_sample();
224 if ( pSample == nullptr ) {
225 ERRORLOG( "Unable to retrieve sample" );
226 assert( pSample );
227 return;
228 }
229
230 // this values are needed if we restore a sample from disk if a
231 // new song with sample changes will load
232 m_bSampleIsModified = pSample->get_is_modified();
233 m_nSamplerate = pSample->get_sample_rate();
234 __loops = pSample->get_loops();
235 __rubberband = pSample->get_rubberband();
236
237 if ( pSample->get_velocity_envelope()->size()==0 ) {
239 m_pTargetSampleView->get_velocity()->push_back( EnvelopePoint( 0, 0 ) );
241 } else {
243
244 for(auto& pt : *pSample->get_velocity_envelope() ){
245 m_pTargetSampleView->get_velocity()->emplace_back( pt );
246 }
247 }
248
249 if ( pSample->get_pan_envelope()->size()==0 ) {
250 m_pTargetSampleView->get_pan()->clear();
251 m_pTargetSampleView->get_pan()->push_back( EnvelopePoint( 0, m_pTargetSampleView->height()/2 ) );
252 m_pTargetSampleView->get_pan()->push_back( EnvelopePoint( m_pTargetSampleView->width(), m_pTargetSampleView->height()/2 ) );
253 } else {
254 for(auto& pt : *pSample->get_pan_envelope() ){
255 m_pTargetSampleView->get_pan()->emplace_back( pt );
256 }
257 }
258
260 __loops.end_frame = pSample->get_loops().end_frame;
262 ProcessingTypeComboBox->setCurrentIndex ( 0 );
263 }
265 ProcessingTypeComboBox->setCurrentIndex ( 1 );
266 }
268 ProcessingTypeComboBox->setCurrentIndex ( 2 );
269 }
270
271 StartFrameSpinBox->setValue( __loops.start_frame );
272 LoopFrameSpinBox->setValue( __loops.loop_frame );
273 EndFrameSpinBox->setValue( __loops.end_frame );
274 LoopCountSpinBox->setValue( __loops.count );
275
282
283 if( !__rubberband.use ) {
284 rubberComboBox->setCurrentIndex( 0 );
285 }
286
287 rubberbandCsettingscomboBox->setCurrentIndex( __rubberband.c_settings );
288 if( !__rubberband.use ) {
289 rubberbandCsettingscomboBox->setCurrentIndex( 4 );
290 }
291
292 pitchdoubleSpinBox->setValue( __rubberband.pitch );
293 if( !__rubberband.use ) {
294 pitchdoubleSpinBox->setValue( 0.0 );
295 }
296
297 if( __rubberband.divider == 1.0/64.0) {
298 rubberComboBox->setCurrentIndex( 1 );
299 }
300 else if( __rubberband.divider == 1.0/32.0) {
301 rubberComboBox->setCurrentIndex( 2 );
302 } else if( __rubberband.divider == 1.0/16.0) {
303 rubberComboBox->setCurrentIndex( 3 );
304 } else if( __rubberband.divider == 1.0/8.0) {
305 rubberComboBox->setCurrentIndex( 4 );
306 } else if( __rubberband.divider == 1.0/4.0) {
307 rubberComboBox->setCurrentIndex( 5 );
308 } else if( __rubberband.divider == 1.0/2.0) {
309 rubberComboBox->setCurrentIndex( 6 );
310 } else if( __rubberband.use && ( __rubberband.divider >= 1.0 ) ) {
311 rubberComboBox->setCurrentIndex( (int)(__rubberband.divider + 6) );
312 }
313
316
317 }
319
320 connect( StartFrameSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( valueChangedStartFrameSpinBox(int) ) );
321 connect( LoopFrameSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( valueChangedLoopFrameSpinBox(int) ) );
322 connect( EndFrameSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( valueChangedEndFrameSpinBox(int) ) );
323 connect( LoopCountSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( valueChangedLoopCountSpinBox( int ) ) );
324 connect( ProcessingTypeComboBox, SIGNAL( currentIndexChanged ( const QString ) ), this, SLOT( valueChangedProcessingTypeComboBox( const QString ) ) );
325 connect( rubberComboBox, SIGNAL( currentIndexChanged ( const QString ) ), this, SLOT( valueChangedrubberComboBox( const QString ) ) );
326 connect( rubberbandCsettingscomboBox, SIGNAL( currentIndexChanged ( const QString ) ), this, SLOT( valueChangedrubberbandCsettingscomboBox( const QString ) ) );
327 connect( pitchdoubleSpinBox, SIGNAL ( valueChanged( double ) ), this, SLOT( valueChangedpitchdoubleSpinBox( double ) ) );
328}
329
331{
332 __loops.start_frame = StartFrameSpinBox->value();
333 __loops.loop_frame = LoopFrameSpinBox->value();
334 __loops.count = LoopCountSpinBox->value();
335 __loops.end_frame = EndFrameSpinBox->value();
336}
337
338
339
341{
342 // wavedisplays
345 m_pMainSampleWaveDisplay->move( 1, 1 );
346
348 m_pSampleAdjustView->move( 1, 1 );
349
350 m_pTargetSampleView->move( 1, 1 );
351}
352
353
354
356{
357 if ( !m_bSampleEditorClean ){
358 auto pCommonStrings = HydrogenApp::get_instance()->getCommonStrings();
359 int err = QMessageBox::information( this, "Hydrogen",
360 pCommonStrings->getUnsavedChanges(),
361 pCommonStrings->getButtonOk(),
362 pCommonStrings->getButtonCancel(),
363 nullptr, 1 );
364 if ( err == 0 ){
365 setClean();
366 accept();
367 }else
368 {
369 return;
370 }
371 }else
372 {
373 accept();
374 }
375}
376
377
378
380{
381 QApplication::setOverrideCursor(Qt::WaitCursor);
384 setClean();
386 QApplication::restoreOverrideCursor();
388}
389
390
391
393{
394 auto pCommonStrings = HydrogenApp::get_instance()->getCommonStrings();
395
396 bool close = false;
397 int err = QMessageBox::information( this, "Hydrogen",
398 pCommonStrings->getUnsavedChanges(),
399 pCommonStrings->getButtonOk(),
400 pCommonStrings->getButtonCancel(),
401 nullptr, 1 );
402 if ( err == 0 ) {
403 close = true;
404 }
405
406 return close;
407}
408
409
410
412{
413 if ( !m_bSampleEditorClean ){
414
415 auto pHydrogen = H2Core::Hydrogen::get_instance();
416 auto pAudioEngine = pHydrogen->getAudioEngine();
417 auto pOldSample = retrieveSample();
418 if ( pOldSample == nullptr ) {
419 ERRORLOG( "Unable to retrieve sample" );
420 assert( pOldSample );
421 return;
422 }
423
424 auto pEditSample = std::make_shared<Sample>( m_sSampleName,
425 pOldSample->getLicense() );
426 pEditSample->set_loops( __loops );
427 pEditSample->set_rubberband( __rubberband );
428 pEditSample->set_velocity_envelope( *m_pTargetSampleView->get_velocity() );
429 pEditSample->set_pan_envelope( *m_pTargetSampleView->get_pan() );
430
431 if( ! pEditSample->load( pAudioEngine->getTransportPosition()->getBpm() ) ){
432 ERRORLOG( "Unable to load modified sample" );
433 return;
434 }
435
436 pAudioEngine->lock( RIGHT_HERE );
437
438 std::shared_ptr<H2Core::Instrument> pInstrument = nullptr;
439 auto pSong = pHydrogen->getSong();
440 if ( pSong != nullptr ) {
441 auto pInstrList = pSong->getInstrumentList();
442 int nInstr = pHydrogen->getSelectedInstrumentNumber();
443 if ( nInstr >= static_cast<int>(pInstrList->size()) ) {
444 nInstr = -1;
445 }
446
447 if (nInstr == -1) {
448 pInstrument = nullptr;
449 }
450 else {
451 pInstrument = pInstrList->get( nInstr );
452 }
453 }
454
455 std::shared_ptr<H2Core::InstrumentLayer> pLayer = nullptr;
456 if( pInstrument != nullptr ) {
457 pLayer = pInstrument->get_component( m_nSelectedComponent )->get_layer( m_nSelectedLayer );
458
459 // insert new sample from newInstrument
460 pLayer->set_sample( pEditSample );
461 }
462
463 pAudioEngine->unlock();
464
465 if ( pLayer != nullptr ) {
467 }
468 }
469}
470
471
472
474{
475
476}
477
478
479
481{
482 m_bAdjusting = true;
483
484 testpTimer();
485// QMessageBox::information ( this, "Hydrogen", tr ( "jep %1" ).arg(m_pSample->get_frames()));
486 m_bSampleIsModified = true;
490 StartFrameSpinBox->setValue( __loops.start_frame );
491 LoopFrameSpinBox->setValue( __loops.loop_frame );
492 EndFrameSpinBox->setValue( __loops.end_frame );
493 m_bOnewayStart = true;
494 m_bOnewayLoop = true;
495 m_bOnewayEnd = true;
497 m_bAdjusting = false;
498 setUnclean();
499 return true;
500}
501
507
509{
510 m_bSampleEditorClean = false;
511 PrevChangesPushButton->setDisabled ( false );
512 PrevChangesPushButton->setFlat ( false );
513 // PrevChangesPushButton->show();
514}
515
517{
519 PrevChangesPushButton->setDisabled ( true );
520 PrevChangesPushButton->setFlat ( true );
521}
522
547
571
595
597{
598 Hydrogen* pHydrogen = Hydrogen::get_instance();
599 auto pAudioEngine = pHydrogen->getAudioEngine();
600
601 if (PlayPushButton->text() == "Stop" ){
602 testpTimer();
603 return;
604 }
605
606 const int selectedLayer = InstrumentEditorPanel::get_instance()->getSelectedLayer();
607
608 std::shared_ptr<Song> pSong = Hydrogen::get_instance()->getSong();
609 if ( pSong == nullptr ) {
610 return;
611 }
612 auto pInstr = pSong->getInstrumentList()->get( Hydrogen::get_instance()->getSelectedInstrumentNumber() );
613 if ( pInstr == nullptr ) {
614 return;
615 }
616 auto pCompo = pInstr->get_component( m_nSelectedComponent );
617 if ( pCompo == nullptr ) {
618 return;
619 }
620 auto pLayer = pCompo->get_layer( selectedLayer );
621 if ( pLayer == nullptr ) {
622 return;
623 }
624 Note *pNote = new Note( pInstr, 0, pLayer->get_end_velocity() - 0.01 );
626 pHydrogen->getAudioEngine()->getSampler()->noteOn(pNote);
627
630 m_bPlayButton = true;
631 m_pMainSampleWaveDisplay->paintLocatorEvent( StartFrameSpinBox->value() / m_divider + 24 , true);
633
634 if( __rubberband.use == false ){
635 m_pTimer->start(40); // update ruler at 25 fps
636 }
637
638
639 m_nRealtimeFrameEnd = pAudioEngine->getRealtimeFrame() + m_nSlframes;
640
641 //calculate the new rubberband sample length
642 if( __rubberband.use ){
643 m_nRealtimeFrameEndForTarget = pAudioEngine->getRealtimeFrame() + (m_nSlframes * m_fRatio + 0.1);
644 }else
645 {
647 }
648 m_pTargetDisplayTimer->start(40); // update ruler at 25 fps
649 PlayPushButton->setText( QString( "Stop") );
650
651}
652
654{
655 if (PlayOrigPushButton->text() == "Stop" ){
656 testpTimer();
657 return;
658 }
659
660 const int selectedlayer = InstrumentEditorPanel::get_instance()->getSelectedLayer();
661 std::shared_ptr<Song> pSong = Hydrogen::get_instance()->getSong();
662 auto pInstr = pSong->getInstrumentList()->get( Hydrogen::get_instance()->getSelectedInstrumentNumber() );
663 if ( pInstr == nullptr ) {
664 DEBUGLOG( "No instrument selected" );
665 return;
666 }
667
668 /*
669 *preview_instrument deletes the last used preview instrument, therefore we have to construct a temporary
670 *instrument. Otherwise pInstr would be deleted if consumed by preview_instrument.
671 */
672 auto pTmpInstrument = Instrument::load_instrument( pInstr->get_drumkit_path(), pInstr->get_name() );
673 auto pNewSample = Sample::load( pInstr->get_component( m_nSelectedComponent )->get_layer( selectedlayer )->get_sample()->get_filepath() );
674
675 if ( pNewSample != nullptr ){
676 int length = ( ( pNewSample->get_frames() / pNewSample->get_sample_rate() + 1) * 100 );
678 Hydrogen::get_instance()->getAudioEngine()->getSampler()->preview_sample( pNewSample, length );
679 m_nSlframes = pNewSample->get_frames();
680 }
681
682 m_pMainSampleWaveDisplay->paintLocatorEvent( StartFrameSpinBox->value() / m_divider + 24 , true);
684 m_pTimer->start(40); // update ruler at 25 fps
686 PlayOrigPushButton->setText( QString( "Stop") );
687}
688
690{
691 unsigned long realpos = Hydrogen::get_instance()->getAudioEngine()->getRealtimeFrame();
692 if ( realpos < m_nRealtimeFrameEnd ){
693 unsigned frame = m_nSlframes - ( m_nRealtimeFrameEnd - realpos );
694 if ( m_bPlayButton == true ){
697 }else{
700 }
701// ERRORLOG( QString("sampleval: %1").arg(frame) );
702 } else {
703 auto pCommonString = HydrogenApp::get_instance()->getCommonStrings();
705 m_pTimer->stop();
706 PlayPushButton->setText( pCommonString->getButtonPlay() );
707 PlayOrigPushButton->setText( pCommonString->getButtonPlayOriginalSample() );
708 m_bPlayButton = false;
709 }
710}
711
713{
714 unsigned long realpos = Hydrogen::get_instance()->getAudioEngine()->getRealtimeFrame();
715 unsigned targetSampleLength;
716 if ( __rubberband.use ){
717 targetSampleLength = m_nSlframes * m_fRatio + 0.1;
718 } else {
719 targetSampleLength = m_nSlframes;
720 }
721
722 if ( realpos < m_nRealtimeFrameEndForTarget ){
723 unsigned pos = targetSampleLength - ( m_nRealtimeFrameEndForTarget - realpos );
724 m_pTargetSampleView->paintLocatorEventTargetDisplay( (m_pTargetSampleView->width() * pos /targetSampleLength), true);
725// ERRORLOG( QString("sampleval: %1").arg(frame) );
726 } else {
727 auto pCommonString = HydrogenApp::get_instance()->getCommonStrings();
729 m_pTargetDisplayTimer->stop();
730 PlayPushButton->setText( pCommonString->getButtonPlay() );
731 PlayOrigPushButton->setText( pCommonString->getButtonPlayOriginalSample() );
732 m_bPlayButton = false;
733 }
734}
735
736
737
739{
741
742 unsigned oneSampleLength = __loops.end_frame - __loops.start_frame;
743 unsigned loopLength = __loops.end_frame - __loops.loop_frame;
744 unsigned repeatsLength = loopLength * __loops.count;
745 unsigned newLength = 0;
746 if (oneSampleLength == loopLength){
747 newLength = oneSampleLength + oneSampleLength * __loops.count ;
748 }else
749 {
750 newLength =oneSampleLength + repeatsLength;
751 }
752
753 unsigned normalLength = m_pSampleFromFile->get_frames();
754
755 unsigned * normalFrames = new unsigned[ normalLength ];
756 unsigned * tempFrames = new unsigned[ newLength ];
757 unsigned * loopFrames = new unsigned[ loopLength ];
758
759 for ( unsigned i = 0; i < normalLength; i++ ) {
760 normalFrames[i] = i;
761 }
762
764 long int z = __loops.loop_frame;
765 long int y = __loops.start_frame;
766
767 for ( unsigned i = 0; i < newLength; i++){ //first vector
768 tempFrames[i] = 0;
769 }
770
771 for ( unsigned i = 0; i < oneSampleLength; i++, y++){ //first vector
772
773 tempFrames[i] = normalFrames[y];
774 }
775
776 for ( unsigned i = 0; i < loopLength; i++, z++){ //loop vector
777
778 loopFrames[i] = normalFrames[z];
779 }
780
781 if ( loopmode == Sample::Loops::REVERSE ){
782 std::reverse(loopFrames, loopFrames + loopLength);
783 }
784
786 std::reverse( tempFrames, tempFrames + oneSampleLength );
787 }
788
790 std::reverse(loopFrames, loopFrames + loopLength);
791 }
792
793 for ( int i = 0; i< __loops.count ;i++){
794 unsigned tempdataend = oneSampleLength + ( loopLength * i );
796 std::copy( loopFrames, loopFrames+loopLength ,tempFrames+ tempdataend );
797 }
798 if ( loopmode == Sample::Loops::PINGPONG && __loops.count > 1){
799 std::reverse(loopFrames, loopFrames + loopLength);
800 }
802 std::copy( loopFrames, loopFrames+loopLength ,tempFrames+ tempdataend );
803 }
804 }
805
806
807 if ( __loops.count == 0 && loopmode == Sample::Loops::REVERSE ){
808 std::reverse( tempFrames + __loops.loop_frame, tempFrames + newLength);
809 }
810
812 {
813 delete[] m_pPositionsRulerPath;
814 }
815
816 m_pPositionsRulerPath = tempFrames;
817
818 delete[] loopFrames;
819 delete[] normalFrames;
820}
821
822
823
825{
827 unsigned oneSampleLength = __loops.end_frame - __loops.start_frame;
828 unsigned loopLength = __loops.end_frame - __loops.loop_frame ;
829 unsigned repeatsLength = loopLength * __loops.count;
830 unsigned newLength = 0;
831
832 if ( oneSampleLength == loopLength ){
833 newLength = oneSampleLength + oneSampleLength * __loops.count ;
834 } else {
835 newLength =oneSampleLength + repeatsLength;
836 }
837
838 m_nSlframes = newLength;
839 newlengthLabel->setText(QString( tr( "new sample length" ) )
840 .append( QString( ": %1 " ).arg(newLength) )
841 .append( tr( "frames" )));
843}
844
845
846
848{
849 testpTimer();
850 int count = LoopCountSpinBox->value();
851
852 if (count == __loops.count) {
854 return;
855 }
856
857 const auto pHydrogen = Hydrogen::get_instance();
858 const auto pAudioDriver = pHydrogen->getAudioOutput();
859 if ( pAudioDriver == nullptr ) {
860 ERRORLOG( "AudioDriver is not ready!" );
861 return;
862 }
863
864 if ( m_nSlframes > pAudioDriver->getSampleRate() * 60 ){
865 pHydrogen->getAudioEngine()->getSampler()->stopPlayingNotes();
867 m_pTimer->stop();
868 m_bPlayButton = false;
869 }
870 __loops.count = count;
871 setUnclean();
873 if ( m_nSlframes > pAudioDriver->getSampleRate() * 60 * 30){ // >30 min
874 LoopCountSpinBox->setMaximum(LoopCountSpinBox->value() -1);
875 }
876
877}
878
879
880
882{
883 int new_settings = rubberbandCsettingscomboBox->currentIndex();
884 if (new_settings == __rubberband.c_settings) {
886 return;
887 }
888 __rubberband.c_settings = new_settings;
889 setUnclean();
890}
891
892
893
895{
896 double new_value = pitchdoubleSpinBox->value();
897 if (std::abs(new_value - __rubberband.pitch) < 0.0001) {
899 return;
900 }
901 __rubberband.pitch = new_value;
902 setUnclean();
903}
904
905
907{
908
909 if( rubberComboBox->currentText() != "off" ){
910 __rubberband.use = true;
911 }else
912 {
913 __rubberband.use = false;
914 __rubberband.divider = 1.0;
915 }
916
917
918 switch ( rubberComboBox->currentIndex() ){
919 case 0 ://
920 __rubberband.divider = 4.0;
921 break;
922 case 1 ://
923 __rubberband.divider = 1.0/64.0;
924 break;
925 case 2 ://
926 __rubberband.divider = 1.0/32.0;
927 break;
928 case 3 ://
929 __rubberband.divider = 1.0/16.0;
930 break;
931 case 4 ://
932 __rubberband.divider = 1.0/8.0;
933 break;
934 case 5 ://
935 __rubberband.divider = 1.0/4.0;
936 break;
937 case 6 ://
938 __rubberband.divider = 1.0/2.0;
939 break;
940 case 7 ://
941 __rubberband.divider = 1.0;
942 break;
943 default:
944 __rubberband.divider = (float)rubberComboBox->currentIndex() - 6.0;
945 }
946// QMessageBox::information ( this, "Hydrogen", tr ( "divider %1" ).arg( __rubberband.divider ));
947// float __rubberband.divider;
949
950
951 setUnclean();
952}
953
955{
956 //calculate ratio
957 double durationtime = 60.0 / Hydrogen::get_instance()->getAudioEngine()->getTransportPosition()->getBpm()
959 double induration = (double) m_nSlframes / (double) m_nSamplerate;
960 if (induration != 0.0) m_fRatio = durationtime / induration;
961
962 //my personal ratio quality settings
963 //ratios < 0.1 || > 3.0 are bad (red) or experimental sounds
964 //ratios > 0.1 && < 0.5 || > 2.0 && < 3.0 are mediocre (yellow)
965 //ratios > 0.5 && < 2.0 are good (green)
966 //
967 // 0.1 0.5 2.0 3.0
968 //<---red---[--yellow--[------green------]----yellow----]---red--->
969
970 //green ratio
971 if( ( m_fRatio >= 0.5 ) && ( m_fRatio <= 2.0 ) ){
972 rubberComboBox->setStyleSheet("QComboBox { background-color: green; }");
973 }
974 //yellow ratio
975 else if( ( m_fRatio >= 0.1 ) && ( m_fRatio <= 3.0 ) ){
976 rubberComboBox->setStyleSheet("QComboBox { background-color: yellow; }");
977 }
978 //red ratio
979 else{
980 rubberComboBox->setStyleSheet("QComboBox { background-color: red; }");
981 }
982 QString text = QString( tr(" RB-Ratio" ) )
983 .append( QString( " %1" ).arg( m_fRatio ) );
984 ratiolabel->setText( text );
985
986 //no rubberband = default
987 if( !__rubberband.use ){
988 rubberComboBox->setStyleSheet("QComboBox { background-color: 58, 62, 72; }");
989 ratiolabel->setText( "" );
990 }
991}
992
993
995{
996 switch ( ProcessingTypeComboBox->currentIndex() ){
997 case 0 ://
999 break;
1000 case 1 ://
1002 break;
1003 case 2 ://
1005 break;
1006 default:
1008 }
1009 setUnclean();
1010}
1011
1012
1013
1019
1020
1021
1035
1036
1037
1039{
1040 if ( m_pTimer->isActive() || m_pTargetDisplayTimer->isActive() ){
1041 auto pCommonString = HydrogenApp::get_instance()->getCommonStrings();
1043 m_pTimer->stop();
1044 m_pTargetDisplayTimer->stop();
1045 PlayPushButton->setText( pCommonString->getButtonPlay() );
1046 PlayOrigPushButton->setText( pCommonString->getButtonPlayOriginalSample() );
1048 m_bPlayButton = false;
1049 }
1050}
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
Definition AudioEngine.h:59
#define INFOLOG(x)
Definition Object.h:237
#define ERRORLOG(x)
Definition Object.h:239
#define DEBUGLOG(x)
Definition Object.h:236
void setDetailSamplePosition(unsigned posi, float zoomfactor, QString type)
void updateDisplay(QString filename)
Sampler * getSampler() const
const std::shared_ptr< TransportPosition > getTransportPosition() const
long long getRealtimeFrame() const
A container for a sample, being able to apply modifications on it.
Definition Sample.h:43
static bool file_executable(const QString &path, bool silent=false)
returns true if the given path is an existing executable regular file
Hydrogen Audio Engine.
Definition Hydrogen.h:54
std::shared_ptr< Song > getSong() const
Get the current song.
Definition Hydrogen.h:122
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:83
AudioEngine * getAudioEngine() const
Definition Hydrogen.h:649
std::shared_ptr< Instrument > getSelectedInstrument() const
void setIsModified(bool bIsModified)
Wrapper around Song::setIsModified() that checks whether a song is set.
static std::shared_ptr< Instrument > load_instrument(const QString &drumkit_path, const QString &instrument_name)
creates a new Instrument, loads samples from a given instrument within a given drumkit
A note plays an associated instrument with a velocity left and right pan.
Definition Note.h:102
void set_specific_compo_id(int value)
__specific_compo_id setter
Definition Note.h:520
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
LoopMode
possible sample editing loop mode
Definition Sample.h:81
int end_frame
the frame index where to end the new sample to
Definition Sample.h:88
int start_frame
the frame index where to start the new sample from
Definition Sample.h:86
LoopMode mode
one of the possible loop modes
Definition Sample.h:90
int count
the counts of loops to apply
Definition Sample.h:89
int loop_frame
the frame index where to start the loop from
Definition Sample.h:87
float pitch
desired pitch
Definition Sample.h:114
int c_settings
TODO should be crispness, see rubberband -h.
Definition Sample.h:115
float divider
TODO should be ratio : desired time ratio.
Definition Sample.h:113
bool use
is rubberband enabled
Definition Sample.h:112
int get_frames() const
Definition Sample.h:377
static std::shared_ptr< Sample > load(const QString &filepath, const License &license=License())
Definition Sample.cpp:136
void preview_instrument(std::shared_ptr< Instrument > pInstr)
Definition Sampler.cpp:1398
void noteOn(Note *pNote)
Start playing a note.
Definition Sampler.cpp:190
void stopPlayingNotes(std::shared_ptr< Instrument > pInstr=nullptr)
Definition Sampler.cpp:1341
void preview_sample(std::shared_ptr< Sample > pSample, int length)
Preview, uses only the first layer.
Definition Sampler.cpp:1368
static HydrogenApp * get_instance()
Returns the instance of HydrogenApp class.
std::shared_ptr< CommonStrings > getCommonStrings()
static InstrumentEditorPanel * get_instance()
void updateDisplay(const QString &filename)
void paintLocatorEvent(int pos, bool last_event)
void updateTargetsamplePositionRuler()
void updateMainsamplePositionRuler()
MainSampleWaveDisplay * m_pMainSampleWaveDisplay
bool returnAllMainWaveDisplayValues()
float m_fZoomfactor
unsigned * m_pPositionsRulerPath
std::shared_ptr< H2Core::Sample > m_pSampleFromFile
void valueChangedLoopFrameSpinBox(int)
QString m_sLineColor
void getAllLocalFrameInfos()
std::shared_ptr< H2Core::Sample > retrieveSample() const
void returnAllTargetDisplayValues()
void createPositionsRulerPath()
H2Core::Sample::Loops __loops
unsigned long m_nRealtimeFrameEndForTarget
void valueChangedProcessingTypeComboBox(const QString)
QTimer * m_pTargetDisplayTimer
QTimer * m_pTimer
bool getCloseQuestion()
void getAllFrameInfos()
bool m_bSampleEditorClean
void createNewLayer()
void setSamplelengthFrames()
bool m_bSampleIsModified
true if sample is modified
unsigned m_nSlframes
QString m_sSampleName
int m_nSelectedComponent
void valueChangedrubberComboBox(const QString)
virtual void closeEvent(QCloseEvent *event) override
void on_PrevChangesPushButton_clicked()
void on_PlayPushButton_clicked()
H2Core::Sample::Rubberband __rubberband
void valueChangedrubberbandCsettingscomboBox(const QString)
virtual void mouseReleaseEvent(QMouseEvent *ev) override
TargetWaveDisplay * m_pTargetSampleView
unsigned m_pDetailFrame
void checkRatioSettings()
SampleEditor(QWidget *pParent, int nSelectedComponent, int nSelectedLayer, QString nSampleFilename)
void valueChangedEndFrameSpinBox(int)
unsigned m_nSamplerate
void testPositionsSpinBoxes()
void on_verticalzoomSlider_valueChanged(int value)
void valueChangedStartFrameSpinBox(int)
void on_ClosePushButton_clicked()
void valueChangedpitchdoubleSpinBox(double)
void on_PlayOrigPushButton_clicked()
void valueChangedLoopCountSpinBox(int)
DetailWaveDisplay * m_pSampleAdjustView
unsigned long m_nRealtimeFrameEnd
H2Core::Sample::PanEnvelope * get_pan()
void updateDisplay(std::shared_ptr< H2Core::InstrumentLayer > pLayer)
void paintLocatorEventTargetDisplay(int pos, bool last_event)
H2Core::Sample::VelocityEnvelope * get_velocity()