void SoundLibraryPanel::on_songLoadAction()
{
	QString songName = __sound_library_tree->currentItem()->text( 0 );
	QString sDirectory = Preferences::get_instance()->getDataDirectory()  + "songs";

	QString sFilename = sDirectory + "/" + songName + ".h2song";
	

	Hydrogen *engine = Hydrogen::get_instance();
	if ( engine->getState() == STATE_PLAYING ) {
                engine->sequencer_stop();
	}

	Song *pSong = Song::load( sFilename );
	if ( pSong == NULL ) {
		QMessageBox::information( this, "Hydrogen", trUtf8("Error loading song.") );
		return;
	}

	// add the new loaded song in the "last used song" vector
	Preferences *pPref = Preferences::get_instance();

	std::vector<QString> recentFiles = pPref->getRecentFiles();
	recentFiles.insert( recentFiles.begin(), sFilename );
	pPref->setRecentFiles( recentFiles );

	HydrogenApp* h2app = HydrogenApp::get_instance();

	h2app->setSong( pSong );

	//updateRecentUsedSongList();
	engine->setSelectedPatternNumber( 0 );
}
Exemple #2
0
void MainForm::action_file_new()
{
	Hydrogen * pEngine = Hydrogen::get_instance();
	if ( (pEngine->getState() == STATE_PLAYING) ) {
		pEngine->sequencer_stop();
	}

	bool proceed = handleUnsavedChanges();
	if(!proceed) {
		return;
	}

	h2app->m_undoStack->clear();
	pEngine->getTimeline()->m_timelinevector.clear();
	Song * pSong = Song::get_empty_song();
	pSong->set_filename( "" );
	h2app->setSong(pSong);
	pEngine->setSelectedPatternNumber( 0 );
	h2app->getInstrumentRack()->getSoundLibraryPanel()->update_background_color();
	h2app->getSongEditorPanel()->updatePositionRuler();
	pEngine->getTimeline()->m_timelinetagvector.clear();

	// update director tags
	EventQueue::get_instance()->push_event( EVENT_METRONOME, 2 );
	// update director songname
	EventQueue::get_instance()->push_event( EVENT_METRONOME, 3 );
}
Exemple #3
0
/* This method is called by Event dispacher thread ( GUI ) */
bool Playlist::loadSong (int songNumber)
{
	Hydrogen* pHydrogen = Hydrogen::get_instance();
	Preferences *pPref = Preferences::get_instance();

	if ( pHydrogen->getState() == STATE_PLAYING )
		pHydrogen->sequencer_stop();

	/* Load Song from file */
	QString selected = pHydrogen->m_PlayList[ songNumber ].m_hFile;
	Song *pSong = Song::load( selected );
	if ( ! pSong ) return false;

	setSelectedSongNr( songNumber );
	setActiveSongNumber( songNumber );

	pHydrogen->setSong( pSong );

	pPref->setLastSongFilename( pSong->get_filename() );
	vector<QString> recentFiles = pPref->getRecentFiles();
	recentFiles.insert( recentFiles.begin(), selected );
	pPref->setRecentFiles( recentFiles );

	execScript( songNumber );

	return true;
}
Exemple #4
0
void MainForm::action_file_save_as()
{
	Hydrogen* pEngine = Hydrogen::get_instance();

	if ( pEngine->getState() == STATE_PLAYING ) {
		  pEngine->sequencer_stop();
	}

	//std::auto_ptr<QFileDialog> fd( new QFileDialog );
	QFileDialog fd(this);
	fd.setFileMode( QFileDialog::AnyFile );
	fd.setFilter( trUtf8("Hydrogen Song (*.h2song)") );
	fd.setAcceptMode( QFileDialog::AcceptSave );
	fd.setWindowTitle( trUtf8( "Save song" ) );
	fd.setSidebarUrls( fd.sidebarUrls() << QUrl::fromLocalFile( Filesystem::songs_dir() ) );

	Song *song = pEngine->getSong();
	QString defaultFilename;
	QString lastFilename = song->get_filename();

	if ( lastFilename.isEmpty() ) {
		defaultFilename = pEngine->getSong()->__name;
		defaultFilename += ".h2song";
	}
	else {
		defaultFilename = lastFilename;
	}

	fd.selectFile( defaultFilename );

	QString filename;
	if (fd.exec() == QDialog::Accepted) {
		filename = fd.selectedFiles().first();
	}

	if ( !filename.isEmpty() ) {
		QString sNewFilename = filename;
		if ( sNewFilename.endsWith(".h2song") == false ) {
			filename += ".h2song";
		}

		song->set_filename(filename);
		action_file_save();
	}
	h2app->setScrollStatusBarMessage( trUtf8("Song saved as.") + QString(" Into: ") + defaultFilename, 2000 );
	h2app->updateWindowTitle();
}
Exemple #5
0
void PlaylistDialog::nodePlayBTN( Button* ref )
{
	Hydrogen *pEngine = Hydrogen::get_instance();
	HydrogenApp *pH2App = HydrogenApp::get_instance();

	if (ref->isPressed()) {
		QTreeWidgetItem* m_pPlaylistItem = m_pPlaylistTree->currentItem();
		if ( m_pPlaylistItem == NULL ){
			QMessageBox::information ( this, "Hydrogen", trUtf8 ( "No valid song selected!" ) );
			m_pPlayBtn->setPressed(false);
			return;
		}
		QString selected = "";
		selected = m_pPlaylistItem->text ( 0 );

		if( selected == pEngine->getSong()->get_filename()){
			pEngine->sequencer_play();
			return;
		}

		if ( pEngine->getState() == STATE_PLAYING ){
			pEngine->sequencer_stop();
		}

		Song *pSong = Song::load ( selected );
		if ( pSong == NULL ){
			QMessageBox::information ( this, "Hydrogen", trUtf8 ( "Error loading song." ) );
			m_pPlayBtn->setPressed(false);
			return;
		}

		QTreeWidget* m_pPlaylist = m_pPlaylistTree;
		int index = m_pPlaylist->indexOfTopLevelItem ( m_pPlaylistItem );
		Playlist::get_instance()->setActiveSongNumber( index );

		pH2App->setSong ( pSong );
		pEngine->setSelectedPatternNumber ( 0 );

		pEngine->sequencer_play();
	}else
	{
		pEngine->sequencer_stop();
		pH2App->setStatusBarMessage(trUtf8("Pause."), 5000);
	}
}
Exemple #6
0
/**
 * The handleAction method is the heard of the MidiActionManager class.
 * It executes the operations that are needed to carry the desired action.
 */
