Skip to content

Commit

Permalink
Merge pull request #65 from spessasus/discussion62
Browse files Browse the repository at this point in the history
Add playback state preserving
  • Loading branch information
spessasus authored Oct 17, 2024
2 parents ed21fae + 4bcb065 commit 6c1bc5c
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 10 deletions.
54 changes: 49 additions & 5 deletions src/spessasynth_lib/sequencer/sequencer.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ import { DUMMY_MIDI_DATA, MidiData } from "../midi_parser/midi_data.js";
* @typedef {Object} SequencerOptions
* @property {boolean|undefined} skipToFirstNoteOn - if true, the sequencer will skip to the first note
* @property {boolean|undefined} autoPlay - if true, the sequencer will automatically start playing the MIDI
* @property {boolean|unescape} preservePlaybackState - if true,
* the sequencer will stay paused when seeking or changing the playback rate
*/

/**
* @type {SequencerOptions}
*/
const DEFAULT_OPTIONS = {
skipToFirstNoteOn: true,
autoPlay: true
autoPlay: true,
preservePlaybackState: false
};

export class Sequencer
Expand Down Expand Up @@ -138,15 +141,25 @@ export class Sequencer
* @type {boolean}
* @private
*/
this._skipToFirstNoteOn = options?.skipToFirstNoteOn ?? true;
this._skipToFirstNoteOn = options?.skipToFirstNoteOn || true;
/**
* @type {boolean}
* @private
*/
this._preservePlaybackState = options?.preservePlaybackState || false;

if (this._skipToFirstNoteOn === false)
{
// setter sends message
this._sendMessage(WorkletSequencerMessageType.setSkipToFirstNote, false);
}

this.loadNewSongList(midiBinaries, options?.autoPlay ?? false);
if (this._preservePlaybackState === true)
{
this._sendMessage(WorkletSequencerMessageType.setPreservePlaybackState, true);
}

this.loadNewSongList(midiBinaries, options?.autoPlay || true);

window.addEventListener("beforeunload", this.resetMIDIOut.bind(this));
}
Expand All @@ -170,6 +183,27 @@ export class Sequencer
this._sendMessage(WorkletSequencerMessageType.setSkipToFirstNote, this._skipToFirstNoteOn);
}

/**
* if true,
* the sequencer will stay paused when seeking or changing the playback rate
* @returns {boolean}
*/
get preservePlaybackState()
{
return this._preservePlaybackState;
}

/**
* if true,
* the sequencer will stay paused when seeking or changing the playback rate
* @param val {boolean}
*/
set preservePlaybackState(val)
{
this._preservePlaybackState = val;
this._sendMessage(WorkletSequencerMessageType.setPreservePlaybackState, val);
}

/**
* @returns {number} Current playback time, in seconds
*/
Expand All @@ -186,7 +220,10 @@ export class Sequencer

set currentTime(time)
{
this.unpause();
if (!this._preservePlaybackState)
{
this.unpause();
}
this._sendMessage(WorkletSequencerMessageType.setTime, time);
}

Expand Down Expand Up @@ -395,8 +432,15 @@ export class Sequencer
// message data is absolute time
const time = this.synth.currentTime - messageData;
Object.entries(this.onTimeChange).forEach((callback) => callback[1](time));
this.unpause();
this._recalculateStartTime(time);
if (this.paused && this._preservePlaybackState)
{
this.pausedTime = time;
}
else
{
this.unpause();
}
break;

case WorkletSequencerReturnMessageType.pause:
Expand Down
3 changes: 3 additions & 0 deletions src/spessasynth_lib/sequencer/worklet_sequencer/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ export function processMessage(messageType, messageData)
case WorkletSequencerMessageType.setSkipToFirstNote:
this._skipToFirstNoteOn = messageData;
break;

case WorkletSequencerMessageType.setPreservePlaybackState:
this.preservePlaybackState = messageData;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/spessasynth_lib/sequencer/worklet_sequencer/play.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,12 +254,14 @@ export function play(resetTime = false)
// reset the time if necesarry
if (resetTime)
{
this.pausedTime = undefined;
this.currentTime = 0;
return;
}

if (this.currentTime >= this.duration)
{
this.pausedTime = undefined;
this.currentTime = 0;
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* @property {number} changeSong - 8 -> goForwards<boolean> if true, next song, if false, previous
* @property {number} getMIDI - 9 -> (no data)
* @property {number} setSkipToFirstNote -10 -> skipToFirstNoteOn<boolean>
* @property {number} setPreservePlaybackState -11 -> preservePlaybackState<boolean>
*/
export const WorkletSequencerMessageType = {
loadNewSongList: 0,
Expand All @@ -23,7 +24,8 @@ export const WorkletSequencerMessageType = {
setLoop: 7,
changeSong: 8,
getMIDI: 9,
setSkipToFirstNote: 10
setSkipToFirstNote: 10,
setPreservePlaybackState: 11
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ class WorkletSequencer
* @private
*/
this._skipToFirstNoteOn = true;

/**
* If true, seq will stay paused when seeking or changing the playback rate
* @type {boolean}
*/
this.preservePlaybackState = false;
}

/**
Expand Down Expand Up @@ -152,15 +158,19 @@ class WorkletSequencer
}
this.stop();
this.playingNotes = [];
const wasPaused = this.paused && this.preservePlaybackState;
this.pausedTime = undefined;
this.post(WorkletSequencerReturnMessageType.timeChange, currentTime - time);
const isNotFinished = this._playTo(time);
this._playTo(time);
this._recalculateStartTime(time);
if (!isNotFinished)
if (wasPaused)
{
return;
this.pause();
}
else
{
this.play();
}
this.play();
}

/**
Expand Down

0 comments on commit 6c1bc5c

Please sign in to comment.