Ejemplo n.º 1
0
void Instrument::save_to( XMLNode* node, int component_id )
{
	XMLNode InstrumentNode = node->ownerDocument().createElement( "instrument" );
	InstrumentNode.write_int( "id", __id );
	InstrumentNode.write_string( "name", __name );
	InstrumentNode.write_float( "volume", __volume );
	InstrumentNode.write_bool( "isMuted", __muted );
	InstrumentNode.write_float( "pan_L", __pan_l );
	InstrumentNode.write_float( "pan_R", __pan_r );
	InstrumentNode.write_float( "randomPitchFactor", __random_pitch_factor );
	InstrumentNode.write_float( "gain", __gain );
	InstrumentNode.write_bool( "filterActive", __filter_active );
	InstrumentNode.write_float( "filterCutoff", __filter_cutoff );
	InstrumentNode.write_float( "filterResonance", __filter_resonance );
	InstrumentNode.write_float( "Attack", __adsr->get_attack() );
	InstrumentNode.write_float( "Decay", __adsr->get_decay() );
	InstrumentNode.write_float( "Sustain", __adsr->get_sustain() );
	InstrumentNode.write_float( "Release", __adsr->get_release() );
	InstrumentNode.write_int( "muteGroup", __mute_group );
	InstrumentNode.write_int( "midiOutChannel", __midi_out_channel );
	InstrumentNode.write_int( "midiOutNote", __midi_out_note );
	InstrumentNode.write_bool( "isStopNote", __stop_notes );
	InstrumentNode.write_int( "isHihat", __hihat_grp );
	InstrumentNode.write_int( "lower_cc", __lower_cc );
	InstrumentNode.write_int( "higher_cc", __higher_cc );
	for ( int i=0; i<MAX_FX; i++ ) {
		InstrumentNode.write_float( QString( "FX%1Level" ).arg( i+1 ), __fx_level[i] );
	}
	for (std::vector<InstrumentComponent*>::iterator it = __components->begin() ; it != __components->end(); ++it) {
		InstrumentComponent* pComponent = *it;
		if( component_id == -1 || pComponent->get_drumkit_componentID() == component_id )
			pComponent->save_to( &InstrumentNode, component_id );
	}
	node->appendChild( InstrumentNode );
}
Ejemplo n.º 2
0
void JackAudioDriver::makeTrackOutputs( Song* pSong )
{

	// Only execute the body of this function if a per-track
	// creation of the output ports is desired.
	if( Preferences::get_instance()->m_bJackTrackOuts == false )
		return;

	InstrumentList * pInstruments = pSong->get_instrument_list();
	Instrument * pInstr;
	int nInstruments = ( int ) pInstruments->size();

	// create dedicated channel output ports
	WARNINGLOG( QString( "Creating / renaming %1 ports" ).arg( nInstruments ) );

	int nTrackCount = 0;

	// Resets the `track_map' matrix.
	for( int i = 0 ; i < MAX_INSTRUMENTS ; i++ ){
		for ( int j = 0 ; j < MAX_COMPONENTS ; j++ ){
			track_map[i][j] = 0;
		}
	}
	// Creates a new output track or reassigns an existing one for
	// each component of each instrument and stores the result in
	// the `track_map'.
	for ( int n = 0; n <= nInstruments - 1; n++ ) {
		pInstr = pInstruments->get( n );
		for (std::vector<InstrumentComponent*>::iterator it = pInstr->get_components()->begin() ; it != pInstr->get_components()->end(); ++it) {
			InstrumentComponent* pCompo = *it;
			setTrackOutput( nTrackCount, pInstr, pCompo, pSong);
			track_map[pInstr->get_id()][pCompo->get_drumkit_componentID()] = nTrackCount;
			nTrackCount++;
		}
	}
	// clean up unused ports
	jack_port_t *p_L, *p_R;
	for ( int n = nTrackCount; n < track_port_count; n++ ) {
		p_L = track_output_ports_L[n];
		p_R = track_output_ports_R[n];
		track_output_ports_L[n] = 0;
		jack_port_unregister( m_pClient, p_L );
		track_output_ports_R[n] = 0;
		jack_port_unregister( m_pClient, p_R );
	}

	track_port_count = nTrackCount;
}
Ejemplo n.º 3
0
Note::Note( Instrument* instrument, int position, float velocity, float pan_l, float pan_r, int length, float pitch )
	: Object( __class_name ),
	  __instrument( instrument ),
	  __instrument_id( 0 ),
	  __specific_compo_id( -1 ),
	  __position( position ),
	  __velocity( velocity ),
	  __pan_l( PAN_MAX ),
	  __pan_r( PAN_MAX ),
	  __length( length ),
	  __pitch( pitch ),
	  __key( C ),
	  __octave( P8 ),
	  __adsr( 0 ),
	  __lead_lag( 0.0 ),
	  __cut_off( 1.0 ),
	  __resonance( 0.0 ),
	  __humanize_delay( 0 ),
	  __bpfb_l( 0.0 ),
	  __bpfb_r( 0.0 ),
	  __lpfb_l( 0.0 ),
	  __lpfb_r( 0.0 ),
	  __pattern_idx( 0 ),
	  __midi_msg( -1 ),
	  __note_off( false ),
	  __just_recorded( false ),
      __probability( 1.0f )
{
	if ( __instrument != 0 ) {
		__adsr = __instrument->copy_adsr();
		__instrument_id = __instrument->get_id();

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

			SelectedLayerInfo *sampleInfo = new SelectedLayerInfo;
			sampleInfo->SelectedLayer = -1;
			sampleInfo->SamplePosition = 0;

			__layers_selected[ pCompo->get_drumkit_componentID() ] = sampleInfo;
		}
	}

	set_pan_l(pan_l);
	set_pan_r(pan_r);
}
Ejemplo n.º 4
0
/**
 * Make sure the number of track outputs match the instruments in @a song , and name the ports.
 */
