1use super::constants::*;
11use crate::{FrameRate, Timecode, TimecodeError};
12
13pub struct LtcEncoder {
15 #[allow(dead_code)]
17 sample_rate: u32,
18 #[allow(dead_code)]
20 frame_rate: FrameRate,
21 amplitude: f32,
23 samples_per_bit: f32,
25 #[allow(dead_code)]
27 phase: f32,
28 polarity: bool,
30}
31
32impl LtcEncoder {
33 pub fn new(sample_rate: u32, frame_rate: FrameRate, amplitude: f32) -> Self {
35 let fps = frame_rate.as_float();
36 let bits_per_second = fps * BITS_PER_FRAME as f64;
37 let samples_per_bit = sample_rate as f64 / bits_per_second;
38
39 LtcEncoder {
40 sample_rate,
41 frame_rate,
42 amplitude: amplitude.clamp(0.0, 1.0),
43 samples_per_bit: samples_per_bit as f32,
44 phase: 0.0,
45 polarity: false,
46 }
47 }
48
49 pub fn encode_frame(&mut self, timecode: &Timecode) -> Result<Vec<f32>, TimecodeError> {
51 let bits = self.timecode_to_bits(timecode)?;
53
54 let samples = self.bits_to_audio(&bits);
56
57 Ok(samples)
58 }
59
60 fn timecode_to_bits(
62 &self,
63 timecode: &Timecode,
64 ) -> Result<[bool; BITS_PER_FRAME], TimecodeError> {
65 let mut bits = [false; BITS_PER_FRAME];
66
67 let frame_units = timecode.frames % 10;
69 let frame_tens = timecode.frames / 10;
70 let second_units = timecode.seconds % 10;
71 let second_tens = timecode.seconds / 10;
72 let minute_units = timecode.minutes % 10;
73 let minute_tens = timecode.minutes / 10;
74 let hour_units = timecode.hours % 10;
75 let hour_tens = timecode.hours / 10;
76
77 self.encode_bcd(&mut bits, 0, frame_units);
79
80 self.encode_nibble(&mut bits, 4, (timecode.user_bits & 0xF) as u8);
82
83 self.encode_bcd(&mut bits, 8, frame_tens);
85
86 bits[10] = timecode.frame_rate.drop_frame;
88
89 bits[11] = false;
91
92 self.encode_nibble(&mut bits, 12, ((timecode.user_bits >> 4) & 0xF) as u8);
94
95 self.encode_bcd(&mut bits, 16, second_units);
97
98 self.encode_nibble(&mut bits, 20, ((timecode.user_bits >> 8) & 0xF) as u8);
100
101 self.encode_bcd(&mut bits, 24, second_tens);
103
104 bits[27] = self.calculate_even_parity(&bits[0..27]);
106
107 self.encode_nibble(&mut bits, 28, ((timecode.user_bits >> 12) & 0xF) as u8);
109
110 self.encode_bcd(&mut bits, 32, minute_units);
112
113 self.encode_nibble(&mut bits, 36, ((timecode.user_bits >> 16) & 0xF) as u8);
115
116 self.encode_bcd(&mut bits, 40, minute_tens);
118
119 bits[43] = false;
121
122 self.encode_nibble(&mut bits, 44, ((timecode.user_bits >> 20) & 0xF) as u8);
124
125 self.encode_bcd(&mut bits, 48, hour_units);
127
128 self.encode_nibble(&mut bits, 52, ((timecode.user_bits >> 24) & 0xF) as u8);
130
131 self.encode_bcd(&mut bits, 56, hour_tens);
133
134 bits[58] = false;
136
137 self.encode_nibble(&mut bits, 59, ((timecode.user_bits >> 28) & 0xF) as u8);
139
140 bits[63] = false;
142
143 self.encode_sync_word(&mut bits);
145
146 Ok(bits)
147 }
148
149 fn encode_bcd(&self, bits: &mut [bool; BITS_PER_FRAME], start: usize, value: u8) {
151 for i in 0..4 {
152 if start + i < BITS_PER_FRAME {
153 bits[start + i] = (value & (1 << i)) != 0;
154 }
155 }
156 }
157
158 fn encode_nibble(&self, bits: &mut [bool; BITS_PER_FRAME], start: usize, value: u8) {
160 for i in 0..4 {
161 if start + i < BITS_PER_FRAME {
162 bits[start + i] = (value & (1 << i)) != 0;
163 }
164 }
165 }
166
167 fn calculate_even_parity(&self, bits: &[bool]) -> bool {
169 let count = bits.iter().filter(|&&b| b).count();
170 count % 2 != 0
171 }
172
173 fn encode_sync_word(&self, bits: &mut [bool; BITS_PER_FRAME]) {
175 let sync_word = SYNC_WORD;
176 for i in 0..SYNC_BITS {
177 bits[DATA_BITS + i] = (sync_word & (1 << i)) != 0;
178 }
179 }
180
181 fn bits_to_audio(&mut self, bits: &[bool; BITS_PER_FRAME]) -> Vec<f32> {
183 let total_samples = (self.samples_per_bit * BITS_PER_FRAME as f32) as usize;
184 let mut samples = Vec::with_capacity(total_samples);
185
186 for &bit in bits.iter() {
187 let bit_samples = self.encode_bit_bmc(bit);
189 samples.extend_from_slice(&bit_samples);
190 }
191
192 samples
193 }
194
195 fn encode_bit_bmc(&mut self, bit: bool) -> Vec<f32> {
197 let samples_per_bit = self.samples_per_bit as usize;
198 let mut samples = Vec::with_capacity(samples_per_bit);
199
200 if bit {
201 for _ in 0..(samples_per_bit / 2) {
204 samples.push(if self.polarity {
205 self.amplitude
206 } else {
207 -self.amplitude
208 });
209 }
210 self.polarity = !self.polarity;
211
212 for _ in (samples_per_bit / 2)..samples_per_bit {
214 samples.push(if self.polarity {
215 self.amplitude
216 } else {
217 -self.amplitude
218 });
219 }
220 self.polarity = !self.polarity;
221 } else {
222 for _ in 0..samples_per_bit {
224 samples.push(if self.polarity {
225 self.amplitude
226 } else {
227 -self.amplitude
228 });
229 }
230 self.polarity = !self.polarity;
231 }
232
233 samples
234 }
235
236 pub fn reset(&mut self) {
238 self.phase = 0.0;
239 self.polarity = false;
240 }
241
242 pub fn set_amplitude(&mut self, amplitude: f32) {
244 self.amplitude = amplitude.clamp(0.0, 1.0);
245 }
246
247 pub fn amplitude(&self) -> f32 {
249 self.amplitude
250 }
251}
252
253#[allow(dead_code)]
255struct WaveformShaper {
256 rise_time: usize,
258 transition_progress: usize,
260 target_level: f32,
262 current_level: f32,
264}
265
266impl WaveformShaper {
267 #[allow(dead_code)]
268 fn new(sample_rate: u32, rise_time_us: f32) -> Self {
269 let rise_time = ((rise_time_us / 1_000_000.0) * sample_rate as f32) as usize;
270
271 WaveformShaper {
272 rise_time: rise_time.max(1),
273 transition_progress: 0,
274 target_level: 0.0,
275 current_level: 0.0,
276 }
277 }
278
279 #[allow(dead_code)]
281 fn set_target(&mut self, level: f32) {
282 if (level - self.target_level).abs() > 0.001 {
283 self.target_level = level;
284 self.transition_progress = 0;
285 }
286 }
287
288 #[allow(dead_code)]
290 fn next_sample(&mut self) -> f32 {
291 if self.transition_progress < self.rise_time {
292 let progress = self.transition_progress as f32 / self.rise_time as f32;
294 self.current_level =
295 self.current_level * (1.0 - progress) + self.target_level * progress;
296 self.transition_progress += 1;
297 } else {
298 self.current_level = self.target_level;
299 }
300
301 self.current_level
302 }
303
304 #[allow(dead_code)]
305 fn reset(&mut self) {
306 self.transition_progress = 0;
307 self.current_level = 0.0;
308 }
309}
310
311#[allow(dead_code)]
313struct PreEmphasisFilter {
314 alpha: f32,
316 prev_input: f32,
318 prev_output: f32,
320}
321
322impl PreEmphasisFilter {
323 #[allow(dead_code)]
324 fn new(time_constant_us: f32, sample_rate: u32) -> Self {
325 let tc = time_constant_us / 1_000_000.0;
326 let dt = 1.0 / sample_rate as f32;
327 let alpha = tc / (tc + dt);
328
329 PreEmphasisFilter {
330 alpha,
331 prev_input: 0.0,
332 prev_output: 0.0,
333 }
334 }
335
336 #[allow(dead_code)]
338 fn process(&mut self, input: f32) -> f32 {
339 let output = self.alpha * (self.prev_output + input - self.prev_input);
340 self.prev_input = input;
341 self.prev_output = output;
342 output
343 }
344
345 #[allow(dead_code)]
346 fn reset(&mut self) {
347 self.prev_input = 0.0;
348 self.prev_output = 0.0;
349 }
350}
351
352#[allow(dead_code)]
354struct DcBlocker {
355 alpha: f32,
357 prev_input: f32,
359 prev_output: f32,
361}
362
363impl DcBlocker {
364 #[allow(dead_code)]
365 fn new(cutoff_hz: f32, sample_rate: u32) -> Self {
366 let rc = 1.0 / (2.0 * std::f32::consts::PI * cutoff_hz);
367 let dt = 1.0 / sample_rate as f32;
368 let alpha = rc / (rc + dt);
369
370 DcBlocker {
371 alpha,
372 prev_input: 0.0,
373 prev_output: 0.0,
374 }
375 }
376
377 #[allow(dead_code)]
379 fn process(&mut self, input: f32) -> f32 {
380 let output = self.alpha * (self.prev_output + input - self.prev_input);
381 self.prev_input = input;
382 self.prev_output = output;
383 output
384 }
385
386 #[allow(dead_code)]
387 fn reset(&mut self) {
388 self.prev_input = 0.0;
389 self.prev_output = 0.0;
390 }
391}
392
393#[allow(dead_code)]
395struct Limiter {
396 threshold: f32,
398 attack_samples: usize,
400 release_samples: usize,
402 gain_reduction: f32,
404}
405
406impl Limiter {
407 #[allow(dead_code)]
408 fn new(threshold: f32, attack_ms: f32, release_ms: f32, sample_rate: u32) -> Self {
409 let attack_samples = ((attack_ms / 1000.0) * sample_rate as f32) as usize;
410 let release_samples = ((release_ms / 1000.0) * sample_rate as f32) as usize;
411
412 Limiter {
413 threshold,
414 attack_samples: attack_samples.max(1),
415 release_samples: release_samples.max(1),
416 gain_reduction: 1.0,
417 }
418 }
419
420 #[allow(dead_code)]
422 fn process(&mut self, input: f32) -> f32 {
423 let abs_input = input.abs();
424
425 if abs_input > self.threshold {
426 let target_gain = self.threshold / abs_input;
428 let attack_coefficient = 1.0 / self.attack_samples as f32;
429 self.gain_reduction += (target_gain - self.gain_reduction) * attack_coefficient;
430 } else {
431 let release_coefficient = 1.0 / self.release_samples as f32;
433 self.gain_reduction += (1.0 - self.gain_reduction) * release_coefficient;
434 }
435
436 input * self.gain_reduction
437 }
438
439 #[allow(dead_code)]
440 fn reset(&mut self) {
441 self.gain_reduction = 1.0;
442 }
443}
444
445pub struct LtcFrameBuffer {
447 sample_rate: u32,
449 frame_rate: FrameRate,
451 amplitude: f32,
453 buffer: Vec<f32>,
455 current_timecode: Option<Timecode>,
457}
458
459impl LtcFrameBuffer {
460 pub fn new(sample_rate: u32, frame_rate: FrameRate, amplitude: f32) -> Self {
462 LtcFrameBuffer {
463 sample_rate,
464 frame_rate,
465 amplitude,
466 buffer: Vec::new(),
467 current_timecode: None,
468 }
469 }
470
471 pub fn set_timecode(&mut self, timecode: Timecode) {
473 self.current_timecode = Some(timecode);
474 }
475
476 pub fn generate_frame(&mut self) -> Result<Vec<f32>, TimecodeError> {
478 if let Some(ref mut tc) = self.current_timecode {
479 let mut encoder = LtcEncoder::new(self.sample_rate, self.frame_rate, self.amplitude);
480 let samples = encoder.encode_frame(tc)?;
481
482 tc.increment()?;
484
485 Ok(samples)
486 } else {
487 Err(TimecodeError::InvalidConfiguration)
488 }
489 }
490
491 pub fn fill_buffer(&mut self, target_samples: usize) -> Result<(), TimecodeError> {
493 while self.buffer.len() < target_samples {
494 let frame_samples = self.generate_frame()?;
495 self.buffer.extend_from_slice(&frame_samples);
496 }
497 Ok(())
498 }
499
500 pub fn read_samples(&mut self, count: usize) -> Vec<f32> {
502 let available = self.buffer.len().min(count);
503 let samples: Vec<f32> = self.buffer.drain(..available).collect();
504 samples
505 }
506
507 pub fn buffer_level(&self) -> usize {
509 self.buffer.len()
510 }
511}
512
513pub struct UserBitsEncoder;
515
516impl UserBitsEncoder {
517 pub fn encode_ascii(text: &str) -> u32 {
519 let bytes = text.as_bytes();
520 let mut user_bits = 0u32;
521
522 for (i, &byte) in bytes.iter().take(4).enumerate() {
523 user_bits |= (byte as u32) << (i * 8);
524 }
525
526 user_bits
527 }
528
529 pub fn encode_date(month: u8, day: u8, year: u16) -> u32 {
531 let mut user_bits = 0u32;
532
533 user_bits |= (month / 10) as u32;
535 user_bits |= ((month % 10) as u32) << 4;
536
537 user_bits |= ((day / 10) as u32) << 8;
539 user_bits |= ((day % 10) as u32) << 12;
540
541 let year_short = (year % 100) as u8;
543 user_bits |= ((year_short / 10) as u32) << 16;
544 user_bits |= ((year_short % 10) as u32) << 20;
545
546 user_bits
547 }
548
549 pub fn encode_binary(data: u32) -> u32 {
551 data
552 }
553}
554
555pub struct SignalQualityMetrics {
557 pub peak_amplitude: f32,
559 pub rms_amplitude: f32,
561 pub crest_factor: f32,
563 pub dc_offset: f32,
565}
566
567impl SignalQualityMetrics {
568 pub fn from_samples(samples: &[f32]) -> Self {
570 let mut sum = 0.0;
571 let mut sum_squared = 0.0;
572 let mut peak: f32 = 0.0;
573
574 for &sample in samples {
575 sum += sample;
576 sum_squared += sample * sample;
577 peak = peak.max(sample.abs());
578 }
579
580 let dc_offset = sum / samples.len() as f32;
581 let rms = (sum_squared / samples.len() as f32).sqrt();
582 let crest_factor = if rms > 0.0 { peak / rms } else { 0.0 };
583
584 SignalQualityMetrics {
585 peak_amplitude: peak,
586 rms_amplitude: rms,
587 crest_factor,
588 dc_offset,
589 }
590 }
591}
592
593#[cfg(test)]
594mod tests {
595 use super::*;
596
597 #[test]
598 fn test_encoder_creation() {
599 let encoder = LtcEncoder::new(48000, FrameRate::Fps25, 0.5);
600 assert_eq!(encoder.amplitude(), 0.5);
601 }
602
603 #[test]
604 fn test_encode_frame() {
605 let mut encoder = LtcEncoder::new(48000, FrameRate::Fps25, 0.5);
606 let timecode = Timecode::new(1, 2, 3, 4, FrameRate::Fps25).unwrap();
607 let samples = encoder.encode_frame(&timecode).unwrap();
608 assert!(!samples.is_empty());
609 }
610
611 #[test]
612 fn test_user_bits_ascii() {
613 let user_bits = UserBitsEncoder::encode_ascii("TEST");
614 assert_ne!(user_bits, 0);
615 }
616
617 #[test]
618 fn test_user_bits_date() {
619 let user_bits = UserBitsEncoder::encode_date(12, 31, 2023);
620 assert_ne!(user_bits, 0);
621 }
622
623 #[test]
624 fn test_even_parity() {
625 let encoder = LtcEncoder::new(48000, FrameRate::Fps25, 0.5);
626 let bits = [true, false, true]; assert!(!encoder.calculate_even_parity(&bits));
628
629 let bits = [true, false, false]; assert!(encoder.calculate_even_parity(&bits));
631 }
632}