From 925f8241e5062baf69cdc3d63209c41458596034 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 25 Mar 2014 11:48:46 -0700 Subject: [PATCH 01/15] adding joint animation --- examples/bot.js | 53 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/examples/bot.js b/examples/bot.js index ea78f40de9..c606b55274 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -23,10 +23,10 @@ function printVector(string, vector) { } var CHANCE_OF_MOVING = 0.005; -var CHANCE_OF_SOUND = 0.005; +var CHANCE_OF_SOUND = 0.000; var CHANCE_OF_HEAD_TURNING = 0.05; var CHANCE_OF_BIG_MOVE = 0.1; -var CHANCE_OF_WAVING = 0.005; // Currently this isn't working +var CHANCE_OF_WAVING = 0.009; var shouldReceiveVoxels = true; var VOXEL_FPS = 60.0; @@ -39,12 +39,16 @@ var isWaving = false; var waveFrequency = 0.0; var waveAmplitude = 0.0; -var X_MIN = 0.0; -var X_MAX = 5.0; -var Z_MIN = 0.0; -var Z_MAX = 5.0; +var X_MIN = 20.0; +var X_MAX = 25.0; +var Z_MIN = 20.0; +var Z_MAX = 25.0; var Y_PELVIS = 2.5; -var SHOULDER_JOINT_NUMBER = 15; +var SPINE_JOINT_NUMBER = 13; +var SHOULDER_JOINT_NUMBER = 17; +var ELBOW_JOINT_NUMBER = 18; +var JOINT_R_HIP = 1; +var JOINT_R_KNEE = 2; var MOVE_RANGE_SMALL = 0.5; var MOVE_RANGE_BIG = Math.max(X_MAX - X_MIN, Z_MAX - Z_MIN) / 2.0; @@ -61,6 +65,9 @@ var targetDirection = { x: 0, y: 0, z: 0, w: 0 }; var currentDirection = { x: 0, y: 0, z: 0, w: 0 }; var targetHeadPitch = 0.0; +var walkFrequency = 5.0; +var walkAmplitude = 45.0; + var cumulativeTime = 0.0; var sounds = []; @@ -115,12 +122,29 @@ printVector("New bot, position = ", Avatar.position); function stopWaving() { isWaving = false; Avatar.clearJointData(SHOULDER_JOINT_NUMBER); + Avatar.clearJointData(ELBOW_JOINT_NUMBER); + Avatar.clearJointData(SPINE_JOINT_NUMBER); +} + +function keepWalking() { + Avatar.setJointData(JOINT_R_HIP, Quat.fromPitchYawRollDegrees(walkAmplitude * Math.sin(cumulativeTime * walkFrequency), 0.0, 0.0)); +} + +function stopWalking() { + Avatar.clearJointData(JOINT_R_HIP); + Avatar.clearJointData(JOINT_R_KNEE); } function updateBehavior(deltaTime) { cumulativeTime += deltaTime; + // Hack - right now you need to set the avatar position a bit after the avatar is made to make sure it's there. + + if (CHANCE_OF_MOVING = 0.000) { + Avatar.position = firstPosition; + } + if (shouldReceiveVoxels && ((cumulativeTime - lastVoxelQueryTime) > (1.0 / VOXEL_FPS))) { VoxelViewer.setPosition(Avatar.position); VoxelViewer.setOrientation(Avatar.orientation); @@ -134,13 +158,18 @@ function updateBehavior(deltaTime) { if (!isWaving && (Math.random() < CHANCE_OF_WAVING)) { isWaving = true; - waveFrequency = 1.0 + Math.random() * 5.0; + waveFrequency = 3.0 + Math.random() * 5.0; waveAmplitude = 5.0 + Math.random() * 60.0; Script.setTimeout(stopWaving, 1000 + Math.random() * 2000); + Avatar.setJointData(ELBOW_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 45, 0.0)); // Initially turn the palm outward } else if (isWaving) { - Avatar.setJointData(SHOULDER_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, waveAmplitude * Math.sin(cumulativeTime * waveFrequency))); + Avatar.setJointData(SHOULDER_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, 60 + waveAmplitude * Math.sin((cumulativeTime - 0.25) * waveFrequency))); + Avatar.setJointData(ELBOW_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, 25 + waveAmplitude/2.0 * Math.sin(cumulativeTime * 1.2 * waveFrequency))); + Avatar.setJointData(SPINE_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, 60 + waveAmplitude/4.0 * Math.sin(cumulativeTime * waveFrequency))); + } + if (Math.random() < CHANCE_OF_SOUND) { playRandomSound(); } @@ -168,11 +197,13 @@ function updateBehavior(deltaTime) { targetPosition.y = Y_PELVIS; isMoving = true; - } else { + } else if (isMoving) { + keepWalking(); Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(Vec3.subtract(targetPosition, Avatar.position), MOVE_RATE)); Avatar.orientation = Quat.mix(Avatar.orientation, targetDirection, TURN_RATE); if (Vec3.length(Vec3.subtract(Avatar.position, targetPosition)) < STOP_TOLERANCE) { - isMoving = false; + isMoving = false; + stopWalking(); } } } From d90244c01ef4715b2600e28e229cab73c19b432c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 25 Mar 2014 22:31:44 -0700 Subject: [PATCH 02/15] first pass, clipping audio meter --- interface/src/Application.cpp | 38 ++++++++++++++++++++++++++++++++++- interface/src/Audio.cpp | 10 +++++++++ interface/src/Audio.h | 2 ++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 13c05fa702..549d1f04e2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2494,7 +2494,7 @@ void Application::displayOverlay() { renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude()); } } - + if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { _audio.renderMuteIcon(1, _glWidget->height() - 50); if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) { @@ -2502,6 +2502,42 @@ void Application::displayOverlay() { _audioScope.render(25, oscilloscopeTop); } } + + const int AUDIO_METER_WIDTH = 300; + const int AUDIO_METER_INSET = 2; + const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET; + const int AUDIO_METER_HEIGHT = 8; + const int AUDIO_METER_Y = _glWidget->height() - 40; + const int AUDIO_METER_X = 25; + const float CLIPPING_INDICATOR_TIME = 1.0f; + float audioLevel = log10(_audio.getLastInputLoudness() + 1.0) / log10(32767.0) * (float)AUDIO_METER_SCALE_WIDTH; + bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)); + + if (isClipping) { + glColor3f(1, 0, 0); + } else { + glColor3f(0, 0, 0); + } + glBegin(GL_QUADS); + // Draw background Quad + glVertex2i(AUDIO_METER_X, AUDIO_METER_Y); + glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, AUDIO_METER_Y); + glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, AUDIO_METER_Y + AUDIO_METER_HEIGHT); + glVertex2i(AUDIO_METER_X, AUDIO_METER_Y + AUDIO_METER_HEIGHT); + + // Draw Meter Quad + if (isClipping) { + glColor3f(1, 1, 1); + } else { + glColor3f(0, 1, 1); + } + // Draw Meter quad + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, AUDIO_METER_Y + AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, AUDIO_METER_Y + AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, AUDIO_METER_Y + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, AUDIO_METER_Y + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); + + glEnd(); if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) { _myAvatar->renderHeadMouse(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 734b5345fb..92bbea3afe 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -60,6 +60,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p _measuredJitter(0), _jitterBufferSamples(initialJitterBufferSamples), _lastInputLoudness(0), + _timeSinceLastClip(-1.0), _dcOffset(0), _noiseGateMeasuredFloor(0), _noiseGateSampleCounter(0), @@ -469,13 +470,22 @@ void Audio::handleAudioInput() { const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; const float DC_OFFSET_AVERAGING = 0.99f; + const float CLIPPING_THRESHOLD = 0.90f; float measuredDcOffset = 0.f; + // Increment the time since the last clip + if (_timeSinceLastClip >= 0.0f) { + _timeSinceLastClip += (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE; + } + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { measuredDcOffset += monoAudioSamples[i]; monoAudioSamples[i] -= (int16_t) _dcOffset; thisSample = fabsf(monoAudioSamples[i]); + if (thisSample > (32767.f * CLIPPING_THRESHOLD)) { + _timeSinceLastClip = 0.0f; + } loudness += thisSample; // Noise Reduction: Count peaks above the average loudness if (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT)) { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 7aa1ef5afe..2d79e82918 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -47,6 +47,7 @@ public: Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent = 0); float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); } + float getTimeSinceLastClip() const { return _timeSinceLastClip; } float getAudioAverageInputLoudness() const { return _lastInputLoudness; } void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; } @@ -130,6 +131,7 @@ private: float _measuredJitter; int16_t _jitterBufferSamples; float _lastInputLoudness; + float _timeSinceLastClip; float _dcOffset; float _noiseGateMeasuredFloor; float* _noiseSampleFrames; From 5cce4b3c03f96d26af9d5df8b4873aeea9df50b0 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 26 Mar 2014 12:14:03 -0700 Subject: [PATCH 03/15] added more movement --- examples/bot.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/bot.js b/examples/bot.js index c606b55274..acd837e3b8 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -128,6 +128,7 @@ function stopWaving() { function keepWalking() { Avatar.setJointData(JOINT_R_HIP, Quat.fromPitchYawRollDegrees(walkAmplitude * Math.sin(cumulativeTime * walkFrequency), 0.0, 0.0)); + Avatar.setJointData(JOINT_R_KNEE, Quat.fromPitchYawRollDegrees(walkAmplitude * Math.sin(cumulativeTime * walkFrequency), 0.0, 0.0)); } function stopWalking() { @@ -141,7 +142,7 @@ function updateBehavior(deltaTime) { // Hack - right now you need to set the avatar position a bit after the avatar is made to make sure it's there. - if (CHANCE_OF_MOVING = 0.000) { + if (CHANCE_OF_MOVING == 0.000) { Avatar.position = firstPosition; } From 718b8f7eb9adca76dbb4a37733c362816ee01d71 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Mar 2014 15:04:45 -0700 Subject: [PATCH 04/15] Changed back to upload either head or skeleton --- interface/src/Application.cpp | 12 ++++++++++-- interface/src/Application.h | 4 +++- interface/src/Menu.cpp | 3 ++- interface/src/Menu.h | 3 ++- libraries/shared/src/FstReader.cpp | 9 +++------ libraries/shared/src/FstReader.h | 2 +- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 13c05fa702..5e0d49a94a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3512,13 +3512,21 @@ void Application::reloadAllScripts() { } } -void Application::uploadFST() { - FstReader reader; +void Application::uploadFST(bool isHead) { + FstReader reader(isHead); if (reader.zip()) { reader.send(); } } +void Application::uploadHead() { + uploadFST(true); +} + +void Application::uploadSkeleton() { + uploadFST(false); +} + void Application::removeScriptName(const QString& fileNameString) { _activeScripts.removeOne(fileNameString); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 15778f2a17..6350d1b63e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -261,7 +261,9 @@ public slots: void stopAllScripts(); void reloadAllScripts(); - void uploadFST(); + void uploadFST(bool isHead); + void uploadHead(); + void uploadSkeleton(); private slots: void timer(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 30be26ee96..d9dcb23b77 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -144,7 +144,8 @@ Menu::Menu() : SLOT(goTo())); addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model"); - addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadFST, 0, Application::getInstance(), SLOT(uploadFST())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0, Application::getInstance(), SLOT(uploadHead())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadSkeleton, 0, Application::getInstance(), SLOT(uploadSkeleton())); addDisabledActionAndSeparator(fileMenu, "Settings"); addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 9452ba220d..25810f0bdd 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -298,7 +298,8 @@ namespace MenuOption { const QString StopAllScripts = "Stop All Scripts"; const QString TestPing = "Test Ping"; const QString TransmitterDrive = "Transmitter Drive"; - const QString UploadFST = "Upload FST file"; + const QString UploadHead = "Upload Head Model"; + const QString UploadSkeleton = "Upload Skeleton Model"; const QString Visage = "Visage"; const QString Quit = "Quit"; const QString Voxels = "Voxels"; diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index 0fb9c46458..551731a542 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -25,17 +25,16 @@ static const QString NAME_FIELD = "name"; static const QString FILENAME_FIELD = "filename"; static const QString TEXDIR_FIELD = "texdir"; static const QString LOD_FIELD = "lod"; -static const QString HEAD_SPECIFIC_FIELD = "bs"; static const QString MODEL_URL = "/api/v1/models"; static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB -FstReader::FstReader() : +FstReader::FstReader(bool isHead) : _lodCount(-1), _texturesCount(-1), _totalSize(0), - _isHead(false), + _isHead(isHead), _readyToSend(false), _dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType)) { @@ -95,9 +94,7 @@ bool FstReader::zip() { } // according to what is read, we modify the command - if (line[1] == HEAD_SPECIFIC_FIELD) { - _isHead = true; - } else if (line[1] == NAME_FIELD) { + if (line[0] == NAME_FIELD) { QHttpPart textPart; textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" " name=\"model_name\""); diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/FstReader.h index 1d9da71641..d06742810b 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/FstReader.h @@ -16,7 +16,7 @@ class QHttpMultiPart; class FstReader { public: - FstReader(); + FstReader(bool isHead); ~FstReader(); bool zip(); From fa2a60448bb808cb82b453faaf6281492bc20aa3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Mar 2014 15:09:44 -0700 Subject: [PATCH 05/15] Fixed double free crash --- libraries/shared/src/FstReader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index 551731a542..15e31cee07 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -170,6 +170,7 @@ bool FstReader::send() { } AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart); + _dataMultiPart = NULL; return true; } From ce186cf0f79689cdf4b4c03a23af90434ba7eefc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Mar 2014 15:10:18 -0700 Subject: [PATCH 06/15] Added bunch of feedback --- libraries/shared/src/FstReader.cpp | 40 +++++++++++++++++------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index 15e31cee07..e3b88f3870 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -62,19 +62,19 @@ bool FstReader::zip() { QString("ModelUploader::zip()"), QString("Could not open FST file."), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Could not open FST file."); return false; } + qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); // Compress and copy the fst if (!compressFile(QFileInfo(fst).filePath(), _zipDir.path() + "/" + QFileInfo(fst).fileName())) { return false; } - _totalSize += QFileInfo(fst).size(); if (!addPart(_zipDir.path() + "/" + QFileInfo(fst).fileName(), QString("fst"))) { return false; } - qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); // Let's read through the FST file QTextStream stream(&fst); @@ -85,14 +85,6 @@ bool FstReader::zip() { continue; } - if (_totalSize > MAX_SIZE) { - QMessageBox::warning(NULL, - QString("ModelUploader::zip()"), - QString("Model too big, over %1 Bytes.").arg(MAX_SIZE), - QMessageBox::Ok); - return false; - } - // according to what is read, we modify the command if (line[0] == NAME_FIELD) { QHttpPart textPart; @@ -100,56 +92,56 @@ bool FstReader::zip() { " name=\"model_name\""); textPart.setBody(line[1].toUtf8()); _dataMultiPart->append(textPart); - } else if (line[1] == FILENAME_FIELD) { + } else if (line[0] == FILENAME_FIELD) { QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]); if (!fbx.exists() || !fbx.isFile()) { // Check existence QMessageBox::warning(NULL, QString("ModelUploader::zip()"), QString("FBX file %1 could not be found.").arg(fbx.fileName()), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(fbx.fileName()); return false; } // Compress and copy if (!compressFile(fbx.filePath(), _zipDir.path() + "/" + line[1])) { return false; } - _totalSize += fbx.size(); if (!addPart(_zipDir.path() + "/" + line[1], "fbx")) { return false; } - } else if (line[1] == TEXDIR_FIELD) { // Check existence + } else if (line[0] == TEXDIR_FIELD) { // Check existence QFileInfo texdir(QFileInfo(fst).path() + "/" + line[1]); if (!texdir.exists() || !texdir.isDir()) { QMessageBox::warning(NULL, QString("ModelUploader::zip()"), QString("Texture directory could not be found."), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Texture directory could not be found."); return false; } if (!addTextures(texdir)) { // Recursive compress and copy return false; } - } else if (line[1] == LOD_FIELD) { + } else if (line[0] == LOD_FIELD) { QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]); if (!lod.exists() || !lod.isFile()) { // Check existence QMessageBox::warning(NULL, QString("ModelUploader::zip()"), QString("FBX file %1 could not be found.").arg(lod.fileName()), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(lod.fileName()); return false; } // Compress and copy if (!compressFile(lod.filePath(), _zipDir.path() + "/" + line[1])) { return false; } - _totalSize += lod.size(); if (!addPart(_zipDir.path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) { return false; } } } - QHttpPart textPart; textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" " name=\"model_category\""); @@ -190,7 +182,6 @@ bool FstReader::addTextures(const QFileInfo& texdir) { if (!compressFile(info.filePath(), _zipDir.path() + "/" + info.fileName())) { return false; } - _totalSize += info.size(); if (!addPart(_zipDir.path() + "/" + info.fileName(), QString("texture%1").arg(++_texturesCount))) { return false; @@ -218,6 +209,7 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa QString("ModelUploader::compressFile()"), QString("Could not compress %1").arg(inFileName), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Could not compress %1").arg(inFileName); return false; } } @@ -235,6 +227,7 @@ bool FstReader::addPart(const QString &path, const QString& name) { QString("ModelUploader::addPart()"), QString("Could not open %1").arg(path), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Could not open %1").arg(path); return false; } @@ -247,6 +240,19 @@ bool FstReader::addPart(const QString &path, const QString& name) { _dataMultiPart->append(part); file->setParent(_dataMultiPart); + + qDebug() << "File " << QFileInfo(*file).fileName() << " added to model."; + _totalSize += file->size(); + if (_totalSize > MAX_SIZE) { + QMessageBox::warning(NULL, + QString("ModelUploader::zip()"), + QString("Model too big, over %1 Bytes.").arg(MAX_SIZE), + QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Model too big, over %1 Bytes.").arg(MAX_SIZE); + return false; + } + qDebug() << "Current model size: " << _totalSize; + return true; } From d32797b54c468411aa74e0c2e830b3c47a67fdb0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Mar 2014 15:10:18 -0700 Subject: [PATCH 07/15] Added bunch of feedback --- libraries/shared/src/FstReader.cpp | 41 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index 15e31cee07..205ab1794d 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -62,19 +62,19 @@ bool FstReader::zip() { QString("ModelUploader::zip()"), QString("Could not open FST file."), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Could not open FST file."); return false; } + qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); // Compress and copy the fst if (!compressFile(QFileInfo(fst).filePath(), _zipDir.path() + "/" + QFileInfo(fst).fileName())) { return false; } - _totalSize += QFileInfo(fst).size(); if (!addPart(_zipDir.path() + "/" + QFileInfo(fst).fileName(), QString("fst"))) { return false; } - qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); // Let's read through the FST file QTextStream stream(&fst); @@ -85,14 +85,6 @@ bool FstReader::zip() { continue; } - if (_totalSize > MAX_SIZE) { - QMessageBox::warning(NULL, - QString("ModelUploader::zip()"), - QString("Model too big, over %1 Bytes.").arg(MAX_SIZE), - QMessageBox::Ok); - return false; - } - // according to what is read, we modify the command if (line[0] == NAME_FIELD) { QHttpPart textPart; @@ -100,56 +92,56 @@ bool FstReader::zip() { " name=\"model_name\""); textPart.setBody(line[1].toUtf8()); _dataMultiPart->append(textPart); - } else if (line[1] == FILENAME_FIELD) { + } else if (line[0] == FILENAME_FIELD) { QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]); if (!fbx.exists() || !fbx.isFile()) { // Check existence QMessageBox::warning(NULL, QString("ModelUploader::zip()"), QString("FBX file %1 could not be found.").arg(fbx.fileName()), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(fbx.fileName()); return false; } // Compress and copy if (!compressFile(fbx.filePath(), _zipDir.path() + "/" + line[1])) { return false; } - _totalSize += fbx.size(); if (!addPart(_zipDir.path() + "/" + line[1], "fbx")) { return false; } - } else if (line[1] == TEXDIR_FIELD) { // Check existence + } else if (line[0] == TEXDIR_FIELD) { // Check existence QFileInfo texdir(QFileInfo(fst).path() + "/" + line[1]); if (!texdir.exists() || !texdir.isDir()) { QMessageBox::warning(NULL, QString("ModelUploader::zip()"), QString("Texture directory could not be found."), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Texture directory could not be found."); return false; } if (!addTextures(texdir)) { // Recursive compress and copy return false; } - } else if (line[1] == LOD_FIELD) { + } else if (line[0] == LOD_FIELD) { QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]); if (!lod.exists() || !lod.isFile()) { // Check existence QMessageBox::warning(NULL, QString("ModelUploader::zip()"), QString("FBX file %1 could not be found.").arg(lod.fileName()), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(lod.fileName()); return false; } // Compress and copy if (!compressFile(lod.filePath(), _zipDir.path() + "/" + line[1])) { return false; } - _totalSize += lod.size(); if (!addPart(_zipDir.path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) { return false; } } } - QHttpPart textPart; textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" " name=\"model_category\""); @@ -171,6 +163,7 @@ bool FstReader::send() { AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart); _dataMultiPart = NULL; + qDebug() << "Model sent."; return true; } @@ -190,7 +183,6 @@ bool FstReader::addTextures(const QFileInfo& texdir) { if (!compressFile(info.filePath(), _zipDir.path() + "/" + info.fileName())) { return false; } - _totalSize += info.size(); if (!addPart(_zipDir.path() + "/" + info.fileName(), QString("texture%1").arg(++_texturesCount))) { return false; @@ -218,6 +210,7 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa QString("ModelUploader::compressFile()"), QString("Could not compress %1").arg(inFileName), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Could not compress %1").arg(inFileName); return false; } } @@ -235,6 +228,7 @@ bool FstReader::addPart(const QString &path, const QString& name) { QString("ModelUploader::addPart()"), QString("Could not open %1").arg(path), QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Could not open %1").arg(path); return false; } @@ -247,6 +241,19 @@ bool FstReader::addPart(const QString &path, const QString& name) { _dataMultiPart->append(part); file->setParent(_dataMultiPart); + + qDebug() << "File " << QFileInfo(*file).fileName() << " added to model."; + _totalSize += file->size(); + if (_totalSize > MAX_SIZE) { + QMessageBox::warning(NULL, + QString("ModelUploader::zip()"), + QString("Model too big, over %1 Bytes.").arg(MAX_SIZE), + QMessageBox::Ok); + qDebug() << "[Warning] " << QString("Model too big, over %1 Bytes.").arg(MAX_SIZE); + return false; + } + qDebug() << "Current model size: " << _totalSize; + return true; } From 0b13a7173cb065f9c8fbe897ea0cb66ed0215859 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 26 Mar 2014 23:24:36 -0700 Subject: [PATCH 08/15] disable wheel for size scaling --- examples/editVoxels.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 5e4b77a10f..4922caf0d8 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -1326,7 +1326,7 @@ function wheelEvent(event) { } } -Controller.wheelEvent.connect(wheelEvent); +// Controller.wheelEvent.connect(wheelEvent); Controller.mousePressEvent.connect(mousePressEvent); Controller.mouseReleaseEvent.connect(mouseReleaseEvent); Controller.mouseMoveEvent.connect(mouseMoveEvent); From 88e7b8e68f636fb0f56f69397288f7d11310865a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 27 Mar 2014 11:16:52 -0700 Subject: [PATCH 09/15] Fixed "memory leak" in Account Manager. --- libraries/shared/src/AccountManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index bb32896ca0..2fe5007ad1 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -148,6 +148,7 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: if (dataMultiPart) { if (operation == QNetworkAccessManager::PostOperation) { networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart); + dataMultiPart->setParent(networkReply); } else { networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart); } @@ -199,6 +200,7 @@ void AccountManager::passSuccessToCallback() { qDebug() << jsonResponse; } } + delete requestReply; } void AccountManager::passErrorToCallback(QNetworkReply::NetworkError errorCode) { @@ -219,6 +221,7 @@ void AccountManager::passErrorToCallback(QNetworkReply::NetworkError errorCode) qDebug() << "Error" << errorCode << "-" << requestReply->errorString(); } } + delete requestReply; } bool AccountManager::hasValidAccessToken() { From d9c48d63fe5dc8e143ac9f95d7bf43bb9fbc4f11 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 27 Mar 2014 11:18:32 -0700 Subject: [PATCH 10/15] Made _zipDir a children of _dataMultiPart so it gets deleted at the right time. --- libraries/shared/src/FstReader.cpp | 33 +++++++++++++++++++++--------- libraries/shared/src/FstReader.h | 7 +++---- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index 205ab1794d..14cff957b1 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -13,11 +13,11 @@ #include #include #include +#include #include #include #include "AccountManager.h" - #include "FstReader.h" @@ -30,7 +30,16 @@ static const QString MODEL_URL = "/api/v1/models"; static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB +// Class providing the QObject parent system to QTemporaryDir +class TemporaryDir : public QTemporaryDir, public QObject { +public: + virtual ~TemporaryDir() { + // ensuring the entire object gets deleted by the QObject parent. + } +}; + FstReader::FstReader(bool isHead) : + _zipDir(new TemporaryDir()), _lodCount(-1), _texturesCount(-1), _totalSize(0), @@ -38,6 +47,8 @@ FstReader::FstReader(bool isHead) : _readyToSend(false), _dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType)) { + _zipDir->setParent(_dataMultiPart); + } FstReader::~FstReader() { @@ -68,10 +79,10 @@ bool FstReader::zip() { qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); // Compress and copy the fst - if (!compressFile(QFileInfo(fst).filePath(), _zipDir.path() + "/" + QFileInfo(fst).fileName())) { + if (!compressFile(QFileInfo(fst).filePath(), _zipDir->path() + "/" + QFileInfo(fst).fileName())) { return false; } - if (!addPart(_zipDir.path() + "/" + QFileInfo(fst).fileName(), + if (!addPart(_zipDir->path() + "/" + QFileInfo(fst).fileName(), QString("fst"))) { return false; } @@ -103,10 +114,10 @@ bool FstReader::zip() { return false; } // Compress and copy - if (!compressFile(fbx.filePath(), _zipDir.path() + "/" + line[1])) { + if (!compressFile(fbx.filePath(), _zipDir->path() + "/" + line[1])) { return false; } - if (!addPart(_zipDir.path() + "/" + line[1], "fbx")) { + if (!addPart(_zipDir->path() + "/" + line[1], "fbx")) { return false; } } else if (line[0] == TEXDIR_FIELD) { // Check existence @@ -133,10 +144,10 @@ bool FstReader::zip() { return false; } // Compress and copy - if (!compressFile(lod.filePath(), _zipDir.path() + "/" + line[1])) { + if (!compressFile(lod.filePath(), _zipDir->path() + "/" + line[1])) { return false; } - if (!addPart(_zipDir.path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) { + if (!addPart(_zipDir->path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) { return false; } } @@ -162,6 +173,7 @@ bool FstReader::send() { } AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart); + _zipDir = NULL; _dataMultiPart = NULL; qDebug() << "Model sent."; @@ -180,10 +192,10 @@ bool FstReader::addTextures(const QFileInfo& texdir) { foreach (QFileInfo info, list) { if (info.isFile()) { // Compress and copy - if (!compressFile(info.filePath(), _zipDir.path() + "/" + info.fileName())) { + if (!compressFile(info.filePath(), _zipDir->path() + "/" + info.fileName())) { return false; } - if (!addPart(_zipDir.path() + "/" + info.fileName(), + if (!addPart(_zipDir->path() + "/" + info.fileName(), QString("texture%1").arg(++_texturesCount))) { return false; } @@ -204,7 +216,7 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa QFile outFile(outFileName); if (!outFile.open(QIODevice::WriteOnly)) { - QDir(_zipDir.path()).mkpath(QFileInfo(outFileName).path()); + QDir(_zipDir->path()).mkpath(QFileInfo(outFileName).path()); if (!outFile.open(QIODevice::WriteOnly)) { QMessageBox::warning(NULL, QString("ModelUploader::compressFile()"), @@ -229,6 +241,7 @@ bool FstReader::addPart(const QString &path, const QString& name) { QString("Could not open %1").arg(path), QMessageBox::Ok); qDebug() << "[Warning] " << QString("Could not open %1").arg(path); + delete file; return false; } diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/FstReader.h index d06742810b..6d1cac01c4 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/FstReader.h @@ -10,11 +10,10 @@ #ifndef __hifi__FstReader__ #define __hifi__FstReader__ -#include - +class TemporaryDir; class QHttpMultiPart; -class FstReader { +class FstReader : public QObject { public: FstReader(bool isHead); ~FstReader(); @@ -23,7 +22,7 @@ public: bool send(); private: - QTemporaryDir _zipDir; + TemporaryDir* _zipDir; int _lodCount; int _texturesCount; int _totalSize; From 41e9017953a2261774c8ec50ee1fe12fbb355c85 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 27 Mar 2014 15:14:38 -0700 Subject: [PATCH 11/15] more audio level meter work, improved gun --- examples/gun.js | 36 ++++++++++++++++++++++++++--------- interface/src/Application.cpp | 12 ++++++++++-- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/examples/gun.js b/examples/gun.js index 94f3fd4ee3..e358e6b391 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -27,6 +27,9 @@ var BULLET_VELOCITY = 5.0; var MIN_THROWER_DELAY = 1000; var MAX_THROWER_DELAY = 1000; var LEFT_BUTTON_3 = 3; +var RELOAD_INTERVAL = 9; + +var showScore = false; // Load some sound to use for loading and firing var fireSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/GUN-SHOT2.raw"); @@ -38,6 +41,8 @@ var targetLaunchSound = new Sound("http://highfidelity-public.s3-us-west-1.amazo var audioOptions = new AudioInjectionOptions(); audioOptions.volume = 0.9; +var shotsFired = 0; + var shotTime = new Date(); // initialize our triggers @@ -63,7 +68,8 @@ var reticle = Overlays.addOverlay("image", { alpha: 1 }); -var text = Overlays.addOverlay("text", { +if (showScore) { + var text = Overlays.addOverlay("text", { x: screenSize.x / 2 - 100, y: screenSize.y / 2 - 50, width: 150, @@ -74,6 +80,8 @@ var text = Overlays.addOverlay("text", { leftMargin: 4, text: "Score: " + score }); +} + function printVector(string, vector) { @@ -94,6 +102,10 @@ function shootBullet(position, velocity) { // Play firing sounds audioOptions.position = position; Audio.playSound(fireSound, audioOptions); + shotsFired++; + if ((shotsFired % RELOAD_INTERVAL) == 0) { + Audio.playSound(loadSound, audioOptions); + } } function shootTarget() { @@ -147,12 +159,15 @@ function particleCollisionWithVoxel(particle, voxel, penetration) { Voxels.eraseVoxel(position.x, position.y, position.z, HOLE_SIZE); //audioOptions.position = position; audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - Audio.playSound(targetHitSound, audioOptions); + Audio.playSound(impactSound, audioOptions); } function particleCollisionWithParticle(particle1, particle2) { score++; - Overlays.editOverlay(text, { text: "Score: " + score } ); + if (showScore) { + Overlays.editOverlay(text, { text: "Score: " + score } ); + } + // Sort out which particle is which // Record shot time @@ -171,12 +186,12 @@ function keyPressEvent(event) { if (event.text == "t") { var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY; Script.setTimeout(shootTarget, time); + } if (event.text == ".") { + shootFromMouse(); } } function update(deltaTime) { - - // Check for mouseLook movement, update rotation // rotate body yaw for yaw received from mouse var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); @@ -257,18 +272,21 @@ function mousePressEvent(event) { isMouseDown = true; lastX = event.x; lastY = event.y; - audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - Audio.playSound(loadSound, audioOptions); + //audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); + //Audio.playSound(loadSound, audioOptions); } -function mouseReleaseEvent(event) { - // position +function shootFromMouse() { var DISTANCE_FROM_CAMERA = 2.0; var camera = Camera.getPosition(); var forwardVector = Quat.getFront(Camera.getOrientation()); var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA)); var velocity = Vec3.multiply(forwardVector, BULLET_VELOCITY); shootBullet(newPosition, velocity); +} + +function mouseReleaseEvent(event) { + // position isMouseDown = false; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 864be460e7..c67f992536 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2503,14 +2503,22 @@ void Application::displayOverlay() { } } - const int AUDIO_METER_WIDTH = 300; + const int AUDIO_METER_WIDTH = 200; const int AUDIO_METER_INSET = 2; const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET; const int AUDIO_METER_HEIGHT = 8; const int AUDIO_METER_Y = _glWidget->height() - 40; const int AUDIO_METER_X = 25; const float CLIPPING_INDICATOR_TIME = 1.0f; - float audioLevel = log10(_audio.getLastInputLoudness() + 1.0) / log10(32767.0) * (float)AUDIO_METER_SCALE_WIDTH; + const float LOG2 = log(2.f); + float audioLevel = 0.f; + float loudness = _audio.getLastInputLoudness() + 1.f; + float log2loudness = log(loudness) / LOG2; + if (loudness < 2048) { + audioLevel = (log2loudness / 11.f) * (AUDIO_METER_SCALE_WIDTH / 5.f); + } else { + audioLevel = (log2loudness - 10.f) * (AUDIO_METER_SCALE_WIDTH / 5.f); + } bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)); if (isClipping) { From 27f0214032989e4e8eb32e6cfd0a5a0acb8e5d66 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 28 Mar 2014 23:09:51 -0700 Subject: [PATCH 12/15] first pass audio VU scope --- interface/src/Application.cpp | 106 ++++++++++++++++++++++++---------- interface/src/Application.h | 1 + interface/src/Menu.cpp | 2 +- 3 files changed, 78 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 98f260c3bf..1974ddd60c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -151,6 +151,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _lastQueriedViewFrustum(), _lastQueriedTime(usecTimestampNow()), _audioScope(256, 200, true), + _trailingAudioLoudness(0.f), _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), _mouseX(0), _mouseY(0), @@ -2504,56 +2505,101 @@ void Application::displayOverlay() { } } + // Audio Scope + const int AUDIO_SCOPE_Y_OFFSET = 135; if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { - _audio.renderMuteIcon(1, _glWidget->height() - 50); if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) { - int oscilloscopeTop = _glWidget->height() - 135; - _audioScope.render(25, oscilloscopeTop); + int oscilloscopeTop = _glWidget->height() - AUDIO_SCOPE_Y_OFFSET; + _audioScope.render(MIRROR_VIEW_LEFT_PADDING, oscilloscopeTop); } } - const int AUDIO_METER_WIDTH = 200; + // Audio VU Meter and Mute Icon + const int MUTE_ICON_SIZE = 24; const int AUDIO_METER_INSET = 2; + const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET; const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET; const int AUDIO_METER_HEIGHT = 8; - const int AUDIO_METER_Y = _glWidget->height() - 40; - const int AUDIO_METER_X = 25; + const int AUDIO_METER_Y_GAP = 8; + const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET; + + int audioMeterY; + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_Y_GAP; + } else { + audioMeterY = AUDIO_METER_Y_GAP; + } + _audio.renderMuteIcon(MIRROR_VIEW_LEFT_PADDING, audioMeterY); + + + const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0}; + const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0}; + const float AUDIO_METER_RED[] = {1.0, 0.0, 0.0}; + const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH; + const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH; const float CLIPPING_INDICATOR_TIME = 1.0f; + const float AUDIO_METER_AVERAGING = 0.5; const float LOG2 = log(2.f); + const float MAX_LOG2_SAMPLE = 15.f; float audioLevel = 0.f; float loudness = _audio.getLastInputLoudness() + 1.f; - float log2loudness = log(loudness) / LOG2; - if (loudness < 2048) { - audioLevel = (log2loudness / 11.f) * (AUDIO_METER_SCALE_WIDTH / 5.f); - } else { - audioLevel = (log2loudness - 10.f) * (AUDIO_METER_SCALE_WIDTH / 5.f); - } + _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness; + + float log2loudness = log(_trailingAudioLoudness) / LOG2; + + audioLevel = log2loudness / MAX_LOG2_SAMPLE * AUDIO_METER_SCALE_WIDTH; + bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)); + glBegin(GL_QUADS); if (isClipping) { glColor3f(1, 0, 0); } else { glColor3f(0, 0, 0); } - glBegin(GL_QUADS); - // Draw background Quad - glVertex2i(AUDIO_METER_X, AUDIO_METER_Y); - glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, AUDIO_METER_Y); - glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, AUDIO_METER_Y + AUDIO_METER_HEIGHT); - glVertex2i(AUDIO_METER_X, AUDIO_METER_Y + AUDIO_METER_HEIGHT); - - // Draw Meter Quad - if (isClipping) { - glColor3f(1, 1, 1); - } else { - glColor3f(0, 1, 1); + // Draw audio meter background Quad + glVertex2i(AUDIO_METER_X, audioMeterY); + glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY); + glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT); + glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT); + + if (audioLevel > AUDIO_RED_START) { + if (!isClipping) { + glColor3fv(AUDIO_METER_RED); + } else { + glColor3f(1, 1, 1); + } + // Draw Red Quad + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); + audioLevel = AUDIO_RED_START; } - // Draw Meter quad - glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, AUDIO_METER_Y + AUDIO_METER_INSET); - glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, AUDIO_METER_Y + AUDIO_METER_INSET); - glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, AUDIO_METER_Y + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); - glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, AUDIO_METER_Y + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); - + if (audioLevel > AUDIO_GREEN_START) { + if (!isClipping) { + glColor3fv(AUDIO_METER_GREEN); + } else { + glColor3f(1, 1, 1); + } + // Draw Green Quad + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); + audioLevel = AUDIO_GREEN_START; + } + // Draw Blue Quad + if (!isClipping) { + glColor3fv(AUDIO_METER_BLUE); + } else { + glColor3f(1, 1, 1); + } + // Draw Blue (low level) quad + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); + glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); glEnd(); if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 15778f2a17..af77adb8fc 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -397,6 +397,7 @@ private: quint64 _lastQueriedTime; Oscilloscope _audioScope; + float _trailingAudioLoudness; OctreeQuery _octreeQuery; // NodeData derived class for querying voxels from voxel server diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7748c466c7..4d93016d4e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -241,7 +241,7 @@ Menu::Menu() : addDisabledActionAndSeparator(viewMenu, "Stats"); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash); addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails())); From f027aac76baa4b37ea178e864c8c9f5c230f78f2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 31 Mar 2014 17:19:04 -0700 Subject: [PATCH 13/15] Fix to model upload in account manager --- libraries/shared/src/AccountManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index 2fe5007ad1..955ba779d1 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -144,15 +144,15 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: break; case QNetworkAccessManager::PostOperation: case QNetworkAccessManager::PutOperation: - authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); if (dataMultiPart) { if (operation == QNetworkAccessManager::PostOperation) { networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart); - dataMultiPart->setParent(networkReply); } else { networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart); } + dataMultiPart->setParent(networkReply); } else { + authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); if (operation == QNetworkAccessManager::PostOperation) { networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray); } else { From 81d1eb7ed264540d670d23cbca081933fc5a873c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 31 Mar 2014 18:24:58 -0700 Subject: [PATCH 14/15] removed unused procedural movement code --- interface/interface_en.ts | 16 ++++++++-------- interface/src/Application.cpp | 10 ---------- interface/src/Application.h | 1 - interface/src/Audio.cpp | 2 -- interface/src/Audio.h | 7 +------ 5 files changed, 9 insertions(+), 27 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 7c5d1ecbcf..a1abb57b52 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc1a843e47..fa1f4ae0a1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1846,15 +1846,6 @@ void Application::updateDialogs(float deltaTime) { } } -void Application::updateAudio(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateAudio()"); - - // Update audio stats for procedural sounds - _audio.setLastAcceleration(_myAvatar->getThrust()); - _audio.setLastVelocity(_myAvatar->getVelocity()); -} - void Application::updateCursor(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateCursor()"); @@ -1903,7 +1894,6 @@ void Application::update(float deltaTime) { updateMetavoxels(deltaTime); // update metavoxels updateCamera(deltaTime); // handle various camera tweaks like off axis projection updateDialogs(deltaTime); // update various stats dialogs if present - updateAudio(deltaTime); // Update audio stats for procedural sounds updateCursor(deltaTime); // Handle cursor updates _particles.update(); // update the particles... diff --git a/interface/src/Application.h b/interface/src/Application.h index fcf8810378..f638d947d9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -312,7 +312,6 @@ private: void updateMetavoxels(float deltaTime); void updateCamera(float deltaTime); void updateDialogs(float deltaTime); - void updateAudio(float deltaTime); void updateCursor(float deltaTime); Avatar* findLookatTargetAvatar(glm::vec3& eyePosition, QUuid &nodeUUID); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index dc34fb2e2d..312a6c5699 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -67,8 +67,6 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p _noiseGateOpen(false), _noiseGateEnabled(true), _noiseGateFramesToClose(0), - _lastVelocity(0), - _lastAcceleration(0), _totalPacketsReceived(0), _collisionSoundMagnitude(0.0f), _collisionSoundFrequency(0.0f), diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 0ffcb77baf..f98e18eb0b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -51,10 +51,7 @@ public: float getAudioAverageInputLoudness() const { return _lastInputLoudness; } void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; } - - void setLastAcceleration(const glm::vec3 lastAcceleration) { _lastAcceleration = lastAcceleration; } - void setLastVelocity(const glm::vec3 lastVelocity) { _lastVelocity = lastVelocity; } - + void setJitterBufferSamples(int samples) { _jitterBufferSamples = samples; } int getJitterBufferSamples() { return _jitterBufferSamples; } @@ -139,8 +136,6 @@ private: bool _noiseGateOpen; bool _noiseGateEnabled; int _noiseGateFramesToClose; - glm::vec3 _lastVelocity; - glm::vec3 _lastAcceleration; int _totalPacketsReceived; float _collisionSoundMagnitude; From 7d12fcee9db07ca8900619c12b22e817b5e457f3 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 31 Mar 2014 21:55:29 -0700 Subject: [PATCH 15/15] 220Hz tone injection option for easier audio quality checks --- interface/src/Audio.cpp | 24 ++++++++++++++++++++---- interface/src/Audio.h | 3 +++ interface/src/Menu.cpp | 6 ++++++ interface/src/Menu.h | 1 + 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 312a6c5699..9f993e653d 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -66,8 +66,10 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), + _toneInjectionEnabled(false), _noiseGateFramesToClose(0), _totalPacketsReceived(0), + _totalInputAudioSamples(0), _collisionSoundMagnitude(0.0f), _collisionSoundFrequency(0.0f), _collisionSoundNoise(0.0f), @@ -390,7 +392,7 @@ void Audio::handleAudioInput() { inputSamplesRequired, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, _inputFormat, _desiredInputFormat); - + // // Impose Noise Gate // @@ -421,13 +423,15 @@ void Audio::handleAudioInput() { const float DC_OFFSET_AVERAGING = 0.99f; const float CLIPPING_THRESHOLD = 0.90f; + // + // Check clipping, adjust DC offset, and check if should open noise gate + // float measuredDcOffset = 0.f; - // Increment the time since the last clip if (_timeSinceLastClip >= 0.0f) { _timeSinceLastClip += (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE; } - + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { measuredDcOffset += monoAudioSamples[i]; monoAudioSamples[i] -= (int16_t) _dcOffset; @@ -489,6 +493,16 @@ void Audio::handleAudioInput() { _lastInputLoudness = 0; } } + // + // Add tone injection if enabled + // + const float TONE_FREQ = 220.f / SAMPLE_RATE * TWO_PI; + const float QUARTER_VOLUME = 8192.f; + if (_toneInjectionEnabled) { + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { + monoAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample)); + } + } // add input data just written to the scope QMetaObject::invokeMethod(_scope, "addSamples", Qt::QueuedConnection, @@ -683,7 +697,9 @@ void Audio::toggleAudioNoiseReduction() { _noiseGateEnabled = !_noiseGateEnabled; } - +void Audio::toggleToneInjection() { + _toneInjectionEnabled = !_toneInjectionEnabled; +} // Take a pointer to the acquired microphone input samples and add procedural sounds void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index f98e18eb0b..170572a4d7 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -81,6 +81,7 @@ public slots: void reset(); void toggleMute(); void toggleAudioNoiseReduction(); + void toggleToneInjection(); virtual void handleAudioByteArray(const QByteArray& audioByteArray); @@ -135,8 +136,10 @@ private: int _noiseGateSampleCounter; bool _noiseGateOpen; bool _noiseGateEnabled; + bool _toneInjectionEnabled; int _noiseGateFramesToClose; int _totalPacketsReceived; + int _totalInputAudioSamples; float _collisionSoundMagnitude; float _collisionSoundFrequency; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4d93016d4e..122d4c5654 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -360,6 +360,12 @@ Menu::Menu() : false, appInstance->getAudio(), SLOT(toggleMute())); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioToneInjection, + 0, + false, + appInstance->getAudio(), + SLOT(toggleToneInjection())); + addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel, Qt::CTRL | Qt::SHIFT | Qt::Key_V, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c7c4c6ecea..206593ce80 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -242,6 +242,7 @@ namespace MenuOption { const QString FilterSixense = "Smooth Sixense Movement"; const QString Enable3DTVMode = "Enable 3DTV Mode"; const QString AudioNoiseReduction = "Audio Noise Reduction"; + const QString AudioToneInjection = "Inject Test Tone"; const QString EchoServerAudio = "Echo Server Audio"; const QString EchoLocalAudio = "Echo Local Audio"; const QString MuteAudio = "Mute Microphone";