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

« back to all changes in this revision

Viewing changes to src/org/herac/tuxguitar/io/importer/MidiImporter.java

  • Committer: Bazaar Package Importer
  • Author(s): Philippe Coval
  • Date: 2007-02-04 01:41:23 UTC
  • Revision ID: james.westby@ubuntu.com-20070204014123-9pv7okph0iaiqkvw
Tags: upstream-0.9.1
ImportĀ upstreamĀ versionĀ 0.9.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package org.herac.tuxguitar.io.importer;
 
2
 
 
3
import java.io.File;
 
4
import java.io.IOException;
 
5
import java.util.ArrayList;
 
6
import java.util.Iterator;
 
7
import java.util.List;
 
8
 
 
9
import javax.sound.midi.MetaMessage;
 
10
import javax.sound.midi.MidiEvent;
 
11
import javax.sound.midi.MidiSystem;
 
12
import javax.sound.midi.Sequence;
 
13
import javax.sound.midi.ShortMessage;
 
14
import javax.sound.midi.Track;
 
15
 
 
16
import org.herac.tuxguitar.player.base.MidiControllers;
 
17
import org.herac.tuxguitar.song.managers.SongManager;
 
18
import org.herac.tuxguitar.song.models.Duration;
 
19
import org.herac.tuxguitar.song.models.InstrumentString;
 
20
import org.herac.tuxguitar.song.models.Measure;
 
21
import org.herac.tuxguitar.song.models.MeasureHeader;
 
22
import org.herac.tuxguitar.song.models.Note;
 
23
import org.herac.tuxguitar.song.models.NoteEffect;
 
24
import org.herac.tuxguitar.song.models.RGBColor;
 
25
import org.herac.tuxguitar.song.models.Song;
 
26
import org.herac.tuxguitar.song.models.SongChannel;
 
27
import org.herac.tuxguitar.song.models.SongTrack;
 
28
import org.herac.tuxguitar.song.models.Tempo;
 
29
import org.herac.tuxguitar.song.models.TimeSignature;
 