void JackOutput::makeTrackOutputs( Song * song )
{

	/// Disable Track Outputs
	if( Preferences::get_instance()->m_bJackTrackOuts == false )
		return;
	///

	InstrumentList * instruments = song->get_instrument_list();
	Instrument * instr;
	int nInstruments = ( int )instruments->size();

	// create dedicated channel output ports
	WARNINGLOG( QString( "Creating / renaming %1 ports" ).arg( nInstruments ) );

	int p_trackCount = 0;

	for( int i = 0 ; i < MAX_INSTRUMENTS ; i++ ){
		for ( int j = 0 ; j < MAX_COMPONENTS ; j++ ){
			track_map[i][j] = 0;
		}
	}

	for ( int n = nInstruments - 1; n >= 0; n-- ) {
		instr = instruments->get( n );
		for (std::vector<InstrumentComponent*>::iterator it = instr->get_components()->begin() ; it != instr->get_components()->end(); ++it) {
			InstrumentComponent* pCompo = *it;
			setTrackOutput( p_trackCount, instr , pCompo, song);
			track_map[instr->get_id()][pCompo->get_drumkit_componentID()] = p_trackCount;
			p_trackCount++;
		}
	}
	// clean up unused ports
	jack_port_t *p_L, *p_R;
	for ( int n = p_trackCount; n < track_port_count; n++ ) {
		p_L = track_output_ports_L[n];
		p_R = track_output_ports_R[n];
		track_output_ports_L[n] = 0;
		jack_port_unregister( client, p_L );
		track_output_ports_R[n] = 0;
		jack_port_unregister( client, p_R );
	}

	track_port_count = p_trackCount;
}
Ejemplo n.º 5
0
Note::Note( Note* other, Instrument* instrument )
	: Object( __class_name ),
	  __instrument( other->get_instrument() ),
	  __instrument_id( 0 ),
	  __specific_compo_id( -1 ),
	  __position( other->get_position() ),
	  __velocity( other->get_velocity() ),
	  __pan_l( other->get_pan_l() ),
	  __pan_r( other->get_pan_r() ),
	  __length( other->get_length() ),
	  __pitch( other->get_pitch() ),
	  __key( other->get_key() ),
	  __octave( other->get_octave() ),
	  __adsr( 0 ),
	  __lead_lag( other->get_lead_lag() ),
	  __cut_off( other->get_cut_off() ),
	  __resonance( other->get_resonance() ),
	  __humanize_delay( other->get_humanize_delay() ),
	  __bpfb_l( other->get_bpfb_l() ),
	  __bpfb_r( other->get_bpfb_r() ),
	  __lpfb_l( other->get_lpfb_l() ),
	  __lpfb_r( other->get_lpfb_r() ),
	  __pattern_idx( other->get_pattern_idx() ),
	  __midi_msg( other->get_midi_msg() ),
	  __note_off( other->get_note_off() ),
	  __just_recorded( other->get_just_recorded() ),
      __probability( other->get_probability() )
{
	if ( instrument != 0 ) __instrument = instrument;
	if ( __instrument != 0 ) {
		__adsr = __instrument->copy_adsr();
		__instrument_id = __instrument->get_id();

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

			SelectedLayerInfo *sampleInfo = new SelectedLayerInfo;
			sampleInfo->SelectedLayer = -1;
			sampleInfo->SamplePosition = 0;

			__layers_selected[ pCompo->get_drumkit_componentID() ] = sampleInfo;
        }
	}
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
0
// 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 );
	}
