3D Audio GSoC:

- Implemented a nice rechanneling solution with unofficial speaker arrangement standards similar to what OpenAL soft has
- Renamend AUD_Channel in the C API to AUD_Handle
- Removed the unlogical 7.2 speaker configuration, that's a hardware only config
This commit is contained in:
Joerg Mueller 2011-06-21 20:24:40 +00:00
parent 044887b5a4
commit c89b4e4b66
10 changed files with 393 additions and 219 deletions

@ -90,7 +90,7 @@ extern "C" {
typedef AUD_Reference<AUD_IFactory> AUD_Sound; typedef AUD_Reference<AUD_IFactory> AUD_Sound;
typedef AUD_Reference<AUD_ReadDevice> AUD_Device; typedef AUD_Reference<AUD_ReadDevice> AUD_Device;
typedef AUD_Reference<AUD_IHandle> AUD_Channel; typedef AUD_Reference<AUD_IHandle> AUD_Handle;
typedef AUD_Reference<AUD_SequencerEntry> AUD_SEntry; typedef AUD_Reference<AUD_SequencerEntry> AUD_SEntry;
#define AUD_CAPI_IMPLEMENTATION #define AUD_CAPI_IMPLEMENTATION
@ -374,7 +374,7 @@ AUD_Sound* AUD_loopSound(AUD_Sound* sound)
} }
} }
int AUD_setLoop(AUD_Channel* handle, int loops) int AUD_setLoop(AUD_Handle* handle, int loops)
{ {
assert(handle); assert(handle);
@ -409,14 +409,14 @@ void AUD_unload(AUD_Sound* sound)
delete sound; delete sound;
} }
AUD_Channel* AUD_play(AUD_Sound* sound, int keep) AUD_Handle* AUD_play(AUD_Sound* sound, int keep)
{ {
assert(sound); assert(sound);
try try
{ {
AUD_Channel channel = AUD_device->play(*sound, keep); AUD_Handle handle = AUD_device->play(*sound, keep);
if(!channel.isNull()) if(!handle.isNull())
return new AUD_Channel(channel); return new AUD_Handle(handle);
} }
catch(AUD_Exception&) catch(AUD_Exception&)
{ {
@ -424,19 +424,19 @@ AUD_Channel* AUD_play(AUD_Sound* sound, int keep)
return NULL; return NULL;
} }
int AUD_pause(AUD_Channel* handle) int AUD_pause(AUD_Handle* handle)
{ {
assert(handle); assert(handle);
return (*handle)->pause(); return (*handle)->pause();
} }
int AUD_resume(AUD_Channel* handle) int AUD_resume(AUD_Handle* handle)
{ {
assert(handle); assert(handle);
return (*handle)->resume(); return (*handle)->resume();
} }
int AUD_stop(AUD_Channel* handle) int AUD_stop(AUD_Handle* handle)
{ {
assert(handle); assert(handle);
int result = (*handle)->stop(); int result = (*handle)->stop();
@ -444,25 +444,25 @@ int AUD_stop(AUD_Channel* handle)
return result; return result;
} }
int AUD_setKeep(AUD_Channel* handle, int keep) int AUD_setKeep(AUD_Handle* handle, int keep)
{ {
assert(handle); assert(handle);
return (*handle)->setKeep(keep); return (*handle)->setKeep(keep);
} }
int AUD_seek(AUD_Channel* handle, float seekTo) int AUD_seek(AUD_Handle* handle, float seekTo)
{ {
assert(handle); assert(handle);
return (*handle)->seek(seekTo); return (*handle)->seek(seekTo);
} }
float AUD_getPosition(AUD_Channel* handle) float AUD_getPosition(AUD_Handle* handle)
{ {
assert(handle); assert(handle);
return (*handle)->getPosition(); return (*handle)->getPosition();
} }
AUD_Status AUD_getStatus(AUD_Channel* handle) AUD_Status AUD_getStatus(AUD_Handle* handle)
{ {
assert(handle); assert(handle);
return (*handle)->getStatus(); return (*handle)->getStatus();
@ -537,7 +537,7 @@ int AUD_setDistanceModel(AUD_DistanceModel model)
return false; return false;
} }
int AUD_setSourceLocation(AUD_Channel* handle, const float* location) int AUD_setSourceLocation(AUD_Handle* handle, const float* location)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -551,7 +551,7 @@ int AUD_setSourceLocation(AUD_Channel* handle, const float* location)
return false; return false;
} }
int AUD_setSourceVelocity(AUD_Channel* handle, const float* velocity) int AUD_setSourceVelocity(AUD_Handle* handle, const float* velocity)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -565,7 +565,7 @@ int AUD_setSourceVelocity(AUD_Channel* handle, const float* velocity)
return false; return false;
} }
int AUD_setSourceOrientation(AUD_Channel* handle, const float* orientation) int AUD_setSourceOrientation(AUD_Handle* handle, const float* orientation)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -579,7 +579,7 @@ int AUD_setSourceOrientation(AUD_Channel* handle, const float* orientation)
return false; return false;
} }
int AUD_setRelative(AUD_Channel* handle, int relative) int AUD_setRelative(AUD_Handle* handle, int relative)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -592,7 +592,7 @@ int AUD_setRelative(AUD_Channel* handle, int relative)
return false; return false;
} }
int AUD_setVolumeMaximum(AUD_Channel* handle, float volume) int AUD_setVolumeMaximum(AUD_Handle* handle, float volume)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -605,7 +605,7 @@ int AUD_setVolumeMaximum(AUD_Channel* handle, float volume)
return false; return false;
} }
int AUD_setVolumeMinimum(AUD_Channel* handle, float volume) int AUD_setVolumeMinimum(AUD_Handle* handle, float volume)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -618,7 +618,7 @@ int AUD_setVolumeMinimum(AUD_Channel* handle, float volume)
return false; return false;
} }
int AUD_setDistanceMaximum(AUD_Channel* handle, float distance) int AUD_setDistanceMaximum(AUD_Handle* handle, float distance)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -631,7 +631,7 @@ int AUD_setDistanceMaximum(AUD_Channel* handle, float distance)
return false; return false;
} }
int AUD_setDistanceReference(AUD_Channel* handle, float distance) int AUD_setDistanceReference(AUD_Handle* handle, float distance)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -644,7 +644,7 @@ int AUD_setDistanceReference(AUD_Channel* handle, float distance)
return false; return false;
} }
int AUD_setAttenuation(AUD_Channel* handle, float factor) int AUD_setAttenuation(AUD_Handle* handle, float factor)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -657,7 +657,7 @@ int AUD_setAttenuation(AUD_Channel* handle, float factor)
return false; return false;
} }
int AUD_setConeAngleOuter(AUD_Channel* handle, float angle) int AUD_setConeAngleOuter(AUD_Handle* handle, float angle)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -670,7 +670,7 @@ int AUD_setConeAngleOuter(AUD_Channel* handle, float angle)
return false; return false;
} }
int AUD_setConeAngleInner(AUD_Channel* handle, float angle) int AUD_setConeAngleInner(AUD_Handle* handle, float angle)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -683,7 +683,7 @@ int AUD_setConeAngleInner(AUD_Channel* handle, float angle)
return false; return false;
} }
int AUD_setConeVolumeOuter(AUD_Channel* handle, float volume) int AUD_setConeVolumeOuter(AUD_Handle* handle, float volume)
{ {
assert(handle); assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle); AUD_Reference<AUD_I3DHandle> h(*handle);
@ -696,7 +696,7 @@ int AUD_setConeVolumeOuter(AUD_Channel* handle, float volume)
return false; return false;
} }
int AUD_setSoundVolume(AUD_Channel* handle, float volume) int AUD_setSoundVolume(AUD_Handle* handle, float volume)
{ {
assert(handle); assert(handle);
try try
@ -707,7 +707,7 @@ int AUD_setSoundVolume(AUD_Channel* handle, float volume)
return false; return false;
} }
int AUD_setSoundPitch(AUD_Channel* handle, float pitch) int AUD_setSoundPitch(AUD_Handle* handle, float pitch)
{ {
assert(handle); assert(handle);
try try
@ -730,18 +730,18 @@ AUD_Device* AUD_openReadDevice(AUD_DeviceSpecs specs)
} }
} }
AUD_Channel* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek) AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek)
{ {
assert(device); assert(device);
assert(sound); assert(sound);
try try
{ {
AUD_Channel channel = (*device)->play(*sound); AUD_Handle handle = (*device)->play(*sound);
if(!channel.isNull()) if(!handle.isNull())
{ {
channel->seek(seek); handle->seek(seek);
return new AUD_Channel(channel); return new AUD_Handle(handle);
} }
} }
catch(AUD_Exception&) catch(AUD_Exception&)
@ -848,13 +848,13 @@ float* AUD_readSoundBuffer(const char* filename, float low, float high,
return result; return result;
} }
static void pauseSound(AUD_Channel* handle) static void pauseSound(AUD_Handle* handle)
{ {
assert(handle); assert(handle);
(*handle)->pause(); (*handle)->pause();
} }
AUD_Channel* AUD_pauseAfter(AUD_Channel* handle, float seconds) AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, float seconds)
{ {
AUD_Reference<AUD_IFactory> silence = new AUD_SilenceFactory; AUD_Reference<AUD_IFactory> silence = new AUD_SilenceFactory;
AUD_Reference<AUD_IFactory> limiter = new AUD_LimiterFactory(silence, 0, seconds); AUD_Reference<AUD_IFactory> limiter = new AUD_LimiterFactory(silence, 0, seconds);
@ -863,12 +863,12 @@ AUD_Channel* AUD_pauseAfter(AUD_Channel* handle, float seconds)
try try
{ {
AUD_Channel channel = AUD_device->play(limiter); AUD_Handle handle2 = AUD_device->play(limiter);
if(!channel.isNull()) if(!handle2.isNull())
{ {
channel->setStopCallback((stopCallback)pauseSound, handle); handle2->setStopCallback((stopCallback)pauseSound, handle);
AUD_device->unlock(); AUD_device->unlock();
return new AUD_Channel(channel); return new AUD_Handle(handle2);
} }
} }
catch(AUD_Exception&) catch(AUD_Exception&)
@ -996,7 +996,7 @@ void AUD_stopPlayback()
#endif #endif
} }
void AUD_seekSequencer(AUD_Channel* handle, float time) void AUD_seekSequencer(AUD_Handle* handle, float time)
{ {
#ifdef WITH_JACK #ifdef WITH_JACK
AUD_JackDevice* device = dynamic_cast<AUD_JackDevice*>(AUD_device.get()); AUD_JackDevice* device = dynamic_cast<AUD_JackDevice*>(AUD_device.get());
@ -1010,7 +1010,7 @@ void AUD_seekSequencer(AUD_Channel* handle, float time)
} }
} }
float AUD_getSequencerPosition(AUD_Channel* handle) float AUD_getSequencerPosition(AUD_Handle* handle)
{ {
#ifdef WITH_JACK #ifdef WITH_JACK
AUD_JackDevice* device = dynamic_cast<AUD_JackDevice*>(AUD_device.get()); AUD_JackDevice* device = dynamic_cast<AUD_JackDevice*>(AUD_device.get());
@ -1048,7 +1048,7 @@ AUD_Sound* AUD_copy(AUD_Sound* sound)
return new AUD_Reference<AUD_IFactory>(*sound); return new AUD_Reference<AUD_IFactory>(*sound);
} }
void AUD_freeChannel(AUD_Channel* channel) void AUD_freeHandle(AUD_Handle* handle)
{ {
delete channel; delete handle;
} }

