diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 28fa4f68a3..90070c44bc 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;