Program Listing for File maestrocontroller.cpp¶
↰ Return to documentation for file (src/controller/maestrocontroller.cpp
)
#include "animation/fireanimation.h"
#include "animation/lightninganimation.h"
#include "animation/plasmaanimation.h"
#include "animation/radialanimation.h"
#include "animation/sparkleanimation.h"
#include "animation/waveanimation.h"
#include "canvas/canvas.h"
#include "core/maestro.h"
#include "cue/animationcuehandler.h"
#include "cue/canvascuehandler.h"
#include "cue/maestrocuehandler.h"
#include "cue/sectioncuehandler.h"
#include "cue/show.h"
#include "cue/showcuehandler.h"
#include "maestrocontroller.h"
#include <QByteArray>
#include <QSettings>
#include "dialog/preferencesdialog.h"
using namespace PixelMaestro;
namespace PixelMaestroStudio {
MaestroController::MaestroController(MaestroControlWidget& maestro_control_widget) : timer_(this), maestro_control_widget_(maestro_control_widget) {
initialize_maestro();
// Initialize timers
timer_.setTimerType(Qt::PreciseTimer);
connect(&timer_, SIGNAL(timeout()), this, SLOT(update()));
}
void MaestroController::add_drawing_area(MaestroDrawingArea& drawing_area) {
drawing_areas_.push_back(&drawing_area);
// Initialize the DrawingArea's SectionDrawingAreas
for (uint8_t section = 0; section < this->num_sections_; section++) {
drawing_area.add_section_drawing_area(sections_[section], section);
}
// Refresh the DrawingArea on each timeout
connect(&timer_, SIGNAL(timeout()), &drawing_area, SLOT(update()));
}
Maestro& MaestroController::get_maestro() {
return *maestro_.data();
}
bool MaestroController::get_running() {
return timer_.isActive();
}
uint64_t MaestroController::get_total_elapsed_time() {
uint64_t elapsed = last_pause_;
if (get_running()) {
elapsed += elapsed_timer_.elapsed();
}
return elapsed;
}
void MaestroController::initialize_maestro() {
if (!maestro_.isNull()) {
maestro_.reset();
}
// Initalize the Maestro with the specified number of Sections
maestro_ = QSharedPointer<Maestro>(new Maestro(nullptr, 0));
QSettings settings;
set_sections(settings.value(PreferencesDialog::num_sections, 1).toInt());
/*
* Set the Maestro's refresh timer.
* If the user hasn't set a custom timer, default to 50ms (20fps).
*/
int refresh = settings.value(PreferencesDialog::refresh_rate, QVariant(50)).toInt();
maestro_->set_timer(refresh);
// Enable the Maestro's CueController and CueHandlers
CueController& controller = maestro_->set_cue_controller(UINT16_MAX);
controller.enable_animation_cue_handler();
controller.enable_canvas_cue_handler();
controller.enable_maestro_cue_handler();
controller.enable_section_cue_handler();
controller.enable_show_cue_handler();
}
void MaestroController::remove_drawing_area(MaestroDrawingArea& drawing_area) {
disconnect(&timer_, SIGNAL(timeout()), &drawing_area, SLOT(update()));
drawing_areas_.removeOne(&drawing_area);
}
void MaestroController::save_maestro_to_datastream(QDataStream& datastream, QVector<CueController::Handler>* save_handlers) {
MaestroCueHandler* maestro_handler = dynamic_cast<MaestroCueHandler*>(maestro_->get_cue_controller().get_handler(CueController::Handler::MaestroCueHandler));
// Maestro-specific Cues
if (save_handlers == nullptr || save_handlers->contains(CueController::Handler::MaestroCueHandler)) {
QSettings settings;
uint16_t interval = static_cast<uint16_t>(settings.value(PreferencesDialog::refresh_rate, 50).toUInt());
if (maestro_->get_timer().get_interval() != interval) {
write_cue_to_stream(datastream, maestro_handler->set_timer(interval));
}
}
// Show-specific Cues
if (save_handlers == nullptr || save_handlers->contains(CueController::Handler::ShowCueHandler)) {
Show* show = maestro_->get_show();
if (show != nullptr) {
write_cue_to_stream(datastream, maestro_handler->set_show());
ShowCueHandler* show_handler = dynamic_cast<ShowCueHandler*>(maestro_->get_cue_controller().get_handler(CueController::Handler::ShowCueHandler));
write_cue_to_stream(datastream, show_handler->set_looping(show->get_looping()));
write_cue_to_stream(datastream, show_handler->set_timing_mode(show->get_timing()));
// Save events for last until I can nail down the byte alignment issues with event Cues
if (show->get_events() != nullptr) {
write_cue_to_stream(datastream, show_handler->set_events(show->get_events(), show->get_num_events(), false));
}
}
}
// Save Sections
if (save_handlers == nullptr || save_handlers->contains(CueController::Handler::SectionCueHandler)) {
for (uint8_t section = 0; section < num_sections_; section++) {
save_section_to_datastream(datastream, section, 0, save_handlers);
}
}
}
void MaestroController::save_section_to_datastream(QDataStream& datastream, uint8_t section_id, uint8_t layer_id, QVector<CueController::Handler>* save_handlers) {
Section* section = maestro_->get_section(section_id);
if (section == nullptr) return;
if (layer_id > 0) {
for (uint8_t i = 0; i < layer_id; i++) {
section = section->get_layer()->section;
}
}
SectionCueHandler* section_handler = dynamic_cast<SectionCueHandler*>(maestro_->get_cue_controller().get_handler(CueController::Handler::SectionCueHandler));
// Global Section settings
if (section->get_brightness() != 255) {
write_cue_to_stream(datastream, section_handler->set_brightness(section_id, layer_id, section->get_brightness()));
}
// Only set dimensions for Sections, not Layers
if (layer_id == 0) {
write_cue_to_stream(datastream, section_handler->set_dimensions(section_id, layer_id, section->get_dimensions().x, section->get_dimensions().y));
}
// Animation & Colors
if (save_handlers == nullptr || save_handlers->contains(CueController::Handler::AnimationCueHandler)) {
Animation* animation = section->get_animation();
if (animation != nullptr) {
write_cue_to_stream(datastream, section_handler->set_animation(section_id, layer_id, animation->get_type()));
AnimationCueHandler* animation_handler = dynamic_cast<AnimationCueHandler*>(maestro_->get_cue_controller().get_handler(CueController::Handler::AnimationCueHandler));
if (animation->get_palette() != nullptr) {
write_cue_to_stream(datastream, animation_handler->set_palette(section_id, layer_id, *animation->get_palette()));
}
write_cue_to_stream(datastream, animation_handler->set_center(section_id, layer_id, animation->get_center().x, animation->get_center().y));
write_cue_to_stream(datastream, animation_handler->set_orientation(section_id, layer_id, animation->get_orientation()));
write_cue_to_stream(datastream, animation_handler->set_reverse(section_id, layer_id, animation->get_reverse()));
write_cue_to_stream(datastream, animation_handler->set_fade(section_id, layer_id, animation->get_fade()));
if (animation->get_timer() != nullptr) {
write_cue_to_stream(datastream, animation_handler->set_timer(section_id, layer_id, animation->get_timer()->get_interval(), animation->get_timer()->get_delay()));
}
// Save Animation-specific settings
switch(animation->get_type()) {
case AnimationType::Fire:
{
FireAnimation* fa = dynamic_cast<FireAnimation*>(animation);
write_cue_to_stream(datastream, animation_handler->set_fire_options(section_id, layer_id, fa->get_multiplier()));
}
break;
case AnimationType::Lightning:
{
LightningAnimation* la = dynamic_cast<LightningAnimation*>(animation);
write_cue_to_stream(datastream, animation_handler->set_lightning_options(section_id, layer_id, la->get_bolt_count(), la->get_drift(), la->get_fork_chance()));
}
break;
case AnimationType::Plasma:
{
PlasmaAnimation* pa = dynamic_cast<PlasmaAnimation*>(animation);
write_cue_to_stream(datastream, animation_handler->set_plasma_options(section_id, layer_id, pa->get_size(), pa->get_resolution()));
}
break;
case AnimationType::Radial:
{
RadialAnimation* ra = dynamic_cast<RadialAnimation*>(animation);
write_cue_to_stream(datastream, animation_handler->set_radial_options(section_id, layer_id, ra->get_resolution()));
}
break;
case AnimationType::Sparkle:
{
SparkleAnimation* sa = dynamic_cast<SparkleAnimation*>(animation);
write_cue_to_stream(datastream, animation_handler->set_sparkle_options(section_id, layer_id, sa->get_threshold()));
}
break;
case AnimationType::Wave:
{
WaveAnimation* wa = dynamic_cast<WaveAnimation*>(animation);
write_cue_to_stream(datastream, animation_handler->set_wave_options(section_id, layer_id, wa->get_skew()));
}
break;
default:
break;
}
}
}
// Scrolling, offset, mirroring, wrap
Point& offset = section->get_offset();
if (offset.x != 0 || offset.y != 0) {
write_cue_to_stream(datastream, section_handler->set_offset(section_id, layer_id, offset.x, offset.y));
}
Section::Scroll* scroll = section->get_scroll();
if (scroll != nullptr) {
write_cue_to_stream(datastream, section_handler->set_scroll(section_id, layer_id, scroll->interval_x, scroll->interval_y, scroll->reverse_x, scroll->reverse_y));
}
Section::Mirror* mirror = section->get_mirror();
if (mirror != nullptr) {
write_cue_to_stream(datastream, section_handler->set_mirror(section_id, layer_id, mirror->x, mirror->y));
}
bool wrap = section->get_wrap();
if (wrap == false) {
write_cue_to_stream(datastream, section_handler->set_wrap(section_id, layer_id, wrap));
}
// Save Canvas settings
if (save_handlers == nullptr || save_handlers->contains(CueController::Handler::CanvasCueHandler)) {
Canvas* canvas = section->get_canvas();
if (canvas != nullptr) {
write_cue_to_stream(datastream, section_handler->set_canvas(section_id, layer_id, canvas->get_num_frames()));
CanvasCueHandler* canvas_handler = dynamic_cast<CanvasCueHandler*>(maestro_->get_cue_controller().get_handler(CueController::Handler::CanvasCueHandler));
if (canvas->get_frame_timer()) {
write_cue_to_stream(datastream, canvas_handler->set_frame_timer(section_id, layer_id, canvas->get_frame_timer()->get_interval()));
}
if (canvas->get_palette() != nullptr) {
write_cue_to_stream(datastream, canvas_handler->set_palette(section_id, layer_id, *canvas->get_palette()));
}
// Draw and save each frame
for (uint16_t frame = 0; frame < canvas->get_num_frames(); frame++) {
write_cue_to_stream(datastream, canvas_handler->draw_frame(section_id, layer_id, frame, section->get_dimensions().x, section->get_dimensions().y, canvas->get_frame(frame)));
}
write_cue_to_stream(datastream, canvas_handler->set_current_frame_index(section_id, layer_id, canvas->get_current_frame_index()));
}
}
// Layers
Section::Layer* layer = section->get_layer();
if (layer != nullptr) {
write_cue_to_stream(datastream, section_handler->set_layer(section_id, layer_id, layer->mix_mode, layer->alpha));
save_section_to_datastream(datastream, section_id, layer_id + 1, save_handlers);
}
}
Section* MaestroController::set_sections(uint8_t num_sections, Point dimensions) {
delete [] this->sections_;
this->sections_ = new Section[num_sections];
this->num_sections_ = num_sections;
// Sets the size of each Section
for (uint8_t section = 0; section < num_sections; section++) {
sections_[section].set_dimensions(dimensions.x, dimensions.y);
}
maestro_->set_sections(sections_, num_sections_);
// Reset each drawing area's Sections
for (MaestroDrawingArea* drawing_area : this->drawing_areas_) {
drawing_area->remove_section_drawing_areas();
for (uint8_t section = 0; section < num_sections; section++) {
drawing_area->add_section_drawing_area(this->sections_[section], section);
}
}
// Reset the MaestroControlWidget's active section
return this->sections_;
}
void MaestroController::start() {
elapsed_timer_.restart();
timer_.start(this->maestro_->get_timer().get_interval());
}
void MaestroController::stop() {
last_pause_ += elapsed_timer_.elapsed();
timer_.stop();
}
void MaestroController::update() {
maestro_->update(get_total_elapsed_time(), false);
}
void MaestroController::write_cue_to_stream(QDataStream& stream, uint8_t* cue) {
if (cue != nullptr) {
uint32_t size = maestro_->get_cue_controller().get_cue_size(cue);
stream.writeRawData((const char*)cue, (int)size);
}
}
MaestroController::~MaestroController() {
// If automatic session saving is enabled, save Maestro configuration
QSettings settings;
if (settings.value(PreferencesDialog::save_session).toBool()) {
QByteArray maestro_config;
QDataStream maestro_datastream(&maestro_config, QIODevice::Truncate);
save_maestro_to_datastream(maestro_datastream);
settings.setValue(PreferencesDialog::last_session, maestro_config);
}
delete [] sections_;
}
}