Pattern* Pattern::load_from( XMLNode* node, InstrumentList* instruments ) { Pattern* pattern = new Pattern( node->read_string( "name", NULL, false, false ), node->read_string( "info", "", false, false ), node->read_string( "category", "unknown", false, false ), node->read_int( "size", -1, false, false ) ); // FIXME support legacy xml element pattern_name, should once be removed if ( pattern->get_name().isEmpty() ) { pattern->set_name( node->read_string( "pattern_name", "unknown", false, false ) ); } XMLNode note_list_node = node->firstChildElement( "noteList" ); if ( !note_list_node.isNull() ) { XMLNode note_node = note_list_node.firstChildElement( "note" ); while ( !note_node.isNull() ) { Note* note = Note::load_from( ¬e_node, instruments ); if( note ) { pattern->insert_note( note ); } note_node = note_node.nextSiblingElement( "note" ); } } return pattern; }
/// /// Create a new pattern /// void SongEditorPanel::newPatBtnClicked( Button* btn ) { UNUSED( btn ); Hydrogen *pEngine = Hydrogen::get_instance(); Song *pSong = pEngine->getSong(); PatternList *pPatternList = pSong->get_pattern_list(); Pattern *pNewPattern = new Pattern( trUtf8("Pattern %1").arg(pPatternList->size()+1)); PatternPropertiesDialog *pDialog = new PatternPropertiesDialog( this, pNewPattern, 0, true ); if ( pDialog->exec() == QDialog::Accepted ) { SE_addEmptyPatternAction*action = new SE_addEmptyPatternAction( pNewPattern->get_name() , pNewPattern->get_info(), pNewPattern->get_category(), pEngine->getSelectedPatternNumber()+1); HydrogenApp::get_instance()->m_undoStack->push( action ); } delete pNewPattern; delete pDialog; }
void MainForm::action_file_export_pattern_as() { if ( ( Hydrogen::get_instance()->getState() == STATE_PLAYING ) ) { Hydrogen::get_instance()->sequencer_stop(); } Hydrogen *engine = Hydrogen::get_instance(); int selectedpattern = engine->getSelectedPatternNumber(); Song *song = engine->getSong(); Pattern *pat = song->get_pattern_list()->get ( selectedpattern ); Instrument *instr = song->get_instrument_list()->get ( 0 ); assert ( instr ); QDir dir = Preferences::get_instance()->__lastspatternDirectory; QFileDialog fd(this); fd.setFileMode ( QFileDialog::AnyFile ); fd.setFilter ( trUtf8 ( "Hydrogen Pattern (*.h2pattern)" ) ); fd.setAcceptMode ( QFileDialog::AcceptSave ); fd.setWindowTitle ( trUtf8 ( "Save Pattern as ..." ) ); fd.setDirectory ( dir ); fd.setSidebarUrls( fd.sidebarUrls() << QUrl::fromLocalFile( Filesystem::patterns_dir() ) ); QString defaultPatternname = QString ( pat->get_name() ); fd.selectFile ( defaultPatternname ); LocalFileMng fileMng; QString filename; if ( fd.exec() == QDialog::Accepted ) { filename = fd.selectedFiles().first(); QString tmpfilename = filename; QString toremove = tmpfilename.section( '/', -1 ); QString newdatapath = tmpfilename.replace( toremove, "" ); Preferences::get_instance()->__lastspatternDirectory = newdatapath; } if ( !filename.isEmpty() ) { QString sNewFilename = filename; if(sNewFilename.endsWith( ".h2pattern" ) ){ sNewFilename += ""; } else{ sNewFilename += ".h2pattern"; } QString patternname = sNewFilename; QString realpatternname = filename; QString realname = realpatternname.mid( realpatternname.lastIndexOf( "/" ) + 1 ); if ( realname.endsWith( ".h2pattern" ) ) realname.replace( ".h2pattern", "" ); pat->set_name(realname); HydrogenApp::get_instance()->getSongEditorPanel()->updateAll(); int err = fileMng.savePattern ( song, engine->getCurrentDrumkitname(), selectedpattern, patternname, realname, 2 ); if ( err != 0 ) { QMessageBox::warning( this, "Hydrogen", trUtf8("Could not export pattern.") ); _ERRORLOG ( "Error saving the pattern" ); } } h2app->setStatusBarMessage ( trUtf8 ( "Pattern saved." ), 10000 ); //update SoundlibraryPanel HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->test_expandedItems(); HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->updateDrumkitList(); }
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 ); }