diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
commit | 145364a8af6a1fec06556221e66d4b724a62fc9a (patch) | |
tree | 53bd71a544008c518034f208d64c932dc2883f50 /src/document/RoseXmlHandler.cpp | |
download | rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.tar.gz rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.zip |
Added old abandoned KDE3 version of the RoseGarden MIDI tool
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/rosegarden@1097595 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/document/RoseXmlHandler.cpp')
-rw-r--r-- | src/document/RoseXmlHandler.cpp | 2368 |
1 files changed, 2368 insertions, 0 deletions
diff --git a/src/document/RoseXmlHandler.cpp b/src/document/RoseXmlHandler.cpp new file mode 100644 index 0000000..028c89a --- /dev/null +++ b/src/document/RoseXmlHandler.cpp @@ -0,0 +1,2368 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <glaurent@telegraph-road.org>, + Chris Cannam <cannam@all-day-breakfast.com>, + Richard Bown <richard.bown@ferventsoftware.com> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "RoseXmlHandler.h" + +#include "sound/Midi.h" +#include <klocale.h> +#include "misc/Debug.h" +#include "misc/Strings.h" +#include "base/AudioLevel.h" +#include "base/AudioPluginInstance.h" +#include "base/BaseProperties.h" +#include "base/Colour.h" +#include "base/ColourMap.h" +#include "base/Composition.h" +#include "base/ControlParameter.h" +#include "base/Device.h" +#include "base/Instrument.h" +#include "base/Marker.h" +#include "base/MidiDevice.h" +#include "base/MidiProgram.h" +#include "base/MidiTypes.h" +#include "base/NotationTypes.h" +#include "base/RealTime.h" +#include "base/Segment.h" +#include "base/Studio.h" +#include "base/Track.h" +#include "base/TriggerSegment.h" +#include "gui/application/RosegardenGUIApp.h" +#include "gui/application/RosegardenApplication.h" +#include "gui/dialogs/FileLocateDialog.h" +#include "gui/general/ProgressReporter.h" +#include "gui/kdeext/KStartupLogo.h" +#include "gui/studio/AudioPlugin.h" +#include "gui/studio/AudioPluginManager.h" +#include "gui/widgets/CurrentProgressDialog.h" +#include "gui/widgets/ProgressDialog.h" +#include "RosegardenGUIDoc.h" +#include "sound/AudioFileManager.h" +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <qcstring.h> +#include <qdatastream.h> +#include <qdialog.h> +#include <qfileinfo.h> +#include <qstring.h> +#include <qstringlist.h> +#include "XmlStorableEvent.h" +#include "XmlSubHandler.h" + +namespace Rosegarden +{ + +using namespace BaseProperties; + +class ConfigurationXmlSubHandler : public XmlSubHandler +{ +public: + ConfigurationXmlSubHandler(const QString &elementName, + Rosegarden::Configuration *configuration); + + virtual bool startElement(const QString& namespaceURI, + const QString& localName, + const QString& qName, + const QXmlAttributes& atts); + + virtual bool endElement(const QString& namespaceURI, + const QString& localName, + const QString& qName, + bool& finished); + + virtual bool characters(const QString& ch); + + //--------------- Data members --------------------------------- + + Rosegarden::Configuration *m_configuration; + + QString m_elementName; + QString m_propertyName; + QString m_propertyType; +}; + +ConfigurationXmlSubHandler::ConfigurationXmlSubHandler(const QString &elementName, + Rosegarden::Configuration *configuration) + : m_configuration(configuration), + m_elementName(elementName) +{ +} + +bool ConfigurationXmlSubHandler::startElement(const QString&, const QString&, + const QString& lcName, + const QXmlAttributes& atts) +{ + m_propertyName = lcName; + m_propertyType = atts.value("type"); + + if (m_propertyName == "property") { + // handle alternative encoding for properties with arbitrary names + m_propertyName = atts.value("name"); + QString value = atts.value("value"); + if (value) { + m_propertyType = "String"; + m_configuration->set<String>(qstrtostr(m_propertyName), + qstrtostr(value)); + } + } + + return true; +} + +bool ConfigurationXmlSubHandler::characters(const QString& chars) +{ + QString ch = chars.stripWhiteSpace(); + // this method is also called on newlines - skip these cases + if (ch.isEmpty()) return true; + + + if (m_propertyType == "Int") { + long i = ch.toInt(); + RG_DEBUG << "\"" << m_propertyName << "\" " + << "value = " << i << endl; + m_configuration->set<Int>(qstrtostr(m_propertyName), i); + + return true; + } + + if (m_propertyType == "RealTime") { + Rosegarden::RealTime rt; + int sepIdx = ch.find(','); + + rt.sec = ch.left(sepIdx).toInt(); + rt.nsec = ch.mid(sepIdx + 1).toInt(); + + RG_DEBUG << "\"" << m_propertyName << "\" " + << "sec = " << rt.sec << ", nsec = " << rt.nsec << endl; + + m_configuration->set<Rosegarden::RealTimeT>(qstrtostr(m_propertyName), rt); + + return true; + } + + if (m_propertyType == "Bool") { + QString chLc = ch.lower(); + + bool b = (chLc == "true" || + chLc == "1" || + chLc == "on"); + + m_configuration->set<Rosegarden::Bool>(qstrtostr(m_propertyName), b); + + return true; + } + + if (!m_propertyType || + m_propertyType == "String") { + + m_configuration->set<Rosegarden::String>(qstrtostr(m_propertyName), + qstrtostr(ch)); + + return true; + } + + + return true; +} + +bool +ConfigurationXmlSubHandler::endElement(const QString&, + const QString&, + const QString& lcName, + bool& finished) +{ + m_propertyName = ""; + m_propertyType = ""; + finished = (lcName == m_elementName); + return true; +} + + +//---------------------------------------- + + + +RoseXmlHandler::RoseXmlHandler(RosegardenGUIDoc *doc, + unsigned int elementCount, + bool createNewDevicesWhenNeeded) + : ProgressReporter(0), + m_doc(doc), + m_currentSegment(0), + m_currentEvent(0), + m_currentTime(0), + m_chordDuration(0), + m_segmentEndMarkerTime(0), + m_inChord(false), + m_inGroup(false), + m_inComposition(false), + m_groupId(0), + m_foundTempo(false), + m_section(NoSection), + m_device(0), + m_deviceRunningId(Device::NO_DEVICE), + m_msb(0), + m_lsb(0), + m_instrument(0), + m_plugin(0), + m_pluginInBuss(false), + m_colourMap(0), + m_keyMapping(0), + m_pluginId(0), + m_totalElements(elementCount), + m_elementsSoFar(0), + m_subHandler(0), + m_deprecation(false), + m_createDevices(createNewDevicesWhenNeeded), + m_haveControls(false), + m_cancelled(false), + m_skipAllAudio(false), + m_hasActiveAudio(false) +{} + +RoseXmlHandler::~RoseXmlHandler() +{ + delete m_subHandler; +} + +Composition & +RoseXmlHandler::getComposition() +{ + return m_doc->getComposition(); +} + +Studio & +RoseXmlHandler::getStudio() +{ + return m_doc->getStudio(); +} + +AudioFileManager & +RoseXmlHandler::getAudioFileManager() +{ + return m_doc->getAudioFileManager(); +} + +AudioPluginManager * +RoseXmlHandler::getAudioPluginManager() +{ + return m_doc->getPluginManager(); +} + +bool +RoseXmlHandler::startDocument() +{ + // Clear tracks + // + getComposition().clearTracks(); + + // And the loop + // + getComposition().setLoopStart(0); + getComposition().setLoopEnd(0); + + // All plugins + // + m_doc->clearAllPlugins(); + + // reset state + return true; +} + +bool +RoseXmlHandler::startElement(const QString& namespaceURI, + const QString& localName, + const QString& qName, const QXmlAttributes& atts) +{ + // First check if user pressed cancel button on the progress + // dialog + // + if (isOperationCancelled()) { + // Ideally, we'd throw here, but at this point Qt is in the stack + // and Qt is very often compiled without exception support. + // + m_cancelled = true; + return false; + } + + QString lcName = qName.lower(); + + if (getSubHandler()) { + return getSubHandler()->startElement(namespaceURI, localName, lcName, atts); + } + + if (lcName == "event") { + + // RG_DEBUG << "RoseXmlHandler::startElement: found event, current time is " << m_currentTime << endl; + + if (m_currentEvent) { + RG_DEBUG << "RoseXmlHandler::startElement: Warning: new event found at time " << m_currentTime << " before previous event has ended; previous event will be lost" << endl; + delete m_currentEvent; + } + + m_currentEvent = new XmlStorableEvent(atts, m_currentTime); + + if (m_currentEvent->has(BEAMED_GROUP_ID)) { + + // remap -- we want to ensure that the segment's nextId + // is always used (and incremented) in preference to the + // stored id + + if (!m_currentSegment) { + m_errorString = "Got grouped event outside of a segment"; + return false; + } + + long storedId = m_currentEvent->get + <Int>(BEAMED_GROUP_ID); + + if (m_groupIdMap.find(storedId) == m_groupIdMap.end()) { + m_groupIdMap[storedId] = m_currentSegment->getNextId(); + } + + m_currentEvent->set + <Int>(BEAMED_GROUP_ID, m_groupIdMap[storedId]); + + } else if (m_inGroup) { + m_currentEvent->set + <Int>(BEAMED_GROUP_ID, m_groupId); + m_currentEvent->set + <String>(BEAMED_GROUP_TYPE, m_groupType); + if (m_groupType == GROUP_TYPE_TUPLED) { + m_currentEvent->set + <Int> + (BEAMED_GROUP_TUPLET_BASE, m_groupTupletBase); + m_currentEvent->set + <Int> + (BEAMED_GROUP_TUPLED_COUNT, m_groupTupledCount); + m_currentEvent->set + <Int> + (BEAMED_GROUP_UNTUPLED_COUNT, m_groupUntupledCount); + } + } + + timeT duration = m_currentEvent->getDuration(); + + if (!m_inChord) { + + m_currentTime = m_currentEvent->getAbsoluteTime() + duration; + + // RG_DEBUG << "RoseXmlHandler::startElement: (we're not in a chord) " << endl; + + } else if (duration != 0) { + + // set chord duration to the duration of the shortest + // element with a non-null duration (if no such elements, + // leave it as 0). + + if (m_chordDuration == 0 || duration < m_chordDuration) { + m_chordDuration = duration; + } + } + + } else if (lcName == "property") { + + if (!m_currentEvent) { + RG_DEBUG << "RoseXmlHandler::startElement: Warning: Found property outside of event at time " << m_currentTime << ", ignoring" << endl; + } else { + m_currentEvent->setPropertyFromAttributes(atts, true); + } + + } else if (lcName == "nproperty") { + + if (!m_currentEvent) { + RG_DEBUG << "RoseXmlHandler::startElement: Warning: Found nproperty outside of event at time " << m_currentTime << ", ignoring" << endl; + } else { + m_currentEvent->setPropertyFromAttributes(atts, false); + } + + } else if (lcName == "chord") { + + m_inChord = true; + + } else if (lcName == "group") { + + if (!m_currentSegment) { + m_errorString = "Got group outside of a segment"; + return false; + } + + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"group\". We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + + m_inGroup = true; + m_groupId = m_currentSegment->getNextId(); + m_groupType = qstrtostr(atts.value("type")); + + if (m_groupType == GROUP_TYPE_TUPLED) { + m_groupTupletBase = atts.value("base").toInt(); + m_groupTupledCount = atts.value("tupled").toInt(); + m_groupUntupledCount = atts.value("untupled").toInt(); + } + + } else if (lcName == "rosegarden-data") { + + // FILE FORMAT VERSIONING -- see comments in + // rosegardenguidoc.cpp. We only care about major and minor + // here, not point. + + QString version = atts.value("version"); + QString smajor = atts.value("format-version-major"); + QString sminor = atts.value("format-version-minor"); + +// std::cerr << "\n\n\nRosegarden file version = \"" << version << "\"\n\n\n" << std::endl; + + if (smajor) { + + int major = smajor.toInt(); + int minor = sminor.toInt(); + + if (major > RosegardenGUIDoc::FILE_FORMAT_VERSION_MAJOR) { + m_errorString = i18n("This file was written by Rosegarden %1, and it uses\na different file format that cannot be read by this version.").arg(version); + return false; + } + + if (major == RosegardenGUIDoc::FILE_FORMAT_VERSION_MAJOR && + minor > RosegardenGUIDoc::FILE_FORMAT_VERSION_MINOR) { + + CurrentProgressDialog::freeze(); + KStartupLogo::hideIfStillThere(); + + KMessageBox::information(0, i18n("This file was written by Rosegarden %1, which is more recent than this version.\nThere may be some incompatibilities with the file format.").arg(version)); + + CurrentProgressDialog::thaw(); + } + } + + } else if (lcName == "studio") { + + if (m_section != NoSection) { + m_errorString = "Found Studio in another section"; + return false; + } + + // In the Studio we clear down everything apart from Devices and + // Instruments before we reload. Instruments are derived from + // the Sequencer, the bank/program information is loaded from + // the file we're currently examining. + // + getStudio().clearMidiBanksAndPrograms(); + getStudio().clearBusses(); + getStudio().clearRecordIns(); + + m_section = InStudio; // set top level section + + // Get and set MIDI filters + // + QString thruStr = atts.value("thrufilter"); + + if (thruStr) + getStudio().setMIDIThruFilter(thruStr.toInt()); + + QString recordStr = atts.value("recordfilter"); + + if (recordStr) + getStudio().setMIDIRecordFilter(recordStr.toInt()); + + QString inputStr = atts.value("audioinputpairs"); + + if (inputStr) { + int inputs = inputStr.toInt(); + if (inputs < 1) + inputs = 1; // we simply don't permit no inputs + while (int(getStudio().getRecordIns().size()) < inputs) { + getStudio().addRecordIn(new RecordIn()); + } + } + + QString mixerStr = atts.value("mixerdisplayoptions"); + + if (mixerStr) { + unsigned int mixer = mixerStr.toUInt(); + getStudio().setMixerDisplayOptions(mixer); + } + + QString metronomeStr = atts.value("metronomedevice"); + + if (metronomeStr) { + DeviceId metronome = metronomeStr.toUInt(); + getStudio().setMetronomeDevice(metronome); + } + + } else if (lcName == "timesignature") { + + if (m_inComposition == false) { + m_errorString = "TimeSignature object found outside Composition"; + return false; + } + + timeT t = 0; + QString timeStr = atts.value("time"); + if (timeStr) + t = timeStr.toInt(); + + int num = 4; + QString numStr = atts.value("numerator"); + if (numStr) + num = numStr.toInt(); + + int denom = 4; + QString denomStr = atts.value("denominator"); + if (denomStr) + denom = denomStr.toInt(); + + bool common = false; + QString commonStr = atts.value("common"); + if (commonStr) + common = (commonStr == "true"); + + bool hidden = false; + QString hiddenStr = atts.value("hidden"); + if (hiddenStr) + hidden = (hiddenStr == "true"); + + bool hiddenBars = false; + QString hiddenBarsStr = atts.value("hiddenbars"); + if (hiddenBarsStr) + hiddenBars = (hiddenBarsStr == "true"); + + getComposition().addTimeSignature + (t, TimeSignature(num, denom, common, hidden, hiddenBars)); + + } else if (lcName == "tempo") { + + timeT t = 0; + QString timeStr = atts.value("time"); + if (timeStr) + t = timeStr.toInt(); + + tempoT tempo = Composition::getTempoForQpm(120.0); + QString tempoStr = atts.value("tempo"); + QString targetStr = atts.value("target"); + QString bphStr = atts.value("bph"); + if (tempoStr) { + tempo = tempoStr.toInt(); + } else if (bphStr) { + tempo = Composition::getTempoForQpm + (double(bphStr.toInt()) / 60.0); + } + + if (targetStr) { + getComposition().addTempoAtTime(t, tempo, targetStr.toInt()); + } else { + getComposition().addTempoAtTime(t, tempo); + } + + } else if (lcName == "composition") { + + if (m_section != NoSection) { + m_errorString = "Found Composition in another section"; + return false; + } + + // set Segment + m_section = InComposition; + + // Get and set the record track + // + QString recordStr = atts.value("recordtrack"); + if (recordStr) { + getComposition().setTrackRecording(recordStr.toInt(), true); + } + + QString recordPlStr = atts.value("recordtracks"); + if (recordPlStr) { + RG_DEBUG << "Record tracks: " << recordPlStr << endl; + QStringList recordList = QStringList::split(',', recordPlStr); + for (QStringList::iterator i = recordList.begin(); + i != recordList.end(); ++i) { + RG_DEBUG << "Record track: " << (*i).toInt() << endl; + getComposition().setTrackRecording((*i).toInt(), true); + } + } + + // Get and set the position pointer + // + int position = 0; + QString positionStr = atts.value("pointer"); + if (positionStr) { + position = positionStr.toInt(); + } + + getComposition().setPosition(position); + + + // Get and (eventually) set the default tempo. + // We prefer the new compositionDefaultTempo over the + // older defaultTempo. + // + QString tempoStr = atts.value("compositionDefaultTempo"); + if (tempoStr) { + tempoT tempo = tempoT(tempoStr.toInt()); + getComposition().setCompositionDefaultTempo(tempo); + } else { + tempoStr = atts.value("defaultTempo"); + if (tempoStr) { + double tempo = qstrtodouble(tempoStr); + getComposition().setCompositionDefaultTempo + (Composition::getTempoForQpm(tempo)); + } + } + + // set the composition flag + m_inComposition = true; + + + // Set the loop + // + QString loopStartStr = atts.value("loopstart"); + QString loopEndStr = atts.value("loopend"); + + if (loopStartStr && loopEndStr) { + int loopStart = loopStartStr.toInt(); + int loopEnd = loopEndStr.toInt(); + + getComposition().setLoopStart(loopStart); + getComposition().setLoopEnd(loopEnd); + } + + QString selectedTrackStr = atts.value("selected"); + + if (selectedTrackStr) { + TrackId selectedTrack = + (TrackId)selectedTrackStr.toInt(); + + getComposition().setSelectedTrack(selectedTrack); + } + + QString soloTrackStr = atts.value("solo"); + if (soloTrackStr) { + if (soloTrackStr.toInt() == 1) + getComposition().setSolo(true); + else + getComposition().setSolo(false); + } + + + QString playMetStr = atts.value("playmetronome"); + if (playMetStr) { + if (playMetStr.toInt()) + getComposition().setPlayMetronome(true); + else + getComposition().setPlayMetronome(false); + } + + QString recMetStr = atts.value("recordmetronome"); + if (recMetStr) { + if (recMetStr.toInt()) + getComposition().setRecordMetronome(true); + else + getComposition().setRecordMetronome(false); + } + + QString nextTriggerIdStr = atts.value("nexttriggerid"); + if (nextTriggerIdStr) { + getComposition().setNextTriggerSegmentId(nextTriggerIdStr.toInt()); + } + + QString copyrightStr = atts.value("copyright"); + if (copyrightStr) { + getComposition().setCopyrightNote(qstrtostr(copyrightStr)); + } + + QString startMarkerStr = atts.value("startMarker"); + QString endMarkerStr = atts.value("endMarker"); + + if (startMarkerStr) { + getComposition().setStartMarker(startMarkerStr.toInt()); + } + + if (endMarkerStr) { + getComposition().setEndMarker(endMarkerStr.toInt()); + } + + } else if (lcName == "track") { + + if (m_section != InComposition) { + m_errorString = "Track object found outside Composition"; + return false; + } + + int id = -1; + int position = -1; + int instrument = -1; + std::string label; + bool muted = false; + + QString trackNbStr = atts.value("id"); + if (trackNbStr) { + id = trackNbStr.toInt(); + } + + QString labelStr = atts.value("label"); + if (labelStr) { + label = qstrtostr(labelStr); + } + + QString mutedStr = atts.value("muted"); + if (mutedStr) { + if (mutedStr == "true") + muted = true; + else + muted = false; + } + + QString positionStr = atts.value("position"); + if (positionStr) { + position = positionStr.toInt(); + } + + QString instrumentStr = atts.value("instrument"); + if (instrumentStr) { + instrument = instrumentStr.toInt(); + } + + Track *track = new Track(id, + instrument, + position, + label, + muted); + + // track properties affecting newly created segments are initialized + // to default values in the ctor, so they don't need to be initialized + // here + + QString presetLabelStr = atts.value("defaultLabel"); + if (labelStr) { + track->setPresetLabel(presetLabelStr); + } + + QString clefStr = atts.value("defaultClef"); + if (clefStr) { + track->setClef(clefStr.toInt()); + } + + QString transposeStr = atts.value("defaultTranspose"); + if (transposeStr) { + track->setTranspose(transposeStr.toInt()); + } + + QString colorStr = atts.value("defaultColour"); + if (colorStr) { + track->setColor(colorStr.toInt()); + } + + QString highplayStr = atts.value("defaultHighestPlayable"); + if (highplayStr) { + track->setHighestPlayable(highplayStr.toInt()); + } + + QString lowplayStr = atts.value("defaultLowestPlayable"); + if (lowplayStr) { + track->setLowestPlayable(lowplayStr.toInt()); + } + + QString staffSizeStr = atts.value("staffSize"); + if (staffSizeStr) { + track->setStaffSize(staffSizeStr.toInt()); + } + + QString staffBracketStr = atts.value("staffBracket"); + if (staffBracketStr) { + track->setStaffBracket(staffBracketStr.toInt()); + } + + getComposition().addTrack(track); + + + } else if (lcName == "segment") { + + if (m_section != NoSection) { + m_errorString = "Found Segment in another section"; + return false; + } + + // set Segment + m_section = InSegment; + + int track = -1, startTime = 0; + unsigned int colourindex = 0; + QString trackNbStr = atts.value("track"); + if (trackNbStr) { + track = trackNbStr.toInt(); + } + + QString startIdxStr = atts.value("start"); + if (startIdxStr) { + startTime = startIdxStr.toInt(); + } + + QString segmentType = (atts.value("type")).lower(); + if (segmentType) { + if (segmentType == "audio") { + int audioFileId = atts.value("file").toInt(); + + // check this file id exists on the AudioFileManager + + if (getAudioFileManager().fileExists(audioFileId) == false) { + // We don't report an error as this audio file might've + // been excluded deliberately as we could't actually + // find the audio file itself. + // + return true; + } + + // Create an Audio segment and add its reference + // + m_currentSegment = new Segment(Segment::Audio); + m_currentSegment->setAudioFileId(audioFileId); + m_currentSegment->setStartTime(startTime); + } else { + // Create a (normal) internal Segment + m_currentSegment = new Segment(Segment::Internal); + } + + } else { + // for the moment we default + m_currentSegment = new Segment(Segment::Internal); + } + + QString repeatStr = atts.value("repeat"); + if (repeatStr.lower() == "true") { + m_currentSegment->setRepeating(true); + } + + QString delayStr = atts.value("delay"); + if (delayStr) { + RG_DEBUG << "Delay string is \"" << delayStr << "\"" << endl; + long delay = delayStr.toLong(); + RG_DEBUG << "Delay is " << delay << endl; + m_currentSegment->setDelay(delay); + } + + QString rtDelaynSec = atts.value("rtdelaynsec"); + QString rtDelayuSec = atts.value("rtdelayusec"); + QString rtDelaySec = atts.value("rtdelaysec"); + if (rtDelaySec && (rtDelaynSec || rtDelayuSec)) { + if (rtDelaynSec) { + m_currentSegment->setRealTimeDelay + (RealTime(rtDelaySec.toInt(), + rtDelaynSec.toInt())); + } else { + m_currentSegment->setRealTimeDelay + (RealTime(rtDelaySec.toInt(), + rtDelayuSec.toInt() * 1000)); + } + } + + QString transposeStr = atts.value("transpose"); + if (transposeStr) + m_currentSegment->setTranspose(transposeStr.toInt()); + + // fill in the label + QString labelStr = atts.value("label"); + if (labelStr) + m_currentSegment->setLabel(qstrtostr(labelStr)); + + m_currentSegment->setTrack(track); + //m_currentSegment->setStartTime(startTime); + + QString colourIndStr = atts.value("colourindex"); + if (colourIndStr) { + colourindex = colourIndStr.toInt(); + } + + m_currentSegment->setColourIndex(colourindex); + + QString snapGridSizeStr = atts.value("snapgridsize"); + if (snapGridSizeStr) { + m_currentSegment->setSnapGridSize(snapGridSizeStr.toInt()); + } + + QString viewFeaturesStr = atts.value("viewfeatures"); + if (viewFeaturesStr) { + m_currentSegment->setViewFeatures(viewFeaturesStr.toInt()); + } + + m_currentTime = startTime; + + QString triggerIdStr = atts.value("triggerid"); + QString triggerPitchStr = atts.value("triggerbasepitch"); + QString triggerVelocityStr = atts.value("triggerbasevelocity"); + QString triggerRetuneStr = atts.value("triggerretune"); + QString triggerAdjustTimeStr = atts.value("triggeradjusttimes"); + + if (triggerIdStr) { + int pitch = -1; + if (triggerPitchStr) + pitch = triggerPitchStr.toInt(); + int velocity = -1; + if (triggerVelocityStr) + velocity = triggerVelocityStr.toInt(); + TriggerSegmentRec *rec = + getComposition().addTriggerSegment(m_currentSegment, + triggerIdStr.toInt(), + pitch, velocity); + if (rec) { + if (triggerRetuneStr) + rec->setDefaultRetune(triggerRetuneStr.lower() == "true"); + if (triggerAdjustTimeStr) + rec->setDefaultTimeAdjust(qstrtostr(triggerAdjustTimeStr)); + } + m_currentSegment->setStartTimeDataMember(startTime); + } else { + getComposition().addSegment(m_currentSegment); + getComposition().setSegmentStartTime(m_currentSegment, startTime); + } + + QString endMarkerStr = atts.value("endmarker"); + if (endMarkerStr) { + delete m_segmentEndMarkerTime; + m_segmentEndMarkerTime = new timeT(endMarkerStr.toInt()); + } + + m_groupIdMap.clear(); + + } else if (lcName == "gui") { + + if (m_section != InSegment) { + m_errorString = "Found GUI element outside Segment"; + return false; + } + + } else if (lcName == "controller") { + + if (m_section != InSegment) { + m_errorString = "Found Controller element outside Segment"; + return false; + } + + QString type = atts.value("type"); + //RG_DEBUG << "RoseXmlHandler::startElement - controller type = " << type << endl; + + if (type == strtoqstr(PitchBend::EventType)) + m_currentSegment->addEventRuler(PitchBend::EventType); + else if (type == strtoqstr(Controller::EventType)) { + QString value = atts.value("value"); + + if (value != "") + m_currentSegment->addEventRuler(Controller::EventType, value.toInt()); + } + + } else if (lcName == "resync") { + + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"resync\". We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + + QString time(atts.value("time")); + bool isNumeric; + int numTime = time.toInt(&isNumeric); + if (isNumeric) + m_currentTime = numTime; + + } else if (lcName == "audio") { + + if (m_section != InAudioFiles) { + m_errorString = "Audio object found outside Audio section"; + return false; + } + + if (m_skipAllAudio) { + std::cout << "SKIPPING audio file" << std::endl; + return true; + } + + QString id(atts.value("id")); + QString file(atts.value("file")); + QString label(atts.value("label")); + + if (id.isEmpty() || file.isEmpty() || label.isEmpty()) { + m_errorString = "Audio object has empty parameters"; + return false; + } + + m_hasActiveAudio = true; + + // attempt to insert file into AudioFileManager + // (this checks the integrity of the file at the + // same time) + // + if (getAudioFileManager().insertFile(qstrtostr(label), + qstrtostr(file), + id.toInt()) == false) { + // Ok, now attempt to use the KFileDialog saved default + // value for the AudioPath. + // + QString thing; + KURL url = KFileDialog::getStartURL(QString(":WAVS"), thing); + getAudioFileManager().setAudioPath(url.path().latin1()); + + /* + RG_DEBUG << "ATTEMPTING TO FIND IN PATH = " + << url.path() << endl; + */ + + if (getAudioFileManager(). + insertFile(qstrtostr(label), + qstrtostr(file), id.toInt()) == false) { + + // Freeze the progress dialog + CurrentProgressDialog::freeze(); + + // Hide splash screen if present on startup + KStartupLogo::hideIfStillThere(); + + // Create a locate file dialog - give it the file name + // and the AudioFileManager path that we've already + // tried. If we manually locate the file then we reset + // the audiofilepath to the new value and see if this + // helps us locate the rest of the files. + // + + QString newFilename = ""; + QString newPath = ""; + + do { + + FileLocateDialog fL((RosegardenGUIApp *)m_doc->parent(), + file, + QString(getAudioFileManager().getAudioPath().c_str())); + int result = fL.exec(); + + if (result == QDialog::Accepted) { + newFilename = fL.getFilename(); + newPath = fL.getDirectory(); + } else if (result == QDialog::Rejected) { + // just skip the file + break; + } else { + // don't process any more audio files + m_skipAllAudio = true; + CurrentProgressDialog::thaw(); + return true; + } + + + } while (getAudioFileManager().insertFile(qstrtostr(label), + qstrtostr(newFilename), + id.toInt()) == false); + + if (newPath != "") { + getAudioFileManager().setAudioPath(qstrtostr(newPath)); + // Set a document post-modify flag + //m_doc->setModified(true); + } + + getAudioFileManager().print(); + + // Restore progress dialog's normal state + CurrentProgressDialog::thaw(); + } else { + // AudioPath is modified so set a document post modify flag + // + //m_doc->setModified(true); + } + + } + + } else if (lcName == "audiopath") { + + if (m_section != InAudioFiles) { + m_errorString = "Audiopath object found outside AudioFiles section"; + return false; + } + + QString search(atts.value("value")); + + if (search.isEmpty()) { + m_errorString = "Audiopath has no value"; + return false; + } + + if (!search.startsWith("/") && !search.startsWith("~")) { + QString docPath = m_doc->getAbsFilePath(); + QString dirPath = QFileInfo(docPath).dirPath(); + if (QFileInfo(dirPath).exists()) { + search = dirPath + "/" + search; + } + } + + getAudioFileManager().setAudioPath(qstrtostr(search)); + + } else if (lcName == "begin") { + + double marker = qstrtodouble(atts.value("index")); + + if (!m_currentSegment) { + // Don't fail - as this segment could be defunct if we + // skipped loading the audio file + // + return true; + } + + if (m_currentSegment->getType() != Segment::Audio) { + m_errorString = "Found audio begin index in non audio segment"; + return false; + } + + // convert to RealTime from float + int sec = (int)marker; + int usec = (int)((marker - ((double)sec)) * 1000000.0); + m_currentSegment->setAudioStartTime(RealTime(sec, usec * 1000)); + + + } else if (lcName == "end") { + + double marker = qstrtodouble(atts.value("index")); + + if (!m_currentSegment) { + // Don't fail - as this segment could be defunct if we + // skipped loading the audio file + // + return true; + } + + if (m_currentSegment->getType() != Segment::Audio) { + m_errorString = "found audio end index in non audio segment"; + return false; + } + + int sec = (int)marker; + int usec = (int)((marker - ((double)sec)) * 1000000.0); + RealTime markerTime(sec, usec * 1000); + + if (markerTime < m_currentSegment->getAudioStartTime()) { + m_errorString = "Audio end index before audio start marker"; + return false; + } + + m_currentSegment->setAudioEndTime(markerTime); + + // Ensure we set end time according to correct RealTime end of Segment + // + RealTime realEndTime = getComposition(). + getElapsedRealTime(m_currentSegment->getStartTime()) + + m_currentSegment->getAudioEndTime() - + m_currentSegment->getAudioStartTime(); + + timeT absEnd = getComposition().getElapsedTimeForRealTime(realEndTime); + m_currentSegment->setEndTime(absEnd); + + } else if (lcName == "fadein") { + + if (!m_currentSegment) { + // Don't fail - as this segment could be defunct if we + // skipped loading the audio file + // + return true; + } + + if (m_currentSegment->getType() != Segment::Audio) { + m_errorString = "found fade in time in non audio segment"; + return false; + } + + double marker = qstrtodouble(atts.value("time")); + int sec = (int)marker; + int usec = (int)((marker - ((double)sec)) * 1000000.0); + RealTime markerTime(sec, usec * 1000); + + m_currentSegment->setFadeInTime(markerTime); + m_currentSegment->setAutoFade(true); + + + } else if (lcName == "fadeout") { + + if (!m_currentSegment) { + // Don't fail - as this segment could be defunct if we + // skipped loading the audio file + // + return true; + } + + if (m_currentSegment->getType() != Segment::Audio) { + m_errorString = "found fade out time in non audio segment"; + return false; + } + + double marker = qstrtodouble(atts.value("time")); + int sec = (int)marker; + int usec = (int)((marker - ((double)sec)) * 1000000.0); + RealTime markerTime(sec, usec * 1000); + + m_currentSegment->setFadeOutTime(markerTime); + m_currentSegment->setAutoFade(true); + + } else if (lcName == "device") { + + if (m_section != InStudio) { + m_errorString = "Found Device outside Studio"; + return false; + } + + m_haveControls = false; + + QString type = (atts.value("type")).lower(); + QString idString = atts.value("id"); + QString nameStr = atts.value("name"); + + if (idString.isNull()) { + m_errorString = "No ID on Device tag"; + return false; + } + int id = idString.toInt(); + + if (type == "midi") { + QString direction = atts.value("direction").lower(); + + if (direction.isNull() || + direction == "" || + direction == "play") { // ignore inputs + + // This will leave m_device set only if there is a + // valid play midi device to modify: + skipToNextPlayDevice(); + + if (m_device) { + if (nameStr && nameStr != "") { + m_device->setName(qstrtostr(nameStr)); + } + } else if (nameStr && nameStr != "") { + addMIDIDevice(nameStr, m_createDevices); // also sets m_device + } + } + + QString connection = atts.value("connection"); + if (m_createDevices && m_device && + !connection.isNull() && connection != "") { + setMIDIDeviceConnection(connection); + } + + setMIDIDeviceName(nameStr); + + QString vstr = atts.value("variation").lower(); + MidiDevice::VariationType variation = + MidiDevice::NoVariations; + if (!vstr.isNull()) { + if (vstr == "lsb") { + variation = MidiDevice::VariationFromLSB; + } else if (vstr == "msb") { + variation = MidiDevice::VariationFromMSB; + } else if (vstr == "") { + variation = MidiDevice::NoVariations; + } + } + MidiDevice *md = dynamic_cast<MidiDevice *> + (m_device); + if (md) { + md->setVariationType(variation); + } + } else if (type == "softsynth") { + m_device = getStudio().getDevice(id); + + if (m_device && m_device->getType() == Device::SoftSynth) + m_device->setName(qstrtostr(nameStr)); + } else if (type == "audio") { + m_device = getStudio().getDevice(id); + + if (m_device && m_device->getType() == Device::Audio) + m_device->setName(qstrtostr(nameStr)); + } else { + m_errorString = "Found unknown Device type"; + return false; + } + + } else if (lcName == "librarian") { + + // The contact details for the maintainer of the banks/programs + // information. + // + if (m_device && m_device->getType() == Device::Midi) { + QString name = atts.value("name"); + QString email = atts.value("email"); + + dynamic_cast<MidiDevice*>(m_device)-> + setLibrarian(qstrtostr(name), qstrtostr(email)); + } + + } else if (lcName == "bank") { + + if (m_device) // only if we have a device + { + if (m_section != InStudio && m_section != InInstrument) + { + m_errorString = "Found Bank outside Studio or Instrument"; + return false; + } + + QString nameStr = atts.value("name"); + m_percussion = (atts.value("percussion").lower() == "true"); + m_msb = (atts.value("msb")).toInt(); + m_lsb = (atts.value("lsb")).toInt(); + + // To actually create a bank + // + if (m_section == InStudio) + { + // Create a new bank + MidiBank bank(m_percussion, + m_msb, + m_lsb, + qstrtostr(nameStr)); + + if (m_device->getType() == Device::Midi) { + // Insert the bank + // + dynamic_cast<MidiDevice*>(m_device)->addBank(bank); + } + } else // otherwise we're referencing it in an instrument + if (m_section == InInstrument) + { + if (m_instrument) { + m_instrument->setPercussion(m_percussion); + m_instrument->setMSB(m_msb); + m_instrument->setLSB(m_lsb); + m_instrument->setSendBankSelect(true); + } + } + } + + } else if (lcName == "program") { + + if (m_device) // only if we have a device + { + if (m_section == InStudio) + { + QString nameStr = (atts.value("name")); + MidiByte pc = atts.value("id").toInt(); + QString keyMappingStr = (atts.value("keymapping")); + + // Create a new program + MidiProgram program + (MidiBank(m_percussion, + m_msb, + m_lsb), + pc, + qstrtostr(nameStr), + keyMappingStr ? qstrtostr(keyMappingStr) : ""); + + if (m_device->getType() == Device::Midi) { + // Insert the program + // + dynamic_cast<MidiDevice*>(m_device)-> + addProgram(program); + } + + } else if (m_section == InInstrument) + { + if (m_instrument) { + MidiByte id = atts.value("id").toInt(); + m_instrument->setProgramChange(id); + m_instrument->setSendProgramChange(true); + } + } else + { + m_errorString = "Found Program outside Studio and Instrument"; + return false; + } + } + + } else if (lcName == "keymapping") { + + if (m_section == InInstrument) { + RG_DEBUG << "Old-style keymapping in instrument found, ignoring" << endl; + } else { + + if (m_section != InStudio) { + m_errorString = "Found Keymapping outside Studio"; + return false; + } + + if (m_device && (m_device->getType() == Device::Midi)) { + QString name = atts.value("name"); + m_keyMapping = new MidiKeyMapping(qstrtostr(name)); + m_keyNameMap.clear(); + } + } + + } else if (lcName == "key") { + + if (m_keyMapping) { + QString numStr = atts.value("number"); + QString namStr = atts.value("name"); + if (numStr && namStr) { + m_keyNameMap[numStr.toInt()] = qstrtostr(namStr); + } + } + + } else if (lcName == "controls") { + + // Only clear down the controllers list if we have found some controllers in the RG file + // + if (m_device) { + dynamic_cast<MidiDevice*>(m_device)->clearControlList(); + } + + m_haveControls = true; + + } else if (lcName == "control") { + + if (m_section != InStudio) { + m_errorString = "Found ControlParameter outside Studio"; + return false; + } + + if (!m_device) { + //!!! ach no, we can't give this warning -- we might be in a <device> elt + // but have no sequencer support, for example. we need a separate m_inDevice + // flag + // m_deprecation = true; + // std::cerr << "WARNING: This Rosegarden file uses a deprecated control parameter structure. We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + + } else if (m_device->getType() == Device::Midi) { + + if (!m_haveControls) { + m_errorString = "Found ControlParameter outside Controls block"; + return false; + } + + QString name = atts.value("name"); + QString type = atts.value("type"); + QString descr = atts.value("description"); + QString min = atts.value("min"); + QString max = atts.value("max"); + QString def = atts.value("default"); + QString conVal = atts.value("controllervalue"); + QString colour = atts.value("colourindex"); + QString ipbPosition = atts.value("ipbposition"); + + ControlParameter con(qstrtostr(name), + qstrtostr(type), + qstrtostr(descr), + min.toInt(), + max.toInt(), + def.toInt(), + MidiByte(conVal.toInt()), + colour.toInt(), + ipbPosition.toInt()); + + dynamic_cast<MidiDevice*>(m_device)-> + addControlParameter(con); + } + + } else if (lcName == "reverb") { // deprecated but we still read 'em + + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"reverb\" (now replaced by a control parameter). We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + + if (m_section != InInstrument) { + m_errorString = "Found Reverb outside Instrument"; + return false; + } + + MidiByte value = atts.value("value").toInt(); + + if (m_instrument) + m_instrument->setControllerValue(MIDI_CONTROLLER_REVERB, value); + + + } else if (lcName == "chorus") { // deprecated but we still read 'em + + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"chorus\" (now replaced by a control parameter). We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + + if (m_section != InInstrument) { + m_errorString = "Found Chorus outside Instrument"; + return false; + } + + MidiByte value = atts.value("value").toInt(); + + if (m_instrument) + m_instrument->setControllerValue(MIDI_CONTROLLER_CHORUS, value); + + } else if (lcName == "filter") { // deprecated but we still read 'em + + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"filter\" (now replaced by a control parameter). We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + + if (m_section != InInstrument) { + m_errorString = "Found Filter outside Instrument"; + return false; + } + + MidiByte value = atts.value("value").toInt(); + + if (m_instrument) + m_instrument->setControllerValue(MIDI_CONTROLLER_FILTER, value); + + + } else if (lcName == "resonance") { // deprecated but we still read 'em + + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"resonance\" (now replaced by a control parameter). We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + + if (m_section != InInstrument) { + m_errorString = "Found Resonance outside Instrument"; + return false; + } + + MidiByte value = atts.value("value").toInt(); + + if (m_instrument) + m_instrument->setControllerValue(MIDI_CONTROLLER_RESONANCE, value); + + + } else if (lcName == "attack") { // deprecated but we still read 'em + + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"attack\" (now replaced by a control parameter). We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + + if (m_section != InInstrument) { + m_errorString = "Found Attack outside Instrument"; + return false; + } + + MidiByte value = atts.value("value").toInt(); + + if (m_instrument) + m_instrument->setControllerValue(MIDI_CONTROLLER_ATTACK, value); + + } else if (lcName == "release") { // deprecated but we still read 'em + + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"release\" (now replaced by a control parameter). We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + + if (m_section != InInstrument) { + m_errorString = "Found Release outside Instrument"; + return false; + } + + MidiByte value = atts.value("value").toInt(); + + if (m_instrument) + m_instrument->setControllerValue(MIDI_CONTROLLER_RELEASE, value); + + } else if (lcName == "pan") { + + if (m_section != InInstrument && m_section != InBuss) { + m_errorString = "Found Pan outside Instrument or Buss"; + return false; + } + + MidiByte value = atts.value("value").toInt(); + + if (m_section == InInstrument) { + if (m_instrument) { + m_instrument->setPan(value); + m_instrument->setSendPan(true); + } + } else if (m_section == InBuss) { + if (m_buss) { + m_buss->setPan(value); + } + } + + // keep "velocity" so we're backwards compatible + } else if (lcName == "velocity" || lcName == "volume") { + + if (lcName == "velocity") { + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"velocity\" for an overall MIDI instrument level (now replaced by \"volume\"). We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + } + + if (m_section != InInstrument) { + m_errorString = "Found Volume outside Instrument"; + return false; + } + + MidiByte value = atts.value("value").toInt(); + + if (m_instrument) { + if (m_instrument->getType() == Instrument::Audio || + m_instrument->getType() == Instrument::SoftSynth) { + // Backward compatibility: "volume" was in a 0-127 + // range and we now store "level" (float dB) instead. + // Note that we have no such compatibility for + // "recordLevel", whose range has changed silently. + if (!m_deprecation) + std::cerr << "WARNING: This Rosegarden file uses the deprecated element \"volume\" for an audio instrument (now replaced by \"level\"). We recommend re-saving the file from this version of Rosegarden to assure your ability to re-load it in future versions" << std::endl; + m_deprecation = true; + m_instrument->setLevel + (AudioLevel::multiplier_to_dB(float(value) / 100.0)); + } else { + m_instrument->setVolume(value); + m_instrument->setSendVolume(true); + } + } + + } else if (lcName == "level") { + + if (m_section != InBuss && + (m_section != InInstrument || + (m_instrument && + m_instrument->getType() != Instrument::Audio && + m_instrument->getType() != Instrument::SoftSynth))) { + m_errorString = "Found Level outside (audio) Instrument or Buss"; + return false; + } + + double value = qstrtodouble(atts.value("value")); + + if (m_section == InBuss) { + if (m_buss) + m_buss->setLevel(value); + } else { + if (m_instrument) + m_instrument->setLevel(value); + } + + } else if (lcName == "controlchange") { + + if (m_section != InInstrument) { + m_errorString = "Found ControlChange outside Instrument"; + return false; + } + + MidiByte type = atts.value("type").toInt(); + MidiByte value = atts.value("value").toInt(); + + if (m_instrument) { + m_instrument->setControllerValue(type, value); + } + + } else if (lcName == "plugin" || lcName == "synth") { + + PluginContainer *container = 0; + + if (m_section == InInstrument) { +// std::cerr << "Found plugin in instrument" << std::endl; + container = m_instrument; + m_pluginInBuss = false; + } else if (m_section == InBuss) { +// std::cerr << "Found plugin in buss" << std::endl; + container = m_buss; + m_pluginInBuss = true; + } else { + m_errorString = "Found Plugin outside Instrument or Buss"; + return false; + } + + // Despite being InInstrument or InBuss we might not actually + // have a valid one. + // + if (container) { + +// std::cerr << "Have container" << std::endl; + + emit setOperationName(i18n("Loading plugins...")); + ProgressDialog::processEvents(); + + // Get the details + int position; + if (lcName == "synth") { + position = Instrument::SYNTH_PLUGIN_POSITION; + } else { + position = atts.value("position").toInt(); + } + + bool bypassed = false; + QString bpStr = atts.value("bypassed"); + if (bpStr.lower() == "true") + bypassed = true; + + std::string program = ""; + QString progStr = atts.value("program"); + if (progStr) { + program = qstrtostr(progStr); + } + + // Plugins are identified by a structured identifier + // string, but we will accept a LADSPA UniqueId if there's + // no identifier, for backward compatibility + + QString identifier = atts.value("identifier"); + + AudioPlugin *plugin = 0; + AudioPluginManager *apm = getAudioPluginManager(); + + if (!identifier) { + if (atts.value("id")) { + unsigned long id = atts.value("id").toULong(); + if (apm) + plugin = apm->getPluginByUniqueId(id); + } + } else { + if (apm) + plugin = apm->getPluginByIdentifier(identifier); + } + +// std::cerr << "Plugin identifier " << identifier << " -> plugin " << plugin << std::endl; + + // If we find the plugin all is well and good but if + // we don't we just skip it. + // + if (plugin) { + m_plugin = container->getPlugin(position); + if (!m_plugin) { + RG_DEBUG << "WARNING: RoseXmlHandler: instrument/buss " + << container->getId() << " has no plugin position " + << position << endl; + } else { + m_plugin->setAssigned(true); + m_plugin->setBypass(bypassed); + m_plugin->setIdentifier(plugin->getIdentifier().data()); +// std::cerr << "set identifier to plugin at position " << position << std::endl; + if (program != "") { + m_plugin->setProgram(program); + } + } + } else { + // we shouldn't be halting import of the RG file just because + // we can't match a plugin + // + if (identifier) { + RG_DEBUG << "WARNING: RoseXmlHandler: plugin " << identifier << " not found" << endl; + m_pluginsNotFound.insert(identifier); + } else if (atts.value("id")) { + RG_DEBUG << "WARNING: RoseXmlHandler: plugin uid " << atts.value("id") << " not found" << endl; + } else { + m_errorString = "No plugin identifier or uid specified"; + return false; + } + } + } else { // no instrument + + if (lcName == "synth") { + QString identifier = atts.value("identifier"); + if (identifier) { + RG_DEBUG << "WARNING: RoseXmlHandler: no instrument for plugin " << identifier << endl; + m_pluginsNotFound.insert(identifier); + } + } + } + + m_section = InPlugin; + + } else if (lcName == "port") { + + if (m_section != InPlugin) { + m_errorString = "Found Port outside Plugin"; + return false; + } + unsigned long portId = atts.value("id").toULong(); + double value = qstrtodouble(atts.value("value")); + + QString changed = atts.value("changed"); + bool changedSinceProgram = (changed == "true"); + + if (m_plugin) { + m_plugin->addPort(portId, value); + if (changedSinceProgram) { + PluginPortInstance *ppi = m_plugin->getPort(portId); + if (ppi) + ppi->changedSinceProgramChange = true; + } + } + + } else if (lcName == "configure") { + + if (m_section != InPlugin) { + m_errorString = "Found Configure outside Plugin"; + return false; + } + + QString key = atts.value("key"); + QString value = atts.value("value"); + + if (m_plugin) { + m_plugin->setConfigurationValue(qstrtostr(key), qstrtostr(value)); + } + + } else if (lcName == "metronome") { + + if (m_section != InStudio) { + m_errorString = "Found Metronome outside Studio"; + return false; + } + + // Only create if we have a device + // + if (m_device && m_device->getType() == Device::Midi) { + InstrumentId instrument = + atts.value("instrument").toInt(); + + MidiMetronome metronome(instrument); + + if (atts.value("barpitch")) + metronome.setBarPitch(atts.value("barpitch").toInt()); + if (atts.value("beatpitch")) + metronome.setBeatPitch(atts.value("beatpitch").toInt()); + if (atts.value("subbeatpitch")) + metronome.setSubBeatPitch(atts.value("subbeatpitch").toInt()); + if (atts.value("depth")) + metronome.setDepth(atts.value("depth").toInt()); + if (atts.value("barvelocity")) + metronome.setBarVelocity(atts.value("barvelocity").toInt()); + if (atts.value("beatvelocity")) + metronome.setBeatVelocity(atts.value("beatvelocity").toInt()); + if (atts.value("subbeatvelocity")) + metronome.setSubBeatVelocity(atts.value("subbeatvelocity").toInt()); + + dynamic_cast<MidiDevice*>(m_device)-> + setMetronome(metronome); + } + + } else if (lcName == "instrument") { + + if (m_section != InStudio) { + m_errorString = "Found Instrument outside Studio"; + return false; + } + + m_section = InInstrument; + + InstrumentId id = atts.value("id").toInt(); + std::string stringType = qstrtostr(atts.value("type")); + Instrument::InstrumentType type; + + if (stringType == "midi") + type = Instrument::Midi; + else if (stringType == "audio") + type = Instrument::Audio; + else if (stringType == "softsynth") + type = Instrument::SoftSynth; + else { + m_errorString = "Found unknown Instrument type"; + return false; + } + + // Try and match an Instrument in the file with one in + // our studio + // + Instrument *instrument = getStudio().getInstrumentById(id); + + // If we've got an instrument and the types match then + // we use it from now on. + // + if (instrument && instrument->getType() == type) { + m_instrument = instrument; + + // We can also get the channel from this tag + // + MidiByte channel = + (MidiByte)atts.value("channel").toInt(); + m_instrument->setMidiChannel(channel); + } + + } else if (lcName == "buss") { + + if (m_section != InStudio) { + m_errorString = "Found Buss outside Studio"; + return false; + } + + m_section = InBuss; + + BussId id = atts.value("id").toInt(); + Buss *buss = getStudio().getBussById(id); + + // If we've got a buss then we use it from now on. + // + if (buss) { + m_buss = buss; + } else { + m_buss = new Buss(id); + getStudio().addBuss(m_buss); + } + + } else if (lcName == "audiofiles") { + + if (m_section != NoSection) { + m_errorString = "Found AudioFiles inside another section"; + return false; + } + + m_section = InAudioFiles; + + int rate = atts.value("expectedRate").toInt(); + if (rate) { + getAudioFileManager().setExpectedSampleRate(rate); + } + + } else if (lcName == "configuration") { + + setSubHandler(new ConfigurationXmlSubHandler + (lcName, &m_doc->getConfiguration())); + + } else if (lcName == "metadata") { + + if (m_section != InComposition) { + m_errorString = "Found Metadata outside Composition"; + return false; + } + + setSubHandler(new ConfigurationXmlSubHandler + (lcName, &getComposition().getMetadata())); + + } else if (lcName == "recordlevel") { + + if (m_section != InInstrument) { + m_errorString = "Found recordLevel outside Instrument"; + return false; + } + + double value = qstrtodouble(atts.value("value")); + + // if the value retrieved is greater than (say) 15 then we + // must have an old-style 0-127 value instead of a shiny new + // dB value, so convert it + if (value > 15.0) { + value = AudioLevel::multiplier_to_dB(value / 100); + } + + if (m_instrument) + m_instrument->setRecordLevel(value); + + } else if (lcName == "audioinput") { + + if (m_section != InInstrument) { + m_errorString = "Found audioInput outside Instrument"; + return false; + } + + int value = atts.value("value").toInt(); + int channel = atts.value("channel").toInt(); + + QString type = atts.value("type"); + if (type) { + if (type.lower() == "buss") { + if (m_instrument) + m_instrument->setAudioInputToBuss(value, channel); + } else if (type.lower() == "record") { + if (m_instrument) + m_instrument->setAudioInputToRecord(value, channel); + } + } + + } else if (lcName == "audiooutput") { + + if (m_section != InInstrument) { + m_errorString = "Found audioOutput outside Instrument"; + return false; + } + + int value = atts.value("value").toInt(); + if (m_instrument) + m_instrument->setAudioOutput(value); + + } else if (lcName == "appearance") { + + m_section = InAppearance; + + } else if (lcName == "colourmap") { + + if (m_section == InAppearance) { + QString mapName = atts.value("name"); + m_inColourMap = true; + if (mapName == "segmentmap") { + m_colourMap = &m_doc->getComposition().getSegmentColourMap(); + } else + if (mapName == "generalmap") { + m_colourMap = &m_doc->getComposition().getGeneralColourMap(); + } else { // This will change later once we get more of the Appearance code sorted out + RG_DEBUG << "RoseXmlHandler::startElement : Found colourmap with unknown name\n"; + } + } else { + m_errorString = "Found colourmap outside Appearance"; + return false; + } + + } else if (lcName == "colourpair") { + + if (m_inColourMap && m_colourMap) { + unsigned int id = atts.value("id").toInt(); + QString name = atts.value("name"); + unsigned int red = atts.value("red").toInt(); + unsigned int blue = atts.value("blue").toInt(); + unsigned int green = atts.value("green").toInt(); + Colour colour(red, green, blue); + m_colourMap->addItem(colour, qstrtostr(name), id); + } else { + m_errorString = "Found colourpair outside ColourMap"; + return false; + } + + } else if (lcName == "markers") { + + if (!m_inComposition) { + m_errorString = "Found Markers outside Composition"; + return false; + } + + // clear down any markers + getComposition().clearMarkers(); + + } else if (lcName == "marker") { + if (!m_inComposition) { + m_errorString = "Found Marker outside Composition"; + return false; + } + int time = atts.value("time").toInt(); + QString name = atts.value("name"); + QString descr = atts.value("description"); + + Marker *marker = + new Marker(time, + qstrtostr(name), + qstrtostr(descr)); + + getComposition().addMarker(marker); + } else { + RG_DEBUG << "RoseXmlHandler::startElement : Don't know how to parse this : " << qName << endl; + } + + return true; +} + +bool +RoseXmlHandler::endElement(const QString& namespaceURI, + const QString& localName, + const QString& qName) +{ + if (getSubHandler()) { + bool finished; + bool res = getSubHandler()->endElement(namespaceURI, localName, qName.lower(), finished); + if (finished) + setSubHandler(0); + return res; + } + + // Set percentage done + // + if ((m_totalElements > m_elementsSoFar) && + (++m_elementsSoFar % 300 == 0)) { + + emit setProgress(int(double(m_elementsSoFar) / double(m_totalElements) * 100.0)); + ProgressDialog::processEvents(); + } + + QString lcName = qName.lower(); + + if (lcName == "rosegarden-data") { + + getComposition().updateTriggerSegmentReferences(); + + } else if (lcName == "event") { + + if (m_currentSegment && m_currentEvent) { + m_currentSegment->insert(m_currentEvent); + m_currentEvent = 0; + } else if (!m_currentSegment && m_currentEvent) { + m_errorString = "Got event outside of a Segment"; + return false; + } + + } else if (lcName == "chord") { + + m_currentTime += m_chordDuration; + m_inChord = false; + m_chordDuration = 0; + + } else if (lcName == "group") { + + m_inGroup = false; + + } else if (lcName == "segment") { + + if (m_currentSegment && m_segmentEndMarkerTime) { + m_currentSegment->setEndMarkerTime(*m_segmentEndMarkerTime); + delete m_segmentEndMarkerTime; + m_segmentEndMarkerTime = 0; + } + + m_currentSegment = 0; + m_section = NoSection; + + } else if (lcName == "bar-segment" || lcName == "tempo-segment") { + + m_currentSegment = 0; + + } else if (lcName == "composition") { + m_inComposition = false; + m_section = NoSection; + + } else if (lcName == "studio") { + + m_section = NoSection; + + } else if (lcName == "buss") { + + m_section = InStudio; + m_buss = 0; + + } else if (lcName == "instrument") { + + m_section = InStudio; + m_instrument = 0; + + } else if (lcName == "plugin") { + + if (m_pluginInBuss) { + m_section = InBuss; + } else { + m_section = InInstrument; + } + m_plugin = 0; + m_pluginId = 0; + + } else if (lcName == "device") { + + m_device = 0; + + } else if (lcName == "keymapping") { + + if (m_section == InStudio) { + if (m_keyMapping) { + if (!m_keyNameMap.empty()) { + MidiDevice *md = dynamic_cast<MidiDevice *> + (m_device); + if (md) { + m_keyMapping->setMap(m_keyNameMap); + md->addKeyMapping(*m_keyMapping); + } + } + m_keyMapping = 0; + } + } + + } else if (lcName == "audiofiles") { + + m_section = NoSection; + + } else if (lcName == "appearance") { + + m_section = NoSection; + + } else if (lcName == "colourmap") { + m_inColourMap = false; + m_colourMap = 0; + } + + return true; +} + +bool +RoseXmlHandler::characters(const QString& s) +{ + if (m_subHandler) + return m_subHandler->characters(s); + + return true; +} + +QString +RoseXmlHandler::errorString() +{ + return m_errorString; +} + +bool +RoseXmlHandler::error(const QXmlParseException& exception) +{ + m_errorString = QString("%1 at line %2, column %3") + .arg(exception.message()) + .arg(exception.lineNumber()) + .arg(exception.columnNumber()); + return QXmlDefaultHandler::error( exception ); +} + +bool +RoseXmlHandler::fatalError(const QXmlParseException& exception) +{ + m_errorString = QString("%1 at line %2, column %3") + .arg(exception.message()) + .arg(exception.lineNumber()) + .arg(exception.columnNumber()); + return QXmlDefaultHandler::fatalError( exception ); +} + +bool +RoseXmlHandler::endDocument() +{ + if (m_foundTempo == false) { + getComposition().setCompositionDefaultTempo + (Composition::getTempoForQpm(120.0)); + } + + return true; +} + +void +RoseXmlHandler::setSubHandler(XmlSubHandler* sh) +{ + delete m_subHandler; + m_subHandler = sh; +} + +void +RoseXmlHandler::addMIDIDevice(QString name, bool createAtSequencer) +{ + unsigned int deviceId = 0; + + if (createAtSequencer) { + + QByteArray data; + QByteArray replyData; + QCString replyType; + QDataStream arg(data, IO_WriteOnly); + + arg << (int)Device::Midi; + arg << (unsigned int)MidiDevice::Play; + + if (!rgapp->sequencerCall("addDevice(int, unsigned int)", replyType, replyData, data)) { + SEQMAN_DEBUG << "RoseXmlHandler::addMIDIDevice - " + << "can't call sequencer addDevice" << endl; + return ; + } + + if (replyType == "unsigned int") { + QDataStream reply(replyData, IO_ReadOnly); + reply >> deviceId; + } else { + SEQMAN_DEBUG << "RoseXmlHandler::addMIDIDevice - " + << "got unknown returntype from addDevice()" << endl; + return ; + } + + if (deviceId == Device::NO_DEVICE) { + SEQMAN_DEBUG << "RoseXmlHandler::addMIDIDevice - " + << "sequencer addDevice failed" << endl; + return ; + } + + SEQMAN_DEBUG << "RoseXmlHandler::addMIDIDevice - " + << " added device " << deviceId << endl; + + } else { + // Generate a new device id at the base Studio side only. + // This may not correspond to any given device id at the + // sequencer side. We should _never_ do this in a document + // that's actually intended to be retained for use, only + // in temporary documents for device import etc. + int tempId = -1; + for (DeviceListIterator i = getStudio().getDevices()->begin(); + i != getStudio().getDevices()->end(); ++i) { + if (int((*i)->getId()) > tempId) + tempId = int((*i)->getId()); + } + deviceId = tempId + 1; + } + + // add the device, so we can name it and set our pointer to it -- + // instruments will be sync'd later in the natural course of things + getStudio().addDevice(qstrtostr(name), deviceId, Device::Midi); + m_device = getStudio().getDevice(deviceId); + m_deviceRunningId = deviceId; +} + +void +RoseXmlHandler::skipToNextPlayDevice() +{ + SEQMAN_DEBUG << "RoseXmlHandler::skipToNextPlayDevice; m_deviceRunningId is " << m_deviceRunningId << endl; + + for (DeviceList::iterator i = getStudio().getDevices()->begin(); + i != getStudio().getDevices()->end(); ++i) { + + MidiDevice *md = + dynamic_cast<MidiDevice *>(*i); + + if (md && md->getDirection() == MidiDevice::Play) { + if (m_deviceRunningId == Device::NO_DEVICE || + md->getId() > m_deviceRunningId) { + + SEQMAN_DEBUG << "RoseXmlHandler::skipToNextPlayDevice: found next device: id " << md->getId() << endl; + + m_device = md; + m_deviceRunningId = md->getId(); + return ; + } + } + } + + SEQMAN_DEBUG << "RoseXmlHandler::skipToNextPlayDevice: fresh out of devices" << endl; + + m_device = 0; +} + +void +RoseXmlHandler::setMIDIDeviceConnection(QString connection) +{ + SEQMAN_DEBUG << "RoseXmlHandler::setMIDIDeviceConnection(" << connection << ")" << endl; + + MidiDevice *md = dynamic_cast<MidiDevice *>(m_device); + if (!md) + return ; + + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + + arg << (unsigned int)md->getId(); + arg << connection; + + rgapp->sequencerSend("setPlausibleConnection(unsigned int, QString)", + data); + // connection should be sync'd later in the natural course of things +} + +void +RoseXmlHandler::setMIDIDeviceName(QString name) +{ + SEQMAN_DEBUG << "RoseXmlHandler::setMIDIDeviceName(" << name << ")" << endl; + + MidiDevice *md = dynamic_cast<MidiDevice *>(m_device); + if (!md) + return ; + + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + + arg << (unsigned int)md->getId(); + arg << name; + + std::cerr << "Renaming device " << md->getId() << " to " << name << std::endl; + + rgapp->sequencerSend("renameDevice(unsigned int, QString)", + data); +} + +} |