mirror of
https://github.com/love2d/love.git
synced 2026-08-19 04:06:17 +02:00
Added sound input and recording functionality.
This commit is contained in:
@@ -49,14 +49,14 @@ namespace audio
|
|||||||
virtual Source * newSource(love::sound::SoundData * soundData) = 0;
|
virtual Source * newSource(love::sound::SoundData * soundData) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current number of simulatenous playing sources.
|
* Gets the current number of simultaneous playing sources.
|
||||||
* @return The current number of simulatenous playing sources.
|
* @return The current number of simultaneous playing sources.
|
||||||
**/
|
**/
|
||||||
virtual int getNumSources() const = 0;
|
virtual int getNumSources() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the maximum supported number of simulatenous playing sources.
|
* Gets the maximum supported number of simultaneous playing sources.
|
||||||
* @return The maximum supported number of simulatenous playing sources.
|
* @return The maximum supported number of simultaneous playing sources.
|
||||||
**/
|
**/
|
||||||
virtual int getMaxSources() const = 0;
|
virtual int getMaxSources() const = 0;
|
||||||
|
|
||||||
@@ -161,6 +161,36 @@ namespace audio
|
|||||||
**/
|
**/
|
||||||
virtual void setVelocity(float * v) = 0;
|
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
|
||||||
|
|
||||||
} // audio
|
} // audio
|
||||||
|
|||||||
@@ -133,6 +133,25 @@ namespace null
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Audio::record()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
love::sound::SoundData * Audio::getRecordedData()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
love::sound::SoundData * Audio::stopRecording(bool)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Audio::canRecord()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // null
|
} // null
|
||||||
} // audio
|
} // audio
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ namespace null
|
|||||||
void getVelocity(float * v) const;
|
void getVelocity(float * v) const;
|
||||||
void setVelocity(float * v);
|
void setVelocity(float * v);
|
||||||
|
|
||||||
|
void record();
|
||||||
|
love::sound::SoundData * getRecordedData();
|
||||||
|
love::sound::SoundData * stopRecording(bool returnData);
|
||||||
|
bool canRecord();
|
||||||
|
|
||||||
}; // Audio
|
}; // Audio
|
||||||
|
|
||||||
} // null
|
} // null
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include "Audio.h"
|
#include "Audio.h"
|
||||||
|
|
||||||
|
#include <sound/Decoder.h>
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
@@ -45,6 +47,14 @@ namespace openal
|
|||||||
if(alcGetError(device) != ALC_NO_ERROR)
|
if(alcGetError(device) != ALC_NO_ERROR)
|
||||||
throw love::Exception("Could not make context current.");
|
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 must be allocated after AL context.
|
||||||
pool = new Pool();
|
pool = new Pool();
|
||||||
|
|
||||||
@@ -61,6 +71,7 @@ namespace openal
|
|||||||
|
|
||||||
alcMakeContextCurrent(0);
|
alcMakeContextCurrent(0);
|
||||||
alcDestroyContext(context);
|
alcDestroyContext(context);
|
||||||
|
alcCaptureCloseDevice(capture);
|
||||||
alcCloseDevice(device);
|
alcCloseDevice(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +200,41 @@ namespace openal
|
|||||||
alListenerfv(AL_VELOCITY, v);
|
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
|
} // openal
|
||||||
} // audio
|
} // audio
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ namespace openal
|
|||||||
// The OpenAL device.
|
// The OpenAL device.
|
||||||
ALCdevice * device;
|
ALCdevice * device;
|
||||||
|
|
||||||
|
// The OpenAL capture device (microphone).
|
||||||
|
ALCdevice * capture;
|
||||||
|
|
||||||
// The OpenAL context.
|
// The OpenAL context.
|
||||||
ALCcontext * context;
|
ALCcontext * context;
|
||||||
|
|
||||||
@@ -108,6 +111,11 @@ namespace openal
|
|||||||
void getVelocity(float * v) const;
|
void getVelocity(float * v) const;
|
||||||
void setVelocity(float * v);
|
void setVelocity(float * v);
|
||||||
|
|
||||||
|
void record();
|
||||||
|
love::sound::SoundData * getRecordedData();
|
||||||
|
love::sound::SoundData * stopRecording(bool returnData);
|
||||||
|
bool canRecord();
|
||||||
|
|
||||||
}; // Audio
|
}; // Audio
|
||||||
|
|
||||||
} // openal
|
} // openal
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include <scripts/audio.lua.h>
|
#include <scripts/audio.lua.h>
|
||||||
|
|
||||||
|
#include <common/runtime.h>
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
@@ -201,6 +203,36 @@ namespace audio
|
|||||||
return 3;
|
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.
|
// List of functions to wrap.
|
||||||
static const luaL_Reg functions[] = {
|
static const luaL_Reg functions[] = {
|
||||||
{ "getNumSources", w_getNumSources },
|
{ "getNumSources", w_getNumSources },
|
||||||
@@ -218,6 +250,9 @@ namespace audio
|
|||||||
{ "getOrientation", w_getOrientation },
|
{ "getOrientation", w_getOrientation },
|
||||||
{ "setVelocity", w_setVelocity },
|
{ "setVelocity", w_setVelocity },
|
||||||
{ "getVelocity", w_getVelocity },
|
{ "getVelocity", w_getVelocity },
|
||||||
|
{ "record", w_record },
|
||||||
|
{ "getRecordedData", w_getRecordedData },
|
||||||
|
{ "stopRecording", w_stopRecording },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ namespace audio
|
|||||||
int w_getOrientation(lua_State * L);
|
int w_getOrientation(lua_State * L);
|
||||||
int w_setVelocity(lua_State * L);
|
int w_setVelocity(lua_State * L);
|
||||||
int w_getVelocity(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);
|
extern "C" LOVE_EXPORT int luaopen_love_audio(lua_State * L);
|
||||||
|
|
||||||
} // audio
|
} // audio
|
||||||
|
|||||||
@@ -64,6 +64,13 @@ namespace sound
|
|||||||
data = (char*)malloc(size);
|
data = (char*)malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SoundData::SoundData(void * d, int samples, int sampleRate, int bits, int channels)
|
||||||
|
: data(0), size(samples*(bits/8)), sampleRate(sampleRate), bits(bits), channels(channels)
|
||||||
|
{
|
||||||
|
data = (char*)malloc(size);
|
||||||
|
memcpy(data, d, size);
|
||||||
|
}
|
||||||
|
|
||||||
SoundData::~SoundData()
|
SoundData::~SoundData()
|
||||||
{
|
{
|
||||||
if(data != 0)
|
if(data != 0)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ namespace sound
|
|||||||
|
|
||||||
SoundData(Decoder * decoder);
|
SoundData(Decoder * decoder);
|
||||||
SoundData(int samples, int sampleRate, int bits, int channels);
|
SoundData(int samples, int sampleRate, int bits, int channels);
|
||||||
|
SoundData(void * d, int samples, int sampleRate, int bits, int channels);
|
||||||
|
|
||||||
virtual ~SoundData();
|
virtual ~SoundData();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user