コード例 #1
0
ファイル: note_test.cpp プロジェクト: blablack/hydrogen
	void testSerializeProbability()
	{
		QDomDocument doc;
		QDomElement root = doc.createElement("note");
		XMLNode node(root);

		InstrumentList *instruments = new InstrumentList();
		Instrument *snare = new Instrument( 1, "Snare", nullptr );
		instruments->add( snare );

		Note *in = new Note(snare, 0, 1.0f, 0.5f, 0.5f, 1, 1.0f);
		in->set_probability(0.67f);
		in->save_to(&node);

		Note *out = Note::load_from(&node, instruments);

		CPPUNIT_ASSERT(in->get_instrument() == out->get_instrument());
		CPPUNIT_ASSERT_EQUAL(in->get_position(), out->get_position());
		CPPUNIT_ASSERT_EQUAL(in->get_velocity(), out->get_velocity());
		CPPUNIT_ASSERT_EQUAL(in->get_pan_l(), out->get_pan_l());
		CPPUNIT_ASSERT_EQUAL(in->get_pan_r(), out->get_pan_r());
		CPPUNIT_ASSERT_EQUAL(in->get_length(), out->get_length());
		CPPUNIT_ASSERT_EQUAL(in->get_pitch(), out->get_pitch());
		CPPUNIT_ASSERT_EQUAL(in->get_probability(), out->get_probability());

		/*
		FIXME: this causes double free
		delete in;
		delete out;
		delete instruments;
		delete snare;
		*/
	}
