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