@ -57,7 +57,7 @@ typedef struct
#ifndef AUD_CAPI_IMPLEMENTATION #ifndef AUD_CAPI_IMPLEMENTATION
typedef void AUD_Sound; typedef void AUD_Sound;
typedef void AUD_Channel; typedef void AUD_Handle;
typedef void AUD_Device; typedef void AUD_Device;
typedef void AUD_SEntry; typedef void AUD_SEntry;
typedef float (*AUD_volumeFunction)(void*, void*, float); typedef float (*AUD_volumeFunction)(void*, void*, float);
@ -159,7 +159,7 @@ extern AUD_Sound* AUD_loopSound(AUD_Sound* sound);
* \param loops The count of remaining loops, -1 for infinity. * \param loops The count of remaining loops, -1 for infinity.
* \return Whether the handle is valid. * \return Whether the handle is valid.
*/ */
extern int AUD_setLoop(AUD_Channel* handle, int loops); extern int AUD_setLoop(AUD_Handle* handle, int loops);
/** /**
* Rectifies a sound. * Rectifies a sound.
@ -181,28 +181,28 @@ extern void AUD_unload(AUD_Sound* sound);
* paused when its end has been reached. * paused when its end has been reached.
* \return A handle to the played back sound. * \return A handle to the played back sound.
*/ */
extern AUD_Channel* AUD_play(AUD_Sound* sound, int keep); extern AUD_Handle* AUD_play(AUD_Sound* sound, int keep);
/** /**
* Pauses a played back sound. * Pauses a played back sound.
* \param handle The handle to the sound. * \param handle The handle to the sound.
* \return Whether the handle has been playing or not. * \return Whether the handle has been playing or not.
*/ */
extern int AUD_pause(AUD_Channel* handle); extern int AUD_pause(AUD_Handle* handle);
/** /**
* Resumes a paused sound. * Resumes a paused sound.
* \param handle The handle to the sound. * \param handle The handle to the sound.
* \return Whether the handle has been paused or not. * \return Whether the handle has been paused or not.
*/ */
extern int AUD_resume(AUD_Channel* handle); extern int AUD_resume(AUD_Handle* handle);
/** /**
* Stops a playing or paused sound. * Stops a playing or paused sound.
* \param handle The handle to the sound. * \param handle The handle to the sound.
* \return Whether the handle has been valid or not. * \return Whether the handle has been valid or not.
*/ */
extern int AUD_stop(AUD_Channel* handle); extern int AUD_stop(AUD_Handle* handle);
/** /**
* Sets the end behaviour of a playing or paused sound. * Sets the end behaviour of a playing or paused sound.
@ -211,7 +211,7 @@ extern int AUD_stop(AUD_Channel* handle);
* paused when its end has been reached. * paused when its end has been reached.
* \return Whether the handle has been valid or not. * \return Whether the handle has been valid or not.
*/ */
extern int AUD_setKeep(AUD_Channel* handle, int keep); extern int AUD_setKeep(AUD_Handle* handle, int keep);
/** /**
* Seeks a playing or paused sound. * Seeks a playing or paused sound.
@ -219,7 +219,7 @@ extern int AUD_setKeep(AUD_Channel* handle, int keep);
* \param seekTo From where the sound file should be played back in seconds. * \param seekTo From where the sound file should be played back in seconds.
* \return Whether the handle has been valid or not. * \return Whether the handle has been valid or not.
*/ */
extern int AUD_seek(AUD_Channel* handle, float seekTo); extern int AUD_seek(AUD_Handle* handle, float seekTo);
/** /**
* Retrieves the playback position of a handle. * Retrieves the playback position of a handle.
@ -227,14 +227,14 @@ extern int AUD_seek(AUD_Channel* handle, float seekTo);
* \return The current playback position in seconds or 0.0 if the handle is * \return The current playback position in seconds or 0.0 if the handle is
* invalid. * invalid.
*/ */
extern float AUD_getPosition(AUD_Channel* handle); extern float AUD_getPosition(AUD_Handle* handle);
/** /**
* Returns the status of a playing, paused or stopped sound. * Returns the status of a playing, paused or stopped sound.
* \param handle The handle to the sound. * \param handle The handle to the sound.
* \return The status of the sound behind the handle. * \return The status of the sound behind the handle.
*/ */
extern AUD_Status AUD_getStatus(AUD_Channel* handle); extern AUD_Status AUD_getStatus(AUD_Handle* handle);
/** /**
* Sets the listener location. * Sets the listener location.
@ -281,7 +281,7 @@ extern int AUD_setDistanceModel(AUD_DistanceModel model);
* \param location The new location. * \param location The new location.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSourceLocation(AUD_Channel* handle, const float* location); extern int AUD_setSourceLocation(AUD_Handle* handle, const float* location);
/** /**
* Sets the velocity of a source. * Sets the velocity of a source.
@ -289,7 +289,7 @@ extern int AUD_setSourceLocation(AUD_Channel* handle, const float* location);
* \param velocity The new velocity. * \param velocity The new velocity.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSourceVelocity(AUD_Channel* handle, const float* velocity); extern int AUD_setSourceVelocity(AUD_Handle* handle, const float* velocity);
/** /**
* Sets the orientation of a source. * Sets the orientation of a source.
@ -297,7 +297,7 @@ extern int AUD_setSourceVelocity(AUD_Channel* handle, const float* velocity);
* \param orientation The new orientation as quaternion. * \param orientation The new orientation as quaternion.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSourceOrientation(AUD_Channel* handle, const float* orientation); extern int AUD_setSourceOrientation(AUD_Handle* handle, const float* orientation);
/** /**
* Sets whether the source location, velocity and orientation are relative * Sets whether the source location, velocity and orientation are relative
@ -306,7 +306,7 @@ extern int AUD_setSourceOrientation(AUD_Channel* handle, const float* orientatio
* \param relative Whether the source is relative. * \param relative Whether the source is relative.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setRelative(AUD_Channel* handle, int relative); extern int AUD_setRelative(AUD_Handle* handle, int relative);
/** /**
* Sets the maximum volume of a source. * Sets the maximum volume of a source.
@ -314,7 +314,7 @@ extern int AUD_setRelative(AUD_Channel* handle, int relative);
* \param volume The new maximum volume. * \param volume The new maximum volume.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setVolumeMaximum(AUD_Channel* handle, float volume); extern int AUD_setVolumeMaximum(AUD_Handle* handle, float volume);
/** /**
* Sets the minimum volume of a source. * Sets the minimum volume of a source.
@ -322,7 +322,7 @@ extern int AUD_setVolumeMaximum(AUD_Channel* handle, float volume);
* \param volume The new minimum volume. * \param volume The new minimum volume.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setVolumeMinimum(AUD_Channel* handle, float volume); extern int AUD_setVolumeMinimum(AUD_Handle* handle, float volume);
/** /**
* Sets the maximum distance of a source. * Sets the maximum distance of a source.
@ -332,7 +332,7 @@ extern int AUD_setVolumeMinimum(AUD_Channel* handle, float volume);
* \param distance The new maximum distance. * \param distance The new maximum distance.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setDistanceMaximum(AUD_Channel* handle, float distance); extern int AUD_setDistanceMaximum(AUD_Handle* handle, float distance);
/** /**
* Sets the reference distance of a source. * Sets the reference distance of a source.
@ -340,7 +340,7 @@ extern int AUD_setDistanceMaximum(AUD_Channel* handle, float distance);
* \param distance The new reference distance. * \param distance The new reference distance.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setDistanceReference(AUD_Channel* handle, float distance); extern int AUD_setDistanceReference(AUD_Handle* handle, float distance);
/** /**
* Sets the attenuation of a source. * Sets the attenuation of a source.
@ -349,7 +349,7 @@ extern int AUD_setDistanceReference(AUD_Channel* handle, float distance);
* \param factor The new attenuation. * \param factor The new attenuation.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setAttenuation(AUD_Channel* handle, float factor); extern int AUD_setAttenuation(AUD_Handle* handle, float factor);
/** /**
* Sets the outer angle of the cone of a source. * Sets the outer angle of the cone of a source.
@ -357,7 +357,7 @@ extern int AUD_setAttenuation(AUD_Channel* handle, float factor);
* \param angle The new outer angle of the cone. * \param angle The new outer angle of the cone.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setConeAngleOuter(AUD_Channel* handle, float angle); extern int AUD_setConeAngleOuter(AUD_Handle* handle, float angle);
/** /**
* Sets the inner angle of the cone of a source. * Sets the inner angle of the cone of a source.
@ -365,7 +365,7 @@ extern int AUD_setConeAngleOuter(AUD_Channel* handle, float angle);
* \param angle The new inner angle of the cone. * \param angle The new inner angle of the cone.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setConeAngleInner(AUD_Channel* handle, float angle); extern int AUD_setConeAngleInner(AUD_Handle* handle, float angle);
/** /**
* Sets the outer volume of the cone of a source. * Sets the outer volume of the cone of a source.
@ -375,7 +375,7 @@ extern int AUD_setConeAngleInner(AUD_Channel* handle, float angle);
* \param volume The new outer volume of the cone. * \param volume The new outer volume of the cone.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setConeVolumeOuter(AUD_Channel* handle, float volume); extern int AUD_setConeVolumeOuter(AUD_Handle* handle, float volume);
/** /**
* Sets the volume of a played back sound. * Sets the volume of a played back sound.
@ -383,7 +383,7 @@ extern int AUD_setConeVolumeOuter(AUD_Channel* handle, float volume);
* \param volume The new volume, must be between 0.0 and 1.0. * \param volume The new volume, must be between 0.0 and 1.0.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSoundVolume(AUD_Channel* handle, float volume); extern int AUD_setSoundVolume(AUD_Handle* handle, float volume);
/** /**
* Sets the pitch of a played back sound. * Sets the pitch of a played back sound.
@ -391,7 +391,7 @@ extern int AUD_setSoundVolume(AUD_Channel* handle, float volume);
* \param pitch The new pitch. * \param pitch The new pitch.
* \return Whether the action succeeded. * \return Whether the action succeeded.
*/ */
extern int AUD_setSoundPitch(AUD_Channel* handle, float pitch); extern int AUD_setSoundPitch(AUD_Handle* handle, float pitch);
/** /**
* Opens a read device, with which audio data can be read. * Opens a read device, with which audio data can be read.
@ -415,7 +415,7 @@ extern int AUD_setDeviceVolume(AUD_Device* device, float volume);
* \param seek The position where the sound should be seeked to. * \param seek The position where the sound should be seeked to.
* \return A handle to the played back sound. * \return A handle to the played back sound.
*/ */
extern AUD_Channel* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek); extern AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek);
/** /**
* Reads the next samples into the supplied buffer. * Reads the next samples into the supplied buffer.
@ -450,7 +450,7 @@ extern float* AUD_readSoundBuffer(const char* filename, float low, float high,
* \param time The time in seconds. * \param time The time in seconds.
* \return The silence handle. * \return The silence handle.
*/ */
extern AUD_Channel* AUD_pauseAfter(AUD_Channel* handle, float seconds); extern AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, float seconds);
extern AUD_Sound* AUD_createSequencer(int muted, void* data, AUD_volumeFunction volume); extern AUD_Sound* AUD_createSequencer(int muted, void* data, AUD_volumeFunction volume);
@ -475,9 +475,9 @@ extern void AUD_startPlayback(void);
extern void AUD_stopPlayback(void); extern void AUD_stopPlayback(void);
extern void AUD_seekSequencer(AUD_Channel* handle, float time); extern void AUD_seekSequencer(AUD_Handle* handle, float time);
extern float AUD_getSequencerPosition(AUD_Channel* handle); extern float AUD_getSequencerPosition(AUD_Handle* handle);
#ifdef WITH_JACK #ifdef WITH_JACK
extern void AUD_setSyncCallback(AUD_syncFunction function, void* data); extern void AUD_setSyncCallback(AUD_syncFunction function, void* data);
@ -487,7 +487,7 @@ extern int AUD_doesPlayback(void);
extern AUD_Sound* AUD_copy(AUD_Sound* sound); extern AUD_Sound* AUD_copy(AUD_Sound* sound);
extern void AUD_freeChannel(AUD_Channel* channel); extern void AUD_freeHandle(AUD_Handle* channel);
#ifdef WITH_PYTHON #ifdef WITH_PYTHON
extern PyObject* AUD_getPythonFactory(AUD_Sound* sound); extern PyObject* AUD_getPythonFactory(AUD_Sound* sound);

