Browse Source

Merged in rcoaxil/love-patches/minor-mic-input (pull request #68)

Microphone input implemented.

--HG--
branch : minor
Alex Szpakowski 8 years ago
parent
commit
99a3653d10

+ 8 - 0
CMakeLists.txt

@@ -309,10 +309,14 @@ set(LOVE_SRC_MODULE_AUDIO_ROOT
 	src/modules/audio/Audio.h
 	src/modules/audio/Audio.h
 	src/modules/audio/Source.cpp
 	src/modules/audio/Source.cpp
 	src/modules/audio/Source.h
 	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.cpp
 	src/modules/audio/wrap_Audio.h
 	src/modules/audio/wrap_Audio.h
 	src/modules/audio/wrap_Source.cpp
 	src/modules/audio/wrap_Source.cpp
 	src/modules/audio/wrap_Source.h
 	src/modules/audio/wrap_Source.h
+	src/modules/audio/wrap_RecordingDevice.cpp
+	src/modules/audio/wrap_RecordingDevice.h
 )
 )
 
 
 set(LOVE_SRC_MODULE_AUDIO_NULL
 set(LOVE_SRC_MODULE_AUDIO_NULL
@@ -320,6 +324,8 @@ set(LOVE_SRC_MODULE_AUDIO_NULL
 	src/modules/audio/null/Audio.h
 	src/modules/audio/null/Audio.h
 	src/modules/audio/null/Source.cpp
 	src/modules/audio/null/Source.cpp
 	src/modules/audio/null/Source.h
 	src/modules/audio/null/Source.h
+	src/modules/audio/null/RecordingDevice.cpp
+	src/modules/audio/null/RecordingDevice.h
 )
 )
 
 
 set(LOVE_SRC_MODULE_AUDIO_OPENAL
 set(LOVE_SRC_MODULE_AUDIO_OPENAL
@@ -329,6 +335,8 @@ set(LOVE_SRC_MODULE_AUDIO_OPENAL
 	src/modules/audio/openal/Pool.h
 	src/modules/audio/openal/Pool.h
 	src/modules/audio/openal/Source.cpp
 	src/modules/audio/openal/Source.cpp
 	src/modules/audio/openal/Source.h
 	src/modules/audio/openal/Source.h
+	src/modules/audio/openal/RecordingDevice.cpp
+	src/modules/audio/openal/RecordingDevice.h
 )
 )
 
 
 set(LOVE_SRC_MODULE_AUDIO
 set(LOVE_SRC_MODULE_AUDIO

+ 1 - 0
src/common/types.cpp

@@ -72,6 +72,7 @@ static const TypeBits *createTypeFlags()
 
 
 	// Audio.
 	// Audio.
 	b[AUDIO_SOURCE_ID] = (one << AUDIO_SOURCE_ID) | b[OBJECT_ID];
 	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.
 	// Sound.
 	b[SOUND_SOUND_DATA_ID] = (one << SOUND_SOUND_DATA_ID) | b[DATA_ID];
 	b[SOUND_SOUND_DATA_ID] = (one << SOUND_SOUND_DATA_ID) | b[DATA_ID];

+ 1 - 0
src/common/types.h

@@ -73,6 +73,7 @@ enum Type
 
 
 	// Audio
 	// Audio
 	AUDIO_SOURCE_ID,
 	AUDIO_SOURCE_ID,
+	AUDIO_RECORDING_DEVICE_ID,
 
 
 	// Sound
 	// Sound
 	SOUND_SOUND_DATA_ID,
 	SOUND_SOUND_DATA_ID,

+ 3 - 27
src/modules/audio/Audio.h

@@ -28,6 +28,7 @@
 #include "common/Module.h"
 #include "common/Module.h"
 #include "common/StringMap.h"
 #include "common/StringMap.h"
 #include "Source.h"
 #include "Source.h"
+#include "RecordingDevice.h"
 
 
 namespace love
 namespace love
 {
 {
@@ -189,34 +190,9 @@ public:
 	virtual float getDopplerScale() const = 0;
 	virtual float getDopplerScale() const = 0;
 
 
 	/**
 	/**
-	 * Begins recording audio input from the microphone.
+	 * @return Reference to a vector of pointers to recording devices. May be empty.
 	 **/
 	 **/
-	virtual void record() = 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.
-	 **/
-	virtual love::sound::SoundData *getRecordedData() = 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.
-	 **/
-	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 const std::vector<RecordingDevice*> &getRecordingDevices() = 0;
 
 
 	/**
 	/**
 	 * Gets the distance model used for attenuation.
 	 * Gets the distance model used for attenuation.

+ 37 - 0
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

+ 101 - 0
src/modules/audio/RecordingDevice.h

@@ -0,0 +1,101 @@
+/**
+ * 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 <string>
+
+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. 
+	 * @return SoundData containing data obtained from recording device.
+	 **/
+	virtual love::sound::SoundData *getData() = 0;
+
+	/**
+	 * @return C string device name.
+	 **/ 
+	virtual const char *getName() 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

+ 2 - 16
src/modules/audio/null/Audio.cpp

@@ -144,23 +144,9 @@ float Audio::getDopplerScale() const
 	return 1.0f;
 	return 1.0f;
 }
 }
 
 
-void Audio::record()
+const std::vector<love::audio::RecordingDevice*> &Audio::getRecordingDevices()
 {
 {
-}
-
-love::sound::SoundData *Audio::getRecordedData()
-{
-	return NULL;
-}
-
-love::sound::SoundData *Audio::stopRecording(bool)
-{
-	return NULL;
-}
-
-bool Audio::canRecord()
-{
-	return false;
+	return capture;
 }
 }
 
 
 Audio::DistanceModel Audio::getDistanceModel() const
 Audio::DistanceModel Audio::getDistanceModel() const

+ 3 - 4
src/modules/audio/null/Audio.h

@@ -24,6 +24,7 @@
 // LOVE
 // LOVE
 #include "audio/Audio.h"
 #include "audio/Audio.h"
 
 
+#include "RecordingDevice.h"
 #include "Source.h"
 #include "Source.h"
 
 
 namespace love
 namespace love
@@ -70,10 +71,7 @@ public:
 	void setDopplerScale(float scale);
 	void setDopplerScale(float scale);
 	float getDopplerScale() const;
 	float getDopplerScale() const;
 
 
-	void record();
-	love::sound::SoundData *getRecordedData();
-	love::sound::SoundData *stopRecording(bool returnData);
-	bool canRecord();
+	const std::vector<love::audio::RecordingDevice*> &getRecordingDevices();
 
 
 	DistanceModel getDistanceModel() const;
 	DistanceModel getDistanceModel() const;
 	void setDistanceModel(DistanceModel distanceModel);
 	void setDistanceModel(DistanceModel distanceModel);
@@ -81,6 +79,7 @@ public:
 private:
 private:
 	float volume;
 	float volume;
 	DistanceModel distanceModel;
 	DistanceModel distanceModel;
+	std::vector<love::audio::RecordingDevice*> capture;
 
 
 }; // Audio
 }; // Audio
 
 

+ 92 - 0
src/modules/audio/null/RecordingDevice.cpp

@@ -0,0 +1,92 @@
+/**
+ * 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 *)
+{
+}
+
+RecordingDevice::~RecordingDevice()
+{
+}
+
+bool RecordingDevice::startRecording()
+{
+	return false;
+}
+
+bool RecordingDevice::startRecording(int, int, int, int)
+{
+	return false;
+}
+
+void RecordingDevice::stopRecording()
+{
+}
+
+love::sound::SoundData *RecordingDevice::getData()
+{
+	return nullptr;
+}
+
+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;
+}
+
+bool RecordingDevice::isRecording() const
+{
+	return false;
+}
+
+} //null
+} //audio
+} //love

+ 58 - 0
src/modules/audio/null/RecordingDevice.h

@@ -0,0 +1,58 @@
+/**
+ * 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);
+	virtual ~RecordingDevice();
+	virtual bool startRecording();
+	virtual bool startRecording(int samples, int sampleRate, int bitDepth, int channels);
+	virtual void stopRecording();
+	virtual love::sound::SoundData *getData();
+	virtual const char *getName() 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

+ 98 - 62
src/modules/audio/openal/Audio.cpp

@@ -20,10 +20,11 @@
 
 
 #include "Audio.h"
 #include "Audio.h"
 #include "common/delay.h"
 #include "common/delay.h"
-
+#include "RecordingDevice.h"
 #include "sound/Decoder.h"
 #include "sound/Decoder.h"
 
 
 #include <cstdlib>
 #include <cstdlib>
+#include <iostream>
 
 
 namespace love
 namespace love
 {
 {
@@ -67,9 +68,29 @@ void Audio::PoolThread::setFinish()
 	finish = true;
 	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()
 Audio::Audio()
 	: device(nullptr)
 	: device(nullptr)
-	, capture(nullptr)
 	, context(nullptr)
 	, context(nullptr)
 	, pool(nullptr)
 	, pool(nullptr)
 	, poolThread(nullptr)
 	, poolThread(nullptr)
@@ -89,26 +110,6 @@ Audio::Audio()
 	if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR)
 	if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR)
 		throw love::Exception("Could not make context current.");
 		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)
-	{
-		std::string device(devices);
-		devices += device.size() + 1;
-		if (device.find("Mic") != std::string::npos || device.find("mic") != std::string::npos)
-		{
-			captureName = device;
-		}
-	}
-
-	capture = alcCaptureOpenDevice(captureName.c_str(), 8000, AL_FORMAT_MONO16, 262144); // about 32 seconds
-
-	if (!capture)
-	{
-		// 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;
-	}*/
-
 	// pool must be allocated after AL context.
 	// pool must be allocated after AL context.
 	try
 	try
 	{
 	{
@@ -118,8 +119,10 @@ Audio::Audio()
 	{
 	{
 		alcMakeContextCurrent(nullptr);
 		alcMakeContextCurrent(nullptr);
 		alcDestroyContext(context);
 		alcDestroyContext(context);
-		//if (capture) alcCaptureCloseDevice(capture);
 		alcCloseDevice(device);
 		alcCloseDevice(device);
+		for (auto c : capture)
+			delete c;
+
 		throw;
 		throw;
 	}
 	}
 
 
@@ -137,8 +140,9 @@ Audio::~Audio()
 
 
 	alcMakeContextCurrent(nullptr);
 	alcMakeContextCurrent(nullptr);
 	alcDestroyContext(context);
 	alcDestroyContext(context);
-	//if (capture) alcCaptureCloseDevice(capture);
 	alcCloseDevice(device);
 	alcCloseDevice(device);
+	for (auto c : capture)
+		delete c;
 }
 }
 
 
 
 
@@ -265,44 +269,6 @@ float Audio::getDopplerScale() const
 	return alGetFloat(AL_DOPPLER_FACTOR);
 	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
 Audio::DistanceModel Audio::getDistanceModel() const
 {
 {
 	return distanceModel;
 	return distanceModel;
@@ -347,6 +313,76 @@ void Audio::setDistanceModel(DistanceModel distanceModel)
 	}
 	}
 }
 }
 
 
