ALboolean _alutSanityCheck (void) { ALCcontext *context; if (initialisationState == Unintialized) { _alutSetError (ALUT_ERROR_INVALID_OPERATION); return AL_FALSE; } context = alcGetCurrentContext (); if (context == NULL) { _alutSetError (ALUT_ERROR_NO_CURRENT_CONTEXT); return AL_FALSE; } if (alGetError () != AL_NO_ERROR) { _alutSetError (ALUT_ERROR_AL_ERROR_ON_ENTRY); return AL_FALSE; } if (alcGetError (alcGetContextsDevice (context)) != ALC_NO_ERROR) { _alutSetError (ALUT_ERROR_ALC_ERROR_ON_ENTRY); return AL_FALSE; } return AL_TRUE; }
static BufferData * loadFile (InputStream *stream) { const char *fileName; Int32BigEndian magic; /* Raw files have no magic number - so use the fileName extension */ fileName = _alutInputStreamGetFileName (stream); if (fileName != NULL && hasSuffixIgnoringCase (fileName, ".raw")) { return loadRawFile (stream); } /* For other file formats, read the quasi-standard four byte magic number */ if (!_alutInputStreamReadInt32BE (stream, &magic)) { return AL_FALSE; } /* Magic number 'RIFF' == Microsoft '.wav' format */ if (magic == 0x52494646) { return loadWavFile (stream); } /* Magic number '.snd' == Sun & Next's '.au' format */ if (magic == 0x2E736E64) { return loadAUFile (stream); } _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_TYPE); return AL_FALSE; }
ALboolean alutInit (int *argcp, char **argv) { ALCdevice *device; ALCcontext *context; if (initialisationState != Unintialized) { _alutSetError (ALUT_ERROR_INVALID_OPERATION); return AL_FALSE; } if ((argcp == NULL) != (argv == NULL)) { _alutSetError (ALUT_ERROR_INVALID_VALUE); return AL_FALSE; } device = alcOpenDevice (NULL); if (device == NULL) { _alutSetError (ALUT_ERROR_OPEN_DEVICE); return AL_FALSE; } context = alcCreateContext (device, NULL); if (context == NULL) { alcCloseDevice (device); _alutSetError (ALUT_ERROR_CREATE_CONTEXT); return AL_FALSE; } if (!alcMakeContextCurrent (context)) { alcDestroyContext (context); alcCloseDevice (device); _alutSetError (ALUT_ERROR_MAKE_CONTEXT_CURRENT); return AL_FALSE; } initialisationState = ALUTDeviceAndContext; alutContext = context; return AL_TRUE; }
ALboolean alutExit (void) { ALCdevice *device; if (initialisationState == Unintialized) { _alutSetError (ALUT_ERROR_INVALID_OPERATION); return AL_FALSE; } if (initialisationState == ExternalDeviceAndContext) { initialisationState = Unintialized; return AL_TRUE; } if (!_alutSanityCheck ()) { return AL_FALSE; } if (!alcMakeContextCurrent (NULL)) { _alutSetError (ALUT_ERROR_MAKE_CONTEXT_CURRENT); return AL_FALSE; } device = alcGetContextsDevice (alutContext); alcDestroyContext (alutContext); if (alcGetError (device) != ALC_NO_ERROR) { _alutSetError (ALUT_ERROR_DESTROY_CONTEXT); return AL_FALSE; } if (!alcCloseDevice (device)) { _alutSetError (ALUT_ERROR_CLOSE_DEVICE); return AL_FALSE; } initialisationState = Unintialized; return AL_TRUE; }
ALboolean alutInitWithoutContext (int *argcp, char **argv) { if (initialisationState != Unintialized) { _alutSetError (ALUT_ERROR_INVALID_OPERATION); return AL_FALSE; } if ((argcp == NULL) != (argv == NULL)) { _alutSetError (ALUT_ERROR_INVALID_VALUE); return AL_FALSE; } initialisationState = ExternalDeviceAndContext; return AL_TRUE; }
ALvoid * _alutMalloc (size_t size) { ALvoid *ptr = malloc (size == 0 ? 1 : size); if (ptr == NULL) { _alutSetError (ALUT_ERROR_OUT_OF_MEMORY); } return ptr; }
ALUT_API ALboolean ALUT_APIENTRY alutSleep (ALfloat duration) { if (duration < 0) { _alutSetError (ALUT_ERROR_INVALID_VALUE); return AL_FALSE; } { ALuint seconds = (ALuint) duration; ALfloat rest = duration - (ALfloat) seconds; #if HAVE_NANOSLEEP && HAVE_TIME_H ALuint microSecs = (ALuint) (rest * 1000000); struct timespec t, remainingTime; t.tv_sec = (time_t) seconds; t.tv_nsec = ((long) microSecs) * 1000; /* At least the interaction of nanosleep and signals is specified! */ while (nanosleep (&t, &remainingTime) < 0) { if (errno != EINTR) { return AL_FALSE; } /* If we received a signal, let's try again with the remaining time. */ t.tv_sec = remainingTime.tv_sec; t.tv_nsec = remainingTime.tv_nsec; } #elif HAVE_USLEEP && HAVE_UNISTD_H while (seconds > 0) { usleep (1000000); seconds--; } usleep ((unsigned int) (rest * 1000000)); #elif HAVE_SLEEP && HAVE_WINDOWS_H while (seconds > 0) { Sleep (1000); seconds--; } Sleep ((DWORD) (rest * 1000)); #endif } return AL_TRUE; }
ALboolean _alutGetFormat (const BufferData *bufferData, ALenum *format) { if (!_alutFormatConstruct (getNumChannels (bufferData), getBitsPerSample (bufferData), format)) { _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE); return AL_FALSE; } return AL_TRUE; }
static ALuint generateBuffer (void) { ALuint buffer; alGenBuffers (1, &buffer); if (alGetError () != AL_NO_ERROR) { _alutSetError (ALUT_ERROR_GEN_BUFFERS); return AL_NONE; } return buffer; }
const char * alutGetMIMETypes (ALenum loader) { if (!_alutSanityCheck ()) { return NULL; } /* We do not distinguish the loaders yet... */ switch (loader) { case ALUT_LOADER_BUFFER: return "audio/basic,audio/x-raw,audio/x-wav"; case ALUT_LOADER_MEMORY: return "audio/basic,audio/x-raw,audio/x-wav"; default: _alutSetError (ALUT_ERROR_INVALID_ENUM); return NULL; } }
static ALboolean passBufferData (BufferData *bufferData, ALuint bid) { ALenum format; size_t size; ALfloat frequency; if (!_alutGetFormat (bufferData, &format)) { return AL_FALSE; } /* GCC is a bit picky about casting function calls, so we do it in two steps... */ size = _alutBufferDataGetLength (bufferData); frequency = _alutBufferDataGetSampleFrequency (bufferData); alBufferData (bid, format, _alutBufferDataGetData (bufferData), (ALsizei) size, (ALsizei) frequency); if (alGetError () != AL_NO_ERROR) { _alutSetError (ALUT_ERROR_BUFFER_DATA); return AL_FALSE; } return AL_TRUE; }
static BufferData * loadWavFile (InputStream *stream) { ALboolean found_header = AL_FALSE; UInt32LittleEndian chunkLength; Int32BigEndian magic; UInt16LittleEndian audioFormat; UInt16LittleEndian numChannels; UInt32LittleEndian sampleFrequency; UInt32LittleEndian byteRate; UInt16LittleEndian blockAlign; UInt16LittleEndian bitsPerSample; Codec *codec = _alutCodecLinear; if (!_alutInputStreamReadUInt32LE (stream, &chunkLength) || !_alutInputStreamReadInt32BE (stream, &magic)) { return NULL; } if (magic != 0x57415645) /* "WAVE" */ { _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE); return NULL; } while (1) { if (!_alutInputStreamReadInt32BE (stream, &magic) || !_alutInputStreamReadUInt32LE (stream, &chunkLength)) { return NULL; } if (magic == 0x666d7420) /* "fmt " */ { found_header = AL_TRUE; if (chunkLength < 16) { _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); return NULL; } if (!_alutInputStreamReadUInt16LE (stream, &audioFormat) || !_alutInputStreamReadUInt16LE (stream, &numChannels) || !_alutInputStreamReadUInt32LE (stream, &sampleFrequency) || !_alutInputStreamReadUInt32LE (stream, &byteRate) || !_alutInputStreamReadUInt16LE (stream, &blockAlign) || !_alutInputStreamReadUInt16LE (stream, &bitsPerSample)) { return NULL; } if (!_alutInputStreamSkip (stream, chunkLength - 16)) { return NULL; } switch (audioFormat) { case 1: /* PCM */ codec = (bitsPerSample == 8 || endianess () == LittleEndian) ? _alutCodecLinear : _alutCodecPCM16; break; case 7: /* uLaw */ bitsPerSample *= 2; /* ToDo: ??? */ codec = _alutCodecULaw; break; default: _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE); return NULL; } } else if (magic == 0x64617461) /* "data" */ { ALvoid *data; if (!found_header) { /* ToDo: A bit wrong to check here, fmt chunk could come later... */ _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); return NULL; } data = _alutInputStreamRead (stream, chunkLength); if (data == NULL) { return NULL; } return codec (data, chunkLength, numChannels, bitsPerSample, (ALfloat) sampleFrequency); } else { if (!_alutInputStreamSkip (stream, chunkLength)) { return NULL; } } if ((chunkLength & 1) && !_alutInputStreamEOF (stream) && !_alutInputStreamSkip (stream, 1)) { return NULL; } } }
static BufferData * loadAUFile (InputStream *stream) { Int32BigEndian dataOffset; /* byte offset to data part, minimum 24 */ Int32BigEndian len; /* number of bytes in the data part, -1 = not known */ Int32BigEndian encoding; /* encoding of the data part, see AUEncoding */ Int32BigEndian sampleFrequency; /* number of samples per second */ Int32BigEndian numChannels; /* number of interleaved channels */ size_t length; Codec *codec; char *data; ALint bitsPerSample; if (!_alutInputStreamReadInt32BE (stream, &dataOffset) || !_alutInputStreamReadInt32BE (stream, &len) || !_alutInputStreamReadInt32BE (stream, &encoding) || !_alutInputStreamReadInt32BE (stream, &sampleFrequency) || !_alutInputStreamReadInt32BE (stream, &numChannels)) { return AL_FALSE; } length = (len == -1) ? (_alutInputStreamGetRemainingLength (stream) - AU_HEADER_SIZE - dataOffset) : (size_t) len; if (! (dataOffset >= AU_HEADER_SIZE && length > 0 && sampleFrequency >= 1 && numChannels >= 1)) { _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); return AL_FALSE; } if (!_alutInputStreamSkip (stream, dataOffset - AU_HEADER_SIZE)) { return AL_FALSE; } switch (encoding) { case AU_ULAW_8: bitsPerSample = 16; codec = _alutCodecULaw; break; case AU_PCM_8: bitsPerSample = 8; codec = _alutCodecPCM8s; break; case AU_PCM_16: bitsPerSample = 16; codec = (endianess () == BigEndian) ? _alutCodecLinear : _alutCodecPCM16; break; case AU_ALAW_8: bitsPerSample = 16; codec = _alutCodecALaw; break; default: _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE); return AL_FALSE; } data = _alutInputStreamRead (stream, length); if (data == NULL) { return NULL; } return codec (data, length, numChannels, bitsPerSample, (ALfloat) sampleFrequency); }