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 #include <QObject>
23
24 #include <hydrogen/audio_engine.h>
25 #include <hydrogen/event_queue.h>
26 #include <hydrogen/hydrogen.h>
27
28 #include <hydrogen/basics/instrument.h>
29 #include <hydrogen/basics/instrument_component.h>
30 #include <hydrogen/basics/instrument_layer.h>
31 #include <hydrogen/basics/instrument_list.h>
32 #include <hydrogen/basics/playlist.h>
33 #include <hydrogen/basics/song.h>
34 #include <hydrogen/basics/pattern_list.h>
35
36 #include <hydrogen/Preferences.h>
37 #include <hydrogen/midi_action.h>
38
39 #include <hydrogen/basics/drumkit.h>
40
41 // #include <QFileInfo>
42
43 #include <sstream>
44
45 using namespace H2Core;
46
47 /**
48 * @class MidiAction
49 *
50 * @brief This class represents a midi action.
51 *
52 * This class represents actions which can be executed
53 * after a midi event occurred. An example is the "MUTE"
54 * action, which mutes the outputs of hydrogen.
55 *
56 * An action can be linked to an event. If this event occurs,
57 * the action gets triggered. The handling of events takes place
58 * in midi_input.cpp .
59 *
60 * Each action has two independent parameters. The two parameters are optional and
61 * can be used to carry additional information, which mean
62 * only something to this very Action. They can have totally different meanings for other Actions.
63 * Example: parameter1 is the Mixer strip and parameter 2 a multiplier for the volume change on this strip
64 *
65 * @author Sebastian Moors
66 *
67 */
68
69 const char* Action::__class_name = "MidiAction";
70
Action(QString typeString)71 Action::Action( QString typeString ) : Object( __class_name ) {
72 type = typeString;
73 QString parameter1 = "0";
74 QString parameter2 = "0" ;
75 }
76
77 /**
78 * @class MidiActionManager
79 *
80 * @brief The MidiActionManager cares for the execution of MidiActions
81 *
82 *
83 * The MidiActionManager handles the execution of midi actions. The class
84 * includes the names and implementations of all possible actions.
85 *
86 *
87 * @author Sebastian Moors
88 *
89 */
90 MidiActionManager* MidiActionManager::__instance = nullptr;
91 const char* MidiActionManager::__class_name = "ActionManager";
92
MidiActionManager()93 MidiActionManager::MidiActionManager() : Object( __class_name ) {
94 __instance = this;
95
96 m_nLastBpmChangeCCParameter = -1;
97 /*
98 the actionMap holds all Action identifiers which hydrogen is able to interpret.
99 it holds pointer to member function
100 */
101 targeted_element empty = {0,0};
102 actionMap.insert(make_pair("PLAY", make_pair(&MidiActionManager::play, empty)));
103 actionMap.insert(make_pair("PLAY/STOP_TOGGLE", make_pair(&MidiActionManager::play_stop_pause_toggle, empty)));
104 actionMap.insert(make_pair("PLAY/PAUSE_TOGGLE", make_pair(&MidiActionManager::play_stop_pause_toggle, empty)));
105 actionMap.insert(make_pair("STOP", make_pair(&MidiActionManager::stop, empty)));
106 actionMap.insert(make_pair("PAUSE", make_pair(&MidiActionManager::pause, empty)));
107 actionMap.insert(make_pair("RECORD_READY", make_pair(&MidiActionManager::record_ready, empty)));
108 actionMap.insert(make_pair("RECORD/STROBE_TOGGLE", make_pair(&MidiActionManager::record_strobe_toggle, empty)));
109 actionMap.insert(make_pair("RECORD_STROBE", make_pair(&MidiActionManager::record_strobe, empty)));
110 actionMap.insert(make_pair("RECORD_EXIT", make_pair(&MidiActionManager::record_exit, empty)));
111 actionMap.insert(make_pair("MUTE", make_pair(&MidiActionManager::mute, empty)));
112 actionMap.insert(make_pair("UNMUTE", make_pair(&MidiActionManager::unmute, empty)));
113 actionMap.insert(make_pair("MUTE_TOGGLE", make_pair(&MidiActionManager::mute_toggle, empty)));
114 actionMap.insert(make_pair("STRIP_MUTE_TOGGLE", make_pair(&MidiActionManager::strip_mute_toggle, empty)));
115 actionMap.insert(make_pair("STRIP_SOLO_TOGGLE", make_pair(&MidiActionManager::strip_solo_toggle, empty)));
116 actionMap.insert(make_pair(">>_NEXT_BAR", make_pair(&MidiActionManager::next_bar, empty)));
117 actionMap.insert(make_pair("<<_PREVIOUS_BAR", make_pair(&MidiActionManager::previous_bar, empty)));
118 actionMap.insert(make_pair("BPM_INCR", make_pair(&MidiActionManager::bpm_increase, empty)));
119 actionMap.insert(make_pair("BPM_DECR", make_pair(&MidiActionManager::bpm_decrease, empty)));
120 actionMap.insert(make_pair("BPM_CC_RELATIVE", make_pair(&MidiActionManager::bpm_cc_relative, empty)));
121 actionMap.insert(make_pair("BPM_FINE_CC_RELATIVE", make_pair(&MidiActionManager::bpm_fine_cc_relative, empty)));
122 actionMap.insert(make_pair("MASTER_VOLUME_RELATIVE", make_pair(&MidiActionManager::master_volume_relative, empty)));
123 actionMap.insert(make_pair("MASTER_VOLUME_ABSOLUTE", make_pair(&MidiActionManager::master_volume_absolute, empty)));
124 actionMap.insert(make_pair("STRIP_VOLUME_RELATIVE", make_pair(&MidiActionManager::strip_volume_relative, empty)));
125 actionMap.insert(make_pair("STRIP_VOLUME_ABSOLUTE", make_pair(&MidiActionManager::strip_volume_absolute, empty)));
126
127 for(int i = 0; i < MAX_FX; ++i) {
128 targeted_element effect = {i,0};
129 ostringstream toChar;
130 toChar << (i+1);
131 string keyAbsolute("EFFECT");
132 string keyRelative("EFFECT");
133 keyAbsolute += toChar.str();
134 keyRelative += toChar.str();
135 keyAbsolute += "_LEVEL_ABSOLUTE";
136 keyRelative += "_LEVEL_RELATIVE";
137 actionMap.insert(make_pair(keyAbsolute, make_pair(&MidiActionManager::effect_level_absolute, effect)));
138 actionMap.insert(make_pair(keyRelative, make_pair(&MidiActionManager::effect_level_relative, effect)));
139 }
140 for(int i = 0; i < MAX_COMPONENTS; ++i) {
141 ostringstream componentToChar;
142 componentToChar << (i+1);
143 for(int j = 0; j < InstrumentComponent::getMaxLayers(); ++j ) {
144 targeted_element sample = {i,j};
145 ostringstream toChar;
146 toChar << (j+1);
147 string keyGain("GAIN_C");
148 string keyPitch("PITCH_C");
149 keyGain += componentToChar.str();
150 keyPitch += componentToChar.str();
151 keyGain += "_L";
152 keyPitch += "_L";
153 keyGain += toChar.str();
154 keyPitch += toChar.str();
155 keyGain += "_LEVEL_ABSOLUTE";
156 keyPitch += "_LEVEL_ABSOLUTE";
157 actionMap.insert(make_pair(keyGain, make_pair(&MidiActionManager::gain_level_absolute, sample)));
158 actionMap.insert(make_pair(keyPitch, make_pair(&MidiActionManager::pitch_level_absolute, sample)));
159 }
160 }
161 actionMap.insert(make_pair("SELECT_NEXT_PATTERN", make_pair(&MidiActionManager::select_next_pattern, empty)));
162 actionMap.insert(make_pair("SELECT_ONLY_NEXT_PATTERN", make_pair(&MidiActionManager::select_only_next_pattern, empty)));
163 actionMap.insert(make_pair("SELECT_NEXT_PATTERN_CC_ABSOLUTE", make_pair(&MidiActionManager::select_next_pattern_cc_absolute, empty)));
164 actionMap.insert(make_pair("SELECT_NEXT_PATTERN_PROMPTLY", make_pair(&MidiActionManager::select_next_pattern_promptly, empty)));
165 actionMap.insert(make_pair("SELECT_NEXT_PATTERN_RELATIVE", make_pair(&MidiActionManager::select_next_pattern_relative, empty)));
166 actionMap.insert(make_pair("SELECT_AND_PLAY_PATTERN", make_pair(&MidiActionManager::select_and_play_pattern, empty)));
167 actionMap.insert(make_pair("PAN_RELATIVE", make_pair(&MidiActionManager::pan_relative, empty)));
168 actionMap.insert(make_pair("PAN_ABSOLUTE", make_pair(&MidiActionManager::pan_absolute, empty)));
169 actionMap.insert(make_pair("FILTER_CUTOFF_LEVEL_ABSOLUTE", make_pair(&MidiActionManager::filter_cutoff_level_absolute, empty)));
170 actionMap.insert(make_pair("BEATCOUNTER", make_pair(&MidiActionManager::beatcounter, empty)));
171 actionMap.insert(make_pair("TAP_TEMPO", make_pair(&MidiActionManager::tap_tempo, empty)));
172 actionMap.insert(make_pair("PLAYLIST_SONG", make_pair(&MidiActionManager::playlist_song, empty)));
173 actionMap.insert(make_pair("PLAYLIST_NEXT_SONG", make_pair(&MidiActionManager::playlist_next_song, empty)));
174 actionMap.insert(make_pair("PLAYLIST_PREV_SONG", make_pair(&MidiActionManager::playlist_previous_song, empty)));
175 actionMap.insert(make_pair("TOGGLE_METRONOME", make_pair(&MidiActionManager::toggle_metronome, empty)));
176 actionMap.insert(make_pair("SELECT_INSTRUMENT", make_pair(&MidiActionManager::select_instrument, empty)));
177 actionMap.insert(make_pair("UNDO_ACTION", make_pair(&MidiActionManager::undo_action, empty)));
178 actionMap.insert(make_pair("REDO_ACTION", make_pair(&MidiActionManager::redo_action, empty)));
179 /*
180 the actionList holds all Action identfiers which hydrogen is able to interpret.
181 */
182 actionList <<"";
183 for(map<string, pair<action_f, targeted_element> >::const_iterator actionIterator = actionMap.begin();
184 actionIterator != actionMap.end();
185 ++actionIterator) {
186 actionList << actionIterator->first.c_str();
187 }
188
189 eventList << ""
190 << "MMC_PLAY"
191 << "MMC_DEFERRED_PLAY"
192 << "MMC_STOP"
193 << "MMC_FAST_FORWARD"
194 << "MMC_REWIND"
195 << "MMC_RECORD_STROBE"
196 << "MMC_RECORD_EXIT"
197 << "MMC_RECORD_READY"
198 << "MMC_PAUSE"
199 << "NOTE"
200 << "CC"
201 << "PROGRAM_CHANGE";
202 }
203
204
~MidiActionManager()205 MidiActionManager::~MidiActionManager() {
206 //INFOLOG( "ActionManager delete" );
207 __instance = nullptr;
208 }
209
create_instance()210 void MidiActionManager::create_instance() {
211 if ( __instance == nullptr ) {
212 __instance = new MidiActionManager;
213 }
214 }
215
play(Action *,Hydrogen * pEngine,targeted_element)216 bool MidiActionManager::play(Action * , Hydrogen* pEngine, targeted_element ) {
217 int nState = pEngine->getState();
218 if ( nState == STATE_READY ) {
219 pEngine->sequencer_play();
220 }
221 return true;
222 }
223
pause(Action *,Hydrogen * pEngine,targeted_element)224 bool MidiActionManager::pause(Action * , Hydrogen* pEngine, targeted_element ) {
225 pEngine->sequencer_stop();
226 return true;
227 }
228
stop(Action *,Hydrogen * pEngine,targeted_element)229 bool MidiActionManager::stop(Action * , Hydrogen* pEngine, targeted_element ) {
230 pEngine->sequencer_stop();
231 pEngine->setPatternPos( 0 );
232 pEngine->setTimelineBpm();
233 return true;
234 }
235
play_stop_pause_toggle(Action * pAction,Hydrogen * pEngine,targeted_element)236 bool MidiActionManager::play_stop_pause_toggle(Action * pAction, Hydrogen* pEngine, targeted_element ) {
237 QString sActionString = pAction->getType();
238 int nState = pEngine->getState();
239 switch ( nState )
240 {
241 case STATE_READY:
242 pEngine->sequencer_play();
243 break;
244
245 case STATE_PLAYING:
246 if( sActionString == "PLAY/STOP_TOGGLE" ) {
247 pEngine->setPatternPos( 0 );
248 }
249 pEngine->sequencer_stop();
250 pEngine->setTimelineBpm();
251 break;
252
253 default:
254 ERRORLOG( "[Hydrogen::ActionManager(PLAY): Unhandled case" );
255 break;
256 }
257
258 return true;
259 }
260
261 //mutes the master, not a single strip
mute(Action *,Hydrogen * pEngine,targeted_element)262 bool MidiActionManager::mute(Action * , Hydrogen* pEngine, targeted_element ) {
263 pEngine->getCoreActionController()->setMasterIsMuted( true );
264 return true;
265 }
266
unmute(Action *,Hydrogen * pEngine,targeted_element)267 bool MidiActionManager::unmute(Action * , Hydrogen* pEngine, targeted_element ) {
268 pEngine->getCoreActionController()->setMasterIsMuted( false );
269 return true;
270 }
271
mute_toggle(Action *,Hydrogen * pEngine,targeted_element)272 bool MidiActionManager::mute_toggle(Action * , Hydrogen* pEngine, targeted_element ) {
273 pEngine->getCoreActionController()->setMasterIsMuted( !Hydrogen::get_instance()->getSong()->__is_muted );
274 return true;
275 }
276
strip_mute_toggle(Action * pAction,Hydrogen * pEngine,targeted_element)277 bool MidiActionManager::strip_mute_toggle(Action * pAction, Hydrogen* pEngine, targeted_element ) {
278
279 bool ok;
280 bool bSucccess = true;
281
282 int nLine = pAction->getParameter1().toInt(&ok,10);
283
284 Song *pSong = pEngine->getSong();
285 InstrumentList *pInstrList = pSong->get_instrument_list();
286
287 if ( pInstrList->is_valid_index( nLine ) ) {
288 Instrument *pInstr = pInstrList->get( nLine );
289
290 if ( pInstr ) {
291 pEngine->getCoreActionController()->setStripIsMuted( nLine, !pInstr->is_muted() );
292 } else {
293 bSucccess = false;
294 }
295 } else {
296 bSucccess = false;
297 }
298
299 return bSucccess;
300 }
301
strip_solo_toggle(Action * pAction,Hydrogen * pEngine,targeted_element)302 bool MidiActionManager::strip_solo_toggle(Action * pAction, Hydrogen* pEngine, targeted_element ) {
303
304 bool ok;
305 bool bSucccess = true;
306
307 int nLine = pAction->getParameter1().toInt(&ok,10);
308
309 Song *pSong = pEngine->getSong();
310 InstrumentList *pInstrList = pSong->get_instrument_list();
311
312 if ( pInstrList->is_valid_index( nLine ) ) {
313 Instrument *pInstr = pInstrList->get( nLine );
314
315 if ( pInstr ) {
316 pEngine->getCoreActionController()->setStripIsSoloed( nLine, !pInstr->is_soloed() );
317 } else {
318 bSucccess = false;
319 }
320 } else {
321 bSucccess = false;
322 }
323
324 return bSucccess;
325 }
326
beatcounter(Action *,Hydrogen * pEngine,targeted_element)327 bool MidiActionManager::beatcounter(Action * , Hydrogen* pEngine, targeted_element ) {
328 pEngine->handleBeatCounter();
329 return true;
330 }
331
tap_tempo(Action *,Hydrogen * pEngine,targeted_element)332 bool MidiActionManager::tap_tempo(Action * , Hydrogen* pEngine, targeted_element ) {
333 pEngine->onTapTempoAccelEvent();
334 return true;
335 }
336
select_next_pattern(Action * pAction,Hydrogen * pEngine,targeted_element)337 bool MidiActionManager::select_next_pattern(Action * pAction, Hydrogen* pEngine, targeted_element ) {
338 bool ok;
339 int row = pAction->getParameter1().toInt(&ok,10);
340 if( row > pEngine->getSong()->get_pattern_list()->size() -1 ) {
341 return false;
342 }
343 if(Preferences::get_instance()->patternModePlaysSelected()) {
344 pEngine->setSelectedPatternNumber( row );
345 }
346 else {
347 pEngine->sequencer_setNextPattern( row );
348 }
349 return true;
350 }
351
select_only_next_pattern(Action * pAction,Hydrogen * pEngine,targeted_element)352 bool MidiActionManager::select_only_next_pattern(Action * pAction, Hydrogen* pEngine, targeted_element ) {
353 bool ok;
354 int row = pAction->getParameter1().toInt(&ok,10);
355 if( row > pEngine->getSong()->get_pattern_list()->size() -1 ) {
356 return false;
357 }
358 if(Preferences::get_instance()->patternModePlaysSelected())
359 {
360 return true;
361 }
362
363 pEngine->sequencer_setOnlyNextPattern( row );
364 return true;
365 }
366
select_next_pattern_relative(Action * pAction,Hydrogen * pEngine,targeted_element)367 bool MidiActionManager::select_next_pattern_relative(Action * pAction, Hydrogen* pEngine, targeted_element ) {
368 bool ok;
369 if(!Preferences::get_instance()->patternModePlaysSelected()) {
370 return true;
371 }
372 int row = pEngine->getSelectedPatternNumber() + pAction->getParameter1().toInt(&ok,10);
373 if( row > pEngine->getSong()->get_pattern_list()->size() -1 ) {
374 return false;
375 }
376
377 pEngine->setSelectedPatternNumber( row );
378 return true;
379 }
380
select_next_pattern_cc_absolute(Action * pAction,Hydrogen * pEngine,targeted_element)381 bool MidiActionManager::select_next_pattern_cc_absolute(Action * pAction, Hydrogen* pEngine, targeted_element ) {
382 bool ok;
383 int row = pAction->getParameter2().toInt(&ok,10);
384
385 if( row > pEngine->getSong()->get_pattern_list()->size() -1 ) {
386 return false;
387 }
388
389 if(Preferences::get_instance()->patternModePlaysSelected()) {
390 pEngine->setSelectedPatternNumber( row );
391 }
392 else {
393 return true;// only usefully in normal pattern mode
394 }
395
396 return true;
397 }
398
399 // obsolete, use SELECT_NEXT_PATTERN_CC_ABSOLUT instead
select_next_pattern_promptly(Action * pAction,Hydrogen * pEngine,targeted_element)400 bool MidiActionManager::select_next_pattern_promptly(Action * pAction, Hydrogen* pEngine, targeted_element ) {
401 bool ok;
402 int row = pAction->getParameter2().toInt(&ok,10);
403 pEngine->setSelectedPatternNumberWithoutGuiEvent( row );
404
405 return true;
406 }
407
select_and_play_pattern(Action * pAction,Hydrogen * pEngine,targeted_element)408 bool MidiActionManager::select_and_play_pattern(Action * pAction, Hydrogen* pEngine, targeted_element ) {
409 bool ok;
410 int row = pAction->getParameter1().toInt(&ok,10);
411 pEngine->setSelectedPatternNumber( row );
412 pEngine->sequencer_setNextPattern( row );
413
414 int nState = pEngine->getState();
415 if ( nState == STATE_READY ) {
416 pEngine->sequencer_play();
417 }
418
419 return true;
420 }
421
select_instrument(Action * pAction,Hydrogen * pEngine,targeted_element)422 bool MidiActionManager::select_instrument(Action * pAction, Hydrogen* pEngine, targeted_element ) {
423 bool ok;
424 int instrument_number = pAction->getParameter2().toInt(&ok,10) ;
425
426 if ( pEngine->getSong()->get_instrument_list()->size() < instrument_number ) {
427 instrument_number = pEngine->getSong()->get_instrument_list()->size() -1;
428 }
429
430 pEngine->setSelectedInstrumentNumber( instrument_number );
431 return true;
432 }
433
effect_level_absolute(Action * pAction,Hydrogen * pEngine,targeted_element nEffect)434 bool MidiActionManager::effect_level_absolute(Action * pAction, Hydrogen* pEngine, targeted_element nEffect) {
435 bool ok;
436 bool bSuccess = true;
437 int nLine = pAction->getParameter1().toInt(&ok,10);
438 int fx_param = pAction->getParameter2().toInt(&ok,10);
439
440 Song *pSong = pEngine->getSong();
441 InstrumentList *pInstrList = pSong->get_instrument_list();
442
443 if ( pInstrList->is_valid_index( nLine) )
444 {
445 Instrument *pInstr = pInstrList->get( nLine );
446
447 if ( pInstr ) {
448 if( fx_param != 0 ) {
449 pInstr->set_fx_level( ( (float) (fx_param / 127.0 ) ), nEffect._id );
450 } else {
451 pInstr->set_fx_level( 0 , nEffect._id );
452 }
453
454 pEngine->setSelectedInstrumentNumber( nLine );
455 } else {
456 bSuccess = false;
457 }
458
459 }
460
461 return bSuccess;
462 }
463
effect_level_relative(Action *,Hydrogen *,targeted_element)464 bool MidiActionManager::effect_level_relative(Action * , Hydrogen* , targeted_element ) {
465 //empty ?
466 return true;
467 }
468
469 //sets the volume of a master output to a given level (percentage)
master_volume_absolute(Action * pAction,Hydrogen * pEngine,targeted_element)470 bool MidiActionManager::master_volume_absolute(Action * pAction, Hydrogen* pEngine, targeted_element ) {
471
472 bool ok;
473 int vol_param = pAction->getParameter2().toInt(&ok,10);
474
475 Song *song = pEngine->getSong();
476
477 if( vol_param != 0 ){
478 song->set_volume( 1.5* ( (float) (vol_param / 127.0 ) ));
479 } else {
480 song->set_volume( 0 );
481 }
482
483 return true;
484 }
485
486 //increments/decrements the volume of the whole song
master_volume_relative(Action * pAction,Hydrogen * pEngine,targeted_element)487 bool MidiActionManager::master_volume_relative(Action * pAction, Hydrogen* pEngine, targeted_element ) {
488
489 bool ok;
490 int vol_param = pAction->getParameter2().toInt(&ok,10);
491
492 Song *song = pEngine->getSong();
493
494 if( vol_param != 0 ) {
495 if ( vol_param == 1 && song->get_volume() < 1.5 ) {
496 song->set_volume( song->get_volume() + 0.05 );
497 } else {
498 if( song->get_volume() >= 0.0 ) {
499 song->set_volume( song->get_volume() - 0.05 );
500 }
501 }
502 } else {
503 song->set_volume( 0 );
504 }
505
506 return true;
507 }
508
509 //sets the volume of a mixer strip to a given level (percentage)
strip_volume_absolute(Action * pAction,Hydrogen * pEngine,targeted_element)510 bool MidiActionManager::strip_volume_absolute(Action * pAction, Hydrogen* pEngine, targeted_element ) {
511
512 bool ok;
513 int nLine = pAction->getParameter1().toInt(&ok,10);
514 int vol_param = pAction->getParameter2().toInt(&ok,10);
515
516 Song *pSong = pEngine->getSong();
517 InstrumentList *pInstrList = pSong->get_instrument_list();
518
519 if ( pInstrList->is_valid_index( nLine) )
520 {
521 Instrument *pInstr = pInstrList->get( nLine );
522
523 if ( pInstr == nullptr) {
524 return false;
525 }
526
527 if( vol_param != 0 ) {
528 pInstr->set_volume( 1.5* ( (float) (vol_param / 127.0 ) ));
529 } else {
530 pInstr->set_volume( 0 );
531 }
532
533 pEngine->setSelectedInstrumentNumber(nLine);
534 }
535
536 return true;
537 }
538
539 //increments/decrements the volume of one mixer strip
strip_volume_relative(Action * pAction,Hydrogen * pEngine,targeted_element)540 bool MidiActionManager::strip_volume_relative(Action * pAction, Hydrogen* pEngine, targeted_element ) {
541
542 bool ok;
543 int nLine = pAction->getParameter1().toInt(&ok,10);
544 int vol_param = pAction->getParameter2().toInt(&ok,10);
545
546 Song *pSong = pEngine->getSong();
547 InstrumentList *pInstrList = pSong->get_instrument_list();
548
549 if ( pInstrList->is_valid_index( nLine) )
550 {
551 Instrument *pInstr = pInstrList->get( nLine );
552
553 if ( pInstr == nullptr) {
554 return false;
555 }
556
557 if( vol_param != 0 ) {
558 if ( vol_param == 1 && pInstr->get_volume() < 1.5 ) {
559 pInstr->set_volume( pInstr->get_volume() + 0.1 );
560 } else {
561 if( pInstr->get_volume() >= 0.0 ){
562 pInstr->set_volume( pInstr->get_volume() - 0.1 );
563 }
564 }
565 } else {
566 pInstr->set_volume( 0 );
567 }
568
569 pEngine->setSelectedInstrumentNumber(nLine);
570 }
571
572 return true;
573 }
574
575 // sets the absolute panning of a given mixer channel
pan_absolute(Action * pAction,Hydrogen * pEngine,targeted_element)576 bool MidiActionManager::pan_absolute(Action * pAction, Hydrogen* pEngine, targeted_element ) {
577
578 bool ok;
579 int nLine = pAction->getParameter1().toInt(&ok,10);
580 int pan_param = pAction->getParameter2().toInt(&ok,10);
581
582 Song *pSong = pEngine->getSong();
583 InstrumentList *pInstrList = pSong->get_instrument_list();
584
585 if( pInstrList->is_valid_index( nLine ) )
586 {
587 float pan_L;
588 float pan_R;
589
590 pEngine->setSelectedInstrumentNumber( nLine );
591
592 Instrument *pInstr = pInstrList->get( nLine );
593
594 if( pInstr == nullptr ) {
595 return false;
596 }
597
598 pan_L = pInstr->get_pan_l();
599 pan_R = pInstr->get_pan_r();
600
601 // pan
602 float fPanValue = 0.0;
603 if (pan_R == 1.0) {
604 fPanValue = 1.0 - (pan_L / 2.0);
605 }
606 else {
607 fPanValue = pan_R / 2.0;
608 }
609
610 fPanValue = 1 * ( ((float) pan_param) / 127.0 );
611
612 if (fPanValue >= 0.5) {
613 pan_L = (1.0 - fPanValue) * 2;
614 pan_R = 1.0;
615 }
616 else {
617 pan_L = 1.0;
618 pan_R = fPanValue * 2;
619 }
620
621 pInstr->set_pan_l( pan_L );
622 pInstr->set_pan_r( pan_R );
623
624 pEngine->setSelectedInstrumentNumber(nLine);
625 }
626
627 return true;
628 }
629
630 // changes the panning of a given mixer channel
631 // this is useful if the panning is set by a rotary control knob
pan_relative(Action * pAction,Hydrogen * pEngine,targeted_element)632 bool MidiActionManager::pan_relative(Action * pAction, Hydrogen* pEngine, targeted_element ) {
633
634
635 bool ok;
636 int nLine = pAction->getParameter1().toInt(&ok,10);
637 int pan_param = pAction->getParameter2().toInt(&ok,10);
638
639 Song *pSong = pEngine->getSong();
640 InstrumentList *pInstrList = pSong->get_instrument_list();
641
642 if( pInstrList->is_valid_index( nLine ) )
643 {
644 float pan_L;
645 float pan_R;
646
647 pEngine->setSelectedInstrumentNumber( nLine );
648
649 Instrument *pInstr = pInstrList->get( nLine );
650
651 if( pInstr == nullptr ) {
652 return false;
653 }
654
655 pan_L = pInstr->get_pan_l();
656 pan_R = pInstr->get_pan_r();
657
658 // pan
659 float fPanValue = 0.0;
660 if (pan_R == 1.0) {
661 fPanValue = 1.0 - (pan_L / 2.0);
662 }
663 else {
664 fPanValue = pan_R / 2.0;
665 }
666
667 if( pan_param == 1 && fPanValue < 1 ) {
668 fPanValue += 0.05;
669 }
670
671 if( pan_param != 1 && fPanValue > 0 ) {
672 fPanValue -= 0.05;
673 }
674
675 if (fPanValue >= 0.5) {
676 pan_L = (1.0 - fPanValue) * 2;
677 pan_R = 1.0;
678 }
679 else {
680 pan_L = 1.0;
681 pan_R = fPanValue * 2;
682 }
683
684 pInstr->set_pan_l( pan_L );
685 pInstr->set_pan_r( pan_R );
686
687 pEngine->setSelectedInstrumentNumber(nLine);
688 }
689
690 return true;
691 }
692
gain_level_absolute(Action * pAction,Hydrogen * pEngine,targeted_element nSample)693 bool MidiActionManager::gain_level_absolute(Action * pAction, Hydrogen* pEngine, targeted_element nSample) {
694 bool ok;
695 int nLine = pAction->getParameter1().toInt(&ok,10);
696 int gain_param = pAction->getParameter2().toInt(&ok,10);
697
698 Song *pSong = pEngine->getSong();
699 InstrumentList *pInstrList = pSong->get_instrument_list();
700
701 if( pInstrList->is_valid_index( nLine ) )
702 {
703 Instrument *pInstr = pInstrList->get( nLine );
704 if( pInstr == nullptr ) {
705 return false;
706 }
707
708 InstrumentComponent* pComponent = pInstr->get_component( nSample._id );
709 if( pComponent == nullptr) {
710 return false;
711 }
712
713 InstrumentLayer* pLayer = pComponent->get_layer( nSample._subId );
714 if( pLayer == nullptr ) {
715 return false;
716 }
717
718 if( gain_param != 0 ) {
719 pLayer->set_gain( 5.0* ( (float) (gain_param / 127.0 ) ) );
720 } else {
721 pLayer->set_gain( 0 );
722 }
723
724 pEngine->setSelectedInstrumentNumber( nLine );
725
726 pEngine->refreshInstrumentParameters( nLine );
727 }
728
729 return true;
730 }
731
pitch_level_absolute(Action * pAction,Hydrogen * pEngine,targeted_element nSample)732 bool MidiActionManager::pitch_level_absolute(Action * pAction, Hydrogen* pEngine, targeted_element nSample) {
733 bool ok;
734 int nLine = pAction->getParameter1().toInt(&ok,10);
735 int pitch_param = pAction->getParameter2().toInt(&ok,10);
736
737 Song *pSong = pEngine->getSong();
738 InstrumentList *pInstrList = pSong->get_instrument_list();
739
740 if( pInstrList->is_valid_index( nLine ) )
741 {
742 Instrument *pInstr = pInstrList->get( nLine );
743 if( pInstr == nullptr ) {
744 return false;
745 }
746
747 InstrumentComponent* pComponent = pInstr->get_component( nSample._id );
748 if( pComponent == nullptr) {
749 return false;
750 }
751
752 InstrumentLayer* pLayer = pComponent->get_layer( nSample._subId );
753 if( pLayer == nullptr ) {
754 return false;
755 }
756
757 if( pitch_param != 0 ){
758 pLayer->set_pitch( 49* ( (float) (pitch_param / 127.0 ) ) -24.5 );
759 } else {
760 pLayer->set_pitch( -24.5 );
761 }
762
763 pEngine->setSelectedInstrumentNumber( nLine );
764
765 pEngine->refreshInstrumentParameters( nLine );
766 }
767
768 return true;
769 }
770
filter_cutoff_level_absolute(Action * pAction,Hydrogen * pEngine,targeted_element)771 bool MidiActionManager::filter_cutoff_level_absolute(Action * pAction, Hydrogen* pEngine, targeted_element ) {
772 bool ok;
773 int nLine = pAction->getParameter1().toInt(&ok,10);
774 int filter_cutoff_param = pAction->getParameter2().toInt(&ok,10);
775
776 Song *pSong = pEngine->getSong();
777 InstrumentList *pInstrList = pSong->get_instrument_list();
778
779 if( pInstrList->is_valid_index( nLine ) )
780 {
781 Instrument *pInstr = pInstrList->get( nLine );
782 if( pInstr == nullptr ) {
783 return false;
784 }
785
786 pInstr->set_filter_active( true );
787 if( filter_cutoff_param != 0 ) {
788 pInstr->set_filter_cutoff( ( (float) (filter_cutoff_param / 127.0 ) ) );
789 } else {
790 pInstr->set_filter_cutoff( 0 );
791 }
792
793 pEngine->setSelectedInstrumentNumber( nLine );
794
795 pEngine->refreshInstrumentParameters( nLine );
796 }
797
798 return true;
799 }
800
801
802 /*
803 * increments/decrements the BPM
804 * this is useful if the bpm is set by a rotary control knob
805 */
bpm_cc_relative(Action * pAction,Hydrogen * pEngine,targeted_element)806 bool MidiActionManager::bpm_cc_relative(Action * pAction, Hydrogen* pEngine, targeted_element ) {
807
808 AudioEngine::get_instance()->lock( RIGHT_HERE );
809
810 //this Action should be triggered only by CC commands
811
812 bool ok;
813 int mult = pAction->getParameter1().toInt(&ok,10);
814 //this value should be 1 to decrement and something other then 1 to increment the bpm
815 int cc_param = pAction->getParameter2().toInt(&ok,10);
816
817 if( m_nLastBpmChangeCCParameter == -1) {
818 m_nLastBpmChangeCCParameter = cc_param;
819 }
820
821 Song* pSong = pEngine->getSong();
822
823 if ( m_nLastBpmChangeCCParameter >= cc_param && pSong->__bpm < 300) {
824 pEngine->setBPM( pSong->__bpm - 1*mult );
825 }
826
827 if ( m_nLastBpmChangeCCParameter < cc_param && pSong->__bpm > 40 ) {
828 pEngine->setBPM( pSong->__bpm + 1*mult );
829 }
830
831 m_nLastBpmChangeCCParameter = cc_param;
832
833 AudioEngine::get_instance()->unlock();
834
835 return true;
836 }
837
838 /*
839 * increments/decrements the BPM
840 * this is useful if the bpm is set by a rotary control knob
841 */
bpm_fine_cc_relative(Action * pAction,Hydrogen * pEngine,targeted_element)842 bool MidiActionManager::bpm_fine_cc_relative(Action * pAction, Hydrogen* pEngine, targeted_element ) {
843
844 AudioEngine::get_instance()->lock( RIGHT_HERE );
845
846 //this Action should be triggered only by CC commands
847 bool ok;
848 int mult = pAction->getParameter1().toInt(&ok,10);
849 //this value should be 1 to decrement and something other then 1 to increment the bpm
850 int cc_param = pAction->getParameter2().toInt(&ok,10);
851
852 if( m_nLastBpmChangeCCParameter == -1) {
853 m_nLastBpmChangeCCParameter = cc_param;
854 }
855
856 Song* pSong = pEngine->getSong();
857
858 if ( m_nLastBpmChangeCCParameter >= cc_param && pSong->__bpm < 300) {
859 pEngine->setBPM( pSong->__bpm - 0.01*mult );
860 }
861
862 if ( m_nLastBpmChangeCCParameter < cc_param && pSong->__bpm > 40 ) {
863 pEngine->setBPM( pSong->__bpm + 0.01*mult );
864 }
865
866 m_nLastBpmChangeCCParameter = cc_param;
867
868 AudioEngine::get_instance()->unlock();
869
870 return true;
871 }
872
bpm_increase(Action * pAction,Hydrogen * pEngine,targeted_element)873 bool MidiActionManager::bpm_increase(Action * pAction, Hydrogen* pEngine, targeted_element ) {
874 AudioEngine::get_instance()->lock( RIGHT_HERE );
875
876 bool ok;
877 int mult = pAction->getParameter1().toInt(&ok,10);
878
879 Song* pSong = pEngine->getSong();
880 if (pSong->__bpm < 300) {
881 pEngine->setBPM( pSong->__bpm + 1*mult );
882 }
883 AudioEngine::get_instance()->unlock();
884
885 EventQueue::get_instance()->push_event( EVENT_TEMPO_CHANGED, -1 );
886
887 return true;
888 }
889
bpm_decrease(Action * pAction,Hydrogen * pEngine,targeted_element)890 bool MidiActionManager::bpm_decrease(Action * pAction, Hydrogen* pEngine, targeted_element ) {
891 AudioEngine::get_instance()->lock( RIGHT_HERE );
892
893 bool ok;
894 int mult = pAction->getParameter1().toInt(&ok,10);
895
896 Song* pSong = pEngine->getSong();
897 if (pSong->__bpm > 40 ) {
898 pEngine->setBPM( pSong->__bpm - 1*mult );
899 }
900 AudioEngine::get_instance()->unlock();
901
902 EventQueue::get_instance()->push_event( EVENT_TEMPO_CHANGED, -1 );
903
904 return true;
905 }
906
next_bar(Action *,Hydrogen * pEngine,targeted_element)907 bool MidiActionManager::next_bar(Action * , Hydrogen* pEngine, targeted_element ) {
908 pEngine->setPatternPos(pEngine->getPatternPos() +1 );
909 pEngine->setTimelineBpm();
910 return true;
911 }
912
913
previous_bar(Action *,Hydrogen * pEngine,targeted_element)914 bool MidiActionManager::previous_bar(Action * , Hydrogen* pEngine, targeted_element ) {
915 pEngine->setPatternPos(pEngine->getPatternPos() -1 );
916 pEngine->setTimelineBpm();
917 return true;
918 }
919
setSong(int songnumber,Hydrogen * pEngine)920 bool setSong( int songnumber, Hydrogen * pEngine ) {
921 int asn = Playlist::get_instance()->getActiveSongNumber();
922 if(asn != songnumber && songnumber >= 0 && songnumber <= Playlist::get_instance()->size() - 1 ) {
923 Playlist::get_instance()->setNextSongByNumber( songnumber );
924 }
925 return true;
926 }
927
playlist_song(Action * pAction,Hydrogen * pEngine,targeted_element)928 bool MidiActionManager::playlist_song(Action * pAction, Hydrogen* pEngine, targeted_element ) {
929 bool ok;
930 int songnumber = pAction->getParameter1().toInt(&ok,10);
931 return setSong( songnumber, pEngine );
932 }
933
playlist_next_song(Action * pAction,Hydrogen * pEngine,targeted_element)934 bool MidiActionManager::playlist_next_song(Action * pAction, Hydrogen* pEngine, targeted_element ) {
935 int songnumber = Playlist::get_instance()->getActiveSongNumber();
936 return setSong( ++songnumber, pEngine );
937 }
938
playlist_previous_song(Action * pAction,Hydrogen * pEngine,targeted_element)939 bool MidiActionManager::playlist_previous_song(Action * pAction, Hydrogen* pEngine, targeted_element ) {
940 int songnumber = Playlist::get_instance()->getActiveSongNumber();
941 return setSong( --songnumber, pEngine );
942 }
943
record_ready(Action * pAction,Hydrogen * pEngine,targeted_element)944 bool MidiActionManager::record_ready(Action * pAction, Hydrogen* pEngine, targeted_element ) {
945 if ( pEngine->getState() != STATE_PLAYING ) {
946 if (!Preferences::get_instance()->getRecordEvents()) {
947 Preferences::get_instance()->setRecordEvents(true);
948 }
949 else {
950 Preferences::get_instance()->setRecordEvents(false);
951 }
952 }
953 return true;
954 }
955
record_strobe_toggle(Action *,Hydrogen *,targeted_element)956 bool MidiActionManager::record_strobe_toggle(Action * , Hydrogen* , targeted_element ) {
957 if (!Preferences::get_instance()->getRecordEvents()) {
958 Preferences::get_instance()->setRecordEvents(true);
959 }
960 else {
961 Preferences::get_instance()->setRecordEvents(false);
962 }
963 return true;
964 }
965
record_strobe(Action *,Hydrogen *,targeted_element)966 bool MidiActionManager::record_strobe(Action * , Hydrogen* , targeted_element ) {
967 if (!Preferences::get_instance()->getRecordEvents()) {
968 Preferences::get_instance()->setRecordEvents(true);
969 }
970 return true;
971 }
972
record_exit(Action *,Hydrogen *,targeted_element)973 bool MidiActionManager::record_exit(Action * , Hydrogen* , targeted_element ) {
974 if (Preferences::get_instance()->getRecordEvents()) {
975 Preferences::get_instance()->setRecordEvents(false);
976 }
977 return true;
978 }
979
toggle_metronome(Action *,Hydrogen *,targeted_element)980 bool MidiActionManager::toggle_metronome(Action * , Hydrogen* , targeted_element ) {
981 Preferences::get_instance()->m_bUseMetronome = !Preferences::get_instance()->m_bUseMetronome;
982 return true;
983 }
984
undo_action(Action *,Hydrogen *,targeted_element)985 bool MidiActionManager::undo_action(Action * , Hydrogen* , targeted_element ) {
986 EventQueue::get_instance()->push_event( EVENT_UNDO_REDO, 0);// 0 = undo
987 return true;
988 }
989
redo_action(Action *,Hydrogen *,targeted_element)990 bool MidiActionManager::redo_action(Action * , Hydrogen* , targeted_element ) {
991 EventQueue::get_instance()->push_event( EVENT_UNDO_REDO, 1);// 1 = redo
992 return true;
993 }
994
handleAction(Action * pAction)995 bool MidiActionManager::handleAction( Action * pAction ) {
996
997 Hydrogen *pEngine = Hydrogen::get_instance();
998 /*
999 return false if action is null
1000 (for example if no Action exists for an event)
1001 */
1002 if( pAction == nullptr ) {
1003 return false;
1004 }
1005
1006 QString sActionString = pAction->getType();
1007
1008 map<string, pair<action_f, targeted_element> >::const_iterator foundAction = actionMap.find(sActionString.toStdString());
1009 if( foundAction != actionMap.end() ) {
1010 action_f action = foundAction->second.first;
1011 targeted_element nElement = foundAction->second.second;
1012 return (this->*action)(pAction, pEngine, nElement);
1013 }
1014
1015 return false;
1016 }
1017