From 13a5dbf4896b2243a5309cc8ae25ecc05d79b255 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 23 Sep 2014 11:01:21 -0700 Subject: [PATCH] Added frame computation and JS hooks --- libraries/avatars/src/AvatarData.cpp | 38 ++++++++++++++++++++++++++++ libraries/avatars/src/AvatarData.h | 5 ++++ libraries/avatars/src/Player.cpp | 34 +++++++++++++++++++------ libraries/avatars/src/Player.h | 2 ++ libraries/avatars/src/Recording.cpp | 5 +++- 5 files changed, 75 insertions(+), 9 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 5ac0c69864..020a993f4f 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -625,6 +625,32 @@ qint64 AvatarData::playerLength() { return _player->getRecording()->getLength(); } +int AvatarData::playerCurrentFrame() { + if (!_player) { + return 0; + } + if (QThread::currentThread() != thread()) { + int result; + QMetaObject::invokeMethod(this, "playerCurrentFrame", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(int, result)); + return result; + } + return _player->getCurrentFrame(); +} + +int AvatarData::playerFrameNumber() { + if (!_player) { + return 0; + } + if (QThread::currentThread() != thread()) { + int result; + QMetaObject::invokeMethod(this, "playerFrameNumber", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(int, result)); + return result; + } + return _player->getRecording()->getFrameNumber(); +} + void AvatarData::loadRecording(QString filename) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "loadRecording", Qt::BlockingQueuedConnection, @@ -649,6 +675,18 @@ void AvatarData::startPlaying() { _player->startPlaying(); } +void AvatarData::setPlayerFrame(int frame) { + if (_player) { + _player->setCurrentFrame(frame); + } +} + +void AvatarData::setPlayerTime(qint64 time) { + if (_player) { + _player->setCurrentTime(time); + } +} + void AvatarData::setPlayFromCurrentLocation(bool playFromCurrentLocation) { if (_player) { _player->setPlayFromCurrentLocation(playFromCurrentLocation); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index bc68103ca6..46061b162b 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -298,8 +298,13 @@ public slots: bool isPlaying(); qint64 playerElapsed(); qint64 playerLength(); + int playerCurrentFrame(); + int playerFrameNumber(); + void loadRecording(QString filename); void startPlaying(); + void setPlayerFrame(int frame); + void setPlayerTime(qint64 time); void setPlayFromCurrentLocation(bool playFromCurrentLocation); void setPlayerLoop(bool loop); void setPlayerUseDisplayName(bool useDisplayName); diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 64cfeaf3da..ca5d0eec8d 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include @@ -224,6 +225,9 @@ void Player::setCurrentFrame(int currentFrame) { _currentFrame = currentFrame; _timerOffset = _recording->getFrameTimestamp(_currentFrame); + _timer.restart(); + + setAudionInjectorPosition(); } void Player::setCurrentTime(qint64 currentTime) { @@ -232,15 +236,14 @@ void Player::setCurrentTime(qint64 currentTime) { return; } - _timerOffset = currentTime; - // Find correct frame - int bestGuess = 0; int lowestBound = 0; int highestBound = _recording->getFrameNumber() - 1; - while (_recording->getFrameTimestamp(bestGuess) <= _timerOffset && - _recording->getFrameTimestamp(bestGuess + 1) > _timerOffset) { - if (_recording->getFrameTimestamp(bestGuess) < _timerOffset) { + int bestGuess = 0; + while (!(_recording->getFrameTimestamp(bestGuess) <= currentTime && + _recording->getFrameTimestamp(bestGuess + 1) > currentTime)) { + + if (_recording->getFrameTimestamp(bestGuess) <= currentTime) { lowestBound = bestGuess; } else { highestBound = bestGuess; @@ -248,9 +251,24 @@ void Player::setCurrentTime(qint64 currentTime) { bestGuess = lowestBound + (highestBound - lowestBound) * - (_timerOffset - _recording->getFrameTimestamp(lowestBound)) / - (_recording->getFrameTimestamp(highestBound) - _recording->getFrameTimestamp(lowestBound)); + (float)(currentTime - _recording->getFrameTimestamp(lowestBound)) / + (float)(_recording->getFrameTimestamp(highestBound) - _recording->getFrameTimestamp(lowestBound)); } + + _currentFrame = bestGuess; + _timerOffset = _recording->getFrameTimestamp(bestGuess); + _timer.restart(); + + setAudionInjectorPosition(); +} + +void Player::setAudionInjectorPosition() { + int MSEC_PER_SEC = 1000; + int SAMPLE_SIZE = 2; // 16 bits + int CHANNEL_COUNT = 1; + int FRAME_SIZE = SAMPLE_SIZE * CHANNEL_COUNT; + int currentAudioFrame = elapsed() * FRAME_SIZE * (SAMPLE_RATE / MSEC_PER_SEC); + _injector->setCurrentSendPosition(currentAudioFrame); } void Player::setPlayFromCurrentLocation(bool playFromCurrentLocation) { diff --git a/libraries/avatars/src/Player.h b/libraries/avatars/src/Player.h index 2156648389..749722df28 100644 --- a/libraries/avatars/src/Player.h +++ b/libraries/avatars/src/Player.h @@ -33,6 +33,7 @@ public: qint64 elapsed() const; RecordingPointer getRecording() const { return _recording; } + int getCurrentFrame() const { return _currentFrame; } public slots: void startPlaying(); @@ -55,6 +56,7 @@ private: void setupAudioThread(); void cleanupAudioThread(); void loopRecording(); + void setAudionInjectorPosition(); bool computeCurrentFrame(); QElapsedTimer _timer; diff --git a/libraries/avatars/src/Recording.cpp b/libraries/avatars/src/Recording.cpp index f84b803c5f..a2d6a322a0 100644 --- a/libraries/avatars/src/Recording.cpp +++ b/libraries/avatars/src/Recording.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include @@ -60,6 +61,9 @@ qint32 Recording::getFrameTimestamp(int i) const { if (i >= _timestamps.size()) { return getLength(); } + if (i < 0) { + return 0; + } return _timestamps[i]; } @@ -770,7 +774,6 @@ RecordingPointer readRecordingFromRecFile(RecordingPointer recording, const QStr fileStream >> audioArray; // Cut down audio if necessary - int SAMPLE_RATE = 48000; // 48 kHz int SAMPLE_SIZE = 2; // 16 bits int MSEC_PER_SEC = 1000; int audioLength = recording->getLength() * SAMPLE_SIZE * (SAMPLE_RATE / MSEC_PER_SEC);