@ -38,75 +38,10 @@ AUD_ChannelMapperFactory::AUD_ChannelMapperFactory(AUD_Reference<AUD_IFactory> f
AUD_DeviceSpecs specs) : AUD_DeviceSpecs specs) :
AUD_MixerFactory(factory, specs) AUD_MixerFactory(factory, specs)
{ {
memset(m_mapping, 0, sizeof(m_mapping));
}
AUD_ChannelMapperFactory::~AUD_ChannelMapperFactory()
{
for(int i = 1; i < 10; i++)
deleteMapping(i);
}
float** AUD_ChannelMapperFactory::getMapping(int ic)
{
ic--;
if(ic > 8 || ic < 0)
return 0;
if(m_mapping[ic])
{
int channels = -1;
while(m_mapping[ic][++channels] != 0);
if(channels != m_specs.channels)
deleteMapping(ic+1);
}
if(!m_mapping[ic])
{
int channels = m_specs.channels;
m_mapping[ic] = new float*[channels+1];
m_mapping[ic][channels] = 0;
for(int i = 0; i < channels; i++)
{
m_mapping[ic][i] = new float[ic+1];
for(int j = 0; j <= ic; j++)
m_mapping[ic][i][j] = ((i == j) || (channels == 1) ||
(ic == 0)) ? 1.0f : 0.0f;
}
}
return m_mapping[ic];
}
void AUD_ChannelMapperFactory::deleteMapping(int ic)
{
ic--;
if(ic > 8 || ic < 0)
return;
if(m_mapping[ic])
{
for(int i = 0; 1; i++)
{
if(m_mapping[ic][i] != 0)
{
delete[] m_mapping[ic][i];
}
else
break;
}
delete[] m_mapping[ic];
m_mapping[ic] = 0;
}
} }
AUD_Reference<AUD_IReader> AUD_ChannelMapperFactory::createReader() AUD_Reference<AUD_IReader> AUD_ChannelMapperFactory::createReader()
{ {
AUD_Reference<AUD_IReader> reader = getReader(); AUD_Reference<AUD_IReader> reader = getReader();
int ic = reader->getSpecs().channels; return new AUD_ChannelMapperReader(reader, m_specs.channels);
return new AUD_ChannelMapperReader(reader,
const_cast<AUD_ChannelMapperFactory*>(this)->getMapping(ic));
} }

@ -41,11 +41,6 @@
class AUD_ChannelMapperFactory : public AUD_MixerFactory class AUD_ChannelMapperFactory : public AUD_MixerFactory
{ {
private: private:
/**
* The mapping specification.
*/
float **m_mapping[9];
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_ChannelMapperFactory(const AUD_ChannelMapperFactory&); AUD_ChannelMapperFactory(const AUD_ChannelMapperFactory&);
AUD_ChannelMapperFactory& operator=(const AUD_ChannelMapperFactory&); AUD_ChannelMapperFactory& operator=(const AUD_ChannelMapperFactory&);
@ -53,20 +48,6 @@ private:
public: public:
AUD_ChannelMapperFactory(AUD_Reference<AUD_IFactory> factory, AUD_DeviceSpecs specs); AUD_ChannelMapperFactory(AUD_Reference<AUD_IFactory> factory, AUD_DeviceSpecs specs);
virtual ~AUD_ChannelMapperFactory();
/**
* Returns the mapping array for editing.
* \param ic The count of input channels the array should have.
* \note The count of output channels is read of the desired output specs.
*/
float** getMapping(int ic);
/**
* Deletes the current channel mapping.
*/
void deleteMapping(int ic);
virtual AUD_Reference<AUD_IReader> createReader(); virtual AUD_Reference<AUD_IReader> createReader();
}; };

