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_ReadDevice> AUD_Device;
typedef AUD_Reference<AUD_IHandle> AUD_Channel;
typedef AUD_Reference<AUD_IHandle> AUD_Handle;
typedef AUD_Reference<AUD_SequencerEntry> AUD_SEntry;
#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);
@ -409,14 +409,14 @@ void AUD_unload(AUD_Sound* sound)
delete sound;
}
AUD_Channel* AUD_play(AUD_Sound* sound, int keep)
AUD_Handle* AUD_play(AUD_Sound* sound, int keep)
{
assert(sound);
try
{
AUD_Channel channel = AUD_device->play(*sound, keep);
if(!channel.isNull())
return new AUD_Channel(channel);
AUD_Handle handle = AUD_device->play(*sound, keep);
if(!handle.isNull())
return new AUD_Handle(handle);
}
catch(AUD_Exception&)
{
@ -424,19 +424,19 @@ AUD_Channel* AUD_play(AUD_Sound* sound, int keep)
return NULL;
}
int AUD_pause(AUD_Channel* handle)
int AUD_pause(AUD_Handle* handle)
{
assert(handle);
return (*handle)->pause();
}
int AUD_resume(AUD_Channel* handle)
int AUD_resume(AUD_Handle* handle)
{
assert(handle);
return (*handle)->resume();
}
int AUD_stop(AUD_Channel* handle)
int AUD_stop(AUD_Handle* handle)
{
assert(handle);
int result = (*handle)->stop();
@ -444,25 +444,25 @@ int AUD_stop(AUD_Channel* handle)
return result;
}
int AUD_setKeep(AUD_Channel* handle, int keep)
int AUD_setKeep(AUD_Handle* handle, int keep)
{
assert(handle);
return (*handle)->setKeep(keep);
}
int AUD_seek(AUD_Channel* handle, float seekTo)
int AUD_seek(AUD_Handle* handle, float seekTo)
{
assert(handle);
return (*handle)->seek(seekTo);
}
float AUD_getPosition(AUD_Channel* handle)
float AUD_getPosition(AUD_Handle* handle)
{
assert(handle);
return (*handle)->getPosition();
}
AUD_Status AUD_getStatus(AUD_Channel* handle)
AUD_Status AUD_getStatus(AUD_Handle* handle)
{
assert(handle);
return (*handle)->getStatus();
@ -537,7 +537,7 @@ int AUD_setDistanceModel(AUD_DistanceModel model)
return false;
}
int AUD_setSourceLocation(AUD_Channel* handle, const float* location)
int AUD_setSourceLocation(AUD_Handle* handle, const float* location)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -551,7 +551,7 @@ int AUD_setSourceLocation(AUD_Channel* handle, const float* location)
return false;
}
int AUD_setSourceVelocity(AUD_Channel* handle, const float* velocity)
int AUD_setSourceVelocity(AUD_Handle* handle, const float* velocity)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -565,7 +565,7 @@ int AUD_setSourceVelocity(AUD_Channel* handle, const float* velocity)
return false;
}
int AUD_setSourceOrientation(AUD_Channel* handle, const float* orientation)
int AUD_setSourceOrientation(AUD_Handle* handle, const float* orientation)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -579,7 +579,7 @@ int AUD_setSourceOrientation(AUD_Channel* handle, const float* orientation)
return false;
}
int AUD_setRelative(AUD_Channel* handle, int relative)
int AUD_setRelative(AUD_Handle* handle, int relative)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -592,7 +592,7 @@ int AUD_setRelative(AUD_Channel* handle, int relative)
return false;
}
int AUD_setVolumeMaximum(AUD_Channel* handle, float volume)
int AUD_setVolumeMaximum(AUD_Handle* handle, float volume)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -605,7 +605,7 @@ int AUD_setVolumeMaximum(AUD_Channel* handle, float volume)
return false;
}
int AUD_setVolumeMinimum(AUD_Channel* handle, float volume)
int AUD_setVolumeMinimum(AUD_Handle* handle, float volume)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -618,7 +618,7 @@ int AUD_setVolumeMinimum(AUD_Channel* handle, float volume)
return false;
}
int AUD_setDistanceMaximum(AUD_Channel* handle, float distance)
int AUD_setDistanceMaximum(AUD_Handle* handle, float distance)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -631,7 +631,7 @@ int AUD_setDistanceMaximum(AUD_Channel* handle, float distance)
return false;
}
int AUD_setDistanceReference(AUD_Channel* handle, float distance)
int AUD_setDistanceReference(AUD_Handle* handle, float distance)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -644,7 +644,7 @@ int AUD_setDistanceReference(AUD_Channel* handle, float distance)
return false;
}
int AUD_setAttenuation(AUD_Channel* handle, float factor)
int AUD_setAttenuation(AUD_Handle* handle, float factor)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -657,7 +657,7 @@ int AUD_setAttenuation(AUD_Channel* handle, float factor)
return false;
}
int AUD_setConeAngleOuter(AUD_Channel* handle, float angle)
int AUD_setConeAngleOuter(AUD_Handle* handle, float angle)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -670,7 +670,7 @@ int AUD_setConeAngleOuter(AUD_Channel* handle, float angle)
return false;
}
int AUD_setConeAngleInner(AUD_Channel* handle, float angle)
int AUD_setConeAngleInner(AUD_Handle* handle, float angle)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -683,7 +683,7 @@ int AUD_setConeAngleInner(AUD_Channel* handle, float angle)
return false;
}
int AUD_setConeVolumeOuter(AUD_Channel* handle, float volume)
int AUD_setConeVolumeOuter(AUD_Handle* handle, float volume)
{
assert(handle);
AUD_Reference<AUD_I3DHandle> h(*handle);
@ -696,7 +696,7 @@ int AUD_setConeVolumeOuter(AUD_Channel* handle, float volume)
return false;
}
int AUD_setSoundVolume(AUD_Channel* handle, float volume)
int AUD_setSoundVolume(AUD_Handle* handle, float volume)
{
assert(handle);
try
@ -707,7 +707,7 @@ int AUD_setSoundVolume(AUD_Channel* handle, float volume)
return false;
}
int AUD_setSoundPitch(AUD_Channel* handle, float pitch)
int AUD_setSoundPitch(AUD_Handle* handle, float pitch)
{
assert(handle);
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(sound);
try
{
AUD_Channel channel = (*device)->play(*sound);
if(!channel.isNull())
AUD_Handle handle = (*device)->play(*sound);
if(!handle.isNull())
{
channel->seek(seek);
return new AUD_Channel(channel);
handle->seek(seek);
return new AUD_Handle(handle);
}
}
catch(AUD_Exception&)
@ -848,13 +848,13 @@ float* AUD_readSoundBuffer(const char* filename, float low, float high,
return result;
}
static void pauseSound(AUD_Channel* handle)
static void pauseSound(AUD_Handle* handle)
{
assert(handle);
(*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> limiter = new AUD_LimiterFactory(silence, 0, seconds);
@ -863,12 +863,12 @@ AUD_Channel* AUD_pauseAfter(AUD_Channel* handle, float seconds)
try
{
AUD_Channel channel = AUD_device->play(limiter);
if(!channel.isNull())
AUD_Handle handle2 = AUD_device->play(limiter);
if(!handle2.isNull())
{
channel->setStopCallback((stopCallback)pauseSound, handle);
handle2->setStopCallback((stopCallback)pauseSound, handle);
AUD_device->unlock();
return new AUD_Channel(channel);
return new AUD_Handle(handle2);
}
}
catch(AUD_Exception&)
@ -996,7 +996,7 @@ void AUD_stopPlayback()
#endif
}
void AUD_seekSequencer(AUD_Channel* handle, float time)
void AUD_seekSequencer(AUD_Handle* handle, float time)
{
#ifdef WITH_JACK
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
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);
}
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
typedef void AUD_Sound;
typedef void AUD_Channel;
typedef void AUD_Handle;
typedef void AUD_Device;
typedef void AUD_SEntry;
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.
* \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.
@ -181,28 +181,28 @@ extern void AUD_unload(AUD_Sound* sound);
* paused when its end has been reached.
* \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.
* \param handle The handle to the sound.
* \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.
* \param handle The handle to the sound.
* \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.
* \param handle The handle to the sound.
* \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.
@ -211,7 +211,7 @@ extern int AUD_stop(AUD_Channel* handle);
* paused when its end has been reached.
* \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.
@ -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.
* \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.
@ -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
* 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.
* \param handle The handle to the sound.
* \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.
@ -281,7 +281,7 @@ extern int AUD_setDistanceModel(AUD_DistanceModel model);
* \param location The new location.
* \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.
@ -289,7 +289,7 @@ extern int AUD_setSourceLocation(AUD_Channel* handle, const float* location);
* \param velocity The new velocity.
* \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.
@ -297,7 +297,7 @@ extern int AUD_setSourceVelocity(AUD_Channel* handle, const float* velocity);
* \param orientation The new orientation as quaternion.
* \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
@ -306,7 +306,7 @@ extern int AUD_setSourceOrientation(AUD_Channel* handle, const float* orientatio
* \param relative Whether the source is relative.
* \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.
@ -314,7 +314,7 @@ extern int AUD_setRelative(AUD_Channel* handle, int relative);
* \param volume The new maximum volume.
* \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.
@ -322,7 +322,7 @@ extern int AUD_setVolumeMaximum(AUD_Channel* handle, float volume);
* \param volume The new minimum volume.
* \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.
@ -332,7 +332,7 @@ extern int AUD_setVolumeMinimum(AUD_Channel* handle, float volume);
* \param distance The new maximum distance.
* \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.
@ -340,7 +340,7 @@ extern int AUD_setDistanceMaximum(AUD_Channel* handle, float distance);
* \param distance The new reference distance.
* \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.
@ -349,7 +349,7 @@ extern int AUD_setDistanceReference(AUD_Channel* handle, float distance);
* \param factor The new attenuation.
* \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.
@ -357,7 +357,7 @@ extern int AUD_setAttenuation(AUD_Channel* handle, float factor);
* \param angle The new outer angle of the cone.
* \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.
@ -365,7 +365,7 @@ extern int AUD_setConeAngleOuter(AUD_Channel* handle, float angle);
* \param angle The new inner angle of the cone.
* \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.
@ -375,7 +375,7 @@ extern int AUD_setConeAngleInner(AUD_Channel* handle, float angle);
* \param volume The new outer volume of the cone.
* \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.
@ -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.
* \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.
@ -391,7 +391,7 @@ extern int AUD_setSoundVolume(AUD_Channel* handle, float volume);
* \param pitch The new pitch.
* \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.
@ -415,7 +415,7 @@ extern int AUD_setDeviceVolume(AUD_Device* device, float volume);
* \param seek The position where the sound should be seeked to.
* \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.
@ -450,7 +450,7 @@ extern float* AUD_readSoundBuffer(const char* filename, float low, float high,
* \param time The time in seconds.
* \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);
@ -475,9 +475,9 @@ extern void AUD_startPlayback(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
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 void AUD_freeChannel(AUD_Channel* channel);
extern void AUD_freeHandle(AUD_Handle* channel);
#ifdef WITH_PYTHON
extern PyObject* AUD_getPythonFactory(AUD_Sound* sound);

@ -38,75 +38,10 @@ AUD_ChannelMapperFactory::AUD_ChannelMapperFactory(AUD_Reference<AUD_IFactory> f
AUD_DeviceSpecs 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> reader = getReader();
int ic = reader->getSpecs().channels;
return new AUD_ChannelMapperReader(reader,
const_cast<AUD_ChannelMapperFactory*>(this)->getMapping(ic));
return new AUD_ChannelMapperReader(reader, m_specs.channels);
}

@ -41,11 +41,6 @@
class AUD_ChannelMapperFactory : public AUD_MixerFactory
{
private:
/**
* The mapping specification.
*/
float **m_mapping[9];
// hide copy constructor and operator=
AUD_ChannelMapperFactory(const AUD_ChannelMapperFactory&);
AUD_ChannelMapperFactory& operator=(const AUD_ChannelMapperFactory&);
@ -53,20 +48,6 @@ private:
public:
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();
};

@ -28,57 +28,124 @@
* \ingroup audaspaceintern
*/
#include <cmath>
#include "AUD_ChannelMapperReader.h"
AUD_ChannelMapperReader::AUD_ChannelMapperReader(AUD_Reference<AUD_IReader> reader,
float **mapping) :
AUD_EffectReader(reader)
AUD_Channels channels) :
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()
{
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
{
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)
{
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();
@ -88,12 +155,172 @@ void AUD_ChannelMapperReader::read(int& length, bool& eos, sample_t* buffer)
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;
for(int k = 0; k < m_rch; k++)
sum += m_mapping[j][k] * in[i * m_rch + k];
buffer[i * m_specs.channels + j] = sum;
for(int k = 0; k < m_source_channels; k++)
sum += m_mapping[j * m_source_channels + k] * in[i * m_source_channels + k];
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.
*/
AUD_Specs m_specs;
AUD_Channels m_target_channels;
/**
* The channel count of the reader.
*/
int m_rch;
AUD_Channels m_source_channels;
/**
* 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=
AUD_ChannelMapperReader(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:
/**
* Creates a channel mapper reader.
* \param reader The reader to map.
* \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.

@ -47,31 +47,15 @@ AUD_DefaultMixer::AUD_DefaultMixer(AUD_DeviceSpecs specs) :
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
if(specs.rate != m_specs.rate)
#ifdef WITH_SAMPLERATE
reader = new AUD_SRCResampleReader(reader, m_specs.specs);
reader = new AUD_SRCResampleReader(reader, m_specs.specs);
#else
reader = new AUD_LinearResampleReader(reader, m_specs.specs);
reader = new AUD_LinearResampleReader(reader, m_specs.specs);
#endif
// rechannel
if(specs.channels != m_specs.channels)
reader = new AUD_ChannelMapperReader(reader,
cmf.getMapping(specs.channels));
reader = new AUD_ChannelMapperReader(reader, m_specs.channels);
return reader;
}

@ -41,6 +41,9 @@
/// 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; }
/// Returns the bit for a channel mask.
#define AUD_CHANNEL_BIT(channel) (0x01 << channel)
/// Returns the smaller of the two values.
#define AUD_MIN(a, b) (((a) < (b)) ? (a) : (b))
/// Returns the bigger of the two values.
@ -79,10 +82,24 @@ typedef enum
AUD_CHANNELS_SURROUND5 = 5, /// 5 channel surround sound.
AUD_CHANNELS_SURROUND51 = 6, /// 5.1 surround sound.
AUD_CHANNELS_SURROUND61 = 7, /// 6.1 surround sound.
AUD_CHANNELS_SURROUND71 = 8, /// 7.1 surround sound.
AUD_CHANNELS_SURROUND72 = 9 /// 7.2 surround sound.
AUD_CHANNELS_SURROUND71 = 8 /// 7.1 surround sound.
} 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.
* 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_freeChannel(AUD_playDevice(mixdown, scene->sound_scene, start / FPS));
AUD_freeHandle(AUD_playDevice(mixdown, scene->sound_scene, start / FPS));
return mixdown;
}

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