Skip to content

Commit

Permalink
VBAP and capture work.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Feb 1, 2004
1 parent 0291242 commit ac25aef
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 138 deletions.
8 changes: 8 additions & 0 deletions osx/CHANGELOG
Expand Up @@ -3,6 +3,14 @@
* CHANGELOG.
*/

01302004 - Started ripping out VBAP. :( I'm not pleased with the results of
VBAP2D...VBAP3D might be useful still, though. Made some changes
to __alcSetSpeakerDefaults() and moved it above the CoreAudio
section of alContext.c, since it doesn't have any Mac-specific
code now. Experimenting with (for lack of a better term) "position
attenuation"...it's something like stereo panning in 2D instead of
1D. ALdevice->speakers is now zero for capture devices (so
ALC_SPEAKER_COUNT is sane in this case). Added alcSpeakerf().
01252004 - Fixed resamplers (ratio was backwards). ALC_EXT_capture work...
I am stunned at my complete inability to create a functional
ring buffer. Got capture to work for the first time! VoIP, here
Expand Down
16 changes: 10 additions & 6 deletions osx/README
Expand Up @@ -15,22 +15,26 @@ apart from the standard openal.org Mac implementation:
for G3 and older systems.
- Is designed with multithreading in mind...should be 100% thread safe, and
can take advantage of multiple CPU systems internally.
- Supports more-than-two speaker configurations...for example, you can
install an M-Audio Revolution 7.1 card and surround yourself with speakers;
audio sources rendered through OpenAL will correctly use speakers, so that
sounds played behind the listener will literally play behind you, too.
- Can handle multiple contexts on multiple devices, all running in parallel.
- Supports the AL_ENUMERATION_EXT extension for device enumeration.
- Supports AL_EXT_vorbis for direct playback of Ogg Vorbis audio; the Vorbis
decoder is a highly optimized and Altivec-enabled fork of xiph.org's
libvorbis-1.0...using this extension can be significantly faster and
easier for the application than using a stock libvorbis and buffer queueing.
- Codebase is designed to be maintainable and flexible. Adding new data
types (as demostrated by AL_EXT_vorbis) is fairly easy.
- Supports ALC_EXT_capture, for recording audio from a microphone, etc.
- Supports ALC_EXT_speaker_attrs, for fine-tuned control of physical
loudspeakers in 3D space.
- Supports AL_EXT_float32, for easier migration from CoreAudio to OpenAL.
- Supports AL_EXT_buffer_offset, which is basically an extended form of
AL_BYTE_LOKI, for when you have to get down and dirty at the lowlevel of
audio playback.
- Codebase is designed to be maintainable and flexible. Adding new data
types (as demostrated by AL_EXT_vorbis) is fairly easy.
- Supports IBM's G5 compiler.
- Supports more-than-two speaker configurations...for example, you can
install an M-Audio Revolution 7.1 card and surround yourself with speakers;
audio sources rendered through OpenAL will correctly use speakers, so that
sounds played behind the listener will literally play behind you, too.

This implementation is fairly robust, but in many ways can still be considered
a "mini-AL" library...it is enough to play UT2003 well, but some features of a
Expand Down
1 change: 1 addition & 0 deletions osx/TODO
Expand Up @@ -35,6 +35,7 @@
- The ring buffer is crap.
- There's a lot of room for optimization in the capture callback.
- There's a lot of untested codepaths in the capture extension.
- 80-column source code cleanup.

// end of TODO ...

202 changes: 83 additions & 119 deletions osx/alContext.c
Expand Up @@ -188,7 +188,7 @@ ALCAPI ALvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALenum param,ALsizei
if (size < sizeof (ALint))
__alcSetError((ALdevice *) dev, ALC_INVALID_VALUE);
else
*data = dev->speakers;
*data = dev->speakers; // if capture device, this is 0.
break;
#endif

Expand Down Expand Up @@ -381,6 +381,7 @@ ALCAPI ALvoid * ALCAPIENTRY alcGetProcAddress(ALCdevice *device, ALubyte *funcN

#if SUPPORTS_ALC_EXT_SPEAKER_ATTRS
PROC_ADDRESS(alcGetSpeakerfv);
PROC_ADDRESS(alcSpeakerf);
PROC_ADDRESS(alcSpeakerfv);
#endif

Expand Down Expand Up @@ -512,6 +513,13 @@ ALCAPI ALvoid ALCAPIENTRY alcSpeakerfv(ALCdevice *dev, ALuint spk, ALfloat *v)
} // switch
} // else
} // alcSpeakerfv


