~ubuntu-branches/ubuntu/oneiric/tuxguitar/oneiric

« back to all changes in this revision

Viewing changes to src/org/herac/tuxguitar/io/gp/GP5InputStream.java

  • Committer: Bazaar Package Importer
  • Author(s): Philippe Coval
  • Date: 2008-06-19 00:30:30 UTC
  • mto: (5.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20080619003030-h719szrhsngou7c6
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package org.herac.tuxguitar.io.gp;
2
 
 
3
 
import java.io.File;
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;
9
 
import java.util.Iterator;
10
 
import java.util.List;
11
 
 
12
 
import org.herac.tuxguitar.io.gp.GPFormatException;
13
 
import org.herac.tuxguitar.song.models.Duration;
14
 
import org.herac.tuxguitar.song.models.InstrumentString;
15
 
import org.herac.tuxguitar.song.models.Lyric;
16
 
import org.herac.tuxguitar.song.models.Marker;
17
 
import org.herac.tuxguitar.song.models.Measure;
18
 
import org.herac.tuxguitar.song.models.MeasureHeader;
19
 
import org.herac.tuxguitar.song.models.Note;
20
 
import org.herac.tuxguitar.song.models.NoteEffect;
21
 
import org.herac.tuxguitar.song.models.Song;
22
 
import org.herac.tuxguitar.song.models.SongChannel;
23
 
import org.herac.tuxguitar.song.models.SongTrack;
24
 
import org.herac.tuxguitar.song.models.Tempo;
25
 
import org.herac.tuxguitar.song.models.TimeSignature;
26
 
import org.herac.tuxguitar.song.models.RGBColor;
27
 
import org.herac.tuxguitar.song.models.VelocityValues;
28
 
import org.herac.tuxguitar.song.models.effects.BendEffect;
29
 
import org.herac.tuxguitar.song.models.effects.GraceEffect;
30
 
import org.herac.tuxguitar.song.models.effects.HarmonicEffect;
31
 
import org.herac.tuxguitar.song.models.effects.TremoloBarEffect;
32
 
import org.herac.tuxguitar.song.models.effects.TremoloPickingEffect;
33
 
import org.herac.tuxguitar.song.models.effects.TrillEffect;
34
 
 
35
 
public class GP5InputStream extends InputStream {
36
 
    private static final String supportedVersions[] = { "FICHIER GUITAR PRO v5.00"/*,"FICHIER GUITAR PRO v5.10" */};    
37
 
    private static final int GP_BEND_SEMITONE = 50;    
38
 
    private static final int GP_BEND_POSITION = 60;    
39
 
    
40
 
    private String version;
41
 
    private InputStream inputStream;
42
 
    private int offset;
43
 
 
44
 
    public GP5InputStream(InputStream inputStream) {
45
 
        super();
46
 
        this.inputStream = inputStream;
47
 
        this.offset = 0;
48
 
    }
49
 
 
50
 
    public GP5InputStream(String fileName) throws FileNotFoundException {
51
 
        this(new FileInputStream(new File(fileName)));
52
 
    }
53
 
 
54
 
    public void close() throws IOException {
55
 
        this.inputStream.close();
56
 
    }
57
 
 
58
 
    public int read() throws IOException {
59
 
        this.offset++;
60
 
        return this.inputStream.read();
61
 
    }
62
 
 
63
 
    
64
 
    private void readVersion(){
65
 
                try {
66
 
                        if(this.version == null){
67
 
                                this.version = readStringByte(30);
68
 
                        }
69
 
                } catch (IOException e) {
70
 
                        this.version = "NOT_SUPPORTED";
71
 
                }       
72
 
    }
73
 
    
74
 
    public static boolean isSupportedVersion(String version) {
75
 
        for (int i = 0; i < supportedVersions.length; i++) {
76
 
            if (version.equals(supportedVersions[i])) {
77
 
                return true;
78
 
            }
79
 
        }
80
 
        return false;
81
 
    }
82
 
    
83
 
    public boolean isSupportedVersion(){
84
 
        try{
85
 
                readVersion();
86
 
                return isSupportedVersion(version);
87
 
        }catch(Exception e){
88
 
                return false;
89
 
        }catch(Error e){
90
 
                return false;
91
 
        }   
92
 
    }        
93
 
 
94
 
    public Song readSong() throws IOException, GPFormatException {
95
 
        readVersion();
96
 
        if (!isSupportedVersion(version)) {
97
 
            throw new GPFormatException("Unsuported Version");
98
 
        }
99
 
 
100
 
        String title = readStringIntegerPlusOne();
101
 
 
102
 
        String subtitle = readStringIntegerPlusOne();
103
 
 
104
 
        String interpret = readStringIntegerPlusOne();
105
 
 
106
 
        String album = readStringIntegerPlusOne();
107
 
        
108
 
        String songAuthor = readStringIntegerPlusOne();
109
 
 
110
 
        String music = readStringIntegerPlusOne();
111
 
        
112
 
        String copyright = readStringIntegerPlusOne();
113
 
 
114
 
        String tab = readStringIntegerPlusOne();
115
 
 
116
 
        String instructions = readStringIntegerPlusOne();
117
 
 
118
 
        int nbNotes = readInt();
119
 
        String note = "";
120
 
        for (int i = 0; i < nbNotes; i++) {
121
 
            note += readStringIntegerPlusOne();
122
 
            note += "\n";
123
 
        }
124
 
        
125
 
        //----lyrics----
126
 
        int lyricTrack = readInt();
127
 
        Lyric lyric = new Lyric(readInt(),readStringInteger());        
128
 
        for (int i = 0; i < 4; i++) {
129
 
                int measureNumber = readInt();
130
 
                String lines = readStringInteger();             
131
 
        }      
132
 
        //--------------
133
 
 
134
 
        skipBytes(30);
135
 
        for (int i = 0; i < 11; i++) {
136
 
                readInt();
137
 
                readStringByte(0);
138
 
        }        
139
 
        
140
 
        
141
 
        int tempoValue = readInt();
142
 
        int key = readByte();
143
 
        int octave = readInt();
144
 
        
145
 
        
146
 
        List channels = new ArrayList();
147
 
        int[] instruments = new int[64];
148
 
        for (int i = 0; i < 64; i++) {
149
 
                channels.add(new SongChannel((short)i,
150
 
                                        (short)i, 
151
 
                                        (short)readInt(),
152
 
                                        toChannelShort(readByte()),
153
 
                                        toChannelShort(readByte()),
154
 
                                        toChannelShort(readByte()),
155
 
                                        toChannelShort(readByte()),
156
 
                                        toChannelShort(readByte()),
157
 
                                        toChannelShort(readByte()),
158
 
                                        false,
159
 
                                        false));       
160
 
            byte[] b = { 0, 0 };
161
 
            read(b);
162
 
        }
163
 
        
164
 
        TimeSignature timeSignature = new TimeSignature(4, new Duration(4));
165
 
 
166
 
        skipBytes(42);
167
 
        
168
 
        int numberOfMeasures = readInt();
169
 
        int numberOfTracks = readInt();
170
 
        
171
 
        List headers = new ArrayList();
172
 
        if (numberOfMeasures > 0) {
173
 
            for (int i = 0; i < numberOfMeasures; i++) {
174
 
                if(i > 0 ){
175
 
                        skipBytes(1);
176
 
                }
177
 
                MeasureHeader header = createMeasureHeader((i + 1),timeSignature);
178
 
                headers.add(header);
179
 
            }
180
 
        }
181
 
 
182
 
        List tracks = new ArrayList();
183
 
        for (int number = 1; number <= numberOfTracks; number++) {
184
 
            tracks.add(createTrack(number, channels,(number == lyricTrack)?lyric:new Lyric()));
185
 
        }
186
 
        
187
 
        skipBytes(2);
188
 
        
189
 
        long nextMeasureStart = 1000;        
190
 
        for (int i = 0; i < numberOfMeasures; i++) {
191
 
            MeasureHeader currHeader = (MeasureHeader) headers.get(i);
192
 
            Tempo tempo = new Tempo(tempoValue);
193
 
            currHeader.setStart(nextMeasureStart);
194
 
            for (int j = 0; j < numberOfTracks; j++) {
195
 
                SongTrack track = (SongTrack) tracks.get(j);
196
 
                Measure measure = new Measure(currHeader,new ArrayList(),new ArrayList(),1,0);                
197
 
                addMeasureComponents(track.getStrings(), measure, track.getMeasures(), tempo);
198
 
                currHeader.setTempo(tempo);
199
 
                track.getMeasures().add(measure);
200
 
                skipBytes(1);
201
 
            }
202
 
            tempoValue = tempo.getValue();
203
 
            nextMeasureStart += currHeader.getLength();            
204
 
        }
205
 
        
206
 
        return new Song(title,interpret,album,songAuthor,tracks,headers,Song.MAX_VOLUME);
207
 
    }
208
 
 
209
 
    private long addNotes(long start, List notes, List trackStrings, List currTrackMeasures, Tempo tempo) throws IOException,
210
 
            GPFormatException {
211
 
        NoteEffect effect = new NoteEffect();
212
 
        
213
 
        int header = readUnsignedByte();
214
 
 
215
 
        if ((header & 0x40) != 0) {
216
 
            int beatStatus = readUnsignedByte();
217
 
            boolean emptyBeat = (beatStatus == 0x00);
218
 
            boolean restBeat = (beatStatus == 0x02);
219
 
        }
220
 
 
221
 
        boolean dottedNotes = ((header & 0x01) != 0);
222
 
 
223
 
        Duration duration = parseDuration(readByte());
224
 
        duration.setDotted(dottedNotes);
225
 
 
226
 
        if ((header & 0x20) != 0) {
227
 
            int tuplet = readInt();
228
 
            //-------Verifico el tupleto--------------------
229
 
            switch (tuplet) {
230
 
            case 3:
231
 
                duration.getTupleto().setEnters(3);
232
 
                duration.getTupleto().setTimes(2);
233
 
                break;
234
 
            case 5:
235
 
                duration.getTupleto().setEnters(5);
236
 
                duration.getTupleto().setTimes(4);
237
 
                break;                
238
 
            case 6:
239
 
                duration.getTupleto().setEnters(6);
240
 
                duration.getTupleto().setTimes(4);
241
 
                break;
242
 
            case 7:
243
 
                duration.getTupleto().setEnters(7);
244
 
                duration.getTupleto().setTimes(4);
245
 
                break;
246
 
            case 9:
247
 
                duration.getTupleto().setEnters(9);
248
 
                duration.getTupleto().setTimes(8);
249
 
                break;
250
 
            case 10:
251
 
                duration.getTupleto().setEnters(10);
252
 
                duration.getTupleto().setTimes(8);
253
 
                break;
254
 
            case 11:
255
 
                duration.getTupleto().setEnters(11);
256
 
                duration.getTupleto().setTimes(8);
257
 
                break;
258
 
            case 12:
259
 
                duration.getTupleto().setEnters(12);
260
 
                duration.getTupleto().setTimes(8);
261
 
                break;                  
262
 
            }
263
 
        }
264
 
 
265
 
        if ((header & 0x02) != 0) {
266
 
            readChordDiagram();
267
 
        }
268
 
 
269
 
        if ((header & 0x04) != 0) {
270
 
            String text = readStringIntegerPlusOne();
271
 
        }
272
 
 
273
 
        if ((header & 0x08) != 0) {
274
 
            readBeatEffects(effect,duration);
275
 
        }
276
 
 
277
 
        if ((header & 0x10) != 0) {
278
 
            readMixChange(tempo);
279
 
        }
280
 
 
281
 
        int stringsPlayed = readUnsignedByte();
282
 
        List strings = getPlayedStrings(stringsPlayed, trackStrings);
283
 
 
284
 
        for (int i = strings.size() - 1; i >= 0; i--) {
285
 
            InstrumentString string = (InstrumentString) strings.get(i);
286
 
            Note note = parseNote(start, string, duration, notes, currTrackMeasures,(NoteEffect)effect.clone());
287
 
            if (note != null) {
288
 
                notes.add(note);
289
 
            }
290
 
        }
291
 
 
292
 
        skipBytes(1);
293
 
        int read = readByte();
294
 
        if (read >= 8 && read < 32) {
295
 
                skipBytes(1);
296
 
        }
297
 
        
298
 
        
299
 
        return duration.getTime();
300
 
    }
301
 
 
302
 
    private List getPlayedStrings(int stringsPlayed, List trackStrings) {
303
 
        List strings = new ArrayList();
304
 
        if ((stringsPlayed & (1 << 0)) != 0 && trackStrings.size() > 6) {
305
 
            strings.add(((InstrumentString) trackStrings.get(6)).clone());
306
 
        }
307
 
        if ((stringsPlayed & (1 << 1)) != 0 && trackStrings.size() > 5) {
308
 
            strings.add(((InstrumentString) trackStrings.get(5)).clone());
309
 
        }
310
 
        if ((stringsPlayed & (1 << 2)) != 0 && trackStrings.size() > 4) {
311
 
            strings.add(((InstrumentString) trackStrings.get(4)).clone());
312
 
        }
313
 
        if ((stringsPlayed & (1 << 3)) != 0 && trackStrings.size() > 3) {
314
 
            strings.add(((InstrumentString) trackStrings.get(3)).clone());
315
 
        }
316
 
        if ((stringsPlayed & (1 << 4)) != 0 && trackStrings.size() > 2) {
317
 
            strings.add(((InstrumentString) trackStrings.get(2)).clone());
318
 
        }
319
 
        if ((stringsPlayed & (1 << 5)) != 0 && trackStrings.size() > 1) {
320
 
            strings.add(((InstrumentString) trackStrings.get(1)).clone());
321
 
        }
322
 
        if ((stringsPlayed & (1 << 6)) != 0 && trackStrings.size() > 0) {
323
 
            strings.add(((InstrumentString) trackStrings.get(0)).clone());
324
 
        }
325
 
        return strings;
326
 
    }
327
 
 
328
 
    private Duration parseDuration(byte value) {
329
 
        Duration duration = null;
330
 
        switch (value) {
331
 
        case -2:
332
 
            duration = new Duration(Duration.WHOLE);
333
 
            break;
334
 
        case -1:
335
 
            duration = new Duration(Duration.HALF);
336
 
            break;
337
 
        case 0:
338
 
            duration = new Duration(Duration.QUARTER);
339
 
            break;
340
 
        case 1:
341
 
            duration = new Duration(Duration.EIGHTH);
342
 
            break;
343
 
        case 2:
344
 
            duration = new Duration(Duration.SIXTEENTH);
345
 
            break;
346
 
        case 3:
347
 
            duration = new Duration(Duration.THIRTY_SECOND);
348
 
            break;
349
 
        case 4:
350
 
            duration = new Duration(Duration.SIXTY_FOURTH);
351
 
            break;
352
 
        }
353
 
        if(duration == null){
354
 
                duration = new Duration(Duration.QUARTER);
355
 
                System.err.println("Incorrect Duration. Forcing duration Quarter as Default.");
356
 
        }        
357
 
        return duration;
358
 
    }
359
 
 
360
 
    private int getTiedNoteValue(int string, List notes, List measures) {
361
 
        if (!notes.isEmpty()) {
362
 
            for (int nIdx = notes.size() - 1; nIdx >= 0; nIdx--) {
363
 
                Note note = (Note) notes.get(nIdx);
364
 
                if (note.getString() == string) {
365
 
                    return note.getValue();
366
 
                }
367
 
            }
368
 
        }
369
 
        if (!measures.isEmpty()) {
370
 
            for (int mIdx = measures.size() - 1; mIdx >= 0; mIdx--) {
371
 
                Measure measure = (Measure) measures.get(mIdx);
372
 
                for (int nIdx = measure.getNotes().size() - 1; nIdx >= 0; nIdx--) {
373
 
                    Note note = (Note) measure.getNotes().get(nIdx);
374
 
                    if (note.getString() == string) {
375
 
                        return note.getValue();
376
 
                    }
377
 
                }
378
 
            }
379
 
        }
380
 
        return -1;
381
 
    }
382
 
 
383
 
    private boolean readBoolean() throws IOException {
384
 
        return (read() == 1);
385
 
    }
386
 
 
387
 
    private byte readByte() throws IOException {
388
 
        return (byte) read();
389
 
    }
390
 
 
391
 
    private RGBColor readColor() throws IOException {
392
 
        int r = readUnsignedByte();
393
 
        int g = readUnsignedByte();
394
 
        int b = readUnsignedByte();
395
 
        read();
396
 
        
397
 
        return new RGBColor(r,g,b);
398
 
    }
399
 
 
400
 
    private int readInt() throws IOException {
401
 
        int integer = 0;
402
 
        byte[] b = { 0, 0, 0, 0 };
403
 
 
404
 
        read(b);
405
 
        integer = ((b[3] & 0xff) << 24) | ((b[2] & 0xff) << 16) | ((b[1] & 0xff) << 8) | (b[0] & 0xff);
406
 
 
407
 
        return integer;
408
 
    }
409
 
    
410
 
    private Marker readMarker(int measure) throws IOException {
411
 
        String name = readStringIntegerPlusOne();
412
 
        RGBColor color = readColor();
413
 
        
414
 
        return new Marker(measure,name,color);
415
 
    }    
416
 
 
417
 
    private MeasureHeader createMeasureHeader(int number,TimeSignature currTimeSignature) throws IOException {
418
 
        int header = readUnsignedByte();
419
 
 
420
 
        int numerator = 0;
421
 
        if ((header & 0x01) != 0) {
422
 
            numerator = readByte();
423
 
        }
424
 
 
425
 
        int denominator = 0;
426
 
        if ((header & 0x02) != 0) {
427
 
            denominator = readByte();
428
 
        }
429
 
 
430
 
        boolean repeatStart = ((header & 0x04) != 0);
431
 
 
432
 
        int numberOfRepetitions = 0;
433
 
        if ((header & 0x08) != 0) {
434
 
                numberOfRepetitions = (readByte() - 1);         
435
 
        }
436
 
 
437
 
        Marker marker = null;
438
 
        if ((header & 0x20) != 0) {
439
 
                marker = readMarker(number);
440
 
        }        
441
 
        
442
 
        int NumberOfAlternateEnding = 0;
443
 
        if ((header & 0x10) != 0) {
444
 
            NumberOfAlternateEnding = readByte();
445
 
        }
446
 
 
447
 
        if ((header & 0x40) != 0) {
448
 
            int type = readByte();
449
 
            readByte();
450
 
        }
451
 
 
452
 
        if ((header & 0x80) != 0) {
453
 
        }
454
 
        
455
 
        boolean doubleBar = ((header & 0x80) != 0);
456
 
 
457
 
        if (numerator > 0) {
458
 
            currTimeSignature.setNumerator(numerator);
459
 
        }
460
 
        if (denominator > 0) {
461
 
            currTimeSignature.setDenominator(new Duration(denominator));
462
 
        }
463
 
 
464
 
        //--------------------------------
465
 
        if(NumberOfAlternateEnding == 0){
466
 
                skipBytes(1);   
467
 
        }                
468
 
        
469
 
        if ((header & 0x01) != 0) {
470
 
                skipBytes(4);           
471
 
        }        
472
 
        
473
 
        int tripletFeel = MeasureHeader.TRIPLET_FEEL_NONE;
474
 
        int gpTripletFeel = readByte(); 
475
 
        if(gpTripletFeel == 1){
476
 
                tripletFeel = MeasureHeader.TRIPLET_FEEL_EIGHTH;
477
 
        }else if(gpTripletFeel == 2){
478
 
                tripletFeel = MeasureHeader.TRIPLET_FEEL_SIXTEENTH;
479
 
        }
480
 
        
481
 
        return new MeasureHeader(number,0,(TimeSignature) currTimeSignature.clone(), new Tempo(120),marker,tripletFeel,repeatStart,numberOfRepetitions);
482
 
    }
483
 
 
484
 
    private void addMeasureComponents(List trackStrings, Measure measure, List currTrackMeasures, Tempo tempo) throws IOException,GPFormatException {
485
 
        //voice 1
486
 
        long nextNoteStart = measure.getStart();
487
 
        int numberOfBeats = readInt();
488
 
        for (int i = 0; i < numberOfBeats; i++) {
489
 
            nextNoteStart += addNotes(nextNoteStart, measure.getNotes(), trackStrings, currTrackMeasures, tempo);
490
 
        }
491
 
        int noteCount = measure.getNotes().size();
492
 
        
493
 
        //voice 2
494
 
        nextNoteStart = measure.getStart();
495
 
        numberOfBeats = readInt();
496
 
        for (int i = 0; i < numberOfBeats; i++) {
497
 
            nextNoteStart += addNotes(nextNoteStart, measure.getNotes(), trackStrings, currTrackMeasures, tempo);
498
 
        }
499
 
        
500
 
        //join voices
501
 
        if(noteCount < measure.getNotes().size()){                
502
 
                new JoinVoicesHelper(measure).process();
503
 
        }
504
 
    }
505
 
 
506
 
    private Note parseNote(long start, InstrumentString string, Duration currDuration, List currMeasureNotes, List currTrackMeasures,NoteEffect effect)
507
 
            throws IOException {
508
 
        int header = readUnsignedByte();
509
 
        
510
 
        effect.setAccentuatedNote(((header & 0x40) != 0));
511
 
        effect.setHeavyAccentuatedNote(((header & 0x02) != 0));
512
 
        effect.setGhostNote(((header & 0x04) != 0));        
513
 
        boolean tiedNote = false;
514
 
        boolean deadNote = false;
515
 
        if ((header & 0x20) != 0) {
516
 
            int noteType = readUnsignedByte();
517
 
            tiedNote = (noteType == 0x02);
518
 
            effect.setDeadNote((noteType == 0x03));
519
 
        }
520
 
 
521
 
        if ((header & 0x01) != 0) {            
522
 
                //byte duration = readByte();
523
 
            //byte tuplet = readByte();
524
 
        }
525
 
 
526
 
        int velocity = VelocityValues.DEFAULT;
527
 
        if ((header & 0x10) != 0) {
528
 
                velocity = (VelocityValues.MIN_VELOCITY + (VelocityValues.VELOCITY_INCREMENT * readByte())) - VelocityValues.VELOCITY_INCREMENT;            
529
 
        }
530
 
 
531
 
        byte numberOfFret = 0;
532
 
        if ((header & 0x20) != 0) {
533
 
            numberOfFret = readByte();
534
 
        }
535
 
 
536
 
        if ((header & 0x80) != 0) {
537
 
            byte fingeringLeftHand = readByte();
538
 
            byte fingeringRightHand = readByte();
539
 
        }
540
 
 
541
 
        //cuando la duracion de la nota no es 100%
542
 
        if ((header & 0x01) != 0) {
543
 
                skipBytes(8);
544
 
        }
545
 
        
546
 
        skipBytes(1);
547
 
        if ((header & 0x08) != 0) {
548
 
            readNoteEffects(effect,currDuration);
549
 
        }        
550
 
        
551
 
        int value = numberOfFret;
552
 
        if (numberOfFret >= 0 || tiedNote) {
553
 
            if (tiedNote) {
554
 
                value = getTiedNoteValue(string.getNumber(), currMeasureNotes, currTrackMeasures);
555
 
            }
556
 
 
557
 
            return new Note(value, start, (Duration) currDuration.clone(), velocity, string.getNumber(),tiedNote,effect);
558
 
        }
559
 
 
560
 
        return null;
561
 
    }
562
 
 
563
 
    private String readStringByte(int expectedLength) throws IOException {
564
 
        byte[] bytes;
565
 
        int realLength = readUnsignedByte();
566
 
 
567
 
        if (expectedLength != 0) {
568
 
                bytes = new byte[expectedLength];
569
 
        } else {
570
 
                bytes = new byte[realLength];
571
 
        }
572
 
        read(bytes);
573
 
        
574
 
        realLength = (realLength >= 0)?realLength:expectedLength;
575
 
        return new String(bytes, 0, realLength);  
576
 
    }
577
 
 
578
 
    private String readStringInteger() throws IOException {
579
 
        byte[] b;
580
 
        String str;
581
 
        int length = readInt();
582
 
 
583
 
        b = new byte[length];
584
 
        read(b);
585
 
 
586
 
        str = new String(b);
587
 
        return str;
588
 
    }
589
 
 
590
 
    private String readStringIntegerPlusOne() throws IOException {
591
 
        byte[] b;
592
 
        String str;
593
 
        int lengthPlusOne = readInt();
594
 
        int length = lengthPlusOne - 1;
595
 
 
596
 
        if (length != read()) {
597
 
            throw new IOException();
598
 
        }
599
 
 
600
 
        b = new byte[length];
601
 
        read(b);
602
 
 
603
 
        str = new String(b);
604
 
        return str;
605
 
    }
606
 
 
607
 
    private SongTrack createTrack(int number, List channels,Lyric lyrics) throws IOException {
608
 
        int test = 0;
609
 
        byte bb = 0;
610
 
        
611
 
        int header = readUnsignedByte();
612
 
 
613
 
        boolean isDrumsTrack = ((header & 0x01) != 0);
614
 
        boolean is12StringedGuitarTrack = ((header & 0x02) != 0);
615
 
        boolean isBanjoTrack = ((header & 0x04) != 0);
616
 
                
617
 
        skipBytes(1);
618
 
        String name = readStringByte(40);        
619
 
 
620
 
        
621
 
        int numberOfStrings = readInt();       
622
 
        
623
 
        List strings = new ArrayList(numberOfStrings);
624
 
 
625
 
        for (int i = 0; i < 7; i++) {
626
 
            int tunning = readInt();
627
 
            if (numberOfStrings > i) {
628
 
                strings.add(new InstrumentString(i + 1, tunning));
629
 
            }
630
 
        }
631
 
 
632
 
        int port = readInt();
633
 
 
634
 
        int channelIndex = readInt();
635
 
 
636
 
        int effects = readInt();
637
 
 
638
 
        int numberOfFrets = readInt();
639
 
 
640
 
        int capo = readInt();
641
 
 
642
 
        RGBColor color = readColor();
643
 
        
644
 
        skipBytes(44);
645
 
        
646
 
        return new SongTrack(number,name,parseChannel(channels,channelIndex,effects), new ArrayList(), strings,capo,color,lyrics);
647
 
    }
648
 
    
649
 
    private SongChannel parseChannel(List channels, int channelIndex,int effectChannel) {
650
 
        SongChannel channel = (SongChannel) channels.get(channelIndex - 1);
651
 
 
652
 
        int instrument = channel.getInstrument();
653
 
        if (instrument == -1) {
654
 
            channel.setInstrument((short)0);
655
 
        }
656
 
        if(!channel.isPercusionChannel()){
657
 
                channel.setEffectChannel((short)(effectChannel - 1));
658
 
        }
659
 
        
660
 
        return channel;
661
 
    }
662
 
 
663
 
 
664
 
    private int readUnsignedByte() throws IOException {
665
 
        return read();
666
 
    }
667
 
 
668
 
    private void readChordType() throws IOException {
669
 
        readUnsignedByte();
670
 
    }
671
 
 
672
 
    private void readRoot() throws IOException {
673
 
        readByte();
674
 
    }
675
 
 
676
 
    private void readTonalityType(int numBytes) throws IOException {
677
 
        if (numBytes == 1) {
678
 
            int type = readUnsignedByte();
679
 
        } else if (numBytes == 4) {
680
 
            int type = readInt();
681
 
        }
682
 
    }
683
 
 
684
 
    private String readChordName() throws IOException {
685
 
        byte[] nameB;
686
 
        char[] nameC;
687
 
        int i;
688
 
        int max;
689
 
 
690
 
        nameB = new byte[21];
691
 
        nameC = new char[20];
692
 
        read(nameB, 0, 21);
693
 
        max = 20;
694
 
        if (nameB[0] < max) {
695
 
            max = nameB[0];
696
 
        }
697
 
 
698
 
        for (i = 1; i <= max; i++) {
699
 
            nameC[i - 1] = (char) nameB[i];
700
 
        }
701
 
        return (String.valueOf(nameC, 0, max));
702
 
    }
703
 
 
704
 
    private void readChordDiagram() throws IOException, GPFormatException {
705
 
        int header;
706
 
        long aux;
707
 
        long skip;
708
 
        int i;
709
 
 
710
 
        header = readUnsignedByte();
711
 
 
712
 
        if ((header & 0x01) == 0) {
713
 
            throw new GPFormatException("Cannot Read Chord Diagram");
714
 
        }
715
 
 
716
 
        boolean sharp = readBoolean();
717
 
 
718
 
        this.skip(3);
719
 
 
720
 
        readRoot();
721
 
 
722
 
        readChordType();
723
 
 
724
 
        int nineElevenThirteen = readUnsignedByte();
725
 
 
726
 
        int bass = readInt();
727
 
 
728
 
        readTonalityType(4);
729
 
 
730
 
        int addedNote = readUnsignedByte();
731
 
 
732
 
        String name = readChordName();
733
 
 
734
 
        this.skip(2);
735
 
 
736
 
        readTonalityType(1);
737
 
 
738
 
        readTonalityType(1);
739
 
 
740
 
        readTonalityType(1);
741
 
 
742
 
        int baseFret = readInt();
743
 
 
744
 
        for (i = 1; i <= 7; i++) {
745
 
            int fret = readInt();
746
 
        }
747
 
 
748
 
        int numBarres = readUnsignedByte();
749
 
 
750
 
        for (i = 1; i <= 5; i++) {
751
 
            int fretOfBarre = readUnsignedByte();
752
 
        }
753
 
        for (i = 1; i <= 5; i++) {
754
 
            int barreStart = readUnsignedByte();
755
 
        }
756
 
        for (i = 1; i <= 5; i++) {
757
 
            int barreEnd = readUnsignedByte();
758
 
        }
759
 
 
760
 
        aux = this.skip(8);
761
 
 
762
 
        for (i = 1; i <= 7; i++) {
763
 
            int fingering = readByte();
764
 
        }
765
 
        boolean chordFingeringDisplayed = readBoolean();
766
 
    }
767
 
 
768
 
    private void readGraceNote() throws IOException {
769
 
        skipBytes(5);
770
 
    }
771
 
    
772
 
    private void readGraceNote(NoteEffect effect) throws IOException {          
773
 
        int fret = readByte();          
774
 
        int velocity = readByte();
775
 
        int transition = readByte();            
776
 
        int duration = readByte();
777
 
        int onBeat = readByte();
778
 
        
779
 
        
780
 
        //dead
781
 
        boolean dead = (fret == 255);
782
 
        
783
 
        //fret
784
 
        fret = ((!dead)?fret:0);
785
 
        
786
 
        //velocity      
787
 
        velocity = (VelocityValues.MIN_VELOCITY + (VelocityValues.VELOCITY_INCREMENT * velocity)) - VelocityValues.VELOCITY_INCREMENT;
788
 
        
789
 
        //transition
790
 
        if(transition == 0){
791
 
                transition = GraceEffect.TRANSITION_NONE;
792
 
        }
793
 
        else if(transition == 1){
794
 
                transition = GraceEffect.TRANSITION_SLIDE;
795
 
        }
796
 
        else if(transition == 2){
797
 
                transition = GraceEffect.TRANSITION_BEND;
798
 
        }
799
 
        else if(transition == 3){
800
 
                transition = GraceEffect.TRANSITION_HAMMER;
801
 
        }
802
 
        
803
 
        effect.setGrace(new GraceEffect(fret,duration,velocity,transition,(onBeat > 0),dead));                  
804
 
    }    
805
 
 
806
 
    private void readBend(NoteEffect effect) throws IOException {
807
 
        byte type = readByte();
808
 
        int value = readInt();
809
 
        
810
 
        BendEffect bend = new BendEffect();        
811
 
        int numPoints = readInt();
812
 
        for (int i = 0; i < numPoints; i++) {
813
 
            
814
 
            int bendPosition = readInt();
815
 
            int bendValue = readInt();
816
 
            byte bendVibrato = readByte();
817
 
            
818
 
            bend.addPoint((int)(bendPosition * BendEffect.MAX_POSITION_LENGTH / GP_BEND_POSITION),(bendValue * BendEffect.SEMITONE_LENGTH / GP_BEND_SEMITONE));         
819
 
        }
820
 
        if(!bend.getPoints().isEmpty()){
821
 
            effect.setBend(bend);
822
 
        }        
823
 
    }
824
 
 
825
 
    private void readTremoloBar(NoteEffect effect) throws IOException {
826
 
        byte type = readByte();
827
 
        int value = readInt();
828
 
        
829
 
        TremoloBarEffect tremoloBar = new TremoloBarEffect();        
830
 
        int numPoints = readInt();
831
 
        for (int i = 0; i < numPoints; i++) {            
832
 
            int bendPosition = readInt();
833
 
            int bendValue = readInt();
834
 
            byte bendVibrato = readByte();
835
 
 
836
 
            tremoloBar.addPoint((int)(bendPosition * TremoloBarEffect.MAX_POSITION_LENGTH / GP_BEND_POSITION),(bendValue * TremoloBarEffect.SEMITONE_LENGTH / GP_BEND_SEMITONE));           
837
 
        }
838
 
        if(!tremoloBar.getPoints().isEmpty()){
839
 
            effect.setTremoloBar(tremoloBar);
840
 
        }        
841
 
    }    
842
 
    
843
 
    private void readNoteEffects(NoteEffect noteEffect,Duration duration) throws IOException {
844
 
        int header1;
845
 
        int header2;
846
 
        int b;
847
 
 
848
 
        header1 = readUnsignedByte();
849
 
        header2 = readUnsignedByte();
850
 
 
851
 
        //bend
852
 
        if ((header1 & 0x01) != 0) {
853
 
            readBend(noteEffect);
854
 
        }
855
 
 
856
 
        //grace
857
 
        if ((header1 & 0x10) != 0) {
858
 
            readGraceNote(noteEffect);
859
 
        }
860
 
 
861
 
        //tremolo picking
862
 
        if ((header2 & 0x04) != 0) {
863
 
                readTremoloPicking(noteEffect);
864
 
        }
865
 
 
866
 
        //slide
867
 
        if ((header2 & 0x08) != 0) {
868
 
            noteEffect.setSlide(true);
869
 
            readByte();            
870
 
        }
871
 
 
872
 
        //harmonic
873
 
        if ((header2 & 0x10) != 0) {
874
 
                readArtificialHarmonic(noteEffect);
875
 
        }
876
 
 
877
 
        //trill
878
 
        if ((header2 & 0x20) != 0) {
879
 
            byte fret = readByte();
880
 
            byte period = readByte();            
881
 
                if(period == 1){
882
 
                        noteEffect.setTrill(new TrillEffect(fret,new Duration(Duration.SIXTEENTH)));            
883
 
                }else if(period == 2){
884
 
                        noteEffect.setTrill(new TrillEffect(fret,new Duration(Duration.THIRTY_SECOND)));
885
 
                }else if(period == 3){
886
 
                        noteEffect.setTrill(new TrillEffect(fret,new Duration(Duration.SIXTY_FOURTH)));
887
 
                }                   
888
 
        }        
889
 
 
890
 
        //hammer
891
 
        noteEffect.setHammer(((header1 & 0x02) != 0));
892
 
 
893
 
        //vibrato        
894
 
        noteEffect.setVibrato(((header2 & 0x40) != 0) || noteEffect.isVibrato());
895
 
 
896
 
        //palm-mute        
897
 
        noteEffect.setPalmMute(((header2 & 0x02) != 0));
898
 
 
899
 
        //staccato
900
 
        noteEffect.setStaccato(((header2 & 0x01) != 0));
901
 
    }
902
 
 
903
 
    private void readBeatEffects(NoteEffect noteEffect,Duration currDuration) throws IOException {
904
 
        int header[] = { 0, 0 };
905
 
 
906
 
        header[0] = readUnsignedByte();
907
 
        header[1] = readUnsignedByte();
908
 
 
909
 
        noteEffect.setFadeIn(((header[0] & 0x10) != 0));        
910
 
        noteEffect.setVibrato(((header[0]  & 0x02) != 0));        
911
 
        
912
 
        if ((header[0] & 0x20) != 0) {
913
 
            int effect = readUnsignedByte();            
914
 
            noteEffect.setTapping(effect == 1);
915
 
            noteEffect.setSlapping(effect == 2);
916
 
            noteEffect.setPopping(effect == 3);            
917
 
        }
918
 
 
919
 
        if ((header[1] & 0x04) != 0) {          
920
 
            readTremoloBar(noteEffect);
921
 
        }
922
 
 
923
 
        if ((header[0] & 0x40) != 0) {
924
 
                //Upstroke - Downstroke
925
 
            readByte();
926
 
            readByte();
927
 
        }
928
 
 
929
 
        if ((header[1] & 0x01) != 0) {
930
 
            //Rasgueado
931
 
        }
932
 
 
933
 
        if ((header[1] & 0x02) != 0) {
934
 
            //Pickstroke
935
 
            readByte();
936
 
        }
937
 
    }
938
 
 
939
 
    private void readMixChange(Tempo currentTempo) throws IOException { 
940
 
        int instrument = readByte();
941
 
        
942
 
        skipBytes(16);
943
 
        int volume = readByte();
944
 
        int pan = readByte();
945
 
        int chorus = readByte();
946
 
        int reverb = readByte();
947
 
        int phaser = readByte();
948
 
        int tremolo = readByte();    
949
 
        String tempoName = readStringInteger();         
950
 
        int tempo = readInt();
951
 
        if(volume >= 0){
952
 
                int type = readByte();  
953
 
        }
954
 
        if(pan >= 0){
955
 
                int type = readByte();  
956
 
        }
957
 
        if(chorus >= 0){
958
 
                int type = readByte();  
959
 
        }
960
 
        if(reverb >= 0){
961
 
                int type = readByte();  
962
 
        }
963
 
        if(phaser >= 0){
964
 
                int type = readByte();  
965
 
        }
966
 
        if(tremolo >= 0){
967
 
                int type = readByte();  
968
 
        }       
969
 
        if(tempo >= 0){
970
 
                currentTempo.setValue(tempo);
971
 
                int type = readByte();  
972
 
        }               
973
 
        int applyToAllTracks = readByte(); 
974
 
        skipBytes(1);           
975
 
    }
976
 
    
977
 
    private void readArtificialHarmonic(NoteEffect effect) throws IOException{          
978
 
        int harmonic = readByte();      
979
 
        if(harmonic == 1){
980
 
                effect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_NATURAL));
981
 
        }       
982
 
        else if(harmonic == 2){
983
 
                int note = readByte();
984
 
                int natural = readByte();
985
 
                int type =  readByte();
986
 
                effect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_ARTIFICIAL,0));               
