Program Listing for File show.cpp

Return to documentation for file (src/cue/show.cpp)

/*
    Show.cpp - Library for scheduling PixelMaestro Events.
*/

#include "show.h"

namespace PixelMaestro {

    Show::Show(CueController& controller, Event* events, uint16_t num_events) : cue_controller_(controller) {
        set_events(events, num_events);
    }

    uint16_t Show::get_current_index() const {
        return current_index_;
    }

    Event* Show::get_event_at_index(uint16_t index) const {
        if (index < num_events_) {
            return &events_[index];
        }

        return nullptr;
    }

    Event* Show::get_events() const {
        return events_;
    }

    uint32_t Show::get_last_time() const {
        return last_time_;
    }

    bool Show::get_looping() const {
        return loop_;
    }

    uint16_t Show::get_num_events() const {
        return num_events_;
    }

    Show::TimingMode Show::get_timing() const {
        return timing_mode_;
    }

    void Show::set_events(Event* events, uint16_t num_events, bool preserve_current_index) {
        if (!preserve_current_index) {
            current_index_ = 0;
        }
        events_ = events;
        num_events_ = num_events;
    }

    void Show::set_looping(bool loop) {
        loop_ = loop;
    }

    void Show::set_timing_mode(TimingMode timing_mode) {
        timing_mode_ = timing_mode;
    }

    void Show::sync(const uint32_t &new_time) {
        this->last_time_ = new_time;
    }

    void Show::update(const uint32_t& current_time) {
        // Make sure we have at least one Event
        if (num_events_ == 0) {
            return;
        }

        if (loop_ && current_index_ >= num_events_) {
            current_index_ = 0;
        }

        // Only run if we're looping, or if we haven't reached the end of the Event list yet.
        if (loop_ || current_index_ < num_events_) {
            check_next_event(current_time);
        }
    }

    // Private methods

    void Show::check_next_event(const uint32_t& current_time) {
        /*
         * Based on the timing method used, determine whether to run the Event.
         *   If Absolute, compare the current time to the next Event's start time.
         *   If Relative, compare the time since the last Event to the next Event's start time.
         * After running the Event, update the last run time and current Event index.
         */
        uint32_t event_time = events_[current_index_].get_time();
        if ((timing_mode_ == TimingMode::Absolute && (current_time >= event_time)) ||
            (timing_mode_ == TimingMode::Relative && ((current_time - last_time_) >= event_time))) {
            cue_controller_.run(events_[current_index_].get_cue());
            last_time_ = current_time;
            update_event_index();

            // Check the next event
            if (current_index_ < num_events_) {
                check_next_event(current_time);
            }
        }
    }

    void Show::update_event_index() {
        // If we've exceeded the number of events, start over from 0
        if (timing_mode_ == TimingMode::Relative && loop_ && (current_index_ + 1 >= num_events_)) {
            current_index_ = 0;
        }
        else {
            ++current_index_;
        }
    }
}