1 package org.herac.tuxguitar.jack.sequencer;
2 
3 import java.util.List;
4 
5 import org.herac.tuxguitar.song.models.TGDuration;
6 
7 public class JackTickController {
8 
9 	private int tempo;
10 	private long frame;
11 	private long lastFrame;
12 	private long tickLength;
13 	private double tick;
14 
15 	private Object lock;
16 	private JackSequencer sequencer;
17 
JackTickController(JackSequencer sequencer)18 	public JackTickController(JackSequencer sequencer){
19 		this.lock = new Object();
20 		this.sequencer = sequencer;
21 	}
22 
process()23 	public void process() {
24 		synchronized (this.lock) {
25 			long frameRate = this.sequencer.getJackClient().getTransportFrameRate();
26 			this.lastFrame = this.frame;
27 			this.frame = this.sequencer.getJackClient().getTransportFrame();
28 			this.tick += ((double)TGDuration.QUARTER_TIME * ((double)getTempo() * (double)(this.frame - this.lastFrame) / 60.00) / (double)frameRate);
29 		}
30 	}
31 
setTick(long tick , boolean updateTransport )32 	public void setTick(long tick , boolean updateTransport ) {
33 		synchronized (this.lock) {
34 			long frameRate = this.sequencer.getJackClient().getTransportFrameRate();
35 			if( updateTransport ){
36 				this.sequencer.getJackClient().setTransportFrame( Math.round( tickToFrame(tick, frameRate )) );
37 			}
38 			this.frame = this.sequencer.getJackClient().getTransportFrame();
39 			this.tick = this.frameToTick( this.frame , frameRate );
40 		}
41 	}
42 
getTick()43 	public double getTick() {
44 		return this.tick;
45 	}
46 
getTickLength()47 	public long getTickLength() {
48 		return this.tickLength;
49 	}
50 
clearTick()51 	public void clearTick(){
52 		this.tickLength = 0;
53 	}
54 
notifyTick(long tick)55 	public void notifyTick(long tick){
56 		this.tickLength = Math.max(this.tickLength,tick);
57 	}
58 
setTempo(int tempo)59 	public void setTempo(int tempo) {
60 		this.tempo = tempo;
61 	}
62 
getTempo()63 	public int getTempo() {
64 		return this.tempo;
65 	}
66 
frameToTick( long frame , long frameRate )67 	public double frameToTick( long frame , long frameRate ){
68 		double framePos = 0;
69 		double tempo = 120;
70 		double tick = TGDuration.QUARTER_TIME;
71 
72 		List tempoChanges = this.sequencer.getJackEventController().getTempoChanges();
73 		for(int i = 0; i < tempoChanges.size(); i ++){
74 			long[] tc = (long[])tempoChanges.get(i);
75 			double tcTick = tc[0];
76 			double tcValue = tc[1];
77 
78 			double tickFrames = ( (((double)frameRate * (tcTick - tick)) / (double)TGDuration.QUARTER_TIME ) * (60.00 / tempo) );
79 			if( framePos + tickFrames <= frame ){
80 				framePos += tickFrames;
81 				tempo = tcValue;
82 				tick = tcTick;
83 			}else{
84 				break;
85 			}
86 		}
87 		if( frame > framePos ){
88 			double timeFrame = ( ( (double)(frame - framePos) / (double)frameRate ) * 1000.00 );
89 			double timeTick =  ( ( timeFrame * (double)TGDuration.QUARTER_TIME ) / 1000.00 );
90 
91 			tick += ( timeTick * ( tempo / 60.00 ) );
92 		}
93 
94 		return tick;
95 	}
96 
tickToFrame( long tick , long frameRate )97 	public double tickToFrame( long tick , long frameRate ){
98 		double tickPos = TGDuration.QUARTER_TIME;
99 		double tempo = 120;
100 		double frame = 0;
101 
102 		List tempoChanges = this.sequencer.getJackEventController().getTempoChanges();
103 		for(int i = 0; i < tempoChanges.size(); i ++){
104 			long[] tc = (long[])tempoChanges.get(i);
105 			double tcTick = tc[0];
106 			double tcValue = tc[1];
107 
108 			double tickFrames = ((((double) frameRate * (tcTick - tickPos)) / (double)TGDuration.QUARTER_TIME ) * (60.00 / tempo));
109 			if( tcTick <= tick ){
110 				frame += tickFrames;
111 				tempo = tcValue;
112 				tickPos = tcTick;
113 			}else{
114 				break;
115 			}
116 		}
117 		if( tick > tickPos ){
118 			double timeTick = ( ( (double)( tick - tickPos ) / (double)TGDuration.QUARTER_TIME ) * 1000.00 );
119 			double timeFrame = ( ( timeTick * (double)frameRate ) / 1000.00 );
120 
121 			frame += (timeFrame * ( 60.00 / tempo));
122 		}
123 
124 		return frame;
125 	}
126 }
127