package org.herac.tuxguitar.io.ptb; import java.io.IOException; import java.io.InputStream; import org.herac.tuxguitar.io.base.TGFileFormat; import org.herac.tuxguitar.io.base.TGFileFormatException; import org.herac.tuxguitar.io.base.TGInputStreamBase; import org.herac.tuxguitar.io.ptb.base.PTBar; import org.herac.tuxguitar.io.ptb.base.PTBeat; import org.herac.tuxguitar.io.ptb.base.PTDirection; import org.herac.tuxguitar.io.ptb.base.PTGuitarIn; import org.herac.tuxguitar.io.ptb.base.PTNote; import org.herac.tuxguitar.io.ptb.base.PTSection; import org.herac.tuxguitar.io.ptb.base.PTSong; import org.herac.tuxguitar.io.ptb.base.PTSymbol; import org.herac.tuxguitar.io.ptb.base.PTTempo; import org.herac.tuxguitar.io.ptb.base.PTTrack; import org.herac.tuxguitar.io.ptb.base.PTTrackInfo; import org.herac.tuxguitar.song.factory.TGFactory; import org.herac.tuxguitar.song.models.TGMeasureHeader; import org.herac.tuxguitar.song.models.TGSong; public class PTInputStream implements TGInputStreamBase{ private static final String PTB_VERSION = "ptab-4"; private InputStream stream; private String version; private PTSong song; private PTSongParser parser; public PTInputStream(){ super(); } @Override public void init(TGFactory factory,InputStream stream){ this.version = null; this.stream = stream; this.parser = new PTSongParser(factory); } @Override public TGFileFormat getFileFormat(){ return new TGFileFormat("PowerTab","*.ptb"); } public boolean isSupportedVersion(String version){ return (version.equals(PTB_VERSION)); } @Override public boolean isSupportedVersion(){ try{ readVersion(); return isSupportedVersion(this.version); }catch(Exception e){ return false; }catch(Error e){ return false; } } private void readVersion(){ if(this.version == null){ this.version = (readString(4) + "-" + readShort()); } } @Override public TGSong readSong() throws TGFileFormatException{ try{ this.readVersion(); if (!isSupportedVersion(this.version)) { throw new IOException("Unsupported Version"); } this.song = new PTSong(); this.readSongInfo(); this.readDataInstruments(this.song.getTrack1()); this.readDataInstruments(this.song.getTrack2()); this.close(); return this.parser.parseSong(this.song); } catch (Throwable throwable) { throw new TGFileFormatException(throwable); } } private void readSongInfo(){ this.song.getInfo().setClassification(readByte()); if(this.song.getInfo().getClassification() == 0) { skip(1); this.song.getInfo().setName(readString()); this.song.getInfo().setInterpret(readString()); this.song.getInfo().setReleaseType(readByte()); if (this.song.getInfo().getReleaseType() == 0){ this.song.getInfo().setAlbumType(readByte()); this.song.getInfo().setAlbum(readString()); this.song.getInfo().setYear(readShort()); this.song.getInfo().setLiveRecording(readBoolean()); }else if(this.song.getInfo().getReleaseType() == 1){ this.song.getInfo().setAlbum(readString()); this.song.getInfo().setLiveRecording(readBoolean()); }else if(this.song.getInfo().getReleaseType() == 2){ this.song.getInfo().setAlbum(readString()); this.song.getInfo().setDay(readShort()); this.song.getInfo().setMonth(readShort()); this.song.getInfo().setYear(readShort()); } if (readByte() == 0) { this.song.getInfo().setAuthor(readString()); this.song.getInfo().setLyricist(readString()); } this.song.getInfo().setArrenger(readString()); this.song.getInfo().setGuitarTranscriber(readString()); this.song.getInfo().setBassTranscriber(readString()); this.song.getInfo().setCopyright(readString()); this.song.getInfo().setLyrics(readString()); this.song.getInfo().setGuitarInstructions(readString()); this.song.getInfo().setBassInstructions(readString()); }else if(this.song.getInfo().getClassification() == 1){ this.song.getInfo().setName(readString()); this.song.getInfo().setAlbum(readString()); this.song.getInfo().setStyle(readShort()); this.song.getInfo().setLevel(readByte()); this.song.getInfo().setAuthor(readString()); this.song.getInfo().setInstructions(readString()); this.song.getInfo().setCopyright(readString()); } } private void readDataInstruments(PTTrack track){ // Guitar section int itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readTrackInfo(track); if (j < itemCount - 1){ readShort(); } } // ChordDiagram section itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readChord(); if (j < itemCount - 1){ readShort(); } } // FloatingText section itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readFloattingText(); if (j < itemCount - 1){ readShort(); } } // GuitarIn section itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readGuitarIn(track); if (j < itemCount - 1){ readShort(); } } // TempoMarker itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readTempoMarker(track); if (j < itemCount - 1){ readShort(); } } // Dynamic section itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readDynamic(); if (j < itemCount - 1){ readShort(); } } // SectionSymbol section itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readSectionSymbol(track); if (j < itemCount - 1){ readShort(); } } // Section section itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readSection(track.getSection(j)); if (j < itemCount - 1){ readShort(); } } } private void readTrackInfo(PTTrack track){ PTTrackInfo info = new PTTrackInfo(); info.setNumber(readByte()); info.setName(readString()); info.setInstrument((short)readByte()); info.setVolume((short)readByte()); info.setBalance((short)readByte()); info.setReverb((short)readByte()); info.setChorus((short)readByte()); info.setTremolo((short)readByte()); info.setPhaser((short)readByte()); readByte();//capo // Tuning readString();//tunningName //bit 7 = Music notation offset sign, bits 6 to 1 = Music notation offset value, bit 0 = display sharps or flats; readByte(); //offset int[] strings = new int[ (readByte() & 0xff) ]; for (int i = 0; i < strings.length; i++) { strings[i] = readByte(); } info.setStrings(strings); track.getInfos().add(info); } private void readSection(PTSection section){ readInt();//left readInt();//top readInt();//right readInt();//bottom int lastBarData = readByte(); readByte(); readByte(); readByte(); readByte(); // BarLine readBarLine(section); // Direction section int itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readDirection(section); if (j < itemCount - 1){ readShort(); } } // ChordText section itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readChordText(); if (j < itemCount - 1){ readShort(); } } // RhythmSlash section itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readRhythmSlash(); if (j < itemCount - 1){ readShort(); } } // Staff section.setStaffs(readHeaderItems()); for (int staff = 0; staff < section.getStaffs(); staff++) { readStaff(staff,section); if (staff < section.getStaffs() - 1){ readShort(); } } // MusicBar section itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readBarLine(section); if (j < itemCount - 1){ readShort(); } } PTBar bar = new PTBar(); bar.setRepeatClose(((lastBarData >>> 5) == 4)?(lastBarData - 128):0); section.getPosition(section.getNextPositionNumber()).addComponent(bar); } private void readStaff(int staff,PTSection section){ readByte(); readByte(); readByte(); readByte(); readByte(); for( int voice = 0 ; voice < 2 ; voice ++ ){ int itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readPosition(staff,voice,section); if (j < itemCount - 1){ readShort(); } } } } private void readPosition(int staff,int voice,PTSection section){ PTBeat beat = new PTBeat(staff,voice); int position = readByte(); int beaming = readByte(); beaming = ((beaming - 128 < 0)?beaming:beaming - 128); readByte(); int data1 = readByte(); readByte(); int data3 = readByte(); int durationValue = readByte(); int multiBarRest = 1; int complexCount = readByte(); for (int i = 0; i < complexCount; i++) { int count = readShort(); readByte(); int type = readByte(); if((type & 0x08) != 0){ multiBarRest = count; } } int itemCount = readHeaderItems(); for (int j = 0; j < itemCount; j++) { readNote(beat); if (j < itemCount - 1){ readShort(); } } beat.setMultiBarRest((itemCount == 0)?multiBarRest:1); beat.setVibrato(((data1 & 0x08) != 0) || ((data1 & 0x10) != 0)); beat.setGrace((data3 & 0x01) != 0); // Set the duration beat.setDuration(durationValue); beat.setDotted((data1 & 0x01) != 0); beat.setDoubleDotted((data1 & 0x02) != 0); beat.setArpeggioUp((data1 & 0x20) != 0); beat.setArpeggioDown((data1 & 0x40) != 0); beat.setEnters(((beaming - (beaming % 8)) / 8) + 1); beat.setTimes((beaming % 8) + 1); section.getPosition(position).addComponent(beat); } private void readNote(PTBeat beat){ PTNote note = new PTNote(); int position = readByte(); int simpleData = readShort(); int symbolCount = readByte(); for (int i = 0; i < symbolCount; i++) { readByte(); readByte(); int data3 = readByte(); int data4 = readByte(); note.setBend((data4 == 101)?((data3 / 16) + 1):0); note.setSlide((data4 == 100)); } note.setValue(position & 0x1f); note.setString(((position & 0xe0) >> 5) + 1); note.setTied((simpleData & 0x01) != 0); note.setDead((simpleData & 0x02) != 0); beat.addNote(note); } private void readTimeSignature(PTBar bar){ int data = readInt(); readByte(); //measurePulses bar.setNumerator(((((data >> 24) - ((data >> 24) % 8)) / 8) + 1)); bar.setDenominator((int)Math.pow(2,(data >> 24) % 8)); } private void readKeySignature(){ readByte(); } private void readBarLine(PTSection section){ PTBar bar = new PTBar(); int position = readByte(); int type = readByte(); //repeat start bar.setRepeatStart(((type >>> 5) == 3)); //repeat end bar.setRepeatClose((((type >>> 5) == 4)?(type - 128):0)); readKeySignature(); readTimeSignature(bar); readRehearsalSign(); section.getPosition(position).addComponent(bar); } private void readChord(){ readShort(); //chordKey readByte(); readShort(); //chordModification readByte(); readByte(); int stringCount = readByte(); for (int j = 0; j < stringCount; j++) { readByte(); //fret } } private void readFloattingText(){ // Floating text readString(); // Read mfc rect readInt();//left readInt();//top readInt();//right readInt();//bottom readByte(); readFontSetting(); } private void readFontSetting(){ readString();//fontName readInt();//pointSize readInt();//weight readBoolean();//italic readBoolean();//underline readBoolean();//strikeout readInt();//color } private void readGuitarIn(PTTrack track){ int section = readShort(); int staff = readByte(); int position = readByte(); skip(1); int info = (readByte() & 0xff); track.getSection(section).getPosition(position).addComponent(new PTGuitarIn(staff,info)); } private void readTempoMarker(PTTrack track){ int section = readShort(); int position = readByte(); int tempo = readShort(); int data = readShort(); readString();//description int tripletFeel = TGMeasureHeader.TRIPLET_FEEL_NONE; if((data & 0x01) != 0){ tripletFeel = TGMeasureHeader.TRIPLET_FEEL_EIGHTH; }else if((data & 0x02) != 0){ tripletFeel = TGMeasureHeader.TRIPLET_FEEL_SIXTEENTH; } if(tempo > 0){ track.getSection(section).getPosition(position).addComponent(new PTTempo(tempo,tripletFeel)); } } private void readSectionSymbol(PTTrack track){ int section = readShort(); int position = readByte(); int data = readInt(); PTSymbol symbol = new PTSymbol(); symbol.setEndNumber( (data >> 16) ); track.getSection(section).getPosition(position).addComponent(symbol); } private void readDynamic(){ readShort(); readByte(); readByte(); readShort(); } private void readRehearsalSign(){ readByte(); readString(); } private void readDirection(PTSection section){ int position = readByte(); int symboleCount = readByte(); for (int i = 0; i < symboleCount; i++) { int data = readShort(); section.getPosition(position).addComponent(new PTDirection( ( data >> 8 ) , ((data & 0xc0) >> 6), (data & 0x1f) ) ); } } private void readChordText(){ readByte(); readShort(); readByte(); readShort(); readByte(); } private void readRhythmSlash(){ readByte(); readByte(); readInt(); } private int readHeaderItems(){ int nbItems = readShort(); if (nbItems != 0){ int header = readShort(); if (header == 0xffff) { if (readShort() != 1) { return -1; } readString(readShort()); } } return nbItems; } private String readString(){ try { int length = (this.stream.read() & 0xff); return this.readString(((length < 0xff)?length:readShort())); } catch (IOException e) { e.printStackTrace(); } return null; } private String readString(int length){ try { byte[] bytes = new byte[length]; this.stream.read(bytes); return new String(bytes); } catch (IOException e) { e.printStackTrace(); } return null; } private int readInt(){ try { byte[] b = new byte[4]; this.stream.read(b); return ((b[3] & 0xff) << 24) | ((b[2] & 0xff) << 16) | ((b[1] & 0xff) << 8) | (b[0] & 0xff); } catch (IOException e) { e.printStackTrace(); } return 0; } private int readShort(){ try { byte[] b = {0, 0}; this.stream.read(b); return ((b[1] & 0xff) << 8) | (b[0] & 0xff); } catch (IOException e) { e.printStackTrace(); } return 0; } private boolean readBoolean(){ try { return (this.stream.read() > 0); } catch (IOException e) { e.printStackTrace(); } return false; } private int readByte(){ try { return this.stream.read(); } catch (IOException e) { e.printStackTrace(); } return 0; } private void skip(int bytes){ try { this.stream.read(new byte[bytes]); } catch (IOException e) { e.printStackTrace(); } } private void close(){ try { this.stream.close(); } catch (IOException e) { e.printStackTrace(); } } }