1
package org.herac.tuxguitar.io.gtp;
3
import java.io.IOException;
4
import java.util.ArrayList;
5
import java.util.Iterator;
8
import org.herac.tuxguitar.io.base.TGFileFormat;
9
import org.herac.tuxguitar.io.base.TGInputStreamBase;
10
import org.herac.tuxguitar.song.models.TGBeat;
11
import org.herac.tuxguitar.song.models.TGChannel;
12
import org.herac.tuxguitar.song.models.TGChord;
13
import org.herac.tuxguitar.song.models.TGColor;
14
import org.herac.tuxguitar.song.models.TGDuration;
15
import org.herac.tuxguitar.song.models.TGLyric;
16
import org.herac.tuxguitar.song.models.TGMarker;
17
import org.herac.tuxguitar.song.models.TGMeasure;
18
import org.herac.tuxguitar.song.models.TGMeasureHeader;
19
import org.herac.tuxguitar.song.models.TGNote;
20
import org.herac.tuxguitar.song.models.TGNoteEffect;
21
import org.herac.tuxguitar.song.models.TGSong;
22
import org.herac.tuxguitar.song.models.TGString;
23
import org.herac.tuxguitar.song.models.TGTempo;
24
import org.herac.tuxguitar.song.models.TGText;
25
import org.herac.tuxguitar.song.models.TGTimeSignature;
26
import org.herac.tuxguitar.song.models.TGTrack;
27
import org.herac.tuxguitar.song.models.TGVelocities;
28
import org.herac.tuxguitar.song.models.effects.TGEffectBend;
29
import org.herac.tuxguitar.song.models.effects.TGEffectGrace;
30
import org.herac.tuxguitar.song.models.effects.TGEffectHarmonic;
31
import org.herac.tuxguitar.song.models.effects.TGEffectTremoloBar;
32
import org.herac.tuxguitar.song.models.effects.TGEffectTremoloPicking;
33
import org.herac.tuxguitar.song.models.effects.TGEffectTrill;
35
public class GP4InputStream extends GTPInputStream implements TGInputStreamBase {
36
private static final String SUPPORTED_VERSIONS[] = { "FICHIER GUITAR PRO v4.00", "FICHIER GUITAR PRO v4.06", "FICHIER GUITAR PRO L4.06" };
37
private static final float GP_BEND_SEMITONE = 25f;
38
private static final float GP_BEND_POSITION = 60f;
40
private int tripletFeel;
42
public GP4InputStream(){
43
super(SUPPORTED_VERSIONS);
46
public TGFileFormat getFileFormat(){
47
return new TGFileFormat("Guitar Pro 4","*.gp4");
50
public TGSong readSong() throws IOException, GTPFormatException {
52
if (!isSupportedVersion(getVersion())) {
54
throw new GTPFormatException("Unsuported Version");
56
TGSong song = getFactory().newSong();
60
this.tripletFeel = ((readBoolean())?TGMeasureHeader.TRIPLET_FEEL_EIGHTH:TGMeasureHeader.TRIPLET_FEEL_NONE);
62
int lyricTrack = readInt();
63
TGLyric lyric = readLyrics();
65
int tempoValue = readInt();
71
List channels = readChannels();
73
int measures = readInt();
74
int tracks = readInt();
76
readMeasureHeaders(song, measures);
77
readTracks(song, tracks, channels, lyric, lyricTrack);
78
readMeasures(song, measures, tracks, tempoValue);
85
private void readInfo(TGSong song) throws IOException{
86
song.setName(readStringByteSizeOfInteger());
87
readStringByteSizeOfInteger();
88
song.setArtist(readStringByteSizeOfInteger());
89
song.setAlbum(readStringByteSizeOfInteger());
90
song.setAuthor(readStringByteSizeOfInteger());
91
readStringByteSizeOfInteger();
92
readStringByteSizeOfInteger();
93
readStringByteSizeOfInteger();
94
int notes = readInt();
95
for (int i = 0; i < notes; i++) {
96
readStringByteSizeOfInteger();
100
private void readMeasureHeaders(TGSong song, int count) throws IOException{
101
TGTimeSignature timeSignature = getFactory().newTimeSignature();
102
for (int i = 0; i < count; i++) {
103
song.addMeasureHeader(readMeasureHeader((i + 1),song,timeSignature));
107
private void readTracks(TGSong song, int count, List channels,TGLyric lyric, int lyricTrack) throws IOException{
108
for (int number = 1; number <= count; number++) {
109
song.addTrack(readTrack(number, channels,(number == lyricTrack)?lyric:getFactory().newLyric()));
113
private void readMeasures(TGSong song, int measures, int tracks, int tempoValue) throws IOException{
114
TGTempo tempo = getFactory().newTempo();
115
tempo.setValue(tempoValue);
116
long start = TGDuration.QUARTER_TIME;
117
for (int i = 0; i < measures; i++) {
118
TGMeasureHeader header = song.getMeasureHeader(i);
119
header.setStart(start);
120
for (int j = 0; j < tracks; j++) {
121
TGTrack track = song.getTrack(j);
122
TGMeasure measure = getFactory().newMeasure(header);
123
track.addMeasure(measure);
124
readMeasure(measure, track, tempo);
126
tempo.copy(header.getTempo());
127
start += header.getLength();
131
private TGLyric readLyrics() throws IOException{
132
TGLyric lyric = getFactory().newLyric();
133
lyric.setFrom(readInt());
134
lyric.setLyrics(readStringInteger());
135
for (int i = 0; i < 4; i++) {
142
private List readChannels() throws IOException{
143
List channels = new ArrayList();
144
for (int i = 0; i < 64; i++) {
145
TGChannel channel = getFactory().newChannel();
146
channel.setChannel((short)i);
147
channel.setEffectChannel((short)i);
148
channel.setInstrument((short)readInt());
149
channel.setVolume(toChannelShort(readByte()));
150
channel.setBalance(toChannelShort(readByte()));
151
channel.setChorus(toChannelShort(readByte()));
152
channel.setReverb(toChannelShort(readByte()));
153
channel.setPhaser(toChannelShort(readByte()));
154
channel.setTremolo(toChannelShort(readByte()));
155
channel.setSolo(false);
156
channel.setMute(false);
157
channels.add(channel);
163
private long readBeat(long start, TGMeasure measure,TGTrack track, TGTempo tempo) throws IOException {
164
int flags = readUnsignedByte();
165
if((flags & 0x40) != 0){
169
TGBeat beat = getFactory().newBeat();
170
TGDuration duration = readDuration(flags);
171
TGNoteEffect effect = getFactory().newEffect();
172
if ((flags & 0x02) != 0) {
173
readChord(track.stringCount(), beat);
175
if ((flags & 0x04) != 0) {
178
if ((flags & 0x08) != 0) {
179
readBeatEffects(effect);
181
if ((flags & 0x10) != 0) {
182
readMixChange(tempo);
184
int stringFlags = readUnsignedByte();
185
for (int i = 6; i >= 0; i--) {
186
if ((stringFlags & (1 << i)) != 0 && (6 - i) < track.stringCount()) {
187
TGString string = track.getString( (6 - i) + 1 ).clone(getFactory());
188
TGNote note = readNote(string, track,effect.clone(getFactory()));
192
beat.setStart(start);
193
duration.copy(beat.getDuration());
194
measure.addBeat(beat);
196
return duration.getTime();
199
private void readText(TGBeat beat) throws IOException{
200
TGText text = getFactory().newText();
201
text.setValue(readStringByteSizeOfInteger());
205
private TGDuration readDuration(int flags) throws IOException {
206
TGDuration duration = getFactory().newDuration();
207
duration.setValue( (int) (Math.pow( 2 , (readByte() + 4) ) / 4 ) );
208
duration.setDotted(((flags & 0x01) != 0));
209
if ((flags & 0x20) != 0) {
210
int tuplet = readInt();
213
duration.getTupleto().setEnters(3);
214
duration.getTupleto().setTimes(2);
217
duration.getTupleto().setEnters(5);
218
duration.getTupleto().setTimes(4);
221
duration.getTupleto().setEnters(6);
222
duration.getTupleto().setTimes(4);
225
duration.getTupleto().setEnters(7);
226
duration.getTupleto().setTimes(4);
229
duration.getTupleto().setEnters(9);
230
duration.getTupleto().setTimes(8);
233
duration.getTupleto().setEnters(10);
234
duration.getTupleto().setTimes(8);
237
duration.getTupleto().setEnters(11);
238
duration.getTupleto().setTimes(8);
241
duration.getTupleto().setEnters(12);
242
duration.getTupleto().setTimes(8);
249
private int getTiedNoteValue(int string, TGTrack track) {
250
int measureCount = track.countMeasures();
251
if (measureCount > 0) {
252
for (int m = measureCount - 1; m >= 0; m--) {
253
TGMeasure measure = track.getMeasure( m );
254
for (int b = measure.countBeats() - 1; b >= 0; b--) {
255
TGBeat beat = measure.getBeat( b );
256
for (int n = 0; n < beat.countNotes(); n ++) {
257
TGNote note = beat.getNote( n );
258
if (note.getString() == string) {
259
return note.getValue();
268
private void readColor(TGColor color) throws IOException {
269
color.setR(readUnsignedByte());
270
color.setG(readUnsignedByte());
271
color.setB(readUnsignedByte());
275
private TGMarker readMarker(int measure) throws IOException {
276
TGMarker marker = getFactory().newMarker();
277
marker.setMeasure(measure);
278
marker.setTitle(readStringByteSizeOfInteger());
279
readColor(marker.getColor());
283
private TGMeasureHeader readMeasureHeader(int number,TGSong song,TGTimeSignature timeSignature) throws IOException {
284
int flags = readUnsignedByte();
285
TGMeasureHeader header = getFactory().newHeader();
286
header.setNumber(number);
288
header.getTempo().setValue(120);
289
header.setTripletFeel(this.tripletFeel);
290
header.setRepeatOpen( ((flags & 0x04) != 0) );
291
if ((flags & 0x01) != 0) {
292
timeSignature.setNumerator(readByte());
294
if ((flags & 0x02) != 0) {
295
timeSignature.getDenominator().setValue(readByte());
297
timeSignature.copy(header.getTimeSignature());
298
if ((flags & 0x08) != 0) {
299
header.setRepeatClose(readByte());
301
if ((flags & 0x10) != 0) {
302
header.setRepeatAlternative(parseRepeatAlternative(song, number, readUnsignedByte()));
304
if ((flags & 0x20) != 0) {
305
header.setMarker(readMarker(number));
307
if ((flags & 0x40) != 0) {
314
private void readMeasure(TGMeasure measure,TGTrack track, TGTempo tempo) throws IOException{
315
long nextNoteStart = measure.getStart();
316
int numberOfBeats = readInt();
317
for (int i = 0; i < numberOfBeats; i++) {
318
nextNoteStart += readBeat(nextNoteStart, measure, track, tempo);
322
private TGNote readNote(TGString string, TGTrack track,TGNoteEffect effect)throws IOException {
323
int flags = readUnsignedByte();
324
TGNote note = getFactory().newNote();
325
note.setString(string.getNumber());
326
note.setEffect(effect);
327
note.getEffect().setAccentuatedNote(((flags & 0x40) != 0));
328
note.getEffect().setGhostNote(((flags & 0x04) != 0));
329
if ((flags & 0x20) != 0) {
330
int noteType = readUnsignedByte();
331
note.setTiedNote( (noteType == 0x02) );
332
note.getEffect().setDeadNote((noteType == 0x03));
334
if ((flags & 0x01) != 0) {
337
if ((flags & 0x10) != 0) {
338
note.setVelocity((TGVelocities.MIN_VELOCITY + (TGVelocities.VELOCITY_INCREMENT * readByte())) - TGVelocities.VELOCITY_INCREMENT);
340
if ((flags & 0x20) != 0) {
341
int fret = readByte();
342
int value = ( note.isTiedNote() ? getTiedNoteValue(string.getNumber(), track) : fret );
343
note.setValue( value >= 0 && value < 100 ? value : 0 );
345
if ((flags & 0x80) != 0) {
348
if ((flags & 0x08) != 0) {
349
readNoteEffects(note.getEffect());
354
private TGTrack readTrack(int number, List channels,TGLyric lyrics) throws IOException {
355
TGTrack track = getFactory().newTrack();
356
track.setNumber(number);
357
track.setLyrics(lyrics);
359
track.setName(readStringByte(40));
360
int stringCount = readInt();
361
for (int i = 0; i < 7; i++) {
362
int tuning = readInt();
363
if (stringCount > i) {
364
TGString string = getFactory().newString();
365
string.setNumber(i + 1);
366
string.setValue(tuning);
367
track.getStrings().add(string);
371
readChannel(track.getChannel(), channels);
373
track.setOffset(readInt());
374
readColor(track.getColor());
378
private void readChannel(TGChannel channel,List channels) throws IOException {
379
int index = (readInt() - 1);
380
int effectChannel = (readInt() - 1);
381
if(index >= 0 && index < channels.size()){
382
((TGChannel) channels.get(index)).copy(channel);
383
if (channel.getInstrument() < 0) {
384
channel.setInstrument((short)0);
386
if(!channel.isPercussionChannel()){
387
channel.setEffectChannel((short)effectChannel);
392
private int parseRepeatAlternative(TGSong song,int measure,int value){
393
int repeatAlternative = 0;
394
int existentAlternatives = 0;
395
Iterator it = song.getMeasureHeaders();
397
TGMeasureHeader header = (TGMeasureHeader)it.next();
398
if(header.getNumber() == measure){
401
if(header.isRepeatOpen()){
402
existentAlternatives = 0;
404
existentAlternatives |= header.getRepeatAlternative();
407
for(int i = 0; i < 8; i ++){
408
if(value > i && (existentAlternatives & (1 << i)) == 0){
409
repeatAlternative |= (1 << i);
412
return repeatAlternative;
415
private void readChord(int strings,TGBeat beat) throws IOException {
416
TGChord chord = getFactory().newChord(strings);
417
if ((readUnsignedByte() & 0x01) == 0) {
418
chord.setName( readStringByteSizeOfInteger() );
419
chord.setFirstFret(readInt());
420
if(chord.getFirstFret() != 0){
421
for (int i = 0; i < 6; i++) {
422
int fret = readInt();
423
if(i < chord.countStrings()){
424
chord.addFretValue(i,fret);
431
chord.setName(readStringByte(21));
433
chord.setFirstFret(readInt());
434
for (int i = 0; i < 7; i++) {
435
int fret = readInt();
436
if(i < chord.countStrings()){
437
chord.addFretValue(i,fret);
442
if(chord.countNotes() > 0){
443
beat.setChord(chord);
447
private void readGrace(TGNoteEffect effect) throws IOException {
448
int fret = readUnsignedByte();
449
TGEffectGrace grace = getFactory().newEffectGrace();
450
grace.setOnBeat(false);
451
grace.setDead( (fret == 255) );
452
grace.setFret( ((!grace.isDead())?fret:0) );
453
grace.setDynamic( (TGVelocities.MIN_VELOCITY + (TGVelocities.VELOCITY_INCREMENT * readUnsignedByte())) - TGVelocities.VELOCITY_INCREMENT );
454
int transition = readUnsignedByte();
456
grace.setTransition( TGEffectGrace.TRANSITION_NONE );
458
else if(transition == 1){
459
grace.setTransition( TGEffectGrace.TRANSITION_SLIDE );
461
else if(transition == 2){
462
grace.setTransition( TGEffectGrace.TRANSITION_BEND );
464
else if(transition == 3){
465
grace.setTransition( TGEffectGrace.TRANSITION_HAMMER );
467
grace.setDuration(readUnsignedByte());
468
effect.setGrace(grace);
471
private void readBend(TGNoteEffect effect) throws IOException {
472
TGEffectBend bend = getFactory().newEffectBend();
474
int points = readInt();
475
for (int i = 0; i < points; i++) {
476
int position = readInt();
477
int value = readInt();
480
int pointPosition = Math.round(position * TGEffectBend.MAX_POSITION_LENGTH / GP_BEND_POSITION);
481
int pointValue = Math.round(value * TGEffectBend.SEMITONE_LENGTH / GP_BEND_SEMITONE);
482
bend.addPoint(pointPosition,pointValue);
484
if(!bend.getPoints().isEmpty()){
485
effect.setBend(bend);
489
private void readTremoloBar(TGNoteEffect effect) throws IOException {
490
TGEffectTremoloBar tremoloBar = getFactory().newEffectTremoloBar();
492
int points = readInt();
493
for (int i = 0; i < points; i++) {
494
int position = readInt();
495
int value = readInt();
498
int pointPosition = Math.round(position * TGEffectTremoloBar.MAX_POSITION_LENGTH / GP_BEND_POSITION);
499
int pointValue = Math.round(value / (GP_BEND_SEMITONE * 2f));
500
tremoloBar.addPoint(pointPosition,pointValue);
502
if(!tremoloBar.getPoints().isEmpty()){
503
effect.setTremoloBar(tremoloBar);
507
public void readTremoloPicking(TGNoteEffect effect) throws IOException{
508
int value = readUnsignedByte();
509
TGEffectTremoloPicking tp = getFactory().newEffectTremoloPicking();
511
tp.getDuration().setValue(TGDuration.EIGHTH);
512
effect.setTremoloPicking(tp);
513
}else if(value == 2){
514
tp.getDuration().setValue(TGDuration.SIXTEENTH);
515
effect.setTremoloPicking(tp);
516
}else if(value == 3){
517
tp.getDuration().setValue(TGDuration.THIRTY_SECOND);
518
effect.setTremoloPicking(tp);
522
private void readNoteEffects(TGNoteEffect noteEffect) throws IOException {
523
int flags1 = readUnsignedByte();
524
int flags2 = readUnsignedByte();
525
noteEffect.setHammer(((flags1 & 0x02) != 0));
526
noteEffect.setVibrato(((flags2 & 0x40) != 0) || noteEffect.isVibrato());
527
noteEffect.setPalmMute(((flags2 & 0x02) != 0));
528
noteEffect.setStaccato(((flags2 & 0x01) != 0));
529
if ((flags1 & 0x01) != 0) {
530
readBend(noteEffect);
532
if ((flags1 & 0x10) != 0) {
533
readGrace(noteEffect);
535
if ((flags2 & 0x04) != 0) {
536
readTremoloPicking(noteEffect);
538
if ((flags2 & 0x08) != 0) {
539
noteEffect.setSlide(true);
542
if ((flags2 & 0x10) != 0) {
543
TGEffectHarmonic harmonic = getFactory().newEffectHarmonic();
544
int type = readByte();
546
harmonic.setType(TGEffectHarmonic.TYPE_NATURAL);
548
harmonic.setType(TGEffectHarmonic.TYPE_TAPPED);
550
harmonic.setType(TGEffectHarmonic.TYPE_PINCH);
552
harmonic.setType(TGEffectHarmonic.TYPE_SEMI);
553
}else if(type == 15){
554
harmonic.setType(TGEffectHarmonic.TYPE_ARTIFICIAL);
556
}else if(type == 17){
557
harmonic.setType(TGEffectHarmonic.TYPE_ARTIFICIAL);
559
}else if(type == 22){
560
harmonic.setType(TGEffectHarmonic.TYPE_ARTIFICIAL);
563
noteEffect.setHarmonic(harmonic);
565
if ((flags2 & 0x20) != 0) {
566
byte fret = readByte();
567
byte period = readByte();
568
TGEffectTrill trill = getFactory().newEffectTrill();
571
trill.getDuration().setValue(TGDuration.SIXTEENTH);
572
noteEffect.setTrill(trill);
573
}else if(period == 2){
574
trill.getDuration().setValue(TGDuration.THIRTY_SECOND);
575
noteEffect.setTrill(trill);
576
}else if(period == 3){
577
trill.getDuration().setValue(TGDuration.SIXTY_FOURTH);
578
noteEffect.setTrill(trill);
583
private void readBeatEffects(TGNoteEffect noteEffect) throws IOException {
584
int flags1 = readUnsignedByte();
585
int flags2 = readUnsignedByte();
586
noteEffect.setFadeIn(((flags1 & 0x10) != 0));
587
noteEffect.setVibrato(((flags1 & 0x02) != 0));
588
if ((flags1 & 0x20) != 0) {
589
int effect = readUnsignedByte();
590
noteEffect.setTapping(effect == 1);
591
noteEffect.setSlapping(effect == 2);
592
noteEffect.setPopping(effect == 3);
594
if ((flags2 & 0x04) != 0) {
595
readTremoloBar(noteEffect);
597
if ((flags1 & 0x40) != 0) {
601
if ((flags2 & 0x02) != 0) {
606
private void readMixChange(TGTempo tempo) throws IOException {
608
int volume = readByte();
609
int pan = readByte();
610
int chorus = readByte();
611
int reverb = readByte();
612
int phaser = readByte();
613
int tremolo = readByte();
614
int tempoValue = readInt();
634
tempo.setValue(tempoValue);
640
private short toChannelShort(byte b){
641
short value = (short)(( b * 8 ) - 1);
642
return (short)Math.max(value,0);