1
package org.herac.tuxguitar.io.gp;
4
import java.io.FileInputStream;
5
import java.io.FileNotFoundException;
6
import java.io.IOException;
7
import java.io.InputStream;
8
import java.util.ArrayList;
11
import org.herac.tuxguitar.song.models.Duration;
12
import org.herac.tuxguitar.song.models.InstrumentString;
13
import org.herac.tuxguitar.song.models.Lyric;
14
import org.herac.tuxguitar.song.models.Marker;
15
import org.herac.tuxguitar.song.models.Measure;
16
import org.herac.tuxguitar.song.models.MeasureHeader;
17
import org.herac.tuxguitar.song.models.Note;
18
import org.herac.tuxguitar.song.models.NoteEffect;
19
import org.herac.tuxguitar.song.models.Song;
20
import org.herac.tuxguitar.song.models.SongChannel;
21
import org.herac.tuxguitar.song.models.SongTrack;
22
import org.herac.tuxguitar.song.models.Tempo;
23
import org.herac.tuxguitar.song.models.TimeSignature;
24
import org.herac.tuxguitar.song.models.RGBColor;
25
import org.herac.tuxguitar.song.models.VelocityValues;
26
import org.herac.tuxguitar.song.models.effects.BendEffect;
27
import org.herac.tuxguitar.song.models.effects.GraceEffect;
28
import org.herac.tuxguitar.song.models.effects.HarmonicEffect;
29
import org.herac.tuxguitar.song.models.effects.TremoloBarEffect;
34
* TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
36
public class GP3InputStream extends InputStream {
37
private static final String GP3_VERSION = "FICHIER GUITAR PRO v3.00";
38
private static final int GP_BEND_SEMITONE = 50;
39
private static final int GP_BEND_POSITION = 60;
41
private InputStream inputStream;
42
private String version;
43
private int tripletFeel;
45
public GP3InputStream(InputStream inputStream) {
47
this.inputStream = inputStream;
50
public GP3InputStream(String fileName) throws FileNotFoundException {
51
this(new FileInputStream(new File(fileName)));
57
public void close() throws IOException {
58
this.inputStream.close();
61
public int read() throws IOException {
62
return this.inputStream.read();
65
public static boolean isSupportedVersion(String version) {
66
return (version.equals(GP3_VERSION));
69
public boolean isSupportedVersion(){
72
return isSupportedVersion(version);
80
private void readVersion(){
82
if(this.version == null){
83
this.version = readStringByte(30);
85
} catch (IOException e) {
86
this.version = "NOT_SUPPORTED";
90
public Song readSong() throws IOException, GPFormatException {
92
if (!isSupportedVersion(version)) {
93
throw new GPFormatException("Unsuported Version");
96
String title = readStringIntegerPlusOne();
98
String subtitle = readStringIntegerPlusOne();
100
String interpret = readStringIntegerPlusOne();
102
String album = readStringIntegerPlusOne();
104
String songAuthor = readStringIntegerPlusOne();
106
String copyright = readStringIntegerPlusOne();
108
String pieceAuthor = readStringIntegerPlusOne();
110
String instructions = readStringIntegerPlusOne();
112
int nbNotes = readInt();
114
for (int i = 0; i < nbNotes; i++) {
115
note += readStringIntegerPlusOne();
119
this.tripletFeel = ((readBoolean())?MeasureHeader.TRIPLET_FEEL_EIGHTH:MeasureHeader.TRIPLET_FEEL_NONE);
121
int tempoValue = readInt();
125
List channels = new ArrayList();
126
int[] instruments = new int[64];
127
for (int i = 0; i < 64; i++) {
128
channels.add(new SongChannel((short)i,
131
toChannelShort(readByte()),
132
toChannelShort(readByte()),
133
toChannelShort(readByte()),
134
toChannelShort(readByte()),
135
toChannelShort(readByte()),
136
toChannelShort(readByte()),
143
TimeSignature timeSignature = new TimeSignature(4, new Duration(4));
144
int numberOfMeasures = readInt();
145
int numberOfTracks = readInt();
147
List headers = new ArrayList();
148
if (numberOfMeasures > 0) {
149
for (int i = 0; i < numberOfMeasures; i++) {
150
MeasureHeader header = createMeasureHeader((i + 1),timeSignature);
155
List tracks = new ArrayList();
156
for (int number = 1; number <= numberOfTracks; number++) {
157
tracks.add(createTrack(number, channels,new Lyric()));
160
long nextMeasureStart = 1000;
161
for (int i = 0; i < numberOfMeasures; i++) {
162
MeasureHeader currHeader = (MeasureHeader) headers.get(i);
163
Tempo tempo = new Tempo(tempoValue);
164
currHeader.setStart(nextMeasureStart);
165
for (int j = 0; j < numberOfTracks; j++) {
166
SongTrack track = (SongTrack) tracks.get(j);
167
Measure measure = new Measure(currHeader,new ArrayList(),new ArrayList(),1,0);
168
addMeasureComponents(track.getStrings(), measure, track.getMeasures(), tempo);
169
currHeader.setTempo(tempo);
170
track.getMeasures().add(measure);
172
tempoValue = tempo.getValue();
173
nextMeasureStart += currHeader.getLength();
178
boolean different = false;
182
if (!different && i > 4) {
188
return new Song(title,interpret,album,songAuthor,tracks,headers,Song.MAX_VOLUME);
192
private List getPlayedStrings(int stringsPlayed, List trackStrings) {
193
List strings = new ArrayList();
194
if ((stringsPlayed & (1 << 0)) != 0 && trackStrings.size() > 6) {
195
strings.add(((InstrumentString) trackStrings.get(6)).clone());
197
if ((stringsPlayed & (1 << 1)) != 0 && trackStrings.size() > 5) {
198
strings.add(((InstrumentString) trackStrings.get(5)).clone());
200
if ((stringsPlayed & (1 << 2)) != 0 && trackStrings.size() > 4) {
201
strings.add(((InstrumentString) trackStrings.get(4)).clone());
203
if ((stringsPlayed & (1 << 3)) != 0 && trackStrings.size() > 3) {
204
strings.add(((InstrumentString) trackStrings.get(3)).clone());
206
if ((stringsPlayed & (1 << 4)) != 0 && trackStrings.size() > 2) {
207
strings.add(((InstrumentString) trackStrings.get(2)).clone());
209
if ((stringsPlayed & (1 << 5)) != 0 && trackStrings.size() > 1) {
210
strings.add(((InstrumentString) trackStrings.get(1)).clone());
212
if ((stringsPlayed & (1 << 6)) != 0 && trackStrings.size() > 0) {
213
strings.add(((InstrumentString) trackStrings.get(0)).clone());
218
private Duration parseDuration(byte value) {
219
Duration duration = null;
222
duration = new Duration(Duration.WHOLE);
225
duration = new Duration(Duration.HALF);
228
duration = new Duration(Duration.QUARTER);
231
duration = new Duration(Duration.EIGHTH);
234
duration = new Duration(Duration.SIXTEENTH);
237
duration = new Duration(Duration.THIRTY_SECOND);
240
duration = new Duration(Duration.SIXTY_FOURTH);
243
if(duration == null){
244
duration = new Duration(Duration.QUARTER);
245
System.err.println("Incorrect Duration. Forcing duration Quarter as Default.");
250
private int getTiedNoteValue(int string, List notes, List measures) {
251
if (!notes.isEmpty()) {
252
for (int nIdx = notes.size() - 1; nIdx >= 0; nIdx--) {
253
Note note = (Note) notes.get(nIdx);
254
if (note.getString() == string) {
255
return note.getValue();
259
if (!measures.isEmpty()) {
260
for (int mIdx = measures.size() - 1; mIdx >= 0; mIdx--) {
261
Measure measure = (Measure) measures.get(mIdx);
262
for (int nIdx = measure.getNotes().size() - 1; nIdx >= 0; nIdx--) {
263
Note note = (Note) measure.getNotes().get(nIdx);
264
if (note.getString() == string) {
265
return note.getValue();
273
private boolean readBoolean() throws IOException {
274
return (read() == 1);
277
private byte readByte() throws IOException {
278
return (byte) read();
281
private RGBColor readColor() throws IOException {
282
int r = readUnsignedByte();
283
int g = readUnsignedByte();
284
int b = readUnsignedByte();
287
return new RGBColor(r,g,b);
290
private int readInt() throws IOException {
292
byte[] b = { 0, 0, 0, 0 };
295
integer = ((b[3] & 0xff) << 24) | ((b[2] & 0xff) << 16) | ((b[1] & 0xff) << 8) | (b[0] & 0xff);
300
private Marker readMarker(int measure) throws IOException {
301
String name = readStringIntegerPlusOne();
302
RGBColor color = readColor();
304
return new Marker(measure,name,color);
307
private MeasureHeader createMeasureHeader(int number,TimeSignature currTimeSignature) throws IOException {
308
int header = readUnsignedByte();
311
if ((header & 0x01) != 0) {
312
numerator = readByte();
316
if ((header & 0x02) != 0) {
317
denominator = readByte();
320
boolean repeatStart = ((header & 0x04) != 0);
322
int numberOfRepetitions = 0;
323
if ((header & 0x08) != 0) {
324
numberOfRepetitions = readByte();
327
int NumberOfAlternateEnding = 0;
328
if ((header & 0x10) != 0) {
329
NumberOfAlternateEnding = readByte();
332
Marker marker = null;
333
if ((header & 0x20) != 0) {
334
marker = readMarker(number);
337
if ((header & 0x40) != 0) {
338
int type = readByte();
342
if ((header & 0x80) != 0) {
345
boolean doubleBar = ((header & 0x80) != 0);
348
currTimeSignature.setNumerator(numerator);
350
if (denominator > 0) {
351
currTimeSignature.setDenominator(new Duration(denominator));
354
return new MeasureHeader(number,0,(TimeSignature) currTimeSignature.clone(), new Tempo(120),marker,tripletFeel,repeatStart,numberOfRepetitions);
357
private void addMeasureComponents(List trackStrings, Measure measure, List currTrackMeasures, Tempo tempo) throws IOException,
359
long nextNoteStart = measure.getStart();
360
int numberOfBeats = readInt();
361
for (int i = 0; i < numberOfBeats; i++) {
362
nextNoteStart += addNotes(nextNoteStart, measure.getNotes(), trackStrings, currTrackMeasures, tempo);
367
private long addNotes(long start, List notes, List trackStrings, List currTrackMeasures, Tempo tempo) throws IOException,
369
NoteEffect effect = new NoteEffect();
371
int header = readUnsignedByte();
373
if ((header & 0x80) != 0) {
374
//TODO ver que es 0x80
378
if ((header & 0x40) != 0) {
379
int beatStatus = readUnsignedByte();
380
boolean emptyBeat = (beatStatus == 0x00);
381
boolean restBeat = (beatStatus == 0x02);
384
boolean dottedNotes = ((header & 0x01) != 0);
386
Duration duration = parseDuration(readByte());
387
duration.setDotted(dottedNotes);
389
if ((header & 0x20) != 0) {
390
int tuplet = readInt();
391
//-------Verifico el tupleto--------------------
394
duration.getTupleto().setEnters(3);
395
duration.getTupleto().setTimes(2);
398
duration.getTupleto().setEnters(5);
399
duration.getTupleto().setTimes(4);
402
duration.getTupleto().setEnters(6);
403
duration.getTupleto().setTimes(4);
406
duration.getTupleto().setEnters(7);
407
duration.getTupleto().setTimes(4);
410
duration.getTupleto().setEnters(9);
411
duration.getTupleto().setTimes(8);
414
duration.getTupleto().setEnters(10);
415
duration.getTupleto().setTimes(8);
418
duration.getTupleto().setEnters(11);
419
duration.getTupleto().setTimes(8);
422
duration.getTupleto().setEnters(12);
423
duration.getTupleto().setTimes(8);
428
if ((header & 0x02) != 0) {
432
if ((header & 0x04) != 0) {
433
String text = readStringIntegerPlusOne();
436
if ((header & 0x08) != 0) {
437
readBeatEffects(effect);
440
if ((header & 0x10) != 0) {
441
readMixChange(tempo);
444
int stringsPlayed = readUnsignedByte();
445
List strings = getPlayedStrings(stringsPlayed, trackStrings);
447
for (int i = strings.size() - 1; i >= 0; i--) {
448
InstrumentString string = (InstrumentString) strings.get(i);
449
Note note = parseNote(start, string, duration, notes, currTrackMeasures,(NoteEffect)effect.clone());
455
return duration.getTime();
458
private Note parseNote(long start, InstrumentString string, Duration currDuration, List currMeasureNotes, List currTrackMeasures,NoteEffect effect) throws IOException {
459
int header = readUnsignedByte();
461
effect.setGhostNote(((header & 0x04) != 0));
462
boolean dotted = ((header & 0x02) != 0);
463
boolean tiedNote = false;
464
boolean deadNote = false;
465
if ((header & 0x20) != 0) {
466
int noteType = readUnsignedByte();
467
tiedNote = (noteType == 0x02);
468
effect.setDeadNote((noteType == 0x03));
471
if ((header & 0x01) != 0) {
472
byte duration = readByte();
473
byte tuplet = readByte();
476
int velocity = VelocityValues.DEFAULT;
477
if ((header & 0x10) != 0) {
478
velocity = (VelocityValues.MIN_VELOCITY + (VelocityValues.VELOCITY_INCREMENT * readByte())) - VelocityValues.VELOCITY_INCREMENT;
481
byte numberOfFret = 0;
482
if ((header & 0x20) != 0) {
483
numberOfFret = readByte();
486
if ((header & 0x80) != 0) {
487
byte fingeringLeftHand = readByte();
488
byte fingeringRightHand = readByte();
491
if ((header & 0x08) != 0) {
492
readNoteEffects(effect,currDuration);
495
int value = numberOfFret;
496
if (numberOfFret >= 0 || tiedNote) {
498
value = getTiedNoteValue(string.getNumber(), currMeasureNotes, currTrackMeasures);
501
return new Note(value, start,(Duration)currDuration.clone(),velocity,string.getNumber(),tiedNote,effect);
507
private String readStringByte(int expectedLength) throws IOException {
509
int realLength = readUnsignedByte();
511
if (expectedLength != 0) {
512
bytes = new byte[expectedLength];
514
bytes = new byte[realLength];
518
realLength = (realLength >= 0)?realLength:expectedLength;
519
return new String(bytes, 0, realLength);
522
private String readStringInteger() throws IOException {
525
int length = readInt();
527
b = new byte[length];
534
private String readStringIntegerPlusOne() throws IOException {
537
int lengthPlusOne = readInt();
538
int length = lengthPlusOne - 1;
540
if (lengthPlusOne > 0) {
543
throw new IOException();
546
b = new byte[length];
557
private SongTrack createTrack(int number, List channels, Lyric lyrics) throws IOException {
558
int header = readUnsignedByte();
560
boolean isDrumsTrack = ((header & 0x01) != 0);
561
boolean is12StringedGuitarTrack = ((header & 0x02) != 0);
562
boolean isBanjoTrack = ((header & 0x04) != 0);
564
String name = readStringByte(40);
566
int numberOfStrings = readInt();
568
List strings = new ArrayList(numberOfStrings);
570
for (int i = 0; i < 7; i++) {
571
int tunning = readInt();
572
if (numberOfStrings > i) {
573
strings.add(new InstrumentString(i + 1, tunning));
577
int port = readInt();
579
int channelIndex = readInt();
581
int effects = readInt();
583
int numberOfFrets = readInt();
585
int capo = readInt();
587
RGBColor color = readColor();
589
return new SongTrack(number,name,parseChannel(channels,channelIndex,effects),new ArrayList(), strings,capo,color,lyrics);
593
private SongChannel parseChannel(List channels, int channelIndex,int effectChannel) {
594
SongChannel channel = (SongChannel) channels.get(channelIndex - 1);
596
int instrument = channel.getInstrument();
597
if (instrument == -1) {
598
channel.setInstrument((short)0);
600
if(!channel.isPercusionChannel()){
601
channel.setEffectChannel((short)(effectChannel - 1));
607
private int readUnsignedByte() throws IOException {
611
private void readChordDiagram() throws IOException, GPFormatException {
612
int header = readUnsignedByte();
614
if ((header & 0x01) == 0) {
615
String name = readStringIntegerPlusOne();
616
int base = readInt();
619
for (int i = 0; i < 6; i++) {
620
int fret = readInt();
624
boolean sharp = readBoolean();
628
int root = readInt();
630
int chordType = readInt();
632
int nineElevenThirteen = readInt();
634
int bass = readInt();
636
int tonalityType = readUnsignedByte();
640
int addedNote = readUnsignedByte();
642
String name = readStringByte(34);
644
int baseFret = readInt();
646
for (int i = 0; i < 6; i++) {
647
int fret = readInt();
650
for (int i = 0; i < 28; i++) {
651
int n = readUnsignedByte();
654
for (int i = 0; i < 7; i++) {
658
int n = readUnsignedByte();
663
private void readGrace(NoteEffect effect) throws IOException {
664
int fret = readUnsignedByte();
665
int velocity = readUnsignedByte();
666
int transition = readUnsignedByte();
667
int duration = readUnsignedByte();
670
boolean dead = (fret == 255);
673
fret = ((!dead)?fret:0);
676
velocity = (VelocityValues.MIN_VELOCITY + (VelocityValues.VELOCITY_INCREMENT * velocity)) - VelocityValues.VELOCITY_INCREMENT;
680
transition = GraceEffect.TRANSITION_NONE;
682
else if(transition == 1){
683
transition = GraceEffect.TRANSITION_SLIDE;
685
else if(transition == 2){
686
transition = GraceEffect.TRANSITION_BEND;
688
else if(transition == 3){
689
transition = GraceEffect.TRANSITION_HAMMER;
692
effect.setGrace(new GraceEffect(fret,duration,velocity,transition,false,dead));
695
private void readGraceNote() throws IOException {
696
byte b[] = new byte[4];
701
private void readBend(NoteEffect effect,Duration duration) throws IOException {
702
byte type = readByte();
703
int value = readInt();
705
BendEffect bend = new BendEffect();
706
int numPoints = readInt();
707
for (int i = 0; i < numPoints; i++) {
709
int bendPosition = readInt();
710
int bendValue = readInt();
711
byte bendVibrato = readByte();
713
bend.addPoint((int)(bendPosition * BendEffect.MAX_POSITION_LENGTH / GP_BEND_POSITION),(bendValue * BendEffect.SEMITONE_LENGTH / GP_BEND_SEMITONE));
715
if(!bend.getPoints().isEmpty()){
716
effect.setBend(bend);
720
private void readTremoloBar(NoteEffect noteEffect) throws IOException {
721
int value = readInt();
722
TremoloBarEffect effect = new TremoloBarEffect();
723
effect.addPoint(0,0);
724
effect.addPoint( (TremoloBarEffect.MAX_POSITION_LENGTH / 2) ,-(value * TremoloBarEffect.SEMITONE_LENGTH / GP_BEND_SEMITONE));
725
effect.addPoint(TremoloBarEffect.MAX_POSITION_LENGTH,0);
726
noteEffect.setTremoloBar(effect);
729
private void readNoteEffects(NoteEffect effect,Duration duration) throws IOException {
732
header = readUnsignedByte();
734
if ((header & 0x01) != 0) {
735
readBend(effect,duration);
738
if ((header & 0x10) != 0) {
742
if ((header & 0x04) != 0) {
743
effect.setSlide(true);
746
if ((header & 0x08) != 0) {
749
if ((header & 0x02) != 0) {
750
effect.setHammer(true);
754
private void readBeatEffects(NoteEffect noteEffect) throws IOException {
755
int header = readUnsignedByte();
757
if ((header & 0x20) != 0) {
758
int effect = readUnsignedByte();
760
readTremoloBar(noteEffect);
762
noteEffect.setTapping(effect == 1);
763
noteEffect.setSlapping(effect == 2);
764
noteEffect.setPopping(effect == 3);
765
int dummy = readInt();
769
if ((header & 0x40) != 0) {
770
//Upstroke - Downstroke
775
if ((header & 0x04) != 0) {
777
noteEffect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_NATURAL));
780
if ((header & 0x08) != 0) {
781
//Harmonic Artificial
782
noteEffect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_ARTIFICIAL,0));
785
//Vibrato || Wide Vibrato
786
noteEffect.setVibrato(((header & 0x01) != 0) || ((header & 0x02) != 0));
789
noteEffect.setFadeIn(((header & 0x10) != 0));
792
private void readMixChange(Tempo tempo) throws IOException {
793
int pos[] = new int[8];
799
for (i = 0; i < 7; i++) {
801
if ((i != 0) && (aux != -1)) {
813
for (i = 0; i < n; i++) {
821
private short toChannelShort(byte b){
823
s = (short)((s * (short)127) / (short)16);
824
return (s <= 127)?s:127;
b'\\ No newline at end of file'