987
 
        }else if(harmonic == 3){
988
 
                effect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_TAPPED,readByte()));
989
 
        }else if(harmonic == 4){
990
 
                effect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_PINCH));
991
 
        }else if(harmonic == 5){
992
 
                effect.setHarmonic(new HarmonicEffect(HarmonicEffect.TYPE_SEMI));
993
 
        }
994
 
        
995
 
        
996
 
        
997
 
    }
998
 
    
999
 
 
1000
 
    public void readTremoloPicking(NoteEffect effect) throws IOException{               
1001
 
        int duration = readUnsignedByte();      
1002
 
        if(duration == 1){
1003
 
                        effect.setTremoloPicking(new TremoloPickingEffect(new Duration(Duration.EIGHTH)));
1004
 
                }else if(duration == 2){
1005
 
                        effect.setTremoloPicking(new TremoloPickingEffect(new Duration(Duration.SIXTEENTH)));
1006
 
                }else if(duration == 3){
1007
 
                        effect.setTremoloPicking(new TremoloPickingEffect(new Duration(Duration.THIRTY_SECOND)));
1008
 
                }
1009
 
        }    
1010
 
    
1011
 
    private short toChannelShort(byte b){
1012
 
        short s = (short)b;
1013
 
        s = (short)((s * (short)127) / (short)16);
1014
 
        return (s <= 127)?s:127;
1015
 
    }
