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
This commit is contained in:
Raidho
2016-10-23 17:56:52 +03:00
parent e5be492431
commit 87f0b2811e
21 changed files with 922 additions and 192 deletions
+8
View File
@@ -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
+1
View File
@@ -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];
+1
View File
@@ -73,6 +73,7 @@ enum Type
// Audio
AUDIO_SOURCE_ID,
AUDIO_RECORDING_DEVICE_ID,
// Sound
SOUND_SOUND_DATA_ID,
+8 -21
View File
@@ -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.
+37
View File
@@ -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
+107
View File
@@ -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 <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.
* @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
+6 -10
View File
@@ -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
+4 -4
View File
@@ -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);
@@ -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
+59
View File
@@ -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
+68 -57
View File
@@ -20,10 +20,11 @@
#include "Audio.h"
#include "common/delay.h"
#include "RecordingDevice.h"
#include "sound/Decoder.h"
#include <cstdlib>
#include <iostream>
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
+15 -6
View File
@@ -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<love::audio::RecordingDevice*> capture;
// The OpenAL context.
ALCcontext *context;
@@ -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
@@ -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 <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, 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
+10 -37
View File
@@ -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;
-9
View File
@@ -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();
+24 -46
View File
@@ -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
};
+1
View File
@@ -26,6 +26,7 @@
#include "common/runtime.h"
#include "Audio.h"
#include "wrap_Source.h"
#include "wrap_RecordingDevice.h"
namespace love
{
+201
View File
@@ -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<love::sound::Sound>(Module::M_SOUND))
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);
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<love::sound::SoundData>(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<love::sound::SoundData>(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
+40
View File
@@ -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
+1 -2
View File
@@ -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;