コード例 #2
0
ファイル: pattern.cpp プロジェクト: hydrogen-music/hydrogen
Note* Pattern::find_note( int idx_a, int idx_b, Instrument* instrument, bool strict ) const
{
	notes_cst_it_t it;
	for( it=__notes.lower_bound( idx_a ); it!=__notes.upper_bound( idx_a ); it++ ) {
		Note* note = it->second;
		assert( note );
		if ( note->get_instrument() == instrument ) return note;
	}
	if( idx_b==-1 ) return 0;
	for( it=__notes.lower_bound( idx_b ); it!=__notes.upper_bound( idx_b ); it++ ) {
		Note* note = it->second;
		assert( note );
		if ( note->get_instrument() == instrument ) return note;
	}
	if ( strict ) return 0;
	// TODO maybe not start from 0 but idx_b-X
	for ( int n=0; n<idx_b; n++ ) {
		for( it=__notes.lower_bound( n ); it!=__notes.upper_bound( n ); it++ ) {
			Note* note = it->second;
			assert( note );
			if ( note->get_instrument() == instrument && ( ( idx_b<=note->get_position()+note->get_length() ) && idx_b>=note->get_position() ) ) return note;
		}
	}

	return 0;
}
コード例 #3
0
ファイル: sampler.cpp プロジェクト: GregoryBonik/hydrogen
void Sampler::stop_playing_notes( Instrument* instrument )
{
	/*
	// send a note-off event to all notes present in the playing note queue
	for ( int i = 0; i < __playing_notes_queue.size(); ++i ) {
		Note *pNote = __playing_notes_queue[ i ];
		pNote->m_pADSR->release();
	}
	*/

	if ( instrument ) { // stop all notes using this instrument
		for ( unsigned i = 0; i < __playing_notes_queue.size(); ) {
			Note *pNote = __playing_notes_queue[ i ];
			assert( pNote );
			if ( pNote->get_instrument() == instrument ) {
				delete pNote;
				instrument->dequeue();
				__playing_notes_queue.erase( __playing_notes_queue.begin() + i );
			}
			++i;
		}
	} else { // stop all notes
		// delete all copied notes in the playing notes queue
		for ( unsigned i = 0; i < __playing_notes_queue.size(); ++i ) {
			Note *pNote = __playing_notes_queue[i];
			pNote->get_instrument()->dequeue();
			delete pNote;
		}
		__playing_notes_queue.clear();
	}
}
コード例 #4
0
ファイル: sampler.cpp プロジェクト: wolkstein/hydrogen
// perche' viene passata anche la canzone? E' davvero necessaria?
void Sampler::process( uint32_t nFrames, Song* pSong )
{
	//infoLog( "[process]" );
	AudioOutput* audio_output = Hydrogen::get_instance()->getAudioOutput();
	assert( audio_output );

	memset( __main_out_L, 0, nFrames * sizeof( float ) );
	memset( __main_out_R, 0, nFrames * sizeof( float ) );

	// Track output queues are zeroed by
	// audioEngine_process_clearAudioBuffers()

	// Max notes limit
	int m_nMaxNotes = Preferences::get_instance()->m_nMaxNotes;
	while ( ( int )__playing_notes_queue.size() > m_nMaxNotes ) {
		Note *oldNote = __playing_notes_queue[ 0 ];
		__playing_notes_queue.erase( __playing_notes_queue.begin() );
		oldNote->get_instrument()->dequeue();
		delete oldNote;	// FIXME: send note-off instead of removing the note from the list?
	}

	for (std::vector<DrumkitComponent*>::iterator it = pSong->get_components()->begin() ; it != pSong->get_components()->end(); ++it) {
		DrumkitComponent* component = *it;
		component->reset_outs(nFrames);
	}


	// eseguo tutte le note nella lista di note in esecuzione
	unsigned i = 0;
	Note* pNote;
	while ( i < __playing_notes_queue.size() ) {
		pNote = __playing_notes_queue[ i ];		// recupero una nuova nota
		if ( __render_note( pNote, nFrames, pSong ) ) {	// la nota e' finita
			__playing_notes_queue.erase( __playing_notes_queue.begin() + i );
			pNote->get_instrument()->dequeue();
			__queuedNoteOffs.push_back( pNote );
//			delete pNote;
//			pNote = NULL;
		} else {
			++i; // carico la prox nota
		}
	}

	//Queue midi note off messages for notes that have a length specified for them

	while ( !__queuedNoteOffs.empty() ) {
		pNote =  __queuedNoteOffs[0];
		MidiOutput* midiOut = Hydrogen::get_instance()->getMidiOutput();
		if( midiOut != NULL ){
			midiOut->handleQueueNoteOff( pNote->get_instrument()->get_midi_out_channel(), pNote->get_midi_key(),  pNote->get_midi_velocity() );

		}
		__queuedNoteOffs.erase( __queuedNoteOffs.begin() );
		if( pNote != NULL) delete pNote;
		pNote = NULL;
	}//while

	processPlaybackTrack(nFrames);
}
コード例 #5
0
ファイル: pattern.cpp プロジェクト: hydrogen-music/hydrogen
void Pattern::purge_instrument( Instrument* instr )
{
	bool locked = false;
	std::list< Note* > slate;
	for( notes_it_t it=__notes.begin(); it!=__notes.end(); ) {
		Note* note = it->second;
		assert( note );
		if ( note->get_instrument() == instr ) {
			if ( !locked ) {
				H2Core::AudioEngine::get_instance()->lock( RIGHT_HERE );
				locked = true;
			}
			slate.push_back( note );
			__notes.erase( it++ );
		} else {
			++it;
		}
	}
	if ( locked ) {
		H2Core::AudioEngine::get_instance()->unlock();
		while ( slate.size() ) {
			delete slate.front();
			slate.pop_front();
		}
	}
}
コード例 #6
0
ファイル: sampler.cpp プロジェクト: heng-O/hydrogen
void Sampler::note_on( Note *note )
{
	//infoLog( "[noteOn]" );
	assert( note );

		note->get_adsr()->attack();
	Instrument *pInstr = note->get_instrument();

	// mute group
	int mute_grp = pInstr->get_mute_group();
	if ( mute_grp != -1 ) {
		// remove all notes using the same mute group
		for ( unsigned j = 0; j < __playing_notes_queue.size(); j++ ) {	// delete older note
			Note *pNote = __playing_notes_queue[ j ];
			if ( ( pNote->get_instrument() != pInstr )  && ( pNote->get_instrument()->get_mute_group() == mute_grp ) ) {
								pNote->get_adsr()->release();
			}
		}
	}

	//note off notes
	if( note->get_note_off() ){
		for ( unsigned j = 0; j < __playing_notes_queue.size(); j++ ) {
			Note *pNote = __playing_notes_queue[ j ];

			if ( ( pNote->get_instrument() == pInstr ) ) {
				//ERRORLOG("note_off");
								pNote->get_adsr()->release();
			}
		}
	}

	pInstr->enqueue();
	if( !note->get_note_off() ){
		__playing_notes_queue.push_back( note );
	} else {
		delete note;
	}

		if( Hydrogen::get_instance()->getMidiOutput() != NULL ){
		Hydrogen::get_instance()->getMidiOutput()->handleQueueNote( note );
	}

}
コード例 #7
0
ファイル: pattern.cpp プロジェクト: hydrogen-music/hydrogen
bool Pattern::references( Instrument* instr )
{
	for( notes_cst_it_t it=__notes.begin(); it!=__notes.end(); it++ ) {
		Note* note = it->second;
		assert( note );
		if ( note->get_instrument() == instr ) {
			return true;
		}
	}
	return false;
}
コード例 #8
0
ファイル: sampler.cpp プロジェクト: heng-O/hydrogen
void Sampler::note_off( Note* note )
	/*
	* this old note_off function is only used by right click on mixer channel strip play button
	* all other note_off stuff will handle in midi_keyboard_note_off() and note_on()
	*/
{

	Instrument *pInstr = note->get_instrument();
	// find the notes using the same instrument, and release them
	for ( unsigned j = 0; j < __playing_notes_queue.size(); j++ ) {
		Note *pNote = __playing_notes_queue[ j ];
		if ( pNote->get_instrument() == pInstr ) {
						pNote->get_adsr()->release();
		}
	}
}
コード例 #9
0
void InstrumentLine::functionClearNotes()
{
	Hydrogen * pEngine = Hydrogen::get_instance();
	int selectedPatternNr = pEngine->getSelectedPatternNumber();
	Pattern *pPattern = getCurrentPattern();
	Instrument *pSelectedInstrument = pEngine->getSong()->get_instrument_list()->get( m_nInstrumentNumber );

	std::list< Note* > noteList;
    const Pattern::notes_t* notes = pPattern->get_notes();
    FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) {
		Note *pNote = it->second;
		assert( pNote );
		if ( pNote->get_instrument() == pSelectedInstrument ) {
			noteList.push_back( pNote );
		}
	}