1016
 
 
1017
 
    private void skipBytes(int count) throws IOException{
1018
 
        for(int i = 0;i < count;i ++){
1019
 
                readByte();
1020
 
        }
1021
 
    }
1022
 
    
1023
 
 
1024
 
    private void skipBytes(int count,boolean debug) throws IOException{
1025
 
        System.out.println("---------");
1026
 
        for(int i = 0;i < count;i ++){
1027
 
                int b = readByte();
1028
 
                System.out.println(b);
1029
 
        }
1030
 
        System.out.println("---------");
1031
 
    }
1032
 
}
1033
 
class JoinVoicesHelper{
1034
 
        private Measure measure;
1035
 
        
1036
 
        public JoinVoicesHelper(Measure measure){
1037
 
                this.measure = measure;
1038
 
        }
1039
 
        
1040
 
        public void process(){
1041
 
                if(!measure.getNotes().isEmpty()){
1042
 
                        orderNotes();
1043
 
                
1044
 
                        long start = ((Note)measure.getNotes().get(0)).getStart();
1045
 
                        long measureStart = measure.getStart();
1046
 
                        long measureLength = measure.getLength();
1047
 
                        while(start < (measureStart + measureLength)){
1048
 
                                List notesAtBeat = getNotesAtBeat(start);
1049
 
                                long maxLength = getMaxLength(start);
1050
 
                                normalizeNotes(notesAtBeat,maxLength);
1051
 
                                start += maxLength;
1052
 
                        }
1053
 
                }
1054
 
        }
1055
 
        
1056
 