+const std::vector<love::audio::RecordingDevice*> &Audio::getRecordingDevices()
+{
+	std::vector<std::string> devnames;
+	std::vector<love::audio::RecordingDevice*> devices;
+
+	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)
+		{
+			defaultname = alcGetString(defaultdevice, ALC_CAPTURE_DEVICE_SPECIFIER);
+			alcCaptureCloseDevice(defaultdevice);
+		}
+		else
+		{
+			//failed to open default recording device - bail, return empty list
+			capture.clear();
+			return capture;
+		}
+	}
+
+	devnames.reserve(capture.size());
+	devnames.push_back(defaultname);
+
+	//find devices name list
+	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)
+			devnames.push_back(str);
+		offset += str.length() + 1;
+	}
+
+	devices.reserve(devnames.size());
+	//build ordered list of devices
+	for (unsigned int i = 0; i < devnames.size(); i++)
+	{
+		devices.push_back(nullptr);
+		auto d = devices.end() - 1;
+
+		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]);
+
+	return capture;
+}
+
 } // openal
 } // openal
 } // audio
 } // audio
 } // love
 } // love

+ 13 - 6
src/modules/audio/openal/Audio.h

@@ -29,6 +29,7 @@
 
 
 // LOVE
 // LOVE
 #include "audio/Audio.h"
 #include "audio/Audio.h"