コード例 #10
0
ファイル: pattern.cpp プロジェクト: hydrogen-music/hydrogen
void Pattern::save_to( XMLNode* node, const Instrument* instrumentOnly ) const
{
	XMLNode pattern_node =  node->createNode( "pattern" );
	pattern_node.write_string( "name", __name );
	pattern_node.write_string( "info", __info );
	pattern_node.write_string( "category", __category );
	pattern_node.write_int( "size", __length );
	XMLNode note_list_node =  pattern_node.createNode( "noteList" );
	int id = ( instrumentOnly == 0 ? -1 : instrumentOnly->get_id() );
	for( auto it=__notes.cbegin(); it!=__notes.cend(); ++it ) {
		Note* note = it->second;
		if( note && ( instrumentOnly == 0 || note->get_instrument()->get_id() == id ) ) {
			XMLNode note_node = note_list_node.createNode( "note" );
			note->save_to( &note_node );
		}
	}
}
コード例 #11
0
ファイル: MainForm.cpp プロジェクト: draekko/hydrogen
void MainForm::functionDeleteInstrument(int instrument)
{
	Hydrogen * H = Hydrogen::get_instance();
	Instrument *pSelectedInstrument = H->getSong()->get_instrument_list()->get( instrument );

	std::list< Note* > noteList;
	Song* song = H->getSong();
	PatternList *patList = song->get_pattern_list();

	QString instrumentName =  pSelectedInstrument->get_name();
	QString drumkitName = H->getCurrentDrumkitname();

	for ( int i = 0; i < patList->size(); i++ ) {
		H2Core::Pattern *pPattern = song->get_pattern_list()->get(i);
		const Pattern::notes_t* notes = pPattern->get_notes();
		FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) {
			Note *pNote = it->second;
			assert( pNote );
			if ( pNote->get_instrument() == pSelectedInstrument ) {
				pNote->set_pattern_idx( i );
				noteList.push_back( pNote );
			}
		}
	}
