void Drumkit::dump() { DEBUGLOG( "Drumkit dump" ); DEBUGLOG( " |- Path = " + __path ); DEBUGLOG( " |- Name = " + __name ); DEBUGLOG( " |- Author = " + __author ); DEBUGLOG( " |- Info = " + __info ); DEBUGLOG( " |- Instrument list" ); for ( int i=0; i<__instruments->size(); i++ ) { Instrument* instrument = ( *__instruments )[i]; DEBUGLOG( QString( " |- (%1 of %2) Name = %3" ) .arg( i ) .arg( __instruments->size()-1 ) .arg( instrument->get_name() ) ); for (std::vector<InstrumentComponent*>::iterator it = instrument->get_components()->begin() ; it != instrument->get_components()->end(); ++it) { InstrumentComponent* component = *it; for ( int j=0; j<MAX_LAYERS; j++ ) { InstrumentLayer* layer = component->get_layer( j ); if ( layer ) { Sample* sample = layer->get_sample(); if ( sample ) { DEBUGLOG( QString( " |- %1 [%2]" ).arg( sample->get_filepath() ).arg( sample->is_empty() ) ); } else { DEBUGLOG( " |- NULL sample" ); } } } } } }
bool Drumkit::save_samples( const QString& dk_dir, bool overwrite ) { INFOLOG( QString( "Saving drumkit %1 samples into %2" ).arg( __name ).arg( dk_dir ) ); if( !Filesystem::mkdir( dk_dir ) ) { return false; } InstrumentList* instruments = get_instruments(); for( int i = 0; i < instruments->size(); i++ ) { Instrument* instrument = ( *instruments )[i]; for (std::vector<InstrumentComponent*>::iterator it = instrument->get_components()->begin() ; it != instrument->get_components()->end(); ++it) { InstrumentComponent* component = *it; for( int n = 0; n < MAX_LAYERS; n++ ) { InstrumentLayer* layer = component->get_layer( n ); if( layer ) { QString src = layer->get_sample()->get_filepath(); QString dst = dk_dir + "/" + layer->get_sample()->get_filename(); if( src != dst ) { QString original_dst = dst; // If the destination path does not have an extension and there is a dot in the path, hell will break loose. QFileInfo maybe? int insertPosition = original_dst.length(); if( original_dst.lastIndexOf(".") > 0 ) insertPosition = original_dst.lastIndexOf("."); if(overwrite == false) { // If the destination path already exists, try to use basename_1, basename_2, etc. instead of basename. int tries = 0; while( Filesystem::file_exists( dst, true )) { tries++; dst = original_dst; dst.insert( insertPosition, QString("_%1").arg(tries) ); } } layer->get_sample()->set_filename( dst ); if( !Filesystem::file_copy( src, dst ) ) { return false; } } } } } } return true; }
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; }
/** * 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; }
Instrument* Instrument::load_from( XMLNode* node, const QString& dk_path, const QString& dk_name ) { int id = node->read_int( "id", EMPTY_INSTR_ID, false, false ); if ( id==EMPTY_INSTR_ID ){ return 0; } Instrument* pInstrument = new Instrument( id, node->read_string( "name", "" ), 0 ); pInstrument->set_drumkit_name( dk_name ); pInstrument->set_volume( node->read_float( "volume", 1.0f ) ); pInstrument->set_muted( node->read_bool( "isMuted", false ) ); pInstrument->set_pan_l( node->read_float( "pan_L", 1.0f ) ); pInstrument->set_pan_r( node->read_float( "pan_R", 1.0f ) ); // may not exist, but can't be empty pInstrument->set_filter_active( node->read_bool( "filterActive", true, false ) ); pInstrument->set_filter_cutoff( node->read_float( "filterCutoff", 1.0f, true, false ) ); pInstrument->set_filter_resonance( node->read_float( "filterResonance", 0.0f, true, false ) ); pInstrument->set_random_pitch_factor( node->read_float( "randomPitchFactor", 0.0f, true, false ) ); float attack = node->read_float( "Attack", 0.0f, true, false ); float decay = node->read_float( "Decay", 0.0f, true, false ); float sustain = node->read_float( "Sustain", 1.0f, true, false ); float release = node->read_float( "Release", 1000.0f, true, false ); pInstrument->set_adsr( new ADSR( attack, decay, sustain, release ) ); pInstrument->set_gain( node->read_float( "gain", 1.0f, true, false ) ); pInstrument->set_mute_group( node->read_int( "muteGroup", -1, true, false ) ); pInstrument->set_midi_out_channel( node->read_int( "midiOutChannel", -1, true, false ) ); pInstrument->set_midi_out_note( node->read_int( "midiOutNote", pInstrument->__midi_out_note, true, false ) ); pInstrument->set_stop_notes( node->read_bool( "isStopNote", true ,false ) ); pInstrument->set_hihat_grp( node->read_int( "isHihat", -1, true ) ); pInstrument->set_lower_cc( node->read_int( "lower_cc", 0, true ) ); pInstrument->set_higher_cc( node->read_int( "higher_cc", 127, true ) ); for ( int i=0; i<MAX_FX; i++ ) { pInstrument->set_fx_level( node->read_float( QString( "FX%1Level" ).arg( i+1 ), 0.0 ), i ); } XMLNode ComponentNode = node->firstChildElement( "instrumentComponent" ); while ( !ComponentNode.isNull() ) { pInstrument->get_components()->push_back( InstrumentComponent::load_from( &ComponentNode, dk_path ) ); ComponentNode = ComponentNode.nextSiblingElement( "instrumentComponent" ); } return pInstrument; }
/// 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; }
// 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 ); }
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 ); } }
/// 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; }
Drumkit* Legacy::load_drumkit( const QString& dk_path ) { if ( version_older_than( 0, 9, 8 ) ) { ERRORLOG( QString( "this code should not be used anymore, it belongs to 0.9.6" ) ); } else { ERRORLOG( QString( "loading drumkit with legacy code" ) ); } XMLDoc doc; if( !doc.read( dk_path ) ) { return 0; } XMLNode root = doc.firstChildElement( "drumkit_info" ); if ( root.isNull() ) { ERRORLOG( "drumkit_info node not found" ); return 0; } QString drumkit_name = root.read_string( "name", "", false, false ); if ( drumkit_name.isEmpty() ) { ERRORLOG( "Drumkit has no name, abort" ); return 0; } Drumkit* drumkit = new Drumkit(); drumkit->set_path( dk_path.left( dk_path.lastIndexOf( "/" ) ) ); drumkit->set_name( drumkit_name ); drumkit->set_author( root.read_string( "author", "undefined author" ) ); drumkit->set_info( root.read_string( "info", "defaultInfo" ) ); drumkit->set_license( root.read_string( "license", "undefined license" ) ); XMLNode instruments_node = root.firstChildElement( "instrumentList" ); if ( instruments_node.isNull() ) { WARNINGLOG( "instrumentList node not found" ); drumkit->set_instruments( new InstrumentList() ); } else { InstrumentList* instruments = new InstrumentList(); XMLNode instrument_node = instruments_node.firstChildElement( "instrument" ); int count = 0; while ( !instrument_node.isNull() ) { count++; if ( count > MAX_INSTRUMENTS ) { ERRORLOG( QString( "instrument count >= %2, stop reading instruments" ).arg( MAX_INSTRUMENTS ) ); break; } Instrument* instrument = 0; int id = instrument_node.read_int( "id", EMPTY_INSTR_ID, false, false ); if ( id!=EMPTY_INSTR_ID ) { instrument = new Instrument( id, instrument_node.read_string( "name", "" ), 0 ); instrument->set_drumkit_name( drumkit_name ); instrument->set_volume( instrument_node.read_float( "volume", 1.0f ) ); instrument->set_muted( instrument_node.read_bool( "isMuted", false ) ); instrument->set_pan_l( instrument_node.read_float( "pan_L", 1.0f ) ); instrument->set_pan_r( instrument_node.read_float( "pan_R", 1.0f ) ); // may not exist, but can't be empty instrument->set_filter_active( instrument_node.read_bool( "filterActive", true, false ) ); instrument->set_filter_cutoff( instrument_node.read_float( "filterCutoff", 1.0f, true, false ) ); instrument->set_filter_resonance( instrument_node.read_float( "filterResonance", 0.0f, true, false ) ); instrument->set_random_pitch_factor( instrument_node.read_float( "randomPitchFactor", 0.0f, true, false ) ); float attack = instrument_node.read_float( "Attack", 0.0f, true, false ); float decay = instrument_node.read_float( "Decay", 0.0f, true, false ); float sustain = instrument_node.read_float( "Sustain", 1.0f, true, false ); float release = instrument_node.read_float( "Release", 1000.0f, true, false ); instrument->set_adsr( new ADSR( attack, decay, sustain, release ) ); instrument->set_gain( instrument_node.read_float( "gain", 1.0f, true, false ) ); instrument->set_mute_group( instrument_node.read_int( "muteGroup", -1, true, false ) ); instrument->set_midi_out_channel( instrument_node.read_int( "midiOutChannel", -1, true, false ) ); instrument->set_midi_out_note( instrument_node.read_int( "midiOutNote", MIDI_MIDDLE_C, true, false ) ); instrument->set_stop_notes( instrument_node.read_bool( "isStopNote", true ,false ) ); instrument->set_hihat_grp( instrument_node.read_int( "isHihat", -1, true ) ); instrument->set_lower_cc( instrument_node.read_int( "lower_cc", 0, true ) ); instrument->set_higher_cc( instrument_node.read_int( "higher_cc", 127, true ) ); for ( int i=0; i<MAX_FX; i++ ) { instrument->set_fx_level( instrument_node.read_float( QString( "FX%1Level" ).arg( i+1 ), 0.0 ), i ); } QDomNode filename_node = instrument_node.firstChildElement( "filename" ); if ( !filename_node.isNull() ) { DEBUGLOG( "Using back compatibility code. filename node found" ); QString sFilename = instrument_node.read_string( "filename", "" ); if( sFilename.isEmpty() ) { ERRORLOG( "filename back compability node is empty" ); } else { Sample* sample = new Sample( dk_path+"/"+sFilename ); bool p_foundMainCompo = false; for (std::vector<DrumkitComponent*>::iterator it = drumkit->get_components()->begin() ; it != drumkit->get_components()->end(); ++it) { DrumkitComponent* existing_compo = *it; if( existing_compo->get_name().compare("Main") == 0) { p_foundMainCompo = true; break; } } if ( !p_foundMainCompo ) { DrumkitComponent* dmCompo = new DrumkitComponent( 0, "Main" ); drumkit->get_components()->push_back(dmCompo); } InstrumentComponent* component = new InstrumentComponent( 0 ); InstrumentLayer* layer = new InstrumentLayer( sample ); component->set_layer( layer, 0 ); instrument->get_components()->push_back( component ); } } else { int n = 0; bool p_foundMainCompo = false; for (std::vector<DrumkitComponent*>::iterator it = drumkit->get_components()->begin() ; it != drumkit->get_components()->end(); ++it) { DrumkitComponent* existing_compo = *it; if( existing_compo->get_name().compare("Main") == 0) { p_foundMainCompo = true; break; } } if ( !p_foundMainCompo ) { DrumkitComponent* dmCompo = new DrumkitComponent( 0, "Main" ); drumkit->get_components()->push_back(dmCompo); } InstrumentComponent* component = new InstrumentComponent( 0 ); XMLNode layer_node = instrument_node.firstChildElement( "layer" ); while ( !layer_node.isNull() ) { if ( n >= MAX_LAYERS ) { ERRORLOG( QString( "n >= MAX_LAYERS (%1)" ).arg( MAX_LAYERS ) ); break; } Sample* sample = new Sample( dk_path+"/"+layer_node.read_string( "filename", "" ) ); InstrumentLayer* layer = new InstrumentLayer( sample ); layer->set_start_velocity( layer_node.read_float( "min", 0.0 ) ); layer->set_end_velocity( layer_node.read_float( "max", 1.0 ) ); layer->set_gain( layer_node.read_float( "gain", 1.0, true, false ) ); layer->set_pitch( layer_node.read_float( "pitch", 0.0, true, false ) ); component->set_layer( layer, n ); n++; layer_node = layer_node.nextSiblingElement( "layer" ); } instrument->get_components()->push_back( component ); } } if( instrument ) { ( *instruments ) << instrument; } else { ERRORLOG( QString( "Empty ID for instrument %1. The drumkit is corrupted. Skipping instrument" ).arg( count ) ); count--; } instrument_node = instrument_node.nextSiblingElement( "instrument" ); } drumkit->set_instruments( instruments ); } return drumkit; }