+#include "audio/RecordingDevice.h"
 #include "common/config.h"
 #include "common/config.h"
 #include "sound/SoundData.h"
 #include "sound/SoundData.h"
 
 
@@ -65,6 +66,15 @@ public:
 	Audio();
 	Audio();
 	~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.
 	// Implements Module.
 	const char *getName() const;
 	const char *getName() const;
 
 
@@ -95,10 +105,7 @@ public:
 	void setDopplerScale(float scale);
 	void setDopplerScale(float scale);
 	float getDopplerScale() const;
 	float getDopplerScale() const;
 
 
-	void record();
-	love::sound::SoundData *getRecordedData();
-	love::sound::SoundData *stopRecording(bool returnData);
-	bool canRecord();
+	const std::vector<love::audio::RecordingDevice*> &getRecordingDevices();
 
 
 	DistanceModel getDistanceModel() const;
 	DistanceModel getDistanceModel() const;
 	void setDistanceModel(DistanceModel distanceModel);
 	void setDistanceModel(DistanceModel distanceModel);
@@ -108,8 +115,8 @@ private:
 	// The OpenAL device.
 	// The OpenAL device.
 	ALCdevice *device;
 	ALCdevice *device;
 
 
-	// The OpenAL capture device (microphone).
-	ALCdevice *capture;
+	// The OpenAL capture devices.
+	std::vector<love::audio::RecordingDevice*> capture;
 
 
 	// The OpenAL context.
 	// The OpenAL context.
 	ALCcontext *context;
 	ALCcontext *context;

+ 157 - 0
src/modules/audio/openal/RecordingDevice.cpp

@@ -0,0 +1,157 @@
+/**
+ * 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"
+#include "sound/Sound.h"
+
+namespace love
+{
+namespace audio
+{
+namespace openal
+{
+
+#define soundInstance() (Module::getInstance<love::sound::Sound>(Module::M_SOUND))
+
+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) 
+	: name(name)
+{
+}
+
+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);
+
+	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;
+
+	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;
+}
+
+love::sound::SoundData *RecordingDevice::getData()
+{
+	if (!isRecording())
+		return nullptr;
+
+	int samples = getSampleCount();
+	if (samples == 0)
+		return nullptr;
+
+	love::sound::SoundData *soundData = soundInstance()->newSoundData(samples, sampleRate, bitDepth, channels);
+
+	alcCaptureSamples(device, soundData->getData(), samples);
+
+	return soundData;
+}
+
+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();
+}
+
+bool RecordingDevice::isRecording() const
+{
+	return device != nullptr;
+}
+
+} //openal
+} //audio
+} //love

+ 76 - 0
src/modules/audio/openal/RecordingDevice.h

@@ -0,0 +1,76 @@
+/**
+ * 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 <OpenAL/alc.h>
+#include <OpenAL/al.h>
+#else
+#include <OpenAL-Soft/alc.h>
+#include <OpenAL-Soft/al.h>
+#endif
+#else
+#include <AL/alc.h>
+#include <AL/al.h>
+#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);
+	virtual ~RecordingDevice();
+	virtual bool startRecording();
+	virtual bool startRecording(int samples, int sampleRate, int bitDepth, int channels);
+	virtual void stopRecording();
+	virtual love::sound::SoundData *getData();
+	virtual const char *getName() 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;
+	ALCdevice *device = nullptr;
+}; //RecordingDevice
+
+} //openal
+} //audio
+} //love
+
+#endif //LOVE_AUDIO_OPENAL_RECORDING_DEVICE_H

+ 10 - 37
src/modules/audio/openal/Source.cpp

@@ -20,6 +20,7 @@
 
 
 #include "Source.h"
 #include "Source.h"
 #include "Pool.h"
 #include "Pool.h"
+#include "Audio.h"
 #include "common/math.h"
 #include "common/math.h"
 
 
 // STD
 // STD
@@ -119,8 +120,8 @@ Source::Source(Pool *pool, love::sound::SoundData *soundData)
 	, channels(soundData->getChannels())
 	, channels(soundData->getChannels())
 	, bitDepth(soundData->getBitDepth())
 	, 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());
 		throw InvalidFormatException(soundData->getChannels(), soundData->getBitDepth());
 
 
 	staticBuffer.set(new StaticDataBuffer(fmt, soundData->getData(), (ALsizei) soundData->getSize(), sampleRate), Acquire::NORETAIN);
 	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)
 	, decoder(decoder)
 	, unusedBufferTop(MAX_BUFFERS - 1)
 	, 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());
 		throw InvalidFormatException(decoder->getChannels(), decoder->getBitDepth());
 
 
 	alGenBuffers(MAX_BUFFERS, streamBuffers);
 	alGenBuffers(MAX_BUFFERS, streamBuffers);
@@ -162,8 +163,8 @@ Source::Source(Pool *pool, int sampleRate, int bitDepth, int channels)
 	, channels(channels)
 	, channels(channels)
 	, bitDepth(bitDepth)
 	, bitDepth(bitDepth)
 {
 {
-	ALenum fmt = getFormat(channels, bitDepth);
-	if (fmt == 0)
+	ALenum fmt = Audio::getFormat(bitDepth, channels);
+	if (fmt == AL_NONE)
 		throw InvalidFormatException(channels, bitDepth);
 		throw InvalidFormatException(channels, bitDepth);
 
 
 	alGenBuffers(MAX_BUFFERS, streamBuffers);
 	alGenBuffers(MAX_BUFFERS, streamBuffers);
@@ -699,7 +700,7 @@ bool Source::queueAtomic(void *data, ALsizei length)
 		if (buffer == AL_NONE)
 		if (buffer == AL_NONE)
 			return false;
 			return false;
 
 
-		alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate);
+		alBufferData(buffer, Audio::getFormat(bitDepth, channels), data, length, sampleRate);
 		alSourceQueueBuffers(source, 1, &buffer);
 		alSourceQueueBuffers(source, 1, &buffer);
 		unusedBufferPop();
 		unusedBufferPop();
 	}
 	}
@@ -710,7 +711,7 @@ bool Source::queueAtomic(void *data, ALsizei length)
 			return false;
 			return false;
 
 
 		//stack acts as queue while stopped
 		//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);
 		unusedBufferQueue(buffer);
 	}
 	}
 	bufferedBytes += length;
 	bufferedBytes += length;
@@ -992,34 +993,6 @@ void Source::setFloatv(float *dst, const float *src) const
 	dst[2] = src[2];
 	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()
 ALuint Source::unusedBufferPeek()
 {
 {
 	return (unusedBufferTop < 0) ? AL_NONE : unusedBuffers[unusedBufferTop];
 	return (unusedBufferTop < 0) ? AL_NONE : unusedBuffers[unusedBufferTop];
@@ -1055,9 +1028,9 @@ int Source::streamAtomic(ALuint buffer, love::sound::Decoder *d)
 	// OpenAL implementations are allowed to ignore 0-size alBufferData calls.
 	// OpenAL implementations are allowed to ignore 0-size alBufferData calls.
 	if (decoded > 0)
 	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());
 			alBufferData(buffer, fmt, d->getBuffer(), decoded, d->getSampleRate());
 		else
 		else
 			decoded = 0;
 			decoded = 0;

+ 0 - 9
src/modules/audio/openal/Source.h

@@ -163,15 +163,6 @@ private:
 
 
 	void setFloatv(float *dst, const float *src) const;
 	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);
 	int streamAtomic(ALuint buffer, love::sound::Decoder *d);
 
 
 	ALuint unusedBufferPeek();
 	ALuint unusedBufferPeek();

+ 17 - 46
src/modules/audio/wrap_Audio.cpp

@@ -257,49 +257,6 @@ int w_getDopplerScale(lua_State *L)
 	return 1;
 	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)
 int w_setDistanceModel(lua_State *L)
 {
 {
 	const char *modelStr = luaL_checkstring(L, 1);
 	const char *modelStr = luaL_checkstring(L, 1);
@@ -320,6 +277,21 @@ int w_getDistanceModel(lua_State *L)
 	return 1;
 	return 1;
 }
 }
 
 
+int w_getRecordingDevices(lua_State *L)
+{
+	const std::vector<RecordingDevice*> &devices = instance()->getRecordingDevices();
+
+	lua_createtable(L, devices.size(), 0);
+
+	for (unsigned int i = 0; i < devices.size(); i++)
+	{
+		luax_pushtype(L, AUDIO_RECORDING_DEVICE_ID, devices[i]);
+		lua_rawseti(L, -2, i + 1);
+	}
+
+	return 1;
+}
+
 // List of functions to wrap.
 // List of functions to wrap.
 static const luaL_Reg functions[] =
 static const luaL_Reg functions[] =
 {
 {
@@ -339,17 +311,16 @@ static const luaL_Reg functions[] =
 	{ "getVelocity", w_getVelocity },
 	{ "getVelocity", w_getVelocity },
 	{ "setDopplerScale", w_setDopplerScale },
 	{ "setDopplerScale", w_setDopplerScale },
 	{ "getDopplerScale", w_getDopplerScale },
 	{ "getDopplerScale", w_getDopplerScale },
-	/*{ "record", w_record },
-	{ "getRecordedData", w_getRecordedData },
-	{ "stopRecording", w_stopRecording },*/
 	{ "setDistanceModel", w_setDistanceModel },
 	{ "setDistanceModel", w_setDistanceModel },
 	{ "getDistanceModel", w_getDistanceModel },
 	{ "getDistanceModel", w_getDistanceModel },