        private void normalizeNotes(List notes,long maxLength){
1057
 
                Duration beatDuration = null;
1058
 
                
1059
 
                Iterator it = notes.iterator();
1060
 
                while(it.hasNext()){
1061
 
                        Note note = (Note)it.next();
1062
 
                        long noteDuration = note.getDuration().getTime();                       
1063
 
                        if(noteDuration <= maxLength && (beatDuration == null || noteDuration > beatDuration.getTime())){
1064
 
                                beatDuration = note.getDuration();
1065
 
                        }
1066
 
                }               
1067
 
                if(beatDuration == null){
1068
 
                        beatDuration = Duration.fromTime(maxLength);
1069
 
                }
1070
 
                if(beatDuration != null){                       
1071
 
                        it = notes.iterator();
1072
 
                        while(it.hasNext()){
1073
 
                                Note note = (Note)it.next();
1074
 
                                note.setDuration((Duration)beatDuration.clone());
1075
 
                        }
1076
 
                }
1077
 
        }
1078
 
        
1079
 
        private List getNotesAtBeat(long start){
1080
 
                List notes = new ArrayList();
1081
 
                Iterator it = measure.getNotes().iterator();
1082
 
                while(it.hasNext()){
1083
 
                        Note note = (Note)it.next();
1084
 
                        if(note.getStart() == start){
1085
 
                                notes.add(note);
1086
 
                        }
1087
 
                }
1088
 
                return notes;
1089
 
        }
1090
 
                
1091
 
