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.TGMarker;
16
import org.herac.tuxguitar.song.models.TGMeasure;
17
import org.herac.tuxguitar.song.models.TGMeasureHeader;
18
import org.herac.tuxguitar.song.models.TGNote;
19
import org.herac.tuxguitar.song.models.TGNoteEffect;
20
import org.herac.tuxguitar.song.models.TGSong;
21
import org.herac.tuxguitar.song.models.TGString;
22
import org.herac.tuxguitar.song.models.TGTempo;
23
import org.herac.tuxguitar.song.models.TGText;
24
import org.herac.tuxguitar.song.models.TGTimeSignature;
25
import org.herac.tuxguitar.song.models.TGTrack;
26
import org.herac.tuxguitar.song.models.TGVelocities;
27
import org.herac.tuxguitar.song.models.effects.TGEffectBend;
28
import org.herac.tuxguitar.song.models.effects.TGEffectGrace;
29
import org.herac.tuxguitar.song.models.effects.TGEffectHarmonic;
30
import org.herac.tuxguitar.song.models.effects.TGEffectTremoloBar;
35
* TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
37
public class GP3InputStream extends GTPInputStream implements TGInputStreamBase {
38
private static final String SUPPORTED_VERSIONS[] = new String[]{ "FICHIER GUITAR PRO v3.00" };
39
private static final float GP_BEND_SEMITONE = 25f;
40
private static final float GP_BEND_POSITION = 60f;
42
private int tripletFeel;
44
public GP3InputStream(){
45
super(SUPPORTED_VERSIONS);
48
public TGFileFormat getFileFormat(){
49
return new TGFileFormat("Guitar Pro 3","*.gp3");
52
public TGSong readSong() throws GTPFormatException, IOException {
54
if (!isSupportedVersion(getVersion())) {
56
throw new GTPFormatException("Unsuported Version");
58
TGSong song = getFactory().newSong();
62
this.tripletFeel = ((readBoolean())?TGMeasureHeader.TRIPLET_FEEL_EIGHTH:TGMeasureHeader.TRIPLET_FEEL_NONE);
64
int tempoValue = readInt();
68
List channels = readChannels();
70
int measures = readInt();
71
int tracks = readInt();
73
readMeasureHeaders(song, measures);
74
readTracks(song, tracks, channels);
75
readMeasures(song, measures, tracks, tempoValue);
82
private List readChannels() throws IOException{
83
List channels = new ArrayList();
84
for (int i = 0; i < 64; i++) {
85
TGChannel channel = getFactory().newChannel();
86
channel.setChannel((short)i);
87
channel.setEffectChannel((short)i);
88
channel.setInstrument((short)readInt());
89
channel.setVolume(toChannelShort(readByte()));
90
channel.setBalance(toChannelShort(readByte()));
91
channel.setChorus(toChannelShort(readByte()));
92
channel.setReverb(toChannelShort(readByte()));
93
channel.setPhaser(toChannelShort(readByte()));
94
channel.setTremolo(toChannelShort(readByte()));
95
channel.setSolo(false);
96
channel.setMute(false);
97
channels.add(channel);
103
private void readInfo(TGSong song) throws IOException{
104
song.setName(readStringByteSizeOfInteger());
105
readStringByteSizeOfInteger();
106
song.setArtist(readStringByteSizeOfInteger());
107
song.setAlbum(readStringByteSizeOfInteger());
108
song.setAuthor(readStringByteSizeOfInteger());
109
readStringByteSizeOfInteger();
110
readStringByteSizeOfInteger();
111
readStringByteSizeOfInteger();
112
int notes = readInt();
113
for (int i = 0; i < notes; i++) {
114
readStringByteSizeOfInteger();
118
private void readMeasureHeaders(TGSong song, int count) throws IOException{
119
TGTimeSignature timeSignature = getFactory().newTimeSignature();
120
for (int i = 0; i < count; i++) {
121
song.addMeasureHeader(readMeasureHeader((i + 1),song,timeSignature));
125
private void readTracks(TGSong song, int count, List channels) throws IOException{
126
for (int number = 1; number <= count; number++) {
127
song.addTrack(readTrack(number, channels));
131
private void readMeasures(TGSong song, int measures, int tracks, int tempoValue) throws IOException{
132
TGTempo tempo = getFactory().newTempo();
133
tempo.setValue(tempoValue);
134
long start = TGDuration.QUARTER_TIME;
135
for (int i = 0; i < measures; i++) {
136
TGMeasureHeader header = song.getMeasureHeader(i);
137
header.setStart(start);
138
for (int j = 0; j < tracks; j++) {
139
TGTrack track = song.getTrack(j);
140
TGMeasure measure = getFactory().newMeasure(header);
141
track.addMeasure(measure);
142
readMeasure(measure, track, tempo);
144
tempo.copy(header.getTempo());
145
start += header.getLength();
149
private TGDuration readDuration(int flags) throws IOException {
150
TGDuration duration = getFactory().newDuration();
151
duration.setValue( (int) (Math.pow( 2 , (readByte() + 4) ) / 4 ) );
152
duration.setDotted(((flags & 0x01) != 0));
153
if ((flags & 0x20) != 0) {
154
int tuplet = readInt();
157
duration.getTupleto().setEnters(3);
158
duration.getTupleto().setTimes(2);
161
duration.getTupleto().setEnters(5);
162
duration.getTupleto().setTimes(4);
165
duration.getTupleto().setEnters(6);
166
duration.getTupleto().setTimes(4);
169
duration.getTupleto().setEnters(7);
170
duration.getTupleto().setTimes(4);
173
duration.getTupleto().setEnters(9);
174
duration.getTupleto().setTimes(8);
177
duration.getTupleto().setEnters(10);
178
duration.getTupleto().setTimes(8);
181
duration.getTupleto().setEnters(11);
182
duration.getTupleto().setTimes(8);
185
duration.getTupleto().setEnters(12);
186
duration.getTupleto().setTimes(8);
193
private int getTiedNoteValue(int string, TGTrack track) {
194
int measureCount = track.countMeasures();
195
if (measureCount > 0) {
196
for (int m = measureCount - 1; m >= 0; m--) {
197
TGMeasure measure = track.getMeasure( m );
198
for (int b = measure.countBeats() - 1; b >= 0; b--) {
199
TGBeat beat = measure.getBeat( b );
200
for (int n = 0; n < beat.countNotes(); n ++) {
201
TGNote note = beat.getNote( n );
202
if (note.getString() == string) {
203
return note.getValue();
212
private void readColor(TGColor color) throws IOException {
213
color.setR(readUnsignedByte());
214
color.setG(readUnsignedByte());
215
color.setB(readUnsignedByte());
219
private TGMarker readMarker(int measure) throws IOException {
220
TGMarker marker = getFactory().newMarker();
221
marker.setMeasure(measure);
222
marker.setTitle(readStringByteSizeOfInteger());
223
readColor(marker.getColor());
227
private TGMeasureHeader readMeasureHeader(int number,TGSong song,TGTimeSignature timeSignature) throws IOException {
228
int flags = readUnsignedByte();
229
TGMeasureHeader header = getFactory().newHeader();
230
header.setNumber(number);
232
header.getTempo().setValue(120);
233
header.setTripletFeel(this.tripletFeel);
234
header.setRepeatOpen( ((flags & 0x04) != 0) );
236
if ((flags & 0x01) != 0) {
237
timeSignature.setNumerator(readByte());
239
if ((flags & 0x02) != 0) {
240
timeSignature.getDenominator().setValue(readByte());
242
timeSignature.copy(header.getTimeSignature());
243
if ((flags & 0x08) != 0) {
244
header.setRepeatClose(readByte());
246
if ((flags & 0x10) != 0) {
247
header.setRepeatAlternative( parseRepeatAlternative(song, number, readUnsignedByte()) );
249
if ((flags & 0x20) != 0) {
250
header.setMarker(readMarker(number));
252
if ((flags & 0x40) != 0) {
259
private void readMeasure(TGMeasure measure, TGTrack track, TGTempo tempo) throws IOException{
260
long nextNoteStart = measure.getStart();
261
int numberOfBeats = readInt();
262
for (int i = 0; i < numberOfBeats; i++) {
263
nextNoteStart += readBeat(nextNoteStart, measure, track, tempo);
267
private long readBeat(long start, TGMeasure measure,TGTrack track, TGTempo tempo) throws IOException{
268
int flags = readUnsignedByte();
269
if((flags & 0x40) != 0){
273
TGBeat beat = getFactory().newBeat();
274
TGDuration duration = readDuration(flags);
275
TGNoteEffect effect = getFactory().newEffect();
276
if ((flags & 0x02) != 0) {
277
readChord(track.stringCount(),beat);
279
if ((flags & 0x04) != 0) {
282
if ((flags & 0x08) != 0) {
283
readBeatEffects(effect);
285
if ((flags & 0x10) != 0) {
286
readMixChange(tempo);
288
int stringFlags = readUnsignedByte();
289
for (int i = 6; i >= 0; i--) {
290
if ((stringFlags & (1 << i)) != 0 && (6 - i) < track.stringCount()) {
291
TGString string = track.getString( (6 - i) + 1 ).clone(getFactory());
292
TGNote note = readNote(string, track,effect.clone(getFactory()));
296
beat.setStart(start);
297
duration.copy(beat.getDuration());
298
measure.addBeat(beat);
300
return duration.getTime();
303
private void readText(TGBeat beat) throws IOException{
304
TGText text = getFactory().newText();
305
text.setValue(readStringByteSizeOfInteger());
309
private TGNote readNote(TGString string,TGTrack track,TGNoteEffect effect) throws IOException {
310
int flags = readUnsignedByte();
311
TGNote note = getFactory().newNote();
312
note.setString(string.getNumber());
313
note.setEffect(effect);
314
note.getEffect().setGhostNote(((flags & 0x04) != 0));
315
if ((flags & 0x20) != 0) {
316
int noteType = readUnsignedByte();
317
note.setTiedNote( (noteType == 0x02) );
318
note.getEffect().setDeadNote((noteType == 0x03));
320
if ((flags & 0x01) != 0) {
323
if ((flags & 0x10) != 0) {
324
note.setVelocity( (TGVelocities.MIN_VELOCITY + (TGVelocities.VELOCITY_INCREMENT * readByte())) - TGVelocities.VELOCITY_INCREMENT );
326
if ((flags & 0x20) != 0) {
327
int fret = readByte();
328
int value = ( note.isTiedNote() ? getTiedNoteValue(string.getNumber(), track) : fret );
329
note.setValue( value >= 0 && value < 100 ? value : 0 );
331
if ((flags & 0x80) != 0) {
334
if ((flags & 0x08) != 0) {
335
readNoteEffects(note.getEffect());
340
private TGTrack readTrack(int number, List channels) throws IOException {
341
TGTrack track = getFactory().newTrack();
342
track.setNumber(number);
344
track.setName(readStringByte(40));
345
int stringCount = readInt();
346
for (int i = 0; i < 7; i++) {
347
int tuning = readInt();
348
if (stringCount > i) {
349
TGString string = getFactory().newString();
350
string.setNumber(i + 1);
351
string.setValue(tuning);
352
track.getStrings().add(string);
356
readChannel(track.getChannel(),channels);
358
track.setOffset(readInt());
359
readColor(track.getColor());
363
private void readChannel(TGChannel channel,List channels) throws IOException {
364
int index = (readInt() - 1);
365
int effectChannel = (readInt() - 1);
366
if(index >= 0 && index < channels.size()){
367
((TGChannel) channels.get(index)).copy(channel);
368
if (channel.getInstrument() < 0) {
369
channel.setInstrument((short)0);
371
if(!channel.isPercussionChannel()){
372
channel.setEffectChannel((short)effectChannel);
377
private int parseRepeatAlternative(TGSong song,int measure,int value){
378
int repeatAlternative = 0;
379
int existentAlternatives = 0;
380
Iterator it = song.getMeasureHeaders();
382
TGMeasureHeader header = (TGMeasureHeader)it.next();
383
if(header.getNumber() == measure){
386
if(header.isRepeatOpen()){
387
existentAlternatives = 0;
389
existentAlternatives |= header.getRepeatAlternative();
392
for(int i = 0; i < 8; i ++){
393
if(value > i && (existentAlternatives & (1 << i)) == 0){
394
repeatAlternative |= (1 << i);
397
return repeatAlternative;
400
private void readChord(int strings, TGBeat beat) throws IOException {
401
TGChord chord = getFactory().newChord(strings);
402
int header = readUnsignedByte();
403
if ((header & 0x01) == 0) {
404
chord.setName(readStringByteSizeOfInteger());
405
chord.setFirstFret(readInt());
406
if (chord.getFirstFret() != 0) {
407
for (int i = 0; i < 6; i++) {
408
int fret = readInt();
409
if(i < chord.countStrings()){
410
chord.addFretValue(i,fret);
417
chord.setName(readStringByte(34));
418
chord.setFirstFret(readInt());
419
for (int i = 0; i < 6; i++) {
420
int fret = readInt();
421
if(i < chord.countStrings()){
422
chord.addFretValue(i,fret);
427
if(chord.countNotes() > 0){
428
beat.setChord(chord);
432
private void readGrace(TGNoteEffect effect) throws IOException {
433
int fret = readUnsignedByte();
434
TGEffectGrace grace = getFactory().newEffectGrace();
435
grace.setOnBeat(false);
436
grace.setDead( (fret == 255) );
437
grace.setFret( ((!grace.isDead())?fret:0) );
438
grace.setDynamic( (TGVelocities.MIN_VELOCITY + (TGVelocities.VELOCITY_INCREMENT * readUnsignedByte())) - TGVelocities.VELOCITY_INCREMENT );
439
int transition = readUnsignedByte();
441
grace.setTransition(TGEffectGrace.TRANSITION_NONE);
443
else if(transition == 1){
444
grace.setTransition(TGEffectGrace.TRANSITION_SLIDE);
446
else if(transition == 2){
447
grace.setTransition(TGEffectGrace.TRANSITION_BEND);
449
else if(transition == 3){
450
grace.setTransition(TGEffectGrace.TRANSITION_HAMMER);
452
grace.setDuration(readUnsignedByte());
453
effect.setGrace(grace);
456
private void readBend(TGNoteEffect effect) throws IOException {
457
TGEffectBend bend = getFactory().newEffectBend();
459
int points = readInt();
460
for (int i = 0; i < points; i++) {
461
int bendPosition = readInt();
462
int bendValue = readInt();
463
readByte(); //vibrato
465
int pointPosition = Math.round(bendPosition * TGEffectBend.MAX_POSITION_LENGTH / GP_BEND_POSITION);
466
int pointValue = Math.round(bendValue * TGEffectBend.SEMITONE_LENGTH / GP_BEND_SEMITONE);
467
bend.addPoint(pointPosition,pointValue);
469
if(!bend.getPoints().isEmpty()){
470
effect.setBend(bend);
474
private void readTremoloBar(TGNoteEffect noteEffect) throws IOException {
475
int value = readInt();
476
TGEffectTremoloBar effect = getFactory().newEffectTremoloBar();
477
effect.addPoint(0,0);
478
effect.addPoint( Math.round(TGEffectTremoloBar.MAX_POSITION_LENGTH / 2f) ,Math.round( -(value / (GP_BEND_SEMITONE * 2f) ) ) );
479
effect.addPoint(TGEffectTremoloBar.MAX_POSITION_LENGTH,0);
480
noteEffect.setTremoloBar(effect);
483
private void readNoteEffects(TGNoteEffect effect) throws IOException {
484
int flags = readUnsignedByte();
485
effect.setSlide( ((flags & 0x04) != 0) );
486
effect.setHammer( ((flags & 0x02) != 0) );
487
if ((flags & 0x01) != 0) {
490
if ((flags & 0x10) != 0) {
495
private void readBeatEffects(TGNoteEffect effect) throws IOException {
496
int flags = readUnsignedByte();
497
effect.setVibrato(((flags & 0x01) != 0) || ((flags & 0x02) != 0));
498
effect.setFadeIn(((flags & 0x10) != 0));
499
if ((flags & 0x20) != 0) {
500
int type = readUnsignedByte();
502
readTremoloBar(effect);
504
effect.setTapping(type == 1);
505
effect.setSlapping(type == 2);
506
effect.setPopping(type == 3);
510
if ((flags & 0x40) != 0) {
514
if ((flags & 0x04) != 0) {
515
TGEffectHarmonic harmonic = getFactory().newEffectHarmonic();
516
harmonic.setType(TGEffectHarmonic.TYPE_NATURAL);
517
effect.setHarmonic(harmonic);
519
if ((flags & 0x08) != 0) {
520
TGEffectHarmonic harmonic = getFactory().newEffectHarmonic();
521
harmonic.setType(TGEffectHarmonic.TYPE_ARTIFICIAL);
523
effect.setHarmonic(harmonic);
527
private void readMixChange(TGTempo tempo) throws IOException {
528
readByte(); //instrument
529
int volume = readByte();
530
int pan = readByte();
531
int chorus = readByte();
532
int reverb = readByte();
533
int phaser = readByte();
534
int tremolo = readByte();
535
int tempoValue = readInt();
555
tempo.setValue(tempoValue);
560
private short toChannelShort(byte b){
561
short value = (short)(( b * 8 ) - 1);
562
return (short)Math.max(value,0);
b'\\ No newline at end of file'