Forum Rule: Always post complete source code & details to reproduce any issue!
Page 7 of 7 FirstFirst ... 5 6 7
Results 151 to 164 of 164

Thread: Audio Library for Linear Timecode (LTC)?

  1. #151
    3.6
    As you probably already noticed, I'm not a high level programmer. Still have to learn a lot.
    What is the purpose of pin 0 in your example. ( syncpin) i left it unconnected.

  2. #152
    I have a working code for syncing the input to the output. (like a tentikal) Pulling pin 2 down to ground will set the sync.
    Here is my code. (could be written better I think)

    /*
    Linear Timecode generation and decoding combined

    Please modify as needed

    (c) Frank B, 2020
    (pls keep copyright-info)

    To enable decoding:
    #define USE_LTC_INPUT
    and connect pin1 to pinA2 (=pin 16) !!!! I see no use to do this ????

    PIN 2 : if set low it will sync incoming TC to the output TC . Then you can disconnect input TC and output will continue

    Licence: MIT
    */
    bool insync=0;
    int incominghours=0;
    int incomingminutes=0;
    int incomingseconds=0;
    int incomingframes=0;

    #define USE_LTC_INPUT //comment-out for generation only
    float fps = 25;
    const int ltcPin = 1;
    const int syncPin = 0;

    #include "TimeLib.h"

    #ifdef USE_LTC_INPUT
    /*
    Connect ltc
    */
    #include <Audio.h>
    #include <analyze_ltc.h>
    AudioInputAnalog adc1;
    AudioAnalyzeLTC ltc1;
    AudioConnection patchCord2(adc1, 0, ltc1, 0);

    #else
    struct ltcframe_t {
    uint64_t data;
    uint16_t sync;
    };
    #endif

    IntervalTimer ltcTimer;
    IntervalTimer fpsTimer;

    volatile int clkCnt = 0;
    ltcframe_t ltc;
    float ltcTimer_freq;

    time_t getTeensy3Time()
    {
    return Teensy3Clock.get();
    }

    void genLtc() {
    static int state = 0;

    if (clkCnt++ >= 2 * 80) {
    //ltcTimer.end();
    clkCnt = 0;
    return;
    }

    int bitval;
    int bitcount = clkCnt / 2;

    ltcframe_t ltct;
    ltct = ltc;

    if (bitcount < 64) {
    bitval = (int) (ltct.data >> bitcount) & 0x01;
    } else {
    bitval = (int) (ltct.sync >> (bitcount - 64)) & 0x01; //backward
    }

    if ( (bitval == 1) || ( (bitval == 0) && (clkCnt & 0x01) ) == 0) {
    state = !state; // toggle state
    digitalWriteFast(ltcPin, state);
    }

    }

    //https://www.geeksforgeeks.org/program-to-find-parity/
    inline
    int getParity(uint64_t n)
    {
    int parity = 0;
    while (n)
    {
    parity = !parity;
    n = n & (n - 1);
    }
    return parity & 0x01;
    }


    /*

    Gets called by rising edge of syncPin
    */
    void startLtc() {

    ltcTimer.begin(genLtc, ltcTimer_freq);
    ltcTimer.priority(0);

    int t, t10;
    uint64_t data = ltc.data;
    clkCnt = 0;

    //get frame number:
    t = ((data >> 8) & 0x03) * 10 + (data & 0x0f);

    //zero out ltc data, leave d+c flags and user-bits untouched:
    data &= 0xf0f0f0f0f0f0fcf0ULL;
    //data = 0;
    //inc frame-number:
    //TODO: realize "drop frame numbering" (when D-Flag is set)
    t++;
    if (t >= (int) fps) t = 0;
    //set frame number:
    t10 = t / 10;
    data |= (t10 & 0x03) << 8;
    data |= ((t - t10 * 10)) << 0;
    printTCout();
    Serial.printf("%02d\n", t);

    //set time:
    t = second();
    t10 = t / 10;
    data |= (t10 & 0x07) << 24; //Seconds tens
    data |= ((t - t10 * 10) & 0x0f) << 16;

    t = minute();
    t10 = t / 10;
    data |= (uint64_t)(t10 & 0x07) << 40; //minute tens
    data |= (uint64_t)((t - t10 * 10) & 0x0f) << 32;

    t = hour();
    t10 = t / 10;
    data |= (uint64_t)(t10 & 0x03) << 56; //hour tens
    data |= (uint64_t)((t - t10 * 10) & 0x0f) << 48;

    //set parity:
    int parity = (!getParity(data)) & 0x01;
    if ((int) fps == 25) {
    data |= (uint64_t) parity << 59;
    } else {
    data |= (uint64_t) parity << 27;
    }

    ltc.data = data;

    }

    void initLtcData()
    {
    ltc.sync = 0xBFFC;
    ltc.data = (uint64_t) 0; //<- place your initial data here
    }

    void genFpsSync() {
    static int state = 0;
    state = !state; // toggle state
    digitalWriteFast(syncPin, state);
    }


    void setup() {

    Serial.begin(115200);
    delay(200);
    #ifdef USE_LTC_INPUT
    AudioMemory(4);
    #endif
    setSyncProvider(getTeensy3Time);
    pinMode(syncPin, OUTPUT);
    pinMode(ltcPin, OUTPUT);
    pinMode(2, INPUT_PULLUP);
    ltcTimer_freq = (1.0f / (2 * 80 * (fps ))) * 1000000.0f - 0.125f;// -0.125: make it a tiny bit faster than needed to allow syncing
    initLtcData();
    //set frame number to last frame to force roll-over with new second()
    ltc.data &= 0xf0f0f0f0f0f0fcf0ULL; //delete all dynamic data in frame
    int t, t10;
    t = fps;
    t10 = t / 10;
    ltc.data |= (t10 & 0x03) << 8;
    ltc.data |= ((t - t10 * 10));
    //now wait for seconds-change
    int secs = second();
    while (secs == second()) {;}

    //start timer and pin-interrupt:
    fpsTimer.begin(&genFpsSync, (1.0f / (2 * fps)) * 1000000.0f);
    fpsTimer.priority(0);
    attachInterrupt(digitalPinToInterrupt(syncPin), &startLtc, RISING);
    NVIC_SET_PRIORITY(88, 0); //set GPIO-INT-Priority for Pin 1

    }

    void loop() {
    if (ltc1.available()) {
    ltcframe_t ltcframe = ltc1.read();
    incominghours=ltc1.hour(&ltcframe);
    incomingminutes=ltc1.minute(&ltcframe);
    incomingseconds=ltc1.second(&ltcframe);
    incomingframes=ltc1.frame(&ltcframe);
    Serial.printf("TC in : %02d:%02d:%02d.%02d\n\n", ltc1.hour(&ltcframe), ltc1.minute(&ltcframe), ltc1.second(&ltcframe), ltc1.frame(&ltcframe));
    }

    bool inpin = digitalRead(2);
    if (inpin==0 && insync==0){
    if (incomingframes==0){
    detachInterrupt(digitalPinToInterrupt(syncPin));
    fpsTimer.end();
    setTime(incominghours,incomingminutes,incomingseco nds, 01, 01, 2022);
    Teensy3Clock.set(now());
    ltcTimer_freq = (1.0f / (2 * 80 * (fps ))) * 1000000.0f - 0.125f;// -0.125: make it a tiny bit faster than needed to allow syncing
    initLtcData();
    //set frame number to last frame to force roll-over with new second()
    ltc.data &= 0xf0f0f0f0f0f0fcf0ULL; //delete all dynamic data in frame
    int t, t10;
    t = fps;
    t10 = t / 10;
    ltc.data |= (t10 & 0x03) << 8;
    ltc.data |= ((t - t10 * 10));
    //now wait for seconds-change
    int secs = second();
    while (secs == second()) {;}
    //start timer and pin-interrupt:
    fpsTimer.begin(&genFpsSync, (1.0f / (2 * fps)) * 1000000.0f);
    fpsTimer.priority(0);
    attachInterrupt(digitalPinToInterrupt(syncPin), &startLtc, RISING);
    NVIC_SET_PRIORITY(88, 0); //set GPIO-INT-Priority for Pin 1
    insync=1;

    }
    }
    }

    void printTCout(){
    Serial.printf("TCout : %02d:%02d:%02d:", hour(), minute(), second());
    }

  3. #153
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    712
    Code:
    /*
    Linear Timecode generation and decoding combined
    
    Please modify as needed
    
    (c) Frank B, 2020
    (pls keep copyright-info)
    
    To enable decoding:
    #define USE_LTC_INPUT
    and connect pin1 to pinA2 (=pin 16) !!!! I see no use to do this ????
    
    PIN 2 : if set low it will sync incoming TC to the output TC . Then you can disconnect input TC and output will continue
    
    Licence: MIT
    */
    bool insync = 0;
    int incominghours = 0;
    int incomingminutes = 0;
    int incomingseconds = 0;
    int incomingframes = 0;
    
    #define USE_LTC_INPUT //comment-out for generation only
    float fps = 25;
    const int ltcPin = 1;
    const int syncPin = 0;
    
    #include "TimeLib.h"
    
    #ifdef USE_LTC_INPUT
    /*
    Connect ltc
    */
    #include <Audio.h>
    #include <analyze_ltc.h>
    AudioInputAnalog adc1;
    AudioAnalyzeLTC ltc1;
    AudioConnection patchCord2(adc1, 0, ltc1, 0);
    
    #else
    struct ltcframe_t {
    	uint64_t data;
    	uint16_t sync;
    };
    #endif
    
    IntervalTimer ltcTimer;
    IntervalTimer fpsTimer;
    
    volatile int clkCnt = 0;
    ltcframe_t ltc;
    float ltcTimer_freq;
    
    time_t getTeensy3Time()
    {
    	return Teensy3Clock.get();
    }
    
    void genLtc() {
    	static int state = 0;
    
    	if (clkCnt++ >= 2 * 80) {
    		//ltcTimer.end();
    		clkCnt = 0;
    		return;
    	}
    
    	int bitval;
    	int bitcount = clkCnt / 2;
    
    	ltcframe_t ltct;
    	ltct = ltc;
    
    	if (bitcount < 64) {
    		bitval = (int)(ltct.data >> bitcount) & 0x01;
    	}
    	else {
    		bitval = (int)(ltct.sync >> (bitcount - 64)) & 0x01; //backward
    	}
    
    	if ((bitval == 1) || ((bitval == 0) && (clkCnt & 0x01)) == 0) {
    		state = !state; // toggle state
    		digitalWriteFast(ltcPin, state);
    	}
    
    }
    
    //https://www.geeksforgeeks.org/program-to-find-parity/
    inline
    int getParity(uint64_t n)
    {
    	int parity = 0;
    	while (n)
    	{
    		parity = !parity;
    		n = n & (n - 1);
    	}
    	return parity & 0x01;
    }
    
    
    /*
    
    Gets called by rising edge of syncPin
    */
    void startLtc() {
    
    	ltcTimer.begin(genLtc, ltcTimer_freq);
    	ltcTimer.priority(0);
    
    	int t, t10;
    	uint64_t data = ltc.data;
    	clkCnt = 0;
    
    	//get frame number:
    	t = ((data >> 8) & 0x03) * 10 + (data & 0x0f);
    
    	//zero out ltc data, leave d+c flags and user-bits untouched:
    	data &= 0xf0f0f0f0f0f0fcf0ULL;
    	//data = 0;
    	//inc frame-number:
    	//TODO: realize "drop frame numbering" (when D-Flag is set)
    	t++;
    	if (t >= (int)fps) t = 0;
    	//set frame number:
    	t10 = t / 10;
    	data |= (t10 & 0x03) << 8;
    	data |= ((t - t10 * 10)) << 0;
    	printTCout();
    	Serial.printf("%02d\n", t);
    
    	//set time:
    	t = second();
    	t10 = t / 10;
    	data |= (t10 & 0x07) << 24; //Seconds tens
    	data |= ((t - t10 * 10) & 0x0f) << 16;
    
    	t = minute();
    	t10 = t / 10;
    	data |= (uint64_t)(t10 & 0x07) << 40; //minute tens
    	data |= (uint64_t)((t - t10 * 10) & 0x0f) << 32;
    
    	t = hour();
    	t10 = t / 10;
    	data |= (uint64_t)(t10 & 0x03) << 56; //hour tens
    	data |= (uint64_t)((t - t10 * 10) & 0x0f) << 48;
    
    	//set parity:
    	int parity = (!getParity(data)) & 0x01;
    	if ((int)fps == 25) {
    		data |= (uint64_t)parity << 59;
    	}
    	else {
    		data |= (uint64_t)parity << 27;
    	}
    
    	ltc.data = data;
    
    }
    
    void initLtcData()
    {
    	ltc.sync = 0xBFFC;
    	ltc.data = (uint64_t)0; //<- place your initial data here
    }
    
    void genFpsSync() {
    	static int state = 0;
    	state = !state; // toggle state
    	digitalWriteFast(syncPin, state);
    }
    
    
    void setup() {
    
    	Serial.begin(115200);
    	delay(200);
    #ifdef USE_LTC_INPUT
    	AudioMemory(4);
    #endif
    	setSyncProvider(getTeensy3Time);
    	pinMode(syncPin, OUTPUT);
    	pinMode(ltcPin, OUTPUT);
    	pinMode(2, INPUT_PULLUP);
    	ltcTimer_freq = (1.0f / (2 * 80 * (fps))) * 1000000.0f - 0.125f;// -0.125: make it a tiny bit faster than needed to allow syncing
    	initLtcData();
    	//set frame number to last frame to force roll-over with new second()
    	ltc.data &= 0xf0f0f0f0f0f0fcf0ULL; //delete all dynamic data in frame
    	int t, t10;
    	t = fps;
    	t10 = t / 10;
    	ltc.data |= (t10 & 0x03) << 8;
    	ltc.data |= ((t - t10 * 10));
    	//now wait for seconds-change
    	int secs = second();
    	while (secs == second()) { ; }
    
    	//start timer and pin-interrupt:
    	fpsTimer.begin(&genFpsSync, (1.0f / (2 * fps)) * 1000000.0f);
    	fpsTimer.priority(0);
    	attachInterrupt(digitalPinToInterrupt(syncPin), &startLtc, RISING);
    	NVIC_SET_PRIORITY(88, 0); //set GPIO-INT-Priority for Pin 1
    
    }
    
    void loop() {
    	if (ltc1.available()) {
    		ltcframe_t ltcframe = ltc1.read();
    		incominghours = ltc1.hour(&ltcframe);
    		incomingminutes = ltc1.minute(&ltcframe);
    		incomingseconds = ltc1.second(&ltcframe);
    		incomingframes = ltc1.frame(&ltcframe);
    		Serial.printf("TC in : %02d:%02d:%02d.%02d\n\n", ltc1.hour(&ltcframe), ltc1.minute(&ltcframe), ltc1.second(&ltcframe), ltc1.frame(&ltcframe));
    	}
    
    	bool inpin = digitalRead(2);
    	if (inpin == 0 && insync == 0) {
    		if (incomingframes == 0) {
    			detachInterrupt(digitalPinToInterrupt(syncPin));
    			fpsTimer.end();
    			setTime(incominghours, incomingminutes, incomingseco nds, 01, 01, 2022);
    			Teensy3Clock.set(now());
    			ltcTimer_freq = (1.0f / (2 * 80 * (fps))) * 1000000.0f - 0.125f;// -0.125: make it a tiny bit faster than needed to allow syncing
    			initLtcData();
    			//set frame number to last frame to force roll-over with new second()
    			ltc.data &= 0xf0f0f0f0f0f0fcf0ULL; //delete all dynamic data in frame
    			int t, t10;
    			t = fps;
    			t10 = t / 10;
    			ltc.data |= (t10 & 0x03) << 8;
    			ltc.data |= ((t - t10 * 10));
    			//now wait for seconds-change
    			int secs = second();
    			while (secs == second()) { ; }
    			//start timer and pin-interrupt:
    			fpsTimer.begin(&genFpsSync, (1.0f / (2 * fps)) * 1000000.0f);
    			fpsTimer.priority(0);
    			attachInterrupt(digitalPinToInterrupt(syncPin), &startLtc, RISING);
    			NVIC_SET_PRIORITY(88, 0); //set GPIO-INT-Priority for Pin 1
    			insync = 1;
    
    		}
    	}
    }
    
    void printTCout() {
    	Serial.printf("TCout : %02d:%02d:%02d:", hour(), minute(), second());
    }
    Could you place your code between code tags using the # button.
    It makes the code much more readable and therefore more liable to get some help.

  4. #154
    I'm really new to forums. Could you explain a bit more how to do this? Is it a button somewhere on the forum, or do I add # before I paste the code?

  5. #155
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    712
    New to this? You've been a member since Nov 2018.
    When making a post, when you want to add some code, press the # button above.
    Type or paste your code between the [ CODE][/CODE ] tags generated.
    Alternatively type or paste your code, highlight it and then press the # button and your code will have the tags placed before and after your code.

  6. #156
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,748
    Quote Originally Posted by olivierdemoustier View Post
    Is it a button somewhere on the forum
    The rightmost button above the text input area.
    Code:
    gives monospaced output like this
    [ In "advanced mode" the button is 3rd from the right ]

    Hovering above each button explains what it does.

  7. #157
    I'm using Chrome on a windows10 machine. It does not show these options. (see screenshot) changed to Explorer, it shows them.
    Click image for larger version. 

Name:	Screenshot.jpg 
Views:	18 
Size:	67.6 KB 
ID:	27328

  8. #158
    Has anyone tested this on Teensy 4.0? LTC input is not working for me?

  9. #159
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    No, but there is nothing what is model-depended.
    Last edited by Frank B; 01-27-2022 at 05:38 PM.

  10. #160
    It really does not work. Maybe Timelib that works different in T4?

  11. #161
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    Don't know. Have you tried USB input?

  12. #162
    Found the solution for T4.0
    You need to have the next line in your code.
    AudioOutputI2S i2s1;
    For T3.6 it is not necessary

  13. #163
    Quote Originally Posted by olivierdemoustier View Post
    Found the solution for T4.0
    You need to have the next line in your code.
    AudioOutputI2S i2s1;
    For T3.6 it is not necessary
    But this only solves the TC input. TC out still not working on T4.0
    I get this message on the serial monitor after compiling.
    ADC2_CFG = 00000637

  14. #164
    Still trying to figure out on how to get this to work on a Teensy4.0, because I need (S)RTC.
    So far I found out that it has something to do with the attachInterrupt on the sync pin. That part won't start until I connect a lose wire to the sync-pin. Strange to start with, A pull up resistor will stop the interrupt. But with the loose wire the TC-FRAME rate is going nuts... It will do more then 20 times 25 frames loops per second.....

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •