hydrogen 1.2.6
InstrumentEditor.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-2025 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 <QtGui>
24#include <QtWidgets>
25
26
27#include <math.h>
28#include <assert.h>
29#include <vector>
30
31#include <core/Basics/Song.h>
32#include <core/Hydrogen.h>
33#include <core/Globals.h>
34#include <core/Basics/Adsr.h>
35#include <core/Basics/Sample.h>
42#include <core/EventQueue.h>
43using namespace H2Core;
44
45#include "../HydrogenApp.h"
46#include "../CommonStrings.h"
47#include "../Widgets/Rotary.h"
50#include "../Widgets/Button.h"
53#include "../Widgets/LCDCombo.h"
54#include "../Widgets/Fader.h"
55#include "InstrumentEditor.h"
57#include "WaveDisplay.h"
58#include "LayerPreview.h"
60
62 : QWidget( pParent )
63 , m_pInstrument( nullptr )
64 , m_nSelectedLayer( 0 )
67{
68 setFixedWidth( 290 );
69
70 auto pCommonStrings = HydrogenApp::get_instance()->getCommonStrings();
71
72 // Instrument properties top
74 m_pInstrumentPropTop->setPixmap( "/instrumentEditor/instrumentTab_top.png" );
75
77 pCommonStrings->getGeneralButton(), false, QSize(),
78 tr( "Show instrument properties" ) );
79 m_pShowInstrumentBtn->move( 4, 4 );
80
81 connect( m_pShowInstrumentBtn, &QPushButton::clicked,
82 [=]() { showLayers( false ); } );
83
85 pCommonStrings->getLayersButton(), false, QSize(),
86 tr( "Show layers properties" ) );
87 m_pShowLayersBtn->move( 145, 4 );
88
89 connect( m_pShowLayersBtn, &QPushButton::clicked,
90 [=]() { showLayers( true ); } );
91
92
93 // Instrument properties
94 m_pInstrumentProp = new PixmapWidget( this );
95 m_pInstrumentProp->move(0, 31);
96 m_pInstrumentProp->setPixmap( "/instrumentEditor/instrumentTab.png" );
97
98 m_pNameLbl = new ClickableLabel( m_pInstrumentProp, QSize( 279, 27 ), "",
100 m_pNameLbl->move( 5, 4 );
101 m_pNameLbl->setScaledContents( true );
102
104 //Midi Out
105
106 ClickableLabel* pMidiOutLbl = new ClickableLabel( m_pInstrumentProp, QSize( 61, 10 ),
107 pCommonStrings->getMidiOutLabel() );
108 pMidiOutLbl->move( 22, 281 );
109
110 m_pMidiOutChannelLCD = new LCDSpinBox( m_pInstrumentProp, QSize( 59, 24 ),
111 LCDSpinBox::Type::Int, -1, 16,
112 true, true );
113 m_pMidiOutChannelLCD->move( 98, 257 );
114 m_pMidiOutChannelLCD->setToolTip(QString(tr("Midi out channel")));
115 connect( m_pMidiOutChannelLCD, SIGNAL( valueChanged( double ) ),
116 this, SLOT( midiOutChannelChanged( double ) ) );
118 pCommonStrings->getMidiOutChannelLabel() );
119 m_pMidiOutChannelLbl->move( 96, 281 );
120
122 m_pMidiOutNoteLCD = new LCDSpinBox( m_pInstrumentProp, QSize( 59, 24 ),
123 LCDSpinBox::Type::Int, 0, 127, true );
124 m_pMidiOutNoteLCD->move( 161, 257 );
125 m_pMidiOutNoteLCD->setToolTip(QString(tr("Midi out note")));
126 connect( m_pMidiOutNoteLCD, SIGNAL( valueChanged( double ) ),
127 this, SLOT( midiOutNoteChanged( double ) ) );
128 m_pMidiOutNoteLbl = new ClickableLabel( m_pInstrumentProp, QSize( 61, 10 ),
129 pCommonStrings->getMidiOutNoteLabel() );
130 m_pMidiOutNoteLbl->move( 159, 281 );
131
133
134 connect( m_pNameLbl, SIGNAL( labelClicked(ClickableLabel*) ),
135 this, SLOT( labelClicked(ClickableLabel*) ) );
136
137 m_pPitchLCD = new LCDDisplay( m_pInstrumentProp, QSize( 56, 20 ), false, false );
138 m_pPitchLCD->move( 24, 213 );
139 m_pPitchLbl = new ClickableLabel( m_pInstrumentProp, QSize( 54, 10 ),
140 pCommonStrings->getPitchLabel() );
141 m_pPitchLbl->move( 25, 235 );
142
143 const float fFinePitch = 0.5;
145 tr( "Pitch offset (Coarse)" ), true,
146 Instrument::fPitchMin + fFinePitch,
147 Instrument::fPitchMax - fFinePitch );
148 m_pPitchCoarseRotary->move( 84, 210 );
149
150 connect( m_pPitchCoarseRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
151 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
152 m_pPitchCoarseLbl = new ClickableLabel( m_pInstrumentProp, QSize( 48, 10 ),
153 pCommonStrings->getPitchCoarseLabel() );
154 m_pPitchCoarseLbl->move( 82, 235 );
155
157 tr( "Pitch offset (Fine)" ), false,
158 -fFinePitch, fFinePitch );
159 //it will have resolution of 100 steps between Min and Max => quantum delta = 0.01
160 m_pPitchFineRotary->move( 138, 210 );
161 connect( m_pPitchFineRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
162 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
163 m_pPitchFineLbl = new ClickableLabel( m_pInstrumentProp, QSize( 48, 10 ),
164 pCommonStrings->getPitchFineLabel() );
165 m_pPitchFineLbl->move( 136, 235 );
166
167
168
170 tr( "Random pitch factor" ), false );
171 m_pRandomPitchRotary->move( 194, 210 );
172 connect( m_pRandomPitchRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
173 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
174 m_pPitchRandomLbl = new ClickableLabel( m_pInstrumentProp, QSize( 48, 10 ),
175 pCommonStrings->getPitchRandomLabel() );
176 m_pPitchRandomLbl->move( 192, 235 );
177
178 // Filter
180 "", pCommonStrings->getBypassButton(), true,
181 QSize( 0, 0 ), "", false, true );
182 connect( m_pFilterBypassBtn, SIGNAL( clicked() ),
183 this, SLOT( filterActiveBtnClicked() ) );
184 m_pFilterBypassBtn->move( 67, 169 );
185
187 tr( "Filter Cutoff" ), false );
188 m_pCutoffRotary->setDefaultValue( m_pCutoffRotary->getMax() );
189 connect( m_pCutoffRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
190 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
191 m_pCutoffLbl = new ClickableLabel( m_pInstrumentProp, QSize( 48, 10 ),
192 pCommonStrings->getCutoffLabel() );
193 m_pCutoffLbl->move( 107, 189 );
194
196 tr( "Filter resonance" ), false );
197 connect( m_pResonanceRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
198 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
199 m_pResonanceLbl = new ClickableLabel( m_pInstrumentProp, QSize( 56, 10 ),
200 pCommonStrings->getResonanceLabel() );
201 m_pResonanceLbl->move( 157, 189 );
202
203 m_pCutoffRotary->move( 109, 164 );
204 m_pResonanceRotary->move( 163, 164 );
205 // ~ Filter
206
207 // ADSR
209 tr( "Length of Attack phase.\n\nValue" ), false );
211 tr( "Length of Decay phase.\n\nValue" ), false );
213 tr( "Sample volume in Sustain phase.\n\nValue" ), false );
214 m_pSustainRotary->setDefaultValue( m_pSustainRotary->getMax() );
216 tr( "Length of Release phase.\n\nValue" ), false );
217 m_pReleaseRotary->setDefaultValue( 0.09 );
218 connect( m_pAttackRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
219 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
220 connect( m_pDecayRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
221 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
222 connect( m_pSustainRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
223 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
224 connect( m_pReleaseRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
225 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
226 m_pAttackRotary->move( 45, 52 );
227 m_pDecayRotary->move( 97, 52 );
228 m_pSustainRotary->move( 149, 52 );
229 m_pReleaseRotary->move( 201, 52 );
230
231 m_pAttackLbl = new ClickableLabel( m_pInstrumentProp, QSize( 48, 10 ),
232 pCommonStrings->getAttackLabel() );
233 m_pAttackLbl->move( 43, 78 );
234 m_pDecayLbl = new ClickableLabel( m_pInstrumentProp, QSize( 48, 10 ),
235 pCommonStrings->getDecayLabel() );
236 m_pDecayLbl->move( 95, 78 );
237 m_pSustainLbl = new ClickableLabel( m_pInstrumentProp, QSize( 48, 10 ),
238 pCommonStrings->getSustainLabel() );
239 m_pSustainLbl->move( 147, 78 );
240 m_pReleaseLbl = new ClickableLabel( m_pInstrumentProp, QSize( 48, 10 ),
241 pCommonStrings->getReleaseLabel() );
242 m_pReleaseLbl->move( 199, 78 );
243 // ~ ADSR
244
245 // instrument gain
246 m_pInstrumentGainLCD = new LCDDisplay( m_pInstrumentProp, QSize( 43, 20 ), false, false );
248 tr( "Instrument gain" ), false, 0.0, 5.0 );
249 m_pInstrumentGain->setDefaultValue( 1.0 );
250 connect( m_pInstrumentGain, SIGNAL( valueChanged( WidgetWithInput* ) ),
251 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
252 m_pInstrumentGainLCD->move( 62, 103 );
253 m_pInstrumentGain->move( 109, 100 );
254 m_pGainLbl = new ClickableLabel( m_pInstrumentProp, QSize( 48, 10 ),
255 pCommonStrings->getGainLabel() );
256 m_pGainLbl->move( 107, 125 );
257
258
259 m_pMuteGroupLCD = new LCDSpinBox( m_pInstrumentProp, QSize( 59, 24 ),
260 LCDSpinBox::Type::Int, -1, 100,
261 true, true );
262 m_pMuteGroupLCD->move( 160, 101 );
263 connect( m_pMuteGroupLCD, SIGNAL( valueChanged( double ) ),
264 this, SLOT( muteGroupChanged( double ) ) );
265 m_pMuteGroupLbl = new ClickableLabel( m_pInstrumentProp, QSize( 61, 10 ),
266 pCommonStrings->getMuteGroupLabel() );
267 m_pMuteGroupLbl->move( 159, 125 );
268
269 m_pIsStopNoteCheckBox = new QCheckBox ( tr( "" ), m_pInstrumentProp );
270 m_pIsStopNoteCheckBox->move( 42, 139 );
271 m_pIsStopNoteCheckBox->adjustSize();
272 m_pIsStopNoteCheckBox->setFixedSize( 14, 14 );
273 m_pIsStopNoteCheckBox->setToolTip( tr( "Stop the current playing instrument-note before trigger the next note sample" ) );
274 m_pIsStopNoteCheckBox->setFocusPolicy ( Qt::NoFocus );
275 connect( m_pIsStopNoteCheckBox, SIGNAL( toggled( bool ) ),
276 this, SLOT( onIsStopNoteCheckBoxClicked( bool ) ) );
277 m_pIsStopNoteLbl = new ClickableLabel( m_pInstrumentProp, QSize( 87, 10 ),
278 pCommonStrings->getIsStopNoteLabel() );
279 m_pIsStopNoteLbl->move( 59, 144 );
280
281 m_pApplyVelocity = new QCheckBox ( "", m_pInstrumentProp );
282 m_pApplyVelocity->move( 153, 139 );
283 m_pApplyVelocity->adjustSize();
284 m_pApplyVelocity->setFixedSize( 14, 14 );
285 m_pApplyVelocity->setToolTip( tr( "Don't change the layers' gain based on velocity" ) );
286 m_pApplyVelocity->setFocusPolicy( Qt::NoFocus );
287 connect( m_pApplyVelocity, SIGNAL( toggled( bool ) ),
288 this, SLOT( onIsApplyVelocityCheckBoxClicked( bool ) ) );
290 pCommonStrings->getApplyVelocityLabel() );
291 m_pApplyVelocityLbl->move( 170, 144 );
292
294 // HiHat setup
295
296 m_pHihatGroupLCD = new LCDSpinBox( m_pInstrumentProp, QSize( 59, 24 ),
297 LCDSpinBox::Type::Int, -1, 32,
298 true, true );
299 m_pHihatGroupLCD->move( 28, 303 );
300 connect( m_pHihatGroupLCD, SIGNAL( valueChanged( double ) ),
301 this, SLOT( hihatGroupChanged( double ) ) );
302 m_pHihatGroupLbl = new ClickableLabel( m_pInstrumentProp, QSize( 69, 10 ),
303 pCommonStrings->getHihatGroupLabel() );
304 m_pHihatGroupLbl->move( 22, 327 );
305
306 m_pHihatMinRangeLCD = new LCDSpinBox( m_pInstrumentProp, QSize( 59, 24 ),
307 LCDSpinBox::Type::Int, 0, 127, true );
308 m_pHihatMinRangeLCD->move( 138, 303 );
309 connect( m_pHihatMinRangeLCD, SIGNAL( valueChanged( double ) ),
310 this, SLOT( hihatMinRangeChanged( double ) ) );
312 pCommonStrings->getHihatMinRangeLabel() );
313 m_pHihatMinRangeLbl->move( 136, 327 );
314
315 m_pHihatMaxRangeLCD = new LCDSpinBox( m_pInstrumentProp, QSize( 59, 24 ),
316 LCDSpinBox::Type::Int, 0, 127, true );
317 m_pHihatMaxRangeLCD->move( 203, 303 );
318 connect( m_pHihatMaxRangeLCD, SIGNAL( valueChanged( double ) ),
319 this, SLOT( hihatMaxRangeChanged( double ) ) );
321 pCommonStrings->getHihatMaxRangeLabel() );
322 m_pHihatMaxRangeLbl->move( 201, 327 );
323 // ~ Instrument properties
324
325 // LAYER properties
326 m_pLayerProp = new PixmapWidget( this );
327 m_pLayerProp->setObjectName( "LayerProperties" );
328 m_pLayerProp->move( 0, 31 );
329 m_pLayerProp->hide();
330 m_pLayerProp->setPixmap( "/instrumentEditor/layerTabsupernew.png" );
331
332 // Component
333 m_pCompoNameLbl = new ClickableLabel( m_pLayerProp, QSize( 279, 27 ), "",
335 m_pCompoNameLbl->move( 5, 4 );
336 connect( m_pCompoNameLbl, SIGNAL( labelClicked(ClickableLabel*) ),
337 this, SLOT( labelCompoClicked(ClickableLabel*) ) );
338
339 m_buttonDropDownCompo = new Button( m_pLayerProp, QSize( 18, 18 ),
340 Button::Type::Push, "dropdown.svg", "",
341 false, QSize( 12, 12 ) );
342 m_buttonDropDownCompo->setObjectName( "InstrumentEditorComponentNameDropDown" );
343 m_buttonDropDownCompo->move( 263, 8 );
344 connect( m_buttonDropDownCompo, SIGNAL( clicked() ),
345 this, SLOT( onDropDownCompoClicked() ) );
346
347 // Layer preview
348 m_pLayerPreview = new LayerPreview( nullptr );
349
350 m_pLayerScrollArea = new QScrollArea( m_pLayerProp);
351 m_pLayerScrollArea->setFrameShape( QFrame::NoFrame );
352 m_pLayerScrollArea->move( 6, 44 );
353 m_pLayerScrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
355 m_pLayerScrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
356 }
357 m_pLayerScrollArea->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
358 m_pLayerScrollArea->setMaximumHeight( 182 );
360
361
362 // Waveform display
364 m_pWaveDisplay->resize( 277, 58 );
365 m_pWaveDisplay->updateDisplay( nullptr );
366 m_pWaveDisplay->move( 5, 241 );
367 connect( m_pWaveDisplay, SIGNAL( doubleClicked(QWidget*) ),
368 this, SLOT( waveDisplayDoubleClicked(QWidget*) ) );
369
370 m_pLoadLayerBtn = new Button( m_pLayerProp, QSize( 92, 18 ), Button::Type::Push,
371 "", pCommonStrings->getLoadLayerButton() );
372 m_pLoadLayerBtn->setObjectName( "LoadLayerButton" );
373 m_pLoadLayerBtn->move( 5, 304 );
374
376 "", pCommonStrings->getDeleteLayerButton() );
377 m_pRemoveLayerBtn->setObjectName( "RemoveLayerButton" );
378 m_pRemoveLayerBtn->move( 97, 304 );
379
381 "", pCommonStrings->getEditLayerButton() );
382 m_pSampleEditorBtn->setObjectName( "SampleEditorButton" );
383 m_pSampleEditorBtn->move( 191, 304 );
384
385 connect( m_pLoadLayerBtn, SIGNAL( clicked() ),
386 this, SLOT( loadLayerBtnClicked() ) );
387 connect( m_pRemoveLayerBtn, SIGNAL( clicked() ),
388 this, SLOT( removeLayerButtonClicked() ) );
389 connect( m_pSampleEditorBtn, SIGNAL( clicked() ),
390 this, SLOT( showSampleEditor() ) );
391 // Layer gain
392 m_pLayerGainLCD = new LCDDisplay( m_pLayerProp, QSize( 36, 16 ), false, false );
394 tr( "Layer gain" ), false , 0.0, 5.0);
395 m_pLayerGainRotary->setDefaultValue( 1.0 );
396 connect( m_pLayerGainRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
397 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
398 m_pLayerGainLbl = new ClickableLabel( m_pLayerProp, QSize( 44, 10 ),
399 pCommonStrings->getLayerGainLabel() );
400 m_pLayerGainLbl->move( 50, 360 );
401
402 m_pCompoGainLCD = new LCDDisplay( m_pLayerProp, QSize( 36, 16 ), false, false );
404 tr( "Component volume" ), false, 0.0, 5.0 );
405 m_pCompoGainRotary->setDefaultValue ( 1.0 );
406 connect( m_pCompoGainRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
407 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
408 m_pCompoGainLbl = new ClickableLabel( m_pLayerProp, QSize( 44, 10 ),
409 pCommonStrings->getComponentGainLabel() );
410 m_pCompoGainLbl->move( 147, 360 );
411
412 m_pLayerPitchCoarseLCD = new LCDDisplay( m_pLayerProp, QSize( 28, 16 ), false, false );
413 m_pLayerPitchFineLCD = new LCDDisplay( m_pLayerProp, QSize( 28, 16 ), false, false );
414 m_pLayerPitchLbl = new ClickableLabel( m_pLayerProp, QSize( 45, 10 ),
415 pCommonStrings->getPitchLabel() );
416 m_pLayerPitchLbl->move( 17, 412 );
417
419 tr( "Layer pitch (Coarse)" ), true,
420 Instrument::fPitchMin + fFinePitch,
421 Instrument::fPitchMax - fFinePitch );
422 connect( m_pLayerPitchCoarseRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
423 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
424 m_pLayerPitchCoarseLbl = new ClickableLabel( m_pLayerProp, QSize( 44, 10 ),
425 pCommonStrings->getPitchCoarseLabel() );
426 m_pLayerPitchCoarseLbl->move( 61, 412 );
427
429 tr( "Layer pitch (Fine)" ), true, -50.0, 50.0 );
430 connect( m_pLayerPitchFineRotary, SIGNAL( valueChanged( WidgetWithInput* ) ),
431 this, SLOT( rotaryChanged( WidgetWithInput* ) ) );
432 m_pLayerPitchFineLbl = new ClickableLabel( m_pLayerProp, QSize( 44, 10 ),
433 pCommonStrings->getPitchFineLabel() );
434 m_pLayerPitchFineLbl->move( 147, 412 );
435
436 m_pLayerGainLCD->move( 53, 343 );
437 m_pLayerGainRotary->move( 94, 341 );
438
439 m_pCompoGainLCD->move( 151, 343 );
440 m_pCompoGainRotary->move( 191, 341 );
441
442 m_pLayerPitchCoarseLCD->move( 70, 393 );
443 m_pLayerPitchCoarseRotary->move( 105, 391 );
444
445 m_pLayerPitchFineLCD->move( 155, 393 );
446 m_pLayerPitchFineRotary->move( 191, 391 );
447
448 m_sampleSelectionAlg = new LCDCombo(m_pLayerProp, QSize( width() - 76 - 7, 18 ), true );
449 m_sampleSelectionAlg->move( 76, 432 );
450 m_sampleSelectionAlg->setToolTip( tr( "Select selection algorithm" ) );
451 m_sampleSelectionAlg->addItem( QString( "First in Velocity" ) );
452 m_sampleSelectionAlg->addItem( QString( "Round Robin" ) );
453 m_sampleSelectionAlg->addItem( QString( "Random" ) );
454 connect( m_sampleSelectionAlg, SIGNAL( currentIndexChanged( int ) ),
455 this, SLOT( sampleSelectionChanged( int ) ) );
456 m_pSampleSelectionLbl = new ClickableLabel( m_pLayerProp, QSize( 70, 10 ),
457 pCommonStrings->getSampleSelectionLabel() );
458 m_pSampleSelectionLbl->move( 7, 436 );
459
460 // ~ Layer properties
461
462 //component handling
463 QStringList itemsCompo;
464 popCompo = new QMenu( this );
465
466 connect( popCompo, SIGNAL( triggered(QAction*) ),
467 this, SLOT( compoChangeAddDelete(QAction*) ) );
468 update();
469 // ~ component handling
470
471 showLayers( false );
472
474
475 selectedInstrumentChangedEvent(); // force an update
476
479}
480
481
482
484{
485 //INFOLOG( "DESTROY" );
486}
487
489 // A new song got loaded
490 if ( nValue == 0 ) {
492
493 // The function call above sets some spurious isModified when
494 // updating the states of the widgets. This has to be reset
495 // for a freshly loaded song.
497 }
498}
499
503
505{
506 Hydrogen *pHydrogen = Hydrogen::get_instance();
507 std::shared_ptr<Song> pSong = pHydrogen->getSong();
508 auto pCompoList = pSong->getComponents();
509
511
512 // update layer list
513 if ( pSong != nullptr && m_pInstrument != nullptr &&
514 pCompoList != nullptr && pCompoList->size() > 0 ) {
515 m_pNameLbl->setText( m_pInstrument->get_name() );
516
517 // ADSR
518 m_pAttackRotary->setValue( sqrtf(m_pInstrument->get_adsr()->getAttack() / 100000.0) );
519 m_pDecayRotary->setValue( sqrtf(m_pInstrument->get_adsr()->getDecay() / 100000.0) );
520 m_pSustainRotary->setValue( m_pInstrument->get_adsr()->getSustain() );
521 float fTmp = m_pInstrument->get_adsr()->getRelease() - 256.0;
522 if( fTmp < 0.0 ) {
523 fTmp = 0.0;
524 }
525 m_pReleaseRotary->setValue( sqrtf(fTmp / 100000.0) );
526 // ~ ADSR
527
528 // filter
529 m_pFilterBypassBtn->setChecked( !m_pInstrument->is_filter_active() );
530 m_pCutoffRotary->setValue( m_pInstrument->get_filter_cutoff() );
531 m_pResonanceRotary->setValue( m_pInstrument->get_filter_resonance() );
532 // ~ filter
533
535
536 // pitch random
537 m_pRandomPitchRotary->setValue( m_pInstrument->get_random_pitch_factor() );
538
539
540 //Stop Note
541 m_pIsStopNoteCheckBox->setChecked( m_pInstrument->is_stop_notes() );
542
543 //Ignore Velocity
544 m_pApplyVelocity->setChecked( m_pInstrument->get_apply_velocity() );
545
546 // instr gain
547 char tmp[7];
548 sprintf( tmp, "%#.2f", m_pInstrument->get_gain() );
549 m_pInstrumentGainLCD->setText( tmp );
550 m_pInstrumentGain->setValue( m_pInstrument->get_gain() );
551
552 // instr mute group
553 m_pMuteGroupLCD->setValue( m_pInstrument->get_mute_group());
554
555 // midi out channel
556 if ( m_pInstrument->get_midi_out_channel() == -1 ) {
557 m_pMidiOutChannelLCD->setValue( -1 ); // turn off
558 } else {
559 // The MIDI channels start at 1 instead of zero.
560 m_pMidiOutChannelLCD->setValue( m_pInstrument->get_midi_out_channel() + 1 );
561 }
562
563 //midi out note
564 m_pMidiOutNoteLCD->setValue( m_pInstrument->get_midi_out_note() );
565
566 // hihat
567 m_pHihatGroupLCD->setValue( m_pInstrument->get_hihat_grp() );
568 m_pHihatMinRangeLCD->setValue( m_pInstrument->get_lower_cc() );
569 m_pHihatMaxRangeLCD->setValue( m_pInstrument->get_higher_cc() );
570
571 // see instrument.h
572 m_sampleSelectionAlg->setCurrentIndex( m_pInstrument->sample_selection_alg() );
573
574 itemsCompo.clear();
575 for ( const auto& pComponent : *pSong->getComponents() ) {
576 if ( ! itemsCompo.contains( pComponent->get_name() ) ) {
577 itemsCompo.append( pComponent->get_name() );
578 }
579 }
580 itemsCompo.append("--sep--");
581 itemsCompo.append("add");
582 itemsCompo.append("delete");
583 itemsCompo.append("rename");
584
585 update();
586
587 bool bFound = false;
588 for ( const auto& ppComponent : *pCompoList ) {
589 if ( ppComponent->get_id() == m_nSelectedComponent ) {
590 bFound = true;
591 break;
592 }
593 }
594 if ( !bFound ){
595 m_nSelectedComponent = pCompoList->front()->get_id();
596 }
597
598 auto pTmpComponent = pSong->getComponent( m_nSelectedComponent );
599
600 assert(pTmpComponent);
601
602 m_pCompoNameLbl->setText( pTmpComponent->get_name() );
603
604 if ( m_nSelectedLayer >= 0 ) {
605
606 auto pComponent = m_pInstrument->get_component( m_nSelectedComponent );
607 if ( pComponent != nullptr ) {
608
609 char tmp[20];
610 sprintf( tmp, "%#.2f", pComponent->get_gain());
611 m_pCompoGainLCD->setText( tmp );
612
613 m_pCompoGainRotary->setValue( pComponent->get_gain() );
614
615 auto pLayer = pComponent->get_layer( m_nSelectedLayer );
616 if ( pLayer != nullptr ) {
617 m_pWaveDisplay->updateDisplay( pLayer );
618 }
619 else {
620 m_pWaveDisplay->updateDisplay( nullptr );
621 }
622 }
623 else {
624 m_pWaveDisplay->updateDisplay( nullptr );
625 }
626 }
627 else {
628 m_pWaveDisplay->updateDisplay( nullptr );
629 }
630 }
631 else {
632 m_pNameLbl->setText( QString( "NULL Instrument..." ) );
633 m_pWaveDisplay->updateDisplay( nullptr );
635 }
636
638}
639
640// In here we just check those parameters that can be altered by MIDI
641// or OSC messages or other parts of Hydrogen.
643{
644 auto pInstrumentList = Hydrogen::get_instance()->getSong()->getInstrumentList();
645
646 // Check if either this particular line or all lines should be updated.
647 if ( m_pInstrument != nullptr ) {
648 if ( m_pInstrument == pInstrumentList->get( nInstrumentNumber ) ||
649 nInstrumentNumber == -1 ) {
650
651 if ( m_pNameLbl->text() != m_pInstrument->get_name() ) {
652 m_pNameLbl->setText( m_pInstrument->get_name() );
653 }
654
655 if ( m_pFilterBypassBtn->isChecked() !=
656 !m_pInstrument->is_filter_active() ) {
657 m_pFilterBypassBtn->setChecked( !m_pInstrument->is_filter_active() );
658 }
659 if ( m_pCutoffRotary->getValue() != m_pInstrument->get_filter_cutoff() ) {
660 m_pCutoffRotary->setValue( m_pInstrument->get_filter_cutoff() );
661 }
662 if ( m_pResonanceRotary->getValue() !=
663 m_pInstrument->get_filter_resonance() ) {
664 m_pResonanceRotary->setValue( m_pInstrument->get_filter_resonance() );
665 }
667 }
668 // In case nInstrumentNumber does not belong to the currently
669 // selected instrument we don't have to do anything.
670 }
671 else {
672 m_pNameLbl->setText( QString( "NULL Instrument..." ) );
673 m_pWaveDisplay->updateDisplay( nullptr );
675 }
676
678}
679
681 const QString sNewPitch = QString( "%1" )
682 .arg( m_pInstrument->get_pitch_offset(), -2, 'f', 2, '0' );
683
684 if ( m_pPitchLCD->text() != sNewPitch ) {
685 m_pPitchLCD->setText( sNewPitch );
686 }
687
688 // pitch offset
689
690 /* fCoarsePitch is the closest integer to pitch_offset (represents the pitch
691 shift interval in half steps) while it is an integer number, it's defined
692 float to be used in next lines */
693 float fCoarsePitch;
694
695 // Since the 'fine' rotary covers values from -0.5 to 0.5 e.g. 1.5 can be
696 // represented by both coarse: 2, fine: -0.5 and coarse: 1, fine: 0.5. We
697 // need some extra logic to avoid unexpected jumping of the rotaries.
698 if ( m_pPitchFineRotary->getValue() == 0.5 &&
699 m_pInstrument->get_pitch_offset() -
700 trunc( m_pInstrument->get_pitch_offset() ) == 0.5 ) {
701 fCoarsePitch = trunc( m_pInstrument->get_pitch_offset() );
702 }
703 else if ( m_pPitchFineRotary->getValue() == -0.5 &&
704 trunc( m_pInstrument->get_pitch_offset() ) -
705 m_pInstrument->get_pitch_offset() == 0.5 ) {
706 fCoarsePitch = ceil( m_pInstrument->get_pitch_offset() );
707 }
708 else {
709 fCoarsePitch = round( m_pInstrument->get_pitch_offset() );
710 }
711
712 // fFinePitch represents the fine adjustment (between -0.5 and +0.5) if
713 // pitch_offset has decimal part
714 const float fFinePitch = m_pInstrument->get_pitch_offset() - fCoarsePitch;
715
716 if ( m_pPitchCoarseRotary->getValue() != fCoarsePitch ) {
717 m_pPitchCoarseRotary->setValue( fCoarsePitch );
718 }
719 if ( m_pPitchFineRotary->getValue() != fFinePitch ) {
720 m_pPitchFineRotary->setValue( fFinePitch );
721 }
722}
723
725{
726 assert( ref );
727 Rotary* pRotary = static_cast<Rotary*>( ref );
728 auto pCoreActionController =
730
731 const auto pSong = Hydrogen::get_instance()->getSong();
732 if ( pSong == nullptr ) {
733 return;
734 }
735
736 float fVal = pRotary->getValue();
737
738 if ( m_pInstrument ) {
739 if ( pRotary == m_pRandomPitchRotary ){
740 m_pInstrument->set_random_pitch_factor( fVal );
741 }
742 else if ( pRotary == m_pPitchCoarseRotary ) {
743 //round fVal, since Coarse is the integer number of half steps
744 float fNewPitch = round( fVal ) + m_pPitchFineRotary->getValue();
745 pCoreActionController->setInstrumentPitch(
746 pSong->getInstrumentList()->index( m_pInstrument ),
747 fNewPitch );
748 }
749 else if ( pRotary == m_pPitchFineRotary ) {
750 float fNewPitch = round( m_pPitchCoarseRotary->getValue() ) + fVal;
751 pCoreActionController->setInstrumentPitch(
752 pSong->getInstrumentList()->index( m_pInstrument ),
753 fNewPitch );
754 }
755 else if ( pRotary == m_pCutoffRotary ) {
756 m_pInstrument->set_filter_cutoff( fVal );
757 }
758 else if ( pRotary == m_pResonanceRotary ) {
759 if ( fVal > 0.95f ) {
760 fVal = 0.95f;
761 }
762 m_pInstrument->set_filter_resonance( fVal );
763 }
764 else if ( pRotary == m_pAttackRotary ) {
765 m_pInstrument->get_adsr()->setAttack( fVal * fVal * 100000 );
766 }
767 else if ( pRotary == m_pDecayRotary ) {
768 m_pInstrument->get_adsr()->setDecay( fVal * fVal * 100000 );
769 }
770 else if ( pRotary == m_pSustainRotary ) {
771 m_pInstrument->get_adsr()->setSustain( fVal );
772 }
773 else if ( pRotary == m_pReleaseRotary ) {
774 m_pInstrument->get_adsr()->setRelease( 256.0 + fVal * fVal * 100000 );
775 }
776 else if ( pRotary == m_pLayerGainRotary ) {
777 char tmp[20];
778 sprintf( tmp, "%#.2f", fVal );
779 m_pLayerGainLCD->setText( tmp );
780
781 auto pCompo = m_pInstrument->get_component(m_nSelectedComponent);
782 if( pCompo ) {
783 auto pLayer = pCompo->get_layer( m_nSelectedLayer );
784 if ( pLayer ) {
785 pLayer->set_gain( fVal );
786 m_pWaveDisplay->updateDisplay( pLayer );
787 }
788 }
789 }
790 else if ( pRotary == m_pCompoGainRotary ) {
791 char tmp[20];
792 sprintf( tmp, "%#.2f", fVal );
793 m_pCompoGainLCD->setText( tmp );
794
795 auto pCompo = m_pInstrument->get_component(m_nSelectedComponent);
796 pCompo->set_gain( fVal );
797 }
798 else if ( pRotary == m_pLayerPitchCoarseRotary ) {
799 m_pLayerPitchCoarseLCD->setText( QString( "%1" ).arg( (int) round( fVal ) ) );
800
801 auto pCompo = m_pInstrument->get_component(m_nSelectedComponent);
802 if( pCompo ) {
803 auto pLayer = pCompo->get_layer( m_nSelectedLayer );
804 if ( pLayer ) {
805 float fCoarse = round( m_pLayerPitchCoarseRotary->getValue() );
806 float fFine = m_pLayerPitchFineRotary->getValue() / 100.0;
807 pLayer->set_pitch( fCoarse + fFine );
808 }
809 }
810 }
811 else if ( pRotary == m_pLayerPitchFineRotary ) {
812 m_pLayerPitchFineLCD->setText( QString( "%1" ).arg( fVal, 0, 'f', 0 ) );
813 auto pCompo = m_pInstrument->get_component(m_nSelectedComponent);
814 if( pCompo ) {
815 auto pLayer = pCompo->get_layer( m_nSelectedLayer );
816 if ( pLayer ) {
817 float fCoarse = round( m_pLayerPitchCoarseRotary->getValue() );
818 float fFine = m_pLayerPitchFineRotary->getValue() / 100.0;
819 pLayer->set_pitch( fCoarse + fFine );
820 }
821 }
822 }
823 else if ( pRotary == m_pInstrumentGain ) {
824 fVal = fVal;
825 char tmp[20];
826 sprintf( tmp, "%#.2f", fVal );
827 m_pInstrumentGainLCD->setText( tmp );
828 m_pInstrument->set_gain( fVal );
829 }
830 else {
831 ERRORLOG( "[rotaryChanged] unhandled rotary" );
832 }
833 }
834}
835
836
838{
839 if ( m_pInstrument ) {
840 m_pInstrument->set_filter_active( ! m_pFilterBypassBtn->isChecked() );
841 }
842}
843
844
846{
847 if ( !m_pInstrument ) {
848 return;
849 }
850
851 auto pCompo = m_pInstrument->get_component(m_nSelectedComponent);
852 if( !pCompo ) {
853 return;
854 }
855
856 auto pLayer = pCompo->get_layer( m_nSelectedLayer );
857 if ( pLayer ) {
858 auto pSample = pLayer->get_sample();
859
860 if( pSample != nullptr ) {
861 QString name = pSample->get_filepath();
863 }
864 }
865 else {
867 }
868}
869
871{
872 if ( m_pInstrument ) {
873 auto pCompo = m_pInstrument->get_component(m_nSelectedComponent);
874 if( pCompo ) {
875 auto pLayer = pCompo->get_layer( m_nSelectedLayer );
876 if ( pLayer != nullptr ) {
877 auto pSample = pLayer->get_sample();
878 if ( pSample == nullptr ) {
879 return;
880 }
881 QString name = pSample->get_filepath();
883 }
884 }
885 }
886}
887
889{
890 auto pHydrogen = Hydrogen::get_instance();
891 pHydrogen->getAudioEngine()->lock( RIGHT_HERE );
892
893 if ( m_pInstrument != nullptr ) {
894 auto pCompo = m_pInstrument->get_component( m_nSelectedComponent );
895 if( pCompo != nullptr ) {
896 pCompo->set_layer( nullptr, m_nSelectedLayer );
897
898 pHydrogen->setIsModified( true );
899
900 // Select next loaded layer - if available - in order to
901 // allow for a quick removal of all layers. In case the
902 // last layer was removed, the previous one will be
903 // selected.
904 int nNextLayerIndex = 0;
905 int nCount = 0;
906 for( int n = 0; n < InstrumentComponent::getMaxLayers(); n++ ) {
907 auto pLayer = pCompo->get_layer( n );
908 if( pLayer != nullptr ){
909 nCount++;
910
911 if ( nNextLayerIndex <= m_nSelectedLayer &&
912 n != m_nSelectedLayer ) {
913 nNextLayerIndex = n;
914 }
915 }
916 }
917
918 if( nCount == 0 ){
919 m_pInstrument->get_components()->erase( m_pInstrument->get_components()->begin() + m_nSelectedComponent );
920 } else {
921 m_pLayerPreview->setSelectedLayer( nNextLayerIndex );
923 }
924
925 }
926 }
927
928 pHydrogen->getAudioEngine()->unlock();
929 selectedInstrumentChangedEvent(); // update all
930 m_pLayerPreview->updateAll();
931}
932
933
934
936{
937 Hydrogen *pHydrogen = Hydrogen::get_instance();
938
940 QString sFilename = "";
941 if ( ! Filesystem::dir_readable( sPath, false ) ){
942 sPath = QDir::homePath();
943 }
944
945 // In case the button was pressed while a layer was selected, we
946 // try to use path of the associated sample as default one.
947 if ( m_nSelectedLayer > 0 &&
948 m_pInstrument != nullptr ) {
949 auto pComponent = m_pInstrument->get_component( m_nSelectedComponent );
950
951 if ( pComponent != nullptr ) {
952 auto pLayer = pComponent->get_layer( m_nSelectedLayer );
953
954 if ( pLayer != nullptr ) {
955 auto pSample = pLayer->get_sample();
956
957 if ( pSample != nullptr ) {
958 if ( ! pSample->get_filepath().isEmpty() ) {
959 QFileInfo fileInfo( pSample->get_filepath() );
960 sPath = fileInfo.absoluteDir().absolutePath();
961 sFilename = fileInfo.absoluteFilePath();
962 }
963 }
964 }
965 }
966 }
967
968
969
970 AudioFileBrowser *pFileBrowser =
971 new AudioFileBrowser( nullptr, true, true, sPath, sFilename );
972 QStringList filename;
973 filename << "false" << "false" << "";
974
975 if (pFileBrowser->exec() == QDialog::Accepted) {
976 filename = pFileBrowser->getSelectedFiles();
977
978 // Only overwrite the default directory if we didn't start
979 // from an existing file or the final directory differs from
980 // the starting one.
981 if ( sFilename.isEmpty() ||
982 sPath != pFileBrowser->getSelectedDirectory() ) {
984 }
985 }
986
987 delete pFileBrowser;
988
989 if ( filename[2].isEmpty() ) {
990 return;
991 }
992
993 bool fnc = false;
994 if ( filename[0] == "true" ){
995 fnc = true;
996 }
997
998 int selectedLayer = m_nSelectedLayer;
999 int firstSelection = selectedLayer;
1000
1001 // Ensure instrument pointer is current
1002 m_pInstrument = pHydrogen->getSelectedInstrument();
1003 if ( m_pInstrument == nullptr ) {
1004 WARNINGLOG( "No instrument selected" );
1005 return;
1006 }
1007
1008 if (filename.size() > 2) {
1009
1010 for ( int i=2; i < filename.size(); ++i )
1011 {
1012 selectedLayer = m_nSelectedLayer + i - 2;
1013 if ( ( i-2 >= InstrumentComponent::getMaxLayers() ) ||
1014 ( selectedLayer + 1 > InstrumentComponent::getMaxLayers() ) ) {
1015 break;
1016 }
1017
1018 auto pNewSample = Sample::load( filename[i] );
1019
1020 pHydrogen->getAudioEngine()->lock( RIGHT_HERE );
1021
1022 /*
1023 if we're using multiple layers, we start inserting the first layer
1024 at m_nSelectedLayer and the next layer at m_nSelectedLayer+1
1025 */
1026
1027 auto pCompo = m_pInstrument->get_component(m_nSelectedComponent);
1028 if( !pCompo ) {
1029 pCompo = std::make_shared<InstrumentComponent>( m_nSelectedComponent );
1030 m_pInstrument->get_components()->push_back( pCompo );
1031 }
1032
1033 auto pLayer = pCompo->get_layer( selectedLayer );
1034
1035 if (pLayer != nullptr) {
1036 // insert new sample from newInstrument, old sample gets deleted by set_sample
1037 pLayer->set_sample( pNewSample );
1038 }
1039 else {
1040 pLayer = std::make_shared<H2Core::InstrumentLayer>( pNewSample );
1041 m_pInstrument->get_component(m_nSelectedComponent)->set_layer( pLayer, selectedLayer );
1042 }
1043
1044 if ( fnc ){
1045 QString newFilename = filename[i].section( '/', -1 );
1046 newFilename.replace( "." + newFilename.section( '.', -1 ), "");
1047 m_pInstrument->set_name( newFilename );
1048 }
1049
1050 //set automatic velocity
1051 if ( filename[1] == "true" ){
1053 }
1054
1055 pHydrogen->getAudioEngine()->unlock();
1056 }
1057
1058 pHydrogen->setIsModified( true );
1059 }
1060
1061 selectedInstrumentChangedEvent(); // update all
1062 selectLayer( firstSelection );
1063 m_pLayerPreview->updateAll();
1064}
1065
1066
1068{
1069 if ( m_pInstrument == nullptr ) {
1070 return;
1071 }
1072 auto pCompo = m_pInstrument->get_component( m_nSelectedComponent );
1073 if ( pCompo == nullptr ) {
1074 return;
1075 }
1076
1077 int nLayers = 0;
1078 for ( int i = 0; i < InstrumentComponent::getMaxLayers() ; i++ ) {
1079
1080 auto pLayer = pCompo->get_layer( i );
1081 if ( pLayer != nullptr ) {
1082 nLayers++;
1083 }
1084 }
1085
1086 if( nLayers == 0 ){
1087 nLayers = 1;
1088 }
1089
1090 float velocityrange = 1.0 / nLayers;
1091
1092 int nLayer = 0;
1093 for ( int i = 0; i < InstrumentComponent::getMaxLayers() ; i++ ) {
1094 auto pLayer = pCompo->get_layer( i );
1095 if ( pLayer != nullptr ) {
1096 pLayer->set_start_velocity( nLayer * velocityrange);
1097 pLayer->set_end_velocity( nLayer * velocityrange + velocityrange );
1098
1099 ++nLayer;
1100 }
1101 }
1102}
1103
1105{
1106 UNUSED( pRef );
1107 std::shared_ptr<Song> pSong = Hydrogen::get_instance()->getSong();
1108 if ( pSong == nullptr ) {
1109 return;
1110 }
1111 auto pComponent = pSong->getComponent( m_nSelectedComponent );
1112 if ( pComponent == nullptr ) {
1113 return;
1114 }
1115 QString sOldName = pComponent->get_name();
1116 bool bIsOkPressed;
1117 QString sNewName = QInputDialog::getText( this, "Hydrogen", tr( "New component name" ), QLineEdit::Normal, sOldName, &bIsOkPressed );
1118
1119 if ( bIsOkPressed && sOldName != sNewName ) {
1120 pComponent->set_name( sNewName );
1121
1123
1124 // this will force an update...
1126 }
1127}
1128
1130{
1131 if (!m_pInstrument) {
1132 return;
1133 }
1134
1135 m_nSelectedComponent = nComponent;
1136 m_pLayerPreview->set_selected_component(m_nSelectedComponent);
1137}
1138
1140{
1141 UNUSED( pRef );
1142
1143 if (m_pInstrument) {
1144 QString sOldName = m_pInstrument->get_name();
1145 bool bIsOkPressed;
1146 QString sNewName = QInputDialog::getText( this, "Hydrogen", tr( "New instrument name" ), QLineEdit::Normal, sOldName, &bIsOkPressed );
1147
1148 if ( bIsOkPressed && sNewName != sOldName ) {
1149 auto pHydrogen = Hydrogen::get_instance();
1150
1151 m_pInstrument->set_name( sNewName );
1153
1154 pHydrogen->setIsModified( true );
1155
1156#ifdef H2CORE_HAVE_JACK
1157 pHydrogen->getAudioEngine()->lock( RIGHT_HERE );
1158 pHydrogen->renameJackPorts( pHydrogen->getSong() );
1159 pHydrogen->getAudioEngine()->unlock();
1160#endif
1161
1162 // this will force an update...
1164 }
1165 else {
1166 // user entered nothing or pressed Cancel
1167 }
1168 }
1169}
1170
1171
1173{
1174 if (!m_pInstrument) {
1175 return;
1176 }
1177 m_nSelectedLayer = nLayer;
1178
1179 auto pComponent = m_pInstrument->get_component( m_nSelectedComponent );
1180 if(pComponent && nLayer >= 0 ){
1181 auto pLayer = pComponent->get_layer( nLayer );
1182 m_pWaveDisplay->updateDisplay( pLayer );
1183 if ( pLayer != nullptr ) {
1184 char tmp[20];
1185
1186 // Layer GAIN
1187 m_pLayerGainRotary->setIsActive( true );
1188 m_pLayerGainRotary->setValue( pLayer->get_gain() );
1189 sprintf( tmp, "%#.2f", pLayer->get_gain() );
1190 m_pLayerGainLCD->setText( tmp );
1191
1192 //Component GAIN
1193 char tmp2[20];
1194 sprintf( tmp2, "%#.2f", pComponent->get_gain());
1195 m_pCompoGainRotary->setIsActive( true );
1196 m_pCompoGainRotary->setValue( pComponent->get_gain());
1197 m_pCompoGainLCD->setText( tmp2 );
1198
1199 // Layer PITCH
1200 float fCoarsePitch = round( pLayer->get_pitch() );
1201 float fFinePitch = pLayer->get_pitch() - fCoarsePitch;
1202 m_pLayerPitchCoarseRotary->setIsActive( true );
1203 m_pLayerPitchCoarseRotary->setValue( fCoarsePitch );
1204 m_pLayerPitchFineRotary->setIsActive( true );
1205 m_pLayerPitchFineRotary->setValue( fFinePitch * 100 );
1206
1207 m_pLayerPitchCoarseLCD->setText( QString( "%1" ).arg( (int) fCoarsePitch ) );
1208 m_pLayerPitchFineLCD->setText( QString( "%1" )
1209 .arg( fFinePitch * 100, 0, 'f', 0 ) );
1210
1211 m_pRemoveLayerBtn->setIsActive( true );
1212 m_pSampleEditorBtn->setIsActive( true );
1213 }
1214 else {
1215 // Layer GAIN
1216 m_pLayerGainRotary->setIsActive( false );
1217 m_pLayerGainRotary->setValue( 1.0 );
1218 m_pLayerGainLCD->setText( "" );
1219
1220 //Component GAIN
1221 m_pCompoGainRotary->setIsActive( false );
1222 m_pCompoGainRotary->setValue( 1.0 );
1223 m_pCompoGainLCD->setText( "" );
1224
1225 // Layer PITCH
1226 m_pLayerPitchCoarseRotary->setIsActive( false );
1227 m_pLayerPitchCoarseRotary->setValue( 0.0 );
1228 m_pLayerPitchFineRotary->setIsActive( false );
1229 m_pLayerPitchFineRotary->setValue( 0.0 );
1230
1231 m_pLayerPitchCoarseLCD->setText( "" );
1232 m_pLayerPitchFineLCD->setText( "" );
1233
1234 m_pRemoveLayerBtn->setIsActive( false );
1235 m_pSampleEditorBtn->setIsActive( false );
1236 }
1237 }
1238 else {
1239 m_pWaveDisplay->updateDisplay( nullptr );
1240
1241 // Layer GAIN
1242 m_pLayerGainRotary->setIsActive( false );
1243 m_pLayerGainRotary->setValue( 1.0 );
1244 m_pLayerGainLCD->setText( "" );
1245
1246 m_pCompoGainRotary->setIsActive( false );
1247 m_pCompoGainRotary->setValue( 1.0 );
1248 m_pCompoGainLCD->setText( "" );
1249
1250 // Layer PITCH
1251 m_pLayerPitchCoarseRotary->setIsActive( false );
1252 m_pLayerPitchCoarseRotary->setValue( 0.0 );
1253 m_pLayerPitchFineRotary->setIsActive( false );
1254 m_pLayerPitchFineRotary->setValue( 0.0 );
1255
1256 m_pLayerPitchCoarseLCD->setText( "" );
1257 m_pLayerPitchFineLCD->setText( "" );
1258
1259 m_pRemoveLayerBtn->setIsActive( false );
1260 m_pSampleEditorBtn->setIsActive( false );
1261 }
1262}
1263
1264
1265
1267{
1268 assert( m_pInstrument );
1269
1270 m_pInstrument->set_mute_group( static_cast<int>(fValue) );
1271 selectedInstrumentChangedEvent(); // force an update
1272}
1273
1275{
1276 m_pInstrument->set_stop_notes( on );
1278 selectedInstrumentChangedEvent(); // force an update
1279}
1280
1282{
1283 assert( m_pInstrument );
1284
1285 m_pInstrument->set_apply_velocity( on );
1287 selectedInstrumentChangedEvent(); // force an update
1288}
1289
1291 assert( m_pInstrument );
1292
1293 if ( fValue != 0.0 ) {
1294 m_pInstrument->set_midi_out_channel( std::max( static_cast<int>(fValue) - 1,
1295 -1 ) );
1296 } else {
1297 if ( m_fPreviousMidiOutChannel == -1.0 ) {
1298 m_pMidiOutChannelLCD->setValue( 1 );
1299 return;
1300 } else {
1301 m_pMidiOutChannelLCD->setValue( -1 );
1302 return;
1303 }
1304 }
1305
1307}
1308
1310 assert( m_pInstrument );
1311
1312 m_pInstrument->set_midi_out_note( static_cast<int>(fValue) );
1313}
1314
1316{
1317 popCompo->popup( m_pCompoNameLbl->mapToGlobal( QPoint( m_pCompoNameLbl->width() - 40, m_pCompoNameLbl->height() / 2 ) ) );
1318}
1319
1321{
1322 popCompo->clear();
1323
1324 for( int i = 0; i < itemsCompo.size(); i++ ) {
1325 if ( itemsCompo.at(i) != "--sep--" ){
1326 popCompo->addAction( itemsCompo.at(i) );
1327 }else{
1328 popCompo->addSeparator();
1329 }
1330 }
1331}
1332
1334{
1335 bool bFoundFreeSlot = true;
1336 auto pDrumkitComponentList = Hydrogen::get_instance()->getSong()->getComponents();
1337 for ( const auto& pComponent : *pDrumkitComponentList ) {
1338 if ( pComponent->get_id() == startingPoint ) {
1339 bFoundFreeSlot = false;
1340 break;
1341 }
1342 }
1343
1344 if(bFoundFreeSlot) {
1345 return startingPoint;
1346 } else {
1347 return findFreeDrumkitComponentId( startingPoint + 1 );
1348 }
1349}
1350
1352{
1353 QString sSelectedAction = pAction->text();
1354
1355 Hydrogen * pHydrogen = Hydrogen::get_instance();
1356
1357 if( sSelectedAction.compare("add") == 0 ) {
1358 if ( m_pInstrument ) {
1359 bool bIsOkPressed;
1360 QString sNewName = QInputDialog::getText( this, "Hydrogen", tr( "Component name" ), QLineEdit::Normal, "New Component", &bIsOkPressed );
1361 if ( bIsOkPressed ) {
1362 auto pDrumkitComponent = std::make_shared<DrumkitComponent>( findFreeDrumkitComponentId(), sNewName );
1363 pHydrogen->getSong()->getComponents()->push_back( pDrumkitComponent );
1364
1365 //auto instrument_component = std::make_shared<InstrumentComponent>( dm_component->get_id() );
1366 //instrument_component->set_gain( 1.0f );
1367 //m_pInstrument->get_components()->push_back( instrument_component );
1368
1369 m_nSelectedComponent = pDrumkitComponent->get_id();
1370 m_pLayerPreview->set_selected_component( pDrumkitComponent->get_id() );
1371
1373
1374 // this will force an update...
1376
1377#ifdef H2CORE_HAVE_JACK
1378 pHydrogen->renameJackPorts(pHydrogen->getSong());
1379#endif
1380 }
1381 else {
1382 // user entered nothing or pressed Cancel
1383 }
1384 }
1385 }
1386 else if( sSelectedAction.compare("delete") == 0 ) {
1387 auto pDrumkitComponents = pHydrogen->getSong()->getComponents();
1388
1389 if(pDrumkitComponents->size() == 1){
1390 ERRORLOG( "There is just a single component remaining. This one can not be deleted." );
1391 return;
1392 }
1393
1394 auto pDrumkitComponent = pHydrogen->getSong()->getComponent( m_nSelectedComponent );
1395
1396 auto pInstruments = pHydrogen->getSong()->getInstrumentList();
1397 for ( int n = ( int )pInstruments->size() - 1; n >= 0; n-- ) {
1398 auto pInstrument = pInstruments->get( n );
1399 for( int o = 0 ; o < pInstrument->get_components()->size() ; o++ ) {
1400 auto pInstrumentComponent = pInstrument->get_components()->at( o );
1401 if( pInstrumentComponent->get_drumkit_componentID() == pDrumkitComponent->get_id() ) {
1402 pInstrument->get_components()->erase( pInstrument->get_components()->begin() + o );;
1403 break;
1404 }
1405 }
1406 }
1407
1408 for ( int n = 0 ; n < pDrumkitComponents->size() ; n++ ) {
1409 auto pTmpDrumkitComponent = pDrumkitComponents->at( n );
1410 if( pTmpDrumkitComponent->get_id() == pDrumkitComponent->get_id() ) {
1411 pDrumkitComponents->erase( pDrumkitComponents->begin() + n );
1412 break;
1413 }
1414 }
1415
1416 m_nSelectedComponent = pDrumkitComponents->front()->get_id();
1417
1418
1420 // this will force an update...
1422 }
1423 else if( sSelectedAction.compare("rename") == 0 ) {
1424 labelCompoClicked( nullptr );
1425 }
1426 else {
1428 auto pDrumkitComponents = pHydrogen->getSong()->getComponents();
1429 for ( const auto& pComponent : *pDrumkitComponents ) {
1430 if ( pComponent->get_name().compare( sSelectedAction ) == 0) {
1431 m_nSelectedComponent = pComponent->get_id();
1432 m_pCompoNameLbl->setText( pComponent->get_name() );
1433 break;
1434 }
1435 }
1436
1437 if( m_pInstrument && !m_pInstrument->get_component(m_nSelectedComponent)) {
1438 INFOLOG("Component needs to be added");
1439
1440 auto pInstrComponent = std::make_shared<InstrumentComponent>( m_nSelectedComponent );
1441 pInstrComponent->set_gain( 1.0f );
1442
1443 m_pInstrument->get_components()->push_back( pInstrComponent );
1444
1445
1446
1447#ifdef H2CORE_HAVE_JACK
1448 pHydrogen->renameJackPorts(pHydrogen->getSong());
1449#endif
1450 }
1451
1452 m_pLayerPreview->set_selected_component(m_nSelectedComponent);
1453
1455
1456 // this will force an update...
1458 }
1459}
1460
1462{
1463 assert( m_pInstrument );
1464
1465 if ( selected == 0 ){
1466 m_pInstrument->set_sample_selection_alg( Instrument::VELOCITY );
1467 }
1468 else if ( selected == 1 ){
1469 m_pInstrument->set_sample_selection_alg( Instrument::ROUND_ROBIN );
1470 }
1471 else if ( selected == 2){
1472 m_pInstrument->set_sample_selection_alg( Instrument::RANDOM );
1473 }
1474
1475 selectedInstrumentChangedEvent(); // force an update
1476}
1477
1479{
1480 assert( m_pInstrument );
1481 m_pInstrument->set_hihat_grp( static_cast<int>(fValue) );
1482}
1483
1485{
1486 assert( m_pInstrument );
1487 m_pInstrument->set_lower_cc( static_cast<int>(fValue) );
1488 m_pHihatMaxRangeLCD->setMinimum( static_cast<int>(fValue) );
1489}
1490
1492{
1493 assert( m_pInstrument );
1494 m_pInstrument->set_higher_cc( static_cast<int>(fValue) );
1495 m_pHihatMinRangeLCD->setMaximum( static_cast<int>(fValue) );
1496}
1497
1499 auto pPref = H2Core::Preferences::get_instance();
1500
1501 if ( changes & H2Core::Preferences::Changes::Colors ) {
1502 setStyleSheet( QString( "QLabel { background: %1 }" )
1503 .arg( pPref->getColorTheme()->m_windowColor.name() ) );
1504 }
1505}
1506
1508 if ( bShow ) {
1509 m_pInstrumentProp->hide();
1510 m_pShowInstrumentBtn->setChecked( false );
1511 m_pLayerProp->show();
1512 m_pShowLayersBtn->setChecked( true );
1513 }
1514 else {
1515 m_pInstrumentProp->show();
1516 m_pShowInstrumentBtn->setChecked( true );
1517 m_pLayerProp->hide();
1518 m_pShowLayersBtn->setChecked( false );
1519 }
1520}
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
Definition AudioEngine.h:61
#define INFOLOG(x)
Definition Object.h:240
#define WARNINGLOG(x)
Definition Object.h:241
#define ERRORLOG(x)
Definition Object.h:242
This dialog is used to preview audiofiles.
QStringList getSelectedFiles()
Generic Button with SVG icons or text.
Definition Button.h:60
@ Push
Button is not set checkable.
Definition Button.h:68
@ Toggle
Button is set checkable.
Definition Button.h:70
Custom QLabel that emits a signal when clicked.
void unlock()
Mutex unlocking of the AudioEngine.
void lock(const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
static EventQueue * get_instance()
Returns a pointer to the current EventQueue singleton stored in __instance.
Definition EventQueue.h:224
void push_event(const EventType type, const int nValue)
Queues the next event into the EventQueue.
static bool dir_readable(const QString &path, bool silent=false)
returns true if the given path is a readable regular directory
Hydrogen Audio Engine.
Definition Hydrogen.h:54
void renameJackPorts(std::shared_ptr< Song > pSong)
Calls audioEngine_renameJackPorts() if Preferences::m_bJackTrackOuts is set to true.
Definition Hydrogen.cpp:957
std::shared_ptr< Song > getSong() const
Get the current song.
Definition Hydrogen.h:123
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:84
AudioEngine * getAudioEngine() const
Definition Hydrogen.h:663
std::shared_ptr< Instrument > getSelectedInstrument() const
void setIsModified(bool bIsModified)
Wrapper around Song::setIsModified() that checks whether a song is set.
CoreActionController * getCoreActionController() const
Definition Hydrogen.h:653
static constexpr float fPitchMin
Minimum support pitch value.
Definition Instrument.h:322
static constexpr float fPitchMax
Maximum support pitch value.
Definition Instrument.h:320
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
void setLastOpenLayerDirectory(QString sPath)
Changes
Bitwise or-able options showing which part of the Preferences were altered using the PreferencesDialo...
@ Colors
At least one of the colors has changed.
QString getLastOpenLayerDirectory() const
static std::shared_ptr< Sample > load(const QString &filepath, const License &license=License())
Definition Sample.cpp:136
void addEventListener(EventListener *pListener)
static HydrogenApp * get_instance()
Returns the instance of HydrogenApp class.
std::shared_ptr< CommonStrings > getCommonStrings()
void preferencesChanged(H2Core::Preferences::Changes changes)
Propagates a change in the Preferences through the GUI.
void showSampleEditor(QString name, int mSelectedComponemt, int mSelectedLayer)
static InstrumentEditorPanel * get_instance()
Rotary * m_pRandomPitchRotary
void labelCompoClicked(ClickableLabel *pRef)
ClickableLabel * m_pLayerPitchLbl
PixmapWidget * m_pInstrumentPropTop
LCDSpinBox * m_pMidiOutNoteLCD
Rotary * m_pPitchCoarseRotary
LCDDisplay * m_pInstrumentGainLCD
LCDSpinBox * m_pHihatMaxRangeLCD
void selectLayer(int nLayer)
ClickableLabel * m_pGainLbl
ClickableLabel * m_pMidiOutNoteLbl
Button * m_buttonDropDownCompo
ClickableLabel * m_pLayerGainLbl
void showLayers(bool bShow)
Used by #Shotlist.
ClickableLabel * m_pPitchFineLbl
ClickableLabel * m_pMuteGroupLbl
ClickableLabel * m_pCompoNameLbl
void hihatGroupChanged(double fValue)
ClickableLabel * m_pReleaseLbl
double m_fPreviousMidiOutChannel
In order to allow for enumerations starting at 1 while using -1 to turn off the LCD.
LCDDisplay * m_pLayerPitchFineLCD
ClickableLabel * m_pHihatGroupLbl
void labelClicked(ClickableLabel *pRef)
ClickableLabel * m_pNameLbl
PixmapWidget * m_pInstrumentProp
void muteGroupChanged(double fValue)
ClickableLabel * m_pCutoffLbl
ClickableLabel * m_pDecayLbl
void onPreferencesChanged(H2Core::Preferences::Changes changes)
void onIsApplyVelocityCheckBoxClicked(bool on)
void onIsStopNoteCheckBoxClicked(bool on)
ClickableLabel * m_pAttackLbl
void selectComponent(int nComponent)
QCheckBox * m_pApplyVelocity
void compoChangeAddDelete(QAction *)
ClickableLabel * m_pHihatMinRangeLbl
virtual void drumkitLoadedEvent() override
virtual void instrumentParametersChangedEvent(int) override
ClickableLabel * m_pCompoGainLbl
ClickableLabel * m_pLayerPitchFineLbl
LCDDisplay * m_pLayerPitchCoarseLCD
Rotary * m_pLayerPitchCoarseRotary
ClickableLabel * m_pIsStopNoteLbl
Button * m_pShowInstrumentBtn
ClickableLabel * m_pResonanceLbl
PixmapWidget * m_pLayerProp
ClickableLabel * m_pPitchCoarseLbl
WaveDisplay * m_pWaveDisplay
ClickableLabel * m_pApplyVelocityLbl
ClickableLabel * m_pLayerPitchCoarseLbl
virtual void selectedInstrumentChangedEvent() override
ClickableLabel * m_pSustainLbl
virtual void updateSongEvent(int) override
ClickableLabel * m_pHihatMaxRangeLbl
LCDSpinBox * m_pMidiOutChannelLCD
void hihatMinRangeChanged(double fValue)
LayerPreview * m_pLayerPreview
Rotary * m_pLayerPitchFineRotary
static int findFreeDrumkitComponentId(int startingPoint=0)
InstrumentEditor(QWidget *parent)
LCDSpinBox * m_pMuteGroupLCD
LCDDisplay * m_pLayerGainLCD
void hihatMaxRangeChanged(double fValue)
LCDCombo * m_sampleSelectionAlg
LCDDisplay * m_pCompoGainLCD
void rotaryChanged(WidgetWithInput *ref)
ClickableLabel * m_pPitchLbl
LCDSpinBox * m_pHihatMinRangeLCD
std::shared_ptr< H2Core::Instrument > m_pInstrument
QScrollArea * m_pLayerScrollArea
LCDSpinBox * m_pHihatGroupLCD
void midiOutNoteChanged(double fValue)
void waveDisplayDoubleClicked(QWidget *pRef)
void midiOutChannelChanged(double fValue)
QCheckBox * m_pIsStopNoteCheckBox
ClickableLabel * m_pMidiOutChannelLbl
ClickableLabel * m_pSampleSelectionLbl
ClickableLabel * m_pPitchRandomLbl
LCDDisplay * m_pPitchLCD
Non-interactive display used for both numerical values and the status display.
Definition LCDDisplay.h:40
Custom spin box.
Definition LCDSpinBox.h:50
Custom rotary widget.
Definition Rotary.h:45
@ Center
The arc features a point at its upmost position.
Definition Rotary.h:55
@ Normal
The arc is of solid red color.
Definition Rotary.h:51
Base class for active user input widget, which are not based on a high-level Qt widget.
float getValue() const
#define UNUSED(v)
Definition Globals.h:42
@ EVENT_SELECTED_INSTRUMENT_CHANGED
Definition EventQueue.h:77