Properly handle sequence.play({range}) for range[0] > 0.

Fixes #15
This commit is contained in:
Aria Minaei 2021-09-21 21:22:26 +02:00
parent e395b84cc1
commit fe4010c2c6
6 changed files with 79 additions and 35 deletions

View file

@ -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)

View file

@ -1 +1 @@
import './space-exploration' import './audio'

View file

@ -167,7 +167,7 @@ export default class Sequence {
} }
if (range[0] >= sequenceDuration) { if (range[0] >= sequenceDuration) {
throw new InvalidArgumentError( 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], range[0],
)} given.`, )} given.`,
) )
@ -182,7 +182,7 @@ export default class Sequence {
if (range[1] > sequenceDuration) { if (range[1] > sequenceDuration) {
logger.warn( 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], range[1],
)} given.`, )} given.`,
) )

View file

@ -64,7 +64,7 @@ export default class AudioPlaybackController implements IPlaybackController {
this.playing = true this.playing = true
const ticker = this._ticker const ticker = this._ticker
const startPos = this.getCurrentPosition() let startPos = this.getCurrentPosition()
const iterationLength = range[1] - range[0] const iterationLength = range[1] - range[0]
if (direction !== 'normal') { 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 (startPos < range[0] || startPos > range[1]) {
// if we're currently out of the range // if we're currently out of the range
this._updatePositionInState(range[0]) 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 // if we're currently at the very end of the range
this._updatePositionInState(range[0]) this._updatePositionInState(range[0])
} }
startPos = this.getCurrentPosition()
const deferred = defer<boolean>() const deferred = defer<boolean>()
@ -96,19 +90,25 @@ export default class AudioPlaybackController implements IPlaybackController {
currentSource.connect(this._mainGain) currentSource.connect(this._mainGain)
currentSource.playbackRate.value = rate currentSource.playbackRate.value = rate
const audioStartTimeInSeconds = this._audioContext.currentTime if (iterationCount > 1000) {
const wait = 0 console.warn(
const timeToRangeEnd = range[1] - startPos `Audio-controlled sequences cannot have an iterationCount larger than 1000. It has been clamped to 1000.`,
currentSource.start(
audioStartTimeInSeconds + wait,
startPos - wait,
wait + timeToRangeEnd,
) )
iterationCount = 1000
}
if (iterationCount > 1) {
currentSource.loop = true
currentSource.loopStart = range[0]
currentSource.loopEnd = range[1]
}
const initialTickerTime = ticker.time const initialTickerTime = ticker.time
let initialElapsedPos = this.getCurrentPosition() - range[0] let initialElapsedPos = startPos - range[0]
const totalPlaybackLength = iterationLength * iterationCount const totalPlaybackLength = iterationLength * iterationCount
currentSource.start(0, startPos, totalPlaybackLength - initialElapsedPos)
const tick = (currentTickerTime: number) => { const tick = (currentTickerTime: number) => {
const elapsedTickerTime = Math.max( const elapsedTickerTime = Math.max(
currentTickerTime - initialTickerTime, currentTickerTime - initialTickerTime,
@ -125,7 +125,7 @@ export default class AudioPlaybackController implements IPlaybackController {
let currentIterationPos = let currentIterationPos =
((elapsedPos / iterationLength) % 1) * iterationLength ((elapsedPos / iterationLength) % 1) * iterationLength
this._updatePositionInState(currentIterationPos) this._updatePositionInState(currentIterationPos + range[0])
requestNextTick() requestNextTick()
} else { } else {
this._updatePositionInState(range[1]) this._updatePositionInState(range[1])

View file

@ -76,26 +76,33 @@ export default class DefaultPlaybackController implements IPlaybackController {
const startPos = this.getCurrentPosition() const startPos = this.getCurrentPosition()
if (startPos < range[0] || startPos > range[1]) { if (startPos < range[0] || startPos > range[1]) {
if (direction === 'normal' || direction === 'alternate') {
this._updatePositionInState(range[0]) this._updatePositionInState(range[0])
} else if ( } else if (
startPos === range[1] && direction === 'reverse' ||
(direction === 'normal' || direction === 'alternate') direction === 'alternateReverse'
) {
this._updatePositionInState(range[0])
} else if (
startPos === range[0] &&
(direction === 'reverse' || direction === 'alternateReverse')
) { ) {
this._updatePositionInState(range[1]) 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<boolean>() const deferred = defer<boolean>()
const initialTickerTime = ticker.time const initialTickerTime = ticker.time
const totalPlaybackLength = iterationLength * iterationCount const totalPlaybackLength = iterationLength * iterationCount
let initialElapsedPos = this.getCurrentPosition() - range[0] let initialElapsedPos = this.getCurrentPosition() - range[0]
if (direction === 'reverse' || direction === 'alternateReverse') { if (direction === 'reverse' || direction === 'alternateReverse') {
initialElapsedPos = range[1] - initialElapsedPos initialElapsedPos = range[1] - this.getCurrentPosition()
} }
const tick = (currentTickerTime: number) => { const tick = (currentTickerTime: number) => {
@ -112,6 +119,7 @@ export default class DefaultPlaybackController implements IPlaybackController {
if (elapsedPos !== totalPlaybackLength) { if (elapsedPos !== totalPlaybackLength) {
const iterationNumber = Math.floor(elapsedPos / iterationLength) const iterationNumber = Math.floor(elapsedPos / iterationLength)
let currentIterationPos = let currentIterationPos =
((elapsedPos / iterationLength) % 1) * iterationLength ((elapsedPos / iterationLength) % 1) * iterationLength
@ -132,7 +140,7 @@ export default class DefaultPlaybackController implements IPlaybackController {
} }
} }
this._updatePositionInState(currentIterationPos) this._updatePositionInState(currentIterationPos + range[0])
requestNextTick() requestNextTick()
} else { } else {
if (direction === 'normal') { if (direction === 'normal') {

View file

@ -39,7 +39,7 @@ export default function useKeyboardShortcuts() {
if (seq.playing) { if (seq.playing) {
seq.pause() seq.pause()
} else { } else {
seq.play({iterationCount: Infinity}) seq.play({iterationCount: 1000})
} }
} else { } else {
return return