From: <wha...@us...> - 2014-05-26 17:37:27
|
Revision: 9512 http://sourceforge.net/p/planeshift/code/9512 Author: whacko88 Date: 2014-05-26 17:37:24 +0000 (Mon, 26 May 2014) Log Message: ----------- implemented MusicXMLElement in place of MusicXMLNote Modified Paths: -------------- trunk/src/common/music/musicutil.cpp trunk/src/common/music/musicutil.h trunk/src/common/music/musicxmlscore.cpp trunk/src/common/music/musicxmlscore.h trunk/src/common/music/scoreelements.cpp Modified: trunk/src/common/music/musicutil.cpp =================================================================== --- trunk/src/common/music/musicutil.cpp 2014-05-22 23:01:43 UTC (rev 9511) +++ trunk/src/common/music/musicutil.cpp 2014-05-26 17:37:24 UTC (rev 9512) @@ -32,6 +32,33 @@ #define SCORE_COMPRESSION_FACTOR 3 +bool psMusic::CheckDuration(int duration) +{ + switch(duration) + { + case SIXTEENTH_DURATION: + return true; + case EIGHTH_DURATION: + return true; + case DOTTED_EIGHTH_DURATION: + return true; + case QUARTER_DURATION: + return true; + case DOTTED_QUARTER_DURATION: + return true; + case HALF_DURATION: + return true; + case DOTTED_HALF_DURATION: + return true; + case WHOLE_DURATION: + return true; + case DOTTED_WHOLE_DURATION: + return true; + default: + return false; + } +} + psMusic::Duration psMusic::GetBiggestDuration(int duration) { if(DOTTED_WHOLE_DURATION <= duration) Modified: trunk/src/common/music/musicutil.h =================================================================== --- trunk/src/common/music/musicutil.h 2014-05-22 23:01:43 UTC (rev 9511) +++ trunk/src/common/music/musicutil.h 2014-05-26 17:37:24 UTC (rev 9512) @@ -225,11 +225,13 @@ DOUBLE_SHARP }; + +// Unit of measure is a sixteenth. If you change this constant you must change the values +// in the enum Duration and the method CheckDuration() too. /** - * Unit measure for duration in in terms of divisions per quarter. If you change this - * constants you must change the values in the enum Duration too. + * Unit measure for duration in in terms of divisions per quarter. */ -#define DURATION_QUARTER_DIVISIONS 16 // unit measure is a sixteenth +#define DURATION_QUARTER_DIVISIONS 16 /** * The number associated to each duration is the number of quarter divisions as specified @@ -250,6 +252,16 @@ /** + * Check wheather the given number of DURATION_QUARTER_DIVISIONS correspond to a specific + * duration taken into account by the enum Duration. + * + * @param duration the duration expressed as the number of DURATION_QUARTER_DIVISIONS. + * @return true if the given duration can be expressed by the type Duration, false + * otherwise. + */ +bool CheckDuration(int duration); + +/** * Returns the biggest duration that can be represented on the score which is less * or equal to the given one. * Modified: trunk/src/common/music/musicxmlscore.cpp =================================================================== --- trunk/src/common/music/musicxmlscore.cpp 2014-05-22 23:01:43 UTC (rev 9511) +++ trunk/src/common/music/musicxmlscore.cpp 2014-05-26 17:37:24 UTC (rev 9512) @@ -35,78 +35,161 @@ // Forward Declarations //------------------------------------------------------------------------------------ -bool MusicXMLNote::LoadXML(csRef<iDocumentNode> &pitchNode) + +bool MusicXMLElement::LoadXMLNote(const csRef<iDocumentNode> ¬eNode, int divisions) { - csRef<iDocumentNode> stepNode = pitchNode->GetNode("step"); - csRef<iDocumentNode> alterNode = pitchNode->GetNode("alter"); - csRef<iDocumentNode> octaveNode = pitchNode->GetNode("octave"); + char step; + int octave; + int duration; + Accidental accidental = NO_ACCIDENTAL; + csRef<iDocumentNode> durationNode; + csRef<iDocumentNode> pitchNode; + csRef<iDocumentNode> stepNode; + csRef<iDocumentNode> octaveNode; + csRef<iDocumentNode> accidentalNode; + if(!noteNode.IsValid()) + { + return false; + } + + // Check that this note belongs to this element + if(this->GetNNotes() > 0 && !noteNode->GetNode("chord").IsValid()) + { + return false; + } + + // Loading duration + durationNode = noteNode->GetNode("duration"); + if(!durationNode.IsValid()) + { + return false; + } + duration = durationNode->GetContentsValueAsInt(); + if(duration <= 0) + { + return false; + } + duration = duration * QUARTER_DURATION / divisions; // convert duration from quarters to sixteenths + if(!CheckDuration(duration)) + { + return false; + } + this->SetDuration(static_cast<Duration>(duration)); + + // If this is a rest, we don't need to do anything else + if(noteNode->GetNode("rest").IsValid()) + { + return true; + } + + // Loading name and octave + pitchNode = noteNode->GetNode("pitch"); + if(!pitchNode.IsValid()) + { + return false; + } + + stepNode = pitchNode->GetNode("step"); + octaveNode = pitchNode->GetNode("octave"); if(!stepNode.IsValid() || !octaveNode.IsValid()) { return false; } - char step = stepNode->GetContentsValue()[0]; + step = stepNode->GetContentsValue()[0]; if(step < 'A' || step > 'G') { return false; } - this->SetName(step); - if(!alterNode.IsValid()) + octave = octaveNode->GetContentsValueAsInt(); + if(octave < 0 || octave > 9) // octave limits according to xsd specification { - this->SetWrittenAccidental(NO_ACCIDENTAL); + return true; } - else // the alter node is optional + + // Loading accidental. Right now it considers both <alter> and <accidental> as the + // written accidental of the note (with priority to <accidental>). This is wrong but + // it's needed for backwards compatibility. In the future, only <accidental> should + // be parsed. + accidentalNode = noteNode->GetNode("accidental"); + if(accidentalNode.IsValid()) { - int alter = alterNode->GetContentsValueAsInt(); - switch(alter) + csString accidentalStr = accidentalNode->GetContentsValue(); + if(accidentalStr == "flat") { - case 0: - this->SetWrittenAccidental(NO_ACCIDENTAL); - break; - case 1: - this->SetWrittenAccidental(SHARP); - break; - case -1: - this->SetWrittenAccidental(FLAT); - break; - default: + accidental = FLAT; + } + else if(accidentalStr == "sharp") + { + accidental = SHARP; + } + else + { return false; } } - - int octave = octaveNode->GetContentsValueAsInt(); - if(octave < 0 || octave > 9) // octave limits according to xsd specification + else { - return true; + csRef<iDocumentNode> alterNode = pitchNode->GetNode("alter"); + if(alterNode.IsValid()) + { + int alter = alterNode->GetContentsValueAsInt(); + switch(alter) + { + case 0: + accidental = NO_ACCIDENTAL; + break; + case 1: + accidental = SHARP; + break; + case -1: + accidental = FLAT; + break; + default: + return false; + } + } } - this->SetOctave(octave); + this->AddNote(step, octave, accidental); + return true; } -csString MusicXMLNote::ToXML() +csString MusicXMLElement::ToXML() { - int alterXML = 0; - Accidental alter = this->GetWrittenAccidental(); - switch(alter) + csString element("<note>"); + + if(this->IsRest()) { - case SHARP: - alterXML = 1; - break; - case FLAT: - alterXML = -1; - break; + element.AppendFmt("<rest/><duration>%d</duration></note>", this->GetDuration()); + return element; } - csString pitch("<pitch>"); - pitch.AppendFmt("<step>%c</step>", this->GetName()); - if(alterXML != 0) + for(size_t i = 0; i < this->GetNNotes(); i++) { - pitch.AppendFmt("<alter>%d</alter>", alterXML); + Note note = this->GetNote(i); + + if(i > 0) + { + element += "<note><chord/>"; + } + + element.AppendFmt("<pitch><step>%c</step><octave>%d</octave></pitch><duration>%d</duration>", + note.GetName(), note.GetOctave(), this->GetDuration()); + switch(note.GetWrittenAccidental()) + { + case SHARP: + element += "<accidental>sharp</accidental>"; + break; + case FLAT: + element += "<accidental>flat</accidental>"; + break; + } + element += "</note>"; } - pitch.AppendFmt("<octave>%d</octave></pitch>", this->GetOctave()); - return pitch; + return element; } Modified: trunk/src/common/music/musicxmlscore.h =================================================================== --- trunk/src/common/music/musicxmlscore.h 2014-05-22 23:01:43 UTC (rev 9511) +++ trunk/src/common/music/musicxmlscore.h 2014-05-26 17:37:24 UTC (rev 9512) @@ -43,19 +43,22 @@ * @{ */ /** - * Extends the class Note by adding the ability to parse MusicXML. + * Extends the class MeasureElement by adding the ability to parse MusicXML. */ -class MusicXMLNote: public Note +class MusicXMLElement: public MeasureElement { public: /** - * Load the note step, note and accidental from the given <pitch> node. + * Load a note from the given <note> node. If this element contain already one or + * more note, only notes that present the <chord/> tag are accepted. * - * @param pitchNode a valid pointer to the <pitch> node containing the definition of - * the note in MusicXML syntax. - * @return false if the given node syntax is wrong, true otherwise. + * @param noteNode a reference to the <note> node containing the definition of the + * note in MusicXML syntax. + * @param divisions divisions per quarter used by the score to indicate duration. + * @return false if the given node syntax is wrong or if this note is not part of + * this chord, true otherwise. */ - bool LoadXML(csRef<iDocumentNode> &pitchNode); + bool LoadXMLNote(const csRef<iDocumentNode> ¬eNode, int divisions); /** * Convert the note to XML. @@ -64,4 +67,6 @@ csString ToXML(); }; +#include "musicxmlscore.hpp" + #endif // MUSIC_XML_SCORE_H Modified: trunk/src/common/music/scoreelements.cpp =================================================================== --- trunk/src/common/music/scoreelements.cpp 2014-05-22 23:01:43 UTC (rev 9511) +++ trunk/src/common/music/scoreelements.cpp 2014-05-26 17:37:24 UTC (rev 9512) @@ -109,9 +109,10 @@ } Note::Note(char name_, int octave_, Accidental writtenAccidental_) -: octave(octave_), writtenAccidental(writtenAccidental_) +: writtenAccidental(writtenAccidental_) { SetName(name_); + SetOctave(octave_); } Accidental Note::GetPlayedAccidental(const ScoreContext &context) const @@ -225,6 +226,7 @@ void Note::SetOctave(int newOctave) { + CS_ASSERT(newOctave >= 0 && newOctave <= 9); octave = newOctave; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |