mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
317 lines
6.1 KiB
C++
317 lines
6.1 KiB
C++
/**
|
|
* Copyright (c) 2006-2011 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 "Audio.h"
|
|
#include <common/delay.h>
|
|
|
|
#include <sound/Decoder.h>
|
|
|
|
namespace love
|
|
{
|
|
namespace audio
|
|
{
|
|
namespace openal
|
|
{
|
|
Audio::PoolThread::PoolThread(Pool* pool)
|
|
: pool(pool), finish(false)
|
|
{
|
|
}
|
|
|
|
void Audio::PoolThread::main()
|
|
{
|
|
while (true)
|
|
{
|
|
{
|
|
thread::Lock lock(mutex);
|
|
if (finish)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
pool->update();
|
|
delay(5);
|
|
}
|
|
}
|
|
|
|
void Audio::PoolThread::setFinish()
|
|
{
|
|
thread::Lock lock(mutex);
|
|
finish = true;
|
|
}
|
|
|
|
|
|
Audio::Audio() : distanceModel(DISTANCE_INVERSE_CLAMPED)
|
|
{
|
|
// Passing zero for default device.
|
|
device = alcOpenDevice(0);
|
|
|
|
if (device == 0)
|
|
throw love::Exception("Could not open device.");
|
|
|
|
context = alcCreateContext(device, 0);
|
|
|
|
if (context == 0)
|
|
throw love::Exception("Could not create context.");
|
|
|
|
alcMakeContextCurrent(context);
|
|
|
|
if (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)
|
|
{
|
|
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 = new Pool();
|
|
|
|
poolThread = new PoolThread(pool);
|
|
poolThread->start();
|
|
}
|
|
|
|
Audio::~Audio()
|
|
{
|
|
poolThread->setFinish();
|
|
poolThread->wait();
|
|
|
|
delete poolThread;
|
|
delete pool;
|
|
|
|
alcMakeContextCurrent(0);
|
|
alcDestroyContext(context);
|
|
//if (capture) alcCaptureCloseDevice(capture);
|
|
alcCloseDevice(device);
|
|
}
|
|
|
|
|
|
const char * Audio::getName() const
|
|
{
|
|
return "love.audio.openal";
|
|
}
|
|
|
|
love::audio::Source * Audio::newSource(love::sound::Decoder * decoder)
|
|
{
|
|
return new Source(pool, decoder);
|
|
}
|
|
|
|
love::audio::Source * Audio::newSource(love::sound::SoundData * soundData)
|
|
{
|
|
return new Source(pool, soundData);
|
|
}
|
|
|
|
int Audio::getNumSources() const
|
|
{
|
|
return pool->getNumSources();
|
|
}
|
|
|
|
int Audio::getMaxSources() const
|
|
{
|
|
return pool->getMaxSources();
|
|
}
|
|
|
|
void Audio::play(love::audio::Source * source)
|
|
{
|
|
source->play();
|
|
}
|
|
|
|
void Audio::stop(love::audio::Source * source)
|
|
{
|
|
source->stop();
|
|
}
|
|
|
|
void Audio::stop()
|
|
{
|
|
pool->stop();
|
|
}
|
|
|
|
void Audio::pause(love::audio::Source * source)
|
|
{
|
|
source->pause();
|
|
}
|
|
|
|
void Audio::pause()
|
|
{
|
|
pool->pause();
|
|
}
|
|
|
|
void Audio::resume(love::audio::Source * source)
|
|
{
|
|
source->resume();
|
|
}
|
|
|
|
void Audio::resume()
|
|
{
|
|
pool->resume();
|
|
}
|
|
|
|
void Audio::rewind(love::audio::Source * source)
|
|
{
|
|
source->rewind();
|
|
}
|
|
|
|
void Audio::rewind()
|
|
{
|
|
pool->rewind();
|
|
}
|
|
|
|
void Audio::setVolume(float volume)
|
|
{
|
|
alListenerf(AL_GAIN, volume);
|
|
}
|
|
|
|
float Audio::getVolume() const
|
|
{
|
|
ALfloat volume;
|
|
alGetListenerf(AL_GAIN, &volume);
|
|
return volume;
|
|
}
|
|
|
|
void Audio::getPosition(float * v) const
|
|
{
|
|
alGetListenerfv(AL_POSITION, v);
|
|
}
|
|
|
|
void Audio::setPosition(float * v)
|
|
{
|
|
alListenerfv(AL_POSITION, v);
|
|
}
|
|
|
|
void Audio::getOrientation(float * v) const
|
|
{
|
|
alGetListenerfv(AL_ORIENTATION, v);
|
|
}
|
|
|
|
void Audio::setOrientation(float * v)
|
|
{
|
|
alListenerfv(AL_ORIENTATION, v);
|
|
}
|
|
|
|
void Audio::getVelocity(float * v) const
|
|
{
|
|
alGetListenerfv(AL_VELOCITY, v);
|
|
}
|
|
|
|
void Audio::setVelocity(float * v)
|
|
{
|
|
alListenerfv(AL_VELOCITY, v);
|
|
}
|
|
|
|
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 this->distanceModel;
|
|
}
|
|
|
|
void Audio::setDistanceModel(DistanceModel distanceModel)
|
|
{
|
|
this->distanceModel = distanceModel;
|
|
|
|
switch (distanceModel)
|
|
{
|
|
case DISTANCE_NONE:
|
|
alDistanceModel(AL_NONE);
|
|
break;
|
|
|
|
case DISTANCE_INVERSE:
|
|
alDistanceModel(AL_INVERSE_DISTANCE);
|
|
break;
|
|
|
|
case DISTANCE_INVERSE_CLAMPED:
|
|
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
|
|
break;
|
|
|
|
case DISTANCE_LINEAR:
|
|
alDistanceModel(AL_LINEAR_DISTANCE);
|
|
break;
|
|
|
|
case DISTANCE_LINEAR_CLAMPED:
|
|
alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
|
|
break;
|
|
|
|
case DISTANCE_EXPONENT:
|
|
alDistanceModel(AL_EXPONENT_DISTANCE);
|
|
break;
|
|
|
|
case DISTANCE_EXPONENT_CLAMPED:
|
|
alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} // openal
|
|
} // audio
|
|
} // love
|