ofxTimeline: multiple timelines or pages set up the same

Hello,
using ofxTimeline, i’d like users to be able to create new timelines, each of which would have the same four curvetracks. i would assume that using pages is the way to go. However, I’m having trouble loading the track xml files using loadTracksFromFolder(). I kept getting “couldn’t load track position file” errors.

I’ve also tried setting up a vector of timelines, changing the names of each curvetrack according to timeline index. However, I’ve seen that older timelines tend to ‘inherit’ the keyframes of later timelines.

SUMMARY QUESTION: what’s the best way to allow users to create new groups of timelines that all have the same number and label of curve tracks.

thanks in advance,
Jake

I did something similar. Here is some thoughts.

I created a vector of timelines. I then initialized it like this:

//Timeline Init
for (int i=0; i<=4; i++) {
    tls.push_back(new ofxTimeline);
    tls.back()->setWorkingFolder("timeline");
    tls.back()->setup();
    tls.back()->setDurationInSeconds(timelineLength);
    tls.back()->addFlags("Rumble Deck Control");
    tls.back()->addFlags("VFD State");
    tls.back()->addCurves("Front Fan", ofRange(0,255));
    tls.back()->addCurves("Top Fan", ofRange(0,255));
    tls.back()->setWidth(ofGetWidth()-300);
    tls.back()->setLoopType(OF_LOOP_NONE);
    tls.back()->setSpacebarTogglePlay(false);
    tls.back()->setAutosave(false);
}

Then I hide them all so they aren’t visible by doing a for loop and tls.at(i)->hide();. And FYI, the setAutosave(false) will make it so if you touch a timeline, it won’t save it to the file and will reload to a default when its re-initialized but will hold in running memory.

By default, timeline xml’s are created in the base data folder. It saved timeline files as timeline(0-4)xxx.xml so there would be a set of them for every one of the 5 timelines I had. So there are timeline(0-4)_Page_One_trackPositions.xml in the base directory then I moved the other tiles to a folder called timeline, there are a ton of the ones for every individual timeline. I based everything off of timeline 0. So I made a function that would copy that to the other ones and then reload the files:

void testApp::syncTimelines() {
    tls.at(0)->saveTracksToFolder("timeline");

    for (int i=1; i<tls.size(); i++) {
        t.copyFromTo("timeline/timeline0_Front_Fan.xml", "timeline/timeline"+ofToString(i)+"_Front_Fan.xml", true, true);
        t.copyFromTo("timeline/timeline0_Rumble_Deck_Control.xml", "timeline/timeline"+ofToString(i)+"_Rumble_Deck_Control.xml", true, true);
        t.copyFromTo("timeline/timeline0_Top_Fan.xml", "timeline/timeline"+ofToString(i)+"_Top_Fan.xml", true, true);
        t.copyFromTo("timeline/timeline0_VFD_State.xml", "timeline/timeline"+ofToString(i)+"_VFD_State.xml", true, true);
    }

    tls.at(1)->loadTracksFromFolder("timeline/");
    tls.at(2)->loadTracksFromFolder("timeline/");
    tls.at(3)->loadTracksFromFolder("timeline/");
    tls.at(4)->loadTracksFromFolder("timeline/");
}

I’m sure this can help you. A little confusing at first. But just playing with it for a while helped me and was able to get it to do what I needed. I now even have two different versions of the show that I can just load from different timeline sets.

2 Likes

@ryanww this is exactly what i was looking for. Thanks very much. I needed the ability to add new timelines on the fly with the same template. here’s what i did for the setup:

void testApp::setupNewTimeline(){
ofLogVerbose() << "setting up new timeline";
ofxTimeline* t = new ofxTimeline();

t->setWorkingFolder("timeline");
t->setup();
t->setFrameRate(30);
t->setDurationInSeconds(15);
t->setLoopType(OF_LOOP_NORMAL);

t->addCurves("Deep_Blue" + ofToString(timelines.size()), ofRange(0, 255));
t->addCurves("Blue" + ofToString(timelines.size()), ofRange(0,255));
t->addCurves("Red" + ofToString(timelines.size()), ofRange(0,255));
t->addCurves("Deep_Red" + ofToString(timelines.size()), ofRange(0, 255));
t->addCurves("Infra_Red" + ofToString(timelines.size()), ofRange(0, 255));
t->setFrameBased(false);
t->setAutosave(false);
timelines.push_back(t);

//set the current timeline to the newest timeline
currentTimelineIndex = timelines.size()-1;

//we want to save the first timeline
if(timelines.size() == 1)
{
    timelines[0]->saveTracksToFolder("timeline");
}

showOneTimeline(currentTimelineIndex);
syncNewTimeline(currentTimelineIndex);

the showOneTimeline function hides all but the current timeline:

void testApp::showOneTimeline(int timelineNum){
//hide all other timelines
for(int i = 0; i < timelines.size(); i++)
{
    if(i != timelineNum)
    {
        timelines[i]->hide();
    }
}
//show and draw current timeline
timelines[timelineNum]->show();

and the syncNewTimeline function syncs up any new timeline to the original template:

void testApp::syncNewTimeline(int timelineNum){

file.copyFromTo("timeline/timeline0_Deep_Blue", "timeline/timeline"+ofToString(timelineNum)+"_Deep_Blue.xml", true, true);
file.copyFromTo("timeline/timeline0_Blue", "timeline/timeline"+ofToString(timelineNum)+"_Blue.xml", true, true);
file.copyFromTo("timeline/timeline0_Red", "timeline/timeline"+ofToString(timelineNum)+"_Red.xml", true, true);
file.copyFromTo("timeline/timeline0_Deep_Red", "timeline/timeline"+ofToString(timelineNum)+"_Deep_Red.xml", true, true);
file.copyFromTo("timeline/timeline0_Infra_Red", "timeline/timeline"+ofToString(timelineNum)+"_Infra_Red.xml", true, true);

timelines[timelineNum]->loadTracksFromFolder("timeline/");

This works really well. Thanks again for taking time to help.

1 Like

No problem! Glad to help out! After all I had spent hours trying many things so as long as it saved someone else the hours, its totally worth it!