From 207612e3b876921e6e8ec8652e3ec9f14c12ce9e Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Mon, 8 Nov 2021 22:15:18 +0100 Subject: [PATCH] Feat/osc feedback (#35) * Add roll function call to OSC * send finished message * request presenter * handling badly formatted messages * loadeventbyindex add step so that we can pause the titles when loading a new event via an API call (eg. OSC) * broadcast title data * handle empty title fields * send finished message in roll mode * calling stop is same as calling unload --- server/src/classes/EventTimer.js | 40 +++++++++++++++++++++---- server/src/classes/Timer.js | 5 ++-- server/src/controllers/OscController.js | 36 +++++++++++++++++----- 3 files changed, 65 insertions(+), 16 deletions(-) diff --git a/server/src/classes/EventTimer.js b/server/src/classes/EventTimer.js index b9673fd47..3171634f4 100644 --- a/server/src/classes/EventTimer.js +++ b/server/src/classes/EventTimer.js @@ -115,9 +115,9 @@ export class EventTimer extends Timer { const reload = 'reload'; const finished = 'finished'; const time = this.timeTag; - // TODO: Should this be boolean? const overtime = this.current > 0 ? 0 : 1; - const title = this.titles.titleNow; + const title = this.titles?.titleNow || ''; + const presenter = this.titles?.presenterNow || ''; switch (event) { case 'time': @@ -138,11 +138,16 @@ export class EventTimer extends Timer { if (err) console.error(err); }); break; - case 'title': + case 'titles': // Send Title of current event this.oscClient.send(add + '/title', title, (err) => { if (err) console.error(err); }); + + // Send presenter data on current event + this.oscClient.send(add + '/presenter', presenter, (err) => { + if (err) console.error(err); + }); break; case 'play': // Play Message @@ -200,6 +205,7 @@ export class EventTimer extends Timer { if (this.state === 'start' || this.state === 'roll') { this.sendOSC('time'); this.sendOSC('overtime'); + this.sendOSC('titles'); } } @@ -228,13 +234,13 @@ export class EventTimer extends Timer { update() { // if there is nothing selected, do nothing if (this.selectedEventId == null && this.state !== 'roll') return; + const now = this._getCurrentTime(); // only implement roll here if (this.state !== 'roll') { super.update(); } else { // update timer as usual - const now = this._getCurrentTime(); this.clock = now; if (this.selectedEventId && this.current > 0) { // something is running, update @@ -249,6 +255,12 @@ export class EventTimer extends Timer { const secondaryRunning = this.secondaryTimer <= 0 && this.secondaryTimer !== null; + if (currentRunning) { + // finished an event + this.sendOSC('finished'); + this._finishedFlag = true; + } + if (currentRunning || secondaryRunning) { // look for events this.rollLoad(); @@ -258,8 +270,18 @@ export class EventTimer extends Timer { } } - // sendOSC on reaching 0 - if (this.current === 0 && this.state === 'start') this.sendOSC('finished'); + // if event is finished + if ( + this.current <= 0 && + (this.state === 'start' || this.state === 'roll') && + !this._finishedFlag + ) { + if (this._finishedAt === null) { + this._finishedAt = now; + } + this.sendOSC('finished'); + this._finishedFlag = true; + } } _setterManager(action, payload) { @@ -629,6 +651,12 @@ export class EventTimer extends Timer { this.loadEvent(eventIndex, 'load', true); } + loadEventByIndex(eventIndex) { + if (eventIndex === -1 || index > this.numEvents) return; + this.pause(); + this.loadEvent(eventIndex, 'load', true); + } + // Loads a given event // load timers // load selectedEventIndex diff --git a/server/src/classes/Timer.js b/server/src/classes/Timer.js index 01ed79dcf..5ed019a14 100644 --- a/server/src/classes/Timer.js +++ b/server/src/classes/Timer.js @@ -15,6 +15,7 @@ export class Timer { _secondaryTarget = null; _finishAt = null; _finishedAt = null; + _finishedFlag = false; _startedAt = null; _pausedAt = null; _pausedInterval = null; @@ -84,9 +85,6 @@ export class Timer { console.error('Timer: no playstate on update call', this.state); break; } - - // Cleanup - if (this.current <= 0 && this._finishedAt == null) this._finishedAt = now; } // helpers @@ -129,6 +127,7 @@ export class Timer { this._secondaryTarget = null; this._finishAt = null; this._finishedAt = null; + this._finishedFlag = false; this._startedAt = null; this._pausedAt = null; this._pausedInterval = null; diff --git a/server/src/controllers/OscController.js b/server/src/controllers/OscController.js index 4a2733ab0..e9508ac4a 100644 --- a/server/src/controllers/OscController.js +++ b/server/src/controllers/OscController.js @@ -26,7 +26,15 @@ export const initiateOSC = (config) => { const args = msg[1]; // get first part before (ontime) - if (address !== 'ontime') return; + if (address !== 'ontime') { + console.error(`OSC IN: Message address ${address} not recognised`); + return; + } + + if (path == null) { + console.error('OSC IN: No path found'); + return; + } // get second part (command) switch (path.toLowerCase()) { @@ -48,6 +56,7 @@ export const initiateOSC = (config) => { global.timer.next(); break; case 'unload': + case 'stop': console.log('calling unload'); global.timer.unload(); break; @@ -57,12 +66,17 @@ export const initiateOSC = (config) => { break; case 'roll': console.log('calling roll'); + global.timer.roll(); break; case 'delay': console.log('calling delay with', args); try { let t = parseInt(args); - if (!isNaN(t)) global.timer.increment(t * 1000 * 60); + if (isNaN(t)) { + console.error(`OSC IN: delay time not recognised ${args}`); + return; + } + global.timer.increment(t * 1000 * 60); } catch (error) { console.log('error parsing: ', error); } @@ -71,16 +85,24 @@ export const initiateOSC = (config) => { console.log('calling goto with', args); try { let eventIndex = parseInt(args); - if (isNaN(eventIndex) || eventIndex <= 0 || eventIndex == null) - return; - global.timer.loadEvent(eventIndex - 1, undefined, true); + if (isNaN(eventIndex) || eventIndex <= 0 || eventIndex == null) { + console.error( + `OSC IN: event index not recognised or out of range ${eventIndex}` + ); + } + global.timer.loadEventByIndex(eventIndex - 1, undefined, true); } catch (error) { console.log('error calling goto: ', error); } break; case 'gotoid': console.log('calling gotoid with', args); - if (args == null) return; + if (args == null) { + console.error( + `OSC IN: event id not recognised or out of range ${args}` + ); + return; + } try { global.timer.loadEventById(args.toString().toLowerCase()); } catch (error) { @@ -89,7 +111,7 @@ export const initiateOSC = (config) => { break; default: - console.log('Error: not recognised'); + console.log(`Error: unhandled message ${path}`); break; } });