コード例 #12
0
ファイル: smf.cpp プロジェクト: hydrogen-music/hydrogen
void SMFWriter::save( const QString& sFilename, Song *pSong )
{
	INFOLOG( "save" );
	const int DRUM_CHANNEL = 9;

	vector<SMFEvent*> eventList;

	SMF smf;


	// Standard MIDI format 1 files should have the first track being the tempo map
	// which is a track that contains global meta events only.
	SMFTrack *pTrack0 = new SMFTrack();
	pTrack0->addEvent( new SMFCopyRightNoticeMetaEvent( pSong->__author , 0 ) );
	pTrack0->addEvent( new SMFTrackNameMetaEvent( pSong->__name , 0 ) );
	pTrack0->addEvent( new SMFSetTempoMetaEvent( pSong->__bpm , 0 ) );
	pTrack0->addEvent( new SMFTimeSignatureMetaEvent( 4 , 4 , 24 , 8 , 0 ) );
	smf.addTrack( pTrack0 );

	
	// Standard MIDI Format 1 files should have note events in tracks =>2
	SMFTrack *pTrack1 = new SMFTrack();
	smf.addTrack( pTrack1 );

	AutomationPath *vp = pSong->get_velocity_automation_path();

	InstrumentList *iList = pSong->get_instrument_list();
	// ogni pattern sara' una diversa traccia
	int nTick = 1;
	for ( unsigned nPatternList = 0 ;
		  nPatternList < pSong->get_pattern_group_vector()->size() ;
		  nPatternList++ ) {
		// infoLog( "[save] pattern list pos: " + toString( nPatternList ) );
		PatternList *pPatternList =
			( *(pSong->get_pattern_group_vector()) )[ nPatternList ];

		int nStartTicks = nTick;
		int nMaxPatternLength = 0;
		for ( unsigned nPattern = 0 ;
			  nPattern < pPatternList->size() ;
			  nPattern++ ) {
			Pattern *pPattern = pPatternList->get( nPattern );
			// infoLog( "      |-> pattern: " + pPattern->getName() );
			if ( ( int )pPattern->get_length() > nMaxPatternLength ) {
				nMaxPatternLength = pPattern->get_length();
			}

			for ( unsigned nNote = 0; nNote < pPattern->get_length(); nNote++ ) {
				const Pattern::notes_t* notes = pPattern->get_notes();
				FOREACH_NOTE_CST_IT_BOUND(notes,it,nNote) {
					Note *pNote = it->second;
					if ( pNote ) {
						float rnd = (float)rand()/(float)RAND_MAX;
						if ( pNote->get_probability() < rnd ) {
							continue;
						}

						float fPos = nPatternList + (float)nNote/(float)nMaxPatternLength;
						float velocity_adjustment = vp->get_value(fPos);
						int nVelocity =
							(int)( 127.0 * pNote->get_velocity() * velocity_adjustment );
						
						int nInstr = iList->index(pNote->get_instrument());
						Instrument *pInstr = pNote->get_instrument();
						int nPitch = pNote->get_midi_key();
						
						eventList.push_back(
							new SMFNoteOnEvent(
								nStartTicks + nNote,
								DRUM_CHANNEL,
								nPitch,
								nVelocity
								)
							);
						int nLength = 12;
						if ( pNote->get_length() != -1 ) {
							nLength = pNote->get_length();
						}
						eventList.push_back(
							new SMFNoteOffEvent(
								nStartTicks + nNote + nLength,
								DRUM_CHANNEL,
								nPitch,
								nVelocity
								)
							);
					}
				}
			}
		}
		nTick += nMaxPatternLength;
	}
コード例 #13
0
ファイル: sampler.cpp プロジェクト: GregoryBonik/hydrogen
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
								}
							}
						}
					}
				}
			}
		}
コード例 #14
0
ファイル: local_file_mgr.cpp プロジェクト: ju1ius/hydrogen
QString LocalFileMng::copyInstrumentLineToString(Song *song, int selectedPattern, int selectedInstrument)
{
	Instrument *instr = song->get_instrument_list()->get( selectedInstrument );
	assert( instr );

	QDomDocument doc;
	QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"");
	doc.appendChild( header );

	QDomNode rootNode = doc.createElement( "instrument_line" );
	//LIB_ID just in work to get better usability
	//writeXmlString( &rootNode, "LIB_ID", "in_work" );
	writeXmlString( rootNode, "author", song->get_author() );
	writeXmlString( rootNode, "license", song->get_license() );

	QDomNode patternList = doc.createElement( "patternList" );

	unsigned nPatterns = song->get_pattern_list()->size();
	for ( unsigned i = 0; i < nPatterns; i++ )
	{
		if ((selectedPattern >= 0) && (selectedPattern != i))
			continue;

		// Export pattern
		Pattern *pat = song->get_pattern_list()->get( i );

		QDomNode patternNode = doc.createElement( "pattern" );
		writeXmlString( patternNode, "pattern_name", pat->get_name() );

		QString category;
		if ( pat->get_category().isEmpty() )
			category = "No category";
		else
			category = pat->get_category();

		writeXmlString( patternNode, "info", pat->get_info() );
		writeXmlString( patternNode, "category", category  );
		writeXmlString( patternNode, "size", QString("%1").arg( pat->get_length() ) );

		QDomNode noteListNode = doc.createElement( "noteList" );
		const Pattern::notes_t* notes = pat->get_notes();
		FOREACH_NOTE_CST_IT_BEGIN_END(notes,it)
		{
			Note *pNote = it->second;
			assert( pNote );

			// Export only specified instrument
			if (pNote->get_instrument() == instr)
			{
				QDomNode noteNode = doc.createElement( "note" );
				writeXmlString( noteNode, "position", QString("%1").arg( pNote->get_position() ) );
				writeXmlString( noteNode, "leadlag", QString("%1").arg( pNote->get_lead_lag() ) );
				writeXmlString( noteNode, "velocity", QString("%1").arg( pNote->get_velocity() ) );
				writeXmlString( noteNode, "pan_L", QString("%1").arg( pNote->get_pan_l() ) );
				writeXmlString( noteNode, "pan_R", QString("%1").arg( pNote->get_pan_r() ) );
				writeXmlString( noteNode, "pitch", QString("%1").arg( pNote->get_pitch() ) );

				writeXmlString( noteNode, "key", pNote->key_to_string() );

				writeXmlString( noteNode, "length", QString("%1").arg( pNote->get_length() ) );
				noteListNode.appendChild( noteNode );
			}
		}
		patternNode.appendChild( noteListNode );

		patternList.appendChild( patternNode );
	}
