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