package org.herac.tuxguitar.io.gpx;
import java.io.InputStream;
import java.math.BigDecimal;
import javax.xml.parsers.DocumentBuilderFactory;
import org.herac.tuxguitar.io.gpx.score.GPXAutomation;
import org.herac.tuxguitar.io.gpx.score.GPXBar;
import org.herac.tuxguitar.io.gpx.score.GPXBeat;
import org.herac.tuxguitar.io.gpx.score.GPXDocument;
import org.herac.tuxguitar.io.gpx.score.GPXMasterBar;
import org.herac.tuxguitar.io.gpx.score.GPXNote;
import org.herac.tuxguitar.io.gpx.score.GPXRhythm;
import org.herac.tuxguitar.io.gpx.score.GPXTrack;
import org.herac.tuxguitar.io.gpx.score.GPXVoice;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class GPXDocumentReader {
private Document xmlDocument;
private GPXDocument gpxDocument;
public GPXDocumentReader(InputStream stream){
this.xmlDocument = getDocument(stream);
this.gpxDocument = new GPXDocument();
}
private Document getDocument(InputStream stream) {
try {
return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(stream);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
public GPXDocument read(){
if( this.xmlDocument != null ){
this.readScore();
this.readAutomations();
this.readTracks();
this.readMasterBars();
this.readBars();
this.readVoices();
this.readBeats();
this.readNotes();
this.readRhythms();
}
return this.gpxDocument;
}
public void readScore(){
if( this.xmlDocument != null ){
Node scoreNode = getChildNode(this.xmlDocument.getFirstChild(), "Score");
if( scoreNode != null ){
this.gpxDocument.getScore().setTitle( getChildNodeContent(scoreNode, "Title"));
this.gpxDocument.getScore().setSubTitle( getChildNodeContent(scoreNode, "SubTitle"));
this.gpxDocument.getScore().setArtist( getChildNodeContent(scoreNode, "Artist"));
this.gpxDocument.getScore().setAlbum( getChildNodeContent(scoreNode, "Album"));
this.gpxDocument.getScore().setWords( getChildNodeContent(scoreNode, "Words"));
this.gpxDocument.getScore().setMusic( getChildNodeContent(scoreNode, "Music"));
this.gpxDocument.getScore().setWordsAndMusic( getChildNodeContent(scoreNode, "WordsAndMusic"));
this.gpxDocument.getScore().setCopyright( getChildNodeContent(scoreNode, "Copyright"));
this.gpxDocument.getScore().setTabber( getChildNodeContent(scoreNode, "Tabber"));
this.gpxDocument.getScore().setInstructions( getChildNodeContent(scoreNode, "Instructions"));
this.gpxDocument.getScore().setNotices( getChildNodeContent(scoreNode, "Notices"));
}
}
}
public void readAutomations(){
if( this.xmlDocument != null ){
Node masterTrackNode = getChildNode(this.xmlDocument.getFirstChild(), "MasterTrack");
if( masterTrackNode != null ){
NodeList automationNodes = getChildNodeList(masterTrackNode, "Automations");
for( int i = 0 ; i < automationNodes.getLength() ; i ++ ){
Node automationNode = automationNodes.item( i );
if( automationNode.getNodeName().equals("Automation") ){
GPXAutomation automation = new GPXAutomation();
automation.setType( getChildNodeContent(automationNode, "Type"));
automation.setBarId( getChildNodeIntegerContent(automationNode, "Bar"));
automation.setValue( getChildNodeIntegerContentArray(automationNode, "Value"));
automation.setLinear( getChildNodeBooleanContent(automationNode, "Linear"));
automation.setPosition( getChildNodeIntegerContent(automationNode, "Position"));
automation.setVisible( getChildNodeBooleanContent(automationNode, "Visible"));
this.gpxDocument.getAutomations().add( automation );
}
}
}
}
}
public void readTracks(){
if( this.xmlDocument != null ){
NodeList trackNodes = getChildNodeList(this.xmlDocument.getFirstChild(), "Tracks");
for( int i = 0 ; i < trackNodes.getLength() ; i ++ ){
Node trackNode = trackNodes.item( i );
if( trackNode.getNodeName().equals("Track") ){
GPXTrack track = new GPXTrack();
track.setId( getAttributeIntegerValue(trackNode, "id") );
track.setName(getChildNodeContent(trackNode, "Name" ));
track.setColor(getChildNodeIntegerContentArray(trackNode, "Color"));
Node gmNode = getChildNode(trackNode, "GeneralMidi");
if( gmNode != null ){
track.setGmProgram(getChildNodeIntegerContent(gmNode, "Program"));
track.setGmChannel1(getChildNodeIntegerContent(gmNode, "PrimaryChannel"));
track.setGmChannel2(getChildNodeIntegerContent(gmNode, "SecondaryChannel"));
}
NodeList propertyNodes = getChildNodeList(trackNode, "Properties");
if( propertyNodes != null ){
for( int p = 0 ; p < propertyNodes.getLength() ; p ++ ){
Node propertyNode = propertyNodes.item( p );
if (propertyNode.getNodeName().equals("Property") ){
if( getAttributeValue(propertyNode, "name").equals("Tuning") ){
track.setTunningPitches( getChildNodeIntegerContentArray(propertyNode, "Pitches") );
}
}
}
}
this.gpxDocument.getTracks().add( track );
}
}
}
}
public void readMasterBars(){
if( this.xmlDocument != null ){
NodeList masterBarNodes = getChildNodeList(this.xmlDocument.getFirstChild(), "MasterBars");
for( int i = 0 ; i < masterBarNodes.getLength() ; i ++ ){
Node masterBarNode = masterBarNodes.item( i );
if( masterBarNode.getNodeName().equals("MasterBar") ){
GPXMasterBar masterBar = new GPXMasterBar();
masterBar.setBarIds( getChildNodeIntegerContentArray(masterBarNode, "Bars"));
masterBar.setTime( getChildNodeIntegerContentArray(masterBarNode, "Time", "/"));
masterBar.setTripletFeel(getChildNodeContent(masterBarNode, "TripletFeel"));
Node repeatNode = getChildNode(masterBarNode, "Repeat");
if( repeatNode != null ){
masterBar.setRepeatStart(getAttributeBooleanValue(repeatNode, "start"));
if( getAttributeBooleanValue(repeatNode, "end") ){
masterBar.setRepeatCount( getAttributeIntegerValue(repeatNode, "count"));
}
}
Node keyNode = getChildNode(masterBarNode, "Key");
if (keyNode != null) {
masterBar.setAccidentalCount(this.getChildNodeIntegerContent(keyNode, "AccidentalCount") );
masterBar.setMode(this.getChildNodeContent(keyNode, "Mode") );
}
this.gpxDocument.getMasterBars().add( masterBar );
}
}
}
}
public void readBars(){
if( this.xmlDocument != null ){
NodeList barNodes = getChildNodeList(this.xmlDocument.getFirstChild(), "Bars");
for( int i = 0 ; i < barNodes.getLength() ; i ++ ){
Node barNode = barNodes.item( i );
if( barNode.getNodeName().equals("Bar") ){
GPXBar bar = new GPXBar();
bar.setId(getAttributeIntegerValue(barNode, "id"));
bar.setVoiceIds( getChildNodeIntegerContentArray(barNode, "Voices"));
bar.setClef(getChildNodeContent(barNode, "Clef"));
bar.setSimileMark(getChildNodeContent(barNode,"SimileMark"));
this.gpxDocument.getBars().add( bar );
}
}
}
}
public void readVoices(){
if( this.xmlDocument != null ){
NodeList voiceNodes = getChildNodeList(this.xmlDocument.getFirstChild(), "Voices");
for( int i = 0 ; i < voiceNodes.getLength() ; i ++ ){
Node voiceNode = voiceNodes.item( i );
if( voiceNode.getNodeName().equals("Voice") ){
GPXVoice voice = new GPXVoice();
voice.setId(getAttributeIntegerValue(voiceNode, "id"));
voice.setBeatIds( getChildNodeIntegerContentArray(voiceNode, "Beats"));
this.gpxDocument.getVoices().add( voice );
}
}
}
}
public void readBeats(){
if( this.xmlDocument != null ){
NodeList beatNodes = getChildNodeList(this.xmlDocument.getFirstChild(), "Beats");
for( int i = 0 ; i < beatNodes.getLength() ; i ++ ){
Node beatNode = beatNodes.item( i );
if( beatNode.getNodeName().equals("Beat") ){
GPXBeat beat = new GPXBeat();
beat.setId(getAttributeIntegerValue(beatNode, "id"));
beat.setDynamic(getChildNodeContent(beatNode, "Dynamic"));
beat.setRhythmId(getAttributeIntegerValue(getChildNode(beatNode, "Rhythm"), "ref"));
beat.setTremolo( getChildNodeIntegerContentArray(beatNode, "Tremolo", "/"));
beat.setNoteIds( getChildNodeIntegerContentArray(beatNode, "Notes"));
NodeList propertyNodes = getChildNodeList(beatNode, "Properties");
if( propertyNodes != null ){
for( int p = 0 ; p < propertyNodes.getLength() ; p ++ ){
Node propertyNode = propertyNodes.item( p );
if (propertyNode.getNodeName().equals("Property") ){
String propertyName = getAttributeValue(propertyNode, "name");
if( propertyName.equals("WhammyBar") ){
beat.setWhammyBarEnabled( getChildNode(propertyNode, "Enable") != null );
}
if( propertyName.equals("WhammyBarOriginValue") ){
beat.setWhammyBarOriginValue( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("WhammyBarMiddleValue") ){
beat.setWhammyBarMiddleValue( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("WhammyBarDestinationValue") ){
beat.setWhammyBarDestinationValue( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("WhammyBarOriginOffset") ){
beat.setWhammyBarOriginOffset( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("WhammyBarMiddleOffset1") ){
beat.setWhammyBarMiddleOffset1( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("WhammyBarMiddleOffset2") ){
beat.setWhammyBarMiddleOffset2( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("WhammyBarDestinationOffset") ){
beat.setWhammyBarDestinationOffset( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
}
}
}
this.gpxDocument.getBeats().add( beat );
}
}
}
}
public void readNotes(){
if( this.xmlDocument != null ){
NodeList noteNodes = getChildNodeList(this.xmlDocument.getFirstChild(), "Notes");
for( int i = 0 ; i < noteNodes.getLength() ; i ++ ){
Node noteNode = noteNodes.item( i );
if( noteNode.getNodeName().equals("Note") ){
GPXNote note = new GPXNote();
note.setId( getAttributeIntegerValue(noteNode, "id") );
Node tieNode = getChildNode(noteNode, "Tie");
note.setTieDestination( tieNode != null ? getAttributeValue(tieNode, "destination").equals("true") : false);
String ghostNodeContent = getChildNodeContent(noteNode, "AntiAccent");
if( ghostNodeContent != null ){
note.setGhost(ghostNodeContent.equals("Normal"));
}
note.setAccent(getChildNodeIntegerContent(noteNode, "Accent"));
note.setTrill(getChildNodeIntegerContent(noteNode, "Trill"));
note.setVibrato( getChildNode(noteNode, "Vibrato") != null );
NodeList propertyNodes = getChildNodeList(noteNode, "Properties");
if( propertyNodes != null ){
for( int p = 0 ; p < propertyNodes.getLength() ; p ++ ){
Node propertyNode = propertyNodes.item( p );
if (propertyNode.getNodeName().equals("Property") ){
String propertyName = getAttributeValue(propertyNode, "name");
if( propertyName.equals("String") ){
note.setString( getChildNodeIntegerContent(propertyNode, "String") );
}
if( propertyName.equals("Fret") ){
note.setFret( getChildNodeIntegerContent(propertyNode, "Fret") );
}
if( propertyName.equals("Midi") ){
note.setMidiNumber( getChildNodeIntegerContent(propertyNode, "Number") );
}
if( propertyName.equals("Tone") ){
note.setTone( getChildNodeIntegerContent(propertyNode, "Step") );
}
if( propertyName.equals("Octave") ){
note.setOctave( getChildNodeIntegerContent(propertyNode, "Number") );
}
if( propertyName.equals("Element") ){
note.setElement( getChildNodeIntegerContent(propertyNode, "Element") );
}
if( propertyName.equals("Variation") ){
note.setVariation( getChildNodeIntegerContent(propertyNode, "Variation") );
}
if( propertyName.equals("Muted") ){
note.setMutedEnabled( getChildNode(propertyNode, "Enable") != null );
}
if( propertyName.equals("PalmMuted") ){
note.setPalmMutedEnabled( getChildNode(propertyNode, "Enable") != null );
}
if( propertyName.equals("Slide") ){
note.setSlide( true );
note.setSlideFlags( getChildNodeIntegerContent(propertyNode, "Flags") );
}
if( propertyName.equals("Tapped") ){
note.setTapped( getChildNode(propertyNode, "Enable") != null );
}
if( propertyName.equals("Bended") ){
note.setBendEnabled( getChildNode(propertyNode, "Enable") != null );
}
if( propertyName.equals("BendOriginValue") ){
note.setBendOriginValue( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("BendMiddleValue") ){
note.setBendMiddleValue( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("BendDestinationValue") ){
note.setBendDestinationValue( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("BendOriginOffset") ){
note.setBendOriginOffset( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("BendMiddleOffset1") ){
note.setBendMiddleOffset1( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("BendMiddleOffset2") ){
note.setBendMiddleOffset2( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("BendDestinationOffset") ){
note.setBendDestinationOffset( new Integer(getChildNodeIntegerContent(propertyNode, "Float")) );
}
if( propertyName.equals("HopoOrigin") ){
note.setHammer(true);
}
if( propertyName.equals("HopoDestination") ){
// this is a hammer-on or pull-off
}
if( propertyName.equals("HarmonicFret") ){
note.setHarmonicFret( ( getChildNodeIntegerContent(propertyNode, "HFret") ) );
}
if( propertyName.equals("HarmonicType") ){
note.setHarmonicType( getChildNodeContent (propertyNode, "HType"));
}
}
}
}
this.gpxDocument.getNotes().add( note );
}
}
}
}
public void readRhythms(){
if( this.xmlDocument != null ){
NodeList rhythmNodes = getChildNodeList(this.xmlDocument.getFirstChild(), "Rhythms");
for( int i = 0 ; i < rhythmNodes.getLength() ; i ++ ){
Node rhythmNode = rhythmNodes.item( i );
if( rhythmNode.getNodeName().equals("Rhythm") ){
Node primaryTupletNode = getChildNode(rhythmNode, "PrimaryTuplet");
Node augmentationDotNode = getChildNode(rhythmNode, "AugmentationDot");
GPXRhythm rhythm = new GPXRhythm();
rhythm.setId( getAttributeIntegerValue(rhythmNode, "id") );
rhythm.setNoteValue(getChildNodeContent(rhythmNode, "NoteValue") );
rhythm.setPrimaryTupletDen(primaryTupletNode != null ? getAttributeIntegerValue(primaryTupletNode, "den") : 1);
rhythm.setPrimaryTupletNum(primaryTupletNode != null ? getAttributeIntegerValue(primaryTupletNode, "num") : 1);
rhythm.setAugmentationDotCount(augmentationDotNode != null ? getAttributeIntegerValue(augmentationDotNode, "count") : 0);
this.gpxDocument.getRhythms().add( rhythm );
}
}
}
}
private String getAttributeValue(Node node, String attribute ){
if( node != null ){
return node.getAttributes().getNamedItem( attribute ).getNodeValue();
}
return null;
}
private int getAttributeIntegerValue(Node node, String attribute ){
try {
return new BigDecimal(this.getAttributeValue(node, attribute)).intValue();
} catch( Throwable throwable ){
return 0;
}
}
private boolean getAttributeBooleanValue(Node node, String attribute ){
String value = this.getAttributeValue(node, attribute);
if( value != null ){
return value.equals("true");
}
return false;
}
private Node getChildNode(Node node, String name ){
NodeList childNodes = node.getChildNodes();
for( int i = 0 ; i < childNodes.getLength() ; i ++ ){
Node childNode = childNodes.item( i );
if( childNode.getNodeName().equals( name ) ){
return childNode;
}
}
return null;
}
private NodeList getChildNodeList(Node node, String name ){
Node childNode = getChildNode(node, name);
if( childNode != null ){
return childNode.getChildNodes();
}
return null;
}
private String getChildNodeContent(Node node, String name ){
Node childNode = getChildNode(node, name);
if( childNode != null ){
return childNode.getTextContent();
}
return null;
}
private boolean getChildNodeBooleanContent(Node node, String name ){
String value = this.getChildNodeContent(node, name);
if( value != null ){
return value.equals("true");
}
return false;
}
private int getChildNodeIntegerContent(Node node, String name){
try {
return new BigDecimal(this.getChildNodeContent(node, name)).intValue();
} catch( Throwable throwable ){
return 0;
}
}
private int[] getChildNodeIntegerContentArray(Node node, String name , String regex){
String rawContents = this.getChildNodeContent(node, name);
if( rawContents != null ){
String[] contents = rawContents.trim().split(regex);
int[] intContents = new int[contents.length];
for( int i = 0 ; i < intContents.length; i ++ ){
try {
intContents[i] = new BigDecimal( contents[i].trim() ).intValue();
} catch( Throwable throwable ){
intContents[i] = 0;
}
}
return intContents;
}
return null;
}
private int[] getChildNodeIntegerContentArray(Node node, String name ){
return getChildNodeIntegerContentArray(node, name, (" ") );
}
}