+	{ "getRecordingDevices", w_getRecordingDevices },
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
 
 
 static const lua_CFunction types[] =
 static const lua_CFunction types[] =
 {
 {
 	luaopen_source,
 	luaopen_source,
+	luaopen_recordingdevice,
 	0
 	0
 };
 };
 
 

+ 1 - 0
src/modules/audio/wrap_Audio.h

@@ -26,6 +26,7 @@
 #include "common/runtime.h"
 #include "common/runtime.h"
 #include "Audio.h"
 #include "Audio.h"
 #include "wrap_Source.h"
 #include "wrap_Source.h"
+#include "wrap_RecordingDevice.h"
 
 
 namespace love
 namespace love
 {
 {

+ 159 - 0
src/modules/audio/wrap_RecordingDevice.cpp

@@ -0,0 +1,159 @@
+/**
+ * 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"
+namespace love
+{
+namespace audio
+{
+
+RecordingDevice *luax_checkrecordingdevice(lua_State *L, int idx)
+{
+	return luax_checktype<RecordingDevice>(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);
+	love::sound::SoundData *s = nullptr;
+
+	luax_catchexcept(L, [&](){ 
+		s = d->getData();
+		d->stopRecording();
+	});
+
+	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);
+	love::sound::SoundData *s = nullptr;
+
+	luax_catchexcept(L, [&](){ 
+		s = d->getData();
+	});
+
+	if (s != nullptr)
+	{
+		luax_pushtype(L, SOUND_SOUND_DATA_ID, s);
+		s->release();
+	}
+	else
+		lua_pushnil(L);
+
+	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_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 },
+	{ "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

+ 40 - 0
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
+