package org.herac.tuxguitar.player.base; import org.herac.tuxguitar.song.models.TGDuration; import org.herac.tuxguitar.song.models.TGMeasureHeader; import org.herac.tuxguitar.song.models.TGSong; public class MidiRepeatController { private int count; private int eHeader; private int index; private int lastIndex; private int repeatAlternative; private long repeatEnd; private long repeatMove; private int repeatNumber; private boolean repeatOpen; private long repeatStart; private int repeatStartIndex; private int sHeader; private boolean shouldPlay; private TGSong song; public MidiRepeatController(TGSong song, int sHeader, int eHeader) { this.song = song; this.sHeader = sHeader; this.eHeader = eHeader; this.count = song.countMeasureHeaders(); this.index = 0; this.lastIndex = -1; this.shouldPlay = true; this.repeatOpen = true; this.repeatAlternative = 0; this.repeatStart = TGDuration.QUARTER_TIME; this.repeatEnd = 0; this.repeatMove = 0; this.repeatStartIndex = 0; this.repeatNumber = 0; } public boolean finished() { return (this.index >= this.count); } public int getIndex() { return this.index; } public long getRepeatMove() { return this.repeatMove; } public void process() { TGMeasureHeader header = this.song.getMeasureHeader(this.index); // Verifica si el compas esta dentro del rango. if ((this.sHeader != -1 && header.getNumber() < this.sHeader) || (this.eHeader != -1 && header.getNumber() > this.eHeader)) { this.shouldPlay = false; this.index++; return; } // Abro repeticion siempre para el primer compas. if ((this.sHeader != -1 && header.getNumber() == this.sHeader) || header.getNumber() == 1) { this.repeatStartIndex = this.index; this.repeatStart = header.getStart(); this.repeatOpen = true; } // Por defecto el compas deberia sonar this.shouldPlay = true; // En caso de existir una repeticion nueva, // guardo el indice de el compas donde empieza una repeticion if (header.isRepeatOpen()) { this.repeatStartIndex = this.index; this.repeatStart = header.getStart(); this.repeatOpen = true; // Si es la primer vez que paso por este compas // Pongo numero de repeticion y final alternativo en cero if (this.index > this.lastIndex) { this.repeatNumber = 0; this.repeatAlternative = 0; } } else { // verifico si hay un final alternativo abierto if (this.repeatAlternative == 0) { this.repeatAlternative = header.getRepeatAlternative(); } // Si estoy en un final alternativo. // el compas solo puede sonar si el numero de repeticion coincide con el // numero de final alternativo. if (this.repeatOpen && (this.repeatAlternative > 0) && ((this.repeatAlternative & (1 << (this.repeatNumber))) == 0)) { this.repeatMove -= header.getLength(); if (header.getRepeatClose() > 0) { this.repeatAlternative = 0; } this.shouldPlay = false; this.index++; return; } } // antes de ejecutar una posible repeticion // guardo el indice del ultimo compas tocado this.lastIndex = Math.max(this.lastIndex, this.index); // si hay una repeticion la hago if (this.repeatOpen && header.getRepeatClose() > 0) { if (this.repeatNumber < header.getRepeatClose() || (this.repeatAlternative > 0)) { this.repeatEnd = header.getStart() + header.getLength(); this.repeatMove += this.repeatEnd - this.repeatStart; this.index = this.repeatStartIndex - 1; this.repeatNumber++; } else { this.repeatStart = 0; this.repeatNumber = 0; this.repeatEnd = 0; this.repeatOpen = false; } this.repeatAlternative = 0; } this.index++; } public boolean shouldPlay() { return this.shouldPlay; } }