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