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; */ }
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; }
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(); } }
// 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); }
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(); } } }
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 ); } }
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; }
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(); } } }
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 ); } }
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( ¬e_node ); } } }
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 ); } } }
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; }
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 } } } } } } }
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 ); }
// 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 ); }
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 ); }