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> {
84 Ok(None)
86 }
87
88 fn frame_rate(&self) -> FrameRate {
89 self.frame_rate
90 }
91
92 fn is_synchronized(&self) -> bool {
93 self.decoder.is_synchronized()
94 }
95}
96
97#[derive(Debug, Clone)]
99pub struct LtcWriterConfig {
100 pub sample_rate: u32,
102 pub frame_rate: FrameRate,
104 pub amplitude: f32,
106}
107
108impl Default for LtcWriterConfig {
109 fn default() -> Self {
110 LtcWriterConfig {
111 sample_rate: 48000,
112 frame_rate: FrameRate::Fps25,
113 amplitude: 0.5,
114 }
115 }
116}
117
118pub struct LtcWriter {
120 encoder: encoder::LtcEncoder,
121 frame_rate: FrameRate,
122}
123
124impl LtcWriter {
125 pub fn new(config: LtcWriterConfig) -> Self {
127 LtcWriter {
128 encoder: encoder::LtcEncoder::new(
129 config.sample_rate,
130 config.frame_rate,
131 config.amplitude,
132 ),
133 frame_rate: config.frame_rate,
134 }
135 }
136
137 pub fn encode_frame(&mut self, timecode: &Timecode) -> Result<Vec<f32>, TimecodeError> {
139 self.encoder.encode_frame(timecode)
140 }
141
142 pub fn reset(&mut self) {
144 self.encoder.reset();
145 }
146}
147
148impl TimecodeWriter for LtcWriter {
149 fn write_timecode(&mut self, timecode: &Timecode) -> Result<(), TimecodeError> {
150 let _samples = self.encode_frame(timecode)?;
151 Ok(())
153 }
154
155 fn frame_rate(&self) -> FrameRate {
156 self.frame_rate
157 }
158
159 fn flush(&mut self) -> Result<(), TimecodeError> {
160 Ok(())
161 }
162}
163
164pub(crate) mod constants {
166 pub const SYNC_WORD: u16 = 0x3FFD;
168
169 pub const BITS_PER_FRAME: usize = 80;
171
172 pub const DATA_BITS: usize = 64;
174
175 pub const SYNC_BITS: usize = 16;
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn test_ltc_reader_creation() {
185 let config = LtcReaderConfig::default();
186 let _reader = LtcReader::new(config);
187 }
188
189 #[test]
190 fn test_ltc_writer_creation() {
191 let config = LtcWriterConfig::default();
192 let _writer = LtcWriter::new(config);
193 }
194
195 #[test]
196 fn test_sync_word() {
197 assert_eq!(constants::SYNC_WORD, 0x3FFD);
198 assert_eq!(constants::BITS_PER_FRAME, 80);
199 }
200}