diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f60fe9a5f8..017fb3bade 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1877,7 +1877,7 @@ void Application::initMenu() { QMenu* optionsMenu = menuBar->addMenu("Options"); (_lookingInMirror = optionsMenu->addAction("Mirror", this, SLOT(setRenderMirrored(bool)), Qt::Key_H))->setCheckable(true); - (_echoAudioMode = optionsMenu->addAction("Echo Audio"))->setCheckable(true); + (_noise = optionsMenu->addAction("Noise", this, SLOT(setNoise(bool)), Qt::Key_N))->setCheckable(true); (_gyroLook = optionsMenu->addAction("Smooth Gyro Look"))->setCheckable(true); @@ -1897,6 +1897,10 @@ void Application::initMenu() { optionsMenu->addAction("Cycle Webcam Send Mode", _webcam.getGrabber(), SLOT(cycleVideoSendMode())); optionsMenu->addAction("Go Home", this, SLOT(goHome()), Qt::CTRL | Qt::Key_G); + QMenu* audioMenu = menuBar->addMenu("Audio"); + (_echoAudioMode = audioMenu->addAction("Echo Audio"))->setCheckable(true); + _rawAudioMicrophoneMix = audioMenu->addAction("Mix RAW Song", this, SLOT(toggleMixedSong())); + QMenu* renderMenu = menuBar->addMenu("Render"); (_renderVoxels = renderMenu->addAction("Voxels", this, SLOT(setRenderVoxels(bool)), Qt::SHIFT | Qt::Key_V))->setCheckable(true); _renderVoxels->setChecked(true); @@ -2066,6 +2070,22 @@ void Application::setListenModeSingleSource() { } } +void Application::toggleMixedSong() { + if (_audio.getSongFileBytes() == 0) { + QString filename = QFileDialog::getOpenFileName(_glWidget, + tr("Choose RAW Audio file"), + QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), + tr("RAW Audio file (*.raw)")); + + QByteArray filenameArray = filename.toLocal8Bit(); + _audio.importSongToMixWithMicrophone(filenameArray.data()); + _rawAudioMicrophoneMix->setText("Stop Mixing Song"); + } else { + _audio.stopMixingSongWithMicrophone(); + _rawAudioMicrophoneMix->setText("Mix RAW Song"); + } +} + void Application::updateFrustumRenderModeAction() { switch (_frustumDrawingMode) { diff --git a/interface/src/Application.h b/interface/src/Application.h index c51665710a..4745196bf4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -177,6 +177,7 @@ private slots: void setListenModeNormal(); void setListenModePoint(); void setListenModeSingleSource(); + void toggleMixedSong(); void renderCoverageMap(); @@ -288,6 +289,7 @@ private: QAction* _fullScreenMode; // whether we are in full screen mode QAction* _frustumRenderModeAction; QAction* _settingsAutosave; // Whether settings are saved automatically + QAction* _rawAudioMicrophoneMix; // Mixing of a RAW audio file with microphone stream for rave gloves QAction* _noise; QAction* _occlusionCulling; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index a9aa61a34e..c1466d5571 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -8,13 +8,11 @@ #ifndef _WIN32 #include -#include #include #include #include - #include #include #include @@ -155,8 +153,38 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); currentPacketPtr += sizeof(headOrientation); + // check if we have a song to add to our audio + if (_songFileBytes > 0 && _songFileStream->tellg() <= _songFileBytes) { + // iterate over BUFFER_LENGTH_SAMPLES_PER_CHANNEL from the song file and add that to our audio + for (int i = 0; i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { + int16_t songSample = 0; + + _songFileStream->read((char*) &songSample, sizeof(songSample)); + + // attenuate the song samples since they will be loud + const float SONG_SAMPLE_ATTENUATION = 0.25; + songSample *= SONG_SAMPLE_ATTENUATION; + + // add the song sample to the output and input buffersg + inputLeft[i] = inputLeft[i] + songSample; + outputLeft[i] = outputLeft[i] + songSample; + outputRight[i] = outputLeft[i] + songSample; + } + } else if (_songFileStream) { + // close the stream + _songFileStream->close(); + + // delete the _songFileStream + delete _songFileStream; + _songFileStream = NULL; + + // reset the _songFileBytes back to zero + _songFileBytes = 0; + } + // copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL); + nodeList->getNodeSocket()->send((sockaddr*) &audioSocket, dataPacket, BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); @@ -385,7 +413,9 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _proceduralEffectSample(0), _heartbeatMagnitude(0.0f), _listenMode(AudioRingBuffer::NORMAL), - _listenRadius(0.0f) + _listenRadius(0.0f), + _songFileStream(NULL), + _songFileBytes(0) { outputPortAudioError(Pa_Initialize()); @@ -456,6 +486,25 @@ Audio::~Audio() { delete[] _echoSamplesLeft; } + +void Audio::importSongToMixWithMicrophone(const char* filename) { + _songFileStream = new std::ifstream(filename); + + long begin = _songFileStream->tellg(); + _songFileStream->seekg(0, std::ios::end); + long end = _songFileStream->tellg(); + + // go back to the beginning + _songFileStream->seekg(0); + + _songFileBytes = end - begin; +} + +void Audio::stopMixingSongWithMicrophone() { + qDebug("Stop mixing called!"); + _songFileBytes = 0; +} + void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBytes) { const int NUM_INITIAL_PACKETS_DISCARD = 3; const int STANDARD_DEVIATION_SAMPLE_COUNT = 500; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 2eb4e7ef70..249453c877 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -9,8 +9,13 @@ #ifndef __interface__Audio__ #define __interface__Audio__ +#include #include + +#include + #include + #include #include @@ -23,7 +28,8 @@ static const int PACKET_LENGTH_BYTES_PER_CHANNEL = PACKET_LENGTH_BYTES / 2; static const int PACKET_LENGTH_SAMPLES = PACKET_LENGTH_BYTES / sizeof(int16_t); static const int PACKET_LENGTH_SAMPLES_PER_CHANNEL = PACKET_LENGTH_SAMPLES / 2; -class Audio { +class Audio : public QObject { + Q_OBJECT public: // initializes audio I/O Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples); @@ -47,6 +53,7 @@ public: void startCollisionSound(float magnitude, float frequency, float noise, float duration); float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; }; + int getSongFileBytes() { return _songFileBytes; } void ping(); @@ -60,8 +67,13 @@ public: void addListenSource(int sourceID); void removeListenSource(int sourceID); void clearListenSources(); + + void importSongToMixWithMicrophone(const char* filename); + +public slots: + void stopMixingSongWithMicrophone(); -private: +private: PaStream* _stream; AudioRingBuffer _ringBuffer; Oscilloscope* _scope; @@ -96,6 +108,8 @@ private: float _collisionSoundDuration; int _proceduralEffectSample; float _heartbeatMagnitude; + std::ifstream* _songFileStream; + int _songFileBytes; AudioRingBuffer::ListenMode _listenMode; float _listenRadius; diff --git a/libraries/voxels/src/JurisdictionMap.cpp b/libraries/voxels/src/JurisdictionMap.cpp index b67963d8d6..f67bbbabf7 100644 --- a/libraries/voxels/src/JurisdictionMap.cpp +++ b/libraries/voxels/src/JurisdictionMap.cpp @@ -44,12 +44,28 @@ JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(NULL) { readFromFile(filename); } - JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector& endNodes) : _rootOctalCode(NULL) { init(rootOctalCode, endNodes); } +JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) { + _rootOctalCode = hexStringToOctalCode(QString(rootHexCode)); + + QString endNodesHexStrings(endNodesHexCodes); + QString delimiterPattern(","); + QStringList endNodeList = endNodesHexStrings.split(delimiterPattern); + + for (int i = 0; i < endNodeList.size(); i++) { + QString endNodeHexString = endNodeList.at(i); + + unsigned char* endNodeOctcode = hexStringToOctalCode(endNodeHexString); + //printOctalCode(endNodeOctcode); + _endNodes.push_back(endNodeOctcode); + } +} + + void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector& endNodes) { clear(); // clean up our own memory _rootOctalCode = rootOctalCode; diff --git a/libraries/voxels/src/JurisdictionMap.h b/libraries/voxels/src/JurisdictionMap.h index a52765549f..6c7cc4f0ca 100644 --- a/libraries/voxels/src/JurisdictionMap.h +++ b/libraries/voxels/src/JurisdictionMap.h @@ -23,6 +23,7 @@ public: JurisdictionMap(); JurisdictionMap(const char* filename); JurisdictionMap(unsigned char* rootOctalCode, const std::vector& endNodes); + JurisdictionMap(const char* rootHextString, const char* endNodesHextString); ~JurisdictionMap(); Area isMyJurisdiction(unsigned char* nodeOctalCode, int childIndex) const; diff --git a/voxel-server/src/README b/voxel-server/src/README index 81824d96a9..76ed051679 100644 --- a/voxel-server/src/README +++ b/voxel-server/src/README @@ -15,6 +15,12 @@ OPTIONS --local This will run the voxel server in "local domain mode" and will look for a domain-server running on the same IP address as the voxel server + + --jurisdictionRoot [hex string of root octcode] + Tells the server to honor jurisdiction from the specified root node and below + + --jurisdictionEndNodes [(<,octcode>...)] + Tells the server to honor jurisdiction from the root down to the octcodes included in the comma separated list --jurisdictionFile [filename] Tells the server to load it's jurisdiction from the specified file. When a voxel server is running with a limited diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 329e8d803c..5d7489135a 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -456,11 +456,22 @@ int main(int argc, const char * argv[]) { printf("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); jurisdiction = new JurisdictionMap(jurisdictionFile); printf("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); + } else { + const char* JURISDICTION_ROOT = "--jurisdictionRoot"; + const char* jurisdictionRoot = getCmdOption(argc, argv, JURISDICTION_ROOT); + if (jurisdictionRoot) { + printf("jurisdictionRoot=%s\n", jurisdictionRoot); + } - // test writing the file... - printf("about to writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); - jurisdiction->writeToFile(jurisdictionFile); - printf("after writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); + const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes"; + const char* jurisdictionEndNodes = getCmdOption(argc, argv, JURISDICTION_ENDNODES); + if (jurisdictionEndNodes) { + printf("jurisdictionEndNodes=%s\n", jurisdictionEndNodes); + } + + if (jurisdictionRoot || jurisdictionEndNodes) { + jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes); + } } NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, listenPort);