Skip to content

Commit ccdbf37

Browse files
committed
LTC is ready boisss
1 parent e31414e commit ccdbf37

File tree

6 files changed

+148
-48
lines changed

6 files changed

+148
-48
lines changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ MTC and LTC timecode generator library in Java
44
**NOTE:** The library is still a wip.
55

66
## What's working:
7-
- LTC generator (Except it has a weird buffer problem, but it's almost fixed)
7+
- LTC generator
88
- Timecode data managment
9+
- Timecode set fields
10+
- TimecodePlayer to choose timecode offset + speed (and, consequently, also direction)
911

1012
## TODO list:
1113
- ALL of the MTC part
12-
- fix audio buffer managment for LTC generator
1314
- Write a timecode reader for both MTC and LTC
14-
- Write a Timecode wrapper that will automatically set framens 'n stuff based of time, speed and direction
15+
- Changing audio output method to something more real time (now "real time" is garanted by just reducing the buffer size lmao)
16+
- 44.1khz support (But I think this will be done together with the previous point)
17+
- Writing docs (sigh)
18+
- Writing an example/test
1519

1620
### The idea
1721

src/main/java/ovh/stranck/javaTimecode/App.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,25 @@
77

88
public class App {
99
public static void main(String[] args) throws LineUnavailableException {
10-
Mixer m = Utils.getMixer("*Realtek High Definition Audio*");
10+
Mixer m = Utils.getMixer("*Realtek*");
1111
System.out.println(m.getMixerInfo());
1212
LTCGenerator ltc = new LTCGenerator(m, 48000);
13+
TimecodePlayer tp = ltc.getTimecodePlayer();
14+
Timecode tc = ltc.getPacket();
1315
System.out.println("starting");
1416
ltc.start();
1517
Wait.wait(1000);
16-
System.out.println("stopping");
17-
ltc.stop();
18-
Wait.wait(10000);
18+
//tc.setHours(1);
19+
//Wait.wait(5000);
20+
tp.setSpeed(1);
21+
Wait.wait(5000);
22+
tp.setSpeed(2);
23+
Wait.wait(5000);
24+
tp.setSpeed(1);
25+
Wait.wait(5000);
26+
//System.out.println("stopping");
27+
//ltc.stop();
28+
//Wait.wait(10000);
1929
/*System.out.println("starting");
2030
ltc.start();
2131
Wait.wait(10000);

src/main/java/ovh/stranck/javaTimecode/Framerates.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,8 @@ public enum Framerates {
3535
public float getFps(){
3636
return fps;
3737
}
38+
public int getIntegerFramerate(){
39+
return (int) Math.ceil(fps);
40+
}
3841
}
3942

src/main/java/ovh/stranck/javaTimecode/Timecode.java

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ovh.stranck.javaTimecode;
22

3-
public abstract class Timecode {
3+
public abstract class Timecode {
4+
protected TimecodePlayer tcPlayer;
45
protected int hours;
56
protected int mins;
67
protected int secs;
@@ -12,15 +13,13 @@ public abstract class Timecode {
1213

1314
public Timecode(int hour, int min, int sec, int frame, Framerates framerate){
1415
this.framerate = framerate;
16+
tcPlayer = new TimecodePlayer(this);
1517
setTime(hour, min, sec, frame);
18+
tcPlayer.updateStartPoint();
1619
}
1720

18-
protected int getIntegerFramerate(){
19-
return (int) Math.ceil(framerate.getFps());
20-
}
21-
22-
protected final void sanityzeTime(){
23-
int fps = getIntegerFramerate();
21+
protected final void sanityzeTime(boolean updateStartPoint){
22+
int fps = framerate.getIntegerFramerate();
2423
secs += frames / fps;
2524
frames %= fps;
2625
if(frames < 0) {
@@ -43,27 +42,34 @@ protected final void sanityzeTime(){
4342
if(hours < 0){
4443
hours = 24 - hours;
4544
}
45+
if(updateStartPoint)
46+
tcPlayer.updateStartPoint();
4647
}
4748

4849
public int getTotalFrames(){
4950
int n = hours;
5051
n = 60 * n + mins;
5152
n = 60 * n + secs;
52-
n = getIntegerFramerate() * n + frames;
53+
n = framerate.getIntegerFramerate() * n + frames;
5354
return n;
5455
}
56+
void setTimeWithoutUpdatingStartPoint(int totalFrames){
57+
hours = mins = secs = 0;
58+
frames = totalFrames;
59+
sanityzeTime(false);
60+
}
5561
public Timecode setTime(int totalFrames){
5662
hours = mins = secs = 0;
5763
frames = totalFrames;
58-
sanityzeTime();
64+
sanityzeTime(true);
5965
return this;
6066
}
6167
public Timecode setTime(int hours, int mins, int secs, int frames){
6268
this.hours = hours;
6369
this.mins = mins;
6470
this.secs = secs;
6571
this.frames = frames;
66-
sanityzeTime();
72+
sanityzeTime(true);
6773
return this;
6874
}
6975

@@ -72,71 +78,71 @@ public int getHours() {
7278
}
7379
public Timecode setHours(int hours) {
7480
this.hours = hours;
75-
sanityzeTime();
81+
sanityzeTime(true);
7682
return this;
7783
}
7884
public Timecode nextHour(){
7985
hours++;
80-
sanityzeTime();
86+
sanityzeTime(true);
8187
return this;
8288
}
8389
public Timecode previousHour(){
8490
hours--;
85-
sanityzeTime();
91+
sanityzeTime(true);
8692
return this;
8793
}
8894
public int getMins() {
8995
return mins;
9096
}
9197
public Timecode setMins(int mins) {
9298
this.mins = mins;
93-
sanityzeTime();
99+
sanityzeTime(true);
94100
return this;
95101
}
96102
public Timecode nextMin(){
97103
mins++;
98-
sanityzeTime();
104+
sanityzeTime(true);
99105
return this;
100106
}
101107
public Timecode previousMin(){
102108
mins--;
103-
sanityzeTime();
109+
sanityzeTime(true);
104110
return this;
105111
}
106112
public int getSecs() {
107113
return secs;
108114
}
109115
public Timecode setSecs(int secs) {
110116
this.secs = secs;
111-
sanityzeTime();
117+
sanityzeTime(true);
112118
return this;
113119
}
114120
public Timecode nextSec(){
115121
secs++;
116-
sanityzeTime();
122+
sanityzeTime(true);
117123
return this;
118124
}
119125
public Timecode previousSec(){
120126
secs--;
121-
sanityzeTime();
127+
sanityzeTime(true);
122128
return this;
123129
}
124130
public int getFrames() {
125131
return frames;
126132
}
127133
public Timecode setFrames(int frames) {
128134
this.frames = frames;
129-
sanityzeTime();
135+
sanityzeTime(true);
130136
return this;
131137
}
132138
public Timecode nextFrame(){
133139
frames++;
134-
sanityzeTime();
140+
sanityzeTime(true);
135141
return this;
136142
}
137143
public Timecode previousFrame(){
138144
frames--;
139-
sanityzeTime();
145+
sanityzeTime(true);
140146
return this;
141147
}
142148
public Framerates getFramerate() {
@@ -148,6 +154,9 @@ public Timecode setFramerate(Framerates framerate) {
148154
setTime(totalFrames);
149155
return this;
150156
}
157+
public TimecodePlayer getTimecodePlayer(){
158+
return tcPlayer;
159+
}
151160
public float getFrameWindow(){
152161
return 1000 / framerate.getFps();
153162
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package ovh.stranck.javaTimecode;
2+
3+
public class TimecodePlayer {
4+
private Timecode t;
5+
private boolean playing = true;
6+
private double speed;
7+
private int offset;
8+
private int zFrame;
9+
private long zMs;
10+
11+
public TimecodePlayer(Timecode t){
12+
this(t, 0);
13+
}
14+
public TimecodePlayer(Timecode t, double speed){
15+
this.t = t;
16+
setSpeed(speed);
17+
}
18+
19+
public synchronized TimecodePlayer updateTimecodeTime(){
20+
if(playing){
21+
//System.out.println((System.currentTimeMillis() - zMs) + " ");
22+
t.setTimeWithoutUpdatingStartPoint((int) ((System.currentTimeMillis() - zMs)
23+
* speed * t.getFramerate().getIntegerFramerate() / 1000 + zFrame + offset));
24+
}
25+
return this;
26+
}
27+
28+
public synchronized TimecodePlayer updateStartPoint(){
29+
zFrame = t.getTotalFrames();
30+
zMs = System.currentTimeMillis();
31+
return this;
32+
}
33+
34+
public synchronized TimecodePlayer play(){
35+
updateStartPoint();
36+
playing = true;
37+
return this;
38+
}
39+
public synchronized TimecodePlayer pause(){
40+
playing = false;
41+
return this;
42+
}
43+
44+
public synchronized TimecodePlayer setSpeed(double speed){
45+
this.speed = speed;
46+
updateStartPoint();
47+
return this;
48+
}
49+
public double getSpeed(){
50+
return speed;
51+
}
52+
public TimecodePlayer setOffset(int offset){
53+
this.offset = offset;
54+
return this;
55+
}
56+
public int getOffset(){
57+
return offset;
58+
}
59+
/*public synchronized TimecodePlayer setTimecode(Timecode t){
60+
this.t = t;
61+
return this;
62+
}*/
63+
public Timecode getTimecode(){
64+
return t;
65+
}
66+
}

src/main/java/ovh/stranck/javaTimecode/ltc/LTCGenerator.java

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
import javax.sound.sampled.Mixer;
77
import javax.sound.sampled.SourceDataLine;
88

9+
import ovh.stranck.javaTimecode.TimecodePlayer;
10+
import ovh.stranck.javaTimecode.Wait;
11+
912
public class LTCGenerator implements Runnable {
10-
private volatile boolean autoIncrement = true;
13+
private volatile float bufferCapacity = 0.5f;
14+
private volatile TimecodePlayer tcPlayer;
1115
private volatile LTCPacket packet;
1216

1317
private SourceDataLine dataLine;
@@ -18,7 +22,7 @@ public class LTCGenerator implements Runnable {
1822
public LTCGenerator(Mixer output, int sampleRate) throws LineUnavailableException{
1923
this.mixer = output;
2024
this.sampleRate = sampleRate;
21-
packet = new LTCPacket();
25+
setPacket(new LTCPacket());
2226

2327
AudioFormat format = new AudioFormat(sampleRate, 8, 1, true, true);
2428
SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
@@ -29,19 +33,17 @@ public LTCGenerator(Mixer output, int sampleRate) throws LineUnavailableExceptio
2933

3034
public void run() {
3135
byte[] content;
32-
long ms = System.currentTimeMillis() + (long)packet.getFrameWindow(), currentMs;
36+
tcPlayer.updateStartPoint();
3337
while(!Thread.interrupted()){
34-
content = packet.asAudioSample(sampleRate);
35-
dataLine.write(content, 0, content.length);
36-
37-
currentMs = System.currentTimeMillis();
38-
if(autoIncrement && currentMs >= ms){
39-
System.out.println(packet/* + " " + packet.asBitsString()*/);
40-
packet.nextFrame();
41-
ms = currentMs + (long)packet.getFrameWindow();
38+
if(dataLine.getBufferSize() * bufferCapacity < dataLine.available()){
39+
tcPlayer.updateTimecodeTime();
40+
content = packet.asAudioSample(sampleRate);
41+
dataLine.write(content, 0, content.length);
42+
System.out.println(packet);
4243
}
44+
Wait.wait(1);
4345
}
44-
System.out.println("Exit");
46+
dataLine.drain();
4547
}
4648

4749
public void start(){
@@ -58,19 +60,25 @@ public void destroy(){
5860
mixer.close();
5961
}
6062

63+
public LTCGenerator setBufferDimension(float dimension){
64+
bufferCapacity = dimension;
65+
return this;
66+
}
67+
public float getCustomBufferDimension(){
68+
return bufferCapacity;
69+
}
70+
public int getRealBufferDimension(){
71+
return dataLine.getBufferSize();
72+
}
6173
public LTCGenerator setPacket(LTCPacket packet){
6274
this.packet = packet;
75+
tcPlayer = packet.getTimecodePlayer();
6376
return this;
6477
}
6578
public LTCPacket getPacket(){
6679
return packet;
6780
}
68-
public LTCGenerator setAutoIncrement(boolean autoIncrement){
69-
this.autoIncrement = autoIncrement;
70-
return this;
71-
}
72-
public boolean isAutoIncrementing(){
73-
return autoIncrement;
81+
public TimecodePlayer getTimecodePlayer(){
82+
return tcPlayer;
7483
}
75-
7684
}

0 commit comments

Comments
 (0)