@ -28,57 +28,124 @@
* \ingroup audaspaceintern * \ingroup audaspaceintern
*/ */
#include <cmath>
#include "AUD_ChannelMapperReader.h" #include "AUD_ChannelMapperReader.h"
AUD_ChannelMapperReader::AUD_ChannelMapperReader(AUD_Reference<AUD_IReader> reader, AUD_ChannelMapperReader::AUD_ChannelMapperReader(AUD_Reference<AUD_IReader> reader,
float **mapping) : AUD_Channels channels) :
AUD_EffectReader(reader) AUD_EffectReader(reader), m_target_channels(channels),
m_source_channels(AUD_CHANNELS_INVALID), m_mapping(0)
{ {
m_specs = reader->getSpecs();
int channels = -1;
m_rch = m_specs.channels;
while(mapping[++channels] != 0);
m_mapping = new float*[channels];
m_specs.channels = (AUD_Channels)channels;
float sum;
int i;
while(channels--)
{
m_mapping[channels] = new float[m_rch];
sum = 0.0f;
for(i=0; i < m_rch; i++)
sum += mapping[channels][i];
for(i=0; i < m_rch; i++)
m_mapping[channels][i] = sum > 0.0f ?
mapping[channels][i]/sum : 0.0f;
}
} }
AUD_ChannelMapperReader::~AUD_ChannelMapperReader() AUD_ChannelMapperReader::~AUD_ChannelMapperReader()
{ {
int channels = m_specs.channels; delete[] m_mapping;
}
while(channels--) float AUD_ChannelMapperReader::angleDistance(float alpha, float beta)
{
alpha = fabs(alpha - beta);
if(alpha > M_PI)
alpha = fabs(alpha - 2 * M_PI);
return alpha;
}
void AUD_ChannelMapperReader::calculateMapping()
{
delete[] m_mapping;
m_mapping = new float[m_source_channels * m_target_channels];
const AUD_Channel* source_channels = CHANNEL_MAPS[m_source_channels - 1];
const AUD_Channel* target_channels = CHANNEL_MAPS[m_target_channels - 1];
int lfe = -1;
for(int i = 0; i < m_target_channels; i++)
{ {
delete[] m_mapping[channels]; if(target_channels[i] == AUD_CHANNEL_LFE)
{
lfe = i;
break;
}
} }
delete[] m_mapping; const float* source_angles = CHANNEL_ANGLES[m_source_channels - 1];
const float* target_angles = CHANNEL_ANGLES[m_target_channels - 1];
int channel_min1, channel_min2;
float angle_min1, angle_min2, angle;
for(int i = 0; i < m_source_channels; i++)
{
if(source_channels[i] == AUD_CHANNEL_LFE)
{
if(lfe != -1)
m_mapping[lfe * m_source_channels + i] = 1;
continue;
}
channel_min1 = channel_min2 = -1;
angle_min1 = angle_min2 = 2 * M_PI;
for(int j = 0; j < m_target_channels; j++)
{
angle = angleDistance(source_angles[i], target_angles[j]);
if(angle < angle_min1)
{
channel_min2 = channel_min1;
angle_min2 = angle_min1;
channel_min1 = j;
angle_min1 = angle;
}
else if(angle < angle_min2)
{
channel_min2 = j;
angle_min2 = angle;
}
}
if(channel_min2 == -1)
{
m_mapping[channel_min1 * m_source_channels + i] = 1;
}
else
{
angle = angle_min1 + angle_min2;
m_mapping[channel_min1 * m_source_channels + i] = cos(M_PI_2 * angle_min1 / angle);
m_mapping[channel_min2 * m_source_channels + i] = cos(M_PI_2 * angle_min2 / angle);
}
}
} }
AUD_Specs AUD_ChannelMapperReader::getSpecs() const AUD_Specs AUD_ChannelMapperReader::getSpecs() const
{ {
return m_specs; AUD_Specs specs = m_reader->getSpecs();
specs.channels = m_target_channels;
return specs;
} }
void AUD_ChannelMapperReader::read(int& length, bool& eos, sample_t* buffer) void AUD_ChannelMapperReader::read(int& length, bool& eos, sample_t* buffer)
{ {
m_buffer.assureSize(length * m_rch * sizeof(sample_t)); AUD_Channels channels = m_reader->getSpecs().channels;
if(channels != m_source_channels)
{
m_source_channels = channels;
calculateMapping();
}
if(m_source_channels == m_target_channels)
{
m_reader->read(length, eos, buffer);
return;
}
m_buffer.assureSize(length * channels * sizeof(sample_t));
sample_t* in = m_buffer.getBuffer(); sample_t* in = m_buffer.getBuffer();
@ -88,12 +155,172 @@ void AUD_ChannelMapperReader::read(int& length, bool& eos, sample_t* buffer)
for(int i = 0; i < length; i++) for(int i = 0; i < length; i++)
{ {
for(int j = 0; j < m_specs.channels; j++) for(int j = 0; j < m_target_channels; j++)
{ {
sum = 0; sum = 0;
for(int k = 0; k < m_rch; k++) for(int k = 0; k < m_source_channels; k++)
sum += m_mapping[j][k] * in[i * m_rch + k]; sum += m_mapping[j * m_source_channels + k] * in[i * m_source_channels + k];
buffer[i * m_specs.channels + j] = sum; buffer[i * m_target_channels + j] = sum;
} }
} }
} }
const AUD_Channel AUD_ChannelMapperReader::MONO_MAP[] =
{
AUD_CHANNEL_FRONT_CENTER
};
const AUD_Channel AUD_ChannelMapperReader::STEREO_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::STEREO_LFE_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_LFE
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND4_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND5_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_FRONT_CENTER,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND51_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_FRONT_CENTER,
AUD_CHANNEL_LFE,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND61_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_FRONT_CENTER,
AUD_CHANNEL_LFE,
AUD_CHANNEL_REAR_CENTER,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT
};
const AUD_Channel AUD_ChannelMapperReader::SURROUND71_MAP[] =
{
AUD_CHANNEL_FRONT_LEFT,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_FRONT_CENTER,
AUD_CHANNEL_LFE,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT,
AUD_CHANNEL_SIDE_LEFT,
AUD_CHANNEL_SIDE_RIGHT
};
const AUD_Channel* AUD_ChannelMapperReader::CHANNEL_MAPS[] =
{
AUD_ChannelMapperReader::MONO_MAP,
AUD_ChannelMapperReader::STEREO_MAP,
AUD_ChannelMapperReader::STEREO_LFE_MAP,
AUD_ChannelMapperReader::SURROUND4_MAP,
AUD_ChannelMapperReader::SURROUND5_MAP,
AUD_ChannelMapperReader::SURROUND51_MAP,
AUD_ChannelMapperReader::SURROUND61_MAP,
AUD_ChannelMapperReader::SURROUND71_MAP
};
const float AUD_ChannelMapperReader::MONO_ANGLES[] =
{
0.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::STEREO_ANGLES[] =
{
-90.0f * M_PI / 180.0f,
90.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::STEREO_LFE_ANGLES[] =
{
-90.0f * M_PI / 180.0f,
90.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND4_ANGLES[] =
{
-45.0f * M_PI / 180.0f,
45.0f * M_PI / 180.0f,
-135.0f * M_PI / 180.0f,
135.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND5_ANGLES[] =
{
-30.0f * M_PI / 180.0f,
30.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
-110.0f * M_PI / 180.0f,
110.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND51_ANGLES[] =
{
-30.0f * M_PI / 180.0f,
30.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
-110.0f * M_PI / 180.0f,
110.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND61_ANGLES[] =
{
-30.0f * M_PI / 180.0f,
30.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
180.0f * M_PI / 180.0f,
-110.0f * M_PI / 180.0f,
110.0f * M_PI / 180.0f
};
const float AUD_ChannelMapperReader::SURROUND71_ANGLES[] =
{
-30.0f * M_PI / 180.0f,
30.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
0.0f * M_PI / 180.0f,
-110.0f * M_PI / 180.0f,
110.0f * M_PI / 180.0f
-150.0f * M_PI / 180.0f,
150.0f * M_PI / 180.0f
};
const float* AUD_ChannelMapperReader::CHANNEL_ANGLES[] =
{
AUD_ChannelMapperReader::MONO_ANGLES,
AUD_ChannelMapperReader::STEREO_ANGLES,
AUD_ChannelMapperReader::STEREO_LFE_ANGLES,
AUD_ChannelMapperReader::SURROUND4_ANGLES,
AUD_ChannelMapperReader::SURROUND5_ANGLES,
AUD_ChannelMapperReader::SURROUND51_ANGLES,
AUD_ChannelMapperReader::SURROUND61_ANGLES,
AUD_ChannelMapperReader::SURROUND71_ANGLES
};

@ -50,29 +50,59 @@ private:
/** /**
* The output specification. * The output specification.
*/ */
AUD_Specs m_specs; AUD_Channels m_target_channels;
/** /**
* The channel count of the reader. * The channel count of the reader.
*/ */
int m_rch; AUD_Channels m_source_channels;
/** /**
* The mapping specification. * The mapping specification.
*/ */
float **m_mapping; float* m_mapping;
static const AUD_Channel MONO_MAP[];
static const AUD_Channel STEREO_MAP[];
static const AUD_Channel STEREO_LFE_MAP[];
static const AUD_Channel SURROUND4_MAP[];
static const AUD_Channel SURROUND5_MAP[];
static const AUD_Channel SURROUND51_MAP[];
static const AUD_Channel SURROUND61_MAP[];
static const AUD_Channel SURROUND71_MAP[];
static const AUD_Channel* CHANNEL_MAPS[];
static const float MONO_ANGLES[];
static const float STEREO_ANGLES[];
static const float STEREO_LFE_ANGLES[];
static const float SURROUND4_ANGLES[];
static const float SURROUND5_ANGLES[];
static const float SURROUND51_ANGLES[];
static const float SURROUND61_ANGLES[];
static const float SURROUND71_ANGLES[];
static const float* CHANNEL_ANGLES[];
// hide copy constructor and operator= // hide copy constructor and operator=
AUD_ChannelMapperReader(const AUD_ChannelMapperReader&); AUD_ChannelMapperReader(const AUD_ChannelMapperReader&);
AUD_ChannelMapperReader& operator=(const AUD_ChannelMapperReader&); AUD_ChannelMapperReader& operator=(const AUD_ChannelMapperReader&);
/**
* Calculates the mapping matrix.
*/
void calculateMapping();
/**
* Calculates the distance between two angles.
*/
float angleDistance(float alpha, float beta);
public: public:
/** /**
* Creates a channel mapper reader. * Creates a channel mapper reader.
* \param reader The reader to map. * \param reader The reader to map.
* \param mapping The mapping specification as two dimensional float array. * \param mapping The mapping specification as two dimensional float array.
*/ */
AUD_ChannelMapperReader(AUD_Reference<AUD_IReader> reader, float **mapping); AUD_ChannelMapperReader(AUD_Reference<AUD_IReader> reader, AUD_Channels channels);
/** /**
* Destroys the reader. * Destroys the reader.

@ -47,31 +47,15 @@ AUD_DefaultMixer::AUD_DefaultMixer(AUD_DeviceSpecs specs) :
AUD_Reference<AUD_IReader> AUD_DefaultMixer::prepare(AUD_Reference<AUD_IReader> reader) AUD_Reference<AUD_IReader> AUD_DefaultMixer::prepare(AUD_Reference<AUD_IReader> reader)
{ {
// hacky for now, until a better channel mapper reader is available
AUD_ChannelMapperFactory cmf(NULL, m_specs);
AUD_Specs specs = reader->getSpecs();
// if channel count is lower in output, rechannel before resampling
if(specs.channels < m_specs.channels)
{
reader = new AUD_ChannelMapperReader(reader,
cmf.getMapping(specs.channels));
specs.channels = m_specs.channels;
}
// resample // resample
if(specs.rate != m_specs.rate)
#ifdef WITH_SAMPLERATE #ifdef WITH_SAMPLERATE
reader = new AUD_SRCResampleReader(reader, m_specs.specs); reader = new AUD_SRCResampleReader(reader, m_specs.specs);
#else #else
reader = new AUD_LinearResampleReader(reader, m_specs.specs); reader = new AUD_LinearResampleReader(reader, m_specs.specs);
#endif #endif
// rechannel // rechannel
if(specs.channels != m_specs.channels) reader = new AUD_ChannelMapperReader(reader, m_specs.channels);
reader = new AUD_ChannelMapperReader(reader,
cmf.getMapping(specs.channels));
return reader; return reader;
} }

@ -41,6 +41,9 @@
/// Throws a AUD_Exception with the provided error code. /// Throws a AUD_Exception with the provided error code.
#define AUD_THROW(exception, errorstr) { AUD_Exception e; e.error = exception; e.str = errorstr; throw e; } #define AUD_THROW(exception, errorstr) { AUD_Exception e; e.error = exception; e.str = errorstr; throw e; }
/// Returns the bit for a channel mask.
#define AUD_CHANNEL_BIT(channel) (0x01 << channel)
/// Returns the smaller of the two values. /// Returns the smaller of the two values.
#define AUD_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define AUD_MIN(a, b) (((a) < (b)) ? (a) : (b))
/// Returns the bigger of the two values. /// Returns the bigger of the two values.
@ -79,10 +82,24 @@ typedef enum
AUD_CHANNELS_SURROUND5 = 5, /// 5 channel surround sound. AUD_CHANNELS_SURROUND5 = 5, /// 5 channel surround sound.
AUD_CHANNELS_SURROUND51 = 6, /// 5.1 surround sound. AUD_CHANNELS_SURROUND51 = 6, /// 5.1 surround sound.
AUD_CHANNELS_SURROUND61 = 7, /// 6.1 surround sound. AUD_CHANNELS_SURROUND61 = 7, /// 6.1 surround sound.
AUD_CHANNELS_SURROUND71 = 8, /// 7.1 surround sound. AUD_CHANNELS_SURROUND71 = 8 /// 7.1 surround sound.
AUD_CHANNELS_SURROUND72 = 9 /// 7.2 surround sound.
} AUD_Channels; } AUD_Channels;
/// The channel names.
typedef enum
{
AUD_CHANNEL_FRONT_LEFT = 0,
AUD_CHANNEL_FRONT_RIGHT,
AUD_CHANNEL_FRONT_CENTER,
AUD_CHANNEL_LFE,
AUD_CHANNEL_REAR_LEFT,
AUD_CHANNEL_REAR_RIGHT,
AUD_CHANNEL_REAR_CENTER,
AUD_CHANNEL_SIDE_LEFT,
AUD_CHANNEL_SIDE_RIGHT,
AUD_CHANNEL_MAX
} AUD_Channel;
/** /**
* The sample rate tells how many samples are played back within one second. * The sample rate tells how many samples are played back within one second.
* Some exotic formats may use other sample rates than provided here. * Some exotic formats may use other sample rates than provided here.

@ -346,7 +346,7 @@ AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start,
AUD_setDeviceVolume(mixdown, volume); AUD_setDeviceVolume(mixdown, volume);
AUD_freeChannel(AUD_playDevice(mixdown, scene->sound_scene, start / FPS)); AUD_freeHandle(AUD_playDevice(mixdown, scene->sound_scene, start / FPS));
return mixdown; return mixdown;
} }

@ -53,14 +53,14 @@ typedef struct KX_3DSoundSettings
class KX_SoundActuator : public SCA_IActuator class KX_SoundActuator : public SCA_IActuator
{ {
Py_Header; Py_Header;
bool m_isplaying; bool m_isplaying;
AUD_Sound* m_sound; AUD_Sound* m_sound;
float m_volume; float m_volume;
float m_pitch; float m_pitch;
bool m_is3d; bool m_is3d;
KX_3DSoundSettings m_3d; KX_3DSoundSettings m_3d;
AUD_Channel* m_handle; AUD_Handle* m_handle;
void play(); void play();