1 package org.herac.tuxguitar.io.ptb;
2 
3 import java.io.IOException;
4 import java.io.InputStream;
5 
6 import org.herac.tuxguitar.io.base.TGFileFormat;
7 import org.herac.tuxguitar.io.base.TGInputStreamBase;
8 import org.herac.tuxguitar.io.ptb.base.PTBar;
9 import org.herac.tuxguitar.io.ptb.base.PTBeat;
10 import org.herac.tuxguitar.io.ptb.base.PTDirection;
11 import org.herac.tuxguitar.io.ptb.base.PTGuitarIn;
12 import org.herac.tuxguitar.io.ptb.base.PTNote;
13 import org.herac.tuxguitar.io.ptb.base.PTSection;
14 import org.herac.tuxguitar.io.ptb.base.PTSong;
15 import org.herac.tuxguitar.io.ptb.base.PTSymbol;
16 import org.herac.tuxguitar.io.ptb.base.PTTempo;
17 import org.herac.tuxguitar.io.ptb.base.PTTrack;
18 import org.herac.tuxguitar.io.ptb.base.PTTrackInfo;
19 import org.herac.tuxguitar.song.factory.TGFactory;
20 import org.herac.tuxguitar.song.models.TGMeasureHeader;
21 import org.herac.tuxguitar.song.models.TGSong;
22 
23 public class PTInputStream implements TGInputStreamBase{
24 
25 	private static final String PTB_VERSION = "ptab-4";
26 
27 	private InputStream stream;
28 	private String version;
29 	private PTSong song;
30 	private PTSongParser parser;
31 
PTInputStream()32 	public PTInputStream(){
33 		super();
34 	}
35 
init(TGFactory factory,InputStream stream)36 	public void init(TGFactory factory,InputStream stream){
37 		this.version = null;
38 		this.stream = stream;
39 		this.parser = new PTSongParser(factory);
40 	}
41 
getFileFormat()42 	public TGFileFormat getFileFormat(){
43 		return new TGFileFormat("PowerTab","*.ptb");
44 	}
45 
isSupportedVersion(String version)46 	public boolean isSupportedVersion(String version){
47 		return (version.equals(PTB_VERSION));
48 	}
49 
isSupportedVersion()50 	public boolean isSupportedVersion(){
51 		try{
52 			readVersion();
53 			return isSupportedVersion(this.version);
54 		}catch(Exception e){
55 			return false;
56 		}catch(Error e){
57 			return false;
58 		}
59 	}
60 
readVersion()61 	private void readVersion(){
62 		if(this.version == null){
63 			this.version = (readString(4) + "-" + readShort());
64 		}
65 	}
66 
readSong()67 	public TGSong readSong() throws IOException{
68 		this.readVersion();
69 		if (!isSupportedVersion(this.version)) {
70 			throw new IOException("Unsupported Version");
71 		}
72 		this.song = new PTSong();
73 		this.readSongInfo();
74 		this.readDataInstruments(this.song.getTrack1());
75 		this.readDataInstruments(this.song.getTrack2());
76 		this.close();
77 
78 		return this.parser.parseSong(this.song);
79 	}
80 
readSongInfo()81 	private void readSongInfo(){
82 		this.song.getInfo().setClassification(readByte());
83 		if(this.song.getInfo().getClassification() == 0) {
84 			skip(1);
85 			this.song.getInfo().setName(readString());
86 			this.song.getInfo().setInterpret(readString());
87 			this.song.getInfo().setReleaseType(readByte());
88 			if (this.song.getInfo().getReleaseType() == 0){
89 				this.song.getInfo().setAlbumType(readByte());
90 				this.song.getInfo().setAlbum(readString());
91 				this.song.getInfo().setYear(readShort());
92 				this.song.getInfo().setLiveRecording(readBoolean());
93 			}else if(this.song.getInfo().getReleaseType() == 1){
94 				this.song.getInfo().setAlbum(readString());
95 				this.song.getInfo().setLiveRecording(readBoolean());
96 			}else if(this.song.getInfo().getReleaseType() == 2){
97 				this.song.getInfo().setAlbum(readString());
98 				this.song.getInfo().setDay(readShort());
99 				this.song.getInfo().setMonth(readShort());
100 				this.song.getInfo().setYear(readShort());
101 			}
102 			if (readByte() == 0) {
103 				this.song.getInfo().setAuthor(readString());
104 				this.song.getInfo().setLyricist(readString());
105 			}
106 			this.song.getInfo().setArrenger(readString());
107 			this.song.getInfo().setGuitarTranscriber(readString());
108 			this.song.getInfo().setBassTranscriber(readString());
109 			this.song.getInfo().setCopyright(readString());
110 			this.song.getInfo().setLyrics(readString());
111 			this.song.getInfo().setGuitarInstructions(readString());
112 			this.song.getInfo().setBassInstructions(readString());
113 		}else if(this.song.getInfo().getClassification() == 1){
114 			this.song.getInfo().setName(readString());
115 			this.song.getInfo().setAlbum(readString());
116 			this.song.getInfo().setStyle(readShort());
117 			this.song.getInfo().setLevel(readByte());
118 			this.song.getInfo().setAuthor(readString());
119 			this.song.getInfo().setInstructions(readString());
120 			this.song.getInfo().setCopyright(readString());
121 		}
122 	}
123 
readDataInstruments(PTTrack track)124 	private void readDataInstruments(PTTrack track){
125 		// Guitar section
126 		int itemCount = readHeaderItems();
127 		for (int j = 0; j < itemCount; j++) {
128 			readTrackInfo(track);
129 			if (j < itemCount - 1){
130 				readShort();
131 			}
132 		}
133 		// ChordDiagram section
134 		itemCount = readHeaderItems();
135 		for (int j = 0; j < itemCount; j++) {
136 			readChord();
137 			if (j < itemCount - 1){
138 				readShort();
139 			}
140 		}
141 		// FloatingText section
142 		itemCount = readHeaderItems();
143 		for (int j = 0; j < itemCount; j++) {
144 			readFloattingText();
145 			if (j < itemCount - 1){
146 				readShort();
147 			}
148 		}
149 		// GuitarIn section
150 		itemCount = readHeaderItems();
151 		for (int j = 0; j < itemCount; j++) {
152 			readGuitarIn(track);
153 			if (j < itemCount - 1){
154 				readShort();
155 			}
156 		}
157 		// TempoMarker
158 		itemCount = readHeaderItems();
159 		for (int j = 0; j < itemCount; j++) {
160 			readTempoMarker(track);
161 			if (j < itemCount - 1){
162 				readShort();
163 			}
164 		}
165 		// Dynamic section
166 		itemCount = readHeaderItems();
167 		for (int j = 0; j < itemCount; j++) {
168 			readDynamic();
169 
170 			if (j < itemCount - 1){
171 				readShort();
172 			}
173 		}
174 		// SectionSymbol section
175 		itemCount = readHeaderItems();
176 		for (int j = 0; j < itemCount; j++) {
177 			readSectionSymbol(track);
178 			if (j < itemCount - 1){
179 				readShort();
180 			}
181 		}
182 		// Section section
183 		itemCount = readHeaderItems();
184 		for (int j = 0; j < itemCount; j++) {
185 			readSection(track.getSection(j));
186 			if (j < itemCount - 1){
187 				readShort();
188 			}
189 		}
190 	}
191 
readTrackInfo(PTTrack track)192 	private void readTrackInfo(PTTrack track){
193 		PTTrackInfo info = new PTTrackInfo();
194 		info.setNumber(readByte());
195 		info.setName(readString());
196 		info.setInstrument((short)readByte());
197 		info.setVolume((short)readByte());
198 		info.setBalance((short)readByte());
199 		info.setReverb((short)readByte());
200 		info.setChorus((short)readByte());
201 		info.setTremolo((short)readByte());
202 		info.setPhaser((short)readByte());
203 
204 		readByte();//capo
205 
206 		// Tuning
207 		readString();//tunningName
208 
209 		//bit 7 = Music notation offset sign, bits 6 to 1 = Music notation offset value, bit 0 = display sharps or flats;
210 		readByte();  //offset
211 
212 		int[] strings = new int[ (readByte() & 0xff) ];
213 		for (int i = 0; i < strings.length; i++) {
214 			strings[i] = readByte();
215 		}
216 		info.setStrings(strings);
217 
218 		track.getInfos().add(info);
219 	}
220 
readSection(PTSection section)221 	private void readSection(PTSection section){
222 		readInt();//left
223 		readInt();//top
224 		readInt();//right
225 		readInt();//bottom
226 
227 		int lastBarData = readByte();
228 
229 		readByte();
230 		readByte();
231 		readByte();
232 		readByte();
233 
234 		// BarLine
235 		readBarLine(section);
236 
237 		// Direction section
238 		int itemCount = readHeaderItems();
239 		for (int j = 0; j < itemCount; j++) {
240 			readDirection(section);
241 			if (j < itemCount - 1){
242 				readShort();
243 			}
244 		}
245 		// ChordText section
246 		itemCount = readHeaderItems();
247 		for (int j = 0; j < itemCount; j++) {
248 			readChordText();
249 			if (j < itemCount - 1){
250 				readShort();
251 			}
252 		}
253 		// RhythmSlash section
254 		itemCount = readHeaderItems();
255 		for (int j = 0; j < itemCount; j++) {
256 			readRhythmSlash();
257 			if (j < itemCount - 1){
258 				readShort();
259 			}
260 		}
261 		// Staff
262 		section.setStaffs(readHeaderItems());
263 		for (int staff = 0; staff < section.getStaffs(); staff++) {
264 			readStaff(staff,section);
265 			if (staff < section.getStaffs() - 1){
266 				readShort();
267 			}
268 		}
269 		// MusicBar section
270 		itemCount = readHeaderItems();
271 		for (int j = 0; j < itemCount; j++) {
272 			readBarLine(section);
273 			if (j < itemCount - 1){
274 				readShort();
275 			}
276 		}
277 		PTBar bar = new PTBar();
278 		bar.setRepeatClose(((lastBarData >>> 5) == 4)?(lastBarData - 128):0);
279 		section.getPosition(section.getNextPositionNumber()).addComponent(bar);
280 	}
281 
readStaff(int staff,PTSection section)282 	private void readStaff(int staff,PTSection section){
283 		readByte();
284 		readByte();
285 		readByte();
286 		readByte();
287 		readByte();
288 
289 		for( int voice = 0 ; voice < 2 ; voice ++ ){
290 			int itemCount = readHeaderItems();
291 			for (int j = 0; j < itemCount; j++) {
292 				readPosition(staff,voice,section);
293 				if (j < itemCount - 1){
294 					readShort();
295 				}
296 			}
297 		}
298 	}
299 
readPosition(int staff,int voice,PTSection section)300 	private void readPosition(int staff,int voice,PTSection section){
301 		PTBeat beat = new PTBeat(staff,voice);
302 
303 		int position = readByte();
304 		int beaming = readByte();
305 		beaming = ((beaming - 128 < 0)?beaming:beaming - 128);
306 
307 		readByte();
308 
309 		int data1 = readByte();
310 		readByte();
311 		int data3 = readByte();
312 		int durationValue = readByte();
313 
314 		int multiBarRest = 1;
315 		int complexCount = readByte();
316 		for (int i = 0; i < complexCount; i++) {
317 			int count = readShort();
318 			readByte();
319 
320 			int type = readByte();
321 			if((type & 0x08) != 0){
322 				multiBarRest = count;
323 			}
324 		}
325 
326 		int itemCount = readHeaderItems();
327 		for (int j = 0; j < itemCount; j++) {
328 			readNote(beat);
329 			if (j < itemCount - 1){
330 				readShort();
331 			}
332 		}
333 		beat.setMultiBarRest((itemCount == 0)?multiBarRest:1);
334 		beat.setVibrato(((data1 & 0x08) != 0) || ((data1 & 0x10) != 0));
335 		beat.setGrace((data3 & 0x01) != 0);
336 
337 		// Set the duration
338 		beat.setDuration(durationValue);
339 		beat.setDotted((data1 & 0x01) != 0);
340 		beat.setDoubleDotted((data1 & 0x02) != 0);
341 		beat.setArpeggioUp((data1 & 0x20) != 0);
342 		beat.setArpeggioDown((data1 & 0x40) != 0);
343 		beat.setEnters(((beaming - (beaming % 8)) / 8) + 1);
344 		beat.setTimes((beaming % 8) + 1);
345 
346 		section.getPosition(position).addComponent(beat);
347 	}
348 
readNote(PTBeat beat)349 	private void readNote(PTBeat beat){
350 		PTNote note = new PTNote();
351 		int position = readByte();
352 		int simpleData = readShort();
353 		int symbolCount = readByte();
354 		for (int i = 0; i < symbolCount; i++) {
355 			readByte();
356 			readByte();
357 			int data3 = readByte();
358 			int data4 = readByte();
359 			note.setBend((data4 == 101)?((data3 / 16) + 1):0);
360 			note.setSlide((data4 == 100));
361 		}
362 		note.setValue(position & 0x1f);
363 		note.setString(((position & 0xe0) >> 5) + 1);
364 		note.setTied((simpleData & 0x01) != 0);
365 		note.setDead((simpleData & 0x02) != 0);
366 		beat.addNote(note);
367 	}
368 
readTimeSignature(PTBar bar)369 	private void readTimeSignature(PTBar bar){
370 		int data = readInt();
371 		readByte(); //measurePulses
372 
373 		bar.setNumerator(((((data >> 24) - ((data >> 24) % 8)) / 8) + 1));
374 		bar.setDenominator((int)Math.pow(2,(data >> 24) % 8));
375 	}
376 
readKeySignature()377 	private void readKeySignature(){
378 		readByte();
379 	}
380 
readBarLine(PTSection section)381 	private void readBarLine(PTSection section){
382 		PTBar bar = new PTBar();
383 		int position = readByte();
384 		int type = readByte();
385 
386 		//repeat start
387 		bar.setRepeatStart(((type >>> 5) == 3));
388 
389 		//repeat end
390 		bar.setRepeatClose((((type >>> 5) == 4)?(type - 128):0));
391 
392 		readKeySignature();
393 		readTimeSignature(bar);
394 		readRehearsalSign();
395 		section.getPosition(position).addComponent(bar);
396 	}
397 
readChord()398 	private void readChord(){
399 		readShort(); //chordKey
400 		readByte();
401 		readShort(); //chordModification
402 		readByte();
403 		readByte();
404 		int stringCount = readByte();
405 		for (int j = 0; j < stringCount; j++) {
406 			readByte(); //fret
407 		}
408 	}
409 
readFloattingText()410 	private void readFloattingText(){
411 		// Floating text
412 		readString();
413 		// Read mfc rect
414 		readInt();//left
415 		readInt();//top
416 		readInt();//right
417 		readInt();//bottom
418 
419 		readByte();
420 		readFontSetting();
421 	}
422 
readFontSetting()423 	private void readFontSetting(){
424 		readString();//fontName
425 		readInt();//pointSize
426 		readInt();//weight
427 		readBoolean();//italic
428 		readBoolean();//underline
429 		readBoolean();//strikeout
430 		readInt();//color
431 	}
432 
readGuitarIn(PTTrack track)433 	private void readGuitarIn(PTTrack track){
434 		int section = readShort();
435 		int staff = readByte();
436 		int position = readByte();
437 		skip(1);
438 		int info = (readByte() & 0xff);
439 		track.getSection(section).getPosition(position).addComponent(new PTGuitarIn(staff,info));
440 	}
441 
readTempoMarker(PTTrack track)442 	private void readTempoMarker(PTTrack track){
443 		int section = readShort();
444 		int position = readByte();
445 		int tempo = readShort();
446 		int data = readShort();
447 		readString();//description
448 		int tripletFeel = TGMeasureHeader.TRIPLET_FEEL_NONE;
449 		if((data & 0x01) != 0){
450 			tripletFeel = TGMeasureHeader.TRIPLET_FEEL_EIGHTH;
451 		}else if((data & 0x02) != 0){
452 			tripletFeel = TGMeasureHeader.TRIPLET_FEEL_SIXTEENTH;
453 		}
454 		if(tempo > 0){
455 			track.getSection(section).getPosition(position).addComponent(new PTTempo(tempo,tripletFeel));
456 		}
457 	}
458 
readSectionSymbol(PTTrack track)459 	private void readSectionSymbol(PTTrack track){
460 		int section = readShort();
461 		int position = readByte();
462 		int data = readInt();
463 		PTSymbol symbol = new PTSymbol();
464 		symbol.setEndNumber( (data >> 16) );
465 		track.getSection(section).getPosition(position).addComponent(symbol);
466 	}
467 
readDynamic()468 	private void readDynamic(){
469 		readShort();
470 		readByte();
471 		readByte();
472 		readShort();
473 	}
474 
readRehearsalSign()475 	private void readRehearsalSign(){
476 		readByte();
477 		readString();
478 	}
479 
readDirection(PTSection section)480 	private void readDirection(PTSection section){
481 		int position = readByte();
482 		int symboleCount = readByte();
483 		for (int i = 0; i < symboleCount; i++) {
484 			int data = readShort();
485 			section.getPosition(position).addComponent(new PTDirection( ( data >> 8 ) , ((data & 0xc0) >> 6), (data & 0x1f) ) );
486 		}
487 	}
488 
readChordText()489 	private void readChordText(){
490 		readByte();
491 		readShort();
492 		readByte();
493 		readShort();
494 		readByte();
495 	}
496 
readRhythmSlash()497 	private void readRhythmSlash(){
498 		readByte();
499 		readByte();
500 		readInt();
501 	}
502 
readHeaderItems()503 	private int readHeaderItems(){
504 		int nbItems = readShort();
505 		if (nbItems != 0){
506 			int header = readShort();
507 			if (header == 0xffff) {
508 				if (readShort() != 1) {
509 					return -1;
510 				}
511 				readString(readShort());
512 			}
513 		}
514 		return nbItems;
515 	}
516 
readString()517 	private String readString(){
518 		try {
519 			int length = (this.stream.read() & 0xff);
520 			return this.readString(((length < 0xff)?length:readShort()));
521 		} catch (IOException e) {
522 			e.printStackTrace();
523 		}
524 		return null;
525 	}
526 
readString(int length)527 	private String readString(int length){
528 		try {
529 			byte[] bytes = new byte[length];
530 			this.stream.read(bytes);
531 			return new String(bytes);
532 		} catch (IOException e) {
533 			e.printStackTrace();
534 		}
535 		return null;
536 	}
537 
readInt()538 	private int readInt(){
539 		try {
540 			byte[] b = new byte[4];
541 			this.stream.read(b);
542 			return ((b[3] & 0xff) << 24) | ((b[2] & 0xff) << 16) | ((b[1] & 0xff) << 8) | (b[0] & 0xff);
543 		} catch (IOException e) {
544 			e.printStackTrace();
545 		}
546 		return 0;
547 	}
548 
readShort()549 	private int readShort(){
550 		try {
551 			byte[] b = {0, 0};
552 			this.stream.read(b);
553 			return ((b[1] & 0xff) << 8) | (b[0] & 0xff);
554 		} catch (IOException e) {
555 			e.printStackTrace();
556 		}
557 		return 0;
558 	}
559 
readBoolean()560 	private boolean readBoolean(){
561 		try {
562 			return (this.stream.read() > 0);
563 		} catch (IOException e) {
564 			e.printStackTrace();
565 		}
566 		return false;
567 	}
568 
readByte()569 	private int readByte(){
570 		try {
571 			return this.stream.read();
572 		} catch (IOException e) {
573 			e.printStackTrace();
574 		}
575 		return 0;
576 	}
577 
skip(int bytes)578 	private void skip(int bytes){
579 		try {
580 			this.stream.read(new byte[bytes]);
581 		} catch (IOException e) {
582 			e.printStackTrace();
583 		}
584 	}
585 
close()586 	private void close(){
587 		try {
588 			this.stream.close();
589 		} catch (IOException e) {
590 			e.printStackTrace();
591 		}
592 	}
593 }
594