mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user