mirror of
https://github.com/love2d/love.git
synced 2026-08-20 04:30:09 +02:00
Merged in rcoaxil/love-patches/minor-mic-input (pull request #68)
Microphone input implemented. --HG-- branch : minor
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
virtual const std::vector<RecordingDevice*> &getRecordingDevices() = 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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the distance model used for attenuation.
|
* Gets the distance model used for attenuation.
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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()
|
||||||
{
|
{
|
||||||
}
|
return capture;
|
||||||
|
|
||||||
love::sound::SoundData *Audio::getRecordedData()
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
love::sound::SoundData *Audio::stopRecording(bool)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Audio::canRecord()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Audio::DistanceModel Audio::getDistanceModel() const
|
Audio::DistanceModel Audio::getDistanceModel() const
|
||||||
|
|||||||
@@ -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();
|
const std::vector<love::audio::RecordingDevice*> &getRecordingDevices();
|
||||||
love::sound::SoundData *getRecordedData();
|
|
||||||
love::sound::SoundData *stopRecording(bool returnData);
|
|
||||||
bool canRecord();
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
const std::vector<love::audio::RecordingDevice*> &getRecordingDevices();
|
||||||
love::sound::SoundData *getRecordedData();
|
|
||||||
love::sound::SoundData *stopRecording(bool returnData);
|
|
||||||
bool canRecord();
|
|
||||||
|
|
||||||
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).
|
// The OpenAL capture devices.
|
||||||
ALCdevice *capture;
|
std::vector<love::audio::RecordingDevice*> capture;
|
||||||
|
|
||||||
// The OpenAL context.
|
// The OpenAL context.
|
||||||
ALCcontext *context;
|
ALCcontext *context;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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());
|
ALenum fmt = Audio::getFormat(soundData->getBitDepth(), soundData->getChannels());
|
||||||
if (fmt == 0)
|
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);
|
ALenum fmt = Audio::getFormat(bitDepth, channels);
|
||||||
if (fmt == 0)
|
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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
Reference in New Issue
Block a user