        private long getMaxLength(long start){
1092
 
                long nextStart = -1;
1093
 
                Iterator it = measure.getNotes().iterator();
1094
 
                while(it.hasNext()){
1095
 
                        Note note = (Note)it.next();
1096
 
                        if(note.getStart() > start && (nextStart < 0 || note.getStart() < nextStart)){
1097
 
                                nextStart = note.getStart();
1098
 
                        }
1099
 
                }
1100
 
                if(nextStart < 0){
1101
 
                        nextStart = (measure.getStart() + measure.getLength());
1102
 
                }
1103
 
                return (nextStart - start);
1104
 
        }
1105
 
        
1106
 
    private void orderNotes(){
1107
 
        int noteCount = measure.getNotes().size();
1108
 
        for(int i = 0;i < noteCount;i++){
1109
 
            Note minNote = null;
1110
 
            for(int noteIdx = i;noteIdx < noteCount;noteIdx++){
1111
 
                Note note = (Note)measure.getNotes().get(noteIdx);
1112
 
                if(minNote == null){
1113
 
                    minNote = note;
1114
 
                }else if(note.getStart() < minNote.getStart()){
1115
 
                        minNote = note;
1116
 
                }else if(note.getStart() == minNote.getStart() && note.getString() < minNote.getString()){
1117
 
                        minNote = note;
1118
 
                }
1119
 
            }
1120
 
            measure.getNotes().remove(minNote);
1121
 
            measure.getNotes().add(i,minNote);
1122
 
        }
1123
 
    }
1124
 
}