timecode_coder/ltc_frame/
mod.rs

1use core::fmt::{Debug, Display, Formatter};
2use intbits::Bits;
3use crate::ltc_frame::ltc_frame_data::LtcFrameData;
4
5pub(crate) mod ltc_frame_data;
6
7/// Represents 80 bits that represent a ltc-tc-frame
8/// Contains functions to push bits received by an audio signal and read it's value as well as functions to write bits to the audio
9pub(crate) struct LtcFrame {
10    ///Are on higher index of all bits received
11    sync_word: u16,
12    ///Contains the data of the old-frame, if the frame is complete
13    data: LtcFrameData,
14    /// Tells how many samples it took to get a whole tc-frame without sync-word
15    frame_data_sample_count: usize,
16}
17
18impl LtcFrame {}
19
20#[cfg(test)]
21impl PartialEq<Self> for LtcFrame {
22    fn eq(&self, other: &Self) -> bool {
23        self.data == other.data && self.sync_word == other.sync_word
24    }
25}
26
27///Implementations that are used to decode and encode timecode
28impl LtcFrame {
29    const LTC_SYNC_WORD: u16 = 0b_0011_1111_1111_1101;
30
31    /// Invalidates the current status of the ltc-frame
32    pub(crate) fn invalidate(&mut self) {
33        self.data.invalidate();
34        self.sync_word = 0;
35    }
36}
37
38#[cfg(feature = "debug")]
39impl Debug for LtcFrame {
40    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
41        write!(f, "sync_word: 0b_{:04b}_{:04b}_{:04b}_{:04b}\ndata: {:?}",
42               self.sync_word.bits(12..16),
43               self.sync_word.bits(8..12),
44               self.sync_word.bits(4..8),
45               self.sync_word.bits(0..4),
46               self.data
47        )
48    }
49}
50
51#[cfg(feature = "debug")]
52impl Display for LtcFrame {
53    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
54        write!(f, "sync_word:{}\ndata: {}", self.sync_word == Self::LTC_SYNC_WORD.bits(12..16), self.data)
55    }
56}
57
58#[cfg(feature = "decode_ltc")]
59impl LtcFrame {
60    ///Constructor that is used when reading ltc stream from audio
61    pub(crate) fn new_empty() -> Self {
62        Self {
63            sync_word: 0,
64            data: LtcFrameData::new_empty(),
65            frame_data_sample_count: 0,
66        }
67    }
68    ///When a new audio bit is received, this function will shift all received data and add it to the end. Once the sync_word matches, the data is a valid frame
69    pub(crate) fn shift_bit(&mut self, bit: bool) {
70        let overflow_bit = self.data.shift_bit_with_overflow(bit);
71        self.sync_word <<= 1;
72        self.sync_word.set_bit(0, overflow_bit);
73    }
74    ///Tells if all data is received by the audio stream after the sync-word
75    pub(crate) fn data_valid(&self) -> bool {
76        self.sync_word == Self::LTC_SYNC_WORD
77    }
78    ///Used to count how many samples a timecode-frame has needed to complete do determine FramesPerSecond of LTC
79    pub(crate) fn sample_received(&mut self) {
80        if self.data.next_bit_is_start_of_frame() {
81            self.frame_data_sample_count = 0;
82        } else {
83            self.frame_data_sample_count += 1;
84        }
85    }
86
87    ///Returns the data read from audio decoding only if all data has been received after the sync-word
88    /// It may be more efficient to first check if data_valid() returns true due to less memory allocation in ram
89    pub(crate) fn get_data(&mut self) -> Option<(LtcFrameData, usize)> {
90        if self.data_valid() {
91            Some((self.data.clone(), self.frame_data_sample_count))
92        } else {
93            None
94        }
95    }
96}