You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rosegarden/src/document/io/HydrogenXMLHandler.cpp

402 lines
11 KiB

/*
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 "HydrogenXMLHandler.h"
#include "base/Event.h"
#include "base/BaseProperties.h"
#include <tdelocale.h>
#include "misc/Debug.h"
#include "misc/Strings.h"
#include "base/Composition.h"
#include "base/Instrument.h"
#include "base/MidiProgram.h"
#include "base/NotationTypes.h"
#include "base/Segment.h"
#include "base/Track.h"
#include <tqstring.h>
namespace Rosegarden
{
HydrogenXMLHandler::HydrogenXMLHandler(Composition *composition,
InstrumentId drumIns):
m_composition(composition),
m_drumInstrument(drumIns),
m_inNote(false),
m_inInstrument(false),
m_inPattern(false),
m_inSequence(false),
m_patternName(""),
m_patternSize(0),
m_sequenceName(""),
m_position(0),
m_velocity(0.0),
m_panL(0.0),
m_panR(0.0),
m_pitch(0.0),
m_instrument(0),
m_id(0),
m_muted(false),
m_fileName(""),
m_bpm(0),
m_volume(0.0),
m_name(""),
m_author(""),
m_notes(""),
m_songMode(false),
m_version(""),
m_currentProperty(""),
m_segment(0),
m_currentTrackNb(0),
m_segmentAdded(false),
m_currentBar(0),
m_newSegment(false)
{}
bool
HydrogenXMLHandler::startDocument()
{
RG_DEBUG << "HydrogenXMLHandler::startDocument" << endl;
m_inNote = false;
m_inInstrument = false;
m_inPattern = false;
m_inSequence = false;
// Pattern attributes
//
m_patternName = "";
m_patternSize = 0;
// Sequence attributes
//
m_sequenceName = "";
// Note attributes
//
m_position = 0;
m_velocity = 0.0;
m_panL = 0.0;
m_panR = 0.0;
m_pitch = 0.0;
m_instrument = 0;
// Instrument attributes
//
m_id = 0;
m_muted = false;
m_instrumentVolumes.clear();
m_fileName = "";
// Global attributes
//
m_bpm = 0;
m_volume = 0.0;
m_name = "";
m_author = "";
m_notes = "";
m_songMode = false;
m_version = "";
m_currentProperty = "";
m_segment = 0;
m_currentTrackNb = 0;
m_segmentAdded = 0;
m_currentBar = 0;
m_newSegment = false;
return true;
}
bool
HydrogenXMLHandler::startElement(const TQString& /*namespaceURI*/,
const TQString& /*localName*/,
const TQString& qName,
const TQXmlAttributes& /*atts*/)
{
TQString lcName = qName.lower();
if (lcName == "note") {
if (m_inInstrument)
return false;
m_inNote = true;
} else if (lcName == "instrument") {
// Beware instrument attributes inside Notes
if (!m_inNote)
m_inInstrument = true;
} else if (lcName == "pattern") {
m_inPattern = true;
m_segmentAdded = false; // flag the segments being added
} else if (lcName == "sequence") {
// Create a new segment and set some flags
//
m_segment = new Segment();
m_newSegment = true;
m_inSequence = true;
}
m_currentProperty = lcName;
return true;
}
bool
HydrogenXMLHandler::endElement(const TQString& /*namespaceURI*/,
const TQString& /*localName*/,
const TQString& qName)
{
TQString lcName = qName.lower();
if (lcName == "note") {
RG_DEBUG << "HydrogenXMLHandler::endElement - Hydrogen Note : position = " << m_position
<< ", velocity = " << m_velocity
<< ", panL = " << m_panL
<< ", panR = " << m_panR
<< ", pitch = " << m_pitch
<< ", instrument = " << m_instrument
<< endl;
timeT barLength = m_composition->getBarEnd(m_currentBar) -
m_composition->getBarStart(m_currentBar);
timeT pos = m_composition->getBarStart(m_currentBar) +
timeT(
double(m_position) / double(m_patternSize) * double(barLength));
// Insert a rest if we've got a new segment
//
if (m_newSegment) {
Event *restEvent = new Event(Note::EventRestType,
m_composition->getBarStart(m_currentBar),
pos - m_composition->getBarStart(m_currentBar),
Note::EventRestSubOrdering);
m_segment->insert(restEvent);
m_newSegment = false;
}
// Create and insert this event
//
Event *noteEvent = new Event(Note::EventType,
pos, Note(Note::Semiquaver).getDuration());
// get drum mapping from instrument and calculate velocity
noteEvent->set
<Int>(
BaseProperties::PITCH, 36 + m_instrument);
noteEvent->set
<Int>(BaseProperties::VELOCITY,
int(127.0 * m_velocity * m_volume *
m_instrumentVolumes[m_instrument]));
m_segment->insert(noteEvent);
m_inNote = false;
} else if (lcName == "instrument" && m_inInstrument) {
RG_DEBUG << "HydrogenXMLHandler::endElement - Hydrogen Instrument : id = " << m_id
<< ", muted = " << m_muted
<< ", volume = " << m_instrumentVolumes[m_instrument]
<< ", filename = \"" << m_fileName << "\""
<< endl;
m_inInstrument = false;
} else if (lcName == "pattern") {
m_inPattern = false;
if (m_segmentAdded) {
// Add a blank track to demarcate patterns
//
Track *track = new Track
(m_currentTrackNb, m_drumInstrument, m_currentTrackNb,
"<blank spacer>", false);
m_currentTrackNb++;
m_composition->addTrack(track);
m_segmentAdded = false;
// Each pattern has it's own bar so that the imported
// song shows off each pattern a bar at a time.
//
m_currentBar++;
}
} else if (lcName == "sequence") {
// If we're closing out a sequencer tab and we have a m_segment then
// we should close up and add that segment. Only create if we have
// some Events in it
//
if (m_segment->size() > 0) {
m_segment->setTrack(m_currentTrackNb);
Track *track = new Track
(m_currentTrackNb, m_drumInstrument, m_currentTrackNb,
m_patternName, false);
m_currentTrackNb++;
// Enforce start and end markers for this bar so that we have a
// whole bar unit segment.
//
m_segment->setEndMarkerTime(m_composition->getBarEnd(m_currentBar));
TQString label = TQString("%1 - %2 %3 %4").arg(strtoqstr(m_patternName))
.arg(strtoqstr(m_sequenceName))
.arg(i18n(" imported from Hydrogen ")).arg(strtoqstr(m_version));
m_segment->setLabel(qstrtostr(label));
m_composition->addTrack(track);
m_composition->addSegment(m_segment);
m_segment = 0;
m_segmentAdded = true;
}
m_inSequence = false;
}
return true;
}
bool
HydrogenXMLHandler::characters(const TQString& chars)
{
TQString ch = chars.stripWhiteSpace();
if (ch == "")
return true;
if (m_inNote) {
if (m_currentProperty == "position") {
m_position = ch.toInt();
} else if (m_currentProperty == "velocity") {
m_velocity = qstrtodouble(ch);
} else if (m_currentProperty == "pan_L") {
m_panL = qstrtodouble(ch);
} else if (m_currentProperty == "pan_R") {
m_panR = qstrtodouble(ch);
} else if (m_currentProperty == "pitch") {
m_pitch = qstrtodouble(ch);
} else if (m_currentProperty == "instrument") {
m_instrument = ch.toInt();
// Standard kit conversion - hardcoded conversion for Hyrdogen's default
// drum kit. The m_instrument mapping for low values maps well onto the
// kick drum GM kit starting point (MIDI pitch = 36).
//
switch (m_instrument) {
case 11: // Cowbell
m_instrument = 20;
break;
case 12: // Ride Jazz
m_instrument = 15;
break;
case 14: // Ride Rock
m_instrument = 17;
break;
case 15: // Crash Jazz
m_instrument = 16;
break;
default:
break;
}
}
} else if (m_inInstrument) {
if (m_currentProperty == "id") {
m_id = ch.toInt();
} else if (m_currentProperty == "ismuted") {
if (ch.lower() == "true")
m_muted = true;
else
m_muted = false;
} else if (m_currentProperty == "filename") {
m_fileName = qstrtostr(chars); // don't strip whitespace from the filename
} else if (m_currentProperty == "volume") {
m_instrumentVolumes.push_back(qstrtodouble(ch));
}
} else if (m_inPattern) {
// Pattern attributes
if (m_currentProperty == "name") {
if (m_inSequence)
m_sequenceName = qstrtostr(chars);
else
m_patternName = qstrtostr(chars);
} else if (m_currentProperty == "size") {
m_patternSize = ch.toInt();
}
} else {
// Global attributes
if (m_currentProperty == "version") {
m_version = qstrtostr(chars);
} else if (m_currentProperty == "bpm") {
m_bpm = qstrtodouble(ch);
m_composition->addTempoAtTime
(0, Composition::getTempoForQpm(m_bpm));
} else if (m_currentProperty == "volume") {
m_volume = qstrtodouble(ch);
} else if (m_currentProperty == "name") {
m_name = qstrtostr(chars);
} else if (m_currentProperty == "author") {
m_author = qstrtostr(chars);
} else if (m_currentProperty == "notes") {
m_notes = qstrtostr(chars);
} else if (m_currentProperty == "mode") {
if (ch.lower() == "song")
m_songMode = true;
else
m_songMode = false;
}
}
return true;
}
bool
HydrogenXMLHandler::endDocument()
{
RG_DEBUG << "HydrogenXMLHandler::endDocument" << endl;
return true;
}
}