Update OpenAL Soft to 1.18.2

This commit is contained in:
Alex Szpakowski
2017-12-10 22:34:10 -04:00
parent 75e0077566
commit b160006eb1
152 changed files with 33572 additions and 15363 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+99 -53
View File
@@ -28,12 +28,13 @@
#include <assert.h>
#include <math.h>
#include <SDL_sound.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "common/alhelpers.h"
#include "common/sdl_sound.h"
#ifndef M_PI
@@ -44,47 +45,63 @@ static LPALCGETSTRINGISOFT alcGetStringiSOFT;
static LPALCRESETDEVICESOFT alcResetDeviceSOFT;
/* LoadBuffer loads the named audio file into an OpenAL buffer object, and
* returns the new buffer ID. */
* returns the new buffer ID.
*/
static ALuint LoadSound(const char *filename)
{
ALenum err, format, type, channels;
ALuint rate, buffer;
size_t datalen;
void *data;
FilePtr sound;
Sound_Sample *sample;
ALenum err, format;
ALuint buffer;
Uint32 slen;
/* Open the audio file */
sound = openAudioFile(filename, 1000);
if(!sound)
sample = Sound_NewSampleFromFile(filename, NULL, 65536);
if(!sample)
{
fprintf(stderr, "Could not open audio in %s\n", filename);
closeAudioFile(sound);
return 0;
}
/* Get the sound format, and figure out the OpenAL format */
if(getAudioInfo(sound, &rate, &channels, &type) != 0)
if(sample->actual.channels == 1)
{
fprintf(stderr, "Error getting audio info for %s\n", filename);
closeAudioFile(sound);
return 0;
if(sample->actual.format == AUDIO_U8)
format = AL_FORMAT_MONO8;
else if(sample->actual.format == AUDIO_S16SYS)
format = AL_FORMAT_MONO16;
else
{
fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format);
Sound_FreeSample(sample);
return 0;
}
}
format = GetFormat(channels, type, NULL);
if(format == AL_NONE)
else if(sample->actual.channels == 2)
{
fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
ChannelsName(channels), TypeName(type), filename);
closeAudioFile(sound);
if(sample->actual.format == AUDIO_U8)
format = AL_FORMAT_STEREO8;
else if(sample->actual.format == AUDIO_S16SYS)
format = AL_FORMAT_STEREO16;
else
{
fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format);
Sound_FreeSample(sample);
return 0;
}
}
else
{
fprintf(stderr, "Unsupported channel count: %d\n", sample->actual.channels);
Sound_FreeSample(sample);
return 0;
}
/* Decode the whole audio stream to a buffer. */
data = decodeAudioStream(sound, &datalen);
if(!data)
slen = Sound_DecodeAll(sample);
if(!sample->buffer || slen == 0)
{
fprintf(stderr, "Failed to read audio from %s\n", filename);
closeAudioFile(sound);
Sound_FreeSample(sample);
return 0;
}
@@ -92,9 +109,8 @@ static ALuint LoadSound(const char *filename)
* close the file. */
buffer = 0;
alGenBuffers(1, &buffer);
alBufferData(buffer, format, data, datalen, rate);
free(data);
closeAudioFile(sound);
alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate);
Sound_FreeSample(sample);
/* Check if an error occured, and clean up if so. */
err = alGetError();
@@ -113,6 +129,7 @@ static ALuint LoadSound(const char *filename)
int main(int argc, char **argv)
{
ALCdevice *device;
ALboolean has_angle_ext;
ALuint source, buffer;
const char *soundname;
const char *hrtfname;
@@ -121,28 +138,18 @@ int main(int argc, char **argv)
ALdouble angle;
ALenum state;
/* Print out usage if no file was specified */
if(argc < 2 || (strcmp(argv[1], "-hrtf") == 0 && argc < 4))
/* Print out usage if no arguments were specified */
if(argc < 2)
{
fprintf(stderr, "Usage: %s [-hrtf <name>] <soundfile>\n", argv[0]);
fprintf(stderr, "Usage: %s [-device <name>] [-hrtf <name>] <soundfile>\n", argv[0]);
return 1;
}
/* Initialize OpenAL with the default device, and check for HRTF support. */
if(InitAL() != 0)
/* Initialize OpenAL, and check for HRTF support. */
argv++; argc--;
if(InitAL(&argv, &argc) != 0)
return 1;
if(strcmp(argv[1], "-hrtf") == 0)
{
hrtfname = argv[2];
soundname = argv[3];
}
else
{
hrtfname = NULL;
soundname = argv[1];
}
device = alcGetContextsDevice(alcGetCurrentContext());
if(!alcIsExtensionPresent(device, "ALC_SOFT_HRTF"))
{
@@ -157,6 +164,24 @@ int main(int argc, char **argv)
LOAD_PROC(device, alcResetDeviceSOFT);
#undef LOAD_PROC
/* Check for the AL_EXT_STEREO_ANGLES extension to be able to also rotate
* stereo sources.
*/
has_angle_ext = alIsExtensionPresent("AL_EXT_STEREO_ANGLES");
printf("AL_EXT_STEREO_ANGLES%s found\n", has_angle_ext?"":" not");
/* Check for user-preferred HRTF */
if(strcmp(argv[0], "-hrtf") == 0)
{
hrtfname = argv[1];
soundname = argv[2];
}
else
{
hrtfname = NULL;
soundname = argv[0];
}
/* Enumerate available HRTFs, and reset the device using one. */
alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf);
if(!num_hrtf)
@@ -178,19 +203,22 @@ int main(int argc, char **argv)
index = i;
}
i = 0;
attr[i++] = ALC_HRTF_SOFT;
attr[i++] = ALC_TRUE;
if(index == -1)
{
if(hrtfname)
printf("HRTF \"%s\" not found\n", hrtfname);
index = 0;
printf("Using default HRTF...\n");
}
printf("Selecting HRTF %d...\n", index);
attr[0] = ALC_HRTF_SOFT;
attr[1] = ALC_TRUE;
attr[2] = ALC_HRTF_ID_SOFT;
attr[3] = index;
attr[4] = 0;
else
{
printf("Selecting HRTF %d...\n", index);
attr[i++] = ALC_HRTF_ID_SOFT;
attr[i++] = index;
}
attr[i] = 0;
if(!alcResetDeviceSOFT(device, attr))
printf("Failed to reset device: %s\n", alcGetString(device, alcGetError(device)));
@@ -207,10 +235,14 @@ int main(int argc, char **argv)
}
fflush(stdout);
/* Initialize SDL_sound. */
Sound_Init();
/* Load the sound into a buffer. */
buffer = LoadSound(soundname);
if(!buffer)
{
Sound_Quit();
CloseAL();
return 1;
}
@@ -229,19 +261,33 @@ int main(int argc, char **argv)
do {
al_nssleep(10000000);
/* Rotate the source around the listener by about 1/4 cycle per second.
* Only affects mono sounds.
/* Rotate the source around the listener by about 1/4 cycle per second,
* and keep it within -pi...+pi.
*/
angle += 0.01 * M_PI * 0.5;
if(angle > M_PI)
angle -= M_PI*2.0;
/* This only rotates mono sounds. */
alSource3f(source, AL_POSITION, (ALfloat)sin(angle), 0.0f, -(ALfloat)cos(angle));
if(has_angle_ext)
{
/* This rotates stereo sounds with the AL_EXT_STEREO_ANGLES
* extension. Angles are specified counter-clockwise in radians.
*/
ALfloat angles[2] = { (ALfloat)(M_PI/6.0 - angle), (ALfloat)(-M_PI/6.0 - angle) };
alSourcefv(source, AL_STEREO_ANGLES, angles);
}
alGetSourcei(source, AL_SOURCE_STATE, &state);
} while(alGetError() == AL_NO_ERROR && state == AL_PLAYING);
/* All done. Delete resources, and close OpenAL. */
/* All done. Delete resources, and close down SDL_sound and OpenAL. */
alDeleteSources(1, &source);
alDeleteBuffers(1, &buffer);
Sound_Quit();
CloseAL();
return 0;
+55 -43
View File
@@ -27,17 +27,15 @@
#include <stdio.h>
#include <assert.h>
#include <SDL_sound.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "common/alhelpers.h"
#include "common/sdl_sound.h"
static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples;
static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT;
static LPALSOURCEDSOFT alSourcedSOFT;
static LPALSOURCE3DSOFT alSource3dSOFT;
static LPALSOURCEDVSOFT alSourcedvSOFT;
@@ -52,47 +50,63 @@ static LPALGETSOURCE3I64SOFT alGetSource3i64SOFT;
static LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT;
/* LoadBuffer loads the named audio file into an OpenAL buffer object, and
* returns the new buffer ID. */
* returns the new buffer ID.
*/
static ALuint LoadSound(const char *filename)
{
ALenum err, format, type, channels;
ALuint rate, buffer;
size_t datalen;
void *data;
FilePtr sound;
Sound_Sample *sample;
ALenum err, format;
ALuint buffer;
Uint32 slen;
/* Open the audio file */
sound = openAudioFile(filename, 1000);
if(!sound)
sample = Sound_NewSampleFromFile(filename, NULL, 65536);
if(!sample)
{
fprintf(stderr, "Could not open audio in %s\n", filename);
closeAudioFile(sound);
return 0;
}
/* Get the sound format, and figure out the OpenAL format */
if(getAudioInfo(sound, &rate, &channels, &type) != 0)
if(sample->actual.channels == 1)
{
fprintf(stderr, "Error getting audio info for %s\n", filename);
closeAudioFile(sound);
return 0;
if(sample->actual.format == AUDIO_U8)
format = AL_FORMAT_MONO8;
else if(sample->actual.format == AUDIO_S16SYS)
format = AL_FORMAT_MONO16;
else
{
fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format);
Sound_FreeSample(sample);
return 0;
}
}
format = GetFormat(channels, type, alIsBufferFormatSupportedSOFT);
if(format == AL_NONE)
else if(sample->actual.channels == 2)
{
fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
ChannelsName(channels), TypeName(type), filename);
closeAudioFile(sound);
if(sample->actual.format == AUDIO_U8)
format = AL_FORMAT_STEREO8;
else if(sample->actual.format == AUDIO_S16SYS)
format = AL_FORMAT_STEREO16;
else
{
fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format);
Sound_FreeSample(sample);
return 0;
}
}
else
{
fprintf(stderr, "Unsupported channel count: %d\n", sample->actual.channels);
Sound_FreeSample(sample);
return 0;
}
/* Decode the whole audio stream to a buffer. */
data = decodeAudioStream(sound, &datalen);
if(!data)
slen = Sound_DecodeAll(sample);
if(!sample->buffer || slen == 0)
{
fprintf(stderr, "Failed to read audio from %s\n", filename);
closeAudioFile(sound);
Sound_FreeSample(sample);
return 0;
}
@@ -100,17 +114,15 @@ static ALuint LoadSound(const char *filename)
* close the file. */
buffer = 0;
alGenBuffers(1, &buffer);
alBufferSamplesSOFT(buffer, rate, format, BytesToFrames(datalen, channels, type),
channels, type, data);
free(data);
closeAudioFile(sound);
alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate);
Sound_FreeSample(sample);
/* Check if an error occured, and clean up if so. */
err = alGetError();
if(err != AL_NO_ERROR)
{
fprintf(stderr, "OpenAL Error: %s\n", alGetString(err));
if(alIsBuffer(buffer))
if(buffer && alIsBuffer(buffer))
alDeleteBuffers(1, &buffer);
return 0;
}
@@ -125,15 +137,16 @@ int main(int argc, char **argv)
ALdouble offsets[2];
ALenum state;
/* Print out usage if no file was specified */
/* Print out usage if no arguments were specified */
if(argc < 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
fprintf(stderr, "Usage: %s [-device <name>] <filename>\n", argv[0]);
return 1;
}
/* Initialize OpenAL with the default device, and check for EFX support. */
if(InitAL() != 0)
/* Initialize OpenAL, and check for source_latency support. */
argv++; argc--;
if(InitAL(&argv, &argc) != 0)
return 1;
if(!alIsExtensionPresent("AL_SOFT_source_latency"))
@@ -157,18 +170,16 @@ int main(int argc, char **argv)
LOAD_PROC(alGetSourcei64SOFT);
LOAD_PROC(alGetSource3i64SOFT);
LOAD_PROC(alGetSourcei64vSOFT);
if(alIsExtensionPresent("AL_SOFT_buffer_samples"))
{
LOAD_PROC(alBufferSamplesSOFT);
LOAD_PROC(alIsBufferFormatSupportedSOFT);
}
#undef LOAD_PROC
/* Initialize SDL_sound. */
Sound_Init();
/* Load the sound into a buffer. */
buffer = LoadSound(argv[1]);
buffer = LoadSound(argv[0]);
if(!buffer)
{
Sound_Quit();
CloseAL();
return 1;
}
@@ -194,10 +205,11 @@ int main(int argc, char **argv)
} while(alGetError() == AL_NO_ERROR && state == AL_PLAYING);
printf("\n");
/* All done. Delete resources, and close OpenAL. */
/* All done. Delete resources, and close down SDL_sound and OpenAL. */
alDeleteSources(1, &source);
alDeleteBuffers(1, &buffer);
Sound_Quit();
CloseAL();
return 0;
+37 -1
View File
@@ -38,6 +38,13 @@
#include "common/alhelpers.h"
#ifndef SDL_AUDIO_MASK_BITSIZE
#define SDL_AUDIO_MASK_BITSIZE (0xFF)
#endif
#ifndef SDL_AUDIO_BITSIZE
#define SDL_AUDIO_BITSIZE(x) (x & SDL_AUDIO_MASK_BITSIZE)
#endif
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
@@ -61,6 +68,35 @@ void SDLCALL RenderSDLSamples(void *userdata, Uint8 *stream, int len)
}
static const char *ChannelsName(ALCenum chans)
{
switch(chans)
{
case ALC_MONO_SOFT: return "Mono";
case ALC_STEREO_SOFT: return "Stereo";
case ALC_QUAD_SOFT: return "Quadraphonic";
case ALC_5POINT1_SOFT: return "5.1 Surround";
case ALC_6POINT1_SOFT: return "6.1 Surround";
case ALC_7POINT1_SOFT: return "7.1 Surround";
}
return "Unknown Channels";
}
static const char *TypeName(ALCenum type)
{
switch(type)
{
case ALC_BYTE_SOFT: return "S8";
case ALC_UNSIGNED_BYTE_SOFT: return "U8";
case ALC_SHORT_SOFT: return "S16";
case ALC_UNSIGNED_SHORT_SOFT: return "U16";
case ALC_INT_SOFT: return "S32";
case ALC_UNSIGNED_INT_SOFT: return "U32";
case ALC_FLOAT_SOFT: return "Float32";
}
return "Unknown Type";
}
/* Creates a one second buffer containing a sine wave, and returns the new
* buffer ID. */
static ALuint CreateSineWave(void)
@@ -169,7 +205,7 @@ int main(int argc, char *argv[])
attrs[6] = 0; /* end of list */
playback.FrameSize = FramesToBytes(1, attrs[1], attrs[3]);
playback.FrameSize = obtained.channels * SDL_AUDIO_BITSIZE(obtained.format) / 8;
/* Initialize OpenAL loopback device, using our format attributes. */
playback.Device = alcLoopbackOpenDeviceSOFT(NULL);
+386
View File
@@ -0,0 +1,386 @@
/*
* OpenAL Recording Example
*
* Copyright (c) 2017 by Chris Robinson <chris.kcat@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* This file contains a relatively simple recorder. */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "common/alhelpers.h"
#if defined(_WIN64)
#define SZFMT "%I64u"
#elif defined(_WIN32)
#define SZFMT "%u"
#else
#define SZFMT "%zu"
#endif
static void fwrite16le(ALushort val, FILE *f)
{
ALubyte data[2] = { val&0xff, (val>>8)&0xff };
fwrite(data, 1, 2, f);
}
static void fwrite32le(ALuint val, FILE *f)
{
ALubyte data[4] = { val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff };
fwrite(data, 1, 4, f);
}
typedef struct Recorder {
ALCdevice *mDevice;
FILE *mFile;
long mDataSizeOffset;
size_t mDataSize;
float mRecTime;
int mChannels;
int mBits;
int mSampleRate;
size_t mFrameSize;
ALbyte *mBuffer;
ALsizei mBufferSize;
} Recorder;
int main(int argc, char **argv)
{
static const char optlist[] =
" --channels/-c <channels> Set channel count (1 or 2)\n"
" --bits/-b <bits> Set channel count (8, 16, or 32)\n"
" --rate/-r <rate> Set sample rate (8000 to 96000)\n"
" --time/-t <time> Time in seconds to record (1 to 10)\n"
" --outfile/-o <filename> Output filename (default: record.wav)";
const char *fname = "record.wav";
const char *devname = NULL;
const char *progname;
Recorder recorder;
long total_size;
ALenum format;
ALCenum err;
progname = argv[0];
if(argc < 2)
{
fprintf(stderr, "Record from a device to a wav file.\n\n"
"Usage: %s [-device <name>] [options...]\n\n"
"Available options:\n%s\n", progname, optlist);
return 0;
}
recorder.mDevice = NULL;
recorder.mFile = NULL;
recorder.mDataSizeOffset = 0;
recorder.mDataSize = 0;
recorder.mRecTime = 4.0f;
recorder.mChannels = 1;
recorder.mBits = 16;
recorder.mSampleRate = 44100;
recorder.mFrameSize = recorder.mChannels * recorder.mBits / 8;
recorder.mBuffer = NULL;
recorder.mBufferSize = 0;
argv++; argc--;
if(argc > 1 && strcmp(argv[0], "-device") == 0)
{
devname = argv[1];
argv += 2;
argc -= 2;
}
while(argc > 0)
{
char *end;
if(strcmp(argv[0], "--") == 0)
break;
else if(strcmp(argv[0], "--channels") == 0 || strcmp(argv[0], "-c") == 0)
{
if(!(argc > 1))
{
fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
return 1;
}
recorder.mChannels = strtol(argv[1], &end, 0);
if((recorder.mChannels != 1 && recorder.mChannels != 2) || (end && *end != '\0'))
{
fprintf(stderr, "Invalid channels: %s\n", argv[1]);
return 1;
}
argv += 2;
argc -= 2;
}
else if(strcmp(argv[0], "--bits") == 0 || strcmp(argv[0], "-b") == 0)
{
if(!(argc > 1))
{
fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
return 1;
}
recorder.mBits = strtol(argv[1], &end, 0);
if((recorder.mBits != 8 && recorder.mBits != 16 && recorder.mBits != 32) ||
(end && *end != '\0'))
{
fprintf(stderr, "Invalid bit count: %s\n", argv[1]);
return 1;
}
argv += 2;
argc -= 2;
}
else if(strcmp(argv[0], "--rate") == 0 || strcmp(argv[0], "-r") == 0)
{
if(!(argc > 1))
{
fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
return 1;
}
recorder.mSampleRate = strtol(argv[1], &end, 0);
if(!(recorder.mSampleRate >= 8000 && recorder.mSampleRate <= 96000) || (end && *end != '\0'))
{
fprintf(stderr, "Invalid sample rate: %s\n", argv[1]);
return 1;
}
argv += 2;
argc -= 2;
}
else if(strcmp(argv[0], "--time") == 0 || strcmp(argv[0], "-t") == 0)
{
if(!(argc > 1))
{
fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
return 1;
}
recorder.mRecTime = strtod(argv[1], &end);
if(!(recorder.mRecTime >= 1.0f && recorder.mRecTime <= 10.0f) || (end && *end != '\0'))
{
fprintf(stderr, "Invalid record time: %s\n", argv[1]);
return 1;
}
argv += 2;
argc -= 2;
}
else if(strcmp(argv[0], "--outfile") == 0 || strcmp(argv[0], "-o") == 0)
{
if(!(argc > 1))
{
fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
return 1;
}
fname = argv[1];
argv += 2;
argc -= 2;
}
else if(strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-h") == 0)
{
fprintf(stderr, "Record from a device to a wav file.\n\n"
"Usage: %s [-device <name>] [options...]\n\n"
"Available options:\n%s\n", progname, optlist);
return 0;
}
else
{
fprintf(stderr, "Invalid option '%s'.\n\n"
"Usage: %s [-device <name>] [options...]\n\n"
"Available options:\n%s\n", argv[0], progname, optlist);
return 0;
}
}
recorder.mFrameSize = recorder.mChannels * recorder.mBits / 8;
format = AL_NONE;
if(recorder.mChannels == 1)
{
if(recorder.mBits == 8)
format = AL_FORMAT_MONO8;
else if(recorder.mBits == 16)
format = AL_FORMAT_MONO16;
else if(recorder.mBits == 32)
format = AL_FORMAT_MONO_FLOAT32;
}
else if(recorder.mChannels == 2)
{
if(recorder.mBits == 8)
format = AL_FORMAT_STEREO8;
else if(recorder.mBits == 16)
format = AL_FORMAT_STEREO16;
else if(recorder.mBits == 32)
format = AL_FORMAT_STEREO_FLOAT32;
}
recorder.mDevice = alcCaptureOpenDevice(devname, recorder.mSampleRate, format, 32768);
if(!recorder.mDevice)
{
fprintf(stderr, "Failed to open %s, %s %d-bit, %s, %dhz (%d samples)\n",
devname ? devname : "default device",
(recorder.mBits == 32) ? "Float" :
(recorder.mBits != 8) ? "Signed" : "Unsigned", recorder.mBits,
(recorder.mChannels == 1) ? "Mono" : "Stereo", recorder.mSampleRate,
32768
);
return 1;
}
fprintf(stderr, "Opened \"%s\"\n", alcGetString(
recorder.mDevice, ALC_CAPTURE_DEVICE_SPECIFIER
));
recorder.mFile = fopen(fname, "wb");
if(!recorder.mFile)
{
fprintf(stderr, "Failed to open '%s' for writing\n", fname);
alcCaptureCloseDevice(recorder.mDevice);
return 1;
}
fputs("RIFF", recorder.mFile);
fwrite32le(0xFFFFFFFF, recorder.mFile); // 'RIFF' header len; filled in at close
fputs("WAVE", recorder.mFile);
fputs("fmt ", recorder.mFile);
fwrite32le(18, recorder.mFile); // 'fmt ' header len
// 16-bit val, format type id (1 = integer PCM, 3 = float PCM)
fwrite16le((recorder.mBits == 32) ? 0x0003 : 0x0001, recorder.mFile);
// 16-bit val, channel count
fwrite16le(recorder.mChannels, recorder.mFile);
// 32-bit val, frequency
fwrite32le(recorder.mSampleRate, recorder.mFile);
// 32-bit val, bytes per second
fwrite32le(recorder.mSampleRate * recorder.mFrameSize, recorder.mFile);
// 16-bit val, frame size
fwrite16le(recorder.mFrameSize, recorder.mFile);
// 16-bit val, bits per sample
fwrite16le(recorder.mBits, recorder.mFile);
// 16-bit val, extra byte count
fwrite16le(0, recorder.mFile);
fputs("data", recorder.mFile);
fwrite32le(0xFFFFFFFF, recorder.mFile); // 'data' header len; filled in at close
recorder.mDataSizeOffset = ftell(recorder.mFile) - 4;
if(ferror(recorder.mFile) || recorder.mDataSizeOffset < 0)
{
fprintf(stderr, "Error writing header: %s\n", strerror(errno));
fclose(recorder.mFile);
alcCaptureCloseDevice(recorder.mDevice);
return 1;
}
fprintf(stderr, "Recording '%s', %s %d-bit, %s, %dhz (%g second%s)\n", fname,
(recorder.mBits == 32) ? "Float" :
(recorder.mBits != 8) ? "Signed" : "Unsigned", recorder.mBits,
(recorder.mChannels == 1) ? "Mono" : "Stereo", recorder.mSampleRate,
recorder.mRecTime, (recorder.mRecTime != 1.0f) ? "s" : ""
);
alcCaptureStart(recorder.mDevice);
while((double)recorder.mDataSize/(double)recorder.mSampleRate < recorder.mRecTime &&
(err=alcGetError(recorder.mDevice)) == ALC_NO_ERROR && !ferror(recorder.mFile))
{
ALCint count = 0;
fprintf(stderr, "\rCaptured "SZFMT" samples", recorder.mDataSize);
alcGetIntegerv(recorder.mDevice, ALC_CAPTURE_SAMPLES, 1, &count);
if(count < 1)
{
al_nssleep(10000000);
continue;
}
if(count > recorder.mBufferSize)
{
ALbyte *data = calloc(recorder.mFrameSize, count);
free(recorder.mBuffer);
recorder.mBuffer = data;
recorder.mBufferSize = count;
}
alcCaptureSamples(recorder.mDevice, recorder.mBuffer, count);
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN
/* Byteswap multibyte samples on big-endian systems (wav needs little-
* endian, and OpenAL gives the system's native-endian).
*/
if(recorder.mBits == 16)
{
ALCint i;
for(i = 0;i < count*recorder.mChannels;i++)
{
ALbyte b = recorder.mBuffer[i*2 + 0];
recorder.mBuffer[i*2 + 0] = recorder.mBuffer[i*2 + 1];
recorder.mBuffer[i*2 + 1] = b;
}
}
else if(recorder.mBits == 32)
{
ALCint i;
for(i = 0;i < count*recorder.mChannels;i++)
{
ALbyte b0 = recorder.mBuffer[i*4 + 0];
ALbyte b1 = recorder.mBuffer[i*4 + 1];
recorder.mBuffer[i*4 + 0] = recorder.mBuffer[i*4 + 3];
recorder.mBuffer[i*4 + 1] = recorder.mBuffer[i*4 + 2];
recorder.mBuffer[i*4 + 2] = b1;
recorder.mBuffer[i*4 + 3] = b0;
}
}
#endif
recorder.mDataSize += fwrite(recorder.mBuffer, recorder.mFrameSize, count, recorder.mFile);
}
alcCaptureStop(recorder.mDevice);
fprintf(stderr, "\rCaptured "SZFMT" samples\n", recorder.mDataSize);
if(err != ALC_NO_ERROR)
fprintf(stderr, "Got device error 0x%04x: %s\n", err, alcGetString(recorder.mDevice, err));
alcCaptureCloseDevice(recorder.mDevice);
recorder.mDevice = NULL;
free(recorder.mBuffer);
recorder.mBuffer = NULL;
recorder.mBufferSize = 0;
total_size = ftell(recorder.mFile);
if(fseek(recorder.mFile, recorder.mDataSizeOffset, SEEK_SET) == 0)
{
fwrite32le(recorder.mDataSize*recorder.mFrameSize, recorder.mFile);
if(fseek(recorder.mFile, 4, SEEK_SET) == 0)
fwrite32le(total_size - 8, recorder.mFile);
}
fclose(recorder.mFile);
recorder.mFile = NULL;
return 0;
}
+57 -43
View File
@@ -27,18 +27,16 @@
#include <stdio.h>
#include <assert.h>
#include <SDL_sound.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "AL/efx-presets.h"
#include "common/alhelpers.h"
#include "common/sdl_sound.h"
static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples;
static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT;
/* Effect object functions */
static LPALGENEFFECTS alGenEffects;
static LPALDELETEEFFECTS alDeleteEffects;
@@ -145,46 +143,63 @@ static ALuint LoadEffect(const EFXEAXREVERBPROPERTIES *reverb)
/* LoadBuffer loads the named audio file into an OpenAL buffer object, and
* returns the new buffer ID. */
* returns the new buffer ID.
*/
static ALuint LoadSound(const char *filename)
{
ALenum err, format, type, channels;
ALuint rate, buffer;
size_t datalen;
void *data;
FilePtr sound;
Sound_Sample *sample;
ALenum err, format;
ALuint buffer;
Uint32 slen;
/* Open the file and get the first stream from it */
sound = openAudioFile(filename, 1000);
if(!sound)
/* Open the audio file */
sample = Sound_NewSampleFromFile(filename, NULL, 65536);
if(!sample)
{
fprintf(stderr, "Could not open audio in %s\n", filename);
return 0;
}
/* Get the sound format, and figure out the OpenAL format */
if(getAudioInfo(sound, &rate, &channels, &type) != 0)
if(sample->actual.channels == 1)
{
fprintf(stderr, "Error getting audio info for %s\n", filename);
closeAudioFile(sound);
return 0;
if(sample->actual.format == AUDIO_U8)
format = AL_FORMAT_MONO8;
else if(sample->actual.format == AUDIO_S16SYS)
format = AL_FORMAT_MONO16;
else
{
fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format);
Sound_FreeSample(sample);
return 0;
}
}
format = GetFormat(channels, type, alIsBufferFormatSupportedSOFT);
if(format == AL_NONE)
else if(sample->actual.channels == 2)
{
fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
ChannelsName(channels), TypeName(type), filename);
closeAudioFile(sound);
if(sample->actual.format == AUDIO_U8)
format = AL_FORMAT_STEREO8;
else if(sample->actual.format == AUDIO_S16SYS)
format = AL_FORMAT_STEREO16;
else
{
fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format);
Sound_FreeSample(sample);
return 0;
}
}
else
{
fprintf(stderr, "Unsupported channel count: %d\n", sample->actual.channels);
Sound_FreeSample(sample);
return 0;
}
/* Decode the whole audio stream to a buffer. */
data = decodeAudioStream(sound, &datalen);
if(!data)
slen = Sound_DecodeAll(sample);
if(!sample->buffer || slen == 0)
{
fprintf(stderr, "Failed to read audio from %s\n", filename);
closeAudioFile(sound);
Sound_FreeSample(sample);
return 0;
}
@@ -192,17 +207,15 @@ static ALuint LoadSound(const char *filename)
* close the file. */
buffer = 0;
alGenBuffers(1, &buffer);
alBufferSamplesSOFT(buffer, rate, format, BytesToFrames(datalen, channels, type),
channels, type, data);
free(data);
closeAudioFile(sound);
alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate);
Sound_FreeSample(sample);
/* Check if an error occured, and clean up if so. */
err = alGetError();
if(err != AL_NO_ERROR)
{
fprintf(stderr, "OpenAL Error: %s\n", alGetString(err));
if(alIsBuffer(buffer))
if(buffer && alIsBuffer(buffer))
alDeleteBuffers(1, &buffer);
return 0;
}
@@ -217,15 +230,16 @@ int main(int argc, char **argv)
ALuint source, buffer, effect, slot;
ALenum state;
/* Print out usage if no file was specified */
/* Print out usage if no arguments were specified */
if(argc < 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
fprintf(stderr, "Usage: %s [-device <name] <filename>\n", argv[0]);
return 1;
}
/* Initialize OpenAL with the default device, and check for EFX support. */
if(InitAL() != 0)
/* Initialize OpenAL, and check for EFX support. */
argv++; argc--;
if(InitAL(&argv, &argc) != 0)
return 1;
if(!alcIsExtensionPresent(alcGetContextsDevice(alcGetCurrentContext()), "ALC_EXT_EFX"))
@@ -260,19 +274,17 @@ int main(int argc, char **argv)
LOAD_PROC(alGetAuxiliaryEffectSlotiv);
LOAD_PROC(alGetAuxiliaryEffectSlotf);
LOAD_PROC(alGetAuxiliaryEffectSlotfv);
if(alIsExtensionPresent("AL_SOFT_buffer_samples"))
{
LOAD_PROC(alBufferSamplesSOFT);
LOAD_PROC(alIsBufferFormatSupportedSOFT);
}
#undef LOAD_PROC
/* Initialize SDL_sound. */
Sound_Init();
/* Load the sound into a buffer. */
buffer = LoadSound(argv[1]);
buffer = LoadSound(argv[0]);
if(!buffer)
{
CloseAL();
Sound_Quit();
return 1;
}
@@ -281,6 +293,7 @@ int main(int argc, char **argv)
if(!effect)
{
alDeleteBuffers(1, &buffer);
Sound_Quit();
CloseAL();
return 1;
}
@@ -315,12 +328,13 @@ int main(int argc, char **argv)
alGetSourcei(source, AL_SOURCE_STATE, &state);
} while(alGetError() == AL_NO_ERROR && state == AL_PLAYING);
/* All done. Delete resources, and close OpenAL. */
/* All done. Delete resources, and close down SDL_sound and OpenAL. */
alDeleteSources(1, &source);
alDeleteAuxiliaryEffectSlots(1, &slot);
alDeleteEffects(1, &effect);
alDeleteBuffers(1, &buffer);
Sound_Quit();
CloseAL();
return 0;
+76 -58
View File
@@ -30,17 +30,21 @@
#include <signal.h>
#include <assert.h>
#include <SDL_sound.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "common/alhelpers.h"
#include "common/sdl_sound.h"
static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples;
static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT;
#ifndef SDL_AUDIO_MASK_BITSIZE
#define SDL_AUDIO_MASK_BITSIZE (0xFF)
#endif
#ifndef SDL_AUDIO_BITSIZE
#define SDL_AUDIO_BITSIZE(x) (x & SDL_AUDIO_MASK_BITSIZE)
#endif
/* Define the number of buffers and buffer size (in milliseconds) to use. 4
* buffers with 200ms each gives a nice per-chunk size, and lets the queue last
@@ -54,13 +58,11 @@ typedef struct StreamPlayer {
ALuint source;
/* Handle for the audio file */
FilePtr file;
Sound_Sample *sample;
/* The format of the output stream */
ALenum format;
ALenum channels;
ALenum type;
ALuint rate;
ALsizei srate;
} StreamPlayer;
static StreamPlayer *NewPlayer(void);
@@ -77,11 +79,9 @@ static StreamPlayer *NewPlayer(void)
{
StreamPlayer *player;
player = malloc(sizeof(*player));
player = calloc(1, sizeof(*player));
assert(player != NULL);
memset(player, 0, sizeof(*player));
/* Generate the buffers and source */
alGenBuffers(NUM_BUFFERS, player->buffers);
assert(alGetError() == AL_NO_ERROR && "Could not create buffers");
@@ -119,37 +119,63 @@ static void DeletePlayer(StreamPlayer *player)
* it will be closed first. */
static int OpenPlayerFile(StreamPlayer *player, const char *filename)
{
Uint32 frame_size;
ClosePlayerFile(player);
/* Open the file and get the first stream from it */
player->file = openAudioFile(filename, BUFFER_TIME_MS);
if(!player->file)
player->sample = Sound_NewSampleFromFile(filename, NULL, 0);
if(!player->sample)
{
fprintf(stderr, "Could not open audio in %s\n", filename);
goto error;
}
/* Get the stream format, and figure out the OpenAL format */
if(getAudioInfo(player->file, &player->rate, &player->channels, &player->type) != 0)
if(player->sample->actual.channels == 1)
{
fprintf(stderr, "Error getting audio info for %s\n", filename);
if(player->sample->actual.format == AUDIO_U8)
player->format = AL_FORMAT_MONO8;
else if(player->sample->actual.format == AUDIO_S16SYS)
player->format = AL_FORMAT_MONO16;
else
{
fprintf(stderr, "Unsupported sample format: 0x%04x\n", player->sample->actual.format);
goto error;
}
}
else if(player->sample->actual.channels == 2)
{
if(player->sample->actual.format == AUDIO_U8)
player->format = AL_FORMAT_STEREO8;
else if(player->sample->actual.format == AUDIO_S16SYS)
player->format = AL_FORMAT_STEREO16;
else
{
fprintf(stderr, "Unsupported sample format: 0x%04x\n", player->sample->actual.format);
goto error;
}
}
else
{
fprintf(stderr, "Unsupported channel count: %d\n", player->sample->actual.channels);
goto error;
}
player->srate = player->sample->actual.rate;
player->format = GetFormat(player->channels, player->type, alIsBufferFormatSupportedSOFT);
if(player->format == 0)
{
fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
ChannelsName(player->channels), TypeName(player->type),
filename);
goto error;
}
frame_size = player->sample->actual.channels *
SDL_AUDIO_BITSIZE(player->sample->actual.format) / 8;
/* Set the buffer size, given the desired millisecond length. */
Sound_SetBufferSize(player->sample, (Uint32)((Uint64)player->srate*BUFFER_TIME_MS/1000) *
frame_size);
return 1;
error:
closeAudioFile(player->file);
player->file = NULL;
if(player->sample)
Sound_FreeSample(player->sample);
player->sample = NULL;
return 0;
}
@@ -157,8 +183,9 @@ error:
/* Closes the audio file stream */
static void ClosePlayerFile(StreamPlayer *player)
{
closeAudioFile(player->file);
player->file = NULL;
if(player->sample)
Sound_FreeSample(player->sample);
player->sample = NULL;
}
@@ -174,16 +201,12 @@ static int StartPlayer(StreamPlayer *player)
/* Fill the buffer queue */
for(i = 0;i < NUM_BUFFERS;i++)
{
uint8_t *data;
size_t got;
/* Get some data to give it to the buffer */
data = getAudioData(player->file, &got);
if(!data) break;
Uint32 slen = Sound_Decode(player->sample);
if(slen == 0) break;
alBufferSamplesSOFT(player->buffers[i], player->rate, player->format,
BytesToFrames(got, player->channels, player->type),
player->channels, player->type, data);
alBufferData(player->buffers[i], player->format,
player->sample->buffer, slen, player->srate);
}
if(alGetError() != AL_NO_ERROR)
{
@@ -220,20 +243,21 @@ static int UpdatePlayer(StreamPlayer *player)
while(processed > 0)
{
ALuint bufid;
uint8_t *data;
size_t got;
Uint32 slen;
alSourceUnqueueBuffers(player->source, 1, &bufid);
processed--;
if((player->sample->flags&(SOUND_SAMPLEFLAG_EOF|SOUND_SAMPLEFLAG_ERROR)))
continue;
/* Read the next chunk of data, refill the buffer, and queue it
* back on the source */
data = getAudioData(player->file, &got);
if(data != NULL)
slen = Sound_Decode(player->sample);
if(slen > 0)
{
alBufferSamplesSOFT(bufid, player->rate, player->format,
BytesToFrames(got, player->channels, player->type),
player->channels, player->type, data);
alBufferData(bufid, player->format, player->sample->buffer, slen,
player->srate);
alSourceQueueBuffers(player->source, 1, &bufid);
}
if(alGetError() != AL_NO_ERROR)
@@ -270,29 +294,23 @@ int main(int argc, char **argv)
StreamPlayer *player;
int i;
/* Print out usage if no file was specified */
/* Print out usage if no arguments were specified */
if(argc < 2)
{
fprintf(stderr, "Usage: %s <filenames...>\n", argv[0]);
fprintf(stderr, "Usage: %s [-device <name>] <filenames...>\n", argv[0]);
return 1;
}
if(InitAL() != 0)
argv++; argc--;
if(InitAL(&argv, &argc) != 0)
return 1;
if(alIsExtensionPresent("AL_SOFT_buffer_samples"))
{
printf("AL_SOFT_buffer_samples supported!\n");
alBufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
alIsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
}
else
printf("AL_SOFT_buffer_samples not supported\n");
Sound_Init();
player = NewPlayer();
/* Play each file listed on the command line */
for(i = 1;i < argc;i++)
for(i = 0;i < argc;i++)
{
const char *namepart;
@@ -306,9 +324,8 @@ int main(int argc, char **argv)
else
namepart = argv[i];
printf("Playing: %s (%s, %s, %dhz)\n", namepart,
TypeName(player->type), ChannelsName(player->channels),
player->rate);
printf("Playing: %s (%s, %dhz)\n", namepart, FormatName(player->format),
player->srate);
fflush(stdout);
if(!StartPlayer(player))
@@ -325,10 +342,11 @@ int main(int argc, char **argv)
}
printf("Done.\n");
/* All files done. Delete the player, and close OpenAL */
/* All files done. Delete the player, and close down SDL_sound and OpenAL */
DeletePlayer(player);
player = NULL;
Sound_Quit();
CloseAL();
return 0;
+66 -31
View File
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include <math.h>
#include "AL/al.h"
@@ -53,6 +54,7 @@ enum WaveType {
WT_Sawtooth,
WT_Triangle,
WT_Impulse,
WT_WhiteNoise,
};
static const char *GetWaveTypeName(enum WaveType type)
@@ -64,10 +66,17 @@ static const char *GetWaveTypeName(enum WaveType type)
case WT_Sawtooth: return "sawtooth";
case WT_Triangle: return "triangle";
case WT_Impulse: return "impulse";
case WT_WhiteNoise: return "noise";
}
return "(unknown)";
}
static inline ALuint dither_rng(ALuint *seed)
{
*seed = (*seed * 96314165) + 907633515;
return *seed;
}
static void ApplySin(ALfloat *data, ALdouble g, ALuint srate, ALuint freq)
{
ALdouble smps_per_cycle = (ALdouble)srate / freq;
@@ -81,6 +90,7 @@ static void ApplySin(ALfloat *data, ALdouble g, ALuint srate, ALuint freq)
*/
static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate)
{
ALuint seed = 22222;
ALint data_size;
ALfloat *data;
ALuint buffer;
@@ -89,25 +99,44 @@ static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate)
data_size = srate * sizeof(ALfloat);
data = calloc(1, data_size);
if(type == WT_Sine)
ApplySin(data, 1.0, srate, freq);
else if(type == WT_Square)
for(i = 1;freq*i < srate/2;i+=2)
ApplySin(data, 4.0/M_PI * 1.0/i, srate, freq*i);
else if(type == WT_Sawtooth)
for(i = 1;freq*i < srate/2;i++)
ApplySin(data, 2.0/M_PI * ((i&1)*2 - 1.0) / i, srate, freq*i);
else if(type == WT_Triangle)
for(i = 1;freq*i < srate/2;i+=2)
ApplySin(data, 8.0/(M_PI*M_PI) * (1.0 - (i&2)) / (i*i), srate, freq*i);
else if(type == WT_Impulse)
switch(type)
{
/* NOTE: Impulse isn't really a waveform, but it can still be useful to
* test (other than resampling, the ALSOFT_DEFAULT_REVERB environment
* variable can prove useful here to test the reverb response).
*/
for(i = 0;i < srate;i++)
data[i] = (i%(srate/freq)) ? 0.0f : 1.0f;
case WT_Sine:
ApplySin(data, 1.0, srate, freq);
break;
case WT_Square:
for(i = 1;freq*i < srate/2;i+=2)
ApplySin(data, 4.0/M_PI * 1.0/i, srate, freq*i);
break;
case WT_Sawtooth:
for(i = 1;freq*i < srate/2;i++)
ApplySin(data, 2.0/M_PI * ((i&1)*2 - 1.0) / i, srate, freq*i);
break;
case WT_Triangle:
for(i = 1;freq*i < srate/2;i+=2)
ApplySin(data, 8.0/(M_PI*M_PI) * (1.0 - (i&2)) / (i*i), srate, freq*i);
break;
case WT_Impulse:
/* NOTE: Impulse isn't handled using additive synthesis, and is
* instead just a non-0 sample at a given rate. This can still be
* useful to test (other than resampling, the ALSOFT_DEFAULT_REVERB
* environment variable can prove useful here to test the reverb
* response).
*/
for(i = 0;i < srate;i++)
data[i] = (i%(srate/freq)) ? 0.0f : 1.0f;
break;
case WT_WhiteNoise:
/* NOTE: WhiteNoise is just uniform set of uncorrelated values, and
* is not influenced by the waveform frequency.
*/
for(i = 0;i < srate;i++)
{
ALuint rng0 = dither_rng(&seed);
ALuint rng1 = dither_rng(&seed);
data[i] = (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX));
}
break;
}
/* Buffer the audio data into a new buffer object. */
@@ -133,6 +162,7 @@ static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate)
int main(int argc, char *argv[])
{
enum WaveType wavetype = WT_Sine;
const char *appname = argv[0];
ALuint source, buffer;
ALint last_pos, num_loops;
ALint max_loops = 4;
@@ -142,23 +172,35 @@ int main(int argc, char *argv[])
ALenum state;
int i;
for(i = 1;i < argc;i++)
argv++; argc--;
if(InitAL(&argv, &argc) != 0)
return 1;
if(!alIsExtensionPresent("AL_EXT_FLOAT32"))
{
fprintf(stderr, "Required AL_EXT_FLOAT32 extension not supported on this device!\n");
CloseAL();
return 1;
}
for(i = 0;i < argc;i++)
{
if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
{
fprintf(stderr, "OpenAL Tone Generator\n"
"\n"
"Usage: %s <options>\n"
"Usage: %s [-device <name>] <options>\n"
"\n"
"Available options:\n"
" --help/-h This help text\n"
" -t <seconds> Time to play a tone (default 5 seconds)\n"
" --waveform/-w <type> Waveform type: sine (default), square, sawtooth,\n"
" triangle, impulse\n"
" triangle, impulse, noise\n"
" --freq/-f <hz> Tone frequency (default 1000 hz)\n"
" --srate/-s <sample rate> Sampling rate (default output rate)\n",
argv[0]
appname
);
CloseAL();
return 1;
}
else if(i+1 < argc && strcmp(argv[i], "-t") == 0)
@@ -179,6 +221,8 @@ int main(int argc, char *argv[])
wavetype = WT_Triangle;
else if(strcmp(argv[i], "impulse") == 0)
wavetype = WT_Impulse;
else if(strcmp(argv[i], "noise") == 0)
wavetype = WT_WhiteNoise;
else
fprintf(stderr, "Unhandled waveform: %s\n", argv[i]);
}
@@ -204,15 +248,6 @@ int main(int argc, char *argv[])
}
}
InitAL();
if(!alIsExtensionPresent("AL_EXT_FLOAT32"))
{
fprintf(stderr, "Required AL_EXT_FLOAT32 extension not supported on this device!\n");
CloseAL();
return 1;
}
{
ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext());
alcGetIntegerv(device, ALC_FREQUENCY, 1, &dev_rate);
+31 -242
View File
@@ -29,6 +29,7 @@
* channel configs and sample types. */
#include <stdio.h>
#include <string.h>
#include "AL/al.h"
#include "AL/alc.h"
@@ -37,15 +38,26 @@
#include "alhelpers.h"
/* InitAL opens the default device and sets up a context using default
* attributes, making the program ready to call OpenAL functions. */
int InitAL(void)
/* InitAL opens a device and sets up a context using default attributes, making
* the program ready to call OpenAL functions. */
int InitAL(char ***argv, int *argc)
{
const ALCchar *name;
ALCdevice *device;
ALCcontext *ctx;
/* Open and initialize a device with default settings */
device = alcOpenDevice(NULL);
/* Open and initialize a device */
device = NULL;
if(argc && argv && *argc > 1 && strcmp((*argv)[0], "-device") == 0)
{
device = alcOpenDevice((*argv)[1]);
if(!device)
fprintf(stderr, "Failed to open \"%s\", trying default\n", (*argv)[1]);
(*argv) += 2;
(*argc) -= 2;
}
if(!device)
device = alcOpenDevice(NULL);
if(!device)
{
fprintf(stderr, "Could not open a device!\n");
@@ -62,7 +74,13 @@ int InitAL(void)
return 1;
}
printf("Opened \"%s\"\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
name = NULL;
if(alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT"))
name = alcGetString(device, ALC_ALL_DEVICES_SPECIFIER);
if(!name || alcGetError(device) != AL_NO_ERROR)
name = alcGetString(device, ALC_DEVICE_SPECIFIER);
printf("Opened \"%s\"\n", name);
return 0;
}
@@ -85,243 +103,14 @@ void CloseAL(void)
}
/* GetFormat retrieves a compatible buffer format given the channel config and
* sample type. If an alIsBufferFormatSupportedSOFT-compatible function is
* provided, it will be called to find the closest-matching format from
* AL_SOFT_buffer_samples. Returns AL_NONE (0) if no supported format can be
* found. */
ALenum GetFormat(ALenum channels, ALenum type, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT)
const char *FormatName(ALenum format)
{
ALenum format = AL_NONE;
/* If using AL_SOFT_buffer_samples, try looking through its formats */
if(palIsBufferFormatSupportedSOFT)
switch(format)
{
/* AL_SOFT_buffer_samples is more lenient with matching formats. The
* specified sample type does not need to match the returned format,
* but it is nice to try to get something close. */
if(type == AL_UNSIGNED_BYTE_SOFT || type == AL_BYTE_SOFT)
{
if(channels == AL_MONO_SOFT) format = AL_MONO8_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO8_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD8_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_8_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_8_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_8_SOFT;
}
else if(type == AL_UNSIGNED_SHORT_SOFT || type == AL_SHORT_SOFT)
{
if(channels == AL_MONO_SOFT) format = AL_MONO16_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO16_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD16_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_16_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_16_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_16_SOFT;
}
else if(type == AL_UNSIGNED_BYTE3_SOFT || type == AL_BYTE3_SOFT ||
type == AL_UNSIGNED_INT_SOFT || type == AL_INT_SOFT ||
type == AL_FLOAT_SOFT || type == AL_DOUBLE_SOFT)
{
if(channels == AL_MONO_SOFT) format = AL_MONO32F_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO32F_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD32F_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_32F_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_32F_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_32F_SOFT;
}
if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format))
format = AL_NONE;
/* A matching format was not found or supported. Try 32-bit float. */
if(format == AL_NONE)
{
if(channels == AL_MONO_SOFT) format = AL_MONO32F_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO32F_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD32F_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_32F_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_32F_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_32F_SOFT;
if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format))
format = AL_NONE;
}
/* 32-bit float not supported. Try 16-bit int. */
if(format == AL_NONE)
{
if(channels == AL_MONO_SOFT) format = AL_MONO16_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO16_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD16_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_16_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_16_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_16_SOFT;
if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format))
format = AL_NONE;
}
/* 16-bit int not supported. Try 8-bit int. */
if(format == AL_NONE)
{
if(channels == AL_MONO_SOFT) format = AL_MONO8_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO8_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD8_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_8_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_8_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_8_SOFT;
if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format))
format = AL_NONE;
}
return format;
case AL_FORMAT_MONO8: return "Mono, U8";
case AL_FORMAT_MONO16: return "Mono, S16";
case AL_FORMAT_STEREO8: return "Stereo, U8";
case AL_FORMAT_STEREO16: return "Stereo, S16";
}
/* We use the AL_EXT_MCFORMATS extension to provide output of Quad, 5.1,
* and 7.1 channel configs, AL_EXT_FLOAT32 for 32-bit float samples, and
* AL_EXT_DOUBLE for 64-bit float samples. */
if(type == AL_UNSIGNED_BYTE_SOFT)
{
if(channels == AL_MONO_SOFT)
format = AL_FORMAT_MONO8;
else if(channels == AL_STEREO_SOFT)
format = AL_FORMAT_STEREO8;
else if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
if(channels == AL_QUAD_SOFT)
format = alGetEnumValue("AL_FORMAT_QUAD8");
else if(channels == AL_5POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_51CHN8");
else if(channels == AL_6POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_61CHN8");
else if(channels == AL_7POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_71CHN8");
}
}
else if(type == AL_SHORT_SOFT)
{
if(channels == AL_MONO_SOFT)
format = AL_FORMAT_MONO16;
else if(channels == AL_STEREO_SOFT)
format = AL_FORMAT_STEREO16;
else if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
if(channels == AL_QUAD_SOFT)
format = alGetEnumValue("AL_FORMAT_QUAD16");
else if(channels == AL_5POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_51CHN16");
else if(channels == AL_6POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_61CHN16");
else if(channels == AL_7POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_71CHN16");
}
}
else if(type == AL_FLOAT_SOFT && alIsExtensionPresent("AL_EXT_FLOAT32"))
{
if(channels == AL_MONO_SOFT)
format = alGetEnumValue("AL_FORMAT_MONO_FLOAT32");
else if(channels == AL_STEREO_SOFT)
format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32");
else if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
if(channels == AL_QUAD_SOFT)
format = alGetEnumValue("AL_FORMAT_QUAD32");
else if(channels == AL_5POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_51CHN32");
else if(channels == AL_6POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_61CHN32");
else if(channels == AL_7POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_71CHN32");
}
}
else if(type == AL_DOUBLE_SOFT && alIsExtensionPresent("AL_EXT_DOUBLE"))
{
if(channels == AL_MONO_SOFT)
format = alGetEnumValue("AL_FORMAT_MONO_DOUBLE");
else if(channels == AL_STEREO_SOFT)
format = alGetEnumValue("AL_FORMAT_STEREO_DOUBLE");
}
/* NOTE: It seems OSX returns -1 from alGetEnumValue for unknown enums, as
* opposed to 0. Correct it. */
if(format == -1)
format = 0;
return format;
}
void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate,
ALenum internalformat, ALsizei samples,
ALenum channels, ALenum type,
const ALvoid *data)
{
alBufferData(buffer, internalformat, data,
FramesToBytes(samples, channels, type),
samplerate);
}
const char *ChannelsName(ALenum chans)
{
switch(chans)
{
case AL_MONO_SOFT: return "Mono";
case AL_STEREO_SOFT: return "Stereo";
case AL_REAR_SOFT: return "Rear";
case AL_QUAD_SOFT: return "Quadraphonic";
case AL_5POINT1_SOFT: return "5.1 Surround";
case AL_6POINT1_SOFT: return "6.1 Surround";
case AL_7POINT1_SOFT: return "7.1 Surround";
}
return "Unknown Channels";
}
const char *TypeName(ALenum type)
{
switch(type)
{
case AL_BYTE_SOFT: return "S8";
case AL_UNSIGNED_BYTE_SOFT: return "U8";
case AL_SHORT_SOFT: return "S16";
case AL_UNSIGNED_SHORT_SOFT: return "U16";
case AL_INT_SOFT: return "S32";
case AL_UNSIGNED_INT_SOFT: return "U32";
case AL_FLOAT_SOFT: return "Float32";
case AL_DOUBLE_SOFT: return "Float64";
}
return "Unknown Type";
}
ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type)
{
switch(channels)
{
case AL_MONO_SOFT: size *= 1; break;
case AL_STEREO_SOFT: size *= 2; break;
case AL_REAR_SOFT: size *= 2; break;
case AL_QUAD_SOFT: size *= 4; break;
case AL_5POINT1_SOFT: size *= 6; break;
case AL_6POINT1_SOFT: size *= 7; break;
case AL_7POINT1_SOFT: size *= 8; break;
}
switch(type)
{
case AL_BYTE_SOFT: size *= sizeof(ALbyte); break;
case AL_UNSIGNED_BYTE_SOFT: size *= sizeof(ALubyte); break;
case AL_SHORT_SOFT: size *= sizeof(ALshort); break;
case AL_UNSIGNED_SHORT_SOFT: size *= sizeof(ALushort); break;
case AL_INT_SOFT: size *= sizeof(ALint); break;
case AL_UNSIGNED_INT_SOFT: size *= sizeof(ALuint); break;
case AL_FLOAT_SOFT: size *= sizeof(ALfloat); break;
case AL_DOUBLE_SOFT: size *= sizeof(ALdouble); break;
}
return size;
}
ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type)
{
return size / FramesToBytes(1, channels, type);
return "Unknown Format";
}
+3 -23
View File
@@ -11,31 +11,11 @@
extern "C" {
#endif /* __cplusplus */
/* Some helper functions to get the name from the channel and type enums. */
const char *ChannelsName(ALenum chans);
const char *TypeName(ALenum type);
/* Helpers to convert frame counts and byte lengths. */
ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type);
ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type);
/* Retrieves a compatible buffer format given the channel configuration and
* sample type. If an alIsBufferFormatSupportedSOFT-compatible function is
* provided, it will be called to find the closest-matching format from
* AL_SOFT_buffer_samples. Returns AL_NONE (0) if no supported format can be
* found. */
ALenum GetFormat(ALenum channels, ALenum type, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT);
/* Loads samples into a buffer using the standard alBufferData call, but with a
* LPALBUFFERSAMPLESSOFT-compatible prototype. Assumes internalformat is valid
* for alBufferData, and that channels and type match it. */
void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate,
ALenum internalformat, ALsizei samples,
ALenum channels, ALenum type,
const ALvoid *data);
/* Some helper functions to get the name from the format enums. */
const char *FormatName(ALenum type);
/* Easy device init/deinit functions. InitAL returns 0 on success. */
int InitAL(void);
int InitAL(char ***argv, int *argc);
void CloseAL(void);
#ifdef __cplusplus
@@ -1,164 +0,0 @@
/*
* SDL_sound Decoder Helpers
*
* Copyright (c) 2013 by Chris Robinson <chris.kcat@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* This file contains routines for helping to decode audio using SDL_sound.
* There's very little OpenAL-specific code here.
*/
#include "sdl_sound.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <assert.h>
#include <SDL_sound.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "alhelpers.h"
static int done_init = 0;
FilePtr openAudioFile(const char *fname, size_t buftime_ms)
{
FilePtr file;
ALuint rate;
Uint32 bufsize;
ALenum chans, type;
/* We need to make sure SDL_sound is initialized. */
if(!done_init)
{
Sound_Init();
done_init = 1;
}
file = Sound_NewSampleFromFile(fname, NULL, 0);
if(!file)
{
fprintf(stderr, "Failed to open %s: %s\n", fname, Sound_GetError());
return NULL;
}
if(getAudioInfo(file, &rate, &chans, &type) != 0)
{
Sound_FreeSample(file);
return NULL;
}
bufsize = FramesToBytes((ALsizei)(buftime_ms/1000.0*rate), chans, type);
if(Sound_SetBufferSize(file, bufsize) == 0)
{
fprintf(stderr, "Failed to set buffer size to %u bytes: %s\n", bufsize, Sound_GetError());
Sound_FreeSample(file);
return NULL;
}
return file;
}
void closeAudioFile(FilePtr file)
{
if(file)
Sound_FreeSample(file);
}
int getAudioInfo(FilePtr file, ALuint *rate, ALenum *channels, ALenum *type)
{
if(file->actual.channels == 1)
*channels = AL_MONO_SOFT;
else if(file->actual.channels == 2)
*channels = AL_STEREO_SOFT;
else
{
fprintf(stderr, "Unsupported channel count: %d\n", file->actual.channels);
return 1;
}
if(file->actual.format == AUDIO_U8)
*type = AL_UNSIGNED_BYTE_SOFT;
else if(file->actual.format == AUDIO_S8)
*type = AL_BYTE_SOFT;
else if(file->actual.format == AUDIO_U16LSB || file->actual.format == AUDIO_U16MSB)
*type = AL_UNSIGNED_SHORT_SOFT;
else if(file->actual.format == AUDIO_S16LSB || file->actual.format == AUDIO_S16MSB)
*type = AL_SHORT_SOFT;
else
{
fprintf(stderr, "Unsupported sample format: 0x%04x\n", file->actual.format);
return 1;
}
*rate = file->actual.rate;
return 0;
}
uint8_t *getAudioData(FilePtr file, size_t *length)
{
*length = Sound_Decode(file);
if(*length == 0)
return NULL;
if((file->actual.format == AUDIO_U16LSB && AUDIO_U16LSB != AUDIO_U16SYS) ||
(file->actual.format == AUDIO_U16MSB && AUDIO_U16MSB != AUDIO_U16SYS) ||
(file->actual.format == AUDIO_S16LSB && AUDIO_S16LSB != AUDIO_S16SYS) ||
(file->actual.format == AUDIO_S16MSB && AUDIO_S16MSB != AUDIO_S16SYS))
{
/* Swap bytes if the decoded endianness doesn't match the system. */
char *buffer = file->buffer;
size_t i;
for(i = 0;i < *length;i+=2)
{
char b = buffer[i];
buffer[i] = buffer[i+1];
buffer[i+1] = b;
}
}
return file->buffer;
}
void *decodeAudioStream(FilePtr file, size_t *length)
{
Uint32 got;
char *mem;
got = Sound_DecodeAll(file);
if(got == 0)
{
*length = 0;
return NULL;
}
mem = malloc(got);
memcpy(mem, file->buffer, got);
*length = got;
return mem;
}
@@ -1,43 +0,0 @@
#ifndef EXAMPLES_SDL_SOUND_H
#define EXAMPLES_SDL_SOUND_H
#include "AL/al.h"
#include <SDL_sound.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Opaque handles to files and streams. Apps don't need to concern themselves
* with the internals */
typedef Sound_Sample *FilePtr;
/* Opens a file with SDL_sound, and specifies the size of the sample buffer in
* milliseconds. */
FilePtr openAudioFile(const char *fname, size_t buftime_ms);
/* Closes/frees an opened file */
void closeAudioFile(FilePtr file);
/* Returns information about the given audio stream. Returns 0 on success. */
int getAudioInfo(FilePtr file, ALuint *rate, ALenum *channels, ALenum *type);
/* Returns a pointer to the next available chunk of decoded audio. The size (in
* bytes) of the returned data buffer is stored in 'length', and the returned
* pointer is only valid until the next call to getAudioData. */
uint8_t *getAudioData(FilePtr file, size_t *length);
/* Decodes all remaining data from the stream and returns a buffer containing
* the audio data, with the size stored in 'length'. The returned pointer must
* be freed with a call to free(). Note that since this decodes the whole
* stream, using it on lengthy streams (eg, music) will use a lot of memory.
* Such streams are better handled using getAudioData to keep smaller chunks in
* memory at any given time. */
void *decodeAudioStream(FilePtr, size_t *length);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* EXAMPLES_SDL_SOUND_H */