mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
Added sound input and recording functionality.
This commit is contained in:
+116
-86
@@ -16,48 +16,48 @@
|
||||
* 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_AUDIO_H
|
||||
#define LOVE_AUDIO_AUDIO_H
|
||||
|
||||
#include <common/Module.h>
|
||||
**/
|
||||
|
||||
#ifndef LOVE_AUDIO_AUDIO_H
|
||||
#define LOVE_AUDIO_AUDIO_H
|
||||
|
||||
#include <common/Module.h>
|
||||
#include "Source.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace sound
|
||||
{
|
||||
class Decoder;
|
||||
class SoundData;
|
||||
}
|
||||
namespace audio
|
||||
{
|
||||
/**
|
||||
* The Audio module is responsible for playing back raw sound samples.
|
||||
**/
|
||||
class Audio : public Module
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
**/
|
||||
virtual ~Audio(){};
|
||||
|
||||
virtual Source * newSource(love::sound::Decoder * decoder) = 0;
|
||||
virtual Source * newSource(love::sound::SoundData * soundData) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current number of simulatenous playing sources.
|
||||
* @return The current number of simulatenous playing sources.
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace sound
|
||||
{
|
||||
class Decoder;
|
||||
class SoundData;
|
||||
}
|
||||
namespace audio
|
||||
{
|
||||
/**
|
||||
* The Audio module is responsible for playing back raw sound samples.
|
||||
**/
|
||||
class Audio : public Module
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
**/
|
||||
virtual ~Audio(){};
|
||||
|
||||
virtual Source * newSource(love::sound::Decoder * decoder) = 0;
|
||||
virtual Source * newSource(love::sound::SoundData * soundData) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current number of simultaneous playing sources.
|
||||
* @return The current number of simultaneous playing sources.
|
||||
**/
|
||||
virtual int getNumSources() const = 0;
|
||||
|
||||
/**
|
||||
* Gets the maximum supported number of simultaneous playing sources.
|
||||
* @return The maximum supported number of simultaneous playing sources.
|
||||
**/
|
||||
virtual int getNumSources() const = 0;
|
||||
|
||||
/**
|
||||
* Gets the maximum supported number of simulatenous playing sources.
|
||||
* @return The maximum supported number of simulatenous playing sources.
|
||||
**/
|
||||
virtual int getMaxSources() const = 0;
|
||||
|
||||
/**
|
||||
@@ -121,49 +121,79 @@ namespace audio
|
||||
* Gets the master volume.
|
||||
* @return The current master volume.
|
||||
**/
|
||||
virtual float getVolume() const = 0;
|
||||
|
||||
/**
|
||||
* Gets the position of the listener.
|
||||
* @param v A float array of size 3 containing (x,y,z) in that order.
|
||||
**/
|
||||
virtual void getPosition(float * v) const = 0;
|
||||
|
||||
/**
|
||||
* Sets the position of the listener.
|
||||
* @param v A float array of size 3 containing [x,y,z] in that order.
|
||||
**/
|
||||
virtual void setPosition(float * v) = 0;
|
||||
|
||||
/**
|
||||
* Gets the orientation of the listener.
|
||||
* @param v A float array of size 6 containing [x,y,z] for the forward
|
||||
* vector, followed by [x,y,z] for the up vector.
|
||||
**/
|
||||
virtual void getOrientation(float * v) const = 0;
|
||||
|
||||
/**
|
||||
* Sets the orientation of the listener.
|
||||
* @param v A float array of size 6 containing [x,y,z] for the forward
|
||||
* vector, followed by [x,y,z] for the up vector.
|
||||
**/
|
||||
virtual void setOrientation(float * v) = 0;
|
||||
|
||||
/**
|
||||
* Gets the velocity of the listener.
|
||||
* @param v A float array of size 3 containing [x,y,z] in that order.
|
||||
**/
|
||||
virtual void getVelocity(float * v) const = 0;
|
||||
|
||||
/**
|
||||
* Sets the velocity of the listener.
|
||||
* @param v A float array of size 3 containing [x,y,z] in that order.
|
||||
**/
|
||||
virtual void setVelocity(float * v) = 0;
|
||||
|
||||
}; // Audio
|
||||
|
||||
} // audio
|
||||
} // love
|
||||
|
||||
#endif // LOVE_AUDIO_AUDIO_H
|
||||
virtual float getVolume() const = 0;
|
||||
|
||||
/**
|
||||
* Gets the position of the listener.
|
||||
* @param v A float array of size 3 containing (x,y,z) in that order.
|
||||
**/
|
||||
virtual void getPosition(float * v) const = 0;
|
||||
|
||||
/**
|
||||
* Sets the position of the listener.
|
||||
* @param v A float array of size 3 containing [x,y,z] in that order.
|
||||
**/
|
||||
virtual void setPosition(float * v) = 0;
|
||||
|
||||
/**
|
||||
* Gets the orientation of the listener.
|
||||
* @param v A float array of size 6 containing [x,y,z] for the forward
|
||||
* vector, followed by [x,y,z] for the up vector.
|
||||
**/
|
||||
virtual void getOrientation(float * v) const = 0;
|
||||
|
||||
/**
|
||||
* Sets the orientation of the listener.
|
||||
* @param v A float array of size 6 containing [x,y,z] for the forward
|
||||
* vector, followed by [x,y,z] for the up vector.
|
||||
**/
|
||||
virtual void setOrientation(float * v) = 0;
|
||||
|
||||
/**
|
||||
* Gets the velocity of the listener.
|
||||
* @param v A float array of size 3 containing [x,y,z] in that order.
|
||||
**/
|
||||
virtual void getVelocity(float * v) const = 0;
|
||||
|
||||
/**
|
||||
* Sets the velocity of the listener.
|
||||
* @param v A float array of size 3 containing [x,y,z] in that order.
|
||||
**/
|
||||
virtual void setVelocity(float * v) = 0;
|
||||
|
||||
/**
|
||||
* Begins recording audio input from the microphone.
|
||||
**/
|
||||
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;
|
||||
|
||||
}; // Audio
|
||||
|
||||
} // audio
|
||||
} // love
|
||||
|
||||
#endif // LOVE_AUDIO_AUDIO_H
|
||||
|
||||
@@ -132,6 +132,25 @@ namespace null
|
||||
void Audio::setVelocity(float *)
|
||||
{
|
||||
}
|
||||
|
||||
void Audio::record()
|
||||
{
|
||||
}
|
||||
|
||||
love::sound::SoundData * Audio::getRecordedData()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
love::sound::SoundData * Audio::stopRecording(bool)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Audio::canRecord()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // null
|
||||
} // audio
|
||||
|
||||
@@ -68,6 +68,11 @@ namespace null
|
||||
void setOrientation(float * v);
|
||||
void getVelocity(float * v) const;
|
||||
void setVelocity(float * v);
|
||||
|
||||
void record();
|
||||
love::sound::SoundData * getRecordedData();
|
||||
love::sound::SoundData * stopRecording(bool returnData);
|
||||
bool canRecord();
|
||||
|
||||
}; // Audio
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "Audio.h"
|
||||
|
||||
#include <sound/Decoder.h>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
@@ -44,6 +46,14 @@ namespace openal
|
||||
|
||||
if(alcGetError(device) != ALC_NO_ERROR)
|
||||
throw love::Exception("Could not make context current.");
|
||||
|
||||
capture = alcCaptureOpenDevice(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
|
||||
love::sound::Decoder::DEFAULT_SAMPLE_RATE, AL_FORMAT_MONO16, 1048576); // about 23 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 = new Pool();
|
||||
@@ -61,6 +71,7 @@ namespace openal
|
||||
|
||||
alcMakeContextCurrent(0);
|
||||
alcDestroyContext(context);
|
||||
alcCaptureCloseDevice(capture);
|
||||
alcCloseDevice(device);
|
||||
}
|
||||
|
||||
@@ -188,6 +199,41 @@ namespace openal
|
||||
{
|
||||
alListenerfv(AL_VELOCITY, v);
|
||||
}
|
||||
|
||||
void Audio::record()
|
||||
{
|
||||
if (!canRecord()) return;
|
||||
alcCaptureStart(capture);
|
||||
}
|
||||
|
||||
love::sound::SoundData * Audio::getRecordedData()
|
||||
{
|
||||
if (!canRecord()) return NULL;
|
||||
int samplerate = love::sound::Decoder::DEFAULT_SAMPLE_RATE;
|
||||
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);
|
||||
}
|
||||
|
||||
} // openal
|
||||
} // audio
|
||||
|
||||
@@ -59,6 +59,9 @@ namespace openal
|
||||
|
||||
// The OpenAL device.
|
||||
ALCdevice * device;
|
||||
|
||||
// The OpenAL capture device (microphone).
|
||||
ALCdevice * capture;
|
||||
|
||||
// The OpenAL context.
|
||||
ALCcontext * context;
|
||||
@@ -107,6 +110,11 @@ namespace openal
|
||||
void setOrientation(float * v);
|
||||
void getVelocity(float * v) const;
|
||||
void setVelocity(float * v);
|
||||
|
||||
void record();
|
||||
love::sound::SoundData * getRecordedData();
|
||||
love::sound::SoundData * stopRecording(bool returnData);
|
||||
bool canRecord();
|
||||
|
||||
}; // Audio
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#include <scripts/audio.lua.h>
|
||||
|
||||
#include <common/runtime.h>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
@@ -200,6 +202,36 @@ namespace audio
|
||||
lua_pushnumber(L, v[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
int w_record(lua_State *)
|
||||
{
|
||||
instance->record();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getRecordedData(lua_State * L)
|
||||
{
|
||||
love::sound::SoundData * sd = instance->getRecordedData();
|
||||
luax_newtype(L, "SoundData", SOUND_SOUND_DATA_T, (void*)sd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_stopRecording(lua_State * L)
|
||||
{
|
||||
if (luax_optboolean(L, 1, true)) {
|
||||
love::sound::SoundData * sd = instance->stopRecording(true);
|
||||
luax_newtype(L, "SoundData", SOUND_SOUND_DATA_T, (void*)sd);
|
||||
return 1;
|
||||
}
|
||||
instance->stopRecording(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_canRecord(lua_State * L) {
|
||||
luax_pushboolean(L, instance->canRecord());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// List of functions to wrap.
|
||||
static const luaL_Reg functions[] = {
|
||||
@@ -218,6 +250,9 @@ namespace audio
|
||||
{ "getOrientation", w_getOrientation },
|
||||
{ "setVelocity", w_setVelocity },
|
||||
{ "getVelocity", w_getVelocity },
|
||||
{ "record", w_record },
|
||||
{ "getRecordedData", w_getRecordedData },
|
||||
{ "stopRecording", w_stopRecording },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@@ -230,47 +265,47 @@ namespace audio
|
||||
{
|
||||
if(instance == 0)
|
||||
{
|
||||
// Try OpenAL first.
|
||||
try
|
||||
{
|
||||
instance = new love::audio::openal::Audio();
|
||||
}
|
||||
catch(love::Exception & e)
|
||||
{
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
// Try OpenAL first.
|
||||
try
|
||||
{
|
||||
instance = new love::audio::openal::Audio();
|
||||
}
|
||||
catch(love::Exception & e)
|
||||
{
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
instance->retain();
|
||||
|
||||
if(instance == 0)
|
||||
{
|
||||
// Fall back to nullaudio.
|
||||
try
|
||||
{
|
||||
instance = new love::audio::null::Audio();
|
||||
}
|
||||
catch(love::Exception & e)
|
||||
{
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if(instance == 0)
|
||||
instance->retain();
|
||||
|
||||
if(instance == 0)
|
||||
{
|
||||
// Fall back to nullaudio.
|
||||
try
|
||||
{
|
||||
instance = new love::audio::null::Audio();
|
||||
}
|
||||
catch(love::Exception & e)
|
||||
{
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if(instance == 0)
|
||||
return luaL_error(L, "Could not open any audio module.");
|
||||
|
||||
WrappedModule w;
|
||||
w.module = instance;
|
||||
w.name = "audio";
|
||||
w.flags = MODULE_T;
|
||||
w.functions = functions;
|
||||
w.types = types;
|
||||
|
||||
luax_register_module(L, w);
|
||||
|
||||
if (luaL_loadbuffer(L, (const char *)audio_lua, sizeof(audio_lua), "audio.lua") == 0)
|
||||
lua_call(L, 0, 0);
|
||||
|
||||
WrappedModule w;
|
||||
w.module = instance;
|
||||
w.name = "audio";
|
||||
w.flags = MODULE_T;
|
||||
w.functions = functions;
|
||||
w.types = types;
|
||||
|
||||
luax_register_module(L, w);
|
||||
|
||||
if (luaL_loadbuffer(L, (const char *)audio_lua, sizeof(audio_lua), "audio.lua") == 0)
|
||||
lua_call(L, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@ namespace audio
|
||||
int w_getOrientation(lua_State * L);
|
||||
int w_setVelocity(lua_State * L);
|
||||
int w_getVelocity(lua_State * L);
|
||||
int w_record(lua_State * L);
|
||||
int w_getRecordedData(lua_State * L);
|
||||
int w_stopRecording(lua_State * L);
|
||||
int w_canRecord(lua_State * L);
|
||||
extern "C" LOVE_EXPORT int luaopen_love_audio(lua_State * L);
|
||||
|
||||
} // audio
|
||||
|
||||
Reference in New Issue
Block a user