Ejemplo n.º 8
0
void InstrumentEditor::compoChangeAddDelete(QAction* pAction)
{
	QString sSelectedAction = pAction->text();

	Hydrogen * pEngine = Hydrogen::get_instance();

	if( sSelectedAction.compare("add") == 0 ) {
		if ( m_pInstrument ) {
			bool bIsOkPressed;
			QString sNewName = QInputDialog::getText( this, "Hydrogen", trUtf8( "Component name" ), QLineEdit::Normal, "New Component", &bIsOkPressed );
			if ( bIsOkPressed  ) {
				DrumkitComponent* pDrumkitComponent = new DrumkitComponent( findFreeDrumkitComponentId(), sNewName );
				pEngine->getSong()->get_components()->push_back( pDrumkitComponent );

				//InstrumentComponent* instrument_component = new InstrumentComponent( dm_component->get_id() );
				//instrument_component->set_gain( 1.0f );
				//m_pInstrument->get_components()->push_back( instrument_component );

				m_nSelectedComponent = pDrumkitComponent->get_id();
				m_pLayerPreview->set_selected_component( pDrumkitComponent->get_id() );

				selectedInstrumentChangedEvent();

				// this will force an update...
				EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 );

#ifdef H2CORE_HAVE_JACK
				pEngine->renameJackPorts(pEngine->getSong());
#endif
			}
			else {
				// user entered nothing or pressed Cancel
			}
		}
	}
	else if( sSelectedAction.compare("delete") == 0 ) {
		std::vector<DrumkitComponent*>* pDrumkitComponents = pEngine->getSong()->get_components();

		if(pDrumkitComponents->size() == 1){
			return;
		}

		DrumkitComponent* pDrumkitComponent = pEngine->getSong()->get_component( m_nSelectedComponent );

		InstrumentList* pInstruments = pEngine->getSong()->get_instrument_list();
		for ( int n = ( int )pInstruments->size() - 1; n >= 0; n-- ) {
			Instrument* pInstrument = pInstruments->get( n );
			for( int o = 0 ; o < pInstrument->get_components()->size() ; o++ ) {
				InstrumentComponent* pInstrumentComponent = pInstrument->get_components()->at( o );
				if( pInstrumentComponent->get_drumkit_componentID() == pDrumkitComponent->get_id() ) {
					for( int nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) {
						InstrumentLayer* pLayer = pInstrumentComponent->get_layer( nLayer );
						if( pLayer )
							delete pLayer;
					}
					pInstrument->get_components()->erase( pInstrument->get_components()->begin() + o );;
					break;
				}
			}
		}

		for ( int n = 0 ; n < pDrumkitComponents->size() ; n++ ) {
			DrumkitComponent* pTmpDrumkitComponent = pDrumkitComponents->at( n );
			if( pTmpDrumkitComponent->get_id() == pDrumkitComponent->get_id() ) {
				pDrumkitComponents->erase( pDrumkitComponents->begin() + n );
				break;
			}
		}

		m_nSelectedComponent = pDrumkitComponents->front()->get_id();

		selectedInstrumentChangedEvent();
		// this will force an update...
		EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 );
	}
	else if( sSelectedAction.compare("rename") == 0 ) {
		labelCompoClicked( NULL );
	}
	else {
		m_nSelectedComponent = -1;
		std::vector<DrumkitComponent*>* pDrumkitComponents = pEngine->getSong()->get_components();
		for (std::vector<DrumkitComponent*>::iterator it = pDrumkitComponents->begin() ; it != pDrumkitComponents->end(); ++it) {
			DrumkitComponent* pDrumkitComponent = *it;
			if( pDrumkitComponent->get_name().compare( sSelectedAction ) == 0) {
				m_nSelectedComponent = pDrumkitComponent->get_id();
				m_pCompoNameLbl->setText( pDrumkitComponent->get_name() );
				break;
			}
		}

		if( m_pInstrument && !m_pInstrument->get_component(m_nSelectedComponent)) {
			INFOLOG("Component needs to be added");

			InstrumentComponent* pInstrComponent = new InstrumentComponent( m_nSelectedComponent );
			pInstrComponent->set_gain( 1.0f );

			m_pInstrument->get_components()->push_back( pInstrComponent );



#ifdef H2CORE_HAVE_JACK
			pEngine->renameJackPorts(pEngine->getSong());
#endif
		}

		m_pLayerPreview->set_selected_component(m_nSelectedComponent);

		selectedInstrumentChangedEvent();

		// this will force an update...
		EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 );
	}
}
Ejemplo n.º 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;
	}

	int nReturnValue = 0;

	for (std::vector<InstrumentComponent*>::iterator it = pInstr->get_components()->begin() ; it !=pInstr->get_components()->end(); ++it) {
		InstrumentComponent *pCompo = *it;
		DrumkitComponent* pMainCompo = 0;

		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 = NULL;
		for ( unsigned nLayer = 0; nLayer < MAX_LAYERS; ++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() ) ) {
				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 );
			nReturnValue = 1;
			continue;
		}

		if ( pNote->get_sample_position( pCompo->get_drumkit_componentID() ) >= pSample->get_frames() ) {
			WARNINGLOG( "sample position out of bounds. The layer has been resized during note play?" );
			nReturnValue = 1;
			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();
					nReturnValue = 1;
					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);

		if ( pInstr->is_muted() || pSong->__is_muted || pMainCompo->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 * 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_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 * 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 )pNote->get_sample_position(pCompo->get_drumkit_componentID()) == 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
			if ( __render_note_no_resample( pSample, pNote, pCompo, pMainCompo, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, pSong ) == 1 )
				nReturnValue = 1;
		} else {	// RESAMPLE
			if ( __render_note_resample( pSample, pNote, pCompo, pMainCompo, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, fLayerPitch, pSong ) == 1 )
				nReturnValue = 1;
		}
	}

	return nReturnValue;
}
Ejemplo n.º 10
0
void Instrument::load_from( Drumkit* pDrumkit, Instrument* pInstrument, bool is_live )
{
	this->get_components()->clear();

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

		InstrumentComponent* pMyComponent = new InstrumentComponent( pSrcComponent->get_drumkit_componentID() );
		pMyComponent->set_gain( pSrcComponent->get_gain() );

		this->get_components()->push_back( pMyComponent );

		for ( int i=0; i<MAX_LAYERS; i++ ) {
			InstrumentLayer* src_layer = pSrcComponent->get_layer( i );
			InstrumentLayer* my_layer = pMyComponent->get_layer( i );

			if( src_layer==0 ) {
				if ( is_live )
					AudioEngine::get_instance()->lock( RIGHT_HERE );
				pMyComponent->set_layer( NULL, i );
				if ( is_live )
					AudioEngine::get_instance()->unlock();
			} else {
				QString sample_path =  pDrumkit->get_path() + "/" + src_layer->get_sample()->get_filename();
				Sample* sample = Sample::load( sample_path );
				if ( sample==0 ) {
					_ERRORLOG( QString( "Error loading sample %1. Creating a new empty layer." ).arg( sample_path ) );
					if ( is_live )
						AudioEngine::get_instance()->lock( RIGHT_HERE );
					pMyComponent->set_layer( NULL, i );
					if ( is_live )
						AudioEngine::get_instance()->unlock();
				} else {
					if ( is_live )
						AudioEngine::get_instance()->lock( RIGHT_HERE );
					pMyComponent->set_layer( new InstrumentLayer( src_layer, sample ), i );
					if ( is_live )
						AudioEngine::get_instance()->unlock();
				}
			}
			delete my_layer;
		}
	}
	if ( is_live )
		AudioEngine::get_instance()->lock( RIGHT_HERE );

	this->set_id( pInstrument->get_id() );
	this->set_name( pInstrument->get_name() );
	this->set_drumkit_name( pDrumkit->get_name() );
	this->set_gain( pInstrument->get_gain() );
	this->set_volume( pInstrument->get_volume() );
	this->set_pan_l( pInstrument->get_pan_l() );
	this->set_pan_r( pInstrument->get_pan_r() );
	this->set_adsr( new ADSR( *( pInstrument->get_adsr() ) ) );
	this->set_filter_active( pInstrument->is_filter_active() );
	this->set_filter_cutoff( pInstrument->get_filter_cutoff() );
	this->set_filter_resonance( pInstrument->get_filter_resonance() );
	this->set_random_pitch_factor( pInstrument->get_random_pitch_factor() );
	this->set_muted( pInstrument->is_muted() );
	this->set_mute_group( pInstrument->get_mute_group() );
	this->set_midi_out_channel( pInstrument->get_midi_out_channel() );
	this->set_midi_out_note( pInstrument->get_midi_out_note() );
	this->set_stop_notes( pInstrument->is_stop_notes() );
	this->set_hihat_grp( pInstrument->get_hihat_grp() );
	this->set_lower_cc( pInstrument->get_lower_cc() );
	this->set_higher_cc( pInstrument->get_higher_cc() );
	if ( is_live )
		AudioEngine::get_instance()->unlock();
}