コード例 #15
0
ファイル: local_file_mgr.cpp プロジェクト: elpescado/hydrogen
// Returns 0 on success, passes the TinyXml error code otherwise.
int SongWriter::writeSong( Song *song, const QString& filename )
{
	INFOLOG( "Saving song " + filename );
	int rv = 0; // return value

	// FIXME: has the file write-permssion?
	// FIXME: verificare che il file non sia gia' esistente
	// FIXME: effettuare copia di backup per il file gia' esistente


	QDomDocument doc;
	QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"");
	doc.appendChild( header );

	QDomNode songNode = doc.createElement( "song" );

	LocalFileMng::writeXmlString( songNode, "version", QString( get_version().c_str() ) );
	LocalFileMng::writeXmlString( songNode, "bpm", QString("%1").arg( song->__bpm ) );
	LocalFileMng::writeXmlString( songNode, "volume", QString("%1").arg( song->get_volume() ) );
	LocalFileMng::writeXmlString( songNode, "metronomeVolume", QString("%1").arg( song->get_metronome_volume() ) );
	LocalFileMng::writeXmlString( songNode, "name", song->__name );
	LocalFileMng::writeXmlString( songNode, "author", song->__author );
	LocalFileMng::writeXmlString( songNode, "notes", song->get_notes() );
	LocalFileMng::writeXmlString( songNode, "license", song->get_license() );
	LocalFileMng::writeXmlBool( songNode, "loopEnabled", song->is_loop_enabled() );
	LocalFileMng::writeXmlBool( songNode, "patternModeMode", Preferences::get_instance()->patternModePlaysSelected());
	
	LocalFileMng::writeXmlString( songNode, "playbackTrackFilename", QString("%1").arg( song->get_playback_track_filename() ) );
	LocalFileMng::writeXmlBool( songNode, "playbackTrackEnabled", song->get_playback_track_enabled() );
	LocalFileMng::writeXmlString( songNode, "playbackTrackVolume", QString("%1").arg( song->get_playback_track_volume() ) );

	
	if ( song->get_mode() == Song::SONG_MODE ) {
		LocalFileMng::writeXmlString( songNode, "mode", QString( "song" ) );
	} else {
		LocalFileMng::writeXmlString( songNode, "mode", QString( "pattern" ) );
	}

	LocalFileMng::writeXmlString( songNode, "humanize_time", QString("%1").arg( song->get_humanize_time_value() ) );
	LocalFileMng::writeXmlString( songNode, "humanize_velocity", QString("%1").arg( song->get_humanize_velocity_value() ) );
	LocalFileMng::writeXmlString( songNode, "swing_factor", QString("%1").arg( song->get_swing_factor() ) );

	// component List
	QDomNode componentListNode = doc.createElement( "componentList" );
	for (std::vector<DrumkitComponent*>::iterator it = song->get_components()->begin() ; it != song->get_components()->end(); ++it) {
		DrumkitComponent* pCompo = *it;

		QDomNode componentNode = doc.createElement( "drumkitComponent" );

		LocalFileMng::writeXmlString( componentNode, "id", QString("%1").arg( pCompo->get_id() ) );
		LocalFileMng::writeXmlString( componentNode, "name", pCompo->get_name() );
		LocalFileMng::writeXmlString( componentNode, "volume", QString("%1").arg( pCompo->get_volume() ) );

		componentListNode.appendChild( componentNode );
	}
	songNode.appendChild( componentListNode );

	// instrument list
	QDomNode instrumentListNode = doc.createElement( "instrumentList" );
	unsigned nInstrument = song->get_instrument_list()->size();

	// INSTRUMENT NODE
	for ( unsigned i = 0; i < nInstrument; i++ ) {
		Instrument *instr = song->get_instrument_list()->get( i );
		assert( instr );

		QDomNode instrumentNode = doc.createElement( "instrument" );

		LocalFileMng::writeXmlString( instrumentNode, "id", QString("%1").arg( instr->get_id() ) );
		LocalFileMng::writeXmlString( instrumentNode, "name", instr->get_name() );
		LocalFileMng::writeXmlString( instrumentNode, "drumkit", instr->get_drumkit_name() );
		LocalFileMng::writeXmlString( instrumentNode, "volume", QString("%1").arg( instr->get_volume() ) );
		LocalFileMng::writeXmlBool( instrumentNode, "isMuted", instr->is_muted() );
		LocalFileMng::writeXmlString( instrumentNode, "pan_L", QString("%1").arg( instr->get_pan_l() ) );
		LocalFileMng::writeXmlString( instrumentNode, "pan_R", QString("%1").arg( instr->get_pan_r() ) );
		LocalFileMng::writeXmlString( instrumentNode, "gain", QString("%1").arg( instr->get_gain() ) );
		LocalFileMng::writeXmlBool( instrumentNode, "applyVelocity", instr->get_apply_velocity() );

		LocalFileMng::writeXmlBool( instrumentNode, "filterActive", instr->is_filter_active() );
		LocalFileMng::writeXmlString( instrumentNode, "filterCutoff", QString("%1").arg( instr->get_filter_cutoff() ) );
		LocalFileMng::writeXmlString( instrumentNode, "filterResonance", QString("%1").arg( instr->get_filter_resonance() ) );

		LocalFileMng::writeXmlString( instrumentNode, "FX1Level", QString("%1").arg( instr->get_fx_level( 0 ) ) );
		LocalFileMng::writeXmlString( instrumentNode, "FX2Level", QString("%1").arg( instr->get_fx_level( 1 ) ) );
		LocalFileMng::writeXmlString( instrumentNode, "FX3Level", QString("%1").arg( instr->get_fx_level( 2 ) ) );
		LocalFileMng::writeXmlString( instrumentNode, "FX4Level", QString("%1").arg( instr->get_fx_level( 3 ) ) );

		assert( instr->get_adsr() );
		LocalFileMng::writeXmlString( instrumentNode, "Attack", QString("%1").arg( instr->get_adsr()->get_attack() ) );
		LocalFileMng::writeXmlString( instrumentNode, "Decay", QString("%1").arg( instr->get_adsr()->get_decay() ) );
		LocalFileMng::writeXmlString( instrumentNode, "Sustain", QString("%1").arg( instr->get_adsr()->get_sustain() ) );
		LocalFileMng::writeXmlString( instrumentNode, "Release", QString("%1").arg( instr->get_adsr()->get_release() ) );

		LocalFileMng::writeXmlString( instrumentNode, "randomPitchFactor", QString("%1").arg( instr->get_random_pitch_factor() ) );

		LocalFileMng::writeXmlString( instrumentNode, "muteGroup", QString("%1").arg( instr->get_mute_group() ) );
		LocalFileMng::writeXmlBool( instrumentNode, "isStopNote", instr->is_stop_notes() );
		switch ( instr->sample_selection_alg() ) {
			case Instrument::VELOCITY:
				LocalFileMng::writeXmlString( instrumentNode, "sampleSelectionAlgo", "VELOCITY" );
				break;
			case Instrument::RANDOM:
				LocalFileMng::writeXmlString( instrumentNode, "sampleSelectionAlgo", "RANDOM" );
				break;
			case Instrument::ROUND_ROBIN:
				LocalFileMng::writeXmlString( instrumentNode, "sampleSelectionAlgo", "ROUND_ROBIN" );
				break;
		}

		LocalFileMng::writeXmlString( instrumentNode, "midiOutChannel", QString("%1").arg( instr->get_midi_out_channel() ) );
		LocalFileMng::writeXmlString( instrumentNode, "midiOutNote", QString("%1").arg( instr->get_midi_out_note() ) );
		LocalFileMng::writeXmlString( instrumentNode, "isHihat", QString("%1").arg( instr->get_hihat_grp() ) );
		LocalFileMng::writeXmlString( instrumentNode, "lower_cc", QString("%1").arg( instr->get_lower_cc() ) );
		LocalFileMng::writeXmlString( instrumentNode, "higher_cc", QString("%1").arg( instr->get_higher_cc() ) );

		for (std::vector<InstrumentComponent*>::iterator it = instr->get_components()->begin() ; it != instr->get_components()->end(); ++it) {
			InstrumentComponent* pComponent = *it;

			QDomNode componentNode = doc.createElement( "instrumentComponent" );

			LocalFileMng::writeXmlString( componentNode, "component_id", QString("%1").arg( pComponent->get_drumkit_componentID() ) );
			LocalFileMng::writeXmlString( componentNode, "gain", QString("%1").arg( pComponent->get_gain() ) );

			for ( unsigned nLayer = 0; nLayer < InstrumentComponent::getMaxLayers(); nLayer++ ) {
				InstrumentLayer *pLayer = pComponent->get_layer( nLayer );

				if ( pLayer == NULL ) continue;
				Sample *pSample = pLayer->get_sample();
				if ( pSample == NULL ) continue;

				bool sIsModified = pSample->get_is_modified();
				Sample::Loops lo = pSample->get_loops();
				Sample::Rubberband ro = pSample->get_rubberband();
				QString sMode = pSample->get_loop_mode_string();


				QDomNode layerNode = doc.createElement( "layer" );
				LocalFileMng::writeXmlString( layerNode, "filename", Filesystem::prepare_sample_path( pSample->get_filepath() ) );
				LocalFileMng::writeXmlBool( layerNode, "ismodified", sIsModified);
				LocalFileMng::writeXmlString( layerNode, "smode", pSample->get_loop_mode_string() );
				LocalFileMng::writeXmlString( layerNode, "startframe", QString("%1").arg( lo.start_frame ) );
				LocalFileMng::writeXmlString( layerNode, "loopframe", QString("%1").arg( lo.loop_frame ) );
				LocalFileMng::writeXmlString( layerNode, "loops", QString("%1").arg( lo.count ) );
				LocalFileMng::writeXmlString( layerNode, "endframe", QString("%1").arg( lo.end_frame ) );
				LocalFileMng::writeXmlString( layerNode, "userubber", QString("%1").arg( ro.use ) );
				LocalFileMng::writeXmlString( layerNode, "rubberdivider", QString("%1").arg( ro.divider ) );
				LocalFileMng::writeXmlString( layerNode, "rubberCsettings", QString("%1").arg( ro.c_settings ) );
				LocalFileMng::writeXmlString( layerNode, "rubberPitch", QString("%1").arg( ro.pitch ) );
				LocalFileMng::writeXmlString( layerNode, "min", QString("%1").arg( pLayer->get_start_velocity() ) );
				LocalFileMng::writeXmlString( layerNode, "max", QString("%1").arg( pLayer->get_end_velocity() ) );
				LocalFileMng::writeXmlString( layerNode, "gain", QString("%1").arg( pLayer->get_gain() ) );
				LocalFileMng::writeXmlString( layerNode, "pitch", QString("%1").arg( pLayer->get_pitch() ) );


				Sample::VelocityEnvelope* velocity = pSample->get_velocity_envelope();
				for (int y = 0; y < velocity->size(); y++){
					QDomNode volumeNode = doc.createElement( "volume" );
					LocalFileMng::writeXmlString( volumeNode, "volume-position", QString("%1").arg( velocity->at(y).frame ) );
					LocalFileMng::writeXmlString( volumeNode, "volume-value", QString("%1").arg( velocity->at(y).value ) );
					layerNode.appendChild( volumeNode );
				}

				Sample::PanEnvelope* pan = pSample->get_pan_envelope();
				for (int y = 0; y < pan->size(); y++){
					QDomNode panNode = doc.createElement( "pan" );
					LocalFileMng::writeXmlString( panNode, "pan-position", QString("%1").arg( pan->at(y).frame ) );
					LocalFileMng::writeXmlString( panNode, "pan-value", QString("%1").arg( pan->at(y).value ) );
					layerNode.appendChild( panNode );
				}

				componentNode.appendChild( layerNode );
			}
			instrumentNode.appendChild( componentNode );
		}

		instrumentListNode.appendChild( instrumentNode );
	}
	songNode.appendChild( instrumentListNode );


	// pattern list
	QDomNode patternListNode = doc.createElement( "patternList" );

	unsigned nPatterns = song->get_pattern_list()->size();
	for ( unsigned i = 0; i < nPatterns; i++ ) {
		Pattern *pat = song->get_pattern_list()->get( i );

		// pattern
		QDomNode patternNode = doc.createElement( "pattern" );
		LocalFileMng::writeXmlString( patternNode, "name", pat->get_name() );
		LocalFileMng::writeXmlString( patternNode, "category", pat->get_category() );
		LocalFileMng::writeXmlString( patternNode, "size", QString("%1").arg( pat->get_length() ) );
		LocalFileMng::writeXmlString( patternNode, "info", pat->get_info() );

		QDomNode noteListNode = doc.createElement( "noteList" );
		const Pattern::notes_t* notes = pat->get_notes();
		FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) {
			Note *pNote = it->second;
			assert( pNote );

			QDomNode noteNode = doc.createElement( "note" );
			LocalFileMng::writeXmlString( noteNode, "position", QString("%1").arg( pNote->get_position() ) );
			LocalFileMng::writeXmlString( noteNode, "leadlag", QString("%1").arg( pNote->get_lead_lag() ) );
			LocalFileMng::writeXmlString( noteNode, "velocity", QString("%1").arg( pNote->get_velocity() ) );
			LocalFileMng::writeXmlString( noteNode, "pan_L", QString("%1").arg( pNote->get_pan_l() ) );
			LocalFileMng::writeXmlString( noteNode, "pan_R", QString("%1").arg( pNote->get_pan_r() ) );
			LocalFileMng::writeXmlString( noteNode, "pitch", QString("%1").arg( pNote->get_pitch() ) );
			LocalFileMng::writeXmlString( noteNode, "probability", QString("%1").arg( pNote->get_probability() ) );

			LocalFileMng::writeXmlString( noteNode, "key", pNote->key_to_string() );

			LocalFileMng::writeXmlString( noteNode, "length", QString("%1").arg( pNote->get_length() ) );
			LocalFileMng::writeXmlString( noteNode, "instrument", QString("%1").arg( pNote->get_instrument()->get_id() ) );

			QString noteoff = "false";
			if ( pNote->get_note_off() ) noteoff = "true";
			LocalFileMng::writeXmlString( noteNode, "note_off", noteoff );
			noteListNode.appendChild( noteNode );

		}
		patternNode.appendChild( noteListNode );

		patternListNode.appendChild( patternNode );
	}
