package org.herac.tuxguitar.io.ptb; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.herac.tuxguitar.io.ptb.base.PTBar; import org.herac.tuxguitar.io.ptb.base.PTComponent; import org.herac.tuxguitar.io.ptb.base.PTDirection; import org.herac.tuxguitar.io.ptb.base.PTPosition; import org.herac.tuxguitar.io.ptb.base.PTSection; import org.herac.tuxguitar.io.ptb.base.PTSong; import org.herac.tuxguitar.io.ptb.base.PTSongInfo; import org.herac.tuxguitar.io.ptb.base.PTSymbol; import org.herac.tuxguitar.io.ptb.base.PTTrack; import org.herac.tuxguitar.io.ptb.base.PTTrackInfo; public class PTSongSynchronizerUtil { public static void synchronizeTracks(PTSong src, PTSong dst){ applyInfo( src.getInfo() , dst.getInfo() ); synchronizeTrack( src.getTrack1(), dst.getTrack1() ); synchronizeTrack( src.getTrack2(), dst.getTrack2() ); } private static void synchronizeTrack(PTTrack src, PTTrack dst){ applyRepeats(src, dst); applyInfos(src, dst); } private static void applyInfo(PTSongInfo src, PTSongInfo dst){ src.copy( dst ); } private static void applyInfos(PTTrack src, PTTrack dst){ Iterator it = src.getInfos().iterator(); while( it.hasNext() ){ PTTrackInfo srcInfo = (PTTrackInfo)it.next(); dst.getInfos().add( srcInfo.getClone() ); } } private static void applyRepeats(PTTrack src, PTTrack dst){ applyRepeats(src, dst, new PTIndex(0,0,0), new PTSongSynchronizerData(), new ArrayList() ); } private static void applyRepeats(PTTrack src, PTTrack dst, PTIndex index, PTSongSynchronizerData rd, List useds){ for( int s = index.s; s < src.getSections().size(); s ++){ PTSection srcSection = (PTSection) src.getSections().get(s); srcSection.sort(); PTSection dstSection = new PTSection( srcSection.getNumber() ); dstSection.setStaffs( srcSection.getStaffs() ); dst.getSections().add( dstSection ); for( int p = (s == index.s ? index.p : 0); p < srcSection.getPositions().size(); p ++){ PTPosition srcPosition = (PTPosition)srcSection.getPositions().get(p); srcPosition.sort(); PTPosition dstPosition = new PTPosition(srcPosition.getPosition() ); dstSection.getPositions().add( dstPosition ); for(int c = (s == index.s && p == index.p ? index.c : 0); c < srcPosition.getComponents().size(); c ++){ PTComponent component = (PTComponent)srcPosition.getComponents().get(c); if(!rd.skip){ dstPosition.addComponent( component.getClone() ); } // ------------------------------ PTBar ------------------------------// if(component instanceof PTBar){ PTBar bar = (PTBar) component; if(bar.getRepeatClose() > 0 && rd.repeatStart != null ){ rd.repeatNumber ++; rd.repeatInProgress = true; rd.repeatAlternative = false; rd.skip = false; if(rd.repeatNumber < bar.getRepeatClose()){ applyRepeats(src, dst, rd.repeatStart , rd, useds); return; } rd.repeatStart = null; rd.repeatNumber = 0; } if( bar.isRepeatStart() ){ rd.repeatStart = new PTIndex(s, p, c ); if(! rd.repeatInProgress ){ rd.repeatNumber = 0; } rd.repeatInProgress = false; } } // ------------------------------ PTSymbol ------------------------------// else if(component instanceof PTSymbol){ PTSymbol symbol = (PTSymbol)component; rd.skip = false; if( !rd.repeatAlternative && ((symbol.getEndNumber() & 1 ) != 0 ) ){ boolean validEnding = ((symbol.getEndNumber() & (1 << (rd.repeatNumber))) != 0 ); if(rd.repeatNumber > 0 && !validEnding ){ rd.skip = true; } rd.repeatAlternative = true; } } // ------------------------------ PTDirection ------------------------------// else if(component instanceof PTDirection){ PTDirection direction = (PTDirection)component; boolean validRepeat = (direction.getRepeat() == 0 || (rd.repeatStart != null && (rd.repeatNumber + 1) == direction.getRepeat())); boolean validDirection = ( direction.getActiveSymbol() == rd.findActiveSymbol ); if ( validDirection && validRepeat ){ rd.findActiveSymbol = 0; if( direction.getDirection() == PTDirection.DIRECTION_FINE ){ // Used to mark when to stop playing (usually the end of the score) if ( canUseDirection(direction, useds) ){ return; } } else if( direction.getDirection() == PTDirection.DIRECTION_DA_CAPO ){ // Go back to the beginning of the score and play from there if ( canUseDirection(direction, useds) ){ applyRepeats(src, dst, new PTIndex( 0, 0, 0 ) , rd , useds ); return; } } else if( direction.getDirection() == PTDirection.DIRECTION_DAL_SEGNO ){ // Go back to the Segno and play from there if ( canUseDirection(direction, useds) ){ PTIndex segno = findUnusedDirection(src, useds, PTDirection.DIRECTION_SEGNO, s, p ); if(segno != null ){ applyRepeats(src, dst, segno ,rd, useds); return; } } } else if( direction.getDirection() == PTDirection.DIRECTION_DAL_SEGNO_SEGNO ){ // Go back to the Segno Segno and play from there if ( canUseDirection(direction, useds) ){ PTIndex segno = findUnusedDirection(src, useds, PTDirection.DIRECTION_SEGNO_SEGNO, s, p ); if(segno != null ){ applyRepeats(src, dst, segno , rd, useds ); return; } } } else if( direction.getDirection() == PTDirection.DIRECTION_TO_CODA ){ // Go to the Coda sign and play from there. Used in conjunction with D.C./D.S. al Coda signs. if ( canUseDirection(direction, useds) ){ PTIndex coda = findUnusedDirection(src, useds, PTDirection.DIRECTION_CODA, -1, -1 ); if( coda != null ){ applyRepeats(src, dst, coda , rd , useds ); return; } } } else if( direction.getDirection() == PTDirection.DIRECTION_TO_DOUBLE_CODA ){ // Go to the Double Coda and play from there. Used in conjunction with D.C./D.S. al Double Coda signs. if ( canUseDirection(direction, useds) ){ PTIndex coda = findUnusedDirection(src, useds, PTDirection.DIRECTION_DOUBLE_CODA, -1, -1 ); if( coda != null ){ applyRepeats(src, dst, coda , rd , useds ); return; } } } else if( direction.getDirection() == PTDirection.DIRECTION_DA_CAPO_AL_CODA ){ // Go back to the beginning of the score and play from there until the To Coda sign is reached, // then jump to the Coda sign. if( canUseDirection(direction, useds) ){ rd.findActiveSymbol = PTDirection.ACTIVE_SYMBOL_DC; applyRepeats(src, dst, new PTIndex(0, 0, 0) , rd ,useds); return; } } else if( direction.getDirection() == PTDirection.DIRECTION_DA_CAPO_AL_DOUBLE_CODA ){ // Go back to the beginning of the score and play from there until the To Double Coda sign is reached, // then jump to the Double Coda sign. if( canUseDirection(direction, useds) ){ rd.findActiveSymbol = PTDirection.ACTIVE_SYMBOL_DC; applyRepeats(src, dst, new PTIndex(0, 0, 0) , rd , useds); return; } } else if( direction.getDirection() == PTDirection.DIRECTION_DAL_SEGNO_AL_CODA ){ // Go back to the Segno sign and play from there until the To Coda sign is reached, // then jump to the Coda sign. if( canUseDirection(direction, useds) ){ PTIndex segno = findUnusedDirection(src, useds, PTDirection.DIRECTION_SEGNO, s, p ); if( segno != null ){ rd.findActiveSymbol = PTDirection.ACTIVE_SYMBOL_DS; applyRepeats(src, dst, segno, rd , useds); return; } } } else if( direction.getDirection() == PTDirection.DIRECTION_DAL_SEGNO_AL_DOUBLE_CODA ){ // Go back to the Segno sign and play from there until the To Double Coda sign is reached, // then jump to the Double Coda sign. if( canUseDirection(direction, useds) ){ PTIndex segno = findUnusedDirection(src, useds, PTDirection.DIRECTION_SEGNO, s, p ); if( segno != null ){ rd.findActiveSymbol = PTDirection.ACTIVE_SYMBOL_DS; applyRepeats(src, dst, segno, rd , useds); return; } } } else if( direction.getDirection() == PTDirection.DIRECTION_DAL_SEGNO_SEGNO_AL_CODA ){ // Go back to the Segno Segno sign and play from there until the To Coda sign is reached, // then jump to the Coda sign. if( canUseDirection(direction, useds) ){ PTIndex segno = findUnusedDirection(src, useds, PTDirection.DIRECTION_SEGNO_SEGNO, s, p ); if( segno != null ){ rd.findActiveSymbol = PTDirection.ACTIVE_SYMBOL_DSS; applyRepeats(src, dst, segno, rd , useds); return; } } } else if( direction.getDirection() == PTDirection.DIRECTION_DAL_SEGNO_SEGNO_AL_DOUBLE_CODA ){ // Go back to the Segno Segno sign and play from there until the To Double Coda sign is reached, // then jump to the Double Coda sign. if( canUseDirection(direction, useds) ){ PTIndex segno = findUnusedDirection(src, useds, PTDirection.DIRECTION_SEGNO_SEGNO, s, p ); if( segno != null ){ rd.findActiveSymbol = PTDirection.ACTIVE_SYMBOL_DSS; applyRepeats(src, dst, segno, rd , useds); return; } } } else if( direction.getDirection() == PTDirection.DIRECTION_DA_CAPO_AL_FINE ){ // Go back to the beginning and play until the Fine sign is reached. if( canUseDirection(direction, useds) ){ rd.findActiveSymbol = PTDirection.ACTIVE_SYMBOL_DC; applyRepeats(src, dst, new PTIndex(0, 0, 0) , rd , useds); return; } } else if( direction.getDirection() == PTDirection.DIRECTION_DAL_SEGNO_AL_FINE ){ // Go back to the Segno sign and play until the Fine sign is reached. PTIndex segno = findUnusedDirection(src, useds, PTDirection.DIRECTION_SEGNO, s, p ); if( segno != null ){ rd.findActiveSymbol = PTDirection.ACTIVE_SYMBOL_DS; applyRepeats(src, dst, segno, rd , useds); return; } } else if( direction.getDirection() == PTDirection.DIRECTION_DAL_SEGNO_SEGNO_AL_FINE ){ // Go back to the Segno Segno sign and play until the Fine sign is reached. PTIndex segno = findUnusedDirection(src, useds, PTDirection.DIRECTION_SEGNO_SEGNO, s, p ); if( segno != null ){ rd.findActiveSymbol = PTDirection.ACTIVE_SYMBOL_DSS; applyRepeats(src, dst, segno, rd , useds); return; } } } } } } } } private static boolean canUseDirection(PTDirection direction, List useds){ boolean inUse = false; for( int i = 0 ; i < useds.size() && !inUse; i ++ ){ PTDirection used = (PTDirection)useds.get( i ); if( used.equals( direction )){ return false; } } useds.add( direction ); return true; } private static PTIndex findUnusedDirection(PTTrack src, List useds, int value, int sEndIndex, int pEndIndex){ return findUnusedDirection(src, useds, value, sEndIndex, pEndIndex, 0 ); } private static PTIndex findUnusedDirection(PTTrack src, List useds, int value, int sEndIndex, int pEndIndex, int activeSymbol){ for( int s = 0; s < ( sEndIndex >= 0 ? sEndIndex+1 : src.getSections().size() ); s ++){ PTSection section = (PTSection) src.getSections().get( s ); for( int p = 0; p < (s == sEndIndex ? pEndIndex+1 : section.getPositions().size() ); p ++){ PTPosition position = (PTPosition)section.getPositions().get(p); for( int c = 0; c < position.getComponents().size() ; c ++){ PTComponent component = (PTComponent)position.getComponents().get( c ); if(component instanceof PTDirection){ PTDirection direction = (PTDirection)component; if( direction.getDirection() == value && ( activeSymbol == 0 || direction.getActiveSymbol() == activeSymbol)){ if( canUseDirection(direction, useds)){ return new PTIndex(s, p , 0); } } } } } } return null; } private static class PTIndex{ /** Index Of Section **/ protected int s; /** Index Of Position **/ protected int p; /** Index Of Component **/ protected int c; protected PTIndex(int s, int p,int c) { this.s = s; this.p = p; this.c = c; } } private static class PTSongSynchronizerData{ /** Current Repeat Start Index **/ protected PTIndex repeatStart; /** Define If Repeat Is In Progress **/ protected boolean repeatInProgress; /** Current Repetition Number **/ protected int repeatNumber; /** Define if there is an Alternative Ending Running **/ protected boolean repeatAlternative; /** Define If Next Components Should Be Skipped **/ protected boolean skip; /** Active Symbol To Search Directions ( D.C, D.S, D.SS ) **/ protected int findActiveSymbol; protected PTSongSynchronizerData(){ this.repeatStart = null; this.repeatNumber = 0; this.repeatAlternative = false; this.skip = false; } } }