diff --git a/packages/playground/src/audio/index.ts b/packages/playground/src/audio/index.ts new file mode 100644 index 0000000..504025e --- /dev/null +++ b/packages/playground/src/audio/index.ts @@ -0,0 +1,36 @@ +import {getProject} from '@theatre/core' +import studio from '@theatre/studio' + +studio.initialize() + +const proj = getProject('Musical project') +const sheet = proj.sheet('Scene') +sheet.object('An object', {x: 0}) + +setTimeout(async () => { + // const d = defer() + // window.addEventListener('click', () => { + // d.resolve(null) + // }) + // await d.promise + await sheet.sequence + .attachAudio({ + source: 'http://localhost:5000/Kai%20Engel%20-%20Moonlight%20Reprise.mp3', + }) + .then(() => { + console.log('ready') + }) + sheet.sequence.position = 11 + await sheet.sequence.play({ + iterationCount: 4, + range: [10, 14], + direction: 'normal', + rate: 2, + }) + // await sheet.sequence.play({ + // iterationCount: 2, + // range: [20, 22], + // direction: 'normal', + // rate: 4, + // }) +}, 10) diff --git a/packages/playground/src/index.tsx b/packages/playground/src/index.tsx index 41a05e0..1403840 100644 --- a/packages/playground/src/index.tsx +++ b/packages/playground/src/index.tsx @@ -1 +1 @@ -import './space-exploration' +import './audio' diff --git a/theatre/core/src/sequences/Sequence.ts b/theatre/core/src/sequences/Sequence.ts index 387be46..1dc7613 100644 --- a/theatre/core/src/sequences/Sequence.ts +++ b/theatre/core/src/sequences/Sequence.ts @@ -167,7 +167,7 @@ export default class Sequence { } if (range[0] >= sequenceDuration) { throw new InvalidArgumentError( - `Argument conf.range[0] in sequence.play(conf) cannot be longer than the duration of the sequence, which is ${sequenceDuration}ms. ${JSON.stringify( + `Argument conf.range[0] in sequence.play(conf) cannot be longer than the duration of the sequence, which is ${sequenceDuration}s. ${JSON.stringify( range[0], )} given.`, ) @@ -182,7 +182,7 @@ export default class Sequence { if (range[1] > sequenceDuration) { logger.warn( - `Argument conf.range[1] in sequence.play(conf) cannot be longer than the duration of the sequence, which is ${sequenceDuration}ms. ${JSON.stringify( + `Argument conf.range[1] in sequence.play(conf) cannot be longer than the duration of the sequence, which is ${sequenceDuration}s. ${JSON.stringify( range[1], )} given.`, ) diff --git a/theatre/core/src/sequences/playbackControllers/AudioPlaybackController.ts b/theatre/core/src/sequences/playbackControllers/AudioPlaybackController.ts index cb9cb4c..e2882dd 100644 --- a/theatre/core/src/sequences/playbackControllers/AudioPlaybackController.ts +++ b/theatre/core/src/sequences/playbackControllers/AudioPlaybackController.ts @@ -64,7 +64,7 @@ export default class AudioPlaybackController implements IPlaybackController { this.playing = true const ticker = this._ticker - const startPos = this.getCurrentPosition() + let startPos = this.getCurrentPosition() const iterationLength = range[1] - range[0] if (direction !== 'normal') { @@ -74,13 +74,6 @@ export default class AudioPlaybackController implements IPlaybackController { ) } - if (iterationCount !== 1) { - throw new InvalidArgumentError( - `Audio-controlled sequences can only have an iterationCount of 1 ` + - `'${iterationCount}' given.`, - ) - } - if (startPos < range[0] || startPos > range[1]) { // if we're currently out of the range this._updatePositionInState(range[0]) @@ -88,6 +81,7 @@ export default class AudioPlaybackController implements IPlaybackController { // if we're currently at the very end of the range this._updatePositionInState(range[0]) } + startPos = this.getCurrentPosition() const deferred = defer() @@ -96,19 +90,25 @@ export default class AudioPlaybackController implements IPlaybackController { currentSource.connect(this._mainGain) currentSource.playbackRate.value = rate - const audioStartTimeInSeconds = this._audioContext.currentTime - const wait = 0 - const timeToRangeEnd = range[1] - startPos + if (iterationCount > 1000) { + console.warn( + `Audio-controlled sequences cannot have an iterationCount larger than 1000. It has been clamped to 1000.`, + ) + iterationCount = 1000 + } + + if (iterationCount > 1) { + currentSource.loop = true + currentSource.loopStart = range[0] + currentSource.loopEnd = range[1] + } - currentSource.start( - audioStartTimeInSeconds + wait, - startPos - wait, - wait + timeToRangeEnd, - ) const initialTickerTime = ticker.time - let initialElapsedPos = this.getCurrentPosition() - range[0] + let initialElapsedPos = startPos - range[0] const totalPlaybackLength = iterationLength * iterationCount + currentSource.start(0, startPos, totalPlaybackLength - initialElapsedPos) + const tick = (currentTickerTime: number) => { const elapsedTickerTime = Math.max( currentTickerTime - initialTickerTime, @@ -125,7 +125,7 @@ export default class AudioPlaybackController implements IPlaybackController { let currentIterationPos = ((elapsedPos / iterationLength) % 1) * iterationLength - this._updatePositionInState(currentIterationPos) + this._updatePositionInState(currentIterationPos + range[0]) requestNextTick() } else { this._updatePositionInState(range[1]) diff --git a/theatre/core/src/sequences/playbackControllers/DefaultPlaybackController.ts b/theatre/core/src/sequences/playbackControllers/DefaultPlaybackController.ts index 130ad99..f85b313 100644 --- a/theatre/core/src/sequences/playbackControllers/DefaultPlaybackController.ts +++ b/theatre/core/src/sequences/playbackControllers/DefaultPlaybackController.ts @@ -76,26 +76,33 @@ export default class DefaultPlaybackController implements IPlaybackController { const startPos = this.getCurrentPosition() if (startPos < range[0] || startPos > range[1]) { - this._updatePositionInState(range[0]) - } else if ( - startPos === range[1] && - (direction === 'normal' || direction === 'alternate') - ) { - this._updatePositionInState(range[0]) - } else if ( - startPos === range[0] && - (direction === 'reverse' || direction === 'alternateReverse') - ) { - this._updatePositionInState(range[1]) + if (direction === 'normal' || direction === 'alternate') { + this._updatePositionInState(range[0]) + } else if ( + direction === 'reverse' || + direction === 'alternateReverse' + ) { + this._updatePositionInState(range[1]) + } + } else if (direction === 'normal' || direction === 'alternate') { + if (startPos === range[1]) { + this._updatePositionInState(range[0]) + } + } else { + if (startPos === range[0]) { + this._updatePositionInState(range[1]) + } } } const deferred = defer() const initialTickerTime = ticker.time const totalPlaybackLength = iterationLength * iterationCount + let initialElapsedPos = this.getCurrentPosition() - range[0] + if (direction === 'reverse' || direction === 'alternateReverse') { - initialElapsedPos = range[1] - initialElapsedPos + initialElapsedPos = range[1] - this.getCurrentPosition() } const tick = (currentTickerTime: number) => { @@ -112,6 +119,7 @@ export default class DefaultPlaybackController implements IPlaybackController { if (elapsedPos !== totalPlaybackLength) { const iterationNumber = Math.floor(elapsedPos / iterationLength) + let currentIterationPos = ((elapsedPos / iterationLength) % 1) * iterationLength @@ -132,7 +140,7 @@ export default class DefaultPlaybackController implements IPlaybackController { } } - this._updatePositionInState(currentIterationPos) + this._updatePositionInState(currentIterationPos + range[0]) requestNextTick() } else { if (direction === 'normal') { diff --git a/theatre/studio/src/UIRoot/useKeyboardShortcuts.ts b/theatre/studio/src/UIRoot/useKeyboardShortcuts.ts index a8c641e..19e1b10 100644 --- a/theatre/studio/src/UIRoot/useKeyboardShortcuts.ts +++ b/theatre/studio/src/UIRoot/useKeyboardShortcuts.ts @@ -39,7 +39,7 @@ export default function useKeyboardShortcuts() { if (seq.playing) { seq.pause() } else { - seq.play({iterationCount: Infinity}) + seq.play({iterationCount: 1000}) } } else { return