1 package org.herac.tuxguitar.song.managers;
2 
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.Comparator;
6 import java.util.Iterator;
7 import java.util.List;
8 
9 import org.herac.tuxguitar.song.factory.TGFactory;
10 import org.herac.tuxguitar.song.models.TGBeat;
11 import org.herac.tuxguitar.song.models.TGChord;
12 import org.herac.tuxguitar.song.models.TGDuration;
13 import org.herac.tuxguitar.song.models.TGMeasure;
14 import org.herac.tuxguitar.song.models.TGNote;
15 import org.herac.tuxguitar.song.models.TGString;
16 import org.herac.tuxguitar.song.models.TGStroke;
17 import org.herac.tuxguitar.song.models.TGText;
18 import org.herac.tuxguitar.song.models.TGTrack;
19 import org.herac.tuxguitar.song.models.TGVoice;
20 import org.herac.tuxguitar.song.models.effects.TGEffectBend;
21 import org.herac.tuxguitar.song.models.effects.TGEffectGrace;
22 import org.herac.tuxguitar.song.models.effects.TGEffectHarmonic;
23 import org.herac.tuxguitar.song.models.effects.TGEffectTremoloBar;
24 import org.herac.tuxguitar.song.models.effects.TGEffectTremoloPicking;
25 import org.herac.tuxguitar.song.models.effects.TGEffectTrill;
26 
27 public class TGMeasureManager {
28 	private TGSongManager songManager;
29 
TGMeasureManager(TGSongManager songManager)30 	public TGMeasureManager(TGSongManager songManager){
31 		this.songManager = songManager;
32 	}
33 
getSongManager()34 	public TGSongManager getSongManager(){
35 		return this.songManager;
36 	}
37 
orderBeats(TGMeasure measure)38 	public void orderBeats(TGMeasure measure){
39 		for(int i = 0;i < measure.countBeats();i++){
40 			TGBeat minBeat = null;
41 			for(int j = i;j < measure.countBeats();j++){
42 				TGBeat beat = measure.getBeat(j);
43 				if(minBeat == null || beat.getStart() < minBeat.getStart()){
44 					minBeat = beat;
45 				}
46 			}
47 			measure.moveBeat(i, minBeat);
48 		}
49 	}
50 
51 	/**
52 	 * Agrega un beat al compas
53 	 */
addBeat(TGMeasure measure,TGBeat beat)54 	public void addBeat(TGMeasure measure,TGBeat beat){
55 		//Verifico si entra en el compas
56 		//if(validateDuration(measure,beat,false,false)){
57 
58 			//Agrego el beat
59 			measure.addBeat(beat);
60 		//}
61 	}
62 
removeBeat(TGBeat beat)63 	public void removeBeat(TGBeat beat){
64 		beat.getMeasure().removeBeat(beat);
65 	}
66 
removeBeat(TGMeasure measure,long start,boolean moveNextComponents)67 	public void removeBeat(TGMeasure measure,long start,boolean moveNextComponents){
68 		TGBeat beat = getBeat(measure, start);
69 		if(beat != null){
70 			removeBeat(beat, moveNextComponents);
71 		}
72 	}
73 
74 	/**
75 	 * Elimina un silencio del compas.
76 	 * si se asigna moveNextComponents = true. los componentes que le siguen
77 	 * se moveran para completar el espacio vacio que dejo el silencio
78 	 */
removeBeat(TGBeat beat,boolean moveNextBeats)79 	public void removeBeat(TGBeat beat,boolean moveNextBeats){
80 		TGMeasure measure = beat.getMeasure();
81 
82 		removeBeat(beat);
83 		if(moveNextBeats){
84 			TGDuration minimumDuration = getMinimumDuration(beat);
85 			long start = beat.getStart();
86 			long length = (minimumDuration != null ? minimumDuration.getTime() : 0);
87 
88 			TGBeat next = getNextBeat(measure.getBeats(),beat);
89 			if(next != null){
90 				length = next.getStart() - start;
91 			}
92 			moveBeatsInMeasure(beat.getMeasure(),start + length,-length, minimumDuration);
93 		}
94 	}
95 
removeEmptyBeats(TGMeasure measure)96 	public void removeEmptyBeats(TGMeasure measure){
97 		List beats = new ArrayList();
98 		Iterator it = measure.getBeats().iterator();
99 		while(it.hasNext()){
100 			TGBeat beat = (TGBeat)it.next();
101 			boolean emptyBeat = true;
102 			for( int v = 0; v < beat.countVoices() ; v ++){
103 				TGVoice voice = beat.getVoice( v );
104 				if(!voice.isEmpty()){
105 					emptyBeat = false;
106 				}
107 			}
108 			if( emptyBeat ){
109 				beats.add( beat );
110 			}
111 		}
112 
113 		it = beats.iterator();
114 		while(it.hasNext()){
115 			TGBeat beat = (TGBeat)it.next();
116 			this.removeBeat( beat );
117 		}
118 	}
119 
removeBeatsBeforeEnd(TGMeasure measure,long fromStart)120 	public void removeBeatsBeforeEnd(TGMeasure measure,long fromStart){
121 		List beats = getBeatsBeforeEnd( measure.getBeats() , fromStart);
122 		Iterator it = beats.iterator();
123 		while(it.hasNext()){
124 			TGBeat beat = (TGBeat) it.next();
125 			removeBeat(beat);
126 		}
127 	}
128 
removeBeatsBeetween(TGMeasure measure,long p1, long p2)129 	public void removeBeatsBeetween(TGMeasure measure,long p1, long p2){
130 		List beats = getBeatsBeetween( measure.getBeats() , p1, p2 );
131 		Iterator it = beats.iterator();
132 		while(it.hasNext()){
133 			TGBeat beat = (TGBeat) it.next();
134 			removeBeat(beat);
135 		}
136 	}
137 
addNote(TGMeasure measure,long start, TGNote note, TGDuration duration, int voice)138 	public void addNote(TGMeasure measure,long start, TGNote note, TGDuration duration, int voice){
139 		TGBeat beat = getBeat(measure, start);
140 		if(beat != null){
141 			addNote(beat, note, duration, voice);
142 		}
143 	}
144 
addNote(TGBeat beat, TGNote note, TGDuration duration, int voice)145 	public void addNote(TGBeat beat, TGNote note, TGDuration duration, int voice){
146 		addNote(beat, note, duration, beat.getStart(),voice);
147 	}
148 
addNote(TGBeat beat, TGNote note, TGDuration duration, long start, int voice)149 	public void addNote(TGBeat beat, TGNote note, TGDuration duration, long start, int voice){
150 		boolean emptyVoice = beat.getVoice( voice ).isEmpty();
151 		if( emptyVoice ){
152 			beat.getVoice( voice ).setEmpty( false );
153 		}
154 
155 		//Verifico si entra en el compas
156 		if(validateDuration(beat.getMeasure(),beat, voice, duration,true,true)){
157 			//Borro lo que haya en la misma posicion
158 			for( int v = 0 ; v < beat.countVoices() ; v ++ ){
159 				removeNote(beat.getMeasure(),beat.getStart(), v, note.getString(), false);
160 			}
161 
162 			duration.copy(beat.getVoice(voice).getDuration());
163 
164 			//trato de agregar un silencio similar al lado
165 			tryChangeSilenceAfter(beat.getMeasure(),beat.getVoice(voice));
166 
167 			// Despues de cambiar la duracion, verifico si hay un beat mejor para agregar la nota.
168 			TGVoice realVoice = beat.getVoice(voice);
169 			if(realVoice.getBeat().getStart() != start){
170 				TGVoice beatIn = getVoiceIn(realVoice.getBeat().getMeasure(), start, voice);
171 				if( beatIn != null ) {
172 					realVoice = beatIn;
173 				}
174 			}
175 			realVoice.addNote(note);
176 		}else{
177 			beat.getVoice( voice ).setEmpty( emptyVoice );
178 		}
179 	}
180 
removeNote(TGNote note, boolean checkRestBeat)181 	public void removeNote(TGNote note, boolean checkRestBeat){
182 		//note.getVoice().removeNote(note);
183 		TGVoice voice = note.getVoice();
184 		if( voice != null ){
185 			// Remove the note
186 			voice.removeNote(note);
187 
188 			TGBeat beat = voice.getBeat();
189 			if(checkRestBeat && beat.isRestBeat()){
190 				//Anulo un posible stroke
191 				beat.getStroke().setDirection( TGStroke.STROKE_NONE );
192 
193 				//Borro un posible acorde
194 				if( beat.getMeasure() != null ){
195 					removeChord(beat.getMeasure(), beat.getStart());
196 				}
197 			}
198 		}
199 	}
200 
removeNote(TGNote note)201 	public void removeNote(TGNote note){
202 		this.removeNote(note, true);
203 	}
204 
removeNote(TGMeasure measure,long start, int voiceIndex,int string)205 	public void removeNote(TGMeasure measure,long start, int voiceIndex,int string){
206 		this.removeNote(measure, start, voiceIndex, string, true);
207 	}
208 
209 	/**
210 	 * Elimina los Componentes que empiecen en Start y esten en la misma cuerda
211 	 * Si hay un Silencio lo borra sin importar la cuerda
212 	 */
removeNote(TGMeasure measure,long start, int voiceIndex,int string, boolean checkRestBeat)213 	public void removeNote(TGMeasure measure,long start, int voiceIndex,int string, boolean checkRestBeat){
214 		TGBeat beat = getBeat(measure, start);
215 		if(beat != null){
216 			TGVoice voice = beat.getVoice(voiceIndex);
217 			for( int i = 0; i < voice.countNotes(); i ++){
218 				TGNote note = voice.getNote(i);
219 				if(note.getString() == string){
220 					removeNote(note , checkRestBeat);
221 					return;
222 				}
223 			}
224 		}
225 	}
226 
removeNotesAfterString(TGMeasure measure,int string)227 	public void removeNotesAfterString(TGMeasure measure,int string){
228 		List notesToRemove = new ArrayList();
229 
230 		Iterator beats = measure.getBeats().iterator();
231 		while(beats.hasNext()){
232 			TGBeat beat = (TGBeat)beats.next();
233 			for(int v = 0; v < beat.countVoices(); v ++){
234 				TGVoice voice = beat.getVoice( v );
235 				Iterator notes = voice.getNotes().iterator();
236 				while(notes.hasNext()){
237 					TGNote note = (TGNote)notes.next();
238 					if(note.getString() > string){
239 						notesToRemove.add(note);
240 					}
241 				}
242 			}
243 		}
244 		Iterator it = notesToRemove.iterator();
245 		while(it.hasNext()){
246 			TGNote note = (TGNote)it.next();
247 			removeNote(note);
248 		}
249 	}
250 
251 	/**
252 	 * Retorna Todas las Notas en la posicion Start
253 	 */
getNotes(TGMeasure measure,long start)254 	public List getNotes(TGMeasure measure,long start){
255 		List notes = new ArrayList();
256 
257 		TGBeat beat = getBeat(measure, start);
258 		if(beat != null){
259 			for(int v = 0 ; v < beat.countVoices(); v ++){
260 				TGVoice voice = beat.getVoice( v );
261 				Iterator it = voice.getNotes().iterator();
262 				while(it.hasNext()){
263 					TGNote note = (TGNote)it.next();
264 					notes.add(note);
265 				}
266 			}
267 		}
268 		return notes;
269 	}
270 
271 	/**
272 	 * Retorna Todas las Notas en el pulso
273 	 */
getNotes(TGBeat beat)274 	public List getNotes(TGBeat beat){
275 		List notes = new ArrayList();
276 
277 		if(beat != null){
278 			for(int v = 0 ; v < beat.countVoices(); v ++){
279 				TGVoice voice = beat.getVoice( v );
280 				if( !voice.isEmpty() && !voice.isRestVoice() ){
281 					Iterator it = voice.getNotes().iterator();
282 					while(it.hasNext()){
283 						TGNote note = (TGNote)it.next();
284 						notes.add(note);
285 					}
286 				}
287 			}
288 		}
289 		return notes;
290 	}
291 
292 	/**
293 	 * Retorna la Nota en la posicion y cuerda
294 	 */
getNote(TGMeasure measure,long start,int string)295 	public TGNote getNote(TGMeasure measure,long start,int string) {
296 		TGBeat beat = getBeat(measure, start);
297 		if(beat != null){
298 			return getNote(beat, string);
299 		}
300 		return null;
301 	}
302 
303 	/**
304 	 * Retorna la Nota en la cuerda
305 	 */
getNote(TGBeat beat,int string)306 	public TGNote getNote(TGBeat beat,int string) {
307 		for( int v = 0; v < beat.countVoices(); v ++){
308 			TGVoice voice = beat.getVoice(v);
309 			if(!voice.isEmpty()){
310 				TGNote note = getNote(voice, string);
311 				if(note != null){
312 					return note;
313 				}
314 			}
315 		}
316 		return null;
317 	}
318 
getNote(TGVoice voice,int string)319 	public TGNote getNote(TGVoice voice,int string) {
320 		Iterator it = voice.getNotes().iterator();
321 		while(it.hasNext()){
322 			TGNote note = (TGNote)it.next();
323 			if (note.getString() == string) {
324 				return note;
325 			}
326 		}
327 		return null;
328 	}
329 
getPreviousNote(TGMeasure measure,long start, int voiceIndex, int string)330 	public TGNote getPreviousNote(TGMeasure measure,long start, int voiceIndex, int string) {
331 		TGBeat beat = getBeat(measure, start);
332 		if( beat != null ){
333 			TGBeat previous = getPreviousBeat(measure.getBeats(),beat);
334 			while(previous != null){
335 				TGVoice voice = previous.getVoice(voiceIndex);
336 				if(!voice.isEmpty()){
337 					for (int i = 0; i < voice.countNotes(); i++) {
338 						TGNote current = voice.getNote(i);
339 						if (current.getString() == string) {
340 							return current;
341 						}
342 					}
343 				}
344 				previous = getPreviousBeat(measure.getBeats(),previous);
345 			}
346 		}
347 		return null;
348 	}
349 
getNextNote(TGMeasure measure,long start, int voiceIndex, int string)350 	public TGNote getNextNote(TGMeasure measure,long start, int voiceIndex, int string) {
351 		TGBeat beat = getBeat(measure, start);
352 		if( beat != null ){
353 			TGBeat next = getNextBeat(measure.getBeats(),beat);
354 			while(next != null){
355 				TGVoice voice = next.getVoice(voiceIndex);
356 				if(!voice.isEmpty()){
357 					for (int i = 0; i < voice.countNotes(); i++) {
358 						TGNote current = voice.getNote(i);
359 						if (current.getString() == string) {
360 							return current;
361 						}
362 					}
363 				}
364 				next = getNextBeat(measure.getBeats(),next);
365 			}
366 		}
367 		return null;
368 	}
369 
getMinimumDuration(TGBeat beat)370 	public TGDuration getMinimumDuration(TGBeat beat){
371 		TGDuration minimumDuration = null;
372 		for(int v = 0; v < beat.countVoices(); v ++){
373 			TGVoice voice = beat.getVoice( v );
374 			if( !voice.isEmpty() ){
375 				if(minimumDuration == null || voice.getDuration().getTime() < minimumDuration.getTime()){
376 					minimumDuration = voice.getDuration();
377 				}
378 			}
379 		}
380 		return minimumDuration;
381 	}
382 
getBeat(TGTrack track,long start)383 	public TGBeat getBeat(TGTrack track,long start) {
384 		Iterator measures = track.getMeasures();
385 		while( measures.hasNext() ){
386 			TGMeasure measure = (TGMeasure)measures.next();
387 			Iterator beats = measure.getBeats().iterator();
388 			while(beats.hasNext()){
389 				TGBeat beat = (TGBeat)beats.next();
390 				if (beat.getStart() == start) {
391 					return beat;
392 				}
393 			}
394 		}
395 		return null;
396 	}
397 	/**
398 	 * Retorna las Nota en la posicion y cuerda
399 	 */
getBeat(TGMeasure measure,long start)400 	public TGBeat getBeat(TGMeasure measure,long start) {
401 		Iterator it = measure.getBeats().iterator();
402 		while(it.hasNext()){
403 			TGBeat beat = (TGBeat)it.next();
404 			if (beat.getStart() == start) {
405 				return beat;
406 			}
407 		}
408 		return null;
409 	}
410 
411 	/**
412 	 * Retorna las Nota en la posicion y cuerda
413 	 */
getBeatIn(TGMeasure measure,long start)414 	public TGBeat getBeatIn(TGMeasure measure,long start) {
415 		TGBeat beatIn = null;
416 		Iterator it = measure.getBeats().iterator();
417 		while(it.hasNext()){
418 			TGBeat beat = (TGBeat)it.next();
419 			TGDuration duration = getMinimumDuration(beat);
420 			if (beat.getStart() <= start && (beat.getStart() + duration.getTime() > start)) {
421 				if(beatIn == null || beat.getStart() > beatIn.getStart()){
422 					beatIn = beat;
423 				}
424 			}
425 		}
426 		return beatIn;
427 	}
428 
429 	/**
430 	 * Retorna las Nota en la posicion y cuerda
431 	 */
getVoiceIn(TGMeasure measure,long start, int voiceIndex)432 	public TGVoice getVoiceIn(TGMeasure measure,long start, int voiceIndex) {
433 		Iterator it = measure.getBeats().iterator();
434 		while(it.hasNext()){
435 			TGBeat beat = (TGBeat)it.next();
436 			TGVoice voice = beat.getVoice(voiceIndex);
437 			if (!voice.isEmpty() && beat.getStart() <= start && (beat.getStart() + voice.getDuration().getTime() > start)) {
438 				return voice;
439 			}
440 		}
441 		return null;
442 	}
443 
444 	/**
445 	 * Retorna el Siguiente Componente
446 	 */
getNextBeat(List beats,TGBeat beat)447 	public TGBeat getNextBeat(List beats,TGBeat beat) {
448 		TGBeat next = null;
449 		for (int i = 0; i < beats.size(); i++) {
450 			TGBeat current = (TGBeat) beats.get(i);
451 			if (current.getStart() > beat.getStart()) {
452 				if (next == null) {
453 					next = current;
454 				} else if (current.getStart() < next.getStart()) {
455 					next = current;
456 				} /*else if (current.getStart() == next.getStart() && current.getDuration().getTime() <= next.getDuration().getTime()) {
457 					next = current;
458 				}*/
459 			}
460 		}
461 		return next;
462 	}
463 
464 	/**
465 	 * Retorna el Componente Anterior
466 	 */
getPreviousBeat(List beats,TGBeat beat)467 	public TGBeat getPreviousBeat(List beats,TGBeat beat) {
468 		TGBeat previous = null;
469 		for (int i = 0; i < beats.size(); i++) {
470 			TGBeat current = (TGBeat) beats.get(i);
471 			if (current.getStart() < beat.getStart()) {
472 				if (previous == null) {
473 					previous = current;
474 				} else if (current.getStart() > previous.getStart()) {
475 					previous = current;
476 				} /*else if (current.getStart() == previous.getStart() && current.getDuration().getTime() <= previous.getDuration().getTime()) {
477 					previous = current;
478 				}*/
479 			}
480 		}
481 		return previous;
482 	}
483 
484 	/**
485 	 * Retorna el Primer Componente
486 	 */
getFirstBeat(List components)487 	public TGBeat getFirstBeat(List components) {
488 		TGBeat first = null;
489 		for (int i = 0; i < components.size(); i++) {
490 			TGBeat component = (TGBeat) components.get(i);
491 			if (first == null || component.getStart() < first.getStart()) {
492 				first = component;
493 			}
494 		}
495 		return first;
496 	}
497 
498 	/**
499 	 * Retorna el Ultimo Componente
500 	 */
getLastBeat(List components)501 	public TGBeat getLastBeat(List components) {
502 		TGBeat last = null;
503 		for (int i = 0; i < components.size(); i++) {
504 			TGBeat component = (TGBeat) components.get(i);
505 			if (last == null || last.getStart() < component.getStart()) {
506 				last = component;
507 			}
508 		}
509 		return last;
510 	}
511 
512 	/**
513 	 * Retorna el Siguiente Componente
514 	 */
515 	/*
516 	public TGBeat getNextRestBeat(List beats,TGBeat component) {
517 		TGBeat next = getNextBeat(beats, component);
518 		while(next != null && !next.isRestBeat()){
519 			next = getNextBeat(beats, next);
520 		}
521 		return next;
522 	}
523 	*/
524 
525 	/**
526 	 * Retorna Todos los desde Start hasta el final del compas
527 	 */
getBeatsBeforeEnd(List beats,long fromStart)528 	public List getBeatsBeforeEnd(List beats,long fromStart) {
529 		List list = new ArrayList();
530 		Iterator it = beats.iterator();
531 		while(it.hasNext()){
532 			TGBeat current = (TGBeat)it.next();
533 			if (current.getStart() >= fromStart) {
534 				list.add(current);
535 			}
536 		}
537 		return list;
538 	}
539 
getBeatsBeetween(List beats,long p1, long p2)540 	public List getBeatsBeetween(List beats,long p1, long p2) {
541 		List list = new ArrayList();
542 		Iterator it = beats.iterator();
543 		while(it.hasNext()){
544 			TGBeat current = (TGBeat)it.next();
545 			if (current.getStart() >= p1 && current.getStart() < p2 ) {
546 				list.add(current);
547 			}
548 		}
549 		return list;
550 	}
551 
locateBeat( TGBeat beat, TGTrack track , boolean newMeasureAlsoForRestBeats)552 	public void locateBeat( TGBeat beat, TGTrack track , boolean newMeasureAlsoForRestBeats) {
553 		if( beat.getMeasure() != null ){
554 			beat.getMeasure().removeBeat(beat);
555 			beat.setMeasure(null);
556 		}
557 		TGMeasure newMeasure = getSongManager().getTrackManager().getMeasureAt(track, beat.getStart() );
558 		if( newMeasure == null ){
559 			boolean createNewMeasure = newMeasureAlsoForRestBeats;
560 			if( !createNewMeasure ){
561 				createNewMeasure = ( !beat.isRestBeat() || beat.isTextBeat() );
562 			}
563 			if( createNewMeasure ){
564 
565 				while( newMeasure == null && beat.getStart() >= TGDuration.QUARTER_TIME){
566 					getSongManager().addNewMeasureBeforeEnd();
567 					newMeasure = getSongManager().getTrackManager().getMeasureAt(track, beat.getStart() );
568 				}
569 			}
570 		}
571 		if( newMeasure != null ){
572 			long mStart = newMeasure.getStart();
573 			long mLength = newMeasure.getLength();
574 			long bStart = beat.getStart();
575 			for( int v = 0 ; v < beat.countVoices() ; v ++ ){
576 				TGVoice voice = beat.getVoice( v );
577 				long vDuration = voice.getDuration().getTime();
578 				if(!voice.isEmpty() && (bStart + vDuration) > (mStart + mLength) ){
579 					long vTiedDuration = ( (bStart + vDuration) - (mStart + mLength) );
580 					vDuration -= vTiedDuration;
581 					if( vDuration > 0 ){
582 						TGDuration duration = TGDuration.fromTime(getSongManager().getFactory(), vDuration);
583 						if( duration != null ){
584 							duration.copy( voice.getDuration() );
585 						}
586 					}
587 					if( vTiedDuration > 0 ) {
588 						TGDuration newVoiceDuration = TGDuration.fromTime(getSongManager().getFactory(), vTiedDuration);
589 						if( newVoiceDuration != null ){
590 							long newBeatStart = (bStart + vDuration);
591 							TGBeat newBeat = getBeat(track, newBeatStart);
592 							if( newBeat == null ){
593 								newBeat = getSongManager().getFactory().newBeat();
594 								newBeat.setStart( (bStart + vDuration) );
595 							}
596 							TGVoice newVoice = newBeat.getVoice( v );
597 							for( int n = 0 ; n < voice.countNotes() ; n ++ ){
598 								TGNote note = voice.getNote( n );
599 								TGNote newNote = getSongManager().getFactory().newNote();
600 								newNote.setTiedNote( true );
601 								newNote.setValue( note.getValue() );
602 								newNote.setString( note.getString() );
603 								newNote.setVelocity( note.getVelocity() );
604 								newVoice.addNote( newNote );
605 							}
606 							newVoice.setEmpty( false );
607 							newVoiceDuration.copy( newVoice.getDuration() );
608 
609 							locateBeat(newBeat, track, newMeasureAlsoForRestBeats);
610 						}
611 					}
612 				}
613 			}
614 
615 			newMeasure.addBeat(beat);
616 		}
617 	}
618 
moveOutOfBoundsBeatsToNewMeasure(TGMeasure measure)619 	public void moveOutOfBoundsBeatsToNewMeasure(TGMeasure measure){
620 		this.moveOutOfBoundsBeatsToNewMeasure(measure, true );
621 	}
622 
moveOutOfBoundsBeatsToNewMeasure(TGMeasure measure, boolean newMeasureAlsoForRestBeats )623 	public void moveOutOfBoundsBeatsToNewMeasure(TGMeasure measure, boolean newMeasureAlsoForRestBeats ){
624 		List beats = new ArrayList();
625 		long mStart = measure.getStart();
626 		long mLength = measure.getLength();
627 		for( int i = 0; i < measure.countBeats() ; i ++ ){
628 			TGBeat beat = measure.getBeat( i );
629 			if( beat.getStart() < mStart || beat.getStart() >= mStart + mLength ){
630 				beats.add( beat );
631 			}
632 			else{
633 				long bStart = beat.getStart();
634 				for( int v = 0 ; v < beat.countVoices() ; v ++ ){
635 					TGVoice voice = beat.getVoice( v );
636 					long vDuration = voice.getDuration().getTime();
637 					if(!voice.isEmpty() && (bStart + vDuration) > (mStart + mLength) ){
638 						beats.add( beat );
639 					}
640 				}
641 			}
642 		}
643 		while( !beats.isEmpty() ){
644 			TGBeat beat = (TGBeat)beats.get( 0 );
645 			if( beat.getMeasure() != null ){
646 				beat.getMeasure().removeBeat(beat);
647 				beat.setMeasure(null);
648 			}
649 			this.locateBeat(beat, measure.getTrack(), newMeasureAlsoForRestBeats);
650 
651 			beats.remove(0);
652 		}
653 	}
654 
moveBeatsInMeasure(TGMeasure measure,long start,long theMove, TGDuration fillDuration)655 	public boolean moveBeatsInMeasure(TGMeasure measure,long start,long theMove, TGDuration fillDuration){
656 		if( theMove == 0 ){
657 			return false;
658 		}
659 		boolean success = true;
660 		long measureStart = measure.getStart();
661 		long measureEnd =  (measureStart + measure.getLength());
662 
663 		// Muevo los componentes
664 		List beatsToMove = getBeatsBeforeEnd(measure.getBeats(),start);
665 		moveBeats(beatsToMove,theMove);
666 
667 		if(success){
668 			List beatsToRemove = new ArrayList();
669 			List beats = new ArrayList(measure.getBeats());
670 
671 			// Verifica los silencios a eliminar al principio del compas
672 			TGBeat first = getFirstBeat( beats );
673 			while(first != null && first.isRestBeat() && !first.isTextBeat() && first.getStart() < measureStart){
674 				beats.remove(first);
675 				beatsToRemove.add(first);
676 				first = getNextBeat( beats,first);
677 			}
678 
679 			// Verifica los silencios a eliminar al final del compas
680 			TGBeat last = getLastBeat(beats);
681 			TGDuration lastDuration = (last != null ? getMinimumDuration(last) : null);
682 			while(last != null && lastDuration != null && last.isRestBeat() && !last.isTextBeat()  && (last.getStart() + lastDuration.getTime() ) > measureEnd  ){
683 				beats.remove(last);
684 				beatsToRemove.add(last);
685 				last = getPreviousBeat(beats,last);
686 				lastDuration = (last != null ? getMinimumDuration(last) : null);
687 			}
688 
689 			// Si el primer o ultimo componente, quedan fuera del compas, entonces el movimiento no es satisfactorio
690 			if(first != null && last != null && lastDuration != null){
691 				if(first.getStart() < measureStart || (last.getStart() + lastDuration.getTime()) > measureEnd){
692 					success = false;
693 				}
694 			}
695 
696 			if(success){
697 				// Elimino los silencios que quedaron fuera del compas.
698 				Iterator it = beatsToRemove.iterator();
699 				while( it.hasNext() ){
700 					TGBeat beat = (TGBeat)it.next();
701 					removeBeat(beat);
702 				}
703 
704 				// Se crean silencios en los espacios vacios, si la duracion fue especificada.
705 				if( fillDuration != null ){
706 					if( theMove < 0 ){
707 						last = getLastBeat(measure.getBeats());
708 						lastDuration = (last != null ? getMinimumDuration(last) : null);
709 						TGBeat beat = getSongManager().getFactory().newBeat();
710 						beat.setStart( (last != null && lastDuration != null ? last.getStart()  + lastDuration.getTime() : start  )  );
711 						if( (beat.getStart() + fillDuration.getTime()) <= measureEnd ){
712 							for(int v = 0; v < beat.countVoices(); v ++){
713 								TGVoice voice = beat.getVoice(v);
714 								voice.setEmpty(false);
715 								fillDuration.copy( voice.getDuration() );
716 							}
717 							addBeat(measure, beat );
718 						}
719 					}
720 					else{
721 						first = getFirstBeat(getBeatsBeforeEnd(measure.getBeats(),start));
722 						TGBeat beat = getSongManager().getFactory().newBeat();
723 						beat.setStart( start );
724 						if( (beat.getStart() + fillDuration.getTime()) <= (first != null ?first.getStart() : measureEnd ) ){
725 							for(int v = 0; v < beat.countVoices(); v ++){
726 								TGVoice voice = beat.getVoice(v);
727 								voice.setEmpty(false);
728 								fillDuration.copy( voice.getDuration() );
729 							}
730 							addBeat(measure, beat );
731 						}
732 					}
733 				}
734 			}
735 		}
736 
737 		// Si el movimiento no es satisfactorio, regreso todo como estaba
738 		if(! success ){
739 			moveBeats(beatsToMove,-theMove);
740 		}
741 
742 		return success;
743 	}
744 
moveAllBeats(TGMeasure measure,long theMove)745 	public void moveAllBeats(TGMeasure measure,long theMove){
746 		moveBeats(measure.getBeats(),theMove);
747 	}
748 
moveBeats(TGMeasure measure, long start, long theMove)749 	public void moveBeats(TGMeasure measure, long start, long theMove){
750 		moveBeats(getBeatsBeforeEnd(measure.getBeats(), start),theMove);
751 	}
752 
753 	/**
754 	 * Mueve los componentes
755 	 */
moveBeats(List beats,long theMove)756 	private void moveBeats(List beats,long theMove){
757 		Iterator it = beats.iterator();
758 		while(it.hasNext()){
759 			TGBeat beat = (TGBeat)it.next();
760 			moveBeat(beat,theMove);
761 		}
762 	}
763 
764 	/**
765 	 * Mueve el componente
766 	 */
moveBeat(TGBeat beat,long theMove)767 	private void moveBeat(TGBeat beat,long theMove){
768 		//obtengo el start viejo
769 		long start = beat.getStart();
770 
771 		//asigno el nuevo start
772 		beat.setStart(start + theMove);
773 	}
774 
cleanBeat(TGBeat beat)775 	public void cleanBeat(TGBeat beat){
776 		beat.getStroke().setDirection( TGStroke.STROKE_NONE );
777 		if( beat.getText() != null ){
778 			beat.removeText();
779 		}
780 		if( beat.getChord() != null){
781 			beat.removeChord();
782 		}
783 
784 		this.cleanBeatNotes(beat);
785 	}
786 
cleanBeatNotes(TGBeat beat)787 	public void cleanBeatNotes(TGBeat beat){
788 		for(int v = 0; v < beat.countVoices(); v ++){
789 			cleanVoiceNotes(beat.getVoice( v ));
790 		}
791 	}
792 
cleanBeatNotes(TGMeasure measure, long start)793 	public void cleanBeatNotes(TGMeasure measure, long start){
794 		TGBeat beat = getBeat(measure, start);
795 		if(beat != null){
796 			cleanBeatNotes(beat);
797 		}
798 	}
799 
cleanVoiceNotes(TGVoice voice)800 	public void cleanVoiceNotes(TGVoice voice){
801 		if(!voice.isEmpty()){
802 			while(voice.countNotes() > 0 ){
803 				TGNote note = voice.getNote(0);
804 				removeNote(note);
805 			}
806 		}
807 	}
808 	/**
809 	 * Agrega el acorde al compas
810 	 */
addChord(TGMeasure measure,long start, TGChord chord)811 	public void addChord(TGMeasure measure,long start, TGChord chord){
812 		TGBeat beat = getBeat(measure, start);
813 		if(beat != null){
814 			addChord(beat, chord);
815 		}
816 	}
817 
818 	/**
819 	 * Agrega el acorde al compas
820 	 */
addChord(TGBeat beat,TGChord chord)821 	public void addChord(TGBeat beat,TGChord chord){
822 		beat.removeChord();
823 		beat.setChord(chord);
824 	}
825 
826 	/**
827 	 * Retorna el acorde en la position
828 	 */
getChord(TGMeasure measure,long start)829 	public TGChord getChord(TGMeasure measure,long start) {
830 		TGBeat beat = getBeat(measure, start);
831 		if(beat != null){
832 			return beat.getChord();
833 		}
834 		return null;
835 	}
836 
837 	/**
838 	 * Borra el acorde en la position
839 	 */
removeChord(TGMeasure measure,long start)840 	public void removeChord(TGMeasure measure,long start) {
841 		TGBeat beat = getBeat(measure, start);
842 		if(beat != null){
843 			beat.removeChord();
844 		}
845 	}
846 
847 	/**
848 	 * Agrega el texto al compas
849 	 */
addText(TGMeasure measure,long start, TGText text)850 	public void addText(TGMeasure measure,long start, TGText text){
851 		TGBeat beat = getBeat(measure, start);
852 		if(beat != null){
853 			addText(beat, text);
854 		}
855 	}
856 
857 	/**
858 	 * Agrega el texto al compas
859 	 */
addText(TGBeat beat,TGText text)860 	public void addText(TGBeat beat,TGText text){
861 		beat.removeText();
862 		if(!text.isEmpty()){
863 			beat.setText(text);
864 		}
865 	}
866 
867 	/**
868 	 * Retorna el texto en la position
869 	 */
getText(TGMeasure measure,long start)870 	public TGText getText(TGMeasure measure,long start) {
871 		TGBeat beat = getBeat(measure, start);
872 		if(beat != null){
873 			return beat.getText();
874 		}
875 		return null;
876 	}
877 
878 	/**
879 	 * Borra el texto en el pulso
880 	 */
removeText(TGBeat beat)881 	public void removeText(TGBeat beat){
882 		beat.removeText();
883 	}
884 
885 	/**
886 	 * Borra el texto en la position
887 	 */
removeText(TGMeasure measure,long start)888 	public boolean removeText(TGMeasure measure,long start) {
889 		TGBeat beat = getBeat(measure, start);
890 		if(beat != null){
891 			removeText(beat);
892 			return true;
893 		}
894 		return false;
895 	}
896 
cleanMeasure(TGMeasure measure)897 	public void cleanMeasure(TGMeasure measure){
898 		while( measure.countBeats() > 0){
899 			removeBeat( measure.getBeat(0));
900 		}
901 	}
902 
903 	/**
904 	 * Mueve la nota a la cuerda de arriba
905 	 */
shiftNoteUp(TGMeasure measure,long start,int string)906 	public int shiftNoteUp(TGMeasure measure,long start,int string){
907 		return shiftNote(measure, start, string,-1);
908 	}
909 
910 	/**
911 	 * Mueve la nota a la cuerda de abajo
912 	 */
shiftNoteDown(TGMeasure measure,long start,int string)913 	public int shiftNoteDown(TGMeasure measure,long start,int string){
914 		return shiftNote(measure, start, string,1);
915 	}
916 
917 	/**
918 	 * Mueve la nota a la siguiente cuerda
919 	 */
shiftNote(TGMeasure measure,long start,int string,int move)920 	private int shiftNote(TGMeasure measure,long start,int string,int move){
921 		TGNote note = getNote(measure,start,string);
922 		if(note != null){
923 			int nextStringNumber = (note.getString() + move);
924 			while(getNote(measure,start,nextStringNumber) != null){
925 				nextStringNumber += move;
926 			}
927 			if(nextStringNumber >= 1 && nextStringNumber <= measure.getTrack().stringCount()){
928 				TGString currentString = measure.getTrack().getString(note.getString());
929 				TGString nextString = measure.getTrack().getString(nextStringNumber);
930 				int noteValue = (note.getValue() + currentString.getValue());
931 				if(noteValue >= nextString.getValue() && ((nextString.getValue() + 30 > noteValue) || measure.getTrack().isPercussionTrack()) ){
932 					note.setValue(noteValue - nextString.getValue());
933 					note.setString(nextString.getNumber());
934 					return note.getString();
935 				}
936 			}
937 		}
938 		return 0;
939 	}
940 
941 	/**
942 	 * Mueve la nota 1 semitono arriba
943 	 */
moveSemitoneUp(TGMeasure measure,long start,int string)944 	public boolean moveSemitoneUp(TGMeasure measure,long start,int string){
945 		return moveSemitone(measure, start, string,1);
946 	}
947 
948 	/**
949 	 * Mueve la nota 1 semitono abajo
950 	 */
moveSemitoneDown(TGMeasure measure,long start,int string)951 	public boolean moveSemitoneDown(TGMeasure measure,long start,int string){
952 		return moveSemitone(measure, start, string,-1);
953 	}
954 
955 	/**
956 	 * Mueve la nota los semitonos indicados
957 	 */
moveSemitone(TGMeasure measure,long start,int string,int semitones)958 	private boolean moveSemitone(TGMeasure measure,long start,int string,int semitones){
959 		TGNote note = getNote(measure,start,string);
960 		if(note != null){
961 			int newValue = (note.getValue() + semitones);
962 			if(newValue >= 0 && (newValue < 30 || measure.getTrack().isPercussionTrack()) ){
963 				note.setValue(newValue);
964 				return true;
965 			}
966 		}
967 		return false;
968 	}
969 
970 	/**
971 	 * Set the beat stroke
972 	 */
setStroke(TGMeasure measure,long start,int value, int direction)973 	public boolean setStroke(TGMeasure measure,long start,int value, int direction){
974 		TGBeat beat = getBeat(measure, start);
975 		if( beat != null ){
976 			beat.getStroke().setValue(value);
977 			beat.getStroke().setDirection(direction);
978 			return true;
979 		}
980 		return false;
981 	}
982 
983 	/**
984 	 * Verifica si el componente se puede insertar en el compas.
985 	 * si no puede, con la opcion removeSilences, verifica si el motivo por el
986 	 * cual no entra es que lo siguen silencios. de ser asi los borra.
987 	 */
988 	/*
989 	public boolean validateDuration(TGMeasure measure,TGBeat beat,boolean moveNextComponents, boolean setCurrentDuration){
990 		return validateDuration(measure, beat, beat.getDuration(),moveNextComponents, setCurrentDuration);
991 	}
992 
993 
994 	public boolean validateDuration(TGMeasure measure,TGBeat beat,TGDuration duration,boolean moveNextBeats, boolean setCurrentDuration){
995 		int errorMargin = 10;
996 		this.orderBeats(measure);
997 		long measureStart = measure.getStart();
998 		long measureEnd =  (measureStart + measure.getLength());
999 		long beatStart = beat.getStart();
1000 		long beatLength = duration.getTime();
1001 		long beatEnd = (beatStart + beatLength);
1002 		List beats = measure.getBeats();
1003 
1004 		//Verifico si hay un beat en el mismo lugar, y comparo las duraciones.
1005 		TGBeat currentBeat = getBeat(measure,beatStart);
1006 		if(currentBeat != null && beatLength <= currentBeat.getDuration().getTime()){
1007 			return true;
1008 		}
1009 
1010 		//Verifico si hay lugar para meter el beat
1011 		TGBeat nextComponent = getNextBeat(beats,beat);
1012 		if(currentBeat == null){
1013 			if(nextComponent == null && beatEnd < (measureEnd + errorMargin)){
1014 				return true;
1015 			}
1016 			if(nextComponent != null && beatEnd < (nextComponent.getStart() + errorMargin)){
1017 				return true;
1018 			}
1019 		}
1020 
1021 		// Busca si hay espacio disponible de silencios entre el componente y el el que le sigue.. si encuentra lo borra
1022 		if(nextComponent != null && nextComponent.isRestBeat()){
1023 			//Verifico si lo que sigue es un silencio. y lo borro
1024 			long nextBeatEnd = 0;
1025 			List nextBeats = new ArrayList();
1026 			while(nextComponent != null && nextComponent.isRestBeat() && !nextComponent.isTextBeat()){
1027 				nextBeats.add(nextComponent);
1028 				nextBeatEnd = nextComponent.getStart() + nextComponent.getDuration().getTime();
1029 				nextComponent = getNextBeat(beats,nextComponent);
1030 			}
1031 			if(nextComponent == null){
1032 				nextBeatEnd = measureEnd;
1033 			}else if(!nextComponent.isRestBeat() || nextComponent.isTextBeat()){
1034 				nextBeatEnd = nextComponent.getStart();
1035 			}
1036 			if(beatEnd <= (nextBeatEnd + errorMargin)){
1037 				while(!nextBeats.isEmpty()){
1038 					TGBeat currBeat = (TGBeat)nextBeats.get(0);
1039 					nextBeats.remove(currBeat);
1040 					removeBeat(currBeat, false);
1041 				}
1042 				return true;
1043 			}
1044 		}
1045 
1046 		// Busca si hay espacio disponible de silencios entre el componente y el final.. si encuentra mueve todo
1047 		if(moveNextBeats){
1048 			nextComponent = getNextBeat(beats,beat);
1049 			if(nextComponent != null){
1050 				long requiredLength = (beatLength  - (nextComponent.getStart() - beatStart));
1051 				long nextSilenceLength = 0;
1052 				TGBeat nextRestBeat = getNextRestBeat(beats, beat);
1053 				while(nextRestBeat != null && !nextRestBeat.isTextBeat()){
1054 					nextSilenceLength += nextRestBeat.getDuration().getTime();
1055 					nextRestBeat = getNextRestBeat(beats, nextRestBeat);
1056 				}
1057 
1058 				if(requiredLength <= (nextSilenceLength + errorMargin)){
1059 					beats = getBeatsBeforeEnd(measure.getBeats(),nextComponent.getStart());
1060 					while(!beats.isEmpty()){
1061 						TGBeat current = (TGBeat)beats.get(0);
1062 						if(current.isRestBeat() && !current.isTextBeat()){
1063 							requiredLength -= current.getDuration().getTime();
1064 							removeBeat(current, false);
1065 						}else if(requiredLength > 0){
1066 							moveBeat(current,requiredLength);
1067 						}
1068 						beats.remove(0);
1069 					}
1070 					return true;
1071 				}
1072 			}
1073 		}
1074 
1075 		// como ultimo intento, asigno la duracion de cualquier componente existente en el lugar.
1076 		if(setCurrentDuration && currentBeat != null){
1077 			currentBeat.getDuration().copy( duration );
1078 			return true;
1079 		}
1080 		return false;
1081 	}
1082 	*/
1083 	/**
1084 	 * Cambia la Duracion del pulso.
1085 	 */
1086 	/*
1087 	@Deprecated
1088 	public void changeDuration(TGMeasure measure,TGBeat beat,TGDuration duration,boolean tryMove){
1089 		//obtengo la duracion vieja
1090 		TGDuration oldDuration = beat.getDuration().clone(getSongManager().getFactory());
1091 
1092 		//si no entra vuelvo a dejar la vieja
1093 		if(validateDuration(measure,beat, duration,tryMove,false)){
1094 			//se lo agrego a todas las notas en la posicion
1095 			beat.setDuration(duration.clone(getSongManager().getFactory()));
1096 
1097 			//trato de agregar un silencio similar al lado
1098 			tryChangeSilenceAfter(measure,beat);
1099 		}else{
1100 			oldDuration.copy( beat.getDuration() );
1101 		}
1102 	}
1103 	*/
1104 	/*
1105 	@Deprecated
1106 	public void tryChangeSilenceAfter(TGMeasure measure,TGBeat beat){
1107 		autoCompleteSilences(measure);
1108 		TGBeat nextBeat = getNextBeat(measure.getBeats(),beat);
1109 
1110 		long beatEnd = (beat.getStart() + beat.getDuration().getTime());
1111 		long measureEnd = (measure.getStart() + measure.getLength());
1112 		if(nextBeat != null && nextBeat.isRestBeat() && beatEnd <= measureEnd){
1113 			long theMove = (getRealStart(measure,beatEnd)) - getRealStart(measure,nextBeat.getStart());
1114 			if((nextBeat.getStart() + theMove) < measureEnd && (nextBeat.getStart() + nextBeat.getDuration().getTime() + theMove) <= measureEnd){
1115 				moveBeat(nextBeat,theMove);
1116 				changeDuration(measure,nextBeat,beat.getDuration().clone(getSongManager().getFactory()),false);
1117 			}
1118 		}
1119 	}
1120 	*/
1121 	/**
1122 	 * Calcula si hay espacios libres. y crea nuevos silencios
1123 	 */
1124 	/*
1125 	public void autoCompleteSilences(TGMeasure measure){
1126 		List components = measure.getBeats();
1127 
1128 		for( int i = 0; i < TGBeat.MAX_VOICES; i ++ ){
1129 			//TGBeat component = getFirstBeat(components);
1130 			TGVoice component = getFirstVoice(components, i);
1131 
1132 			long start = measure.getStart();
1133 			long end = 0;
1134 			long diff = 0;
1135 
1136 			while (component != null) {
1137 				end = component.getBeat().getStart() + component.getDuration().getTime();
1138 				if(component.getBeat().getStart() > start){
1139 					diff = component.getBeat().getStart() - start;
1140 					if(diff > 0){
1141 						createSilences(measure,start,diff, i);
1142 					}
1143 				}
1144 				start = end;
1145 				component = getNextVoice(components,component.getBeat(), i);
1146 			}
1147 			end = measure.getStart() + measure.getLength();
1148 			diff = end - start;
1149 			if(diff > 0){
1150 				createSilences(measure,start,diff, i);
1151 			}
1152 		}
1153 	}
1154 	*/
autoCompleteSilences(TGMeasure measure)1155 	public void autoCompleteSilences(TGMeasure measure){
1156 		TGBeat beat = getFirstBeat( measure.getBeats() );
1157 		if( beat == null ){
1158 			createSilences(measure, measure.getStart(), measure.getLength(), 0);
1159 			return;
1160 		}
1161 		for( int v = 0 ; v < TGBeat.MAX_VOICES ; v ++ ){
1162 			TGVoice voice = getFirstVoice( measure.getBeats() , v );
1163 			if( voice != null && voice.getBeat().getStart() > measure.getStart() ){
1164 				createSilences(measure, measure.getStart(), (voice.getBeat().getStart() - measure.getStart()), v);
1165 			}
1166 		}
1167 
1168 		long[] start = new long[beat.countVoices()];
1169 		long[] uncompletedLength = new long[beat.countVoices()];
1170 		for( int v = 0; v < uncompletedLength.length; v ++ ){
1171 			start[v] = 0;
1172 			uncompletedLength[v] = 0;
1173 		}
1174 
1175 		while (beat != null) {
1176 			for( int v = 0; v < beat.countVoices(); v ++ ){
1177 				TGVoice voice = beat.getVoice( v );
1178 				if( !voice.isEmpty() ){
1179 					long voiceEnd = (beat.getStart() + voice.getDuration().getTime());
1180 					long nextPosition = (measure.getStart() + measure.getLength());
1181 
1182 					TGVoice nextVoice = getNextVoice(measure.getBeats(), beat, voice.getIndex());
1183 					if(nextVoice != null){
1184 						nextPosition = nextVoice.getBeat().getStart();
1185 					}
1186 					if( voiceEnd < nextPosition ){
1187 						start[v] = voiceEnd;
1188 						uncompletedLength[v] = (nextPosition - voiceEnd);
1189 					}
1190 				}
1191 			}
1192 
1193 			for( int v = 0; v < uncompletedLength.length; v ++ ){
1194 				if( uncompletedLength[v] > 0 ){
1195 					createSilences(measure,start[v],uncompletedLength[v], v);
1196 				}
1197 				start[v] = 0;
1198 				uncompletedLength[v] = 0;
1199 			}
1200 			beat = getNextBeat(measure.getBeats(), beat );
1201 		}
1202 	}
1203 
1204 	/**
1205 	 * Crea Silencios temporarios en base a length
1206 	 */
createSilences(TGMeasure measure,long start,long length, int voiceIndex)1207 	private void createSilences(TGMeasure measure,long start,long length, int voiceIndex){
1208 		long nextStart = start;
1209 		List durations = createDurations(getSongManager().getFactory(),length);
1210 		Iterator it = durations.iterator();
1211 		while(it.hasNext()){
1212 			TGDuration duration = (TGDuration)it.next();
1213 
1214 			boolean isNew = false;
1215 			long beatStart = getRealStart(measure, nextStart);
1216 			TGBeat beat = getBeat(measure, beatStart);
1217 			if( beat == null ){
1218 				beat = getSongManager().getFactory().newBeat();
1219 				beat.setStart( getRealStart(measure, nextStart) );
1220 				isNew = true;
1221 			}
1222 			//TGBeat beat = getSongManager().getFactory().newBeat();
1223 			//beat.setStart( getRealStart(measure, nextStart) );
1224 
1225 			TGVoice voice = beat.getVoice(voiceIndex);
1226 			voice.setEmpty(false);
1227 			duration.copy(voice.getDuration());
1228 
1229 			if( isNew ){
1230 				addBeat(measure,beat);
1231 			}
1232 			// temporal
1233 			//beat.getVoice(0).setEmpty(false);
1234 			//beat.getVoice(1).setEmpty(false);
1235 			// /temporal
1236 
1237 			nextStart += duration.getTime();
1238 		}
1239 	}
1240 
getRealStart(TGMeasure measure,long currStart)1241 	public long getRealStart(TGMeasure measure,long currStart){
1242 		long beatLength = TGSongManager.getDivisionLength(measure.getHeader());
1243 		long start = currStart;
1244 		boolean startBeat = (start % beatLength == 0);
1245 		if(!startBeat){
1246 			TGDuration minDuration = getSongManager().getFactory().newDuration();
1247 			minDuration.setValue(TGDuration.SIXTY_FOURTH);
1248 			minDuration.getDivision().setEnters(3);
1249 			minDuration.getDivision().setTimes(2);
1250 			for(int i = 0;i < minDuration.getTime();i++){
1251 				start ++;
1252 				startBeat = (start % beatLength == 0);
1253 				if(startBeat){
1254 				   break;
1255 				}
1256 			}
1257 			if(!startBeat){
1258 				start = currStart;
1259 			}
1260 		}
1261 		return start;
1262 	}
1263 
1264 	/**
1265 	 * Liga la nota
1266 	 */
changeTieNote(TGMeasure measure,long start,int string)1267 	public void changeTieNote(TGMeasure measure,long start,int string){
1268 		TGNote note = getNote(measure,start,string);
1269 		if(note != null){
1270 			changeTieNote(note);
1271 		}
1272 	}
1273 
1274 	/**
1275 	 * Liga la nota
1276 	 */
changeTieNote(TGNote note)1277 	public void changeTieNote(TGNote note){
1278 		note.setTiedNote(!note.isTiedNote());
1279 		note.getEffect().setDeadNote(false);
1280 	}
1281 
1282 	/**
1283 	 * Agrega un vibrato
1284 	 */
changeVibratoNote(TGMeasure measure,long start,int string)1285 	public void changeVibratoNote(TGMeasure measure,long start,int string){
1286 		TGNote note = getNote(measure,start,string);
1287 		if(note != null){
1288 			note.getEffect().setVibrato(!note.getEffect().isVibrato());
1289 		}
1290 	}
1291 
1292 	/**
1293 	 * Agrega una nota muerta
1294 	 */
changeDeadNote(TGNote note)1295 	public void changeDeadNote(TGNote note){
1296 		note.getEffect().setDeadNote(!note.getEffect().isDeadNote());
1297 		note.setTiedNote(false);
1298 	}
1299 
1300 	/**
1301 	 * Agrega un slide
1302 	 */
changeSlideNote(TGMeasure measure,long start,int string)1303 	public void changeSlideNote(TGMeasure measure,long start,int string){
1304 		TGNote note = getNote(measure,start,string);
1305 		if(note != null){
1306 			note.getEffect().setSlide(!note.getEffect().isSlide());
1307 		}
1308 	}
1309 
1310 	/**
1311 	 * Agrega un hammer
1312 	 */
changeHammerNote(TGMeasure measure,long start,int string)1313 	public void changeHammerNote(TGMeasure measure,long start,int string){
1314 		TGNote note = getNote(measure,start,string);
1315 		if(note != null){
1316 			note.getEffect().setHammer(!note.getEffect().isHammer());
1317 		}
1318 	}
1319 
1320 	/**
1321 	 * Agrega un palm-mute
1322 	 */
changePalmMute(TGMeasure measure,long start,int string)1323 	public void changePalmMute(TGMeasure measure,long start,int string){
1324 		TGNote note = getNote(measure,start,string);
1325 		if(note != null){
1326 			note.getEffect().setPalmMute(!note.getEffect().isPalmMute());
1327 		}
1328 	}
1329 
1330 	/**
1331 	 * Agrega un staccato
1332 	 */
changeStaccato(TGMeasure measure,long start,int string)1333 	public void changeStaccato(TGMeasure measure,long start,int string){
1334 		TGNote note = getNote(measure,start,string);
1335 		if(note != null){
1336 			note.getEffect().setStaccato(!note.getEffect().isStaccato());
1337 		}
1338 	}
1339 
1340 	/**
1341 	 * Agrega un tapping
1342 	 */
changeTapping(TGMeasure measure,long start,int string)1343 	public void changeTapping(TGMeasure measure,long start,int string){
1344 		TGNote note = getNote(measure,start,string);
1345 		if(note != null){
1346 			note.getEffect().setTapping(!note.getEffect().isTapping());
1347 		}
1348 	}
1349 
1350 	/**
1351 	 * Agrega un slapping
1352 	 */
changeSlapping(TGMeasure measure,long start,int string)1353 	public void changeSlapping(TGMeasure measure,long start,int string){
1354 		TGNote note = getNote(measure,start,string);
1355 		if(note != null){
1356 			note.getEffect().setSlapping(!note.getEffect().isSlapping());
1357 		}
1358 	}
1359 
1360 	/**
1361 	 * Agrega un popping
1362 	 */
changePopping(TGMeasure measure,long start,int string)1363 	public void changePopping(TGMeasure measure,long start,int string){
1364 		TGNote note = getNote(measure,start,string);
1365 		if(note != null){
1366 			note.getEffect().setPopping(!note.getEffect().isPopping());
1367 		}
1368 	}
1369 
1370 	/**
1371 	 * Agrega un bend
1372 	 */
changeBendNote(TGMeasure measure,long start,int string,TGEffectBend bend)1373 	public void changeBendNote(TGMeasure measure,long start,int string,TGEffectBend bend){
1374 		TGNote note = getNote(measure,start,string);
1375 		if(note != null){
1376 			note.getEffect().setBend(bend);
1377 		}
1378 	}
1379 
1380 	/**
1381 	 * Agrega un tremoloBar
1382 	 */
changeTremoloBar(TGMeasure measure,long start,int string,TGEffectTremoloBar tremoloBar)1383 	public void changeTremoloBar(TGMeasure measure,long start,int string,TGEffectTremoloBar tremoloBar){
1384 		TGNote note = getNote(measure,start,string);
1385 		if(note != null){
1386 			note.getEffect().setTremoloBar(tremoloBar);
1387 		}
1388 	}
1389 
1390 	/**
1391 	 * Agrega un GhostNote
1392 	 */
changeGhostNote(TGMeasure measure,long start,int string)1393 	public void changeGhostNote(TGMeasure measure,long start,int string){
1394 		TGNote note = getNote(measure,start,string);
1395 		if(note != null){
1396 			note.getEffect().setGhostNote(!note.getEffect().isGhostNote());
1397 		}
1398 	}
1399 
1400 	/**
1401 	 * Agrega un AccentuatedNote
1402 	 */
changeAccentuatedNote(TGMeasure measure,long start,int string)1403 	public void changeAccentuatedNote(TGMeasure measure,long start,int string){
1404 		TGNote note = getNote(measure,start,string);
1405 		if(note != null){
1406 			note.getEffect().setAccentuatedNote(!note.getEffect().isAccentuatedNote());
1407 		}
1408 	}
1409 
1410 	/**
1411 	 * Agrega un GhostNote
1412 	 */
changeHeavyAccentuatedNote(TGMeasure measure,long start,int string)1413 	public void changeHeavyAccentuatedNote(TGMeasure measure,long start,int string){
1414 		TGNote note = getNote(measure,start,string);
1415 		if(note != null){
1416 			note.getEffect().setHeavyAccentuatedNote(!note.getEffect().isHeavyAccentuatedNote());
1417 		}
1418 	}
1419 
1420 	/**
1421 	 * Agrega un harmonic
1422 	 */
changeHarmonicNote(TGMeasure measure,long start,int string,TGEffectHarmonic harmonic)1423 	public void changeHarmonicNote(TGMeasure measure,long start,int string,TGEffectHarmonic harmonic){
1424 		TGNote note = getNote(measure,start,string);
1425 		if(note != null){
1426 			note.getEffect().setHarmonic(harmonic);
1427 		}
1428 	}
1429 
1430 	/**
1431 	 * Agrega un grace
1432 	 */
changeGraceNote(TGMeasure measure,long start,int string,TGEffectGrace grace)1433 	public void changeGraceNote(TGMeasure measure,long start,int string,TGEffectGrace grace){
1434 		TGNote note = getNote(measure,start,string);
1435 		if(note != null){
1436 			note.getEffect().setGrace(grace);
1437 		}
1438 	}
1439 
1440 	/**
1441 	 * Agrega un trill
1442 	 */
changeTrillNote(TGMeasure measure,long start,int string,TGEffectTrill trill)1443 	public void changeTrillNote(TGMeasure measure,long start,int string,TGEffectTrill trill){
1444 		TGNote note = getNote(measure,start,string);
1445 		if(note != null){
1446 			note.getEffect().setTrill(trill);
1447 		}
1448 	}
1449 
1450 	/**
1451 	 * Agrega un tremolo picking
1452 	 */
changeTremoloPicking(TGMeasure measure,long start,int string,TGEffectTremoloPicking tremoloPicking)1453 	public void changeTremoloPicking(TGMeasure measure,long start,int string,TGEffectTremoloPicking tremoloPicking){
1454 		TGNote note = getNote(measure,start,string);
1455 		if(note != null){
1456 			note.getEffect().setTremoloPicking(tremoloPicking);
1457 		}
1458 	}
1459 
1460 	/**
1461 	 * Agrega un fadeIn
1462 	 */
changeFadeIn(TGMeasure measure,long start,int string)1463 	public void changeFadeIn(TGMeasure measure,long start,int string){
1464 		TGNote note = getNote(measure,start,string);
1465 		if(note != null){
1466 			note.getEffect().setFadeIn(!note.getEffect().isFadeIn());
1467 		}
1468 	}
1469 
1470 	/**
1471 	 * Cambia el Velocity
1472 	 */
changeVelocity(int velocity,TGMeasure measure,long start,int string)1473 	public void changeVelocity(int velocity,TGMeasure measure,long start,int string){
1474 		TGNote note = getNote(measure,start,string);
1475 		if(note != null){
1476 			note.setVelocity(velocity);
1477 		}
1478 	}
1479 	/*
1480 	public static List createDurations(TGFactory factory,long time){
1481 		List durations = new ArrayList();
1482 		TGDuration tempDuration = factory.newDuration();
1483 		tempDuration.setValue(TGDuration.WHOLE);
1484 		tempDuration.setDotted(true);
1485 		long tempTime = time;
1486 		boolean finish = false;
1487 		while(!finish){
1488 			long currentDurationTime = tempDuration.getTime();
1489 			if(currentDurationTime <= tempTime){
1490 				durations.add(tempDuration.clone(factory));
1491 				tempTime -= currentDurationTime;
1492 			}else{
1493 				if(tempDuration.isDotted()){
1494 					tempDuration.setDotted(false);
1495 				}else{
1496 					tempDuration.setValue(tempDuration.getValue() * 2);
1497 					tempDuration.setDotted(true);
1498 				}
1499 			}
1500 			if(tempDuration.getValue() > TGDuration.SIXTY_FOURTH){
1501 				finish = true;
1502 			}
1503 		}
1504 		return durations;
1505 	}
1506 	*/
1507 
createDurations(TGFactory factory,long time)1508 	public static List createDurations(TGFactory factory,long time){
1509 		List durations = new ArrayList();
1510 		TGDuration minimum = factory.newDuration();
1511 		minimum.setValue(TGDuration.SIXTY_FOURTH);
1512 		minimum.setDotted(false);
1513 		minimum.setDoubleDotted(false);
1514 		minimum.getDivision().setEnters(3);
1515 		minimum.getDivision().setTimes(2);
1516 
1517 		long missingTime = time;
1518 		while( missingTime > minimum.getTime() ){
1519 			TGDuration duration = TGDuration.fromTime(factory, missingTime, minimum ,  10);
1520 			durations.add( duration.clone(factory) );
1521 			missingTime -= duration.getTime();
1522 		}
1523 		return durations;
1524 	}
1525 
1526 
1527 
1528 
1529 
1530 
1531 
1532 
1533 
1534 
1535 
1536 
1537 
1538 
1539 	/**
1540 	 * Retorna el Siguiente Componente
1541 	 */
getNextVoice(List beats,TGBeat beat, int index)1542 	public TGVoice getNextVoice(List beats,TGBeat beat, int index) {
1543 		TGVoice next = null;
1544 		for (int i = 0; i < beats.size(); i++) {
1545 			TGBeat current = (TGBeat) beats.get(i);
1546 			if (current.getStart() > beat.getStart() && !current.getVoice(index).isEmpty()) {
1547 				if (next == null) {
1548 					next = current.getVoice(index);
1549 				} else if (current.getStart() < next.getBeat().getStart()) {
1550 					next = current.getVoice(index);
1551 				} /*else if (current.getStart() == next.getBeat().getStart() && current.getDuration().getTime() <= next.getDuration().getTime()) {
1552 					next = current.getVoice(index);
1553 				}*/
1554 			}
1555 		}
1556 		return next;
1557 	}
1558 
1559 	/**
1560 	 * Retorna el Componente Anterior
1561 	 */
getPreviousVoice(List beats,TGBeat beat, int index)1562 	public TGVoice getPreviousVoice(List beats,TGBeat beat, int index) {
1563 		TGVoice previous = null;
1564 		for (int i = 0; i < beats.size(); i++) {
1565 			TGBeat current = (TGBeat) beats.get(i);
1566 			if (current.getStart() < beat.getStart() && !current.getVoice(index).isEmpty()) {
1567 				if (previous == null) {
1568 					previous = current.getVoice(index);
1569 				} else if (current.getStart() > previous.getBeat().getStart()) {
1570 					previous = current.getVoice(index);
1571 				} /*else if (current.getStart() == previous.getBeat().getStart() && current.getDuration().getTime() <= previous.getDuration().getTime()) {
1572 					previous = current.getVoice(index);
1573 				}*/
1574 			}
1575 		}
1576 		return previous;
1577 	}
1578 
1579 	/**
1580 	 * Retorna el Primer Componente
1581 	 */
getFirstVoice(List beats, int index)1582 	public TGVoice getFirstVoice(List beats, int index) {
1583 		TGVoice first = null;
1584 		for (int i = 0; i < beats.size(); i++) {
1585 			TGBeat current = (TGBeat) beats.get(i);
1586 			if ( (first == null || current.getStart() < first.getBeat().getStart() ) && !current.getVoice(index).isEmpty()) {
1587 				first = current.getVoice(index);
1588 			}
1589 		}
1590 		return first;
1591 	}
1592 
1593 	/**
1594 	 * Retorna el Ultimo Componente
1595 	 */
getLastVoice(List beats, int index)1596 	public TGVoice getLastVoice(List beats, int index) {
1597 		TGVoice last = null;
1598 		for (int i = 0; i < beats.size(); i++) {
1599 			TGBeat current = (TGBeat) beats.get(i);
1600 			if ( (last == null || last.getBeat().getStart() < current.getStart()) && !current.getVoice(index).isEmpty() ) {
1601 				last = current.getVoice(index);
1602 			}
1603 		}
1604 		return last;
1605 	}
1606 
1607 
1608 	/**
1609 	 * Retorna el Siguiente Componente
1610 	 */
getNextRestVoice(List beats,TGVoice voice)1611 	public TGVoice getNextRestVoice(List beats,TGVoice voice) {
1612 		TGVoice next = getNextVoice(beats, voice.getBeat(), voice.getIndex());
1613 		while(next != null && !next.isRestVoice()){
1614 			next = getNextVoice(beats, next.getBeat(), next.getIndex());
1615 		}
1616 		return next;
1617 	}
1618 
getVoicesBeforeEnd(List beats,long fromStart, int index)1619 	public List getVoicesBeforeEnd(List beats,long fromStart, int index) {
1620 		List list = new ArrayList();
1621 		Iterator it = beats.iterator();
1622 		while(it.hasNext()){
1623 			TGBeat beat = (TGBeat)it.next();
1624 			if (beat.getStart() >= fromStart) {
1625 				TGVoice voice = beat.getVoice(index);
1626 				if(!voice.isEmpty()){
1627 					list.add(voice);
1628 				}
1629 			}
1630 		}
1631 		return list;
1632 	}
1633 
addSilence(TGMeasure measure,long start, TGDuration duration, int voice)1634 	public void addSilence(TGMeasure measure,long start, TGDuration duration, int voice){
1635 		TGBeat beat = getBeat(measure, start);
1636 		if(beat != null){
1637 			addSilence(beat, duration, voice);
1638 		}
1639 	}
1640 
addSilence(TGBeat beat, TGDuration duration, int voice)1641 	public void addSilence(TGBeat beat, TGDuration duration, int voice){
1642 		addSilence(beat, duration, beat.getStart(),voice);
1643 	}
1644 
addSilence(TGBeat beat, TGDuration duration, long start, int voice)1645 	public void addSilence(TGBeat beat, TGDuration duration, long start, int voice){
1646 		boolean emptyVoice = beat.getVoice( voice ).isEmpty();
1647 		if( emptyVoice ){
1648 			beat.getVoice( voice ).setEmpty( false );
1649 		}
1650 
1651 		//Verifico si entra en el compas
1652 		if(validateDuration(beat.getMeasure(),beat, voice, duration,true,true)){
1653 			//Borro lo que haya en la misma posicion
1654 			//removeNote(beat.getMeasure(),beat.getStart(),voice, note.getString());
1655 
1656 			duration.copy(beat.getVoice(voice).getDuration());
1657 
1658 			//trato de agregar un silencio similar al lado
1659 			tryChangeSilenceAfter(beat.getMeasure(),beat.getVoice(voice));
1660 
1661 			// Despues de cambiar la duracion, verifico si hay un beat mejor para agregar el silencio.
1662 			TGVoice realVoice = beat.getVoice(voice);
1663 			if(realVoice.getBeat().getStart() != start){
1664 				TGVoice beatIn = getVoiceIn(realVoice.getBeat().getMeasure(), start, voice);
1665 				if( beatIn != null ) {
1666 					realVoice = beatIn;
1667 				}
1668 			}
1669 			realVoice.setEmpty(false);
1670 		}else{
1671 			beat.getVoice( voice ).setEmpty( emptyVoice );
1672 		}
1673 	}
1674 
removeVoice(TGVoice voice)1675 	public void removeVoice(TGVoice voice){
1676 		voice.setEmpty(true);
1677 
1678 		// Remove the beat If all voices are empty
1679 		TGBeat beat = voice.getBeat();
1680 		for(int i = 0; i < beat.countVoices(); i ++){
1681 			if( !beat.getVoice(i).isEmpty() ){
1682 				return;
1683 			}
1684 		}
1685 		this.removeBeat(beat);
1686 	}
1687 
removeVoice(TGVoice voice,boolean moveNextVoices)1688 	public void removeVoice(TGVoice voice,boolean moveNextVoices){
1689 		removeVoice(voice);
1690 		if(moveNextVoices){
1691 			long start = voice.getBeat().getStart();
1692 			long length = voice.getDuration().getTime();
1693 			TGVoice next = getNextVoice(voice.getBeat().getMeasure().getBeats(),voice.getBeat(),voice.getIndex());
1694 			if(next != null){
1695 				length = next.getBeat().getStart() - start;
1696 			}
1697 			moveVoices(voice.getBeat().getMeasure(),start + length,-length, voice.getIndex(), voice.getDuration());
1698 		}
1699 	}
1700 
removeVoice(TGMeasure measure,long start,int index, boolean moveNextComponents)1701 	public void removeVoice(TGMeasure measure,long start,int index, boolean moveNextComponents){
1702 		TGBeat beat = getBeat(measure, start);
1703 		if(beat != null){
1704 			removeVoice(beat.getVoice(index), moveNextComponents);
1705 		}
1706 	}
1707 
removeVoicesOutOfTime(TGMeasure measure)1708 	public void removeVoicesOutOfTime(TGMeasure measure){
1709 		List voicesToRemove = new ArrayList();
1710 
1711 		long mStart = measure.getStart();
1712 		long mEnd = mStart + measure.getLength();
1713 
1714 		Iterator beats = measure.getBeats().iterator();
1715 		while(beats.hasNext()){
1716 			TGBeat beat = (TGBeat)beats.next();
1717 			for( int v = 0; v < beat.countVoices() ; v ++){
1718 				TGVoice voice = beat.getVoice( v );
1719 				if(!voice.isEmpty()){
1720 					if( beat.getStart() < mStart || (beat.getStart() + voice.getDuration().getTime()) > mEnd){
1721 						voicesToRemove.add( voice );
1722 					}
1723 				}
1724 			}
1725 		}
1726 		Iterator it = voicesToRemove.iterator();
1727 		while(it.hasNext()){
1728 			TGVoice voice = (TGVoice)it.next();
1729 			this.removeVoice( voice );
1730 		}
1731 	}
1732 
removeMeasureVoices(TGMeasure measure,int index)1733 	public void removeMeasureVoices(TGMeasure measure,int index){
1734 		boolean hasNotes = false;
1735 
1736 		List voices = new ArrayList();
1737 		Iterator it = measure.getBeats().iterator();
1738 		while(it.hasNext()){
1739 			TGBeat beat = (TGBeat)it.next();
1740 			TGVoice voice = beat.getVoice(index);
1741 			if(voice.isRestVoice()){
1742 				voices.add(voice);
1743 			}else if(!voice.isEmpty()){
1744 				hasNotes = true;
1745 				break;
1746 			}
1747 		}
1748 
1749 		if( !hasNotes ){
1750 			it = voices.iterator();
1751 			while(it.hasNext()){
1752 				TGVoice voice = (TGVoice)it.next();
1753 				this.removeVoice( voice );
1754 			}
1755 		}
1756 	}
1757 
changeVoiceDirection( TGVoice voice , int direction)1758 	public void changeVoiceDirection( TGVoice voice , int direction){
1759 		voice.setDirection( direction );
1760 	}
1761 
changeDuration(TGMeasure measure,TGBeat beat,TGDuration duration,int voice, boolean tryMove)1762 	public void changeDuration(TGMeasure measure,TGBeat beat,TGDuration duration,int voice, boolean tryMove){
1763 		//obtengo la duracion vieja
1764 		TGDuration oldDuration = beat.getVoice(voice).getDuration().clone(getSongManager().getFactory());
1765 
1766 		//si no entra vuelvo a dejar la vieja
1767 		if(validateDuration(measure,beat, voice, duration,tryMove,false)){
1768 			//se lo agrego a todas las notas en la posicion
1769 			beat.getVoice(voice).setDuration(duration.clone(getSongManager().getFactory()));
1770 
1771 			//trato de agregar un silencio similar al lado
1772 			tryChangeSilenceAfter(measure,beat.getVoice(voice));
1773 		}else{
1774 			oldDuration.copy( beat.getVoice(voice).getDuration() );
1775 		}
1776 	}
1777 
tryChangeSilenceAfter(TGMeasure measure,TGVoice voice)1778 	public void tryChangeSilenceAfter(TGMeasure measure,TGVoice voice){
1779 		autoCompleteSilences(measure);
1780 
1781 		TGVoice nextVoice = getNextVoice(measure.getBeats(),voice.getBeat(),voice.getIndex());
1782 
1783 		long beatEnd = (voice.getBeat().getStart() + voice.getDuration().getTime());
1784 		long measureEnd = (measure.getStart() + measure.getLength());
1785 		if(nextVoice != null && !nextVoice.isEmpty() && nextVoice.isRestVoice() && beatEnd <= measureEnd){
1786 			long theMove = (getRealStart(measure,beatEnd)) - getRealStart(measure,nextVoice.getBeat().getStart());
1787 			if((nextVoice.getBeat().getStart() + theMove) < measureEnd && (nextVoice.getBeat().getStart() + nextVoice.getDuration().getTime() + theMove) <= measureEnd){
1788 				moveVoice(nextVoice,theMove);
1789 				changeDuration(measure,nextVoice.getBeat(),voice.getDuration().clone(getSongManager().getFactory()),nextVoice.getIndex(),false);
1790 			}
1791 		}
1792 	}
1793 
moveVoices(List voices,long theMove)1794 	private void moveVoices(List voices,long theMove){
1795 		/*
1796 		Iterator it = voices.iterator();
1797 		while(it.hasNext()){
1798 			TGVoice voice = (TGVoice)it.next();
1799 			moveVoice(voice,theMove);
1800 		}
1801 		*/
1802 		int count = voices.size();
1803 		for( int i = 0 ; i < count ; i ++ ){
1804 			TGVoice voice = (TGVoice)voices.get( (theMove < 0 ? i : ( (count - 1) - i ) ) );
1805 			moveVoice(voice,theMove);
1806 		}
1807 	}
1808 
moveVoice(TGVoice voice, long theMove)1809 	public void moveVoice(TGVoice voice, long theMove){
1810 		long newStart = (voice.getBeat().getStart() + theMove);
1811 
1812 		TGBeat newBeat = getBeat(voice.getBeat().getMeasure(),newStart);
1813 		if( newBeat == null ){
1814 			newBeat = getSongManager().getFactory().newBeat();
1815 			newBeat.setStart( newStart );
1816 			addBeat(voice.getBeat().getMeasure(), newBeat);
1817 		}
1818 
1819 		this.moveVoice(voice, newBeat);
1820 	}
1821 
moveVoice(TGVoice voice, TGBeat beat)1822 	public void moveVoice(TGVoice voice, TGBeat beat){
1823 		TGBeat currentBeat = voice.getBeat();
1824 		if(!currentBeat.equals(beat)){
1825 			if(currentBeat.getVoice( voice.getIndex() ).equals( voice )){
1826 				if ( currentBeat.isTextBeat() && isUniqueVoice(voice, false) ){
1827 						beat.setText( currentBeat.getText() );
1828 						currentBeat.removeText();
1829 				}
1830 				if( isUniqueVoice(voice, true) ){
1831 					if( currentBeat.isChordBeat() ){
1832 						beat.setChord( currentBeat.getChord() );
1833 						currentBeat.removeChord();
1834 					}
1835 					if( currentBeat.getStroke().getDirection() != TGStroke.STROKE_NONE ){
1836 						currentBeat.getStroke().copy( beat.getStroke() );
1837 						currentBeat.getStroke().setDirection(TGStroke.STROKE_NONE);
1838 					}
1839 				}
1840 				// Make sure to remove another voice instance from old beat.
1841 				TGVoice newVoice = getSongManager().getFactory().newVoice(voice.getIndex());
1842 				currentBeat.setVoice( voice.getIndex(), newVoice);
1843 				this.removeVoice(newVoice);
1844 			}
1845 			beat.setVoice( voice.getIndex() , voice);
1846 		}
1847 	}
1848 
validateDuration(TGMeasure measure,TGBeat beat,int voice, TGDuration duration,boolean moveNextBeats, boolean setCurrentDuration)1849 	public boolean validateDuration(TGMeasure measure,TGBeat beat,int voice, TGDuration duration,boolean moveNextBeats, boolean setCurrentDuration){
1850 		int errorMargin = 10;
1851 		this.orderBeats(measure);
1852 		long measureStart = measure.getStart();
1853 		long measureEnd =  (measureStart + measure.getLength());
1854 		long beatStart = beat.getStart();
1855 		long beatLength = duration.getTime();
1856 		long beatEnd = (beatStart + beatLength);
1857 		List beats = measure.getBeats();
1858 
1859 		//Verifico si hay un beat en el mismo lugar, y comparo las duraciones.
1860 		TGBeat currentBeat = getBeat(measure,beatStart);
1861 		TGVoice currentVoice = null;
1862 		if(currentBeat != null){
1863 			currentVoice = currentBeat.getVoice(voice);
1864 			if(!currentVoice.isEmpty() && beatLength <= currentVoice.getDuration().getTime()){
1865 				return true;
1866 			}
1867 		}
1868 
1869 		//Verifico si hay lugar para meter el beat
1870 		TGVoice nextVoice = getNextVoice(beats,beat, voice);
1871 		if(currentVoice == null || currentVoice.isEmpty()){
1872 			if((nextVoice == null || nextVoice.isEmpty()) && beatEnd < (measureEnd + errorMargin)){
1873 				return true;
1874 			}
1875 			if((nextVoice != null && !nextVoice.isEmpty()) && beatEnd < (nextVoice.getBeat().getStart() + errorMargin)){
1876 				return true;
1877 			}
1878 		}
1879 
1880 		// Busca si hay espacio disponible de silencios entre el componente y el el que le sigue.. si encuentra lo borra
1881 		if(nextVoice != null && !nextVoice.isEmpty() && nextVoice.isRestVoice()){
1882 			//Verifico si lo que sigue es un silencio. y lo borro
1883 			long nextBeatEnd = 0;
1884 			List nextBeats = new ArrayList();
1885 			while(nextVoice != null && !nextVoice.isEmpty() && nextVoice.isRestVoice() && !nextVoice.getBeat().isTextBeat()){
1886 				nextBeats.add(nextVoice);
1887 				nextBeatEnd = nextVoice.getBeat().getStart() + nextVoice.getDuration().getTime();
1888 				nextVoice = getNextVoice(beats,nextVoice.getBeat(), voice);
1889 			}
1890 			if(nextVoice == null || nextVoice.isEmpty()){
1891 				nextBeatEnd = measureEnd;
1892 			}else if(!nextVoice.isRestVoice() || nextVoice.getBeat().isTextBeat()){
1893 				nextBeatEnd = nextVoice.getBeat().getStart();
1894 			}
1895 			if(beatEnd <= (nextBeatEnd + errorMargin)){
1896 				while(!nextBeats.isEmpty()){
1897 					TGVoice currVoice = (TGVoice)nextBeats.get(0);
1898 					nextBeats.remove(currVoice);
1899 					removeVoice(currVoice, false);
1900 				}
1901 				return true;
1902 			}
1903 		}
1904 
1905 		// Busca si hay espacio disponible de silencios entre el componente y el final.. si encuentra mueve todo
1906 
1907 		if(moveNextBeats){
1908 			nextVoice = getNextVoice(beats,beat, voice);
1909 			if(nextVoice != null){
1910 				long requiredLength = (beatLength  - (nextVoice.getBeat().getStart() - beatStart));
1911 				long nextSilenceLength = 0;
1912 				TGVoice nextRestBeat = getNextRestVoice(beats, beat.getVoice(voice));
1913 				while(nextRestBeat != null){
1914 					nextSilenceLength += nextRestBeat.getDuration().getTime();
1915 					nextRestBeat = getNextRestVoice(beats, nextRestBeat);
1916 				}
1917 
1918 				if(requiredLength <= (nextSilenceLength + errorMargin)){
1919 					List voices = getVoicesBeforeEnd(measure.getBeats(),nextVoice.getBeat().getStart(), voice);
1920 					while(!voices.isEmpty()){
1921 						TGVoice currentVocie = (TGVoice)voices.get(0);
1922 						if(currentVocie.isRestVoice()){
1923 							requiredLength -= currentVocie.getDuration().getTime();
1924 							removeVoice(currentVocie, false);
1925 						}else if(requiredLength > 0){
1926 							moveVoice(currentVocie,requiredLength);
1927 						}
1928 						voices.remove(0);
1929 					}
1930 					return true;
1931 				}
1932 			}
1933 		}
1934 
1935 
1936 		// como ultimo intento, asigno la duracion de cualquier componente existente en el lugar.
1937 		if(setCurrentDuration && currentVoice != null && !currentVoice.isEmpty()){
1938 			currentVoice.getDuration().copy( duration );
1939 			return true;
1940 		}
1941 		return false;
1942 	}
1943 	/*
1944 	public boolean moveVoices(TGMeasure measure,long start,long theMove, int voiceIndex, TGDuration fillDuration){
1945 		if( theMove == 0 ){
1946 			return false;
1947 		}
1948 		boolean success = true;
1949 		long measureStart = measure.getStart();
1950 		long measureEnd =  (measureStart + measure.getLength());
1951 
1952 		// Muevo los componentes
1953 		List voicesToMove = getVoicesBeforeEnd(measure.getBeats(),start, voiceIndex);
1954 		moveVoices(voicesToMove,theMove);
1955 
1956 		if(success){
1957 			List voicesToRemove = new ArrayList();
1958 			List beats = new ArrayList(measure.getBeats());
1959 
1960 			// Verifica los silencios a eliminar al principio del compas
1961 			TGVoice first = getFirstVoice( beats, voiceIndex );
1962 			while(first != null && first.isRestVoice() && first.getBeat().getStart() < measureStart){
1963 				beats.remove(first);
1964 				voicesToRemove.add(first);
1965 				first = getNextVoice( beats,first.getBeat(), voiceIndex);
1966 			}
1967 
1968 			// Verifica los silencios a eliminar al final del compas
1969 			TGVoice last = getLastVoice(beats, voiceIndex);
1970 			TGDuration lastDuration = (last != null ? last.getDuration() : null);
1971 			while(last != null && lastDuration != null && last.isRestVoice() && (last.getBeat().getStart() + lastDuration.getTime() ) > measureEnd  ){
1972 				beats.remove(last);
1973 				voicesToRemove.add(last);
1974 				last = getPreviousVoice(beats,last.getBeat(), voiceIndex);
1975 				lastDuration = (last != null ? last.getDuration() : null);
1976 			}
1977 
1978 			// Si el primer o ultimo componente, quedan fuera del compas, entonces el movimiento no es satisfactorio
1979 			if(first != null && last != null && lastDuration != null){
1980 				if(first.getBeat().getStart() < measureStart || (last.getBeat().getStart() + lastDuration.getTime()) > measureEnd){
1981 					success = false;
1982 				}
1983 			}
1984 
1985 			if(success){
1986 				// Elimino los silencios que quedaron fuera del compas.
1987 				Iterator it = voicesToRemove.iterator();
1988 				while( it.hasNext() ){
1989 					TGVoice beat = (TGVoice)it.next();
1990 					removeVoice(beat);
1991 				}
1992 
1993 				// Se crean silencios en los espacios vacios, si la duracion fue especificada.
1994 				if( fillDuration != null ){
1995 					if( theMove < 0 ){
1996 						last = getLastVoice(measure.getBeats(), voiceIndex);
1997 						lastDuration = (last != null ? last.getDuration() : null);
1998 						long beatStart = ( (last != null && lastDuration != null ? last.getBeat().getStart()  + lastDuration.getTime() : start  )  );
1999 						if( (beatStart + fillDuration.getTime()) <= measureEnd ){
2000 							boolean beatNew = false;
2001 							TGBeat beat = getBeat(measure, beatStart);
2002 							if(beat == null){
2003 								beat = getSongManager().getFactory().newBeat();
2004 								beat.setStart( beatStart );
2005 								beatNew = true;
2006 							}
2007 							TGVoice voice = beat.getVoice(voiceIndex);
2008 							voice.setEmpty(false);
2009 							fillDuration.copy( voice.getDuration() );
2010 							if( beatNew ){
2011 								addBeat(measure, beat );
2012 							}
2013 						}
2014 					}
2015 					else{
2016 						first = getFirstVoice(getBeatsBeforeEnd(measure.getBeats(),start), voiceIndex);
2017 						if( (start + fillDuration.getTime()) <= (first != null ?first.getBeat().getStart() : measureEnd ) ){
2018 							boolean beatNew = false;
2019 							TGBeat beat = getBeat(measure, start);
2020 							if(beat == null){
2021 								beat = getSongManager().getFactory().newBeat();
2022 								beat.setStart( start );
2023 								beatNew = true;
2024 							}
2025 							TGVoice voice = beat.getVoice(voiceIndex);
2026 							voice.setEmpty(false);
2027 							fillDuration.copy( voice.getDuration() );
2028 							if( beatNew ){
2029 								addBeat(measure, beat );
2030 							}
2031 						}
2032 					}
2033 				}
2034 			}
2035 		}
2036 
2037 		// Si el movimiento no es satisfactorio, regreso todo como estaba
2038 		if(! success ){
2039 			moveVoices(voicesToMove,-theMove);
2040 		}
2041 		this.removeEmptyBeats(measure);
2042 
2043 		return success;
2044 	}
2045 	*/
2046 
moveVoices(TGMeasure measure,long start,long theMove, int voiceIndex, TGDuration fillDuration)2047 	public boolean moveVoices(TGMeasure measure,long start,long theMove, int voiceIndex, TGDuration fillDuration){
2048 		if( theMove == 0 ){
2049 			return false;
2050 		}
2051 		boolean success = true;
2052 		long measureStart = measure.getStart();
2053 		long measureEnd =  (measureStart + measure.getLength());
2054 
2055 		List voicesToMove = getVoicesBeforeEnd(measure.getBeats(),start, voiceIndex);
2056 		List voicesToRemove = new ArrayList();
2057 		List currentBeats = getBeatsBeforeEnd(measure.getBeats(), start);
2058 
2059 		// Verifica los silencios a eliminar al principio del compas
2060 		TGVoice first = getFirstVoice( currentBeats, voiceIndex );
2061 		while(first != null && first.isRestVoice() && (!first.getBeat().isTextBeat() || !isUniqueVoice(first,false)) && (first.getBeat().getStart() + theMove) < measureStart){
2062 			currentBeats.remove(first.getBeat());
2063 			voicesToRemove.add(first);
2064 			first = getNextVoice( currentBeats,first.getBeat(), voiceIndex);
2065 		}
2066 
2067 		// Verifica los silencios a eliminar al final del compas
2068 		TGVoice last = getLastVoice(currentBeats, voiceIndex);
2069 		TGDuration lastDuration = (last != null ? last.getDuration() : null);
2070 		while(last != null && lastDuration != null && last.isRestVoice() && (!last.getBeat().isTextBeat() || !isUniqueVoice(last,false)) && (last.getBeat().getStart() + lastDuration.getTime() + theMove) > measureEnd  ){
2071 			currentBeats.remove(last.getBeat());
2072 			voicesToRemove.add(last);
2073 			last = getPreviousVoice(currentBeats,last.getBeat(), voiceIndex);
2074 			lastDuration = (last != null ? last.getDuration() : null);
2075 		}
2076 
2077 		// Si el primer o ultimo componente, quedan fuera del compas, entonces el movimiento no es satisfactorio
2078 		if(first != null && last != null && lastDuration != null){
2079 			if((first.getBeat().getStart() + theMove) < measureStart || (last.getBeat().getStart() + lastDuration.getTime() + theMove) > measureEnd){
2080 				success = false;
2081 			}
2082 		}
2083 
2084 		if(success){
2085 			this.moveVoices(voicesToMove,theMove);
2086 
2087 			// Elimino los silencios que quedaron fuera del compas.
2088 			Iterator it = voicesToRemove.iterator();
2089 			while( it.hasNext() ){
2090 				TGVoice beat = (TGVoice)it.next();
2091 				removeVoice(beat);
2092 			}
2093 
2094 			// Se crean silencios en los espacios vacios, si la duracion fue especificada.
2095 			if( fillDuration != null ){
2096 				if( theMove < 0 ){
2097 					last = getLastVoice(measure.getBeats(), voiceIndex);
2098 					lastDuration = (last != null ? last.getDuration() : null);
2099 					long beatStart = ( (last != null && lastDuration != null ? last.getBeat().getStart()  + lastDuration.getTime() : start  )  );
2100 					if( (beatStart + fillDuration.getTime()) <= measureEnd ){
2101 						boolean beatNew = false;
2102 						TGBeat beat = getBeat(measure, beatStart);
2103 						if(beat == null){
2104 							beat = getSongManager().getFactory().newBeat();
2105 							beat.setStart( beatStart );
2106 							beatNew = true;
2107 						}
2108 						TGVoice voice = beat.getVoice(voiceIndex);
2109 						voice.setEmpty(false);
2110 						fillDuration.copy( voice.getDuration() );
2111 						if( beatNew ){
2112 							addBeat(measure, beat );
2113 						}
2114 					}
2115 				}
2116 				else{
2117 					first = getFirstVoice(getBeatsBeforeEnd(measure.getBeats(),start), voiceIndex);
2118 					if( (start + fillDuration.getTime()) <= (first != null ?first.getBeat().getStart() : measureEnd ) ){
2119 						boolean beatNew = false;
2120 						TGBeat beat = getBeat(measure, start);
2121 						if(beat == null){
2122 							beat = getSongManager().getFactory().newBeat();
2123 							beat.setStart( start );
2124 							beatNew = true;
2125 						}
2126 						TGVoice voice = beat.getVoice(voiceIndex);
2127 						voice.setEmpty(false);
2128 						fillDuration.copy( voice.getDuration() );
2129 						if( beatNew ){
2130 							addBeat(measure, beat );
2131 						}
2132 					}
2133 				}
2134 			}
2135 
2136 			// Borro todos los beats que quedaron vacios.
2137 			this.removeEmptyBeats(measure);
2138 		}
2139 
2140 		return success;
2141 	}
2142 
isUniqueVoice(TGVoice voice, boolean ignoreRests)2143 	public boolean isUniqueVoice(TGVoice voice, boolean ignoreRests){
2144 		TGBeat beat = voice.getBeat();
2145 		for( int v = 0 ; v < beat.countVoices() ; v ++ ){
2146 			if( v != voice.getIndex() ){
2147 				TGVoice currentVoice = beat.getVoice( v );
2148 				if( !currentVoice.isEmpty() && (!ignoreRests || !currentVoice.isRestVoice())){
2149 					return false;
2150 				}
2151 			}
2152 		}
2153 		return true;
2154 	}
2155 
transposeNotes( TGMeasure measure, int transposition , boolean tryKeepString, boolean applyToChords, int applyToString)2156 	public void transposeNotes( TGMeasure measure, int transposition , boolean tryKeepString, boolean applyToChords, int applyToString){
2157 		if( transposition != 0 ){
2158 			if( measure != null ){
2159 				TGTrack track = measure.getTrack();
2160 				if( track != null ){
2161 					List strings = getSortedStringsByValue(track, ( transposition > 0 ? 1 : -1 ) ) ;
2162 					for( int i = 0 ; i < measure.countBeats() ; i ++ ){
2163 						TGBeat beat = measure.getBeat( i );
2164 						transposeNotes( beat, strings, transposition , tryKeepString, applyToChords, applyToString );
2165 					}
2166 				}
2167 			}
2168 		}
2169 	}
2170 
transposeNotes( TGMeasure measure, int[] transpositionStrings , boolean tryKeepString , boolean applyToChords)2171 	public void transposeNotes( TGMeasure measure, int[] transpositionStrings , boolean tryKeepString , boolean applyToChords){
2172 		if( transpositionStrings != null && transpositionStrings.length > 0 ){
2173 			if( measure != null ){
2174 				TGTrack track = measure.getTrack();
2175 				if( track != null ){
2176 					TGNote[] notes = new TGNote[ transpositionStrings.length ];
2177 
2178 					for( int b = 0 ; b < measure.countBeats() ; b ++ ){
2179 						TGBeat beat = measure.getBeat( b );
2180 
2181 						for( int n = 0 ; n < notes.length ; n ++ ){
2182 							notes[ n ] = getNote( beat, (n + 1) );
2183 						}
2184 
2185 						for( int i = 0 ; i < notes.length ; i ++ ){
2186 							if( notes[ i ] != null ){
2187 								int transposition = transpositionStrings[ i ];
2188 								if( transposition != 0 ){
2189 									int applyToString = notes[i].getString();
2190 									List strings = getSortedStringsByValue(track, ( transposition > 0 ? 1 : -1 ) ) ;
2191 									transposeNotes( beat, strings, transposition , tryKeepString, applyToChords, applyToString );
2192 								}
2193 							}
2194 						}
2195 					}
2196 				}
2197 			}
2198 		}
2199 	}
2200 
transposeNotes( TGBeat beat, List strings, int transposition , boolean tryKeepString, boolean applyToChord, int applyToString)2201 	public void transposeNotes( TGBeat beat, List strings, int transposition , boolean tryKeepString, boolean applyToChord, int applyToString){
2202 		if( transposition != 0 ){
2203 			List notes = getNotes(beat);
2204 
2205 			int stringCount = strings.size();
2206 			for( int i = 0 ; i < stringCount ; i ++ ){
2207 				TGString string = (TGString)strings.get( (stringCount - i) - 1 );
2208 				if( applyToString == -1 || string.getNumber() == applyToString ){
2209 					TGNote note = null;
2210 					for( int n = 0 ; n < notes.size() ; n ++ ){
2211 						TGNote current = (TGNote)notes.get( n );
2212 						if( current.getString() == string.getNumber() ){
2213 							note = current;
2214 						}
2215 					}
2216 					if( note != null ){
2217 						transposeNote(note, notes, strings, transposition, tryKeepString, false );
2218 					}
2219 
2220 					if( applyToChord && beat.isChordBeat() ){
2221 						TGChord chord = beat.getChord();
2222 						int chordString = ( string.getNumber() - 1 );
2223 						if( chord.getFretValue( chordString ) >= 0 ){
2224 							transposeChordNote(chord, chordString, strings, transposition, tryKeepString, false);
2225 						}
2226 						chord.setFirstFret( -1 );
2227 					}
2228 				}
2229 			}
2230 		}
2231 	}
2232 
transposeNote( TGNote note, List notes, List strings , int transposition , boolean tryKeepString, boolean forceChangeString )2233 	private boolean transposeNote( TGNote note, List notes, List strings , int transposition , boolean tryKeepString, boolean forceChangeString ){
2234 		boolean canTransposeFret = false;
2235 
2236 		int maximumFret = 29;
2237 
2238 		int transposedFret = ( note.getValue() + transposition );
2239 
2240 		// Check if transposition could be done without change the string
2241 		if( transposedFret >= 0 && transposedFret <= maximumFret ){
2242 			// Do it now if keep string is the priority
2243 			if( !forceChangeString && tryKeepString ){
2244 				note.setValue( transposedFret );
2245 				return true;
2246 			}
2247 			canTransposeFret = true;
2248 		}
2249 
2250 		// Check the current string index for this note
2251 		int stringIndex = -1;
2252 		for( int i = 0 ; i < strings.size() ; i ++ ){
2253 			TGString string = ( TGString ) strings.get( i );
2254 			if( string.getNumber() == note.getString() ){
2255 				stringIndex = i;
2256 				break;
2257 			}
2258 		}
2259 
2260 		// Try to change the string of the note
2261 		TGString string = ( TGString ) strings.get( stringIndex );
2262 		int transposedValue = ( string.getValue() + note.getValue() + transposition );
2263 		int nextStringIndex = ( stringIndex + 1 );
2264 		while( nextStringIndex >= 0 && nextStringIndex < strings.size() ){
2265 			TGString nextString = ( TGString ) strings.get( nextStringIndex );
2266 			TGNote nextOwner = null;
2267 			for( int i = 0 ; i < notes.size() ; i ++ ){
2268 				TGNote nextNote = (TGNote) notes.get( i );
2269 				if( nextNote.getString() == nextString.getNumber() ){
2270 					nextOwner = nextNote;
2271 				}
2272 			}
2273 
2274 			int transposedStringFret = ( transposedValue - nextString.getValue() );
2275 			if( transposedStringFret >= 0 && transposedStringFret <= maximumFret ){
2276 				if( nextOwner != null ){
2277 					if( ! transposeNote(nextOwner, notes, strings, 0 , tryKeepString , !canTransposeFret ) ){
2278 						// Note was removed.
2279 						nextOwner = null ;
2280 					}
2281 				}
2282 				if( nextOwner == null || nextOwner.getString() != nextString.getNumber() ){
2283 					note.setValue( transposedStringFret );
2284 					note.setString( nextString.getNumber() );
2285 
2286 					return true;
2287 				}
2288 			}
2289 			nextStringIndex ++;
2290 		}
2291 
2292 		// Keep using same string if it's possible
2293 		if( !forceChangeString && canTransposeFret ){
2294 			note.setValue( transposedFret );
2295 			return true;
2296 		}
2297 
2298 		// If note can't be transposed, it must be removed.
2299 		notes.remove( note );
2300 		removeNote(note);
2301 
2302 		return false;
2303 	}
2304 
transposeChordNote( TGChord chord, int chordString, List strings , int transposition , boolean tryKeepString, boolean forceChangeString )2305 	private boolean transposeChordNote( TGChord chord, int chordString, List strings , int transposition , boolean tryKeepString, boolean forceChangeString ){
2306 		boolean canTransposeFret = false;
2307 
2308 		int maximumFret = 24;
2309 
2310 		int noteValue = chord.getFretValue( chordString );
2311 		int noteString = (chordString + 1 );
2312 
2313 		int transposedFret = ( noteValue + transposition );
2314 
2315 		// Check if transposition could be done without change the string
2316 		if( transposedFret >= 0 && transposedFret <= maximumFret ){
2317 			// Do it now if keep string is the priority
2318 			if( !forceChangeString && tryKeepString ){
2319 				chord.addFretValue(chordString, transposedFret);
2320 				return true;
2321 			}
2322 			canTransposeFret = true;
2323 		}
2324 
2325 		// Check the current string index for this note
2326 		int stringIndex = -1;
2327 		for( int i = 0 ; i < strings.size() ; i ++ ){
2328 			TGString string = ( TGString ) strings.get( i );
2329 			if( string.getNumber() == noteString ){
2330 				stringIndex = i;
2331 				break;
2332 			}
2333 		}
2334 
2335 		// Try to change the string of the note
2336 		TGString string = ( TGString ) strings.get( stringIndex );
2337 		int transposedValue = ( string.getValue() + noteValue + transposition );
2338 		int nextStringIndex = ( stringIndex + 1 );
2339 		while( nextStringIndex >= 0 && nextStringIndex < strings.size() ){
2340 			TGString nextString = ( TGString ) strings.get( nextStringIndex );
2341 			int nextChordString = -1;
2342 			for( int i = 0 ; i < chord.countStrings() ; i ++ ){
2343 				if( (i + 1) == nextString.getNumber() ){
2344 					if( chord.getFretValue( i ) >= 0 ){
2345 						nextChordString = i;
2346 					}
2347 				}
2348 			}
2349 
2350 			int transposedStringFret = ( transposedValue - nextString.getValue() );
2351 			if( transposedStringFret >= 0 && transposedStringFret <= maximumFret ){
2352 				if( nextChordString >= 0 ){
2353 					transposeChordNote(chord, nextChordString , strings, 0 , tryKeepString , !canTransposeFret );
2354 				}
2355 				if( nextChordString < 0 || chord.getFretValue( nextChordString ) < 0 ){
2356 					chord.addFretValue( chordString , -1 );
2357 					chord.addFretValue( ( nextString.getNumber() - 1 ) , transposedStringFret );
2358 
2359 					return true;
2360 				}
2361 			}
2362 			nextStringIndex ++;
2363 		}
2364 
2365 		// Keep using same string if it's possible
2366 		if( !forceChangeString && canTransposeFret ){
2367 			chord.addFretValue( chordString , transposedFret );
2368 			return true;
2369 		}
2370 
2371 		// If note can't be transposed, it must be removed.
2372 		chord.addFretValue( chordString , -1 );
2373 
2374 		return false;
2375 	}
2376 
getSortedStringsByValue( TGTrack track , final int direction )2377 	public List getSortedStringsByValue( TGTrack track , final int direction ){
2378 		List strings = new ArrayList();
2379 		for( int number = 1 ; number <= track.stringCount() ; number ++ ){
2380 			strings.add( track.getString( number ) );
2381 		}
2382 
2383 		Collections.sort( strings , new Comparator() {
2384 			public int compare(Object o1, Object o2) {
2385 				if( o1 != null && o2 != null && o1 instanceof TGString && o2 instanceof TGString ){
2386 					TGString s1 = (TGString)o1;
2387 					TGString s2 = (TGString)o2;
2388 					int status = ( s1.getValue() - s2.getValue() );
2389 					if( status == 0 ){
2390 						return 0;
2391 					}
2392 					return ( (status * direction) > 0 ? 1 : -1 );
2393 				}
2394 				return 0;
2395 			}
2396 		});
2397 
2398 		return strings;
2399 	}
2400 }
2401