bool MidiActionManager::handleAction( MidiAction * pAction ){

	Hydrogen *pEngine = Hydrogen::get_instance();

	/*
		return false if action is null
		(for example if no Action exists for an event)
	*/
	if( pAction == NULL )	return false;

	QString sActionString = pAction->getType();


	if( sActionString == "PLAY" )
	{
		int nState = pEngine->getState();
		if ( nState == STATE_READY ){
			pEngine->sequencer_play();
		}
		return true;
	}

	if( sActionString == "PLAY/STOP_TOGGLE" || sActionString == "PLAY/PAUSE_TOGGLE" )
	{
		int nState = pEngine->getState();
		switch ( nState )
		{
		case STATE_READY:
			pEngine->sequencer_play();
			break;

		case STATE_PLAYING:
			if( sActionString == "PLAY/STOP_TOGGLE" ) pEngine->setPatternPos( 0 );
			pEngine->sequencer_stop();
			pEngine->setTimelineBpm();
			break;

		default:
			ERRORLOG( "[Hydrogen::ActionManager(PLAY): Unhandled case" );
		}

		return true;
	}

	if( sActionString == "PAUSE" )
	{
		pEngine->sequencer_stop();
		return true;
	}

	if( sActionString == "STOP" )
	{
		pEngine->sequencer_stop();
		pEngine->setPatternPos( 0 );
		pEngine->setTimelineBpm();
		return true;
	}

	if( sActionString == "MUTE" ){
		//mutes the master, not a single strip
		pEngine->getSong()->__is_muted = true;
		return true;
	}

	if( sActionString == "UNMUTE" ){
		pEngine->getSong()->__is_muted = false;
		return true;
	}

	if( sActionString == "MUTE_TOGGLE" ){
		pEngine->getSong()->__is_muted = !Hydrogen::get_instance()->getSong()->__is_muted;
		return true;
	}

	if( sActionString == "BEATCOUNTER" ){
		pEngine->handleBeatCounter();
		return true;
	}

	if( sActionString == "TAP_TEMPO" ){
		pEngine->onTapTempoAccelEvent();
		return true;
	}

	if( sActionString == "SELECT_NEXT_PATTERN" ){
		bool ok;
		int row = pAction->getParameter1().toInt(&ok,10);
		if( row> pEngine->getSong()->get_pattern_list()->size() -1 )
			return false;
		if(Preferences::get_instance()->patternModePlaysSelected())
			pEngine->setSelectedPatternNumber( row );
		else
			pEngine->sequencer_setNextPattern( row, false, true );
		return true;
	}

	if( sActionString == "SELECT_NEXT_PATTERN_RELATIVE" ){

		bool ok;

		if(!Preferences::get_instance()->patternModePlaysSelected())
		{
			return true;
		}

		int row = pEngine->getSelectedPatternNumber() + pAction->getParameter1().toInt(&ok,10);

		if( row> pEngine->getSong()->get_pattern_list()->size() -1 )
		{
			return false;
		}

		pEngine->setSelectedPatternNumber( row );

		return true;
	}

	if( sActionString == "SELECT_PREV_PATTERN_RELATIVE" ){
		bool ok;
		if(!Preferences::get_instance()->patternModePlaysSelected())
			return true;
		int row = pEngine->getSelectedPatternNumber() - pAction->getParameter1().toInt(&ok,10);
		if( row < 0 )
			return false;

		pEngine->setSelectedPatternNumber( row );
		return true;
	}

	if( sActionString == "SELECT_NEXT_PATTERN_CC_ABSOLUT" ){
		bool ok;
		int row = pAction->getParameter2().toInt(&ok,10);
		if( row> pEngine->getSong()->get_pattern_list()->size() -1 )
			return false;
		if(Preferences::get_instance()->patternModePlaysSelected())
			pEngine->setSelectedPatternNumber( row );
		else
			return true;// only usefully in normal pattern mode
		return true;
	}

	if( sActionString == "SELECT_NEXT_PATTERN_PROMPTLY" ){// obsolete, use SELECT_NEXT_PATTERN_CC_ABSOLUT instead
		bool ok;
		int row = pAction->getParameter2().toInt(&ok,10);
		pEngine->setSelectedPatternNumberWithoutGuiEvent( row );
		return true;
	}

	if( sActionString == "SELECT_AND_PLAY_PATTERN"){
		bool ok;
		int row = pAction->getParameter1().toInt(&ok,10);
		pEngine->setSelectedPatternNumber( row );
		pEngine->sequencer_setNextPattern( row, false, true );

		int nState = pEngine->getState();
		if ( nState == STATE_READY ){
			pEngine->sequencer_play();
		}

		return true;
	}

	if( sActionString == "SELECT_INSTRUMENT" ){
		bool ok;
		int  instrument_number = pAction->getParameter2().toInt(&ok,10) ;
		if ( pEngine->getSong()->get_instrument_list()->size() < instrument_number )
			instrument_number = pEngine->getSong()->get_instrument_list()->size() -1;
		pEngine->setSelectedInstrumentNumber( instrument_number );
		return true;
	}

	if( sActionString == "EFFECT1_LEVEL_ABSOLUTE" ){
		bool ok;
		int nLine = pAction->getParameter1().toInt(&ok,10);
		int fx_param = pAction->getParameter2().toInt(&ok,10);
		setAbsoluteFXLevel( nLine, 0 , fx_param );
	}

	if( sActionString == "EFFECT2_LEVEL_ABSOLUTE" ){
		bool ok;
		int nLine = pAction->getParameter1().toInt(&ok,10);
		int fx_param = pAction->getParameter2().toInt(&ok,10);
		setAbsoluteFXLevel( nLine, 1 , fx_param );
	}

	if( sActionString == "EFFECT3_LEVEL_ABSOLUTE" ){
		bool ok;
		int nLine = pAction->getParameter1().toInt(&ok,10);
		int fx_param = pAction->getParameter2().toInt(&ok,10);
		setAbsoluteFXLevel( nLine, 2 , fx_param );
	}

	if( sActionString == "EFFECT4_LEVEL_ABSOLUTE" ){
		bool ok;
		int nLine = pAction->getParameter1().toInt(&ok,10);
		int fx_param = pAction->getParameter2().toInt(&ok,10);
		setAbsoluteFXLevel( nLine, 3 , fx_param );
	}

	if( sActionString == "MASTER_VOLUME_RELATIVE" ){
		//increments/decrements the volume of the whole song

		bool ok;
		int vol_param = pAction->getParameter2().toInt(&ok,10);

		Hydrogen *engine = Hydrogen::get_instance();
		Song *song = engine->getSong();



		if( vol_param != 0 ){
			if ( vol_param == 1 && song->get_volume() < 1.5 ){
				song->set_volume( song->get_volume() + 0.05 );
			}  else  {
				if( song->get_volume() >= 0.0 ){
					song->set_volume( song->get_volume() - 0.05 );
				}
			}
		} else {
			song->set_volume( 0 );
		}

	}

	if( sActionString == "MASTER_VOLUME_ABSOLUTE" ){
		//sets the volume of a master output to a given level (percentage)

		bool ok;
		int vol_param = pAction->getParameter2().toInt(&ok,10);


		Hydrogen *engine = Hydrogen::get_instance();
		Song *song = engine->getSong();


		if( vol_param != 0 ){
			song->set_volume( 1.5* ( (float) (vol_param / 127.0 ) ));
		} else {
			song->set_volume( 0 );
		}

	}

	if( sActionString == "STRIP_VOLUME_RELATIVE" ){
		//increments/decrements the volume of one mixer strip

		bool ok;
		int nLine = pAction->getParameter1().toInt(&ok,10);
		int vol_param = pAction->getParameter2().toInt(&ok,10);

		Hydrogen::get_instance()->setSelectedInstrumentNumber( nLine );

		Hydrogen *engine = Hydrogen::get_instance();
		Song *song = engine->getSong();
		InstrumentList *instrList = song->get_instrument_list();

		Instrument *instr = instrList->get( nLine );

		if ( instr == NULL) return 0;

		if( vol_param != 0 ){
			if ( vol_param == 1 && instr->get_volume() < 1.5 ){
				instr->set_volume( instr->get_volume() + 0.1 );
			}  else  {
				if( instr->get_volume() >= 0.0 ){
					instr->set_volume( instr->get_volume() - 0.1 );
				}
			}
		} else {
			instr->set_volume( 0 );
		}

		Hydrogen::get_instance()->setSelectedInstrumentNumber(nLine);
	}

	if( sActionString == "STRIP_VOLUME_ABSOLUTE" ){
		//sets the volume of a mixer strip to a given level (percentage)

		bool ok;
		int nLine = pAction->getParameter1().toInt(&ok,10);
		int vol_param = pAction->getParameter2().toInt(&ok,10);

		Hydrogen::get_instance()->setSelectedInstrumentNumber( nLine );

		Hydrogen *engine = Hydrogen::get_instance();
		Song *song = engine->getSong();
		InstrumentList *instrList = song->get_instrument_list();

		Instrument *instr = instrList->get( nLine );

		if ( instr == NULL) return 0;

		if( vol_param != 0 ){
			instr->set_volume( 1.5* ( (float) (vol_param / 127.0 ) ));
		} else {
			instr->set_volume( 0 );
		}

		Hydrogen::get_instance()->setSelectedInstrumentNumber(nLine);
	}

	if( sActionString == "PAN_ABSOLUTE" ){

		// sets the absolute panning of a given mixer channel

		bool ok;
		int nLine = pAction->getParameter1().toInt(&ok,10);
		int pan_param = pAction->getParameter2().toInt(&ok,10);


		float pan_L;
		float pan_R;

		Hydrogen *engine = Hydrogen::get_instance();
		engine->setSelectedInstrumentNumber( nLine );
		Song *song = engine->getSong();
		InstrumentList *instrList = song->get_instrument_list();

		Instrument *instr = instrList->get( nLine );

		if( instr == NULL )
			return false;

		pan_L = instr->get_pan_l();
		pan_R = instr->get_pan_r();

		// pan
		float fPanValue = 0.0;
		if (pan_R == 1.0) {
			fPanValue = 1.0 - (pan_L / 2.0);
		}
		else {
			fPanValue = pan_R / 2.0;
		}


		fPanValue = 1 * ( ((float) pan_param) / 127.0 );


		if (fPanValue >= 0.5) {
			pan_L = (1.0 - fPanValue) * 2;
			pan_R = 1.0;
		}
		else {
			pan_L = 1.0;
			pan_R = fPanValue * 2;
		}


		instr->set_pan_l( pan_L );
		instr->set_pan_r( pan_R );

		Hydrogen::get_instance()->setSelectedInstrumentNumber(nLine);

		return true;
	}

	if( sActionString == "PAN_RELATIVE" ){

		// changes the panning of a given mixer channel
		// this is useful if the panning is set by a rotary control knob

		bool ok;
		int nLine = pAction->getParameter1().toInt(&ok,10);
		int pan_param = pAction->getParameter2().toInt(&ok,10);

		float pan_L;
		float pan_R;

		Hydrogen *engine = Hydrogen::get_instance();
		engine->setSelectedInstrumentNumber( nLine );
		Song *song = engine->getSong();
		InstrumentList *instrList = song->get_instrument_list();

		Instrument *instr = instrList->get( nLine );

		if( instr == NULL )
			return false;

		pan_L = instr->get_pan_l();
		pan_R = instr->get_pan_r();

		// pan
		float fPanValue = 0.0;
		if (pan_R == 1.0) {
			fPanValue = 1.0 - (pan_L / 2.0);
		}
		else {
			fPanValue = pan_R / 2.0;
		}

		if( pan_param == 1 && fPanValue < 1 ){
			fPanValue += 0.05;
		}

		if( pan_param != 1 && fPanValue > 0 ){
			fPanValue -= 0.05;
		}

		if (fPanValue >= 0.5) {
			pan_L = (1.0 - fPanValue) * 2;
			pan_R = 1.0;
		}
		else {
			pan_L = 1.0;
			pan_R = fPanValue * 2;
		}


		instr->set_pan_l( pan_L );
		instr->set_pan_r( pan_R );

		Hydrogen::get_instance()->setSelectedInstrumentNumber(nLine);

		return true;
	}

	if( sActionString == "BPM_CC_RELATIVE" ){
		/*
		 * increments/decrements the BPM
		 * this is useful if the bpm is set by a rotary control knob
		*/

		AudioEngine::get_instance()->lock( RIGHT_HERE );

		int mult = 1;

		//second parameter of cc command
		//this value should be 1 to decrement and something other then 1 to increment the bpm
		int cc_param = 1;

		//this Action should be triggered only by CC commands

		bool ok;
		mult = pAction->getParameter1().toInt(&ok,10);
		cc_param = pAction->getParameter2().toInt(&ok,10);

		if( lastBpmChangeCCParameter == -1)
		{
			lastBpmChangeCCParameter = cc_param;
		}

		Song* pSong = pEngine->getSong();

		if ( lastBpmChangeCCParameter >= cc_param && pSong->__bpm  < 300) {
			pEngine->setBPM( pSong->__bpm - 1*mult );
		}

		if ( lastBpmChangeCCParameter < cc_param && pSong->__bpm  > 40 ) {
			pEngine->setBPM( pSong->__bpm + 1*mult );
		}

		lastBpmChangeCCParameter = cc_param;

		AudioEngine::get_instance()->unlock();

		return true;
	}

	if( sActionString == "BPM_FINE_CC_RELATIVE" ){
		/*
		 * increments/decrements the BPM
		 * this is useful if the bpm is set by a rotary control knob
		 */

		AudioEngine::get_instance()->lock( RIGHT_HERE );

		int mult = 1;

		//second parameter of cc command
		//this value should be 1 to decrement and something other then 1 to increment the bpm
		int cc_param = 1;

		//this Action should be triggered only by CC commands

		bool ok;
		mult = pAction->getParameter1().toInt(&ok,10);
		cc_param = pAction->getParameter2().toInt(&ok,10);

		if( lastBpmChangeCCParameter == -1)
		{
			lastBpmChangeCCParameter = cc_param;
		}

		Song* pSong = pEngine->getSong();

		if ( lastBpmChangeCCParameter >= cc_param && pSong->__bpm  < 300) {
			pEngine->setBPM( pSong->__bpm - 0.01*mult );
		}

		if ( lastBpmChangeCCParameter < cc_param && pSong->__bpm  > 40 ) {
			pEngine->setBPM( pSong->__bpm + 0.01*mult );
		}

		lastBpmChangeCCParameter = cc_param;

		AudioEngine::get_instance()->unlock();

		return true;
	}

	if( sActionString == "BPM_INCR" ){
		AudioEngine::get_instance()->lock( RIGHT_HERE );

		int mult = 1;

		bool ok;
		mult = pAction->getParameter1().toInt(&ok,10);


		Song* pSong = pEngine->getSong();
		if (pSong->__bpm  < 300) {
			pEngine->setBPM( pSong->__bpm + 1*mult );
		}
		AudioEngine::get_instance()->unlock();

		return true;
	}

	if( sActionString == "BPM_DECR" ){
		AudioEngine::get_instance()->lock( RIGHT_HERE );

		int mult = 1;

		bool ok;
		mult = pAction->getParameter1().toInt(&ok,10);

		Song* pSong = pEngine->getSong();
		if (pSong->__bpm  > 40 ) {
			pEngine->setBPM( pSong->__bpm - 1*mult );
		}
		AudioEngine::get_instance()->unlock();

		return true;
	}

	if( sActionString == ">>_NEXT_BAR"){
		pEngine->setPatternPos(pEngine->getPatternPos() +1 );
		pEngine->setTimelineBpm();
		return true;
	}

	if( sActionString == "<<_PREVIOUS_BAR"){
		pEngine->setPatternPos(pEngine->getPatternPos() -1 );
		pEngine->setTimelineBpm();
		return true;
	}

	if( sActionString == "PLAYLIST_SONG"){
		bool ok;
		int songnumber = pAction->getParameter2().toInt(&ok,10);
		return setSong( songnumber );
	}

	if( sActionString == "PLAYLIST_NEXT_SONG"){
		int songnumber = Playlist::get_instance()->getActiveSongNumber();
		return setSong( ++songnumber );
	}

	if( sActionString == "PLAYLIST_PREV_SONG"){
		int songnumber = Playlist::get_instance()->getActiveSongNumber();
		return setSong( --songnumber );
	}

	if( sActionString == "RECORD_READY"){
		if ( pEngine->getState() != STATE_PLAYING ) {
			if (!Preferences::get_instance()->getRecordEvents()) {
				Preferences::get_instance()->setRecordEvents(true);
			}
			else {
				Preferences::get_instance()->setRecordEvents(false);
			}
		}
		return true;
	}
	if( sActionString == "RECORD/STROBE_TOGGLE"){
		if (!Preferences::get_instance()->getRecordEvents()) {
			Preferences::get_instance()->setRecordEvents(true);
		}
		else {
			Preferences::get_instance()->setRecordEvents(false);
		}
		return true;
	}

	if( sActionString == "RECORD_STROBE"){

		if (!Preferences::get_instance()->getRecordEvents()) {
			Preferences::get_instance()->setRecordEvents(true);
		}
		return true;
	}

	if( sActionString == "RECORD_EXIT"){

		if (Preferences::get_instance()->getRecordEvents()) {
			Preferences::get_instance()->setRecordEvents(false);
		}
		return true;
	}

	if( sActionString == "TOGGLE_METRONOME"){

		Preferences::get_instance()->m_bUseMetronome = !Preferences::get_instance()->m_bUseMetronome;
		return true;
	}

	if( sActionString == "UNDO_ACTION"){
		EventQueue::get_instance()->push_event( EVENT_UNDO_REDO, 0);// 0 = undo
		return true;
	}

	if( sActionString == "REDO_ACTION"){
		EventQueue::get_instance()->push_event( EVENT_UNDO_REDO, 1);// 1 = redo
		return true;
	}
	return false;
}
Exemple #7
0
int main(int argc, char *argv[])
{
	try {
		// Options...
		char *cp;
		struct option *op;
		char opts[NELEM(long_opts) * 3 + 1];

		// Build up the short option QString
		cp = opts;
		for (op = long_opts; op < &long_opts[NELEM(long_opts)]; op++) {
			*cp++ = op->val;
			if (op->has_arg)
				*cp++ = ':';
			if (op->has_arg == optional_argument )
				*cp++ = ':';  // gets another one
		}

		// Deal with the options
		QString songFilename;
		QString playlistFilename;
		QString outFilename = NULL;
		QString sSelectedDriver;
		bool showVersionOpt = false;
		const char* logLevelOpt = "Error";
		bool showHelpOpt = false;
		QString drumkitName;
		QString drumkitToLoad;
		short bits = 16;
		int rate = 44100;
		short interpolation = 0;
#ifdef H2CORE_HAVE_JACKSESSION
		QString sessionId;
#endif
		int c;
		while ( 1 ) {
			c = getopt_long(argc, argv, opts, long_opts, NULL);
			if ( c == -1 ) break;

			switch(c) {
			case 'd':
				sSelectedDriver = QString::fromLocal8Bit(optarg);
				break;
			case 's':
				songFilename = QString::fromLocal8Bit(optarg);
				break;
			case 'p':
				playlistFilename = QString::fromLocal8Bit(optarg);
				break;
			case 'o':
				outFilename = QString::fromLocal8Bit(optarg);
				break;
			case 'i':
				//install h2drumkit
				drumkitName = QString::fromLocal8Bit(optarg);
				break;
			case 'k':
				//load Drumkit
				drumkitToLoad = QString::fromLocal8Bit(optarg);
				break;
			case 'r':
				rate = strtol(optarg, NULL, 10);
				break;
			case 'b':
				bits = strtol(optarg, NULL, 10);
				break;
			case 'v':
				showVersionOpt = true;
				break;
			case 'V':
				logLevelOpt = (optarg) ? optarg : "Warning";
				break;
#ifdef H2CORE_HAVE_JACKSESSION
			case 'S':
				sessionId = QString::fromLocal8Bit(optarg);
				break;
#endif
			case 'h':
			case '?':
				showHelpOpt = true;
				break;
			}
		}

		if ( showVersionOpt ) {
			cout << get_version() << endl;
			exit(0);
		}

		showInfo();
		if ( showHelpOpt ) {
			showUsage();
			exit(0);
		}

		// Man your battle stations... this is not a drill.
		Logger* logger = Logger::bootstrap( Logger::parse_log_level( logLevelOpt ) );
		Object::bootstrap( logger, logger->should_log( Logger::Debug ) );
		Filesystem::bootstrap( logger );
		MidiMap::create_instance();
		Preferences::create_instance();
		Preferences* preferences = Preferences::get_instance();
		// See below for Hydrogen.

		___INFOLOG( QString("Using QT version ") + QString( qVersion() ) );
		___INFOLOG( "Using data path: " + Filesystem::sys_data_path() );

#ifdef H2CORE_HAVE_LASH
		LashClient::create_instance("hydrogen", "Hydrogen", &argc, &argv);
		LashClient* lashClient = LashClient::get_instance();
#endif

		if ( ! drumkitName.isEmpty() ){
			Drumkit::install( drumkitName );
			exit(0);
		}

		if (sSelectedDriver == "auto") {
			preferences->m_sAudioDriver = "Auto";
		}
		else if (sSelectedDriver == "jack") {
			preferences->m_sAudioDriver = "Jack";
		}
		else if ( sSelectedDriver == "oss" ) {
			preferences->m_sAudioDriver = "Oss";
		}
		else if ( sSelectedDriver == "alsa" ) {
			preferences->m_sAudioDriver = "Alsa";
		}
		else if (sSelectedDriver == "CoreAudio") {
			preferences->m_sAudioDriver = "CoreAudio";
		}
		else if (sSelectedDriver == "PulseAudio") {
			preferences->m_sAudioDriver = "PulseAudio";
		}

#ifdef H2CORE_HAVE_LASH
		if ( preferences->useLash() && lashClient->isConnected() ) {
			lash_event_t* lash_event = lashClient->getNextEvent();
			if (lash_event && lash_event_get_type(lash_event) == LASH_Restore_File) {
				// notify client that this project was not a new one
				lashClient->setNewProject(false);

				songFilename = "";
				songFilename.append( QString::fromLocal8Bit(lash_event_get_string(lash_event)) );
				songFilename.append("/hydrogen.h2song");

				//Logger::get_instance()->log("[LASH] Restore file: " + songFilename);

				lash_event_destroy(lash_event);
			} else if (lash_event) {
				//Logger::get_instance()->log("[LASH] ERROR: Instead of restore file got event: " + lash_event_get_type(lash_event));
				lash_event_destroy(lash_event);
			}
		}
#endif
#ifdef H2CORE_HAVE_JACKSESSION
		if (!sessionId.isEmpty()) {
			preferences->setJackSessionUUID ( sessionId );
			/* imo, jack sessions use jack as default audio driver.
			 * hydrogen remember last used audiodriver.
			 * here we make it save that hydrogen start in a jacksession case
			 * every time with jack as audio driver
			 */
			preferences->m_sAudioDriver = "Jack";

		}
		/* the use of applicationFilePath() make it
		 * possible to use different executables.
		 * for example if you start hydrogen from a local
		 * build directory.
		 */
//		QString path = pQApp->applicationFilePath();
//		preferences->setJackSessionApplicationPath ( path );
#endif
		Hydrogen::create_instance();
		Hydrogen *pHydrogen = Hydrogen::get_instance();
		Song *pSong = NULL;
		Playlist *pPlaylist = NULL;

		// Load playlist
		if ( ! playlistFilename.isEmpty() ) {
			pPlaylist = Playlist::load ( playlistFilename );
			if ( ! pPlaylist ) {
				___ERRORLOG( "Error loading the playlist" );
				return 0;
			}

			/* Load first song */
			preferences->setLastPlaylistFilename( playlistFilename );
			pPlaylist->loadSong( 0 );
			pSong = pHydrogen->getSong();
			show_playlist ( pHydrogen, pPlaylist->getActiveSongNumber() );
		}

		// Load song - if wasn't already loaded with playlist
		if ( ! pSong ) {
			if ( !songFilename.isEmpty() ) {
				pSong = Song::load( songFilename );
			} else {
				/* Try load last song */
				bool restoreLastSong = preferences->isRestoreLastSongEnabled();
				QString filename = preferences->getLastSongFilename();
				if ( restoreLastSong && ( !filename.isEmpty() ))
					pSong = Song::load( filename );
			}

			/* Still not loaded */
			if (! pSong) {
				___INFOLOG("Starting with empty song");
				pSong = Song::get_empty_song();
				pSong->set_filename( "" );
			}

			pHydrogen->setSong( pSong );
			preferences->setLastSongFilename( songFilename );
		}

		if ( ! drumkitToLoad.isEmpty() ){
			Drumkit* drumkitInfo = Drumkit::load_by_name( drumkitToLoad, true );
			if ( drumkitInfo ) {
				pHydrogen->loadDrumkit( drumkitInfo );
			} else {
				___ERRORLOG ( "Error loading the drumkit" );
			}
		}

		AudioEngine* AudioEngine = AudioEngine::get_instance();
		Sampler* sampler = AudioEngine->get_sampler();
		switch ( interpolation ) {
			case 1:
					sampler->setInterpolateMode( Sampler::COSINE );
					break;
			case 2:
					sampler->setInterpolateMode( Sampler::THIRD );
					break;
			case 3:
					sampler->setInterpolateMode( Sampler::CUBIC );
					break;
			case 4:
					sampler->setInterpolateMode( Sampler::HERMITE );
					break;
			case 0:
			default:
					sampler->setInterpolateMode( Sampler::LINEAR );
		}

		EventQueue *pQueue = EventQueue::get_instance();

		signal(SIGINT, signal_handler);

		bool ExportMode = false;
		if ( ! outFilename.isEmpty() ) {
			pHydrogen->startExportSong ( outFilename, rate, bits );
			cout << "Export Progress ... ";
			bool ExportMode = true;
		}

		// Interactive mode
		while ( ! quit ) {
			/* FIXME: Someday here will be The Real CLI ;-) */
			Event event = pQueue->pop_event();
			// if ( event.type > 0) cout << "EVENT TYPE: " << event.type << endl;

			/* Event handler */
			switch ( event.type ) {
			case EVENT_PROGRESS: /* event used only in export mode */
				if ( ! ExportMode ) break;
	
				if ( event.value < 100 ) {
					cout << "\rExport Progress ... " << event.value << "%";
				} else {
					cout << "\rExport Progress ... DONE" << endl;
					quit = true;
				}
				break;
			case EVENT_PLAYLIST_LOADSONG: /* Load new song on MIDI event */
				if ( pPlaylist->loadSong ( event.value ) ) {
					pSong = pHydrogen->getSong();
					show_playlist ( pHydrogen, pPlaylist->getActiveSongNumber() );
				}
				break;
			case EVENT_NONE: /* Sleep if there is no more events */
				Sleeper::msleep ( 100 );
				break;
			}
		}

		if ( pHydrogen->getState() == STATE_PLAYING )
			pHydrogen->sequencer_stop();

		delete pSong;
		delete pPlaylist;

		delete pQueue;
		delete pHydrogen;
		delete preferences;
		delete AudioEngine;

		delete MidiMap::get_instance();
		delete MidiActionManager::get_instance();

		___INFOLOG( "Quitting..." );
		delete Logger::get_instance();

		int nObj = Object::objects_count();
		if (nObj != 0) {
			cerr << "\n\n\n " << nObj << " alive objects\n\n" << endl << endl;
			Object::write_objects_map_to_cerr();
		}
	}
	catch ( const H2Exception& ex ) {
		cerr << "[main] Exception: " << ex.what() << endl;
	}
	catch (...) {
		cerr << "[main] Unknown exception X-(" << endl;
	}

	return 0;
}
Exemple #8
0
void Sampler::setPlayingNotelength( Instrument* instrument, unsigned long ticks, unsigned long noteOnTick )
{
	if ( instrument ) { // stop all notes using this instrument
		Hydrogen *pEngine = Hydrogen::get_instance();
		Song* mSong = pEngine->getSong();
		int selectedpattern = pEngine->__get_selected_PatterNumber();
		Pattern* currentPattern = NULL;


		if ( mSong->get_mode() == Song::PATTERN_MODE ||
		( pEngine->getState() != STATE_PLAYING )){
			PatternList *pPatternList = mSong->get_pattern_list();
			if ( ( selectedpattern != -1 )
			&& ( selectedpattern < ( int )pPatternList->size() ) ) {
				currentPattern = pPatternList->get( selectedpattern );
			}
		}else
		{
			std::vector<PatternList*> *pColumns = mSong->get_pattern_group_vector();
//			Pattern *pPattern = NULL;
			int pos = pEngine->getPatternPos() +1;
			for ( int i = 0; i < pos; ++i ) {
				PatternList *pColumn = ( *pColumns )[i];
				currentPattern = pColumn->get( 0 );
			}
		}


		if ( currentPattern ) {
				int patternsize = currentPattern->get_length();

				for ( unsigned nNote = 0; nNote < currentPattern->get_length(); nNote++ ) {
					const Pattern::notes_t* notes = currentPattern->get_notes();
					FOREACH_NOTE_CST_IT_BOUND(notes,it,nNote) {
						Note *pNote = it->second;
						if ( pNote!=NULL ) {
							if( !Preferences::get_instance()->__playselectedinstrument ){
								if ( pNote->get_instrument() == instrument
								&& pNote->get_position() == noteOnTick ) {
									AudioEngine::get_instance()->lock( RIGHT_HERE );

									if ( ticks >  patternsize )
										ticks = patternsize - noteOnTick;
									pNote->set_length( ticks );
									Hydrogen::get_instance()->getSong()->__is_modified = true;
									AudioEngine::get_instance()->unlock(); // unlock the audio engine
								}
							}else
							{
								if ( pNote->get_instrument() == pEngine->getSong()->get_instrument_list()->get( pEngine->getSelectedInstrumentNumber())
								&& pNote->get_position() == noteOnTick ) {
									AudioEngine::get_instance()->lock( RIGHT_HERE );
									if ( ticks >  patternsize )
										ticks = patternsize - noteOnTick;
									pNote->set_length( ticks );
									Hydrogen::get_instance()->getSong()->__is_modified = true;
									AudioEngine::get_instance()->unlock(); // unlock the audio engine
								}
							}
						}
					}
				}
			}
		}
Exemple #9
0
/// Render a note
/// Return 0: the note is not ended
/// Return 1: the note is ended
unsigned Sampler::__render_note( Note* pNote, unsigned nBufferSize, Song* pSong )
{
	//infoLog( "[renderNote] instr: " + pNote->getInstrument()->m_sName );
	assert( pSong );

	unsigned int nFramepos;
	Hydrogen* pEngine = Hydrogen::get_instance();
	AudioOutput* audio_output = pEngine->getAudioOutput();
	if (  pEngine->getState() == STATE_PLAYING ) {
		nFramepos = audio_output->m_transport.m_nFrames;
	} else {
		// use this to support realtime events when not playing
		nFramepos = pEngine->getRealtimeFrames();
	}

	Instrument *pInstr = pNote->get_instrument();
	if ( !pInstr ) {
		ERRORLOG( "NULL instrument" );
		return 1;
	}

	float fLayerGain = 1.0;
	float fLayerPitch = 0.0;

	// scelgo il sample da usare in base alla velocity
	Sample *pSample = NULL;
	for ( unsigned nLayer = 0; nLayer < MAX_LAYERS; ++nLayer ) {
		InstrumentLayer *pLayer = pInstr->get_layer( nLayer );
		if ( pLayer == NULL ) continue;

		if ( ( pNote->get_velocity() >= pLayer->get_start_velocity() ) && ( pNote->get_velocity() <= pLayer->get_end_velocity() ) ) {
			pSample = pLayer->get_sample();
			fLayerGain = pLayer->get_gain();
			fLayerPitch = pLayer->get_pitch();
			break;
		}
	}
	if ( !pSample ) {
		QString dummy = QString( "NULL sample for instrument %1. Note velocity: %2" ).arg( pInstr->get_name() ).arg( pNote->get_velocity() );
		WARNINGLOG( dummy );
		return 1;
	}

	if ( pNote->get_sample_position() >= pSample->get_frames() ) {
		WARNINGLOG( "sample position out of bounds. The layer has been resized during note play?" );
		return 1;
	}

	int noteStartInFrames = ( int ) ( pNote->get_position() * audio_output->m_transport.m_nTickSize ) + pNote->get_humanize_delay();

	int nInitialSilence = 0;
	if ( noteStartInFrames > ( int ) nFramepos ) {	// scrivo silenzio prima dell'inizio della nota
		nInitialSilence = noteStartInFrames - nFramepos;
		int nFrames = nBufferSize - nInitialSilence;
		if ( nFrames < 0 ) {
			int noteStartInFramesNoHumanize = ( int )pNote->get_position() * audio_output->m_transport.m_nTickSize;
			if ( noteStartInFramesNoHumanize > ( int )( nFramepos + nBufferSize ) ) {
				// this note is not valid. it's in the future...let's skip it....
				ERRORLOG( QString( "Note pos in the future?? Current frames: %1, note frame pos: %2" ).arg( nFramepos ).arg(noteStartInFramesNoHumanize ) );
				//pNote->dumpInfo();
				return 1;
			}
			// delay note execution
			//INFOLOG( "Delaying note execution. noteStartInFrames: " + to_string( noteStartInFrames ) + ", nFramePos: " + to_string( nFramepos ) );
			return 0;
		}
	}

	float cost_L = 1.0f;
	float cost_R = 1.0f;
	float cost_track_L = 1.0f;
	float cost_track_R = 1.0f;

	if ( pInstr->is_muted() || pSong->__is_muted ) {	// is instrument muted?
		cost_L = 0.0;
		cost_R = 0.0;
		if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) {
		// Post-Fader
		cost_track_L = 0.0;
		cost_track_R = 0.0;
		}

	} else {	// Precompute some values...
		cost_L = cost_L * pNote->get_velocity();		// note velocity
		cost_L = cost_L * pNote->get_pan_l();		// note pan
		cost_L = cost_L * fLayerGain;				// layer gain
		cost_L = cost_L * pInstr->get_pan_l();		// instrument pan
		cost_L = cost_L * pInstr->get_gain();		// instrument gain

		cost_L = cost_L * pInstr->get_volume();		// instrument volume
		if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) {
			// Post-Fader
			cost_track_L = cost_L * 2;
		}
		cost_L = cost_L * pSong->get_volume();	// song volume
		cost_L = cost_L * 2; // max pan is 0.5


		cost_R = cost_R * pNote->get_velocity();		// note velocity
		cost_R = cost_R * pNote->get_pan_r();		// note pan
		cost_R = cost_R * fLayerGain;				// layer gain
		cost_R = cost_R * pInstr->get_pan_r();		// instrument pan
		cost_R = cost_R * pInstr->get_gain();		// instrument gain

		cost_R = cost_R * pInstr->get_volume();		// instrument volume
		if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) {
		// Post-Fader
			cost_track_R = cost_R * 2;
		}
		cost_R = cost_R * pSong->get_volume();	// song pan
		cost_R = cost_R * 2; // max pan is 0.5
	}

	// direct track outputs only use velocity
	if ( Preferences::get_instance()->m_nJackTrackOutputMode == 1 ) {
		cost_track_L = cost_track_L * pNote->get_velocity();
		cost_track_L = cost_track_L * fLayerGain;
		cost_track_R = cost_track_L;
	}

	// Se non devo fare resample (drumkit) posso evitare di utilizzare i float e gestire il tutto in
	// maniera ottimizzata
	//	constant^12 = 2, so constant = 2^(1/12) = 1.059463.
	//	float nStep = 1.0;1.0594630943593

	float fTotalPitch = pNote->get_total_pitch() + fLayerPitch;

	//_INFOLOG( "total pitch: " + to_string( fTotalPitch ) );
	if( ( int )pNote->get_sample_position() == 0 )
	{
		if( Hydrogen::get_instance()->getMidiOutput() != NULL ){
			Hydrogen::get_instance()->getMidiOutput()->handleQueueNote( pNote );
		}
	}

	if ( fTotalPitch == 0.0 && pSample->get_sample_rate() == audio_output->getSampleRate() ) {	// NO RESAMPLE
				return __render_note_no_resample( pSample, pNote, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, pSong );
	} else {	// RESAMPLE
				return __render_note_resample( pSample, pNote, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, fLayerPitch, pSong );
	}
}
Exemple #10
0
bool Sampler::processPlaybackTrack(int nBufferSize)
{
	Hydrogen* pEngine = Hydrogen::get_instance();
	AudioOutput* pAudioOutput = Hydrogen::get_instance()->getAudioOutput();
	Song* pSong = pEngine->getSong();

	if(   !pSong->get_playback_track_enabled()
	   || pEngine->getState() != STATE_PLAYING
	   || pSong->get_mode() != Song::SONG_MODE)
	{
		return false;
	}

	InstrumentComponent *pCompo = __playback_instrument->get_components()->front();
	Sample *pSample = pCompo->get_layer(0)->get_sample();

	float fVal_L;
	float fVal_R;

	float *pSample_data_L = pSample->get_data_l();
	float *pSample_data_R = pSample->get_data_r();
	
	float fInstrPeak_L = __playback_instrument->get_peak_l(); // this value will be reset to 0 by the mixer..
	float fInstrPeak_R = __playback_instrument->get_peak_r(); // this value will be reset to 0 by the mixer..

	assert(pSample);

	int nAvail_bytes = 0;
	int	nInitialBufferPos = 0;

	if(pSample->get_sample_rate() == pAudioOutput->getSampleRate()){
		//No resampling	
		__playBackSamplePosition = pAudioOutput->m_transport.m_nFrames;
	
		nAvail_bytes = pSample->get_frames() - ( int )__playBackSamplePosition;
		
		if ( nAvail_bytes > nBufferSize ) {
			nAvail_bytes = nBufferSize;
		}

		int nInitialSamplePos = ( int ) __playBackSamplePosition;
		int nSamplePos = nInitialSamplePos;
	
		int nTimes = nInitialBufferPos + nAvail_bytes;
	
		if(__playBackSamplePosition > pSample->get_frames()){
			//playback track has ended..
			return true;
		}
	
		for ( int nBufferPos = nInitialBufferPos; nBufferPos < nTimes; ++nBufferPos ) {
			fVal_L = pSample_data_L[ nSamplePos ];
			fVal_R = pSample_data_R[ nSamplePos ];
	
			fVal_L = fVal_L * 1.0f * pSong->get_playback_track_volume(); //costr
			fVal_R = fVal_R * 1.0f * pSong->get_playback_track_volume(); //cost l
	
			//pDrumCompo->set_outs( nBufferPos, fVal_L, fVal_R );
	
			// to main mix
			if ( fVal_L > fInstrPeak_L ) {
				fInstrPeak_L = fVal_L;
			}
			if ( fVal_R > fInstrPeak_R ) {
				fInstrPeak_R = fVal_R;
			}
			
			__main_out_L[nBufferPos] += fVal_L;
			__main_out_R[nBufferPos] += fVal_R;
			
			++nSamplePos;
		}
	} else {
		//Perform resampling
		double	fSamplePos = 0;
		int		nSampleFrames = pSample->get_frames();
		float	fStep = 1.0594630943593;
		fStep *= ( float )pSample->get_sample_rate() / pAudioOutput->getSampleRate(); // Adjust for audio driver sample rate
		
		
		if(pAudioOutput->m_transport.m_nFrames == 0){
			fSamplePos = 0;
		} else {
			fSamplePos = ( (pAudioOutput->m_transport.m_nFrames/nBufferSize) * (nBufferSize * fStep));
		}
		
		nAvail_bytes = ( int )( ( float )( pSample->get_frames() - fSamplePos ) / fStep );
	
		if ( nAvail_bytes > nBufferSize ) {
			nAvail_bytes = nBufferSize;
		}

		int nTimes = nInitialBufferPos + nAvail_bytes;
	
		for ( int nBufferPos = nInitialBufferPos; nBufferPos < nTimes; ++nBufferPos ) {
			int nSamplePos = ( int ) fSamplePos;
			double fDiff = fSamplePos - nSamplePos;
			if ( ( nSamplePos + 1 ) >= nSampleFrames ) {
				//we reach the last audioframe.
				//set this last frame to zero do nothin wrong.
							fVal_L = 0.0;
							fVal_R = 0.0;
			} else {
				// some interpolation methods need 4 frames data.
					float last_l;
					float last_r;
					if ( ( nSamplePos + 2 ) >= nSampleFrames ) {
						last_l = 0.0;
						last_r = 0.0;
					} else {
						last_l =  pSample_data_L[nSamplePos + 2];
						last_r =  pSample_data_R[nSamplePos + 2];
					}
	
					switch( __interpolateMode ){
	
							case LINEAR:
									fVal_L = pSample_data_L[nSamplePos] * (1 - fDiff ) + pSample_data_L[nSamplePos + 1] * fDiff;
									fVal_R = pSample_data_R[nSamplePos] * (1 - fDiff ) + pSample_data_R[nSamplePos + 1] * fDiff;
									break;
							case COSINE:
									fVal_L = cosine_Interpolate( pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], fDiff);
									fVal_R = cosine_Interpolate( pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], fDiff);
									break;
							case THIRD:
									fVal_L = third_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff);
									fVal_R = third_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff);
									break;
							case CUBIC:
									fVal_L = cubic_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff);
									fVal_R = cubic_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff);
									break;
							case HERMITE:
									fVal_L = hermite_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff);
									fVal_R = hermite_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff);
									break;
					}
			}
			
			if ( fVal_L > fInstrPeak_L ) {
				fInstrPeak_L = fVal_L;
			}
			if ( fVal_R > fInstrPeak_R ) {
				fInstrPeak_R = fVal_R;
			}

			__main_out_L[nBufferPos] += fVal_L;
			__main_out_R[nBufferPos] += fVal_R;


			fSamplePos += fStep;
		} //for
	}
	
	__playback_instrument->set_peak_l( fInstrPeak_L );
	__playback_instrument->set_peak_r( fInstrPeak_R );

	return true;
}
Exemple #11
0
/// Render a note
/// Return false: the note is not ended
/// Return true: the note is ended
bool Sampler::__render_note( Note* pNote, unsigned nBufferSize, Song* pSong )
{
	//infoLog( "[renderNote] instr: " + pNote->getInstrument()->m_sName );
	assert( pSong );

	unsigned int nFramepos;
	Hydrogen* pEngine = Hydrogen::get_instance();
	AudioOutput* audio_output = pEngine->getAudioOutput();
	if (  pEngine->getState() == STATE_PLAYING ) {
		nFramepos = audio_output->m_transport.m_nFrames;
	} else {
		// use this to support realtime events when not playing
		nFramepos = pEngine->getRealtimeFrames();
	}

	Instrument *pInstr = pNote->get_instrument();
	if ( !pInstr ) {
		ERRORLOG( "NULL instrument" );
		return 1;
	}

	bool nReturnValues [pInstr->get_components()->size()];
	
	for(int i = 0; i < pInstr->get_components()->size(); i++){
		nReturnValues[i] = false;
	}
	
	int nReturnValueIndex = 0;
	int nAlreadySelectedLayer = -1;

	for (std::vector<InstrumentComponent*>::iterator it = pInstr->get_components()->begin() ; it !=pInstr->get_components()->end(); ++it) {
		nReturnValues[nReturnValueIndex] = false;
		InstrumentComponent *pCompo = *it;
		DrumkitComponent* pMainCompo = pEngine->getSong()->get_component( pCompo->get_drumkit_componentID() );

		if( pNote->get_specific_compo_id() != -1 && pNote->get_specific_compo_id() != pCompo->get_drumkit_componentID() )
			continue;

		if(		pInstr->is_preview_instrument()
			||	pInstr->is_metronome_instrument()){
			pMainCompo = pEngine->getSong()->get_components()->front();
		} else {
			pMainCompo = pEngine->getSong()->get_component( pCompo->get_drumkit_componentID() );
		}

		assert(pMainCompo);

		float fLayerGain = 1.0;
		float fLayerPitch = 0.0;

		// scelgo il sample da usare in base alla velocity
		Sample *pSample = nullptr;
		SelectedLayerInfo *pSelectedLayer = pNote->get_layer_selected( pCompo->get_drumkit_componentID() );

		if ( !pSelectedLayer ) {
			QString dummy = QString( "NULL Layer Information for instrument %1. Component: %2" ).arg( pInstr->get_name() ).arg( pCompo->get_drumkit_componentID() );
			WARNINGLOG( dummy );
			nReturnValues[nReturnValueIndex] = true;
			continue;
		}

		if( pSelectedLayer->SelectedLayer != -1 ) {
			InstrumentLayer *pLayer = pCompo->get_layer( pSelectedLayer->SelectedLayer );

			if( pLayer )
			{
				pSample = pLayer->get_sample();
				fLayerGain = pLayer->get_gain();
				fLayerPitch = pLayer->get_pitch();
			}
			
		}
		else {
			switch ( pInstr->sample_selection_alg() ) {
				case Instrument::VELOCITY:
					for ( unsigned nLayer = 0; nLayer < __maxLayers; ++nLayer ) {
						InstrumentLayer *pLayer = pCompo->get_layer( nLayer );
						if ( pLayer == NULL ) continue;

						if ( ( pNote->get_velocity() >= pLayer->get_start_velocity() ) && ( pNote->get_velocity() <= pLayer->get_end_velocity() ) ) {
							pSelectedLayer->SelectedLayer = nLayer;

							pSample = pLayer->get_sample();
							fLayerGain = pLayer->get_gain();
							fLayerPitch = pLayer->get_pitch();
							break;
						}
					}
					break;

				case Instrument::RANDOM:
					if( nAlreadySelectedLayer != -1 ) {
						InstrumentLayer *pLayer = pCompo->get_layer( nAlreadySelectedLayer );
						if ( pLayer != NULL ) {
							pSelectedLayer->SelectedLayer = nAlreadySelectedLayer;

							pSample = pLayer->get_sample();
							fLayerGain = pLayer->get_gain();
							fLayerPitch = pLayer->get_pitch();
						}
					}
					if( pSample == NULL ) {
						int __possibleIndex[ __maxLayers ];
						int __poundSamples = 0;
						for ( unsigned nLayer = 0; nLayer < __maxLayers; ++nLayer ) {
							InstrumentLayer *pLayer = pCompo->get_layer( nLayer );
							if ( pLayer == NULL ) continue;

							if ( ( pNote->get_velocity() >= pLayer->get_start_velocity() ) && ( pNote->get_velocity() <= pLayer->get_end_velocity() ) ) {
								__possibleIndex[__poundSamples] = nLayer;
								__poundSamples++;
							}
						}

						if( __poundSamples > 0 ) {
							nAlreadySelectedLayer = __possibleIndex[rand() % __poundSamples];
							pSelectedLayer->SelectedLayer = nAlreadySelectedLayer;

							InstrumentLayer *pLayer = pCompo->get_layer( nAlreadySelectedLayer );

							pSample = pLayer->get_sample();
							fLayerGain = pLayer->get_gain();
							fLayerPitch = pLayer->get_pitch();
						}
					}
					break;

				case Instrument::ROUND_ROBIN:
					if( nAlreadySelectedLayer != -1 ) {
						InstrumentLayer *pLayer = pCompo->get_layer( nAlreadySelectedLayer );
						if ( pLayer != NULL ) {
							pSelectedLayer->SelectedLayer = nAlreadySelectedLayer;

							pSample = pLayer->get_sample();
							fLayerGain = pLayer->get_gain();
							fLayerPitch = pLayer->get_pitch();
						}
					}
					if( !pSample ) {
						int __possibleIndex[ __maxLayers ];
						int __foundSamples = 0;
						float __roundRobinID;
						for ( unsigned nLayer = 0; nLayer < __maxLayers; ++nLayer ) {
							InstrumentLayer *pLayer = pCompo->get_layer( nLayer );
							if ( pLayer == NULL ) continue;

							if ( ( pNote->get_velocity() >= pLayer->get_start_velocity() ) && ( pNote->get_velocity() <= pLayer->get_end_velocity() ) ) {
								__possibleIndex[__foundSamples] = nLayer;
								__roundRobinID = pLayer->get_start_velocity();
								__foundSamples++;
							}
						}

						if( __foundSamples > 0 ) {
							__roundRobinID = pInstr->get_id() * 10 + __roundRobinID;
							int p_indexToUse = pSong->get_latest_round_robin(__roundRobinID)+1;
							if( p_indexToUse > __foundSamples - 1)
								p_indexToUse = 0;

							pSong->set_latest_round_robin(__roundRobinID, p_indexToUse);
							nAlreadySelectedLayer = __possibleIndex[p_indexToUse];

							pSelectedLayer->SelectedLayer = nAlreadySelectedLayer;

							InstrumentLayer *pLayer = pCompo->get_layer( nAlreadySelectedLayer );
							pSample = pLayer->get_sample();
							fLayerGain = pLayer->get_gain();
							fLayerPitch = pLayer->get_pitch();
						}
					}
					break;
			}
		}
		if ( !pSample ) {
			QString dummy = QString( "NULL sample for instrument %1. Note velocity: %2" ).arg( pInstr->get_name() ).arg( pNote->get_velocity() );
			WARNINGLOG( dummy );
			nReturnValues[nReturnValueIndex] = true;
			continue;
		}

		if ( pSelectedLayer->SamplePosition >= pSample->get_frames() ) {
			WARNINGLOG( "sample position out of bounds. The layer has been resized during note play?" );
			nReturnValues[nReturnValueIndex] = true;
			continue;
		}

		int noteStartInFrames = ( int ) ( pNote->get_position() * audio_output->m_transport.m_nTickSize ) + pNote->get_humanize_delay();

		int nInitialSilence = 0;
		if ( noteStartInFrames > ( int ) nFramepos ) {	// scrivo silenzio prima dell'inizio della nota
			nInitialSilence = noteStartInFrames - nFramepos;
			int nFrames = nBufferSize - nInitialSilence;
			if ( nFrames < 0 ) {
				int noteStartInFramesNoHumanize = ( int )pNote->get_position() * audio_output->m_transport.m_nTickSize;
				if ( noteStartInFramesNoHumanize > ( int )( nFramepos + nBufferSize ) ) {
					// this note is not valid. it's in the future...let's skip it....
					ERRORLOG( QString( "Note pos in the future?? Current frames: %1, note frame pos: %2" ).arg( nFramepos ).arg(noteStartInFramesNoHumanize ) );
					//pNote->dumpInfo();
					nReturnValues[nReturnValueIndex] = true;
					continue;
				}
				// delay note execution
				//INFOLOG( "Delaying note execution. noteStartInFrames: " + to_string( noteStartInFrames ) + ", nFramePos: " + to_string( nFramepos ) );
				//return 0;
				continue;
			}
		}

		float cost_L = 1.0f;
		float cost_R = 1.0f;
		float cost_track_L = 1.0f;
		float cost_track_R = 1.0f;

		assert(pMainCompo);
		
		bool isMutedForExport = (pEngine->getIsExportSessionActive() && !pInstr->is_currently_exported());
		
		/*
		 *  Is instrument muted?
		 *
		 *  This can be the case either if the song, instrument or component is muted or if we're in an
		 *  export session and we're doing per-instruments exports, but this instrument is not currently
		 *  beeing exported.
		 */
		if ( isMutedForExport || pInstr->is_muted() || pSong->__is_muted || pMainCompo->is_muted() ) {	
			cost_L = 0.0;
			cost_R = 0.0;
			if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) {
				// Post-Fader
				cost_track_L = 0.0;
				cost_track_R = 0.0;
			}

		} else {	// Precompute some values...
			if ( pInstr->get_apply_velocity() ) {
				cost_L = cost_L * pNote->get_velocity();		// note velocity
				cost_R = cost_R * pNote->get_velocity();		// note velocity
			}
			cost_L = cost_L * pNote->get_pan_l();		// note pan
			cost_L = cost_L * fLayerGain;				// layer gain
			cost_L = cost_L * pInstr->get_pan_l();		// instrument pan
			cost_L = cost_L * pInstr->get_gain();		// instrument gain

			cost_L = cost_L * pCompo->get_gain();		// Component gain
			cost_L = cost_L * pMainCompo->get_volume(); // Component volument

			cost_L = cost_L * pInstr->get_volume();		// instrument volume
			if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) {
			// Post-Fader
			cost_track_L = cost_L * 2;
			}
			cost_L = cost_L * pSong->get_volume();	// song volume
			cost_L = cost_L * 2; // max pan is 0.5

			cost_R = cost_R * pNote->get_pan_r();		// note pan
			cost_R = cost_R * fLayerGain;				// layer gain
			cost_R = cost_R * pInstr->get_pan_r();		// instrument pan
			cost_R = cost_R * pInstr->get_gain();		// instrument gain

			cost_R = cost_R * pCompo->get_gain();		// Component gain
			cost_R = cost_R * pMainCompo->get_volume(); // Component volument

			cost_R = cost_R * pInstr->get_volume();		// instrument volume
			if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) {
			// Post-Fader
			cost_track_R = cost_R * 2;
			}
			cost_R = cost_R * pSong->get_volume();	// song pan
			cost_R = cost_R * 2; // max pan is 0.5
		}

		// direct track outputs only use velocity
		if ( Preferences::get_instance()->m_nJackTrackOutputMode == 1 ) {
			cost_track_L = cost_track_L * pNote->get_velocity();
			cost_track_L = cost_track_L * fLayerGain;
			cost_track_R = cost_track_L;
		}

		// Se non devo fare resample (drumkit) posso evitare di utilizzare i float e gestire il tutto in
		// maniera ottimizzata
		//	constant^12 = 2, so constant = 2^(1/12) = 1.059463.
		//	float nStep = 1.0;1.0594630943593

		float fTotalPitch = pNote->get_total_pitch() + fLayerPitch;

		//_INFOLOG( "total pitch: " + to_string( fTotalPitch ) );
		if( ( int )pSelectedLayer->SamplePosition == 0 )
		{
			if( Hydrogen::get_instance()->getMidiOutput() != NULL ){
			Hydrogen::get_instance()->getMidiOutput()->handleQueueNote( pNote );
			}
		}

		if ( fTotalPitch == 0.0 && pSample->get_sample_rate() == audio_output->getSampleRate() ) // NO RESAMPLE
			nReturnValues[nReturnValueIndex] = __render_note_no_resample( pSample, pNote, pSelectedLayer, pCompo, pMainCompo, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, pSong );
		else // RESAMPLE
			nReturnValues[nReturnValueIndex] = __render_note_resample( pSample, pNote, pSelectedLayer, pCompo, pMainCompo, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, fLayerPitch, pSong );

		nReturnValueIndex++;
	}
	for ( unsigned i = 0 ; i < pInstr->get_components()->size() ; i++ )
		if ( !nReturnValues[i] ) return false;
	return true;
}
Exemple #12
0
void PlaylistDialog::on_m_pPlaylistTree_itemDoubleClicked ()
{

	QTreeWidgetItem* m_pPlaylistItem = m_pPlaylistTree->currentItem();
	if ( m_pPlaylistItem == NULL ){
		QMessageBox::information ( this, "Hydrogen", trUtf8 ( "No Song selected!" ) );
		return;
	}
	QString selected;
	selected = m_pPlaylistItem->text ( 0 );

	QTreeWidget* m_pPlaylist = m_pPlaylistTree;
	int index = m_pPlaylist->indexOfTopLevelItem ( m_pPlaylistItem );
	Playlist::get_instance()->setSelectedSongNr( index );
	Playlist::get_instance()->setActiveSongNumber( index );

	HydrogenApp *pH2App = HydrogenApp::get_instance();
	Hydrogen *pEngine = Hydrogen::get_instance();


	if ( pEngine->getState() == STATE_PLAYING ){
		pEngine->sequencer_stop();
	}

	m_pPlayBtn->setPressed(false);

	Timeline* pTimeline = pEngine->getTimeline();
	pTimeline->m_timelinetagvector.clear();

	Song *pSong = Song::load ( selected );
	if ( pSong == NULL ){
		QMessageBox::information ( this, "Hydrogen", trUtf8 ( "Error loading song." ) );
		return;
	}

	pH2App->setSong ( pSong );
	pEngine->setSelectedPatternNumber ( 0 );

	HydrogenApp::get_instance()->getSongEditorPanel()->updatePositionRuler();
	pH2App->setStatusBarMessage( trUtf8( "Playlist: set song no. %1" ).arg( index +1 ), 5000 );

	HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->update_background_color();

	EventQueue::get_instance()->push_event( EVENT_METRONOME, 3 );

///exec script
///this is very very simple and only an experiment
#ifdef WIN32
	//I know nothing about windows scripts -wolke-
	return;
#else
	QString execscript;
	selected = m_pPlaylistItem->text ( 1 );
	bool execcheckbox = m_pPlaylistItem->checkState ( 2 );

	if( execcheckbox == false){
		//QMessageBox::information ( this, "Hydrogen", trUtf8 ( "No Script selected!" ));
		return;
	}

	if( execscript == "Script not used"){
		//QMessageBox::information ( this, "Hydrogen", trUtf8 ( "Script not in use!" ));
		return;
	}

	char *file;
	file = new char[ selected.length() + 1 ];
	strcpy( file , selected.toAscii() );
	int ret = std::system( file );
	delete [] file;
	return;
#endif

}