package org.herac.tuxguitar.io.midi;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.herac.tuxguitar.gm.GMChannelRoute;
import org.herac.tuxguitar.gm.GMChannelRouter;
import org.herac.tuxguitar.io.base.TGFileFormat;
import org.herac.tuxguitar.io.base.TGFileFormatException;
import org.herac.tuxguitar.io.base.TGLocalFileImporter;
import org.herac.tuxguitar.io.midi.base.MidiEvent;
import org.herac.tuxguitar.io.midi.base.MidiMessage;
import org.herac.tuxguitar.io.midi.base.MidiSequence;
import org.herac.tuxguitar.io.midi.base.MidiTrack;
import org.herac.tuxguitar.player.base.MidiControllers;
import org.herac.tuxguitar.song.factory.TGFactory;
import org.herac.tuxguitar.song.managers.TGSongManager;
import org.herac.tuxguitar.song.models.TGBeat;
import org.herac.tuxguitar.song.models.TGChannel;
import org.herac.tuxguitar.song.models.TGColor;
import org.herac.tuxguitar.song.models.TGDuration;
import org.herac.tuxguitar.song.models.TGMeasure;
import org.herac.tuxguitar.song.models.TGMeasureHeader;
import org.herac.tuxguitar.song.models.TGNote;
import org.herac.tuxguitar.song.models.TGSong;
import org.herac.tuxguitar.song.models.TGString;
import org.herac.tuxguitar.song.models.TGTempo;
import org.herac.tuxguitar.song.models.TGTimeSignature;
import org.herac.tuxguitar.song.models.TGTrack;
public class MidiSongImporter implements TGLocalFileImporter{
private static final int MIN_DURATION_VALUE = TGDuration.SIXTY_FOURTH;
private int resolution;
private List channels;
private List headers;
private List tracks;
private List tempNotes;
private List tempChannels;
private List trackTuningHelpers;
private GMChannelRouter channelRouter;
private MidiSettings settings;
protected TGFactory factory;
protected InputStream stream;
public MidiSongImporter(){
super();
}
@Override
public TGFileFormat getFileFormat() {
return new TGFileFormat("Midi","*.mid;*.midi");
}
@Override
public String getImportName() {
return "Midi";
}
@Override
public boolean configure(boolean setDefaults){
this.settings = (MidiSettings.getDefaults());
return (this.settings != null);
}
@Override
public void init(TGFactory factory,InputStream stream) {
this.factory = factory;
this.stream = stream;
}
@Override
public TGSong importSong() throws TGFileFormatException {
try {
if(this.settings == null || this.factory == null || this.stream == null ){
return null;
}
MidiSequence sequence = new MidiFileReader().getSequence(this.stream);
initFields(sequence);
for(int i = 0; i < sequence.countTracks(); i++){
MidiTrack track = sequence.getTrack(i);
int trackNumber = getNextTrackNumber();
int events = track.size();
for(int j = 0;j < events;j ++){
MidiEvent event = track.get(j);
parseMessage(trackNumber,event.getTick(),event.getMessage());
}
}
checkAll();
TGSong song = this.factory.newSong();
Iterator channels = this.channels.iterator();
while(channels.hasNext()){
song.addChannel((TGChannel)channels.next());
}
Iterator headers = this.headers.iterator();
while(headers.hasNext()){
song.addMeasureHeader((TGMeasureHeader)headers.next());
}
Iterator tracks = this.tracks.iterator();
while(tracks.hasNext()){
song.addTrack((TGTrack)tracks.next());
}
return new SongAdjuster(this.factory,song).adjustSong();
} catch (Throwable throwable) {
throw new TGFileFormatException(throwable);
}
}
private void initFields(MidiSequence sequence){
this.resolution = sequence.getResolution();
this.channels = new ArrayList();
this.headers = new ArrayList();
this.tracks = new ArrayList();
this.tempNotes = new ArrayList();
this.tempChannels = new ArrayList();
this.trackTuningHelpers = new ArrayList();
this.channelRouter = new GMChannelRouter();
}
private int getNextTrackNumber(){
return (this.tracks.size() + 1);
}
private void parseMessage(int trackNumber,long tick,MidiMessage message){
long parsedTick = parseTick(tick + this.resolution);
//NOTE ON
if(message.getType() == MidiMessage.TYPE_SHORT && message.getCommand() == MidiMessage.NOTE_ON){
parseNoteOn(trackNumber,parsedTick,message.getData());
}
//NOTE OFF
else if(message.getType() == MidiMessage.TYPE_SHORT && message.getCommand() == MidiMessage.NOTE_OFF){
parseNoteOff(trackNumber,parsedTick,message.getData());
}
//PROGRAM CHANGE
else if(message.getType() == MidiMessage.TYPE_SHORT && message.getCommand() == MidiMessage.PROGRAM_CHANGE){
parseProgramChange(message.getData());
}
//CONTROL CHANGE
else if(message.getType() == MidiMessage.TYPE_SHORT && message.getCommand() == MidiMessage.CONTROL_CHANGE){
parseControlChange(message.getData());
}
//TIME SIGNATURE
else if(message.getType() == MidiMessage.TYPE_META && message.getCommand() == MidiMessage.TIME_SIGNATURE_CHANGE){
parseTimeSignature(parsedTick,message.getData());
}
//TEMPO
else if(message.getType() == MidiMessage.TYPE_META && message.getCommand() == MidiMessage.TEMPO_CHANGE){
parseTempo(parsedTick,message.getData());
}
}
private long parseTick(long tick){
return Math.abs(TGDuration.QUARTER_TIME * tick / this.resolution);
}
private void parseNoteOn(int track,long tick,byte[] data){
int length = data.length;
int channel = (length > 0)?((data[0] & 0xFF) & 0x0F):0;
int value = (length > 1)?(data[1] & 0xFF):0;
int velocity = (length > 2)?(data[2] & 0xFF):0;
if(velocity == 0){
parseNoteOff(track,tick,data);
}else if(value > 0){
makeTempNotesBefore(tick,track);
getTempChannel(channel).setTrack(track);
getTrackTuningHelper(track).checkValue(value);
this.tempNotes.add(new TempNote(track,channel,value,tick));
}
}
private void parseNoteOff(int track,long tick,byte[] data){
int length = data.length;
int channel = (length > 0)?((data[0] & 0xFF) & 0x0F):0;
int value = (length > 1)?(data[1] & 0xFF):0;
makeNote(tick,track,channel,value);
}
private void parseProgramChange(byte[] data){
int length = data.length;
int channel = (length > 0)?((data[0] & 0xFF) & 0x0F):-1;
int instrument = (length > 1)?(data[1] & 0xFF):-1;
if(channel != -1 && instrument != -1){
getTempChannel(channel).setInstrument(instrument);
}
}
private void parseControlChange(byte[] data){
int length = data.length;
int channel = (length > 0)?((data[0] & 0xFF) & 0x0F):-1;
int control = (length > 1)?(data[1] & 0xFF):-1;
int value = (length > 2)?(data[2] & 0xFF):-1;
if(channel != -1 && control != -1 && value != -1){
if(control == MidiControllers.VOLUME){
getTempChannel(channel).setVolume(value);
}
else if(control == MidiControllers.BALANCE){
getTempChannel(channel).setBalance(value);
}
}
}
private void parseTimeSignature(long tick,byte[] data){
if(data.length >= 2){
TGTimeSignature timeSignature = this.factory.newTimeSignature();
timeSignature.setNumerator(data[0]);
timeSignature.getDenominator().setValue(TGDuration.QUARTER);
if (data[1] == 0) {
timeSignature.getDenominator().setValue(TGDuration.WHOLE);
} else if (data[1] == 1) {
timeSignature.getDenominator().setValue(TGDuration.HALF);
} else if (data[1] == 2) {
timeSignature.getDenominator().setValue(TGDuration.QUARTER);
} else if (data[1] == 3) {
timeSignature.getDenominator().setValue(TGDuration.EIGHTH);
} else if (data[1] == 4) {
timeSignature.getDenominator().setValue(TGDuration.SIXTEENTH);
} else if (data[1] == 5) {
timeSignature.getDenominator().setValue(TGDuration.THIRTY_SECOND);
}
getHeader(tick).setTimeSignature(timeSignature);
}
}
private void parseTempo(long tick,byte[] data){
if(data.length >= 3){
TGTempo tempo = TGTempo.fromUSQ(this.factory,(data[2] & 0xff) | ((data[1] & 0xff) << 8) | ((data[0] & 0xff) << 16));
getHeader(tick).setTempo(tempo);
}
}
private TGTrack getTrack(int number){
Iterator it = this.tracks.iterator();
while(it.hasNext()){
TGTrack track = (TGTrack)it.next();
if(track.getNumber() == number){
return track;
}
}
TGTrack track = this.factory.newTrack();
track.setNumber(number);
track.setChannelId(-1);
TGColor.RED.copy(track.getColor());
this.tracks.add(track);
return track;
}
private TGMeasureHeader getHeader(long tick){
long realTick = (tick >= TGDuration.QUARTER_TIME)?tick:TGDuration.QUARTER_TIME;
Iterator it = this.headers.iterator();
while(it.hasNext()){
TGMeasureHeader header = (TGMeasureHeader)it.next();
if(realTick >= header.getStart() && realTick < header.getStart() + header.getLength()){
return header;
}
}
TGMeasureHeader last = getLastHeader();
TGMeasureHeader header = this.factory.newHeader();
header.setNumber((last != null)?last.getNumber() + 1:1);
header.setStart((last != null)?(last.getStart() + last.getLength()):TGDuration.QUARTER_TIME);
header.getTempo().setValue( (last != null)?last.getTempo().getValue():120 );
if(last != null){
last.getTimeSignature().copy(header.getTimeSignature());
}else{
header.getTimeSignature().setNumerator(4);
header.getTimeSignature().getDenominator().setValue(TGDuration.QUARTER);
}
this.headers.add(header);
if(realTick >= header.getStart() && realTick < header.getStart() + header.getLength()){
return header;
}
return getHeader(realTick);
}
private TGMeasureHeader getLastHeader(){
if(!this.headers.isEmpty()){
return (TGMeasureHeader)this.headers.get(this.headers.size() - 1);
}
return null;
}
private TGMeasure getMeasure(TGTrack track,long tick){
long realTick = (tick >= TGDuration.QUARTER_TIME)?tick:TGDuration.QUARTER_TIME;
Iterator it = track.getMeasures();
while(it.hasNext()){
TGMeasure measure = (TGMeasure)it.next();
if(realTick >= measure.getStart() && realTick < measure.getStart() + measure.getLength()){
return measure;
}
}
getHeader(realTick);
for(int i = 0;i < this.headers.size();i++){
boolean exist = false;
TGMeasureHeader header = (TGMeasureHeader)this.headers.get(i);
int measureCount = track.countMeasures();
for(int j = 0;j < measureCount;j++){
TGMeasure measure = track.getMeasure(j);
if(measure.getHeader().equals(header)){
exist = true;
}
}
if(!exist){
TGMeasure measure = this.factory.newMeasure(header);
track.addMeasure(measure);
}
}
return getMeasure(track,realTick);
}
private TGBeat getBeat(TGMeasure measure, long start){
int beatCount = measure.countBeats();
for( int i = 0 ; i < beatCount ; i ++){
TGBeat beat = measure.getBeat( i );
if( beat.getStart() == start){
return beat;
}
}
TGBeat beat = this.factory.newBeat();
beat.setStart(start);
measure.addBeat(beat);
return beat;
}
private TempNote getTempNote(int track,int channel,int value,boolean purge){
for(int i = 0;i < this.tempNotes.size();i ++){
TempNote note = (TempNote)this.tempNotes.get(i);
if(note.getTrack() == track && note.getChannel() == channel && note.getValue() == value){
if(purge){
this.tempNotes.remove(i);
}
return note;
}
}
return null;
}
protected TrackTuningHelper getTrackTuningHelper(int track){
Iterator it = this.trackTuningHelpers.iterator();
while(it.hasNext()){
TrackTuningHelper helper = (TrackTuningHelper)it.next();
if(helper.getTrack() == track){
return helper;
}
}
TrackTuningHelper helper = new TrackTuningHelper(track);
this.trackTuningHelpers.add(helper);
return helper;
}
private void makeTempNotesBefore(long tick,int track){
long nextTick = tick;
boolean check = true;
while(check){
check = false;
for(int i = 0;i < this.tempNotes.size();i ++){
TempNote note = (TempNote)this.tempNotes.get(i);
if(note.getTick() < nextTick && note.getTrack() == track){
nextTick = note.getTick() + (TGDuration.QUARTER_TIME * 5); //First beat + 4/4 measure;
makeNote(nextTick,track,note.getChannel(),note.getValue());
check = true;
break;
}
}
}
}
private void makeNote(long tick,int track,int channel,int value){
TempNote tempNote = getTempNote(track,channel,value,true);
if(tempNote != null){
int nString = 0;
int nValue = (tempNote.getValue() + this.settings.getTranspose());
int nVelocity = 64;
long nStart = tempNote.getTick();
TGDuration minDuration = newDuration(MIN_DURATION_VALUE);
TGDuration nDuration = TGDuration.fromTime(this.factory,tick - tempNote.getTick(),minDuration);
TGMeasure measure = getMeasure(getTrack(track),tempNote.getTick());
TGBeat beat = getBeat(measure, nStart);
nDuration.copy(beat.getVoice(0).getDuration());
TGNote note = this.factory.newNote();
note.setValue(nValue);
note.setString(nString);
note.setVelocity(nVelocity);
beat.getVoice(0).addNote(note);
}
}
public TempChannel getTempChannel(int channel){
Iterator it = this.tempChannels.iterator();
while(it.hasNext()){
TempChannel tempChannel = (TempChannel)it.next();
if(tempChannel.getChannel() == channel){
return tempChannel;
}
}
TempChannel tempChannel = new TempChannel(channel);
this.tempChannels.add(tempChannel);
return tempChannel;
}
private void checkAll()throws Exception{
checkChannels();
checkTracks();
int headerCount = this.headers.size();
for(int i = 0;i < this.tracks.size();i ++){
TGTrack track = (TGTrack)this.tracks.get(i);
while(track.countMeasures() < headerCount){
long start = TGDuration.QUARTER_TIME;
TGMeasure lastMeasure = ((track.countMeasures() > 0)?track.getMeasure(track.countMeasures() - 1) :null);
if(lastMeasure != null){
start = (lastMeasure.getStart() + lastMeasure.getLength());
}
track.addMeasure(this.factory.newMeasure(getHeader(start)));
}
}
if(this.headers.isEmpty() || this.tracks.isEmpty()){
throw new Exception("Empty Song");
}
}
private void checkChannels(){
for(int tc = 0 ; tc < this.tempChannels.size() ; tc ++ ){
TempChannel tempChannel = (TempChannel)this.tempChannels.get( tc );
if( tempChannel.getTrack() > 0 ){
boolean channelExists = false;
for(int c = 0 ; c < this.channels.size() ; c ++ ){
TGChannel tgChannel = (TGChannel) this.channels.get(c);
GMChannelRoute gmChannelRoute = this.channelRouter.getRoute(tgChannel.getChannelId());
if( gmChannelRoute != null ){
if( gmChannelRoute.getChannel1() == tempChannel.getChannel() || gmChannelRoute.getChannel2() == tempChannel.getChannel() ){
channelExists = true;
}
}
}
if(!channelExists){
TGChannel tgChannel = this.factory.newChannel();
tgChannel.setChannelId(this.channels.size() + 1);
tgChannel.setProgram((short)tempChannel.getInstrument());
tgChannel.setVolume((short)tempChannel.getVolume());
tgChannel.setBalance((short)tempChannel.getBalance());
tgChannel.setName(("#" + tgChannel.getChannelId()));
tgChannel.setBank(tempChannel.getChannel() == 9 ? TGChannel.DEFAULT_PERCUSSION_BANK : TGChannel.DEFAULT_BANK);
GMChannelRoute gmChannelRoute = new GMChannelRoute(tgChannel.getChannelId());
gmChannelRoute.setChannel1(tempChannel.getChannel());
gmChannelRoute.setChannel2(tempChannel.getChannel());
for(int tcAux = (tc + 1) ; tcAux < this.tempChannels.size() ; tcAux ++ ){
TempChannel tempChannelAux = (TempChannel)this.tempChannels.get( tcAux );
if( tempChannel.getTrack() == tempChannelAux.getTrack() ){
if( gmChannelRoute.getChannel2() == gmChannelRoute.getChannel1() ){
gmChannelRoute.setChannel2( tempChannelAux.getChannel() );
}else{
tempChannelAux.setTrack(-1);
}
}
}
this.channelRouter.configureRoutes(gmChannelRoute, (tempChannel.getChannel() == 9));
this.channels.add( tgChannel );
}
}
}
}
private void checkTracks(){
Iterator it = this.tracks.iterator();
while(it.hasNext()){
TGTrack track = (TGTrack)it.next();
TGChannel trackChannel = null;
Iterator tcIt = this.tempChannels.iterator();
while(tcIt.hasNext()){
TempChannel tempChannel = (TempChannel)tcIt.next();
if( tempChannel.getTrack() == track.getNumber() ){
Iterator channelIt = this.channels.iterator();
while( channelIt.hasNext() ){
TGChannel tgChannel = (TGChannel)channelIt.next();
GMChannelRoute gmChannelRoute = this.channelRouter.getRoute(tgChannel.getChannelId());
if( gmChannelRoute != null && tempChannel.getChannel() == gmChannelRoute.getChannel1() ){
trackChannel = tgChannel;
}
}
}
}
if( trackChannel != null ){
track.setChannelId( trackChannel.getChannelId() );
}
if( trackChannel != null && trackChannel.isPercussionChannel() ){
track.setStrings(TGSongManager.createPercussionStrings(this.factory,6));
}else{
track.setStrings(getTrackTuningHelper(track.getNumber()).getStrings());
}
}
}
protected TGDuration newDuration(int value){
TGDuration duration = this.factory.newDuration();
duration.setValue(value);
return duration;
}
private class TempNote{
private int track;
private int channel;
private int value;
private long tick;
public TempNote(int track, int channel, int value,long tick) {
this.track = track;
this.channel = channel;
this.value = value;
this.tick = tick;
}
public int getChannel() {
return this.channel;
}
public long getTick() {
return this.tick;
}
public int getTrack() {
return this.track;
}
public int getValue() {
return this.value;
}
}
private class TempChannel{
private int channel;
private int instrument;
private int volume;
private int balance;
private int track;
public TempChannel(int channel) {
this.channel = channel;
this.instrument = 0;
this.volume = 127;
this.balance = 64;
this.track = -1;
}
public int getBalance() {
return this.balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public int getChannel() {
return this.channel;
}
public int getInstrument() {
return this.instrument;
}
public void setInstrument(int instrument) {
this.instrument = instrument;
}
public int getTrack() {
return this.track;
}
public void setTrack(int track) {
this.track = track;
}
public int getVolume() {
return this.volume;
}
public void setVolume(int volume) {
this.volume = volume;
}
}
private class TrackTuningHelper{
private int track;
private int maxValue;
private int minValue;
public TrackTuningHelper(int track){
this.track = track;
this.maxValue = -1;
this.minValue = -1;
}
public void checkValue(int value){
if(this.minValue < 0 || value < this.minValue){
this.minValue = value;
}
if(this.maxValue < 0 || value > this.maxValue){
this.maxValue = value;
}
}
public List getStrings() {
List strings = new ArrayList();
int maxFret = 24;
if(this.minValue >= 40 && this.maxValue <= 64 + maxFret){
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,1, 64));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,2, 59));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,3, 55));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,4, 50));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,5, 45));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,6, 40));
}
else if(this.minValue >= 38 && this.maxValue <= 64 + maxFret){
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,1, 64));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,2, 59));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,3, 55));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,4, 50));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,5, 45));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,6, 38));
}
else if(this.minValue >= 35 && this.maxValue <= 64 + maxFret){
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,1, 64));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,2, 59));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,3, 55));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,4, 50));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,5, 45));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,6, 40));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,7, 35));
}
else if(this.minValue >= 28 && this.maxValue <= 43 + maxFret){
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,1, 43));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,2, 38));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,3, 33));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,4, 28));
}
else if(this.minValue >= 23 && this.maxValue <= 43 + maxFret){
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,1, 43));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,2, 38));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,3, 33));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,4, 28));
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,5, 23));
}else{
int stringCount = 6;
int stringSpacing = ((this.maxValue - (maxFret - 4) - this.minValue) / stringCount);
if(stringSpacing > 5){
stringCount = 7;
stringSpacing = ((this.maxValue - (maxFret - 4) - this.minValue) / stringCount);
}
int maxStringValue = (this.minValue + (stringCount * stringSpacing));
while(strings.size() < stringCount){
maxStringValue -= stringSpacing;
strings.add(TGSongManager.newString(MidiSongImporter.this.factory,strings.size() + 1,maxStringValue));
}
}
return strings;
}
public int getTrack() {
return this.track;
}
}
}
class SongAdjuster{
private TGFactory factory;
private TGSong song;
private long minDurationTime;
public SongAdjuster(TGFactory factory,TGSong song){
this.factory = factory;
this.song = song;
this.minDurationTime = 40;
}
public TGSong adjustSong(){
Iterator it = this.song.getTracks();
while(it.hasNext()){
TGTrack track = (TGTrack)it.next();
adjustTrack(track);
}
return this.song;
}
private void adjustTrack(TGTrack track){
Iterator it = track.getMeasures();
while(it.hasNext()){
TGMeasure measure = (TGMeasure)it.next();
process(measure);
}
}
public void process(TGMeasure measure){
orderBeats(measure);
joinBeats(measure);
adjustStrings(measure);
}
public void joinBeats(TGMeasure measure){
TGBeat previous = null;
boolean finish = true;
long measureStart = measure.getStart();
long measureEnd = (measureStart + measure.getLength());
for(int i = 0;i < measure.countBeats();i++){
TGBeat beat = measure.getBeat( i );
long beatStart = beat.getStart();
long beatLength = beat.getVoice(0).getDuration().getTime();
if(previous != null){
long previousStart = previous.getStart();
long previousLength = previous.getVoice(0).getDuration().getTime();
//if(previousStart == beatStart){
if(beatStart >= previousStart && (previousStart + this.minDurationTime) > beatStart ){
// add beat notes to previous
for(int n = 0;n < beat.getVoice(0).countNotes();n++){
TGNote note = beat.getVoice(0).getNote( n );
previous.getVoice(0).addNote( note );
}
// add beat chord to previous
if(!previous.isChordBeat() && beat.isChordBeat()){
previous.setChord( beat.getChord() );
}
// add beat text to previous
if(!previous.isTextBeat() && beat.isTextBeat()){
previous.setText( beat.getText() );
}
// set the best duration
if(beatLength > previousLength && (beatStart + beatLength) <= measureEnd){
beat.getVoice(0).getDuration().copy(previous.getVoice(0).getDuration());
}
measure.removeBeat(beat);
finish = false;
break;
}
else if(previousStart < beatStart && (previousStart + previousLength) > beatStart){
if(beat.getVoice(0).isRestVoice()){
measure.removeBeat(beat);
finish = false;
break;
}
TGDuration duration = TGDuration.fromTime(this.factory, (beatStart - previousStart) );
duration.copy( previous.getVoice(0).getDuration() );
}
}
if( (beatStart + beatLength) > measureEnd ){
if(beat.getVoice(0).isRestVoice()){
measure.removeBeat(beat);
finish = false;
break;
}
TGDuration duration = TGDuration.fromTime(this.factory, (measureEnd - beatStart) );
duration.copy( beat.getVoice(0).getDuration() );
}
previous = beat;
}
if(!finish){
joinBeats(measure);
}
}
public void orderBeats(TGMeasure measure){
for(int i = 0;i < measure.countBeats();i++){
TGBeat minBeat = null;
for(int j = i;j < measure.countBeats();j++){
TGBeat beat = measure.getBeat(j);
if(minBeat == null || beat.getStart() < minBeat.getStart()){
minBeat = beat;
}
}
measure.moveBeat(i, minBeat);
}
}
private void adjustStrings(TGMeasure measure){
for(int i = 0;i < measure.countBeats();i++){
TGBeat beat = measure.getBeat( i );
adjustStrings(beat);
}
}
private void adjustStrings(TGBeat beat){
TGTrack track = beat.getMeasure().getTrack();
List freeStrings = new ArrayList( track.getStrings() );
List notesToRemove = new ArrayList();
//ajusto las cuerdas
Iterator it = beat.getVoice(0).getNotes().iterator();
while(it.hasNext()){
TGNote note = (TGNote)it.next();
int string = getStringForValue(freeStrings,note.getValue());
for(int j = 0;j < freeStrings.size();j ++){
TGString tempString = (TGString)freeStrings.get(j);
if(tempString.getNumber() == string){
note.setValue(note.getValue() - tempString.getValue());
note.setString(tempString.getNumber());
freeStrings.remove(j);
break;
}
}
//Cannot have more notes on same string
if(note.getString() < 1){
notesToRemove.add( note );
}
}
// Remove notes
while( notesToRemove.size() > 0 ){
beat.getVoice(0).removeNote( (TGNote)notesToRemove.get( 0 ) );
notesToRemove.remove( 0 );
}
}
private int getStringForValue(List strings,int value){
int minFret = -1;
int stringForValue = 0;
for(int i = 0;i < strings.size();i++){
TGString string = (TGString)strings.get(i);
int fret = value - string.getValue();
if(minFret < 0 || (fret >= 0 && fret < minFret)){
stringForValue = string.getNumber();
minFret = fret;
}
}
return stringForValue;
}
}