https://github.com/cppplayground/ltc-lineartimecode-smpte
A LinearTimecode decode library for Arduino.cc
https://github.com/cppplayground/ltc-lineartimecode-smpte
Last synced: about 1 year ago
JSON representation
A LinearTimecode decode library for Arduino.cc
- Host: GitHub
- URL: https://github.com/cppplayground/ltc-lineartimecode-smpte
- Owner: CppPlayground
- License: apache-2.0
- Created: 2022-08-31T20:53:59.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2024-04-10T05:22:49.000Z (over 2 years ago)
- Last Synced: 2025-02-25T02:43:55.917Z (over 1 year ago)
- Language: C++
- Homepage:
- Size: 178 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# LTC LinearTimecode (SMPTE)
A LinearTimecode decode library for [Arduino.cc](https://www.arduino.cc)
Use this library to decode linear timecodes. You can generate such timecodes for example on the [elteesee](https://elteesee.pehrhovey.net) website made by [pehrhovey](http://pehrhovey.net/blog/about/). You can find more references in [this wikipedia](https://en.wikipedia.org/wiki/Linear_timecode) article.
> Skip to [How to use the library](#how-to-use-the-library)
----
### What is LTC?
"LTC" stands for "Linear Timecode" and is used to encode/decode timecode data in an audio signal. Basically you have an audio signal that runs synchronously with the music or the film and in which the timecode is stored as a bit sequence. You can also store the date in a timecode, but I'll just cover the time for now.
----
### How does LTC work?
The time code consists of 8 bytes and a fixed sync word at the end. So 10 bytes in total. The fixed sync word at the end is used to tell the decoder that the sequence has ended.
> A long bit period corresponds to a 0 bit
A double short bit period corresponds to a 1 bit
#### Example for one frame
> This example shows the timecode `00:00:00.00`

> [Raw image](https://raw.githubusercontent.com/Mqxx/LTC-LinearTimecode-SMPTE/main/assets/signwave.svg)
#### Which byte does what?
Byte | Bit | Visuel | Meaning
:---: |:---: |:---: |:---
A | `0` - `3` | `--:--:--.-X` | Frame number units (0โ9)
B | `0` - `3` | `--:--:--.X-` | Frame number tens (0-2)
C | `0` - `3` | `--:--:-X.--` | Seconds number units (0โ9)
D | `0` - `3` | `--:--:X-.--` | Seconds number tens (0โ5)
E | `0` - `3` | `--:-X:--.--` | Minutes number units (0-9)
F | `0` - `3` | `--:X-:--.--` | Minutes number tens (0-5)
G | `0` - `3` | `-X:--:--.--` | Hours number units (0-9)
H | `0` - `3` | `X-:--:--.--` | Hours number tens (0-2)
I | `0` - `7` | | Sync word
J | `0` - `7` | | Sync word
> Binary decimal numbers [wiki](https://en.wikipedia.org/wiki/Binary_number)
----
### How does the library decode the timecode?
#### Standards
First, there are different timecode standards, which differ in the number of frames or the length of a frame as you can see on the [elteesee](https://elteesee.pehrhovey.net) website.
- 23.976 F
- 24 F
- 25 F
- 29.97ndf (no drop frame)
- 30 F
#### Calculate one bit lenght
To calculate how long one bit lasts, we need to do a bit of math. Got it? A *bit* of math? Nahh lets go on ๐
:
```ino
// convert framerate to ms
float framerate = 25.00;
float ms = 1000 / framerate;
// now calculate how long one bit is
// a frame consists of 80 bits
// this gives us back how long one bit is in ms
float oneBit = ms / 80;
// convert ms to ยตs and cast to int and we have the bit length in ยตs
const int bitLength = int(oneBit * 1000);
```
Now the library just waits for an interrupt. An interrupt occurs when the sine wave crosses 0. Then the library checks the time difference between the two interrupts. A short time between two interrupts means that a 1 bit has arrived, and a long time between two interrupts means that a 0 bit has arrived.
----
### How to use the library?
#### Syntax
###### constructor
```ino
LinearTimecode::LinearTimecode(LinearTimecode::frameTypes frameType);
```
`enum frameType` : `{ FRAME_23_976, FRAME_24, FRAME_25, NO_DROP_FRAME_29_97, FRAME_30 }`
```ino
LinearTimecode::LinearTimecode(const unsigned int frameDuration);
```
`const unsigned int frameDuration` : `duration`
###### methodes
```ino
const int LinearTimecode::getBitLength();
```
> Returns the bit length of one bit.
```ino
uint8_t LinearTimecode::getByteBuffer(const unsigned int index);
```
`const unsigned int index` : `index`
> Returns the byte buffer at the specified index.
```ino
float LinearTimecode::getFramerate();
```
> Returns the set frame rate as a floating point number
```ino
const int LinearTimecode::getFrames();
```
> Returns the current frame
```ino
const int LinearTimecode::getSeconds();
```
> Returns the current second
```ino
const int LinearTimecode::getMinutes();
```
> Returns the current minute
```ino
const int LinearTimecode::getHours();
```
> Returns the current hour
```ino
String LinearTimecode::getTimecode(LinearTimecode::formats format);
```
`enum format` : `{ FORMAT_DOT, FORMAT_COLON, FORMAT_DOT_COLON, FORMAT_SPACE }`
> Returns the timecode in a string format
> Format | Visual
> :--- |:---:
> `FORMAT_DOT` | `HH.MM.SS.FF`
> `FORMAT_COLON` | `HH:MM:SS:FF`
> `FORMAT_DOT_COLON` | `HH:MM:SS.FF`
> `FORMAT_SPACE` | `HH MM SS FF`
```ino
void LinearTimecode::onEdgeChange();
```
> Needs to be executed on an interrupt change on the audio pin
```ino
void LinearTimecode::onSync(void (*callback)());
```
`void (*callback)()` : `function to execute`
> Gets called when the sync pattern is detected
```ino
void LinearTimecode::setShortEdgeDuration(const unsigned int min, const unsigned int max);
```
`const unsigned int min` : `the minimum short edge duration`
`const unsigned int max` : `the maximum short edge duration`
> Set the minimum and maximum duration of the short edge
```ino
void LinearTimecode::setLongEdgeDuration(const unsigned int min, const unsigned int max);
```
`const unsigned int min` : `the minimum long edge duration`
`const unsigned int max` : `the maximum long edge duration`
> Set the minimum and maximum duration of the long edge
```ino
void LinearTimecode::setSyncPattern(word pattern);
```
`word pattern` : `sync pattern`
> Set the sync pattern
#### Example
###### code
```ino
// include
// include the libary
#include
// define
// the audio in pin needs to be an change intrrupt pin!
#define AUDIO_IN 2
// Create a new LinearTimecode class instance (I'll call it "ltc") with a frame rate of 25 frames
LinearTimecode ltc(ltc.FRAME_30);
// the setup function
void setup() {
// begin serial
Serial.begin(115200);
// attach the interrupt pin to pin 2
attachInterrupt(2, [](){
// call the onEdgeChange() method of your class instance
// this needs to be in a lambda function!
ltc.onEdgeChange();
}, CHANGE);
// call the onSync() method of your class instance
ltc.onSync([](){
// print the result in the console
Serial.println(ltc.getTimecode(ltc.FORMAT_DOT_COLON));
});
}
void loop() {
}
```
###### output
```
10:03:12.13
```
> Example timecode