1
package org.herac.tuxguitar.io.ptb;
3
import java.io.IOException;
4
import java.io.InputStream;
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;
23
public class PTInputStream implements TGInputStreamBase{
25
private static final String PTB_VERSION = "ptab-4";
27
private InputStream stream;
28
private String version;
30
private PTSongParser parser;
32
public PTInputStream(){
36
public void init(TGFactory factory,InputStream stream){
39
this.parser = new PTSongParser(factory);
42
public TGFileFormat getFileFormat(){
43
return new TGFileFormat("PowerTab","*.ptb");
46
public boolean isSupportedVersion(String version){
47
return (version.equals(PTB_VERSION));
50
public boolean isSupportedVersion(){
53
return isSupportedVersion(this.version);
61
private void readVersion(){
62
if(this.version == null){
63
this.version = (readString(4) + "-" + readShort());
67
public TGSong readSong() throws IOException{
69
if (!isSupportedVersion(this.version)) {
70
throw new IOException("Unsuported Version");
72
this.song = new PTSong();
74
this.readDataInstruments(this.song.getTrack1());
75
this.readDataInstruments(this.song.getTrack2());
78
return this.parser.parseSong(this.song);
81
private void readSongInfo(){
82
this.song.getInfo().setClassification(readByte());
83
if(this.song.getInfo().getClassification() == 0) {
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());
102
if (readByte() == 0) {
103
this.song.getInfo().setAuthor(readString());
104
this.song.getInfo().setLyricist(readString());
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());
124
private void readDataInstruments(PTTrack track){
126
int itemCount = readHeaderItems();
127
for (int j = 0; j < itemCount; j++) {
128
readTrackInfo(track);
129
if (j < itemCount - 1){
133
// ChordDiagram section
134
itemCount = readHeaderItems();
135
for (int j = 0; j < itemCount; j++) {
137
if (j < itemCount - 1){
141
// FloatingText section
142
itemCount = readHeaderItems();
143
for (int j = 0; j < itemCount; j++) {
145
if (j < itemCount - 1){
150
itemCount = readHeaderItems();
151
for (int j = 0; j < itemCount; j++) {
153
if (j < itemCount - 1){
158
itemCount = readHeaderItems();
159
for (int j = 0; j < itemCount; j++) {
160
readTempoMarker(track);
161
if (j < itemCount - 1){
166
itemCount = readHeaderItems();
167
for (int j = 0; j < itemCount; j++) {
170
if (j < itemCount - 1){
174
// SectionSymbol section
175
itemCount = readHeaderItems();
176
for (int j = 0; j < itemCount; j++) {
177
readSectionSymbol(track);
178
if (j < itemCount - 1){
183
itemCount = readHeaderItems();
184
for (int j = 0; j < itemCount; j++) {
185
readSection(track.getSection(j));
186
if (j < itemCount - 1){
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());
207
readString();//tunningName
209
//bit 7 = Music notation offset sign, bits 6 to 1 = Music notation offset value, bit 0 = display sharps or flats;
212
int[] strings = new int[ (readByte() & 0xff) ];
213
for (int i = 0; i < strings.length; i++) {
214
strings[i] = readByte();
216
info.setStrings(strings);
218
track.getInfos().add(info);
221
private void readSection(PTSection section){
227
int lastBarData = readByte();
235
readBarLine(section);
238
int itemCount = readHeaderItems();
239
for (int j = 0; j < itemCount; j++) {
240
readDirection(section);
241
if (j < itemCount - 1){
246
itemCount = readHeaderItems();
247
for (int j = 0; j < itemCount; j++) {
249
if (j < itemCount - 1){
253
// RhythmSlash section
254
itemCount = readHeaderItems();
255
for (int j = 0; j < itemCount; j++) {
257
if (j < itemCount - 1){
262
section.setStaffs(readHeaderItems());
263
for (int staff = 0; staff < section.getStaffs(); staff++) {
264
readStaff(staff,section);
265
if (staff < section.getStaffs() - 1){
270
itemCount = readHeaderItems();
271
for (int j = 0; j < itemCount; j++) {
272
readBarLine(section);
273
if (j < itemCount - 1){
277
PTBar bar = new PTBar();
278
bar.setRepeatClose(((lastBarData >>> 5) == 4)?(lastBarData - 128):0);
279
section.getPosition(section.getNextPositionNumber()).addComponent(bar);
282
private void readStaff(int staff,PTSection section){
288
int itemCount = readHeaderItems();
289
for (int j = 0; j < itemCount; j++) {
290
readPosition(staff,0,section);
291
if (j < itemCount - 1){
296
itemCount = readHeaderItems();
297
for (int j = 0; j < itemCount; j++) {
298
readPosition(staff,1,section);
299
if (j < itemCount - 1){
305
private void readPosition(int staff,int voice,PTSection section){
306
PTBeat beat = new PTBeat(staff,voice);
308
int position = readByte();
309
int beaming = readByte();
310
beaming = ((beaming - 128 < 0)?beaming:beaming - 128);
314
int data1 = readByte();
316
int data3 = readByte();
317
int durationValue = readByte();
319
int multiBarRest = 1;
320
int complexCount = readByte();
321
for (int i = 0; i < complexCount; i++) {
322
int count = readShort();
325
int type = readByte();
326
if((type & 0x08) != 0){
327
multiBarRest = count;
331
int itemCount = readHeaderItems();
332
for (int j = 0; j < itemCount; j++) {
334
if (j < itemCount - 1){
338
beat.setMultiBarRest((itemCount == 0)?multiBarRest:1);
339
beat.setVibrato(((data1 & 0x08) != 0) || ((data1 & 0x10) != 0));
340
beat.setGrace((data3 & 0x01) != 0);
343
beat.setDuration(durationValue);
344
beat.setDotted((data1 & 0x01) != 0);
345
beat.setDoubleDotted((data1 & 0x02) != 0);
346
beat.setEnters(((beaming - (beaming % 8)) / 8) + 1);
347
beat.setTimes((beaming % 8) + 1);
349
section.getPosition(position).addComponent(beat);
352
private void readNote(PTBeat beat){
353
PTNote note = new PTNote();
354
int position = readByte();
355
int simpleData = readShort();
356
int symbolCount = readByte();
357
for (int i = 0; i < symbolCount; i++) {
360
int data3 = readByte();
361
int data4 = readByte();
362
note.setBend((data4 == 101)?((data3 / 16) + 1):0);
363
note.setSlide((data4 == 100));
365
note.setValue(position & 0x1f);
366
note.setString(((position & 0xe0) >> 5) + 1);
367
note.setTied((simpleData & 0x01) != 0);
368
note.setDead((simpleData & 0x02) != 0);
372
private void readTimeSignature(PTBar bar){
373
int data = readInt();
374
readByte(); //measurePulses
376
bar.setNumerator(((((data >> 24) - ((data >> 24) % 8)) / 8) + 1));
377
bar.setDenominator((int)Math.pow(2,(data >> 24) % 8));
380
private void readKeySignature(){
384
private void readBarLine(PTSection section){
385
PTBar bar = new PTBar();
386
int position = readByte();
387
int type = readByte();
390
bar.setRepeatStart(((type >>> 5) == 3));
393
bar.setRepeatClose((((type >>> 5) == 4)?(type - 128):0));
396
readTimeSignature(bar);
398
section.getPosition(position).addComponent(bar);
401
private void readChord(){
402
readShort(); //chordKey
404
readShort(); //chordModification
407
int stringCount = readByte();
408
for (int j = 0; j < stringCount; j++) {
413
private void readFloattingText(){
426
private void readFontSetting(){
427
readString();//fontName
428
readInt();//pointSize
430
readBoolean();//italic
431
readBoolean();//underline
432
readBoolean();//strikeout
436
private void readGuitarIn(PTTrack track){
437
int section = readShort();
438
int staff = readByte();
439
int position = readByte();
441
int info = (readByte() & 0xff);
442
track.getSection(section).getPosition(position).addComponent(new PTGuitarIn(staff,info));
445
private void readTempoMarker(PTTrack track){
446
int section = readShort();
447
int position = readByte();
448
int tempo = readShort();
449
int data = readShort();
450
readString();//description
451
int tripletFeel = TGMeasureHeader.TRIPLET_FEEL_NONE;
452
if((data & 0x01) != 0){
453
tripletFeel = TGMeasureHeader.TRIPLET_FEEL_EIGHTH;
454
}else if((data & 0x02) != 0){
455
tripletFeel = TGMeasureHeader.TRIPLET_FEEL_SIXTEENTH;
458
track.getSection(section).getPosition(position).addComponent(new PTTempo(tempo,tripletFeel));
462
private void readSectionSymbol(PTTrack track){
463
int section = readShort();
464
int position = readByte();
465
int data = readInt();
466
PTSymbol symbol = new PTSymbol();
467
symbol.setEndNumber( (data >> 16) );
468
track.getSection(section).getPosition(position).addComponent(symbol);
471
private void readDynamic(){
478
private void readRehearsalSign(){
483
private void readDirection(PTSection section){
484
int position = readByte();
485
int symboleCount = readByte();
486
for (int i = 0; i < symboleCount; i++) {
487
int data = readShort();
488
section.getPosition(position).addComponent(new PTDirection( ( data >> 8 ) , ((data & 0xc0) >> 6), (data & 0x1f) ) );
492
private void readChordText(){
500
private void readRhythmSlash(){
506
private int readHeaderItems(){
507
int nbItems = readShort();
509
int header = readShort();
510
if (header == 0xffff) {
511
if (readShort() != 1) {
514
readString(readShort());
520
private String readString(){
522
int length = (this.stream.read() & 0xff);
523
return this.readString(((length < 0xff)?length:readShort()));
524
} catch (IOException e) {
530
private String readString(int length){
532
byte[] bytes = new byte[length];
533
this.stream.read(bytes);
534
return new String(bytes);
535
} catch (IOException e) {
541
private int readInt(){
543
byte[] b = new byte[4];
545
return ((b[3] & 0xff) << 24) | ((b[2] & 0xff) << 16) | ((b[1] & 0xff) << 8) | (b[0] & 0xff);
546
} catch (IOException e) {
552
private int readShort(){
556
return ((b[1] & 0xff) << 8) | (b[0] & 0xff);
557
} catch (IOException e) {
563
private boolean readBoolean(){
565
return (this.stream.read() > 0);
566
} catch (IOException e) {
572
private int readByte(){
574
return this.stream.read();
575
} catch (IOException e) {
581
private void skip(int bytes){
583
this.stream.read(new byte[bytes]);
584
} catch (IOException e) {
589
private void close(){
592
} catch (IOException e) {