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;
30
import org.herac.tuxguitar.song.models.effects.TremoloPickingEffect;
31
import org.herac.tuxguitar.song.models.effects.TrillEffect;
33
public class GP4InputStream extends InputStream {
34
private static final String supportedVersions[] = { "FICHIER GUITAR PRO v4.00", "FICHIER GUITAR PRO v4.06", "FICHIER GUITAR PRO L4.06" };
35
private static final int GP_BEND_SEMITONE = 50;
36
private static final int GP_BEND_POSITION = 60;
38
private InputStream inputStream;
39
private String version;
40
private int tripletFeel;
44
public GP4InputStream(InputStream inputStream) {
46
this.inputStream = inputStream;
50
public GP4InputStream(String fileName) throws FileNotFoundException {
51
this(new FileInputStream(new File(fileName)));
54
public void close() throws IOException {
55
this.inputStream.close();
58
public int read() throws IOException {
60
return this.inputStream.read();
63
private void readVersion(){
65
if(this.version == null){
66
this.version = readStringByte(30);
68
} catch (IOException e) {
69
this.version = "NOT_SUPPORTED";
73
public static boolean isSupportedVersion(String version) {
74
for (int i = 0; i < supportedVersions.length; i++) {
75
if (version.equals(supportedVersions[i])) {
82
public boolean isSupportedVersion(){
85
return isSupportedVersion(version);
93
public Song readSong() throws IOException, GPFormatException {
95
if (!isSupportedVersion(version)) {
96
throw new GPFormatException("Unsuported Version");
99
String title = readStringIntegerPlusOne();
101
String subtitle = readStringIntegerPlusOne();
103
String interpret = readStringIntegerPlusOne();
105
String album = readStringIntegerPlusOne();
107
String songAuthor = readStringIntegerPlusOne();
109
String copyright = readStringIntegerPlusOne();
111
String pieceAuthor = readStringIntegerPlusOne();
113
String instructions = readStringIntegerPlusOne();
115
int nbNotes = readInt();
117
for (int i = 0; i < nbNotes; i++) {
118
note += readStringIntegerPlusOne();
122
//boolean tripletFeel = readBoolean();
123
this.tripletFeel = ((readBoolean())?MeasureHeader.TRIPLET_FEEL_EIGHTH:MeasureHeader.TRIPLET_FEEL_NONE);
127
int lyricTrack = readInt();
128
Lyric lyric = new Lyric(readInt(),readStringInteger());
129
for (int i = 0; i < 4; i++) {
130
int measureNumber = readInt();
131
String lines = readStringInteger();
135
int tempoValue = readInt();
137
int key = readByte();
139
int octave = readInt();
141
List channels = new ArrayList();
142
int[] instruments = new int[64];
143
for (int i = 0; i < 64; i++) {
144
channels.add(new SongChannel((short)i,
147
toChannelShort(readByte()),
148
toChannelShort(readByte()),
149
toChannelShort(readByte()),
150
toChannelShort(readByte()),
151
toChannelShort(readByte()),
152
toChannelShort(readByte()),
159
TimeSignature timeSignature = new TimeSignature(4, new Duration(4));
161
int numberOfMeasures = readInt();
162
int numberOfTracks = readInt();
164
List headers = new ArrayList();
165
if (numberOfMeasures > 0) {
166
for (int i = 0; i < numberOfMeasures; i++) {
167
MeasureHeader header = createMeasureHeader((i + 1),timeSignature);
172
List tracks = new ArrayList();
173
for (int number = 1; number <= numberOfTracks; number++) {
174
SongTrack track = createTrack(number, channels,(number == lyricTrack)?lyric:new Lyric());
178
long nextMeasureStart = 1000;
179
for (int i = 0; i < numberOfMeasures; i++) {
180
MeasureHeader currHeader = (MeasureHeader) headers.get(i);
181
Tempo tempo = new Tempo(tempoValue);
182
currHeader.setStart(nextMeasureStart);
183
for (int j = 0; j < numberOfTracks; j++) {
184
SongTrack track = (SongTrack) tracks.get(j);
185
Measure measure = new Measure(currHeader,new ArrayList(),new ArrayList(),1,0);
186
addMeasureComponents(track.getStrings(), measure, track.getMeasures(), tempo);
187
currHeader.setTempo(tempo);
188
track.getMeasures().add(measure);
190
tempoValue = tempo.getValue();
191
nextMeasureStart += currHeader.getLength();
194
return new Song(title,interpret,album,songAuthor,tracks,headers,Song.MAX_VOLUME);
197
private long addNotes(long start, List notes, List trackStrings, List currTrackMeasures, Tempo tempo) throws IOException,GPFormatException {
198
NoteEffect effect = new NoteEffect();
200
int header = readUnsignedByte();
202
if ((header & 0x40) != 0) {
203
int beatStatus = readUnsignedByte();
204
boolean emptyBeat = (beatStatus == 0x00);
205
boolean restBeat = (beatStatus == 0x02);
208
boolean dottedNotes = ((header & 0x01) != 0);
210
Duration duration = parseDuration(readByte());
211
duration.setDotted(dottedNotes);
213
if ((header & 0x20) != 0) {
214
int tuplet = readInt();
215
//-------Verifico el tupleto--------------------
218
duration.getTupleto().setEnters(3);
219
duration.getTupleto().setTimes(2);
222
duration.getTupleto().setEnters(5);
223
duration.getTupleto().setTimes(4);
226
duration.getTupleto().setEnters(6);
227
duration.getTupleto().setTimes(4);
230
duration.getTupleto().setEnters(7);
231
duration.getTupleto().setTimes(4);
234
duration.getTupleto().setEnters(9);
235
duration.getTupleto().setTimes(8);
238
duration.getTupleto().setEnters(10);
239
duration.getTupleto().setTimes(8);
242
duration.getTupleto().setEnters(11);
243
duration.getTupleto().setTimes(8);
246
duration.getTupleto().setEnters(12);
247
duration.getTupleto().setTimes(8);
252
if ((header & 0x02) != 0) {
256
if ((header & 0x04) != 0) {
257
String text = readStringIntegerPlusOne();
260
if ((header & 0x08) != 0) {
261
readBeatEffects(effect,duration);
264
if ((header & 0x10) != 0) {
265
readMixChange(tempo);
268
int stringsPlayed = readUnsignedByte();
269
List strings = getPlayedStrings(stringsPlayed, trackStrings);
271
for (int i = strings.size() - 1; i >= 0; i--) {
272
InstrumentString string = (InstrumentString) strings.get(i);
273
Note note = parseNote(start, string, duration, notes, currTrackMeasures,(NoteEffect)effect.clone());
279
return duration.getTime();
282
private List getPlayedStrings(int stringsPlayed, List trackStrings) {
283
List strings = new ArrayList();
284
if ((stringsPlayed & (1 << 0)) != 0 && trackStrings.size() > 6) {
285
strings.add(((InstrumentString) trackStrings.get(6)).clone());
287
if ((stringsPlayed & (1 << 1)) != 0 && trackStrings.size() > 5) {
288
strings.add(((InstrumentString) trackStrings.get(5)).clone());
290
if ((stringsPlayed & (1 << 2)) != 0 && trackStrings.size() > 4) {
291
strings.add(((InstrumentString) trackStrings.get(4)).clone());
293
if ((stringsPlayed & (1 << 3)) != 0 && trackStrings.size() > 3) {
294
strings.add(((InstrumentString) trackStrings.get(3)).clone());
296
if ((stringsPlayed & (1 << 4)) != 0 && trackStrings.size() > 2) {
297
strings.add(((InstrumentString) trackStrings.get(2)).clone());
299
if ((stringsPlayed & (1 << 5)) != 0 && trackStrings.size() > 1) {
300
strings.add(((InstrumentString) trackStrings.get(1)).clone());
302
if ((stringsPlayed & (1 << 6)) != 0 && trackStrings.size() > 0) {
303
strings.add(((InstrumentString) trackStrings.get(0)).clone());
308
private Duration parseDuration(byte value) {
309
Duration duration = null;
312
duration = new Duration(Duration.WHOLE);
315
duration = new Duration(Duration.HALF);
318
duration = new Duration(Duration.QUARTER);
321
duration = new Duration(Duration.EIGHTH);
324
duration = new Duration(Duration.SIXTEENTH);
327
duration = new Duration(Duration.THIRTY_SECOND);
330
duration = new Duration(Duration.SIXTY_FOURTH);
333
if(duration == null){
334
duration = new Duration(Duration.QUARTER);
335
System.err.println("Incorrect Duration. Forcing duration Quarter as Default.");
340
private int getTiedNoteValue(int string, List notes, List measures) {
341
if (!notes.isEmpty()) {
342
for (int nIdx = notes.size() - 1; nIdx >= 0; nIdx--) {
343
Note note = (Note) notes.get(nIdx);
344
if (note.getString() == string) {
345
return note.getValue();
349
if (!measures.isEmpty()) {
350
for (int mIdx = measures.size() - 1; mIdx >= 0; mIdx--) {
351
Measure measure = (Measure) measures.get(mIdx);
352
for (int nIdx = measure.getNotes().size() - 1; nIdx >= 0; nIdx--) {
353
Note note = (Note) measure.getNotes().get(nIdx);
354
if (note.getString() == string) {
355
return note.getValue();
363
private boolean readBoolean() throws IOException {
364
return (read() == 1);
367
private byte readByte() throws IOException {
368
return (byte) read();
371
private RGBColor readColor() throws IOException {
372
int r = readUnsignedByte();
373
int g = readUnsignedByte();
374
int b = readUnsignedByte();
377
return new RGBColor(r,g,b);
380
private int readInt() throws IOException {
382
byte[] b = { 0, 0, 0, 0 };
385
integer = ((b[3] & 0xff) << 24) | ((b[2] & 0xff) << 16) | ((b[1] & 0xff) << 8) | (b[0] & 0xff);
390
private Marker readMarker(int measure) throws IOException {
391
String name = readStringIntegerPlusOne();
392
RGBColor color = readColor();
394
return new Marker(measure,name,color);
397
private MeasureHeader createMeasureHeader(int number,TimeSignature currTimeSignature) throws IOException {
398
int header = readUnsignedByte();
401
if ((header & 0x01) != 0) {
402
numerator = readByte();
406
if ((header & 0x02) != 0) {
407
denominator = readByte();
410
boolean repeatStart = ((header & 0x04) != 0);
412
int numberOfRepetitions = 0;
413
if ((header & 0x08) != 0) {
414
numberOfRepetitions = readByte();
417
int NumberOfAlternateEnding = 0;
418
if ((header & 0x10) != 0) {
419
NumberOfAlternateEnding = readByte();
422
Marker marker = null;
423
if ((header & 0x20) != 0) {
424
marker = readMarker(number);
427
if ((header & 0x40) != 0) {
428
int type = readByte();
432
if ((header & 0x80) != 0) {
435
boolean doubleBar = ((header & 0x80) != 0);
438
currTimeSignature.setNumerator(numerator);
440
if (denominator > 0) {
441
currTimeSignature.setDenominator(new Duration(denominator));
444
return new MeasureHeader(number,0,(TimeSignature) currTimeSignature.clone(), new Tempo(120),marker,tripletFeel,repeatStart,numberOfRepetitions);
447
private void addMeasureComponents(List trackStrings, Measure measure, List currTrackMeasures, Tempo tempo) throws IOException,
449
long nextNoteStart = measure.getStart();
450
int numberOfBeats = readInt();
451
for (int i = 0; i < numberOfBeats; i++) {
452
nextNoteStart += addNotes(nextNoteStart, measure.getNotes(), trackStrings, currTrackMeasures, tempo);
457
private Note parseNote(long start, InstrumentString string, Duration currDuration, List currMeasureNotes, List currTrackMeasures,NoteEffect effect)
459
int header = readUnsignedByte();
461
//boolean accentuated = ((header & 0x40) != 0);
462
//boolean ghostNote = ((header & 0x04) != 0);
463
boolean dotted = ((header & 0x02) != 0);
465
effect.setAccentuatedNote(((header & 0x40) != 0));
466
effect.setGhostNote(((header & 0x04) != 0));
468
boolean tiedNote = false;
469
boolean deadNote = false;
470
if ((header & 0x20) != 0) {
471
int noteType = readUnsignedByte();
472
tiedNote = (noteType == 0x02);
473
effect.setDeadNote((noteType == 0x03));
476
if ((header & 0x01) != 0) {
477
byte duration = readByte();
478
byte tuplet = readByte();
481
int velocity = VelocityValues.DEFAULT;
482
if ((header & 0x10) != 0) {
483
velocity = (VelocityValues.MIN_VELOCITY + (VelocityValues.VELOCITY_INCREMENT * readByte())) - VelocityValues.VELOCITY_INCREMENT;
486
byte numberOfFret = 0;
487
if ((header & 0x20) != 0) {
488
numberOfFret = readByte();
491
if ((header & 0x80) != 0) {
492
byte fingeringLeftHand = readByte();
493
byte fingeringRightHand = readByte();
496
if ((header & 0x08) != 0) {
497
readNoteEffects(effect,currDuration);
500
int value = numberOfFret;
501
if (numberOfFret >= 0 || tiedNote) {
503
value = getTiedNoteValue(string.getNumber(), currMeasureNotes, currTrackMeasures);
506
return new Note(value, start, (Duration) currDuration.clone(), velocity, string.getNumber(),tiedNote,effect);
512
private String readStringByte(int expectedLength) throws IOException {
514
int realLength = readUnsignedByte();
516
if (expectedLength != 0) {
517
bytes = new byte[expectedLength];
519
bytes = new byte[realLength];
523
realLength = (realLength >= 0)?realLength:expectedLength;
524
return new String(bytes, 0, realLength);
527
private String readStringInteger() throws IOException {
530
int length = readInt();
532
b = new byte[length];
539
private String readStringIntegerPlusOne() throws IOException {
542
int lengthPlusOne = readInt();
543
int length = lengthPlusOne - 1;
545
if (length != read()) {
546
throw new IOException();
549
b = new byte[length];
556
private SongTrack createTrack(int number, List channels,Lyric lyrics) throws IOException {
557
int header = readUnsignedByte();
559
boolean isDrumsTrack = ((header & 0x01) != 0);
560
boolean is12StringedGuitarTrack = ((header & 0x02) != 0);
561
boolean isBanjoTrack = ((header & 0x04) != 0);
563
String name = readStringByte(40);
565
int numberOfStrings = readInt();
567
List strings = new ArrayList(numberOfStrings);
569
for (int i = 0; i < 7; i++) {
570
int tunning = readInt();
571
if (numberOfStrings > i) {
572
strings.add(new InstrumentString(i + 1, tunning));
576
int port = readInt();
578
int channelIndex = readInt();
580
int effects = readInt();
582
int numberOfFrets = readInt();
584
int capo = readInt();
586
RGBColor color = readColor();
588
return new SongTrack(number,name,parseChannel(channels,channelIndex,effects), new ArrayList(), strings,capo,color,lyrics);
591
private SongChannel parseChannel(List channels, int channelIndex,int effectChannel) {
592
SongChannel channel = (SongChannel) channels.get(channelIndex - 1);
594
int instrument = channel.getInstrument();
595
if (instrument == -1) {
596
channel.setInstrument((short)0);
598
if(!channel.isPercusionChannel()){
599
channel.setEffectChannel((short)(effectChannel - 1));
606
private int readUnsignedByte() throws IOException {
610
private void readChordType() throws IOException {
614
private void readRoot() throws IOException {
618
private void readTonalityType(int numBytes) throws IOException {
620
int type = readUnsignedByte();
621
} else if (numBytes == 4) {
622
int type = readInt();
626
private String readChordName() throws IOException {
632
nameB = new byte[21];
633
nameC = new char[20];
636
if (nameB[0] < max) {
640
for (i = 1; i <= max; i++) {
641
nameC[i - 1] = (char) nameB[i];
643
return (String.valueOf(nameC, 0, max));
646
private void readChordDiagram() throws IOException, GPFormatException {
647
int header = readUnsignedByte();
649
if ((header & 0x01) == 0) {
650
String name = readStringIntegerPlusOne();
651
int base = readInt();
654
for (int i = 0; i < 6; i++) {
655
int fret = readInt();
658
//new GPFormatException("Cannot Read Chord Diagram");
661
boolean sharp = readBoolean();
669
int nineElevenThirteen = readUnsignedByte();
671
int bass = readInt();
675
int addedNote = readUnsignedByte();
677
String name = readChordName();
687
int baseFret = readInt();
689
for (int i = 1; i <= 7; i++) {
690
int fret = readInt();
693
int numBarres = readUnsignedByte();
695
for (int i = 1; i <= 5; i++) {
696
int fretOfBarre = readUnsignedByte();
698
for (int i = 1; i <= 5; i++) {
699
int barreStart = readUnsignedByte();
701
for (int i = 1; i <= 5; i++) {
702
int barreEnd = readUnsignedByte();
707
for (int i = 1; i <= 7; i++) {
708
int fingering = readByte();
711
boolean chordFingeringDisplayed = readBoolean();
715
private void readGraceNote(NoteEffect effect) throws IOException {
716
int fret = readUnsignedByte();
717
int velocity = readUnsignedByte();
718
int transition = readUnsignedByte();
719
int duration = readUnsignedByte();
722
boolean dead = (fret == 255);
725
fret = ((!dead)?fret:0);
728
velocity = (VelocityValues.MIN_VELOCITY + (VelocityValues.VELOCITY_INCREMENT * velocity)) - VelocityValues.VELOCITY_INCREMENT;
732
transition = GraceEffect.TRANSITION_NONE;
734
else if(transition == 1){
735
transition = GraceEffect.TRANSITION_SLIDE;
737
else if(transition == 2){
738
transition = GraceEffect.TRANSITION_BEND;
740
else if(transition == 3){
741
transition = GraceEffect.TRANSITION_HAMMER;
744
effect.setGrace(new GraceEffect(fret,duration,velocity,transition,false,dead));
747
private void readBend(NoteEffect effect,Duration duration) throws IOException {
748
byte type = readByte();
749
int value = readInt();
751
BendEffect bend = new BendEffect();
752
int numPoints = readInt();
753
for (int i = 0; i < numPoints; i++) {
754
int bendPosition = readInt();
755
int bendValue = readInt();
756
byte bendVibrato = readByte();
758
bend.addPoint((int)(bendPosition * BendEffect.MAX_POSITION_LENGTH / GP_BEND_POSITION),(bendValue * BendEffect.SEMITONE_LENGTH / GP_BEND_SEMITONE));
760
if(!bend.getPoints().isEmpty()){
761
effect.setBend(bend);
765
private void readTremoloBar(NoteEffect effect,Duration duration) throws IOException {
766
byte type = readByte();
767
int value = readInt();
769
TremoloBarEffect tremoloBar = new TremoloBarEffect();
770
int numPoints = readInt();
771
for (int i = 0; i < numPoints; i++) {
772
int bendPosition = readInt();
773
int bendValue = readInt();
774
byte bendVibrato = readByte();
776
tremoloBar.addPoint((int)(bendPosition * TremoloBarEffect.MAX_POSITION_LENGTH / GP_BEND_POSITION),(bendValue * TremoloBarEffect.SEMITONE_LENGTH / GP_BEND_SEMITONE));
778
if(!tremoloBar.getPoints().isEmpty()){
779
effect.setTremoloBar(tremoloBar);
783
public void readTremoloPicking(NoteEffect effect) throws IOException{
784
int duration = readUnsignedByte();
786
effect.setTremoloPicking(new TremoloPickingEffect(new Duration(Duration.EIGHTH)));
787
}else if(duration == 2){
788
effect.setTremoloPicking(new TremoloPickingEffect(new Duration(Duration.SIXTEENTH)));
789
}else if(duration == 3){
790
effect.setTremoloPicking(new TremoloPickingEffect(new Duration(Duration.THIRTY_SECOND)));
794
private void readNoteEffects(NoteEffect noteEffect,Duration duration) throws IOException {
799
header1 = readUnsignedByte();
800
header2 = readUnsignedByte();
802
if ((header1 & 0x01) != 0) {
803
readBend(noteEffect,duration);
806
if ((header1 & 0x10) != 0) {
807
readGraceNote(noteEffect);
810
if ((header2 & 0x04) != 0) {
811
readTremoloPicking(noteEffect);
814
if ((header2 & 0x08) != 0) {
815
noteEffect.setSlide(true);
819
if ((header2 & 0x10) != 0) {
822
noteEffect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_NATURAL));
824
noteEffect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_TAPPED));
826
noteEffect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_PINCH));
828
noteEffect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_SEMI));
830
noteEffect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_ARTIFICIAL,19));
832
noteEffect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_ARTIFICIAL,24));
834
noteEffect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_ARTIFICIAL,12));
839
if ((header2 & 0x20) != 0) {
840
byte fret = readByte();
841
byte period = readByte();
843
noteEffect.setTrill(new TrillEffect(fret,new Duration(Duration.SIXTEENTH)));
844
}else if(period == 2){
845
noteEffect.setTrill(new TrillEffect(fret,new Duration(Duration.THIRTY_SECOND)));
846
}else if(period == 3){
847
noteEffect.setTrill(new TrillEffect(fret,new Duration(Duration.SIXTY_FOURTH)));
851
if ((header1 & 0x08) != 0) {
855
noteEffect.setHammer(((header1 & 0x02) != 0));
858
noteEffect.setVibrato(((header2 & 0x40) != 0) || noteEffect.isVibrato());
861
noteEffect.setPalmMute(((header2 & 0x02) != 0));
864
noteEffect.setStaccato(((header2 & 0x01) != 0));
868
private void readBeatEffects(NoteEffect noteEffect,Duration currDuration) throws IOException {
869
int header[] = { 0, 0 };
871
header[0] = readUnsignedByte();
872
header[1] = readUnsignedByte();
874
noteEffect.setFadeIn(((header[0] & 0x10) != 0));
875
noteEffect.setVibrato(((header[0] & 0x02) != 0));
877
if ((header[0] & 0x20) != 0) {
878
int effect = readUnsignedByte();
879
noteEffect.setTapping(effect == 1);
880
noteEffect.setSlapping(effect == 2);
881
noteEffect.setPopping(effect == 3);
884
if ((header[1] & 0x04) != 0) {
885
readTremoloBar(noteEffect,currDuration);
888
if ((header[0] & 0x40) != 0) {
889
//Upstroke - Downstroke
894
if ((header[1] & 0x01) != 0) {
898
if ((header[1] & 0x02) != 0) {
906
private void readMixChange(Tempo tempo) throws IOException {
907
int pos[] = new int[8];
912
for (i = 0; i < 7; i++) {
914
if ((i != 0) && (aux != -1)) {
926
for (i = 0; i < n; i++) {
929
int applyToAllTracks = readUnsignedByte();
932
private short toChannelShort(byte b){
934
s = (short)((s * (short)127) / (short)16);
935
return (s <= 127)?s:127;