From e5be49243101e357bf1216169427824ccd0de21e Mon Sep 17 00:00:00 2001 From: Raidho Date: Wed, 19 Oct 2016 02:33:03 +0000 Subject: [PATCH 1/9] Created new branch minor-mic-input --HG-- branch : minor-mic-input From 87f0b2811efa8577cafeeb7a34be8a557b8adfd1 Mon Sep 17 00:00:00 2001 From: Raidho Date: Sun, 23 Oct 2016 17:56:52 +0300 Subject: [PATCH 2/9] Microphone input implemented. RecordingDevice class added (number)love.audio.getRecordingDeviceCount() and (table)love.audio.getRecordingDevices() exposed (bool):startRecording([samples, sampleRate, bitDepth, channels], (SoundData):stopRecording([SoundData]), (SoundData):getData([SoundData]), (number):getSampleCount(), (number):getSampleRate(), (number):getBitDepth(), (number):getChannels(), (string):getName(), (number):getID(), (bool):isRecording() member functions exposed previously existed stub implementation removed getFormat moved to love::audio::openal::Audio getFormat arguments order swapped to (bitDepth, channels) getFormat now returns AL_NONE if format is invalid --HG-- branch : minor-mic-input --- CMakeLists.txt | 8 + src/common/types.cpp | 1 + src/common/types.h | 1 + src/modules/audio/Audio.h | 29 +-- src/modules/audio/RecordingDevice.cpp | 37 ++++ src/modules/audio/RecordingDevice.h | 107 ++++++++++ src/modules/audio/null/Audio.cpp | 16 +- src/modules/audio/null/Audio.h | 8 +- src/modules/audio/null/RecordingDevice.cpp | 97 +++++++++ src/modules/audio/null/RecordingDevice.h | 59 ++++++ src/modules/audio/openal/Audio.cpp | 125 ++++++------ src/modules/audio/openal/Audio.h | 21 +- src/modules/audio/openal/RecordingDevice.cpp | 156 ++++++++++++++ src/modules/audio/openal/RecordingDevice.h | 78 +++++++ src/modules/audio/openal/Source.cpp | 47 +---- src/modules/audio/openal/Source.h | 9 - src/modules/audio/wrap_Audio.cpp | 70 +++---- src/modules/audio/wrap_Audio.h | 1 + src/modules/audio/wrap_RecordingDevice.cpp | 201 +++++++++++++++++++ src/modules/audio/wrap_RecordingDevice.h | 40 ++++ src/modules/sound/SoundData.h | 3 +- 21 files changed, 922 insertions(+), 192 deletions(-) create mode 100644 src/modules/audio/RecordingDevice.cpp create mode 100644 src/modules/audio/RecordingDevice.h create mode 100644 src/modules/audio/null/RecordingDevice.cpp create mode 100644 src/modules/audio/null/RecordingDevice.h create mode 100644 src/modules/audio/openal/RecordingDevice.cpp create mode 100644 src/modules/audio/openal/RecordingDevice.h create mode 100644 src/modules/audio/wrap_RecordingDevice.cpp create mode 100644 src/modules/audio/wrap_RecordingDevice.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a74fd7056..27fc045bf 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,10 +312,14 @@ set(LOVE_SRC_MODULE_AUDIO_ROOT src/modules/audio/Audio.h src/modules/audio/Source.cpp src/modules/audio/Source.h + src/modules/audio/RecordingDevice.cpp + src/modules/audio/RecordingDevice.h src/modules/audio/wrap_Audio.cpp src/modules/audio/wrap_Audio.h src/modules/audio/wrap_Source.cpp src/modules/audio/wrap_Source.h + src/modules/audio/wrap_RecordingDevice.cpp + src/modules/audio/wrap_RecordingDevice.h ) set(LOVE_SRC_MODULE_AUDIO_NULL @@ -323,6 +327,8 @@ set(LOVE_SRC_MODULE_AUDIO_NULL src/modules/audio/null/Audio.h src/modules/audio/null/Source.cpp src/modules/audio/null/Source.h + src/modules/audio/null/RecordingDevice.cpp + src/modules/audio/null/RecordingDevice.h ) set(LOVE_SRC_MODULE_AUDIO_OPENAL @@ -332,6 +338,8 @@ set(LOVE_SRC_MODULE_AUDIO_OPENAL src/modules/audio/openal/Pool.h src/modules/audio/openal/Source.cpp src/modules/audio/openal/Source.h + src/modules/audio/openal/RecordingDevice.cpp + src/modules/audio/openal/RecordingDevice.h ) set(LOVE_SRC_MODULE_AUDIO diff --git a/src/common/types.cpp b/src/common/types.cpp index 4bb44ecce..2385315c9 100644 --- a/src/common/types.cpp +++ b/src/common/types.cpp @@ -72,6 +72,7 @@ static const TypeBits *createTypeFlags() // Audio. b[AUDIO_SOURCE_ID] = (one << AUDIO_SOURCE_ID) | b[OBJECT_ID]; + b[AUDIO_RECORDING_DEVICE_ID] = (one << AUDIO_RECORDING_DEVICE_ID) | b[OBJECT_ID]; // Sound. b[SOUND_SOUND_DATA_ID] = (one << SOUND_SOUND_DATA_ID) | b[DATA_ID]; diff --git a/src/common/types.h b/src/common/types.h index a18191947..7b7d1e1ee 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -73,6 +73,7 @@ enum Type // Audio AUDIO_SOURCE_ID, + AUDIO_RECORDING_DEVICE_ID, // Sound SOUND_SOUND_DATA_ID, diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index 0a114a8ad..9a0d43aba 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -28,6 +28,7 @@ #include "common/Module.h" #include "common/StringMap.h" #include "Source.h" +#include "RecordingDevice.h" namespace love { @@ -189,34 +190,20 @@ public: virtual float getDopplerScale() const = 0; /** - * Begins recording audio input from the microphone. + * @return Number of recording devices. **/ - virtual void record() = 0; + virtual int getRecordingDeviceCount() const = 0; /** - * Gets a section of recorded audio. - * Per OpenAL, the measurement begins from the start of the - * audio data in memory, which is after the last time this function - * was called. If this function has not been called yet this recording - * session, it just grabs from the beginning. - * @return All the recorded SoundData thus far. + * @param index Index number of recording device. 0 is default device. + * @return Selected recording device. **/ - virtual love::sound::SoundData *getRecordedData() = 0; + virtual RecordingDevice *getRecordingDevice(int index) const = 0; /** - * Stops recording and, if passed true, returns all the recorded audio - * not already gotten by getRecordedData. - * @param returnData Whether to return recorded audio. - * @return if returnData, all the recorded audio yet to be gotten, - * otherwise NULL. + * @return Index number of a recording device, -1 if not present. **/ - virtual love::sound::SoundData *stopRecording(bool returnData) = 0; - - /** - * Checks whether LOVE is able to record audio input. - * @return hasMic Whether LOVE has a microphone enabled. - **/ - virtual bool canRecord() = 0; + virtual int getRecordingDeviceIndex(RecordingDevice *device) const = 0; /** * Gets the distance model used for attenuation. diff --git a/src/modules/audio/RecordingDevice.cpp b/src/modules/audio/RecordingDevice.cpp new file mode 100644 index 000000000..f03470218 --- /dev/null +++ b/src/modules/audio/RecordingDevice.cpp @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "RecordingDevice.h" + +namespace love +{ +namespace audio +{ + +RecordingDevice::RecordingDevice() +{ +} + +RecordingDevice::~RecordingDevice() +{ +} + +} //audio +} //love diff --git a/src/modules/audio/RecordingDevice.h b/src/modules/audio/RecordingDevice.h new file mode 100644 index 000000000..ac2d9150c --- /dev/null +++ b/src/modules/audio/RecordingDevice.h @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented = 0; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_AUDIO_RECORDING_DEVICE_H +#define LOVE_AUDIO_RECORDING_DEVICE_H + +#include "common/Object.h" +#include "sound/SoundData.h" + +#include + +namespace love +{ +namespace audio +{ + +class RecordingDevice : public love::Object +{ +public: + RecordingDevice(); + virtual ~RecordingDevice(); + + /** + * Begins audio input recording process. using default (previous) parameters. + * @return True if recording started successfully. + **/ + virtual bool startRecording() = 0; + + /** + * Begins audio input recording process. + * @param samples Number of samples to buffer. + * @param sampleRate Desired sample rate. + * @param bitDepth Desired bit depth (8 or 16). + * @param channels Desired number of channels. + * @return True if recording started successfully. + **/ + virtual bool startRecording(int samples, int sampleRate, int bitDepth, int channels) = 0; + + /** + * Stops audio input recording. + **/ + virtual void stopRecording() = 0; + + /** + * Retreives recorded data. + * @param soundData Reference to a SoundData to fill. + * @return number of samples obtained from device. + **/ + virtual int getData(love::sound::SoundData *soundData) = 0; + + /** + * @return C string device name. + **/ + virtual const char *getName() const = 0; + + /** + * @return Unique ID number. + **/ + virtual int getID() const = 0; + + /** + * @return Number of samples currently recorded. + **/ + virtual int getSampleCount() const = 0; + + /** + * @return Sample rate for recording. + **/ + virtual int getSampleRate() const = 0; + + /** + * @return Bit depth for recording. + **/ + virtual int getBitDepth() const = 0; + + /** + * @return Number of channels for recording. + **/ + virtual int getChannels() const = 0; + + /** + * @return True if currently recording. + **/ + virtual bool isRecording() const = 0; +}; //RecordingDevice + +} //audio +} //love + +#endif //LOVE_AUDIO_RECORDING_DEVICE_H diff --git a/src/modules/audio/null/Audio.cpp b/src/modules/audio/null/Audio.cpp index b2a0ffe4a..85d48c629 100644 --- a/src/modules/audio/null/Audio.cpp +++ b/src/modules/audio/null/Audio.cpp @@ -144,23 +144,19 @@ float Audio::getDopplerScale() const return 1.0f; } -void Audio::record() +int Audio::getRecordingDeviceCount() const { + return 0; } -love::sound::SoundData *Audio::getRecordedData() +love::audio::RecordingDevice *Audio::getRecordingDevice(int index) const { - return NULL; + return nullptr; } -love::sound::SoundData *Audio::stopRecording(bool) +int Audio::getRecordingDeviceIndex(love::audio::RecordingDevice *device) const { - return NULL; -} - -bool Audio::canRecord() -{ - return false; + return -1; } Audio::DistanceModel Audio::getDistanceModel() const diff --git a/src/modules/audio/null/Audio.h b/src/modules/audio/null/Audio.h index e4143d447..a2c82e031 100644 --- a/src/modules/audio/null/Audio.h +++ b/src/modules/audio/null/Audio.h @@ -24,6 +24,7 @@ // LOVE #include "audio/Audio.h" +#include "RecordingDevice.h" #include "Source.h" namespace love @@ -70,10 +71,9 @@ public: void setDopplerScale(float scale); float getDopplerScale() const; - void record(); - love::sound::SoundData *getRecordedData(); - love::sound::SoundData *stopRecording(bool returnData); - bool canRecord(); + int getRecordingDeviceCount() const; + love::audio::RecordingDevice *getRecordingDevice(int index) const; + int getRecordingDeviceIndex(love::audio::RecordingDevice *device) const; DistanceModel getDistanceModel() const; void setDistanceModel(DistanceModel distanceModel); diff --git a/src/modules/audio/null/RecordingDevice.cpp b/src/modules/audio/null/RecordingDevice.cpp new file mode 100644 index 000000000..9e62b4168 --- /dev/null +++ b/src/modules/audio/null/RecordingDevice.cpp @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented = 0; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "RecordingDevice.h" +#include "Audio.h" + +namespace love +{ +namespace audio +{ +namespace null +{ + +const char *RecordingDevice::name = "null"; + +RecordingDevice::RecordingDevice(const char *, int) +{ +} + +RecordingDevice::~RecordingDevice() +{ +} + +bool RecordingDevice::startRecording() +{ + return false; +} + +bool RecordingDevice::startRecording(int, int, int, int) +{ + return false; +} + +void RecordingDevice::stopRecording() +{ +} + +int RecordingDevice::getData(love::sound::SoundData*) +{ + return 0; +} + +int RecordingDevice::getSampleCount() const +{ + return 0; +} + +int RecordingDevice::getSampleRate() const +{ + return 8000; +} + +int RecordingDevice::getBitDepth() const +{ + return 16; +} + +int RecordingDevice::getChannels() const +{ + return 1; +} + +const char *RecordingDevice::getName() const +{ + return name; +} + +int RecordingDevice::getID() const +{ + return 0; +} + +bool RecordingDevice::isRecording() const +{ + return false; +} + +} //null +} //audio +} //love diff --git a/src/modules/audio/null/RecordingDevice.h b/src/modules/audio/null/RecordingDevice.h new file mode 100644 index 000000000..8fcb1bdad --- /dev/null +++ b/src/modules/audio/null/RecordingDevice.h @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented = 0; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_AUDIO_NULL_RECORDING_DEVICE_H +#define LOVE_AUDIO_NULL_RECORDING_DEVICE_H + +#include "audio/RecordingDevice.h" +#include "sound/SoundData.h" + +namespace love +{ +namespace audio +{ +namespace null +{ + +class RecordingDevice : public love::audio::RecordingDevice +{ +public: + RecordingDevice(const char *name, int id); + virtual ~RecordingDevice(); + virtual bool startRecording(); + virtual bool startRecording(int samples, int sampleRate, int bitDepth, int channels); + virtual void stopRecording(); + virtual int getData(love::sound::SoundData *soundData); + virtual const char *getName() const; + virtual int getID() const; + virtual int getSampleCount() const; + virtual int getSampleRate() const; + virtual int getBitDepth() const; + virtual int getChannels() const; + virtual bool isRecording() const; + +private: + static const char *name; +}; //RecordingDevice + +} //null +} //audio +} //love + +#endif //LOVE_AUDIO_NULL_RECORDING_DEVICE_H diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index c3b1bd05e..cb9b45f09 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -20,10 +20,11 @@ #include "Audio.h" #include "common/delay.h" - +#include "RecordingDevice.h" #include "sound/Decoder.h" #include +#include namespace love { @@ -67,9 +68,29 @@ void Audio::PoolThread::setFinish() finish = true; } +ALenum Audio::getFormat(int bitDepth, int channels) +{ + if (bitDepth != 8 && bitDepth != 16) + return AL_NONE; + + if (channels == 1) + return bitDepth == 8 ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16; + else if (channels == 2) + return bitDepth == 8 ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16; + #ifdef AL_EXT_MCFORMATS + else if (alIsExtensionPresent("AL_EXT_MCFORMATS")) + { + if (channels == 6) + return bitDepth == 8 ? AL_FORMAT_51CHN8 : AL_FORMAT_51CHN16; + else if (channels == 8) + return bitDepth == 8 ? AL_FORMAT_71CHN8 : AL_FORMAT_71CHN16; + } + #endif + return AL_NONE; +} + Audio::Audio() : device(nullptr) - , capture(nullptr) , context(nullptr) , pool(nullptr) , poolThread(nullptr) @@ -89,25 +110,28 @@ Audio::Audio() if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR) throw love::Exception("Could not make context current."); - /*std::string captureName(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); - const ALCchar * devices = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); - while (*devices) + //find and push default capture device + //AL may not return actual device name string when asked directly + std::string defaultname; + ALCdevice *defaultdevice = alcCaptureOpenDevice(NULL, 8000, 8, 1); + if (alGetError() == AL_NO_ERROR) { - std::string device(devices); - devices += device.size() + 1; - if (device.find("Mic") != std::string::npos || device.find("mic") != std::string::npos) - { - captureName = device; - } + defaultname = alcGetString(defaultdevice, ALC_CAPTURE_DEVICE_SPECIFIER); + alcCaptureCloseDevice(defaultdevice); + capture.push_back(new RecordingDevice(defaultname.c_str(), 0)); } - capture = alcCaptureOpenDevice(captureName.c_str(), 8000, AL_FORMAT_MONO16, 262144); // about 32 seconds - - if (!capture) + const ALCchar *devstr = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + size_t offset = 0; + while (true) { - // We're not going to prevent LOVE from running without a microphone, but we should warn, at least - std::cerr << "Warning, couldn't open capture device! No audio input!" << std::endl; - }*/ + if (devstr[offset] == '\0') + break; + std::string str((ALCchar*)&devstr[offset]); + if (str != defaultname) + capture.push_back(new RecordingDevice(str.c_str(), capture.size())); + offset += str.length() + 1; + } // pool must be allocated after AL context. try @@ -118,8 +142,10 @@ Audio::Audio() { alcMakeContextCurrent(nullptr); alcDestroyContext(context); - //if (capture) alcCaptureCloseDevice(capture); alcCloseDevice(device); + for (unsigned int i = 0; i < capture.size(); i++) + delete capture[i]; + throw; } @@ -137,8 +163,9 @@ Audio::~Audio() alcMakeContextCurrent(nullptr); alcDestroyContext(context); - //if (capture) alcCaptureCloseDevice(capture); alcCloseDevice(device); + for (unsigned int i = 0; i < capture.size(); i++) + delete capture[i]; } @@ -265,44 +292,6 @@ float Audio::getDopplerScale() const return alGetFloat(AL_DOPPLER_FACTOR); } -void Audio::record() -{ - if (!canRecord()) return; - alcCaptureStart(capture); -} - -love::sound::SoundData *Audio::getRecordedData() -{ - if (!canRecord()) - return NULL; - int samplerate = 8000; - ALCint samples; - alcGetIntegerv(capture, ALC_CAPTURE_SAMPLES, 4, &samples); - void *data = malloc(samples * (2/sizeof(char))); - alcCaptureSamples(capture, data, samples); - love::sound::SoundData *sd = new love::sound::SoundData(data, samples, samplerate, 16, 1); - free(data); - return sd; -} - -love::sound::SoundData *Audio::stopRecording(bool returnData) -{ - if (!canRecord()) - return NULL; - love::sound::SoundData *sd = NULL; - if (returnData) - { - sd = getRecordedData(); - } - alcCaptureStop(capture); - return sd; -} - -bool Audio::canRecord() -{ - return (capture != NULL); -} - Audio::DistanceModel Audio::getDistanceModel() const { return distanceModel; @@ -347,6 +336,28 @@ void Audio::setDistanceModel(DistanceModel distanceModel) } } +int Audio::getRecordingDeviceCount() const +{ + return capture.size(); +} + +love::audio::RecordingDevice *Audio::getRecordingDevice(int index) const +{ + if (index < 0 || (unsigned int)index >= capture.size()) + return nullptr; + + return capture[index]; +} + +int Audio::getRecordingDeviceIndex(love::audio::RecordingDevice *device) const +{ + for (unsigned int i = 0; i < capture.size(); i++) + if (device == capture[i]) + return i; + + return -1; +} + } // openal } // audio } // love diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index b676abf8c..846e0e54c 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -29,6 +29,7 @@ // LOVE #include "audio/Audio.h" +#include "audio/RecordingDevice.h" #include "common/config.h" #include "sound/SoundData.h" @@ -65,6 +66,15 @@ public: Audio(); ~Audio(); + /** + * Gets the OpenAL format identifier based on number of + * channels and bits. + * @param channels. + * @param bitDepth Either 8-bit samples, or 16-bit samples. + * @return One of AL_FORMAT_*, or AL_NONE if unsupported format. + **/ + static ALenum getFormat(int bitDepth, int channels); + // Implements Module. const char *getName() const; @@ -95,10 +105,9 @@ public: void setDopplerScale(float scale); float getDopplerScale() const; - void record(); - love::sound::SoundData *getRecordedData(); - love::sound::SoundData *stopRecording(bool returnData); - bool canRecord(); + int getRecordingDeviceCount() const; + love::audio::RecordingDevice *getRecordingDevice(int index) const; + int getRecordingDeviceIndex(love::audio::RecordingDevice *device) const; DistanceModel getDistanceModel() const; void setDistanceModel(DistanceModel distanceModel); @@ -108,8 +117,8 @@ private: // The OpenAL device. ALCdevice *device; - // The OpenAL capture device (microphone). - ALCdevice *capture; + // The OpenAL capture devices. + std::vector capture; // The OpenAL context. ALCcontext *context; diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp new file mode 100644 index 000000000..afe06ef69 --- /dev/null +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -0,0 +1,156 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented = 0; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "RecordingDevice.h" +#include "Audio.h" + +namespace love +{ +namespace audio +{ +namespace openal +{ + +class InvalidFormatException : public love::Exception +{ +public: + + InvalidFormatException(int channels, int bitdepth) + : Exception("Recording %d channels with %d bits per sample is not supported.", channels, bitdepth) + { + } + +}; + +RecordingDevice::RecordingDevice(const char *name, int id) + : name(name) + , id(id) +{ +} + +RecordingDevice::~RecordingDevice() +{ + if (!isRecording()) + return; + + alcCaptureStop(device); + alcCaptureCloseDevice(device); +} + +bool RecordingDevice::startRecording() +{ + return startRecording(samples, sampleRate, bitDepth, channels); +} + +bool RecordingDevice::startRecording(int samples, int sampleRate, int bitDepth, int channels) +{ + if (isRecording()) + { + alcCaptureStop(device); + alcCaptureCloseDevice(device); + } + + ALenum format = Audio::getFormat(bitDepth, channels); + if (format == AL_NONE) + throw InvalidFormatException(channels, bitDepth); + + device = alcCaptureOpenDevice(name.c_str(), sampleRate, format, samples); + if (device == nullptr) + return false; + + alcCaptureStart(device); + this->samples = samples; + this->sampleRate = sampleRate; + this->bitDepth = bitDepth; + this->channels = channels; + return true; +} + +void RecordingDevice::stopRecording() +{ + if (!isRecording()) + return; + + alcCaptureStop(device); + alcCaptureCloseDevice(device); + device = nullptr; +} + +int RecordingDevice::getData(love::sound::SoundData *soundData) +{ + if (!isRecording()) + return 0; + + int samples = getSampleCount(); + if (samples == 0) + return 0; + + //resize internal buffer to proper size + if (samples != soundData->getSampleCount()) + soundData->load(samples, sampleRate, bitDepth, channels); + + alcCaptureSamples(device, soundData->getData(), samples); + + return samples; +} + +int RecordingDevice::getSampleCount() const +{ + if (!isRecording()) + return 0; + + ALCint samples; + alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, sizeof(ALCint), &samples); + return (int)samples; +} + +int RecordingDevice::getSampleRate() const +{ + return sampleRate; +} + +int RecordingDevice::getBitDepth() const +{ + return bitDepth; +} + +int RecordingDevice::getChannels() const +{ + return channels; +} + +const char *RecordingDevice::getName() const +{ + return name.c_str(); +} + +int RecordingDevice::getID() const +{ + return id; +} + +bool RecordingDevice::isRecording() const +{ + return device == nullptr ? false : true; +} + +} //openal +} //audio +} //love diff --git a/src/modules/audio/openal/RecordingDevice.h b/src/modules/audio/openal/RecordingDevice.h new file mode 100644 index 000000000..3e4ae14ca --- /dev/null +++ b/src/modules/audio/openal/RecordingDevice.h @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented = 0; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_AUDIO_OPENAL_RECORDING_DEVICE_H +#define LOVE_AUDIO_OPENAL_RECORDING_DEVICE_H + +#ifdef LOVE_APPLE_USE_FRAMEWORKS +#ifdef LOVE_IOS +#include +#include +#else +#include +#include +#endif +#else +#include +#include +#endif + +#include "audio/RecordingDevice.h" +#include "sound/SoundData.h" + +namespace love +{ +namespace audio +{ +namespace openal +{ + +class RecordingDevice : public love::audio::RecordingDevice +{ +public: + RecordingDevice(const char *name, int id); + virtual ~RecordingDevice(); + virtual bool startRecording(); + virtual bool startRecording(int samples, int sampleRate, int bitDepth, int channels); + virtual void stopRecording(); + virtual int getData(love::sound::SoundData *soundData); + virtual const char *getName() const; + virtual int getID() const; + virtual int getSampleCount() const; + virtual int getSampleRate() const; + virtual int getBitDepth() const; + virtual int getChannels() const; + virtual bool isRecording() const; + +private: + int samples = 8192; + int sampleRate = 8000; + int bitDepth = 16; + int channels = 1; + std::string name; + int id; + ALCdevice *device = nullptr; +}; //RecordingDevice + +} //openal +} //audio +} //love + +#endif //LOVE_AUDIO_OPENAL_RECORDING_DEVICE_H diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index 47169c583..8c981489d 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -20,6 +20,7 @@ #include "Source.h" #include "Pool.h" +#include "Audio.h" #include "common/math.h" // STD @@ -119,8 +120,8 @@ Source::Source(Pool *pool, love::sound::SoundData *soundData) , channels(soundData->getChannels()) , bitDepth(soundData->getBitDepth()) { - ALenum fmt = getFormat(soundData->getChannels(), soundData->getBitDepth()); - if (fmt == 0) + ALenum fmt = Audio::getFormat(soundData->getBitDepth(), soundData->getChannels()); + if (fmt == AL_NONE) throw InvalidFormatException(soundData->getChannels(), soundData->getBitDepth()); staticBuffer.set(new StaticDataBuffer(fmt, soundData->getData(), (ALsizei) soundData->getSize(), sampleRate), Acquire::NORETAIN); @@ -141,7 +142,7 @@ Source::Source(Pool *pool, love::sound::Decoder *decoder) , decoder(decoder) , unusedBufferTop(MAX_BUFFERS - 1) { - if (getFormat(decoder->getChannels(), decoder->getBitDepth()) == 0) + if (Audio::getFormat(decoder->getBitDepth(), decoder->getChannels()) == AL_NONE) throw InvalidFormatException(decoder->getChannels(), decoder->getBitDepth()); alGenBuffers(MAX_BUFFERS, streamBuffers); @@ -162,8 +163,8 @@ Source::Source(Pool *pool, int sampleRate, int bitDepth, int channels) , channels(channels) , bitDepth(bitDepth) { - ALenum fmt = getFormat(channels, bitDepth); - if (fmt == 0) + ALenum fmt = Audio::getFormat(bitDepth, channels); + if (fmt == AL_NONE) throw InvalidFormatException(channels, bitDepth); alGenBuffers(MAX_BUFFERS, streamBuffers); @@ -688,7 +689,7 @@ bool Source::queueAtomic(void *data, ALsizei length) if (buffer == AL_NONE) return false; - alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate); + alBufferData(buffer, Audio::getFormat(bitDepth, channels), data, length, sampleRate); alSourceQueueBuffers(source, 1, &buffer); unusedBufferPop(); } @@ -699,7 +700,7 @@ bool Source::queueAtomic(void *data, ALsizei length) return false; //stack acts as queue while stopped - alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate); + alBufferData(buffer, Audio::getFormat(bitDepth, channels), data, length, sampleRate); unusedBufferQueue(buffer); } bufferedBytes += length; @@ -966,34 +967,6 @@ void Source::setFloatv(float *dst, const float *src) const dst[2] = src[2]; } -ALenum Source::getFormat(int channels, int bitDepth) const -{ - if (channels == 1 && bitDepth == 8) - return AL_FORMAT_MONO8; - else if (channels == 1 && bitDepth == 16) - return AL_FORMAT_MONO16; - else if (channels == 2 && bitDepth == 8) - return AL_FORMAT_STEREO8; - else if (channels == 2 && bitDepth == 16) - return AL_FORMAT_STEREO16; - -#ifdef AL_EXT_MCFORMATS - if (alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if (channels == 6 && bitDepth == 8) - return AL_FORMAT_51CHN8; - else if (channels == 6 && bitDepth == 16) - return AL_FORMAT_51CHN16; - else if (channels == 8 && bitDepth == 8) - return AL_FORMAT_71CHN8; - else if (channels == 8 && bitDepth == 16) - return AL_FORMAT_71CHN16; - } -#endif - - return 0; -} - ALuint Source::unusedBufferPeek() { return (unusedBufferTop < 0) ? AL_NONE : unusedBuffers[unusedBufferTop]; @@ -1029,9 +1002,9 @@ int Source::streamAtomic(ALuint buffer, love::sound::Decoder *d) // OpenAL implementations are allowed to ignore 0-size alBufferData calls. if (decoded > 0) { - int fmt = getFormat(d->getChannels(), d->getBitDepth()); + int fmt = Audio::getFormat(d->getBitDepth(), d->getChannels()); - if (fmt != 0) + if (fmt != AL_NONE) alBufferData(buffer, fmt, d->getBuffer(), decoded, d->getSampleRate()); else decoded = 0; diff --git a/src/modules/audio/openal/Source.h b/src/modules/audio/openal/Source.h index 9bddfb73d..680cf5ddb 100644 --- a/src/modules/audio/openal/Source.h +++ b/src/modules/audio/openal/Source.h @@ -163,15 +163,6 @@ private: void setFloatv(float *dst, const float *src) const; - /** - * Gets the OpenAL format identifier based on number of - * channels and bits. - * @param channels Either 1 (mono) or 2 (stereo). - * @param bitDepth Either 8-bit samples, or 16-bit samples. - * @return One of AL_FORMAT_*, or 0 if unsupported format. - **/ - ALenum getFormat(int channels, int bitDepth) const; - int streamAtomic(ALuint buffer, love::sound::Decoder *d); ALuint unusedBufferPeek(); diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 7a178abc8..90ee82a82 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -257,49 +257,6 @@ int w_getDopplerScale(lua_State *L) return 1; } -int w_record(lua_State *) -{ - instance()->record(); - return 0; -} - -int w_getRecordedData(lua_State *L) -{ - love::sound::SoundData *sd = instance()->getRecordedData(); - if (!sd) - lua_pushnil(L); - else - { - luax_pushtype(L, SOUND_SOUND_DATA_ID, sd); - sd->release(); - } - return 1; -} - -int w_stopRecording(lua_State *L) -{ - if (luax_optboolean(L, 1, true)) - { - love::sound::SoundData *sd = instance()->stopRecording(true); - if (!sd) - lua_pushnil(L); - else - { - luax_pushtype(L, SOUND_SOUND_DATA_ID, sd); - sd->release(); - } - return 1; - } - instance()->stopRecording(false); - return 0; -} - -int w_canRecord(lua_State *L) -{ - luax_pushboolean(L, instance()->canRecord()); - return 1; -} - int w_setDistanceModel(lua_State *L) { const char *modelStr = luaL_checkstring(L, 1); @@ -320,6 +277,27 @@ int w_getDistanceModel(lua_State *L) return 1; } +int w_getRecordingDeviceCount(lua_State *L) +{ + lua_pushnumber(L, instance()->getRecordingDeviceCount()); + return 1; +} + +int w_getRecordingDevices(lua_State *L) +{ + int count = instance()->getRecordingDeviceCount(); + lua_createtable(L, count, 0); + + for (int i = 0; i < count; i++) + { + RecordingDevice *device = instance()->getRecordingDevice(i); + luax_pushtype(L, AUDIO_RECORDING_DEVICE_ID, device); + lua_rawseti(L, -2, i + 1); + } + + return 1; +} + // List of functions to wrap. static const luaL_Reg functions[] = { @@ -339,17 +317,17 @@ static const luaL_Reg functions[] = { "getVelocity", w_getVelocity }, { "setDopplerScale", w_setDopplerScale }, { "getDopplerScale", w_getDopplerScale }, - /*{ "record", w_record }, - { "getRecordedData", w_getRecordedData }, - { "stopRecording", w_stopRecording },*/ { "setDistanceModel", w_setDistanceModel }, { "getDistanceModel", w_getDistanceModel }, + { "getRecordingDeviceCount", w_getRecordingDeviceCount }, + { "getRecordingDevices", w_getRecordingDevices }, { 0, 0 } }; static const lua_CFunction types[] = { luaopen_source, + luaopen_recordingdevice, 0 }; diff --git a/src/modules/audio/wrap_Audio.h b/src/modules/audio/wrap_Audio.h index 0f358517d..3990f29d6 100644 --- a/src/modules/audio/wrap_Audio.h +++ b/src/modules/audio/wrap_Audio.h @@ -26,6 +26,7 @@ #include "common/runtime.h" #include "Audio.h" #include "wrap_Source.h" +#include "wrap_RecordingDevice.h" namespace love { diff --git a/src/modules/audio/wrap_RecordingDevice.cpp b/src/modules/audio/wrap_RecordingDevice.cpp new file mode 100644 index 000000000..fbb5c3016 --- /dev/null +++ b/src/modules/audio/wrap_RecordingDevice.cpp @@ -0,0 +1,201 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "wrap_RecordingDevice.h" +#include "wrap_Audio.h" + +#include "sound/SoundData.h" +#include "sound/Sound.h" + +#define soundInstance() (Module::getInstance(Module::M_SOUND)) + +namespace love +{ +namespace audio +{ + +RecordingDevice *luax_checkrecordingdevice(lua_State *L, int idx) +{ + return luax_checktype(L, idx, AUDIO_RECORDING_DEVICE_ID); +} + +int w_RecordingDevice_startRecording(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + if (lua_gettop(L) > 1) + { + int samples = luaL_checkinteger(L, 2); + int sampleRate = luaL_checkinteger(L, 3); + int bitDepth = luaL_checkinteger(L, 4); + int channels = luaL_checkinteger(L, 5); + luax_catchexcept(L, [&](){ + lua_pushboolean(L, d->startRecording(samples, sampleRate, bitDepth, channels)); + }); + } + else + luax_catchexcept(L, [&](){ + lua_pushboolean(L, d->startRecording()); + }); + return 1; +} + +int w_RecordingDevice_stopRecording(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + int samples = d->getSampleCount(); + if (samples == 0) + { + lua_pushnil(L); + return 1; + } + + love::sound::SoundData *s = nullptr; + if (lua_gettop(L) > 1) + { + if (luax_istype(L, 2, SOUND_SOUND_DATA_ID)) + s = luax_totype(L, 2, SOUND_SOUND_DATA_ID); + else + return luaL_typerror(L, 2, "SoundData"); + + s->retain(); + } + else + { + luax_catchexcept(L, [&](){ + s = soundInstance()->newSoundData(samples, d->getSampleRate(), d->getBitDepth(), d->getChannels()); + }); + } + + luax_catchexcept(L, [&](){ + d->getData(s); + d->stopRecording(); + }); + + luax_pushtype(L, SOUND_SOUND_DATA_ID, s); + s->release(); + return 1; +} + +int w_RecordingDevice_getData(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + int samples = d->getSampleCount(); + if (samples == 0) + { + lua_pushnil(L); + return 1; + } + + love::sound::SoundData *s = nullptr; + if (lua_gettop(L) > 1) + { + if (luax_istype(L, 2, SOUND_SOUND_DATA_ID)) + s = luax_totype(L, 2, SOUND_SOUND_DATA_ID); + else + return luaL_typerror(L, 2, "SoundData"); + + s->retain(); + } + else + { + luax_catchexcept(L, [&](){ + s = soundInstance()->newSoundData(samples, d->getSampleRate(), d->getBitDepth(), d->getChannels()); + }); + } + + luax_catchexcept(L, [&](){ d->getData(s); }); + + luax_pushtype(L, SOUND_SOUND_DATA_ID, s); + s->release(); + return 1; +} + +int w_RecordingDevice_getSampleCount(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + lua_pushnumber(L, d->getSampleCount()); + return 1; +} + +int w_RecordingDevice_getSampleRate(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + lua_pushnumber(L, d->getSampleRate()); + return 1; +} + +int w_RecordingDevice_getBitDepth(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + lua_pushnumber(L, d->getBitDepth()); + return 1; +} + +int w_RecordingDevice_getChannels(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + lua_pushnumber(L, d->getChannels()); + return 1; +} + +int w_RecordingDevice_getName(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + lua_pushstring(L, d->getName()); + return 1; +} + +int w_RecordingDevice_getID(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + lua_pushnumber(L, d->getID()); + return 1; +} + +int w_RecordingDevice_isRecording(lua_State *L) +{ + RecordingDevice *d = luax_checkrecordingdevice(L, 1); + lua_pushboolean(L, d->isRecording()); + return 1; +} + +static const luaL_Reg w_RecordingDevice_functions[] = +{ + { "startRecording", w_RecordingDevice_startRecording }, + { "stopRecording", w_RecordingDevice_stopRecording }, + { "getData", w_RecordingDevice_getData }, + { "getSampleCount", w_RecordingDevice_getSampleCount }, + { "getSampleRate", w_RecordingDevice_getSampleRate }, + { "getBitDepth", w_RecordingDevice_getBitDepth }, + { "getChannels", w_RecordingDevice_getChannels }, + { "getName", w_RecordingDevice_getName }, + { "getID", w_RecordingDevice_getID }, + { "isRecording", w_RecordingDevice_isRecording }, + { 0, 0 } +}; + +extern "C" int luaopen_recordingdevice(lua_State *L) +{ + int ret = luax_register_type(L, AUDIO_RECORDING_DEVICE_ID, "RecordingDevice", w_RecordingDevice_functions, nullptr); + return ret; +} + +} //audio +} //love diff --git a/src/modules/audio/wrap_RecordingDevice.h b/src/modules/audio/wrap_RecordingDevice.h new file mode 100644 index 000000000..d9dc9c2e4 --- /dev/null +++ b/src/modules/audio/wrap_RecordingDevice.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_AUDIO_WRAP_RECORDING_DEVICE_H +#define LOVE_AUDIO_WRAP_RECORDING_DEVICE_H + +// LOVE +#include "common/runtime.h" +#include "RecordingDevice.h" + +namespace love +{ +namespace audio +{ + +RecordingDevice *luax_checkrecordingdevice(lua_State *L, int idx); +extern "C" int luaopen_recordingdevice(lua_State *L); + +} // audio +} // love + +#endif //LOVE_AUDIO_WRAP_RECORDING_DEVICE_H + diff --git a/src/modules/sound/SoundData.h b/src/modules/sound/SoundData.h index 07b13c2d3..821fb291e 100644 --- a/src/modules/sound/SoundData.h +++ b/src/modules/sound/SoundData.h @@ -54,11 +54,10 @@ public: void setSample(int i, float sample); float getSample(int i) const; + void load(int samples, int sampleRate, int bitDepth, int channels, void *newData = 0); private: - void load(int samples, int sampleRate, int bitDepth, int channels, void *newData = 0); - uint8 *data; size_t size; From 9a090e8df84e8b83474d02bc1db8ec2d8b75e88d Mon Sep 17 00:00:00 2001 From: Raidho Date: Sun, 23 Oct 2016 18:53:02 +0300 Subject: [PATCH 3/9] made RecordingDevice create new SoundData every time captured samples are aquired --HG-- branch : minor-mic-input --- src/modules/audio/openal/RecordingDevice.cpp | 5 +-- src/modules/audio/wrap_RecordingDevice.cpp | 38 +++----------------- 2 files changed, 8 insertions(+), 35 deletions(-) diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index afe06ef69..5eb77f648 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -102,8 +102,9 @@ int RecordingDevice::getData(love::sound::SoundData *soundData) if (samples == 0) return 0; - //resize internal buffer to proper size - if (samples != soundData->getSampleCount()) + //reinitialize soundData if necessary + if (samples != soundData->getSampleCount() || sampleRate != soundData->getSampleRate() || + bitDepth != soundData->getBitDepth() || channels != soundData->getChannels()) soundData->load(samples, sampleRate, bitDepth, channels); alcCaptureSamples(device, soundData->getData(), samples); diff --git a/src/modules/audio/wrap_RecordingDevice.cpp b/src/modules/audio/wrap_RecordingDevice.cpp index fbb5c3016..b78dc3bc1 100644 --- a/src/modules/audio/wrap_RecordingDevice.cpp +++ b/src/modules/audio/wrap_RecordingDevice.cpp @@ -67,23 +67,8 @@ int w_RecordingDevice_stopRecording(lua_State *L) } love::sound::SoundData *s = nullptr; - if (lua_gettop(L) > 1) - { - if (luax_istype(L, 2, SOUND_SOUND_DATA_ID)) - s = luax_totype(L, 2, SOUND_SOUND_DATA_ID); - else - return luaL_typerror(L, 2, "SoundData"); - - s->retain(); - } - else - { - luax_catchexcept(L, [&](){ - s = soundInstance()->newSoundData(samples, d->getSampleRate(), d->getBitDepth(), d->getChannels()); - }); - } - luax_catchexcept(L, [&](){ + s = soundInstance()->newSoundData(samples, d->getSampleRate(), d->getBitDepth(), d->getChannels()); d->getData(s); d->stopRecording(); }); @@ -104,23 +89,10 @@ int w_RecordingDevice_getData(lua_State *L) } love::sound::SoundData *s = nullptr; - if (lua_gettop(L) > 1) - { - if (luax_istype(L, 2, SOUND_SOUND_DATA_ID)) - s = luax_totype(L, 2, SOUND_SOUND_DATA_ID); - else - return luaL_typerror(L, 2, "SoundData"); - - s->retain(); - } - else - { - luax_catchexcept(L, [&](){ - s = soundInstance()->newSoundData(samples, d->getSampleRate(), d->getBitDepth(), d->getChannels()); - }); - } - - luax_catchexcept(L, [&](){ d->getData(s); }); + luax_catchexcept(L, [&](){ + s = soundInstance()->newSoundData(samples, d->getSampleRate(), d->getBitDepth(), d->getChannels()); + d->getData(s); + }); luax_pushtype(L, SOUND_SOUND_DATA_ID, s); s->release(); From 424d2704ec67664bda33770448a8a7b6f64c8cf0 Mon Sep 17 00:00:00 2001 From: Raidho Date: Sun, 23 Oct 2016 19:22:56 +0300 Subject: [PATCH 4/9] made RecordingDevice throw errors on invalid parameters --HG-- branch : minor-mic-input --- src/modules/audio/openal/RecordingDevice.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index 5eb77f648..abae69571 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -71,6 +71,12 @@ bool RecordingDevice::startRecording(int samples, int sampleRate, int bitDepth, if (format == AL_NONE) throw InvalidFormatException(channels, bitDepth); + if (samples <= 0) + throw love::Exception("Invalid number of samples."); + + if (sampleRate <= 0) + throw love::Exception("Invalid sample rate."); + device = alcCaptureOpenDevice(name.c_str(), sampleRate, format, samples); if (device == nullptr) return false; From 3de68707d1f8cf9ab7ae84617429d5e5af2566c1 Mon Sep 17 00:00:00 2001 From: Raidho Date: Tue, 25 Oct 2016 02:05:53 +0300 Subject: [PATCH 5/9] made device enumeration lazy made enumerator to first attempt aquire default device name by standard means, then to fall back to read name from opened device getRecordingDeviceCount removed for being redundant --HG-- branch : minor-mic-input --- src/modules/audio/Audio.h | 15 +--- src/modules/audio/null/Audio.cpp | 14 +--- src/modules/audio/null/Audio.h | 5 +- src/modules/audio/openal/Audio.cpp | 72 +++++++++----------- src/modules/audio/openal/Audio.h | 4 +- src/modules/audio/openal/RecordingDevice.cpp | 2 +- src/modules/audio/wrap_Audio.cpp | 17 ++--- 7 files changed, 45 insertions(+), 84 deletions(-) diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index 9a0d43aba..c10ffe813 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -190,20 +190,9 @@ public: virtual float getDopplerScale() const = 0; /** - * @return Number of recording devices. + * @return Reference to a vector of pointers to recording devices. May be empty. **/ - virtual int getRecordingDeviceCount() const = 0; - - /** - * @param index Index number of recording device. 0 is default device. - * @return Selected recording device. - **/ - virtual RecordingDevice *getRecordingDevice(int index) const = 0; - - /** - * @return Index number of a recording device, -1 if not present. - **/ - virtual int getRecordingDeviceIndex(RecordingDevice *device) const = 0; + virtual std::vector *getRecordingDevices() = 0; /** * Gets the distance model used for attenuation. diff --git a/src/modules/audio/null/Audio.cpp b/src/modules/audio/null/Audio.cpp index 85d48c629..957129978 100644 --- a/src/modules/audio/null/Audio.cpp +++ b/src/modules/audio/null/Audio.cpp @@ -144,19 +144,9 @@ float Audio::getDopplerScale() const return 1.0f; } -int Audio::getRecordingDeviceCount() const +std::vector *Audio::getRecordingDevices() { - return 0; -} - -love::audio::RecordingDevice *Audio::getRecordingDevice(int index) const -{ - return nullptr; -} - -int Audio::getRecordingDeviceIndex(love::audio::RecordingDevice *device) const -{ - return -1; + return &capture; } Audio::DistanceModel Audio::getDistanceModel() const diff --git a/src/modules/audio/null/Audio.h b/src/modules/audio/null/Audio.h index a2c82e031..3f841fec5 100644 --- a/src/modules/audio/null/Audio.h +++ b/src/modules/audio/null/Audio.h @@ -71,9 +71,7 @@ public: void setDopplerScale(float scale); float getDopplerScale() const; - int getRecordingDeviceCount() const; - love::audio::RecordingDevice *getRecordingDevice(int index) const; - int getRecordingDeviceIndex(love::audio::RecordingDevice *device) const; + std::vector *getRecordingDevices(); DistanceModel getDistanceModel() const; void setDistanceModel(DistanceModel distanceModel); @@ -81,6 +79,7 @@ public: private: float volume; DistanceModel distanceModel; + std::vector capture; }; // Audio diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index cb9b45f09..6283b293b 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -110,29 +110,6 @@ Audio::Audio() if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR) throw love::Exception("Could not make context current."); - //find and push default capture device - //AL may not return actual device name string when asked directly - std::string defaultname; - ALCdevice *defaultdevice = alcCaptureOpenDevice(NULL, 8000, 8, 1); - if (alGetError() == AL_NO_ERROR) - { - defaultname = alcGetString(defaultdevice, ALC_CAPTURE_DEVICE_SPECIFIER); - alcCaptureCloseDevice(defaultdevice); - capture.push_back(new RecordingDevice(defaultname.c_str(), 0)); - } - - const ALCchar *devstr = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); - size_t offset = 0; - while (true) - { - if (devstr[offset] == '\0') - break; - std::string str((ALCchar*)&devstr[offset]); - if (str != defaultname) - capture.push_back(new RecordingDevice(str.c_str(), capture.size())); - offset += str.length() + 1; - } - // pool must be allocated after AL context. try { @@ -336,26 +313,41 @@ void Audio::setDistanceModel(DistanceModel distanceModel) } } -int Audio::getRecordingDeviceCount() const +std::vector *Audio::getRecordingDevices() { - return capture.size(); -} + if (capture.size() == 0) + { + std::string defaultname(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); -love::audio::RecordingDevice *Audio::getRecordingDevice(int index) const -{ - if (index < 0 || (unsigned int)index >= capture.size()) - return nullptr; + //no device name obtained from AL, fallback to reading from device + if (defaultname.length() == 0) + { + //use some safe basic parameters - 8 kHz, 8 bits, 1 channel + ALCdevice *defaultdevice = alcCaptureOpenDevice(NULL, 8000, 8, 1); + if (alGetError() == AL_NO_ERROR) + { + defaultname = alcGetString(defaultdevice, ALC_CAPTURE_DEVICE_SPECIFIER); + alcCaptureCloseDevice(defaultdevice); + } + else + //failed to open default recording device - bail, return empty list + return &capture; + } + capture.push_back(new RecordingDevice(defaultname.c_str(), 0)); - return capture[index]; -} - -int Audio::getRecordingDeviceIndex(love::audio::RecordingDevice *device) const -{ - for (unsigned int i = 0; i < capture.size(); i++) - if (device == capture[i]) - return i; - - return -1; + const ALCchar *devstr = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + size_t offset = 0; + while (true) + { + if (devstr[offset] == '\0') + break; + std::string str((ALCchar*)&devstr[offset]); + if (str != defaultname) + capture.push_back(new RecordingDevice(str.c_str(), capture.size())); + offset += str.length() + 1; + } + } + return &capture; } } // openal diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index 846e0e54c..469586d59 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -105,9 +105,7 @@ public: void setDopplerScale(float scale); float getDopplerScale() const; - int getRecordingDeviceCount() const; - love::audio::RecordingDevice *getRecordingDevice(int index) const; - int getRecordingDeviceIndex(love::audio::RecordingDevice *device) const; + std::vector *getRecordingDevices(); DistanceModel getDistanceModel() const; void setDistanceModel(DistanceModel distanceModel); diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index abae69571..b8d29f27c 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -155,7 +155,7 @@ int RecordingDevice::getID() const bool RecordingDevice::isRecording() const { - return device == nullptr ? false : true; + return device != nullptr; } } //openal diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 90ee82a82..175f1d4af 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -277,21 +277,15 @@ int w_getDistanceModel(lua_State *L) return 1; } -int w_getRecordingDeviceCount(lua_State *L) -{ - lua_pushnumber(L, instance()->getRecordingDeviceCount()); - return 1; -} - int w_getRecordingDevices(lua_State *L) { - int count = instance()->getRecordingDeviceCount(); - lua_createtable(L, count, 0); + std::vector *devices = instance()->getRecordingDevices(); - for (int i = 0; i < count; i++) + lua_createtable(L, (*devices).size(), 0); + + for (unsigned int i = 0; i < (*devices).size(); i++) { - RecordingDevice *device = instance()->getRecordingDevice(i); - luax_pushtype(L, AUDIO_RECORDING_DEVICE_ID, device); + luax_pushtype(L, AUDIO_RECORDING_DEVICE_ID, (*devices)[i]); lua_rawseti(L, -2, i + 1); } @@ -319,7 +313,6 @@ static const luaL_Reg functions[] = { "getDopplerScale", w_getDopplerScale }, { "setDistanceModel", w_setDistanceModel }, { "getDistanceModel", w_getDistanceModel }, - { "getRecordingDeviceCount", w_getRecordingDeviceCount }, { "getRecordingDevices", w_getRecordingDevices }, { 0, 0 } }; From a99c7576529d484eb7ed7254a99f52f857c35d0b Mon Sep 17 00:00:00 2001 From: Raidho Date: Tue, 25 Oct 2016 02:39:39 +0300 Subject: [PATCH 6/9] made :getData produce SoundData directly moved SoundData::load back to private --HG-- branch : minor-mic-input --- src/modules/audio/RecordingDevice.h | 5 +-- src/modules/audio/null/RecordingDevice.cpp | 4 +- src/modules/audio/null/RecordingDevice.h | 2 +- src/modules/audio/openal/RecordingDevice.cpp | 16 +++---- src/modules/audio/openal/RecordingDevice.h | 2 +- src/modules/audio/wrap_RecordingDevice.cpp | 46 +++++++++----------- src/modules/sound/SoundData.h | 3 +- 7 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/modules/audio/RecordingDevice.h b/src/modules/audio/RecordingDevice.h index ac2d9150c..83af9580e 100644 --- a/src/modules/audio/RecordingDevice.h +++ b/src/modules/audio/RecordingDevice.h @@ -60,10 +60,9 @@ public: /** * Retreives recorded data. - * @param soundData Reference to a SoundData to fill. - * @return number of samples obtained from device. + * @return SoundData containing data obtained from recording device. **/ - virtual int getData(love::sound::SoundData *soundData) = 0; + virtual love::sound::SoundData *getData() = 0; /** * @return C string device name. diff --git a/src/modules/audio/null/RecordingDevice.cpp b/src/modules/audio/null/RecordingDevice.cpp index 9e62b4168..f68f08903 100644 --- a/src/modules/audio/null/RecordingDevice.cpp +++ b/src/modules/audio/null/RecordingDevice.cpp @@ -52,9 +52,9 @@ void RecordingDevice::stopRecording() { } -int RecordingDevice::getData(love::sound::SoundData*) +love::sound::SoundData *RecordingDevice::getData() { - return 0; + return nullptr; } int RecordingDevice::getSampleCount() const diff --git a/src/modules/audio/null/RecordingDevice.h b/src/modules/audio/null/RecordingDevice.h index 8fcb1bdad..da5e14ec1 100644 --- a/src/modules/audio/null/RecordingDevice.h +++ b/src/modules/audio/null/RecordingDevice.h @@ -39,7 +39,7 @@ public: virtual bool startRecording(); virtual bool startRecording(int samples, int sampleRate, int bitDepth, int channels); virtual void stopRecording(); - virtual int getData(love::sound::SoundData *soundData); + virtual love::sound::SoundData *getData(); virtual const char *getName() const; virtual int getID() const; virtual int getSampleCount() const; diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index b8d29f27c..5e9eba7f2 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -20,6 +20,7 @@ #include "RecordingDevice.h" #include "Audio.h" +#include "sound/Sound.h" namespace love { @@ -28,6 +29,8 @@ namespace audio namespace openal { +#define soundInstance() (Module::getInstance(Module::M_SOUND)) + class InvalidFormatException : public love::Exception { public: @@ -99,23 +102,20 @@ void RecordingDevice::stopRecording() device = nullptr; } -int RecordingDevice::getData(love::sound::SoundData *soundData) +love::sound::SoundData *RecordingDevice::getData() { if (!isRecording()) - return 0; + return nullptr; int samples = getSampleCount(); if (samples == 0) - return 0; + return nullptr; - //reinitialize soundData if necessary - if (samples != soundData->getSampleCount() || sampleRate != soundData->getSampleRate() || - bitDepth != soundData->getBitDepth() || channels != soundData->getChannels()) - soundData->load(samples, sampleRate, bitDepth, channels); + love::sound::SoundData *soundData = soundInstance()->newSoundData(samples, sampleRate, bitDepth, channels); alcCaptureSamples(device, soundData->getData(), samples); - return samples; + return soundData; } int RecordingDevice::getSampleCount() const diff --git a/src/modules/audio/openal/RecordingDevice.h b/src/modules/audio/openal/RecordingDevice.h index 3e4ae14ca..00488a8f4 100644 --- a/src/modules/audio/openal/RecordingDevice.h +++ b/src/modules/audio/openal/RecordingDevice.h @@ -52,7 +52,7 @@ public: virtual bool startRecording(); virtual bool startRecording(int samples, int sampleRate, int bitDepth, int channels); virtual void stopRecording(); - virtual int getData(love::sound::SoundData *soundData); + virtual love::sound::SoundData *getData(); virtual const char *getName() const; virtual int getID() const; virtual int getSampleCount() const; diff --git a/src/modules/audio/wrap_RecordingDevice.cpp b/src/modules/audio/wrap_RecordingDevice.cpp index b78dc3bc1..256ef7e5a 100644 --- a/src/modules/audio/wrap_RecordingDevice.cpp +++ b/src/modules/audio/wrap_RecordingDevice.cpp @@ -22,10 +22,6 @@ #include "wrap_Audio.h" #include "sound/SoundData.h" -#include "sound/Sound.h" - -#define soundInstance() (Module::getInstance(Module::M_SOUND)) - namespace love { namespace audio @@ -59,43 +55,41 @@ int w_RecordingDevice_startRecording(lua_State *L) int w_RecordingDevice_stopRecording(lua_State *L) { RecordingDevice *d = luax_checkrecordingdevice(L, 1); - int samples = d->getSampleCount(); - if (samples == 0) - { - lua_pushnil(L); - return 1; - } - love::sound::SoundData *s = nullptr; + luax_catchexcept(L, [&](){ - s = soundInstance()->newSoundData(samples, d->getSampleRate(), d->getBitDepth(), d->getChannels()); - d->getData(s); + s = d->getData(); d->stopRecording(); }); - luax_pushtype(L, SOUND_SOUND_DATA_ID, s); - s->release(); + if (s != nullptr) + { + luax_pushtype(L, SOUND_SOUND_DATA_ID, s); + s->release(); + } + else + lua_pushnil(L); + return 1; } int w_RecordingDevice_getData(lua_State *L) { RecordingDevice *d = luax_checkrecordingdevice(L, 1); - int samples = d->getSampleCount(); - if (samples == 0) - { - lua_pushnil(L); - return 1; - } - love::sound::SoundData *s = nullptr; + luax_catchexcept(L, [&](){ - s = soundInstance()->newSoundData(samples, d->getSampleRate(), d->getBitDepth(), d->getChannels()); - d->getData(s); + s = d->getData(); }); - luax_pushtype(L, SOUND_SOUND_DATA_ID, s); - s->release(); + if (s != nullptr) + { + luax_pushtype(L, SOUND_SOUND_DATA_ID, s); + s->release(); + } + else + lua_pushnil(L); + return 1; } diff --git a/src/modules/sound/SoundData.h b/src/modules/sound/SoundData.h index 821fb291e..07b13c2d3 100644 --- a/src/modules/sound/SoundData.h +++ b/src/modules/sound/SoundData.h @@ -54,10 +54,11 @@ public: void setSample(int i, float sample); float getSample(int i) const; - void load(int samples, int sampleRate, int bitDepth, int channels, void *newData = 0); private: + void load(int samples, int sampleRate, int bitDepth, int channels, void *newData = 0); + uint8 *data; size_t size; From 57d02dec2b12bea4282b6ccaa1d125958a6d741c Mon Sep 17 00:00:00 2001 From: Raidho Date: Thu, 3 Nov 2016 06:31:31 +0300 Subject: [PATCH 7/9] Addressed some criticism getRecordingDevices internal function is now returns constant reference, also re-enumerates devices every time it is called; this is a slow operation getID removed for not being useful --HG-- branch : minor-mic-input --- src/modules/audio/Audio.h | 2 +- src/modules/audio/RecordingDevice.h | 5 -- src/modules/audio/null/Audio.cpp | 4 +- src/modules/audio/null/Audio.h | 2 +- src/modules/audio/null/RecordingDevice.cpp | 5 -- src/modules/audio/null/RecordingDevice.h | 1 - src/modules/audio/openal/Audio.cpp | 60 ++++++++++---------- src/modules/audio/openal/Audio.h | 2 +- src/modules/audio/openal/RecordingDevice.cpp | 5 -- src/modules/audio/openal/RecordingDevice.h | 1 - src/modules/audio/wrap_Audio.cpp | 8 +-- src/modules/audio/wrap_RecordingDevice.cpp | 8 --- 12 files changed, 39 insertions(+), 64 deletions(-) diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index c10ffe813..811845bd4 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -192,7 +192,7 @@ public: /** * @return Reference to a vector of pointers to recording devices. May be empty. **/ - virtual std::vector *getRecordingDevices() = 0; + virtual const std::vector &getRecordingDevices() = 0; /** * Gets the distance model used for attenuation. diff --git a/src/modules/audio/RecordingDevice.h b/src/modules/audio/RecordingDevice.h index 83af9580e..48c7d41cd 100644 --- a/src/modules/audio/RecordingDevice.h +++ b/src/modules/audio/RecordingDevice.h @@ -69,11 +69,6 @@ public: **/ virtual const char *getName() const = 0; - /** - * @return Unique ID number. - **/ - virtual int getID() const = 0; - /** * @return Number of samples currently recorded. **/ diff --git a/src/modules/audio/null/Audio.cpp b/src/modules/audio/null/Audio.cpp index 957129978..9db2e67b1 100644 --- a/src/modules/audio/null/Audio.cpp +++ b/src/modules/audio/null/Audio.cpp @@ -144,9 +144,9 @@ float Audio::getDopplerScale() const return 1.0f; } -std::vector *Audio::getRecordingDevices() +const std::vector &Audio::getRecordingDevices() { - return &capture; + return capture; } Audio::DistanceModel Audio::getDistanceModel() const diff --git a/src/modules/audio/null/Audio.h b/src/modules/audio/null/Audio.h index 3f841fec5..fdd8325fc 100644 --- a/src/modules/audio/null/Audio.h +++ b/src/modules/audio/null/Audio.h @@ -71,7 +71,7 @@ public: void setDopplerScale(float scale); float getDopplerScale() const; - std::vector *getRecordingDevices(); + const std::vector &getRecordingDevices(); DistanceModel getDistanceModel() const; void setDistanceModel(DistanceModel distanceModel); diff --git a/src/modules/audio/null/RecordingDevice.cpp b/src/modules/audio/null/RecordingDevice.cpp index f68f08903..0d135fa95 100644 --- a/src/modules/audio/null/RecordingDevice.cpp +++ b/src/modules/audio/null/RecordingDevice.cpp @@ -82,11 +82,6 @@ const char *RecordingDevice::getName() const return name; } -int RecordingDevice::getID() const -{ - return 0; -} - bool RecordingDevice::isRecording() const { return false; diff --git a/src/modules/audio/null/RecordingDevice.h b/src/modules/audio/null/RecordingDevice.h index da5e14ec1..dd4ccc205 100644 --- a/src/modules/audio/null/RecordingDevice.h +++ b/src/modules/audio/null/RecordingDevice.h @@ -41,7 +41,6 @@ public: virtual void stopRecording(); virtual love::sound::SoundData *getData(); virtual const char *getName() const; - virtual int getID() const; virtual int getSampleCount() const; virtual int getSampleRate() const; virtual int getBitDepth() const; diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index 6283b293b..8658f5957 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -313,41 +313,41 @@ void Audio::setDistanceModel(DistanceModel distanceModel) } } -std::vector *Audio::getRecordingDevices() +const std::vector &Audio::getRecordingDevices() { - if (capture.size() == 0) + capture.clear(); + + std::string defaultname(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); + + //no device name obtained from AL, fallback to reading from device + if (defaultname.length() == 0) { - std::string defaultname(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); - - //no device name obtained from AL, fallback to reading from device - if (defaultname.length() == 0) + //use some safe basic parameters - 8 kHz, 8 bits, 1 channel + ALCdevice *defaultdevice = alcCaptureOpenDevice(NULL, 8000, 8, 1); + if (alGetError() == AL_NO_ERROR) { - //use some safe basic parameters - 8 kHz, 8 bits, 1 channel - ALCdevice *defaultdevice = alcCaptureOpenDevice(NULL, 8000, 8, 1); - if (alGetError() == AL_NO_ERROR) - { - defaultname = alcGetString(defaultdevice, ALC_CAPTURE_DEVICE_SPECIFIER); - alcCaptureCloseDevice(defaultdevice); - } - else - //failed to open default recording device - bail, return empty list - return &capture; - } - capture.push_back(new RecordingDevice(defaultname.c_str(), 0)); - - const ALCchar *devstr = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); - size_t offset = 0; - while (true) - { - if (devstr[offset] == '\0') - break; - std::string str((ALCchar*)&devstr[offset]); - if (str != defaultname) - capture.push_back(new RecordingDevice(str.c_str(), capture.size())); - offset += str.length() + 1; + defaultname = alcGetString(defaultdevice, ALC_CAPTURE_DEVICE_SPECIFIER); + alcCaptureCloseDevice(defaultdevice); } + else + //failed to open default recording device - bail, return empty list + return capture; } - return &capture; + capture.push_back(new RecordingDevice(defaultname.c_str(), 0)); + + const ALCchar *devstr = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + size_t offset = 0; + while (true) + { + if (devstr[offset] == '\0') + break; + std::string str((ALCchar*)&devstr[offset]); + if (str != defaultname) + capture.push_back(new RecordingDevice(str.c_str(), capture.size())); + offset += str.length() + 1; + } + + return capture; } } // openal diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index 469586d59..aaa675fdc 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -105,7 +105,7 @@ public: void setDopplerScale(float scale); float getDopplerScale() const; - std::vector *getRecordingDevices(); + const std::vector &getRecordingDevices(); DistanceModel getDistanceModel() const; void setDistanceModel(DistanceModel distanceModel); diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index 5e9eba7f2..80bfc08ad 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -148,11 +148,6 @@ const char *RecordingDevice::getName() const return name.c_str(); } -int RecordingDevice::getID() const -{ - return id; -} - bool RecordingDevice::isRecording() const { return device != nullptr; diff --git a/src/modules/audio/openal/RecordingDevice.h b/src/modules/audio/openal/RecordingDevice.h index 00488a8f4..c6005601f 100644 --- a/src/modules/audio/openal/RecordingDevice.h +++ b/src/modules/audio/openal/RecordingDevice.h @@ -54,7 +54,6 @@ public: virtual void stopRecording(); virtual love::sound::SoundData *getData(); virtual const char *getName() const; - virtual int getID() const; virtual int getSampleCount() const; virtual int getSampleRate() const; virtual int getBitDepth() const; diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 175f1d4af..24db7df8a 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -279,13 +279,13 @@ int w_getDistanceModel(lua_State *L) int w_getRecordingDevices(lua_State *L) { - std::vector *devices = instance()->getRecordingDevices(); + const std::vector &devices = instance()->getRecordingDevices(); - lua_createtable(L, (*devices).size(), 0); + lua_createtable(L, devices.size(), 0); - for (unsigned int i = 0; i < (*devices).size(); i++) + for (unsigned int i = 0; i < devices.size(); i++) { - luax_pushtype(L, AUDIO_RECORDING_DEVICE_ID, (*devices)[i]); + luax_pushtype(L, AUDIO_RECORDING_DEVICE_ID, devices[i]); lua_rawseti(L, -2, i + 1); } diff --git a/src/modules/audio/wrap_RecordingDevice.cpp b/src/modules/audio/wrap_RecordingDevice.cpp index 256ef7e5a..d4d3cc534 100644 --- a/src/modules/audio/wrap_RecordingDevice.cpp +++ b/src/modules/audio/wrap_RecordingDevice.cpp @@ -128,13 +128,6 @@ int w_RecordingDevice_getName(lua_State *L) return 1; } -int w_RecordingDevice_getID(lua_State *L) -{ - RecordingDevice *d = luax_checkrecordingdevice(L, 1); - lua_pushnumber(L, d->getID()); - return 1; -} - int w_RecordingDevice_isRecording(lua_State *L) { RecordingDevice *d = luax_checkrecordingdevice(L, 1); @@ -152,7 +145,6 @@ static const luaL_Reg w_RecordingDevice_functions[] = { "getBitDepth", w_RecordingDevice_getBitDepth }, { "getChannels", w_RecordingDevice_getChannels }, { "getName", w_RecordingDevice_getName }, - { "getID", w_RecordingDevice_getID }, { "isRecording", w_RecordingDevice_isRecording }, { 0, 0 } }; From c7c253f4498dae46660ccccbfe62f20c037fcd77 Mon Sep 17 00:00:00 2001 From: Raidho Date: Thu, 3 Nov 2016 20:24:21 +0300 Subject: [PATCH 8/9] made getRecordingDevices keep already existing devices --HG-- branch : minor-mic-input --- src/modules/audio/null/RecordingDevice.cpp | 2 +- src/modules/audio/null/RecordingDevice.h | 2 +- src/modules/audio/openal/Audio.cpp | 30 +++++++++++++++++--- src/modules/audio/openal/RecordingDevice.cpp | 3 +- src/modules/audio/openal/RecordingDevice.h | 3 +- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/modules/audio/null/RecordingDevice.cpp b/src/modules/audio/null/RecordingDevice.cpp index 0d135fa95..876683c17 100644 --- a/src/modules/audio/null/RecordingDevice.cpp +++ b/src/modules/audio/null/RecordingDevice.cpp @@ -30,7 +30,7 @@ namespace null const char *RecordingDevice::name = "null"; -RecordingDevice::RecordingDevice(const char *, int) +RecordingDevice::RecordingDevice(const char *) { } diff --git a/src/modules/audio/null/RecordingDevice.h b/src/modules/audio/null/RecordingDevice.h index dd4ccc205..c679c9a92 100644 --- a/src/modules/audio/null/RecordingDevice.h +++ b/src/modules/audio/null/RecordingDevice.h @@ -34,7 +34,7 @@ namespace null class RecordingDevice : public love::audio::RecordingDevice { public: - RecordingDevice(const char *name, int id); + RecordingDevice(const char *name); virtual ~RecordingDevice(); virtual bool startRecording(); virtual bool startRecording(int samples, int sampleRate, int bitDepth, int channels); diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index 8658f5957..e8a0bd674 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -315,7 +315,8 @@ void Audio::setDistanceModel(DistanceModel distanceModel) const std::vector &Audio::getRecordingDevices() { - capture.clear(); + std::vector devnames; + std::vector devices; std::string defaultname(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); @@ -330,11 +331,15 @@ const std::vector &Audio::getRecordingDevices() alcCaptureCloseDevice(defaultdevice); } else - //failed to open default recording device - bail, return empty list + { + //failed to open default recording device - bail, return empty list + capture.clear(); return capture; + } } - capture.push_back(new RecordingDevice(defaultname.c_str(), 0)); + devnames.push_back(defaultname); + //find devices name list const ALCchar *devstr = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); size_t offset = 0; while (true) @@ -343,10 +348,27 @@ const std::vector &Audio::getRecordingDevices() break; std::string str((ALCchar*)&devstr[offset]); if (str != defaultname) - capture.push_back(new RecordingDevice(str.c_str(), capture.size())); + devnames.push_back(str); offset += str.length() + 1; } + //build list of devices + devices.reserve(devnames.size()); + for (unsigned int i = 0; i < devnames.size(); i++) + { + devices[i] = nullptr; + for (auto c = capture.begin(); c != capture.end(); c++) + if (devnames[i] == (*c)->getName()) + devices[i] = *c; + + if (devices[i] == nullptr) + devices[i] = new RecordingDevice(devnames[i].c_str()); + } + + capture.clear(); + for (unsigned int i = 0; i < devnames.size(); i++) + capture.push_back(devices[i]); + return capture; } diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index 80bfc08ad..e978e6e48 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -42,9 +42,8 @@ public: }; -RecordingDevice::RecordingDevice(const char *name, int id) +RecordingDevice::RecordingDevice(const char *name) : name(name) - , id(id) { } diff --git a/src/modules/audio/openal/RecordingDevice.h b/src/modules/audio/openal/RecordingDevice.h index c6005601f..463ca3a38 100644 --- a/src/modules/audio/openal/RecordingDevice.h +++ b/src/modules/audio/openal/RecordingDevice.h @@ -47,7 +47,7 @@ namespace openal class RecordingDevice : public love::audio::RecordingDevice { public: - RecordingDevice(const char *name, int id); + RecordingDevice(const char *name); virtual ~RecordingDevice(); virtual bool startRecording(); virtual bool startRecording(int samples, int sampleRate, int bitDepth, int channels); @@ -66,7 +66,6 @@ private: int bitDepth = 16; int channels = 1; std::string name; - int id; ALCdevice *device = nullptr; }; //RecordingDevice From 422325588ecc26994725778c721e498add3b2687 Mon Sep 17 00:00:00 2001 From: Raidho Date: Fri, 4 Nov 2016 05:40:07 +0300 Subject: [PATCH 9/9] fixed potential memory leak, minor code imporovements --HG-- branch : minor-mic-input --- src/modules/audio/openal/Audio.cpp | 33 ++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index e8a0bd674..8b6f20ead 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -120,8 +120,8 @@ Audio::Audio() alcMakeContextCurrent(nullptr); alcDestroyContext(context); alcCloseDevice(device); - for (unsigned int i = 0; i < capture.size(); i++) - delete capture[i]; + for (auto c : capture) + delete c; throw; } @@ -141,8 +141,8 @@ Audio::~Audio() alcMakeContextCurrent(nullptr); alcDestroyContext(context); alcCloseDevice(device); - for (unsigned int i = 0; i < capture.size(); i++) - delete capture[i]; + for (auto c : capture) + delete c; } @@ -337,6 +337,8 @@ const std::vector &Audio::getRecordingDevices() return capture; } } + + devnames.reserve(capture.size()); devnames.push_back(defaultname); //find devices name list @@ -352,20 +354,29 @@ const std::vector &Audio::getRecordingDevices() offset += str.length() + 1; } - //build list of devices devices.reserve(devnames.size()); + //build ordered list of devices for (unsigned int i = 0; i < devnames.size(); i++) { - devices[i] = nullptr; - for (auto c = capture.begin(); c != capture.end(); c++) - if (devnames[i] == (*c)->getName()) - devices[i] = *c; + devices.push_back(nullptr); + auto d = devices.end() - 1; - if (devices[i] == nullptr) - devices[i] = new RecordingDevice(devnames[i].c_str()); + for (auto c : capture) + if (devnames[i] == c->getName()) + *d = c; + + if (*d == nullptr) + *d = new RecordingDevice(devnames[i].c_str()); + else + (*d)->retain(); } + for (auto c : capture) + c->release(); capture.clear(); + capture.reserve(devices.size()); + + //this needs to be executed in specific order for (unsigned int i = 0; i < devnames.size(); i++) capture.push_back(devices[i]);