ALCAPI ALvoid ALCAPIENTRY alcSpeakerf(ALCdevice *dev, ALuint spk, ALfloat x)
{
ALfloat xyz[3] = { x, 0.0f, 0.0f };
alcSpeakerfv(dev, spk, xyz);
} // alcSpeakerf
#endif


Expand Down Expand Up @@ -633,6 +641,64 @@ ALCAPI ALvoid ALCAPIENTRY alcCaptureSamples(ALCdevice *device, ALvoid *buf,
} // alcCaptureSamples
#endif


static ALvoid __alcSetSpeakerDefaults(ALdevice *dev)
{
UInt32 i;

dev->speakerConfig = SPKCFG_STDSTEREO;
if (dev->speakers > 2)
dev->speakerConfig = SPKCFG_POSATTENUATION;

if (dev->speakers == 0) // may be capture device, etc...
return;

for (i = 0; i < dev->speakers; i++) // fill in sane defaults...
{
dev->speakerazimuths[i] = 0.0f;
dev->speakerelevations[i] = 0.0f;
dev->speakergains[i] = 1.0f;
i++;
} // for

switch (dev->speakers)
{
case 1:
dev->speakerazimuths[0] = 0.0f;
break;

case 2:
dev->speakerazimuths[0] = -90.0f;
dev->speakerazimuths[1] = 90.0f;
break;

case 8: // 7.1 setup
dev->speakerazimuths[0] = -35.0f;
dev->speakerazimuths[1] = 35.0f;
dev->speakerazimuths[2] = -80.0f;
dev->speakerazimuths[3] = 80.0f;
dev->speakerazimuths[4] = -125.0f;
dev->speakerazimuths[5] = 125.0f;
dev->speakerazimuths[6] = -170.0f;
dev->speakerazimuths[7] = 170.0f;
break;

case 4: // Quadiphonic !!! FIXME
case 5: // 4.1 setup. !!! FIXME
case 6: // 5.1 setup. !!! FIXME
default:
assert(0);
break;
} // switch

// !!! FIXME: Override default speaker attributes with config file.

#if USE_VBAP
__alcTriangulateSpeakers(dev);
#endif
} // __alcGetDefaultSpeakerPos


//----------------------------------------------------------------------------
// With the exception of some defines in the headers, I've tried to keep all
// the CoreAudio and MacOS specifics below here...
Expand Down Expand Up @@ -1039,7 +1105,6 @@ static ALvoid __alcMixContext(ALcontext *ctx, UInt8 *_dst,
__alUngrabContext(ctx);
} // __alcMixContext