30
 
 
31
public class MidiImporter implements SongImporter{
 
32
 
 
33
        private static final long MIN_START = 1000;
 
34
        
 
35
        private static final Duration MIN_DURATION = new Duration(Duration.SIXTY_FOURTH);
 
36
        
 
37
        private float divisionType;
 
38
        private int resolution;
 
39
        private boolean moveTick;
 
40
        private List headers;
 
41
        private List tracks;
 
42
        private List tempNotes;
 
43
        private List tempChannels;
 
44
        private List trackTunningHelpers;
 
45
        
 
46
        public MidiImporter(){          
 
47
        }
 
48
        
 
49
        public Song importSong(String fileName) throws IOException, Exception, Error{                           
 
50
                Sequence sequence = MidiSystem.getSequence(new File(fileName));                 
 
51
                initFields(sequence);
 
52
                
 
53
                Track[] tracks = sequence.getTracks();
 
54
                for(int i = 0; i < tracks.length; i++){                         
 
55
                        Track track = tracks[i];        
 
56
                        int trackNumber = getNextTrackNumber();
 
57
                        int events = track.size();
 
58
                        for(int j = 0;j < events;j ++){
 
59
                                MidiEvent event = track.get(j);         
 
60
                                parseMessage(trackNumber,event.getTick(),event.getMessage().getMessage());
 
61
                        }                       
 
62
                }
 
63
                checkAll();
 
64
                
 
65
                return new SongAdjuster(new Song(this.tracks,this.headers)).adjustSong();
 
66
                //return new Song(this.tracks,this.headers);
 
67
        }
 
68
                
 
69
        private void initFields(Sequence sequence){
 
70
                this.divisionType = sequence.getDivisionType();
 
71
                this.resolution = sequence.getResolution();
 
72
                this.headers = new ArrayList();
 
73
                this.tracks = new ArrayList();
 
74
                this.tempNotes = new ArrayList();
 
75
                this.tempChannels = new ArrayList();
 
76
                this.trackTunningHelpers = new ArrayList();
 
77
        }
 
78
        
 
79
        private int getNextTrackNumber(){
 
80
                return (tracks.size() + 1);
 
81
        }
 
82
        
 
83
        private void parseMessage(int trackNumber,long tick,byte[] data){               
 
84
                int length = data.length;       
 
85
                tick = parseTick(tick + resolution);
 
86
                
 
87
                //NOTE ON
 
88
                if((((length > 0)?(data[0] & 0xFF):0) & 0xF0) == ShortMessage.NOTE_ON){
 
89
                        parseNoteOn(trackNumber,tick,data);
 
90
                }
 
91
                //NOTE OFF              
 
92
                else if((((length > 0)?(data[0] & 0xFF):0) & 0xF0) == ShortMessage.NOTE_OFF){
 
93
                        parseNoteOff(trackNumber,tick,data);
 
94
                }
 
95
                //PROGRAM CHANGE                
 
96
                else if((((length > 0)?(data[0] & 0xFF):0) & 0xF0) == ShortMessage.PROGRAM_CHANGE){
 
97
                        parseProgramChange(data);
 
98
                }
 
99
                //CONTROL CHANGE                
 
100
                else if((((length > 0)?(data[0] & 0xFF):0) & 0xF0) == ShortMessage.CONTROL_CHANGE){
 
101
                        parseControlChange(data);
 
102
                }                               
 
103
                //TIME SIGNATURE                
 
104
                else if(((length > 0)?(data[0] & 0xFF):0) == MetaMessage.META && (data[1] == 0x58)){
 
105
                        parseTimeSignature(tick,data);
 
106
                }               
 
107
                //TEMPO         
 
108
                else if(((length > 0)?(data[0] & 0xFF):0) == MetaMessage.META && (data[1] == 0x51)){
 
109
                        parseTempo(tick,data);
 
110
                }                               
 
111
        }
 
112
 
 
113
        private long parseTick(long tick){
 
114
                return Math.abs(Duration.QUARTER_TIME * tick / this.resolution);
 
115
        }
 
116
        
 
117
        private void parseNoteOn(int track,long tick,byte[] data){                              
 
118
                int length = data.length;               
 
119
                int channel = (length > 0)?((data[0] & 0xFF) & 0x0F):0;
 
120
                int value = (length > 1)?(data[1] & 0xFF):0;
 
121
                int velocity = (length > 2)?(data[2] & 0xFF):0;
 
122
                if(velocity == 0){
 
123
                        parseNoteOff(track,tick,data);
 
124
                }else if(value > 0){                    
 
125
                        makeTempNotesBefore(tick,track);                
 
126
                        getTempChannel(channel).track = track;
 
127
                        getTrackTunningHelper(track).checkValue(value);
 
128
                        tempNotes.add(new TempNote(track,channel,value,tick));
 
129
                }
 
130
        }
 
131
        
 
132
        private void parseNoteOff(int track,long tick,byte[] data){             
 
133
                int length = data.length;
 
134
                
 
135
                int channel = (length > 0)?((data[0] & 0xFF) & 0x0F):0;
 
136
                int value = (length > 1)?(data[1] & 0xFF):0;
 
137
                int velocity = (length > 2)?(data[2] & 0xFF):0;
 
138
                
 
139
                makeNote(tick,track,channel,value);
 
140
        }       
 
141
        
 
142
        private void parseProgramChange(byte[] data){           
 
143
                int length = data.length;               
 
144
                int channel = (length > 0)?((data[0] & 0xFF) & 0x0F):-1;
 
145
                int instrument = (length > 1)?(data[1] & 0xFF):-1;
 
146
                if(channel != -1 && instrument != -1){
 
147
                        getTempChannel(channel).instrument = instrument;
 
148
                }
 
149
        }               
 
150
 
 
151
        private void parseControlChange(byte[] data){                           
 
152
                int length = data.length;               
 
153
                int channel = (length > 0)?((data[0] & 0xFF) & 0x0F):-1;
 
154
                int control = (length > 1)?(data[1] & 0xFF):-1;
 
155
                int value = (length > 2)?(data[2] & 0xFF):-1;
 
156
                if(channel != -1 && control != -1 && value != -1){
 
157
                        if(control == MidiControllers.VOLUME){
 
158
                                getTempChannel(channel).volume = value;
 
159
                        }
 
160
                        else if(control == MidiControllers.BALANCE){
 
161
                                getTempChannel(channel).balance = value;
 
162
                        }                       
 
163
                }
 
164
        }               
 
165
 
 
166
        
 
167
        private void parseTimeSignature(long tick,byte[] data){
 
168
                TimeSignature timeSignature = new TimeSignature(data[3],new Duration(Duration.QUARTER));
 
169
                if (data[4] == 0) {
 
170
                        timeSignature.getDenominator().setValue(Duration.WHOLE);                        
 
171
        } else if (data[4] == 1) {
 
172
                timeSignature.getDenominator().setValue(Duration.HALF);
 
173
        } else if (data[4] == 2) {
 
174
                timeSignature.getDenominator().setValue(Duration.QUARTER);
 
175
        } else if (data[4] == 3) {
 
176
                timeSignature.getDenominator().setValue(Duration.EIGHTH);
 
177
        } else if (data[4] == 4) {
 
178
                timeSignature.getDenominator().setValue(Duration.SIXTEENTH);
 
179
        } else if (data[4] == 5) {
 
180
                timeSignature.getDenominator().setValue(Duration.THIRTY_SECOND);
 
181
        }                                                
 
182
                //timeSignature.getDenominator().setValue((96 / data[5]));              
 
183
                getHeader(tick).setTimeSignature(timeSignature);
 
184
        }               
 
185
        
 
186
        private void parseTempo(long tick,byte[] data){                         
 
187
                Tempo tempo = Tempo.fromUSQ((data[5] & 0x00ff) | ((data[4] & 0x00ff) << 8) | ((data[3] & 0x00ff) << 16));               
 
188
                getHeader(tick).setTempo(tempo);
 
189
        }       
 
190
        
 
191
        private SongTrack getTrack(int number){         
 
192
                Iterator it = tracks.iterator();
 
193
                while(it.hasNext()){
 
194
                        SongTrack track = (SongTrack)it.next();
 
195
                        if(track.getNumber() == number){
 
196
                                return track;
 
197
                        }
 
198
                }               
 
199
                SongChannel channel = new SongChannel((short)-1,(short)-1,(short)0);
 
200
                SongTrack track = new SongTrack(number,"",channel,new ArrayList(),new ArrayList(),0,(RGBColor)RGBColor.RED.clone());
 
201
                //SongTrack track = new SongTrack(number,"",channel,new ArrayList(),SongManager.createDefaultInstrumentStrings(),0,(RGBColor)RGBColor.RED.clone());
 
202
                tracks.add(track);
 
203
                return track;   
 
204
        }               
 
205
        
 
206
        private MeasureHeader getHeader(long tick){
 
207
                tick = (tick >= MIN_START)?tick:MIN_START;
 
208
                
 
209
                Iterator it = headers.iterator();
 
210
                while(it.hasNext()){
 
211
                        MeasureHeader header = (MeasureHeader)it.next();
 
212
                        if(tick >= header.getStart() && tick < header.getStart() + header.getLength()){
 
213
                                return header;
 
214
                        }
 
215
                }               
 
216
                MeasureHeader last = getLastHeader();           
 
217
                int number = (last != null)?last.getNumber() + 1:1;
 
218
                long start = (last != null)?(last.getStart() + last.getLength()):1000;
 
219
                int tripletFeel = MeasureHeader.TRIPLET_FEEL_NONE;
 
220
                TimeSignature timeSignature = (last != null)?(TimeSignature)last.getTimeSignature().clone():new TimeSignature(4,new Duration(Duration.QUARTER));
 
221
                Tempo tempo = (last != null)?(Tempo)last.getTempo().clone():new Tempo(120);                                             
 
222
                MeasureHeader header = new MeasureHeader(number,start,timeSignature,tempo,null,tripletFeel,false,0);
 
223
                
 
224
                this.headers.add(header);
 
225
                
 
226
                if(header.getStart() + header.getLength() <= tick){             
 
227
                        return header;
 
228
                }
 
229
                return getHeader(tick);
 
230
        }
 
231
        
 
232
        private MeasureHeader getLastHeader(){
 
233
                if(!this.headers.isEmpty()){
 
234
                        return (MeasureHeader)this.headers.get(this.headers.size() - 1);
 
235
                }               
 
236
                return null;
 
237
        }
 
238
 
 
239
        private Measure getMeasure(SongTrack track,long tick){  
 
240
                tick = (tick >= MIN_START)?tick:MIN_START;              
 
241
                Iterator it = track.getMeasures().iterator();
 
242
                while(it.hasNext()){
 
243
                        Measure measure = (Measure)it.next();
 
244
                        if(tick >= measure.getStart() && tick < measure.getStart() + measure.getLength()){
 
245
                                return measure;
 
246
                        }
 
247
                }                               
 
248
                getHeader(tick);
 
249
                for(int i = 0;i < headers.size();i++){
 
250
                        boolean exist = false;
 
251
                        MeasureHeader header = (MeasureHeader)headers.get(i);                   
 
252
                        for(int j = 0;j < track.getMeasures().size();j++){
 
253
                                Measure measure = (Measure)track.getMeasures().get(j);                          
 
254
                                if(measure.getHeader().equals(header)){
 
255
                                        exist = true;
 
256
                                }
 
257
                        }
 
258
                        if(!exist){
 
259
                                track.getMeasures().add(new Measure(header,new ArrayList(),new ArrayList(),1,0));               
 
260
                        }
 
261
                }
 
262
                return getMeasure(track,tick);
 
263
        }
 
264
        
 
265
        private TempNote getTempNote(int track,int channel,int value,boolean purge){
 
266
                for(int i = 0;i < tempNotes.size();i ++){
 
267
                        TempNote note = (TempNote)tempNotes.get(i);
 
268
                        if(note.track == track && note.channel == channel && note.value == value){
 
269
                                if(purge){
 
270
                                        tempNotes.remove(i);
 
271
                                }
 
272
                                return note;
 
273
                        }
 
274
                }
 
275
                return null;
 
276
        }
 
277
        
 
278
        private TrackTunningHelper getTrackTunningHelper(int track){
 
279
                Iterator it = this.trackTunningHelpers.iterator();
 
280
                while(it.hasNext()){
 
281
                        TrackTunningHelper helper = (TrackTunningHelper)it.next();
 
282
                        if(helper.getTrack() == track){
 
283
                                return helper;
 
284
                        }
 
285
                }
 
286
                TrackTunningHelper helper = new TrackTunningHelper(track);              
 
287
                this.trackTunningHelpers.add(helper);
 
288
                
 
289
                return helper;          
 
290
        }
 
291
        
 
292
        private void makeTempNotesBefore(long tick,int track){
 
293
                boolean check = true;
 
294
                while(check){
 
295
                        check = false;
 
296
                        for(int i = 0;i < tempNotes.size();i ++){
 
297
                                TempNote note = (TempNote)tempNotes.get(i);
 
298
                                if(note.tick < tick && note.track == track){
 
299
                                        //TODO
 
300
                                        tick = note.tick + 5000;
 
301
                                        makeNote(tick,track,note.channel,note.value);
 
302
                                        check = true;
 
303
                                        break;
 
304
                                }
 
305
                        }
 
306
                }
 
307
        }
 
308
        
 
309
        private void makeNote(long tick,int track,int channel,int value){                               
 
310
                TempNote tempNote = getTempNote(track,channel,value,true);                                      
 
311
                if(tempNote != null){
 
312
                        int nString = 0;
 
313
                        int nValue = tempNote.value;                                            
 
314
                        int nVelocity = 64;                     
 
315
                        long nStart = tempNote.tick;    
 
316
                        Duration nDuration = Duration.fromTime(tick - tempNote.tick,MIN_DURATION);
 
317
                        NoteEffect effect = new NoteEffect();
 
318
 
 
319
                        Measure measure = getMeasure(getTrack(track),tempNote.tick);
 
320
                        Note note = new Note(nValue,nStart,nDuration,nVelocity,nString,false,effect);
 
321
                        measure.addNote(note);                  
 
322
                }
 
323
        }
 
324
 
 
325
        
 
326
        public TempChannel getTempChannel(int channel){
 
327
                Iterator it = tempChannels.iterator();
 
328
                while(it.hasNext()){
 
329
                        TempChannel tempChannel = (TempChannel)it.next();
 
330
                        if(tempChannel.channel == channel){
 
331
                                return tempChannel;
 
332
                        }
 
333
                }       
 
334
                TempChannel tempChannel = new TempChannel(channel);
 
335
                tempChannels.add(tempChannel);
 
336
                
 
337
                return tempChannel;
 
338
        }       
 
339
        
 
340
        
 
341
        
 
342
        
 
343
        private void checkAll()throws Exception{
 
344
                checkTracks();
 
345
                
 
346
                int headerCount = headers.size();
 
347
                for(int i = 0;i < tracks.size();i ++){
 
348
                        SongTrack track = (SongTrack)tracks.get(i);     
 
349
                                
 
350
                        while(track.getMeasures().size() < headerCount){                                
 
351
                                long start = Duration.QUARTER_TIME;
 
352
                                Measure lastMeasure = (Measure)((!track.getMeasures().isEmpty())?track.getMeasures().get(track.getMeasures().size() - 1) :null);
 
353
                                if(lastMeasure != null){
 
354
                                        start = (lastMeasure.getStart() + lastMeasure.getLength());
 
355
                                }
 
356
                                track.getMeasures().add(new Measure(getHeader(start),new ArrayList(),new ArrayList(),1,0));
 
357
                        }
 
358
                }
 
359
                
 
360
                if(headers.isEmpty() || tracks.isEmpty()){
 
361
                        throw new Exception("Empty Song");
 
362
                }
 
363
        }
 
364
        
 
365
        private void checkTracks(){
 
366
                Iterator it = tracks.iterator();
 
367
                while(it.hasNext()){
 
368
                        SongTrack track = (SongTrack)it.next();
 
369
                        int channel1 = 0;
 
370
                        int channel2 = 0;
 
371
                        Iterator tcIt = tempChannels.iterator();
 
372
                        while(tcIt.hasNext()){
 
373
                                TempChannel tempChannel = (TempChannel)tcIt.next();
 
374
                                if(tempChannel.track == track.getNumber()){
 
375
                                        if(track.getChannel().getChannel() < 0){
 
376
                                                track.getChannel().setChannel((short)tempChannel.channel);
 
377
                                                track.getChannel().setInstrument((short)tempChannel.instrument);
 
378
                                                track.getChannel().setVolume((short)tempChannel.volume);
 
379
                                                track.getChannel().setBalance((short)tempChannel.balance);
 
380
                                        }else if(track.getChannel().getEffectChannel() < 0){
 
381
                                                track.getChannel().setEffectChannel((short)tempChannel.channel);
 
382
                                        }
 
383
                                }
 
384
                        }
 
385
                        if(track.getChannel().getChannel() < 0){
 
386
                                track.getChannel().setChannel((short)(SongManager.MAX_CHANNELS - 1));
 
387
                                track.getChannel().setInstrument((short)0);
 
388
                                track.getChannel().setVolume((short)127);
 
389
                                track.getChannel().setBalance((short)64);                               
 
390
                        }
 
391
                        if(track.getChannel().getEffectChannel() < 0){
 
392
                                track.getChannel().setEffectChannel(track.getChannel().getChannel());
 
393
                        }                       
 
394
                        
 
395
                        if(!track.isPercussionTrack()){
 
396
                                track.setStrings(getTrackTunningHelper((int)track.getNumber()).getStrings());
 
397
                        }else{
 
398
                                track.setStrings(SongManager.createPercusionStrings(6));
 
399
                        }
 
400
                }
 
401
        }
 
402
        
 
403
        
 
404
        private class TempNote{                                         
 
405
                private int track;
 
406
                private int channel;
 
407
                private int value;
 
408
                private long tick;
 
409
                
 
410
                public TempNote(int track, int channel, int value,long tick) {
 
411
                        this.track = track;
 
412
                        this.channel = channel;
 
413
                        this.value = value;
 
414
                        this.tick = tick;
 
415
                }                                       
 
416
        }
 
417
        
 
418
        private class TempChannel{
 
419
                private int channel;                                            
 
420
                private int instrument;
 
421
                private int volume;
 
422
                private int balance;
 
423
                private int track;
 
424
                
 
425
                public TempChannel(int channel) {
 
426
                        this.channel = channel;
 
427
                        this.instrument = 0;
 
428
                        this.volume = 127;
 
429
                        this.balance = 64;
 
430
                        this.track = -1;
 
431
                }                               
 
432
        }
 
433
        
 
434
        
 
435
        private class TrackTunningHelper{
 
436
                private int track;
 
437
                private int maxValue;
 
438
                private int minValue;
 
439
                
 
440
                public TrackTunningHelper(int track){           
 
441
                        this.track = track;
 
442
                        this.maxValue = -1;
 
443
                        this.minValue = -1;
 
444
                }
 
445
                
 
446
                public void checkValue(int value){
 
447
                        if(this.minValue < 0 || value < this.minValue){
 
448
                                this.minValue = value;
 
449
                        }
 
450
                        if(this.maxValue < 0 || value > this.maxValue){
 
451
                                this.maxValue = value;
 
452
                        }                       
 
453
                }
 
454
                
 
455
 
 
456
            private List getStrings() {
 
457
                List strings = new ArrayList();
 
458
 
 
459
                int maxFret = 24;
 
460
                
 
461
                if(minValue >= 40 && maxValue <= 64 + maxFret){
 
462
                strings.add(new InstrumentString(1, 64));
 
463
                strings.add(new InstrumentString(2, 59));
 
464
                strings.add(new InstrumentString(3, 55));
 
465
                strings.add(new InstrumentString(4, 50));
 
466
                strings.add(new InstrumentString(5, 45));
 
467
                strings.add(new InstrumentString(6, 40));                                               
 
468
                }
 
469
                else if(minValue >= 38 && maxValue <= 64 + maxFret){
 
470
                strings.add(new InstrumentString(1, 64));
 
471
                strings.add(new InstrumentString(2, 59));
 
472
                strings.add(new InstrumentString(3, 55));
 
473
                strings.add(new InstrumentString(4, 50));
 
474
                strings.add(new InstrumentString(5, 45));
 
475
                strings.add(new InstrumentString(6, 38));                                               
 
476
                }               
 
477
                else if(minValue >= 35 && maxValue <= 64 + maxFret){
 
478
                        strings.add(new InstrumentString(1, 64));
 
479
                        strings.add(new InstrumentString(2, 59));
 
480
                        strings.add(new InstrumentString(3, 55));
 
481
                        strings.add(new InstrumentString(4, 50));
 
482
                        strings.add(new InstrumentString(5, 45));
 
483
                        strings.add(new InstrumentString(6, 40));
 
484
                        strings.add(new InstrumentString(7, 35));                                               
 
485
                }
 
486
                else if(minValue >= 28 && maxValue <= 43 + maxFret){
 
487
                strings.add(new InstrumentString(1, 43));
 
488
                strings.add(new InstrumentString(2, 38));
 
489
                strings.add(new InstrumentString(3, 33));
 
490
                strings.add(new InstrumentString(4, 28));                       
 
491
                }
 
492
                else if(minValue >= 23 && maxValue <= 43 + maxFret){
 
493
                strings.add(new InstrumentString(1, 43));
 
494
                strings.add(new InstrumentString(2, 38));
 
495
                strings.add(new InstrumentString(3, 33));
 
496
                strings.add(new InstrumentString(4, 28));
 
497
                strings.add(new InstrumentString(5, 23));
 
498
                }else{
 
499
                        int stringCount = 6;                    
 
500
                        int stringSpacing = ((maxValue - (maxFret - 4) - minValue) / stringCount);
 
501
                        if(stringSpacing > 5){
 
502
                                stringCount = 7;                        
 
503
                                stringSpacing = ((maxValue - (maxFret - 4) - minValue) / stringCount);                          
 
504
                        }
 
505
                        
 
506
                        int maxStringValue = (minValue + (stringCount * stringSpacing));
 
507
                        while(strings.size() < stringCount){         
 
508
                                maxStringValue -= stringSpacing;
 
509
                                strings.add(new InstrumentString(strings.size() + 1,maxStringValue));
 
510
                        }
 
511
                }
 
512
 
 
513
                return strings;
 
514
            }           
 
515
 
 
516
                public int getMaxValue() {
 
517
                        return maxValue;
 
518
                }
 
519
 
 
520
                public int getMinValue() {
 
521
                        return minValue;
 
522
                }
 
523
 
 
524
                public int getTrack() {
 
525
                        return track;
 
526
                }
 
527
                
 
528
        }
 
529
        
 
530
        private class SongAdjuster{                             
 
531
                private Song song;
 
532
                private long minDurationTime;
 
533
                
 
534
                public SongAdjuster(Song song){
 
535
                        this.song = song;
 
536
                        this.minDurationTime = 60;
 
537
                }
 
538
                
 
539
                public Song adjustSong(){
 
540
                        Iterator it = song.getTracks().iterator();
 
541
                
 
542
                        while(it.hasNext()){
 
543
                                SongTrack track = (SongTrack)it.next();
 
544
                                adjustTrack(track);                     
 
545
                        }
 
546
                        return song;
 
547
                }
 
548
                
 
549
                private void adjustTrack(SongTrack track){
 
550
                        Iterator it = track.getMeasures().iterator();
 
551
                        while(it.hasNext()){
 
552
                                Measure measure = (Measure)it.next();
 
553
                                adjustMeasure(measure);
 
554
                                adjustStrings(track,measure);
 
555
                        }
 
556
                }
 
557
 
 
558
                /*
 
559
                private void adjustMeasure(Measure measure){                                            
 
560
 
 
561
                        for(int i = 0; i < measure.getNotes().size();i++){
 
562
                                Note note = (Note)measure.getNotes().get(i);
 
563
                                long start = note.getStart();
 
564
                                long time = note.getDuration().getTime();                               
 
565
                                if(i == 0 && measure.getStart() + minDurationTime > start){
 
566
                                        note.setStart(measure.getStart());
 
567
                                }                               
 
568
                                int nextIndex = (i + 1);
 
569
                                for(int j = nextIndex; j < measure.getNotes().size();j++){
 
570
                                        Note next = (Note)measure.getNotes().get(j);
 
571
                                        long nextTime = next.getDuration().getTime();
 
572
                                        long diff = 0;
 
573
                                        if(start + minDurationTime > next.getStart()){
 
574
                                                start = (next.getStart() > start)?next.getStart():start;
 
575
                                                next.setStart(note.getStart());
 
576
                                                if(time > nextTime){
 
577
                                                        next.setDuration((Duration)note.getDuration().clone());
 
578
                                                        time = next.getDuration().getTime();
 
579
                                                }else if(time < nextTime){
 
580
                                                        note.setDuration((Duration)next.getDuration().clone());
 
581
                                                }
 
582
                                        }else{  
 
583
                                                if(note.getStart() + time + minDurationTime + diff > next.getStart()){
 
584
                                                        diff = (next.getStart() - (note.getStart() + time));
 
585
                                                        next.setStart(note.getStart() + time);                                          
 
586
                                                }else{
 
587
                                                        break;
 
588
                                                }
 
589
                                        }
 
590
                                }
 
591
                        }
 
592
                }
 
593
                */
 
594
                private void adjustMeasure(Measure measure){                                            
 
595
                        List beatNotes = new ArrayList();
 
596
                        long nextStart = measure.getStart();                    
 
597
                        
 
598
                        for(int i = 0; i < measure.getNotes().size();i++){
 
599
                                Note note = (Note)measure.getNotes().get(i);
 
600
                                long start = note.getStart();
 
601
                                int nextIndex = (i + 1);
 
602
                                beatNotes.add(note);
 
603
                                
 
604
                                if((nextStart < start && nextStart + minDurationTime > start) || (nextStart > start && nextStart - minDurationTime < start)){
 
605
                                        note.setStart(nextStart);
 
606
                                }
 
607
 
 
608
                                long end = measure.getStart() + measure.getLength();
 
609
                                for(int j = nextIndex; j < measure.getNotes().size();j++){
 
610
                                        Note next = (Note)measure.getNotes().get(j);
 
611
                                        long nextTime = next.getDuration().getTime();
 
612
                                        long diff = 0;
 
613
                                        if(start + minDurationTime > next.getStart()){
 
614
                                                start = (next.getStart() > start)?next.getStart():start;
 
615
                                                beatNotes.add(next);    
 
616
                                                i = j;
 
617
                                        }else{
 
618
                                                end= next.getStart();
 
619
                                                break;
 
620
                                        }
 
621
                                }
 
622
                                nextStart = nextStart + adjustBeat(beatNotes,note.getStart(),end);
 
623
                                beatNotes.clear();                              
 
624
                        }
 
625
                }               
 
626
                
 
627
                private long adjustBeat(List beatNotes,long start,long nextBeatStart){
 
628
                        Duration lengthDuration = Duration.fromTime(nextBeatStart - start,MIN_DURATION);                        
 
629
                        long length = lengthDuration.getTime();
 
630
                        
 
631
                        Duration maxDuration = null;
 
632
                        for(int i = 0; i < beatNotes.size();i++){
 
633
                                Note note = (Note)beatNotes.get(i);
 
634
                                note.setStart(start);                                                           
 
635
                                if(maxDuration == null || note.getDuration().getTime() > maxDuration.getTime()){
 
636
                                        maxDuration = note.getDuration();
 
637
                                }
 
638
                        }
 
639
                        if(maxDuration != null){        
 
640
                                if(maxDuration.getTime() > length){
 
641
                                        maxDuration = lengthDuration;
 
642
                                }                               
 
643
                                for(int i = 0; i < beatNotes.size();i++){
 
644
                                        Note note = (Note)beatNotes.get(i);
 
645
                                        note.setStart(start);
 
646
                                        note.setDuration((Duration)maxDuration.clone());
 
647
                                }                       
 
648
                        }
 
649
                        
 
650
                        return length;
 
651
                }
 
652
                
 
653
                
 
654
                private void adjustStrings(SongTrack track,Measure measure){
 
655
                        List tempStrings = new ArrayList();
 
656
                        
 
657
                        //ajusto las cuerdas
 
658
                        long start = 0;         
 
659
                        Iterator it = measure.getNotes().iterator();
 
660
                        while(it.hasNext()){
 
661
                                Note note = (Note)it.next();
 
662
 
 
663
                                //checkeo las cuerdas
 
664
                                if(note.getStart() != start){
 
665
                                        tempStrings.clear();
 
666
                                        tempStrings.addAll(track.getStrings());
 
667
                                }
 
668
                                int string = getStringForValue(tempStrings,note.getValue());
 
669
                                for(int j = 0;j < tempStrings.size();j ++){
 
670
                                        InstrumentString tempString = (InstrumentString)tempStrings.get(j);     
 
671
                                        if(tempString.getNumber() == string){                                           
 
672
                                                note.setValue(note.getValue() - tempString.getValue());
 
673
                                                note.setString(tempString.getNumber());
 
674
                                                tempStrings.remove(j);
 
675
                                                break;
 
676
                                        }
 
677
                                }                               
 
678
                                if(note.getString() < 1){
 
679
                                        string = getStringForValue(track.getStrings(),note.getValue());
 
680
                                        note.setValue(note.getValue() - ((InstrumentString)track.getStrings().get(string - 1)).getValue());
 
681
                                        note.setString(string);
 
682
                                }                               
 
683
                                start = note.getStart();
 
684
                        }
 
685
                }               
 
686
                
 
687
                
 
688
                
 
689
                private int getStringForValue(List strings,int value){
 
690
                        int minFret = -1;
 
691
                        int stringForValue = 0;
 
692
                        for(int i = 0;i < strings.size();i++){
 
693
                                InstrumentString string = (InstrumentString)strings.get(i);                                             
 
694
                                int fret = value - string.getValue();                   
 
695
                                if(minFret < 0 || (fret >= 0 && fret < minFret)){
 
696
                                        stringForValue = string.getNumber();
 
697
                                        minFret = fret;                         
 
698
                                }
 
699
                        }                                               
 
700
                        return stringForValue;
 
701
                }       
 
702
                
 
703
        }
 
704
}