コード例 #16
0
ファイル: local_file_mgr.cpp プロジェクト: deufrai/hydrogen
int LocalFileMng::savePattern( Song *song , const QString& drumkit_name, int selectedpattern , const QString& patternname, const QString& realpatternname, int mode)
{
	//int mode = 1 save, int mode = 2 save as
	// INSTRUMENT NODE

	Instrument *instr = song->get_instrument_list()->get( 0 );
	assert( instr );

	Pattern *pat = song->get_pattern_list()->get( selectedpattern );

	QString sPatternDir = Preferences::get_instance()->getDataDirectory() + "patterns/" +  drumkit_name;

	INFOLOG( "[savePattern]" + sPatternDir );

	// check if the directory exists
	QDir dir( sPatternDir );
	QDir dirPattern( sPatternDir );
	if ( !dir.exists() ) {
		dir.mkdir( sPatternDir );// create the drumkit directory
	}

	QString sPatternXmlFilename;
	// create the drumkit.xml file
	switch ( mode ){
	case 1: //save
		sPatternXmlFilename = sPatternDir + "/" + QString( patternname + QString( ".h2pattern" ));
		break;
	case 2: //save as
		sPatternXmlFilename = patternname;
		break;
	case 3: //"save" but overwrite a existing pattern. mode 3 disable the last file exist check
		sPatternXmlFilename = sPatternDir + "/" + QString( patternname + QString( ".h2pattern" ));
		break;
	case 4: //tmp pattern needed by undo/redo
		sPatternXmlFilename = patternname;
	default:
		WARNINGLOG( "Pattern Save unknown status");
		break;

	}

	//test if the file exists
	QFile testfile( sPatternXmlFilename );
	if ( testfile.exists() && mode == 1)
		return 1;

	QDomDocument doc;
	QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"");
	doc.appendChild( header );

	QDomNode rootNode = doc.createElement( "drumkit_pattern" );
	//LIB_ID just in work to get better usability
	//writeXmlString( &rootNode, "LIB_ID", "in_work" );
	writeXmlString( rootNode, "pattern_for_drumkit", drumkit_name );
	writeXmlString( rootNode, "author", song->get_author() );
	writeXmlString( rootNode, "license", song->get_license() );


	// pattern
	QDomNode patternNode = doc.createElement( "pattern" );
	writeXmlString( patternNode, "pattern_name", realpatternname );

	QString category;
	if ( pat->get_category().isEmpty() )
		category = "No category";
	else
		category = pat->get_category();

	writeXmlString( patternNode, "info", pat->get_info() );
	writeXmlString( patternNode, "category", category  );
	writeXmlString( patternNode, "size", QString("%1").arg( pat->get_length() ) );

	QDomNode noteListNode = doc.createElement( "noteList" );
	const Pattern::notes_t* notes = pat->get_notes();
	FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) {
		Note *pNote = it->second;
		assert( pNote );

		QDomNode noteNode = doc.createElement( "note" );
		writeXmlString( noteNode, "position", QString("%1").arg( pNote->get_position() ) );
		writeXmlString( noteNode, "leadlag", QString("%1").arg( pNote->get_lead_lag() ) );
		writeXmlString( noteNode, "velocity", QString("%1").arg( pNote->get_velocity() ) );
		writeXmlString( noteNode, "pan_L", QString("%1").arg( pNote->get_pan_l() ) );
		writeXmlString( noteNode, "pan_R", QString("%1").arg( pNote->get_pan_r() ) );
		writeXmlString( noteNode, "pitch", QString("%1").arg( pNote->get_pitch() ) );

		writeXmlString( noteNode, "key", pNote->key_to_string() );

		writeXmlString( noteNode, "length", QString("%1").arg( pNote->get_length() ) );
		writeXmlString( noteNode, "instrument", QString("%1").arg( pNote->get_instrument()->get_id() ) );
		noteListNode.appendChild( noteNode );
	}