oximedia_timecode/ltc/
mod.rs1pub mod decoder;
19pub mod encoder;
20
21use crate::{FrameRate, Timecode, TimecodeError, TimecodeReader, TimecodeWriter};
22
23#[derive(Debug, Clone)]
25pub struct LtcReaderConfig {
26 pub sample_rate: u32,
28 pub frame_rate: FrameRate,
30 pub min_amplitude: f32,
32 pub max_speed: f32,
34}
35
36impl Default for LtcReaderConfig {
37 fn default() -> Self {
38 LtcReaderConfig {
39 sample_rate: 48000,
40 frame_rate: FrameRate::Fps25,
41 min_amplitude: 0.1,
42 max_speed: 2.0,
43 }
44 }
45}
46
47pub struct LtcReader {
49 decoder: decoder::LtcDecoder,
50 frame_rate: FrameRate,
51}
52
53impl LtcReader {
54 pub fn new(config: LtcReaderConfig) -> Self {
56 LtcReader {
57 decoder: decoder::LtcDecoder::new(
58 config.sample_rate,
59 config.frame_rate,
60 config.min_amplitude,
61 ),
62 frame_rate: config.frame_rate,
63 }
64 }
65
66 pub fn process_samples(&mut self, samples: &[f32]) -> Result<Option<Timecode>, TimecodeError> {
68 self.decoder.process_samples(samples)
69 }
70
71 pub fn reset(&mut self) {
73 self.decoder.reset();
74 }
75
76 pub fn sync_confidence(&self) -> f32 {
78 self.decoder.sync_confidence()
79 }
80}
81
82impl TimecodeReader for LtcReader {
83 fn read_timecode(&mut self) -> Result<Option<Timecode>, TimecodeError> {
94 Ok(self.decoder.last_decoded_timecode())
95 }
96
97 fn frame_rate(&self) -> FrameRate {
98 self.frame_rate
99 }
100
101 fn is_synchronized(&self) -> bool {
102 self.decoder.is_synchronized()
103 }
104}
105
106#[derive(Debug, Clone)]
108pub struct LtcWriterConfig {
109 pub sample_rate: u32,
111 pub frame_rate: FrameRate,
113 pub amplitude: f32,
115}
116
117impl Default for LtcWriterConfig {
118 fn default() -> Self {
119 LtcWriterConfig {
120 sample_rate: 48000,
121 frame_rate: FrameRate::Fps25,
122 amplitude: 0.5,
123 }
124 }
125}
126
127pub struct LtcWriter {
129 encoder: encoder::LtcEncoder,
130 frame_rate: FrameRate,
131}
132
133impl LtcWriter {
134 pub fn new(config: LtcWriterConfig) -> Self {
136 LtcWriter {
137 encoder: encoder::LtcEncoder::new(
138 config.sample_rate,
139 config.frame_rate,
140 config.amplitude,
141 ),
142 frame_rate: config.frame_rate,
143 }
144 }
145
146 pub fn encode_frame(&mut self, timecode: &Timecode) -> Result<Vec<f32>, TimecodeError> {
148 self.encoder.encode_frame(timecode)
149 }
150
151 pub fn reset(&mut self) {
153 self.encoder.reset();
154 }
155}
156
157impl TimecodeWriter for LtcWriter {
158 fn write_timecode(&mut self, timecode: &Timecode) -> Result<(), TimecodeError> {
159 let _samples = self.encode_frame(timecode)?;
160 Ok(())
162 }
163
164 fn frame_rate(&self) -> FrameRate {
165 self.frame_rate
166 }
167
168 fn flush(&mut self) -> Result<(), TimecodeError> {
169 Ok(())
170 }
171}
172
173pub(crate) mod constants {
175 pub const SYNC_WORD: u16 = 0x3FFD;
177
178 pub const BITS_PER_FRAME: usize = 80;
180
181 pub const DATA_BITS: usize = 64;
183
184 pub const SYNC_BITS: usize = 16;
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn test_ltc_reader_creation() {
194 let config = LtcReaderConfig::default();
195 let _reader = LtcReader::new(config);
196 }
197
198 #[test]
199 fn test_ltc_writer_creation() {
200 let config = LtcWriterConfig::default();
201 let _writer = LtcWriter::new(config);
202 }
203
204 #[test]
205 fn test_sync_word() {
206 assert_eq!(constants::SYNC_WORD, 0x3FFD);
207 assert_eq!(constants::BITS_PER_FRAME, 80);
208 }
209}