1 /*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 *
5 * http://www.hydrogen-music.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY, without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23 #include "SampleEditor.h"
24 #include "../HydrogenApp.h"
25 #include "../InstrumentEditor/InstrumentEditor.h"
26 #include "../InstrumentEditor/InstrumentEditorPanel.h"
27 #include "../Widgets/Button.h"
28
29 #include "MainSampleWaveDisplay.h"
30 #include "DetailWaveDisplay.h"
31 #include "TargetWaveDisplay.h"
32
33 #include <hydrogen/h2_exception.h>
34 #include <hydrogen/Preferences.h>
35 #include <hydrogen/basics/sample.h>
36 #include <hydrogen/basics/instrument_component.h>
37 #include <hydrogen/basics/instrument_list.h>
38 #include <hydrogen/basics/instrument_layer.h>
39 #include <hydrogen/audio_engine.h>
40 #include <hydrogen/hydrogen.h>
41
42 #include <QModelIndex>
43 #include <QTreeWidget>
44 #include <QMessageBox>
45 #include <algorithm>
46 #include <memory>
47
48 using namespace H2Core;
49
50 const char* SampleEditor::__class_name = "SampleEditor";
51
SampleEditor(QWidget * pParent,int nSelectedComponent,int nSelectedLayer,QString mSamplefilename)52 SampleEditor::SampleEditor ( QWidget* pParent, int nSelectedComponent, int nSelectedLayer, QString mSamplefilename )
53 : QDialog ( pParent )
54 , Object ( __class_name )
55 {
56 setupUi ( this );
57 INFOLOG ( "INIT" );
58
59 m_pTimer = new QTimer(this);
60 connect(m_pTimer, SIGNAL(timeout()), this, SLOT(updateMainsamplePositionRuler()));
61 m_pTargetDisplayTimer = new QTimer(this);
62 connect(m_pTargetDisplayTimer, SIGNAL(timeout()), this, SLOT(updateTargetsamplePositionRuler()));
63
64 m_pSampleEditorStatus = true;
65 m_pSampleFromFile = nullptr;
66 m_pSelectedLayer = nSelectedLayer;
67 m_pSelectedComponent = nSelectedComponent;
68 m_samplename = mSamplefilename;
69 m_pZoomfactor = 1;
70 m_pDetailFrame = 0;
71 m_pLineColor = "default";
72 m_pOnewayStart = false;
73 m_pOnewayLoop = false;
74 m_pOnewayEnd = false;
75 m_pslframes = 0;
76 m_pPositionsRulerPath = nullptr;
77 m_pPlayButton = false;
78 m_pRatio = 1.0f;
79 __rubberband.c_settings = 4;
80
81 QString newfilename = mSamplefilename.section( '/', -1 );
82
83 //init Displays
84 m_pMainSampleWaveDisplay = new MainSampleWaveDisplay( mainSampleview );
85 m_pSampleAdjustView = new DetailWaveDisplay( mainSampleAdjustView );
86 m_pTargetSampleView = new TargetWaveDisplay( targetSampleView );
87
88 setWindowTitle ( QString( "SampleEditor " + newfilename) );
89 setFixedSize ( width(), height() );
90 setModal ( true );
91
92 //this new sample give us the not changed real samplelength
93 m_pSampleFromFile = Sample::load( mSamplefilename );
94 if (!m_pSampleFromFile) reject();
95
96 unsigned slframes = m_pSampleFromFile->get_frames();
97
98 LoopCountSpinBox->setRange(0, 20000 );
99 StartFrameSpinBox->setRange(0, slframes );
100 LoopFrameSpinBox->setRange(0, slframes );
101 EndFrameSpinBox->setRange(0, slframes );
102 EndFrameSpinBox->setValue( slframes );
103 rubberbandCsettingscomboBox->setCurrentIndex( 4 );
104 rubberComboBox->setCurrentIndex( 0 );
105
106 __rubberband.use = false;
107 __rubberband.divider = 1.0;
108 openDisplays();
109 getAllFrameInfos();
110
111 #ifndef H2CORE_HAVE_RUBBERBAND
112 if ( QFile( Preferences::get_instance()->m_rubberBandCLIexecutable ).exists() == false ){
113 RubberbandCframe->setDisabled ( true );
114 __rubberband.use = false;
115 m_pSampleEditorStatus = true;
116 }
117 #else
118 RubberbandCframe->setDisabled ( false );
119 m_pSampleEditorStatus = true;
120 #endif
121
122 __rubberband.pitch = 0.0;
123
124 }
125
126
127
~SampleEditor()128 SampleEditor::~SampleEditor()
129 {
130 m_pMainSampleWaveDisplay->close();
131 delete m_pMainSampleWaveDisplay;
132 m_pMainSampleWaveDisplay = nullptr;
133
134 m_pSampleAdjustView->close();
135 delete m_pSampleAdjustView;
136 m_pSampleAdjustView = nullptr;
137
138 m_pTargetSampleView->close();
139 delete m_pTargetSampleView;
140 m_pTargetSampleView = nullptr;
141
142 delete m_pSampleFromFile;
143 m_pSampleFromFile = nullptr;
144
145 INFOLOG ( "DESTROY" );
146 }
147
148
closeEvent(QCloseEvent * event)149 void SampleEditor::closeEvent(QCloseEvent *event)
150 {
151 if ( !m_pSampleEditorStatus ) {
152 int err = QMessageBox::information( this, "Hydrogen", tr( "Unsaved changes left. These changes will be lost. \nAre you sure?"), tr("&Ok"), tr("&Cancel"), nullptr, 1 );
153 if ( err == 0 ) {
154 m_pSampleEditorStatus = true;
155 accept();
156 } else {
157 event->ignore();
158 return;
159 }
160 } else {
161 accept();
162 }
163 }
164
165
getAllFrameInfos()166 void SampleEditor::getAllFrameInfos()
167 {
168 H2Core::Instrument *pInstrument = nullptr;
169 Sample* pSample = nullptr;
170 Song *pSong = Hydrogen::get_instance()->getSong();
171
172 if (pSong != nullptr) {
173 InstrumentList *pInstrList = pSong->get_instrument_list();
174 int nInstr = Hydrogen::get_instance()->getSelectedInstrumentNumber();
175 if ( nInstr >= static_cast<int>(pInstrList->size()) ) {
176 nInstr = -1;
177 }
178
179 if (nInstr == -1) {
180 pInstrument = nullptr;
181 }
182 else {
183 pInstrument = pInstrList->get( nInstr );
184 //INFOLOG( "new instr: " + pInstrument->m_sName );
185 }
186 }
187
188 assert( pInstrument );
189
190 H2Core::InstrumentLayer *pLayer = pInstrument->get_component(0)->get_layer( m_pSelectedLayer );
191 if ( pLayer ) {
192 pSample = pLayer->get_sample();
193 }
194
195 assert( pSample );
196
197 //this values are needed if we restore a sample from disk if a new song with sample changes will load
198 m_sample_is_modified = pSample->get_is_modified();
199 m_pSamplerate = pSample->get_sample_rate();
200 __loops = pSample->get_loops();
201 __rubberband = pSample->get_rubberband();
202
203 if ( pSample->get_velocity_envelope()->size()==0 ) {
204 m_pTargetSampleView->get_velocity()->clear();
205 m_pTargetSampleView->get_velocity()->push_back( std::make_unique<EnvelopePoint>( 0, 0 ) );
206 m_pTargetSampleView->get_velocity()->push_back( std::make_unique<EnvelopePoint>( m_pTargetSampleView->width(), 0 ) );
207 } else {
208 m_pTargetSampleView->get_velocity()->clear();
209
210 for(auto& pEnvPtr : *pSample->get_velocity_envelope() ){
211 m_pTargetSampleView->get_velocity()->emplace_back( std::make_unique<EnvelopePoint>( pEnvPtr->value, pEnvPtr->frame ) );
212 }
213 }
214
215 if ( pSample->get_pan_envelope()->size()==0 ) {
216 m_pTargetSampleView->get_pan()->clear();
217 m_pTargetSampleView->get_pan()->push_back( std::make_unique<EnvelopePoint>( 0, m_pTargetSampleView->height()/2 ) );
218 m_pTargetSampleView->get_pan()->push_back( std::make_unique<EnvelopePoint>( m_pTargetSampleView->width(), m_pTargetSampleView->height()/2 ) );
219 } else {
220 for(auto& pEnvPtr : *pSample->get_pan_envelope() ){
221 m_pTargetSampleView->get_pan()->emplace_back( std::make_unique<EnvelopePoint>( pEnvPtr.get() ) );
222 }
223 }
224
225 if (m_sample_is_modified) {
226 __loops.end_frame = pSample->get_loops().end_frame;
227 if ( __loops.mode == Sample::Loops::FORWARD ) {
228 ProcessingTypeComboBox->setCurrentIndex ( 0 );
229 }
230 if ( __loops.mode == Sample::Loops::REVERSE ) {
231 ProcessingTypeComboBox->setCurrentIndex ( 1 );
232 }
233 if ( __loops.mode == Sample::Loops::PINGPONG ) {
234 ProcessingTypeComboBox->setCurrentIndex ( 2 );
235 }
236
237 StartFrameSpinBox->setValue( __loops.start_frame );
238 LoopFrameSpinBox->setValue( __loops.loop_frame );
239 EndFrameSpinBox->setValue( __loops.end_frame );
240 LoopCountSpinBox->setValue( __loops.count );
241
242 m_pMainSampleWaveDisplay->m_pStartFramePosition = __loops.start_frame / m_divider + 25 ;
243 m_pMainSampleWaveDisplay->updateDisplayPointer();
244 m_pMainSampleWaveDisplay->m_pLoopFramePosition = __loops.loop_frame / m_divider + 25 ;
245 m_pMainSampleWaveDisplay->updateDisplayPointer();
246 m_pMainSampleWaveDisplay->m_pEndFramePosition = __loops.end_frame / m_divider + 25 ;
247 m_pMainSampleWaveDisplay->updateDisplayPointer();
248
249 if( !__rubberband.use ) {
250 rubberComboBox->setCurrentIndex( 0 );
251 }
252
253 rubberbandCsettingscomboBox->setCurrentIndex( __rubberband.c_settings );
254 if( !__rubberband.use ) {
255 rubberbandCsettingscomboBox->setCurrentIndex( 4 );
256 }
257
258 pitchdoubleSpinBox->setValue( __rubberband.pitch );
259 if( !__rubberband.use ) {
260 pitchdoubleSpinBox->setValue( 0.0 );
261 }
262
263 if( __rubberband.divider == 1.0/64.0) {
264 rubberComboBox->setCurrentIndex( 1 );
265 }
266 else if( __rubberband.divider == 1.0/32.0) {
267 rubberComboBox->setCurrentIndex( 2 );
268 } else if( __rubberband.divider == 1.0/16.0) {
269 rubberComboBox->setCurrentIndex( 3 );
270 } else if( __rubberband.divider == 1.0/8.0) {
271 rubberComboBox->setCurrentIndex( 4 );
272 } else if( __rubberband.divider == 1.0/4.0) {
273 rubberComboBox->setCurrentIndex( 5 );
274 } else if( __rubberband.divider == 1.0/2.0) {
275 rubberComboBox->setCurrentIndex( 6 );
276 } else if( __rubberband.use && ( __rubberband.divider >= 1.0 ) ) {
277 rubberComboBox->setCurrentIndex( (int)(__rubberband.divider + 6) );
278 }
279
280 setSamplelengthFrames();
281 checkRatioSettings();
282
283 }
284 m_pTargetSampleView->updateDisplay( pLayer );
285
286 connect( StartFrameSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( valueChangedStartFrameSpinBox(int) ) );
287 connect( LoopFrameSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( valueChangedLoopFrameSpinBox(int) ) );
288 connect( EndFrameSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( valueChangedEndFrameSpinBox(int) ) );
289 connect( LoopCountSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( valueChangedLoopCountSpinBox( int ) ) );
290 connect( ProcessingTypeComboBox, SIGNAL( currentIndexChanged ( const QString ) ), this, SLOT( valueChangedProcessingTypeComboBox( const QString ) ) );
291 connect( rubberComboBox, SIGNAL( currentIndexChanged ( const QString ) ), this, SLOT( valueChangedrubberComboBox( const QString ) ) );
292 connect( rubberbandCsettingscomboBox, SIGNAL( currentIndexChanged ( const QString ) ), this, SLOT( valueChangedrubberbandCsettingscomboBox( const QString ) ) );
293 connect( pitchdoubleSpinBox, SIGNAL ( valueChanged( double ) ), this, SLOT( valueChangedpitchdoubleSpinBox( double ) ) );
294 }
295
getAllLocalFrameInfos()296 void SampleEditor::getAllLocalFrameInfos()
297 {
298 __loops.start_frame = StartFrameSpinBox->value();
299 __loops.loop_frame = LoopFrameSpinBox->value();
300 __loops.count = LoopCountSpinBox->value();
301 __loops.end_frame = EndFrameSpinBox->value();
302 }
303
304
305
openDisplays()306 void SampleEditor::openDisplays()
307 {
308 H2Core::Instrument *pInstrument = nullptr;
309 Song *pSong = Hydrogen::get_instance()->getSong();
310 if (pSong != nullptr) {
311 InstrumentList *pInstrList = pSong->get_instrument_list();
312 int nInstr = Hydrogen::get_instance()->getSelectedInstrumentNumber();
313 if ( nInstr >= static_cast<int>(pInstrList->size()) ) {
314 nInstr = -1;
315 }
316
317 if (nInstr == -1) {
318 pInstrument = nullptr;
319 }
320 else {
321 pInstrument = pInstrList->get( nInstr );
322 //INFOLOG( "new instr: " + pInstrument->m_sName );
323 }
324 }
325
326
327 // wavedisplays
328 m_divider = m_pSampleFromFile->get_frames() / 574.0F;
329 m_pMainSampleWaveDisplay->updateDisplay( m_samplename );
330 m_pMainSampleWaveDisplay->move( 1, 1 );
331
332 m_pSampleAdjustView->updateDisplay( m_samplename );
333 m_pSampleAdjustView->move( 1, 1 );
334
335 m_pTargetSampleView->move( 1, 1 );
336 }
337
338
339
on_ClosePushButton_clicked()340 void SampleEditor::on_ClosePushButton_clicked()
341 {
342 if ( !m_pSampleEditorStatus ){
343 int err = QMessageBox::information( this, "Hydrogen", tr( "Unsaved changes left. These changes will be lost. \nAre you sure?"), tr("&Ok"), tr("&Cancel"), nullptr, 1 );
344 if ( err == 0 ){
345 m_pSampleEditorStatus = true;
346 accept();
347 }else
348 {
349 return;
350 }
351 }else
352 {
353 accept();
354 }
355 }
356
357
358
on_PrevChangesPushButton_clicked()359 void SampleEditor::on_PrevChangesPushButton_clicked()
360 {
361 QApplication::setOverrideCursor(Qt::WaitCursor);
362 getAllLocalFrameInfos();
363 createNewLayer();
364 m_pSampleEditorStatus = true;
365 QApplication::restoreOverrideCursor();
366 }
367
368
369
getCloseQuestion()370 bool SampleEditor::getCloseQuestion()
371 {
372 bool close = false;
373 int err = QMessageBox::information( this, "Hydrogen", tr( "Close dialog! maybe there is some unsaved work on sample.\nAre you sure?"), tr("&Ok"), tr("&Cancel"), nullptr, 1 );
374 if ( err == 0 ) close = true;
375
376 return close;
377 }
378
379
380
createNewLayer()381 void SampleEditor::createNewLayer()
382 {
383 if ( !m_pSampleEditorStatus ){
384
385 Sample *pEditSample = Sample::load( m_samplename, __loops, __rubberband, *m_pTargetSampleView->get_velocity(), *m_pTargetSampleView->get_pan() );
386
387 if( pEditSample == nullptr ){
388 return;
389 }
390
391 AudioEngine::get_instance()->lock( RIGHT_HERE );
392
393 H2Core::Instrument *pInstrument = nullptr;
394 Song *pSong = Hydrogen::get_instance()->getSong();
395 if (pSong != nullptr) {
396 InstrumentList *pInstrList = pSong->get_instrument_list();
397 int nInstr = Hydrogen::get_instance()->getSelectedInstrumentNumber();
398 if ( nInstr >= static_cast<int>(pInstrList->size()) ) {
399 nInstr = -1;
400 }
401
402 if (nInstr == -1) {
403 pInstrument = nullptr;
404 }
405 else {
406 pInstrument = pInstrList->get( nInstr );
407 }
408 }
409
410 H2Core::InstrumentLayer *pLayer = pInstrument->get_component(0)->get_layer( m_pSelectedLayer );
411
412 // insert new sample from newInstrument
413 pLayer->set_sample( pEditSample );
414
415 AudioEngine::get_instance()->unlock();
416 m_pTargetSampleView->updateDisplay( pLayer );
417 }
418 }
419
420
421
mouseReleaseEvent(QMouseEvent * ev)422 void SampleEditor::mouseReleaseEvent(QMouseEvent *ev)
423 {
424
425 }
426
427
428
returnAllMainWaveDisplayValues()429 bool SampleEditor::returnAllMainWaveDisplayValues()
430 {
431 testpTimer();
432 // QMessageBox::information ( this, "Hydrogen", tr ( "jep %1" ).arg(m_pSample->get_frames()));
433 m_sample_is_modified = true;
434 if( m_pMainSampleWaveDisplay->__startsliderismoved ) __loops.start_frame = m_pMainSampleWaveDisplay->m_pStartFramePosition * m_divider - 25 * m_divider;
435 if( m_pMainSampleWaveDisplay->__loopsliderismoved ) __loops.loop_frame = m_pMainSampleWaveDisplay->m_pLoopFramePosition * m_divider - 25 * m_divider;
436 if( m_pMainSampleWaveDisplay->__endsliderismoved ) __loops.end_frame = m_pMainSampleWaveDisplay->m_pEndFramePosition * m_divider - 25 * m_divider ;
437 StartFrameSpinBox->setValue( __loops.start_frame );
438 LoopFrameSpinBox->setValue( __loops.loop_frame );
439 EndFrameSpinBox->setValue( __loops.end_frame );
440 m_pOnewayStart = true;
441 m_pOnewayLoop = true;
442 m_pOnewayEnd = true;
443 setSamplelengthFrames();
444
445 return true;
446 }
447
448
returnAllTargetDisplayValues()449 void SampleEditor::returnAllTargetDisplayValues()
450 {
451 setSamplelengthFrames();
452 m_sample_is_modified = true;
453
454 }
455
456
457
setTrue()458 void SampleEditor::setTrue()
459 {
460 m_pSampleEditorStatus = false;
461 }
462
463
464
valueChangedStartFrameSpinBox(int)465 void SampleEditor::valueChangedStartFrameSpinBox( int )
466 {
467 testpTimer();
468 m_pDetailFrame = StartFrameSpinBox->value();
469 m_pLineColor = "Start";
470 if ( !m_pOnewayStart ){
471 m_pMainSampleWaveDisplay->m_pStartFramePosition = StartFrameSpinBox->value() / m_divider + 25 ;
472 m_pMainSampleWaveDisplay->updateDisplayPointer();
473 m_pSampleAdjustView->setDetailSamplePosition( m_pDetailFrame, m_pZoomfactor , m_pLineColor);
474 __loops.start_frame = StartFrameSpinBox->value();
475
476 }else
477 {
478 m_pSampleAdjustView->setDetailSamplePosition( m_pDetailFrame, m_pZoomfactor , m_pLineColor);
479 m_pOnewayStart = false;
480 }
481 testPositionsSpinBoxes();
482 m_pSampleEditorStatus = false;
483 setSamplelengthFrames();
484 }
485
486
487
valueChangedLoopFrameSpinBox(int)488 void SampleEditor::valueChangedLoopFrameSpinBox( int )
489 {
490 testpTimer();
491 m_pDetailFrame = LoopFrameSpinBox->value();
492 m_pLineColor = "Loop";
493 if ( !m_pOnewayLoop ){
494 m_pMainSampleWaveDisplay->m_pLoopFramePosition = LoopFrameSpinBox->value() / m_divider + 25 ;
495 m_pMainSampleWaveDisplay->updateDisplayPointer();
496 m_pSampleAdjustView->setDetailSamplePosition( m_pDetailFrame, m_pZoomfactor , m_pLineColor);
497 __loops.loop_frame = LoopFrameSpinBox->value();
498 }else
499 {
500 m_pSampleAdjustView->setDetailSamplePosition( m_pDetailFrame, m_pZoomfactor , m_pLineColor);
501 m_pOnewayLoop = false;
502 }
503 testPositionsSpinBoxes();
504 m_pSampleEditorStatus = false;
505 setSamplelengthFrames();
506 }
507
508
509
valueChangedEndFrameSpinBox(int)510 void SampleEditor::valueChangedEndFrameSpinBox( int )
511 {
512 testpTimer();
513 m_pDetailFrame = EndFrameSpinBox->value();
514 m_pLineColor = "End";
515 if ( !m_pOnewayEnd ){
516 m_pMainSampleWaveDisplay->m_pEndFramePosition = EndFrameSpinBox->value() / m_divider + 25 ;
517 m_pMainSampleWaveDisplay->updateDisplayPointer();
518 m_pSampleAdjustView->setDetailSamplePosition( m_pDetailFrame, m_pZoomfactor , m_pLineColor);
519 __loops.end_frame = EndFrameSpinBox->value();
520 }else
521 {
522 m_pOnewayEnd = false;
523 m_pSampleAdjustView->setDetailSamplePosition( m_pDetailFrame, m_pZoomfactor , m_pLineColor);
524 }
525 testPositionsSpinBoxes();
526 m_pSampleEditorStatus = false;
527 setSamplelengthFrames();
528 }
529
530
531
on_PlayPushButton_clicked()532 void SampleEditor::on_PlayPushButton_clicked()
533 {
534 if (PlayPushButton->text() == "Stop" ){
535 testpTimer();
536 return;
537 }
538
539 const float pan_L = 0.5f;
540 const float pan_R = 0.5f;
541 const int nLength = -1;
542 const float fPitch = 0.0f;
543 const int selectedLayer = InstrumentEditorPanel::get_instance()->getSelectedLayer();
544
545 Song *pSong = Hydrogen::get_instance()->getSong();
546 Instrument *pInstr = pSong->get_instrument_list()->get( Hydrogen::get_instance()->getSelectedInstrumentNumber() );
547
548 Note *pNote = new Note( pInstr, 0, pInstr->get_component( m_pSelectedComponent )->get_layer( selectedLayer )->get_end_velocity() - 0.01, pan_L, pan_R, nLength, fPitch);
549 pNote->set_specific_compo_id( m_pSelectedComponent );
550 AudioEngine::get_instance()->get_sampler()->note_on(pNote);
551
552 setSamplelengthFrames();
553 createPositionsRulerPath();
554 m_pPlayButton = true;
555 m_pMainSampleWaveDisplay->paintLocatorEvent( StartFrameSpinBox->value() / m_divider + 24 , true);
556 m_pSampleAdjustView->setDetailSamplePosition( __loops.start_frame, m_pZoomfactor , nullptr);
557
558 if( __rubberband.use == false ){
559 m_pTimer->start(40); // update ruler at 25 fps
560 }
561
562
563 m_pRealtimeFrameEnd = Hydrogen::get_instance()->getRealtimeFrames() + m_pslframes;
564
565 //calculate the new rubberband sample length
566 if( __rubberband.use ){
567 m_prealtimeframeendfortarget = Hydrogen::get_instance()->getRealtimeFrames() + (m_pslframes * m_pRatio + 0.1);
568 }else
569 {
570 m_prealtimeframeendfortarget = m_pRealtimeFrameEnd;
571 }
572 m_pTargetDisplayTimer->start(40); // update ruler at 25 fps
573 PlayPushButton->setText( QString( "Stop") );
574
575 }
576
577
578
on_PlayOrigPushButton_clicked()579 void SampleEditor::on_PlayOrigPushButton_clicked()
580 {
581 if (PlayOrigPushButton->text() == "Stop" ){
582 testpTimer();
583 return;
584 }
585
586 const int selectedlayer = InstrumentEditorPanel::get_instance()->getSelectedLayer();
587 Song *pSong = Hydrogen::get_instance()->getSong();
588 Instrument *pInstr = pSong->get_instrument_list()->get( Hydrogen::get_instance()->getSelectedInstrumentNumber() );
589
590 /*
591 *preview_instrument deletes the last used preview instrument, therefore we have to construct a temporary
592 *instrument. Otherwise pInstr would be deleted if consumed by preview_instrument.
593 */
594 Instrument *tmpInstrument = Instrument::load_instrument( pInstr->get_drumkit_name(), pInstr->get_name() );
595 Sample *pNewSample = Sample::load( pInstr->get_component(0)->get_layer( selectedlayer )->get_sample()->get_filepath() );
596
597 if ( pNewSample ){
598 int length = ( ( pNewSample->get_frames() / pNewSample->get_sample_rate() + 1) * 100 );
599 AudioEngine::get_instance()->get_sampler()->preview_instrument( tmpInstrument );
600 AudioEngine::get_instance()->get_sampler()->preview_sample( pNewSample, length );
601 m_pslframes = pNewSample->get_frames();
602 }
603
604 m_pMainSampleWaveDisplay->paintLocatorEvent( StartFrameSpinBox->value() / m_divider + 24 , true);
605 m_pSampleAdjustView->setDetailSamplePosition( __loops.start_frame, m_pZoomfactor , nullptr);
606 m_pTimer->start(40); // update ruler at 25 fps
607 m_pRealtimeFrameEnd = Hydrogen::get_instance()->getRealtimeFrames() + m_pslframes;
608 PlayOrigPushButton->setText( QString( "Stop") );
609 }
610
611
612
updateMainsamplePositionRuler()613 void SampleEditor::updateMainsamplePositionRuler()
614 {
615 unsigned long realpos = Hydrogen::get_instance()->getRealtimeFrames();
616 if ( realpos < m_pRealtimeFrameEnd ){
617 unsigned frame = m_pslframes - ( m_pRealtimeFrameEnd - realpos );
618 if ( m_pPlayButton == true ){
619 m_pMainSampleWaveDisplay->paintLocatorEvent( m_pPositionsRulerPath[frame] / m_divider + 25 , true);
620 m_pSampleAdjustView->setDetailSamplePosition( m_pPositionsRulerPath[frame], m_pZoomfactor , nullptr);
621 }else{
622 m_pMainSampleWaveDisplay->paintLocatorEvent( frame / m_divider + 25 , true);
623 m_pSampleAdjustView->setDetailSamplePosition( frame, m_pZoomfactor , nullptr);
624 }
625 // ERRORLOG( QString("sampleval: %1").arg(frame) );
626 }else
627 {
628 m_pMainSampleWaveDisplay->paintLocatorEvent( -1 , false);
629 m_pTimer->stop();
630 PlayPushButton->setText( QString("&Play") );
631 PlayOrigPushButton->setText( QString( "P&lay original sample") );
632 m_pPlayButton = false;
633 }
634 }
635
636
updateTargetsamplePositionRuler()637 void SampleEditor::updateTargetsamplePositionRuler()
638 {
639 unsigned long realpos = Hydrogen::get_instance()->getRealtimeFrames();
640 unsigned targetSampleLength;
641 if( __rubberband.use ){
642 targetSampleLength = m_pslframes * m_pRatio + 0.1;
643 }else
644 {
645 targetSampleLength = m_pslframes;
646 }
647 if ( realpos < m_prealtimeframeendfortarget ){
648 unsigned pos = targetSampleLength - ( m_prealtimeframeendfortarget - realpos );
649 m_pTargetSampleView->paintLocatorEventTargetDisplay( (m_pTargetSampleView->width() * pos /targetSampleLength), true);
650 // ERRORLOG( QString("sampleval: %1").arg(frame) );
651 }else
652 {
653 m_pTargetSampleView->paintLocatorEventTargetDisplay( -1 , false);
654 m_pTargetDisplayTimer->stop();
655 PlayPushButton->setText(QString( "&Play") );
656 PlayOrigPushButton->setText( QString( "P&lay original sample") );
657 m_pPlayButton = false;
658 }
659 }
660
661
662
createPositionsRulerPath()663 void SampleEditor::createPositionsRulerPath()
664 {
665 setSamplelengthFrames();
666
667 unsigned oneSampleLength = __loops.end_frame - __loops.start_frame;
668 unsigned loopLength = __loops.end_frame - __loops.loop_frame;
669 unsigned repeatsLength = loopLength * __loops.count;
670 unsigned newLength = 0;
671 if (oneSampleLength == loopLength){
672 newLength = oneSampleLength + oneSampleLength * __loops.count ;
673 }else
674 {
675 newLength =oneSampleLength + repeatsLength;
676 }
677
678 unsigned normalLength = m_pSampleFromFile->get_frames();
679
680 unsigned * normalFrames = new unsigned[ normalLength ];
681 unsigned * tempFrames = new unsigned[ newLength ];
682 unsigned * loopFrames = new unsigned[ loopLength ];
683
684 for ( unsigned i = 0; i < normalLength; i++ ) {
685 normalFrames[i] = i;
686 }
687
688 Sample::Loops::LoopMode loopmode = __loops.mode;
689 long int z = __loops.loop_frame;
690 long int y = __loops.start_frame;
691
692 for ( unsigned i = 0; i < newLength; i++){ //first vector
693 tempFrames[i] = 0;
694 }
695
696 for ( unsigned i = 0; i < oneSampleLength; i++, y++){ //first vector
697
698 tempFrames[i] = normalFrames[y];
699 }
700
701 for ( unsigned i = 0; i < loopLength; i++, z++){ //loop vector
702
703 loopFrames[i] = normalFrames[z];
704 }
705
706 if ( loopmode == Sample::Loops::REVERSE ){
707 reverse(loopFrames, loopFrames + loopLength);
708 }
709
710 if ( loopmode == Sample::Loops::REVERSE && __loops.count > 0 && __loops.start_frame == __loops.loop_frame ){
711 reverse( tempFrames, tempFrames + oneSampleLength );
712 }
713
714 if ( loopmode == Sample::Loops::PINGPONG && __loops.start_frame == __loops.loop_frame){
715 reverse(loopFrames, loopFrames + loopLength);
716 }
717
718 for ( int i = 0; i< __loops.count ;i++){
719 unsigned tempdataend = oneSampleLength + ( loopLength * i );
720 if ( __loops.start_frame == __loops.loop_frame ){
721 copy( loopFrames, loopFrames+loopLength ,tempFrames+ tempdataend );
722 }
723 if ( loopmode == Sample::Loops::PINGPONG && __loops.count > 1){
724 reverse(loopFrames, loopFrames + loopLength);
725 }
726 if ( __loops.start_frame != __loops.loop_frame ){
727 copy( loopFrames, loopFrames+loopLength ,tempFrames+ tempdataend );
728 }
729 }
730
731
732 if ( __loops.count == 0 && loopmode == Sample::Loops::REVERSE ){
733 reverse( tempFrames + __loops.loop_frame, tempFrames + newLength);
734 }
735
736 if(m_pPositionsRulerPath)
737 {
738 delete[] m_pPositionsRulerPath;
739 }
740
741 m_pPositionsRulerPath = tempFrames;
742
743 delete[] loopFrames;
744 delete[] normalFrames;
745 }
746
747
748
setSamplelengthFrames()749 void SampleEditor::setSamplelengthFrames()
750 {
751 getAllLocalFrameInfos();
752 unsigned oneSampleLength = __loops.end_frame - __loops.start_frame;
753 unsigned loopLength = __loops.end_frame - __loops.loop_frame ;
754 unsigned repeatsLength = loopLength * __loops.count;
755 unsigned newLength = 0;
756
757 if (oneSampleLength == loopLength){
758 newLength = oneSampleLength + oneSampleLength * __loops.count ;
759 }else
760 {
761 newLength =oneSampleLength + repeatsLength;
762 }
763
764 m_pslframes = newLength;
765 newlengthLabel->setText(QString("new sample length: %1 frames").arg(newLength));
766 checkRatioSettings();
767 }
768
769
770
valueChangedLoopCountSpinBox(int)771 void SampleEditor::valueChangedLoopCountSpinBox( int )
772 {
773 testpTimer();
774 if ( m_pslframes > Hydrogen::get_instance()->getAudioOutput()->getSampleRate() * 60 ){
775 AudioEngine::get_instance()->get_sampler()->stop_playing_notes();
776 m_pMainSampleWaveDisplay->paintLocatorEvent( -1 , false);
777 m_pTimer->stop();
778 m_pPlayButton = false;
779 }
780 __loops.count = LoopCountSpinBox->value() ;
781 m_pSampleEditorStatus = false;
782 setSamplelengthFrames();
783 if ( m_pslframes > Hydrogen::get_instance()->getAudioOutput()->getSampleRate() * 60 * 30){ // >30 min
784 LoopCountSpinBox->setMaximum(LoopCountSpinBox->value() -1);
785 }
786
787 }
788
789
790
valueChangedrubberbandCsettingscomboBox(const QString)791 void SampleEditor::valueChangedrubberbandCsettingscomboBox( const QString )
792 {
793 __rubberband.c_settings = rubberbandCsettingscomboBox->currentIndex();
794 m_pSampleEditorStatus = false;
795 }
796
797
798
valueChangedpitchdoubleSpinBox(double)799 void SampleEditor::valueChangedpitchdoubleSpinBox( double )
800 {
801 __rubberband.pitch = pitchdoubleSpinBox->value();
802 m_pSampleEditorStatus = false;
803 }
804
805
valueChangedrubberComboBox(const QString)806 void SampleEditor::valueChangedrubberComboBox( const QString )
807 {
808
809 if( rubberComboBox->currentText() != "off" ){
810 __rubberband.use = true;
811 }else
812 {
813 __rubberband.use = false;
814 __rubberband.divider = 1.0;
815 }
816
817
818 switch ( rubberComboBox->currentIndex() ){
819 case 0 ://
820 __rubberband.divider = 4.0;
821 break;
822 case 1 ://
823 __rubberband.divider = 1.0/64.0;
824 break;
825 case 2 ://
826 __rubberband.divider = 1.0/32.0;
827 break;
828 case 3 ://
829 __rubberband.divider = 1.0/16.0;
830 break;
831 case 4 ://
832 __rubberband.divider = 1.0/8.0;
833 break;
834 case 5 ://
835 __rubberband.divider = 1.0/4.0;
836 break;
837 case 6 ://
838 __rubberband.divider = 1.0/2.0;
839 break;
840 case 7 ://
841 __rubberband.divider = 1.0;
842 break;
843 default:
844 __rubberband.divider = (float)rubberComboBox->currentIndex() - 6.0;
845 }
846 // QMessageBox::information ( this, "Hydrogen", tr ( "divider %1" ).arg( __rubberband.divider ));
847 // float __rubberband.divider;
848 setSamplelengthFrames();
849
850
851 m_pSampleEditorStatus = false;
852 }
853
checkRatioSettings()854 void SampleEditor::checkRatioSettings()
855 {
856 //calculate ratio
857 double durationtime = 60.0 / Hydrogen::get_instance()->getNewBpmJTM() * __rubberband.divider;
858 double induration = (double) m_pslframes / (double) m_pSamplerate;
859 if (induration != 0.0) m_pRatio = durationtime / induration;
860
861 //my personal ratio quality settings
862 //ratios < 0.1 || > 3.0 are bad (red) or experimental sounds
863 //ratios > 0.1 && < 0.5 || > 2.0 && < 3.0 are mediocre (yellow)
864 //ratios > 0.5 && < 2.0 are good (green)
865 //
866 // 0.1 0.5 2.0 3.0
867 //<---red---[--yellow--[------green------]----yellow----]---red--->
868
869 //green ratio
870 if( ( m_pRatio >= 0.5 ) && ( m_pRatio <= 2.0 ) ){
871 rubberComboBox->setStyleSheet("QComboBox { background-color: green; }");
872 }
873 //yellow ratio
874 else if( ( m_pRatio >= 0.1 ) && ( m_pRatio <= 3.0 ) ){
875 rubberComboBox->setStyleSheet("QComboBox { background-color: yellow; }");
876 }
877 //red ratio
878 else{
879 rubberComboBox->setStyleSheet("QComboBox { background-color: red; }");
880 }
881 QString text = QString( " RB-Ratio = %1").arg(m_pRatio);
882 ratiolabel->setText( text );
883
884 //no rubberband = default
885 if( !__rubberband.use ){
886 rubberComboBox->setStyleSheet("QComboBox { background-color: 58, 62, 72; }");
887 ratiolabel->setText( "" );
888 }
889 }
890
891
valueChangedProcessingTypeComboBox(const QString unused)892 void SampleEditor::valueChangedProcessingTypeComboBox( const QString unused )
893 {
894 switch ( ProcessingTypeComboBox->currentIndex() ){
895 case 0 ://
896 __loops.mode = Sample::Loops::FORWARD;
897 break;
898 case 1 ://
899 __loops.mode = Sample::Loops::REVERSE;
900 break;
901 case 2 ://
902 __loops.mode = Sample::Loops::PINGPONG;
903 break;
904 default:
905 __loops.mode = Sample::Loops::FORWARD;
906 }
907 m_pSampleEditorStatus = false;
908 }
909
910
911
on_verticalzoomSlider_valueChanged(int value)912 void SampleEditor::on_verticalzoomSlider_valueChanged( int value )
913 {
914 m_pZoomfactor = value / 10 +1;
915 m_pSampleAdjustView->setDetailSamplePosition( m_pDetailFrame, m_pZoomfactor, m_pLineColor );
916 }
917
918
919
testPositionsSpinBoxes()920 void SampleEditor::testPositionsSpinBoxes()
921 {
922 if ( __loops.start_frame > __loops.loop_frame ) __loops.loop_frame = __loops.start_frame;
923 if ( __loops.start_frame > __loops.end_frame ) __loops.end_frame = __loops.start_frame;
924 if ( __loops.loop_frame > __loops.end_frame ) __loops.end_frame = __loops.loop_frame;
925 if ( __loops.end_frame < __loops.loop_frame ) __loops.loop_frame = __loops.end_frame;
926 if ( __loops.end_frame < __loops.start_frame ) __loops.start_frame = __loops.end_frame;
927 StartFrameSpinBox->setValue( __loops.start_frame );
928 LoopFrameSpinBox->setValue( __loops.loop_frame );
929 EndFrameSpinBox->setValue( __loops.end_frame );
930 }
931
932
933
testpTimer()934 void SampleEditor::testpTimer()
935 {
936 if ( m_pTimer->isActive() || m_pTargetDisplayTimer->isActive() ){
937 m_pMainSampleWaveDisplay->paintLocatorEvent( -1 , false);
938 m_pTimer->stop();
939 m_pTargetDisplayTimer->stop();
940 PlayPushButton->setText( QString( "&Play" ) );
941 PlayOrigPushButton->setText( QString( "P&lay original sample") );
942 AudioEngine::get_instance()->get_sampler()->stop_playing_notes();
943 m_pPlayButton = false;
944 }
945 }
946