#if SUPPORTS_ALC_EXT_CAPTURE
static OSStatus __alcCaptureDevice(AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData)
{
Expand All @@ -1049,14 +1114,16 @@ static OSStatus __alcCaptureDevice(AudioDeviceID inDevice, const AudioTimeStamp
ALsizei samples = 0;
ALsizei resampsize = 0;
ALboolean doConvert = AL_TRUE;
ALsizei chans = dev->streamFormat.mChannelsPerFrame;

assert(dev->isInputDevice);
assert(dev->speakers == 0);
assert(dev->capture.started);

if (!inInputData)
return kAudioHardwareNoError;

samples = inInputData->mBuffers[0].mDataByteSize / (sizeof (Float32) * dev->speakers);
samples = inInputData->mBuffers[0].mDataByteSize / (sizeof(Float32)*chans);
if ((ALint) dev->streamFormat.mSampleRate == dev->capture.freq)
{
resampled = inInputData->mBuffers[0].mData;
Expand All @@ -1066,7 +1133,7 @@ static OSStatus __alcCaptureDevice(AudioDeviceID inDevice, const AudioTimeStamp
{
ALfloat ratio = ((ALfloat) dev->capture.freq) / ((ALfloat) dev->streamFormat.mSampleRate);
samples = (ALsizei) (((ALfloat) samples) * ratio);
resampsize = samples * (sizeof (Float32) * dev->speakers);
resampsize = samples * (sizeof (Float32) * chans);

// !!! FIXME: Allocate this in alcCaptureOpenDevice()!
if (dev->capture.resampled == NULL)
Expand All @@ -1079,7 +1146,7 @@ static OSStatus __alcCaptureDevice(AudioDeviceID inDevice, const AudioTimeStamp

resampled = (Float32 *) dev->capture.resampled;
// !!! FIXME: Handle > 2 channel?
if (dev->speakers == 1)
if (chans == 1)
{
__alResampleMonoFloat32(inInputData->mBuffers[0].mData,
inInputData->mBuffers[0].mDataByteSize,
Expand All @@ -1094,9 +1161,9 @@ static OSStatus __alcCaptureDevice(AudioDeviceID inDevice, const AudioTimeStamp
} // else

#if SUPPORTS_AL_EXT_FLOAT32
if (dev->speakers == 1)
if (chans == 1)
doConvert = (dev->capture.format != AL_FORMAT_MONO_FLOAT32);
else if (dev->speakers == 2)
else if (chans == 2)
doConvert = (dev->capture.format != AL_FORMAT_STEREO_FLOAT32);
#endif

Expand All @@ -1114,7 +1181,7 @@ static OSStatus __alcCaptureDevice(AudioDeviceID inDevice, const AudioTimeStamp
} // if
converted = dev->capture.converted;

if (dev->speakers == 1)
if (chans == 1)
{
rc = __alConvertFromMonoFloat32(resampled, converted,
dev->capture.format, samples);
Expand Down Expand Up @@ -1194,114 +1261,6 @@ static OSStatus __alcMixDevice(AudioDeviceID inDevice, const AudioTimeStamp* i
} // __alcMixDevice


static ALvoid __alcSetSpeakerDefaults(ALdevice *dev)
{
UInt32 i = 0;

dev->speakerConfig = SPKCFG_STDSTEREO; // sane default.

/* !!! FIXME: Coerce speaker positions out of CoreAudio.
AudioDeviceID device = dev->device;
AudioChannelLayout *layout;
Boolean writable;
OSStatus error;
UInt32 count;
dev->speakerConfig = SPKCFG_STDSTEREO; // sane default.
error = AudioDeviceGetPropertyInfo(device, 0, 0,
kAudioDevicePropertyPreferredChannelLayout,
&count, &writable);
if (error != kAudioHardwareNoError)
count = 0;
else
{
layout = (AudioChannelLayout *) alloca(count);
error = AudioDeviceGetProperty(device, 0, 0,
kAudioDevicePropertyPreferredChannelLayout,
&count, layout);
if (error == kAudioHardwareNoError)
count = 0;
else
{
count = layout->mNumberChannelDescriptions;
if (count > dev->speakers)
count = dev->speakers;
} // else
} // else
for (i = 0; i < count; i++)
{
UInt32 chanFlags = layout->mChannelDescriptions[i].mChannelFlags;
Float32 *coreAudio = layout->mChannelDescriptions[i].mCoordinates;
dev->speakergains[i] = 1.0f;
if (chanFlags & kAudioChannelFlags_RectangularCoordinates)
{
// CoreAudio appears to use a right-handed coordinate system,
// like OpenAL, but specifies it as X, Z, Y, not X, Y, Z.
openAL[0] = coreAudio[0];
openAL[1] = coreAudio[2];
openAL[2] = coreAudio[1];
} // if
else if (chanFlags & kAudioChannelFlags_SphericalCoordinates)
{
//0 == azimuth
//1 == elevation
//2 == distance
assert(0); // !!! FIXME: write me!
} // if
else
{
// !!! FIXME: Sane position defaults.
} // else
openAL += 3;
azi += aziincr;
} // for
*/

while (i < dev->speakers) // fill in sane defaults if needed.
{
dev->speakerelevations[i] = 0.0f;
dev->speakergains[i] = 1.0f;
i++;
} // while
if (dev->speakers == 1)
dev->speakerazimuths[0] = 0.0f;
else if (dev->speakers == 2)
{
dev->speakerazimuths[0] = -90.0f;
dev->speakerazimuths[1] = 90.0f;
} // else if
else if (dev->speakers == 8)
{
dev->speakerazimuths[0] = -35.0f;
dev->speakerazimuths[1] = 35.0f;
dev->speakerazimuths[2] = -80.0f;
dev->speakerazimuths[3] = 80.0f;
dev->speakerazimuths[4] = -125.0f;
dev->speakerazimuths[5] = 125.0f;
dev->speakerazimuths[6] = -170.0f;
dev->speakerazimuths[7] = 170.0f;
}
else
{
assert(0);
}

// !!! FIXME: Override default speaker attributes with config file.

#if USE_VBAP
__alcTriangulateSpeakers(dev);
#endif
} // __alcGetDefaultSpeakerPos


static ALCdevice* __alcOpenDeviceInternal(const ALubyte *deviceName,
ALboolean isOutput, ALsizei freq)
{
Expand Down Expand Up @@ -1380,9 +1339,14 @@ static ALCdevice* __alcOpenDeviceInternal(const ALubyte *deviceName,

memcpy(&retval->streamFormat, &streamFormat, sizeof (streamFormat));
retval->device = device;
retval->speakers = streamFormat.mChannelsPerFrame;
if (retval->speakers > AL_MAXSPEAKERS)
retval->speakers = AL_MAXSPEAKERS;
if (isInput)
retval->speakers = 0;
else
{
retval->speakers = streamFormat.mChannelsPerFrame;
if (retval->speakers > AL_MAXSPEAKERS)
retval->speakers = AL_MAXSPEAKERS;
} // else

// Set up default speaker attributes.
__alcSetSpeakerDefaults(retval);
Expand Down
19 changes: 12 additions & 7 deletions osx/alInternal.h
Expand Up @@ -346,6 +346,7 @@ ALvoid __alUngrabContext(ALcontext *ctx);
typedef enum
{
SPKCFG_STDSTEREO, // 2 speakers, left and right. Regular stereo output.
SPKCFG_POSATTENUATION, // 2D position attenuation
#if USE_VBAP
SPKCFG_VBAP_2D, // >= 2 speakers around listener at elevation 0.
SPKCFG_VBAP_3D, // >= 3 speakers around listener at arbitrary positions.
Expand Down Expand Up @@ -380,7 +381,7 @@ typedef struct ALdevice_struct
ALfloat speakergains[AL_MAXSPEAKERS];
ALfloat speakerazimuths[AL_MAXSPEAKERS];
ALfloat speakerelevations[AL_MAXSPEAKERS];
ALfloat speakerpos[AL_MAXSPEAKERS*3]; // x, y, z
ALfloat speakerpos[AL_MAXSPEAKERS*3]; // x, y, z ... internal use only.

#if USE_VBAP
ALsizei vbapgroups; // number of speaker triangles/pairs.
Expand Down Expand Up @@ -454,19 +455,23 @@ ALboolean __alIsExtensionPresent(const ALbyte *extName, ALboolean isALC);


#if SUPPORTS_ALC_EXT_SPEAKER_ATTRS
ALCAPI ALvoid ALCAPIENTRY alcGetSpeakerfv(ALCdevice *dev, ALuint spk, ALenum param, ALfloat *v);
ALCAPI ALvoid ALCAPIENTRY alcSpeakerfv(ALCdevice *dev, ALuint spk, ALfloat *v);
ALCAPI ALvoid ALCAPIENTRY alcGetSpeakerfv(ALCdevice *dev, ALuint spk,
ALenum param, ALfloat *v);
ALCAPI ALvoid ALCAPIENTRY alcSpeakerfv(ALCdevice *dev, ALuint spk,
ALfloat *v);
ALCAPI ALvoid ALCAPIENTRY alcSpeakerf(ALCdevice *dev, ALuint spk, ALfloat x);

#ifndef ALC_SPEAKER_COUNT
#define ALC_SPEAKER_COUNT 0x1032 // alcGetInteger
#define ALC_SPEAKER_COUNT 0x1032 // alcGetInteger
#endif
#ifndef ALC_SPEAKER_GAIN
#define ALC_SPEAKER_GAIN 0x1033 // alcSpeakerfv
#define ALC_SPEAKER_GAIN 0x1033 // alcSpeakerf
#endif
#ifndef ALC_SPEAKER_AZIMUTH
#define ALC_SPEAKER_AZIMUTH 0x1034 // alcSpeakerfv
#define ALC_SPEAKER_AZIMUTH 0x1034 // alcSpeakerf
#endif
#ifndef ALC_SPEAKER_ELEVATION
#define ALC_SPEAKER_ELEVATION 0x1035 // alcSpeakerfv
#define ALC_SPEAKER_ELEVATION 0x1035 // alcSpeakerf
#endif
#endif

Expand Down

0 comments on commit ac25aef

Please sign in to comment.