diff options
| author | Ray <raysan5@gmail.com> | 2013-11-18 23:38:44 +0100 |
|---|---|---|
| committer | Ray <raysan5@gmail.com> | 2013-11-18 23:38:44 +0100 |
| commit | 46f10b45ad181a00e8cfa3ba2540f2922e1553cd (patch) | |
| tree | da74ac29ab65c9c6fa82a36cadd796091a14d71f /src/audio.c | |
| parent | cbbf800bb838431a626b232df8eb5db4e0a7e150 (diff) | |
| download | raylib-46f10b45ad181a00e8cfa3ba2540f2922e1553cd.tar.gz raylib-46f10b45ad181a00e8cfa3ba2540f2922e1553cd.zip | |
raylib basic folders structure and some files... ;)
Diffstat (limited to 'src/audio.c')
| -rw-r--r-- | src/audio.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/src/audio.c b/src/audio.c new file mode 100644 index 00000000..41ba6fed --- /dev/null +++ b/src/audio.c @@ -0,0 +1,306 @@ +/********************************************************************************************* +* +* raylib.audio +* +* Basic functions to manage Audio: InitAudioDevice, LoadAudioFiles, PlayAudioFiles +* +* Uses external lib: +* OpenAL - Audio device management lib +* TODO: stb_vorbis - Ogg audio files loading +* +* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" + +#include <AL/al.h> // OpenAL basic header +#include <AL/alc.h> // OpenAL context header (like OpenGL, OpenAL requires a context to work) + +#include <stdlib.h> // To use exit() function +#include <stdio.h> // Used for .WAV loading + +//#include "stb_vorbis.h" // TODO: OGG loading functions + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Nop... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +// Wave file data +typedef struct Wave { + unsigned char *data; // Buffer data pointer + unsigned int sampleRate; + unsigned int dataSize; + short channels; + short format; +} Wave; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// Nop... + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +static Wave LoadWAV(char *fileName); +static void UnloadWAV(Wave wave); +//static Ogg LoadOGG(char *fileName); + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Window and OpenGL Context Functions +//---------------------------------------------------------------------------------- + +// Initialize audio device and context +void InitAudioDevice() +{ + // Open and initialize a device with default settings + ALCdevice *device = alcOpenDevice(NULL); + + if(!device) + { + fprintf(stderr, "Could not open a device!\n"); + exit(1); + } + + ALCcontext *context = alcCreateContext(device, NULL); + + if(context == NULL || alcMakeContextCurrent(context) == ALC_FALSE) + { + if(context != NULL) alcDestroyContext(context); + + alcCloseDevice(device); + + fprintf(stderr, "Could not set a context!\n"); + exit(1); + } + + printf("Opened \"%s\"\n", alcGetString(device, ALC_DEVICE_SPECIFIER)); + + // Listener definition (just for 2D) + alListener3f(AL_POSITION, 0, 0, 0); + alListener3f(AL_VELOCITY, 0, 0, 0); + alListener3f(AL_ORIENTATION, 0, 0, -1); +} + +// Close the audio device for the current context, and destroys the context +void CloseAudioDevice() +{ + ALCdevice *device; + ALCcontext *context = alcGetCurrentContext(); + + if (context == NULL) return; + + device = alcGetContextsDevice(context); + + alcMakeContextCurrent(NULL); + alcDestroyContext(context); + alcCloseDevice(device); +} + +// Load sound to memory +Sound LoadSound(char *fileName) +{ + Sound sound; + + // NOTE: The entire file is loaded to memory to play it all at once (no-streaming) + + // WAV file loading + // NOTE: Buffer space is allocated inside LoadWAV, Wave must be freed + Wave wave = LoadWAV(fileName); + + ALenum format; + // The OpenAL format is worked out by looking at the number of channels and the bits per sample + if (wave.channels == 1) + { + if (wave.sampleRate == 8 ) format = AL_FORMAT_MONO8; + else if (wave.sampleRate == 16) format = AL_FORMAT_MONO16; + } + else if (wave.channels == 2) + { + if (wave.sampleRate == 8 ) format = AL_FORMAT_STEREO8; + else if (wave.sampleRate == 16) format = AL_FORMAT_STEREO16; + } + + // Create an audio source + ALuint source; + alGenSources(1, &source); // Generate pointer to audio source + + alSourcef(source, AL_PITCH, 1); + alSourcef(source, AL_GAIN, 1); + alSource3f(source, AL_POSITION, 0, 0, 0); + alSource3f(source, AL_VELOCITY, 0, 0, 0); + alSourcei(source, AL_LOOPING, AL_FALSE); + + // Convert loaded data to OpenAL buffer + //---------------------------------------- + ALuint buffer; + alGenBuffers(1, &buffer); // Generate pointer to buffer + + // Upload sound data to buffer + alBufferData(buffer, format, wave.data, wave.dataSize, wave.sampleRate); + + // Attach sound buffer to source + alSourcei(source, AL_BUFFER, buffer); + + // Unallocate WAV data + UnloadWAV(wave); + + printf("Sample rate: %i\n", wave.sampleRate); + printf("Channels: %i\n", wave.channels); + printf("Format: %i\n", wave.format); + + printf("Audio file loaded...!\n"); + + sound.source = source; + sound.buffer = buffer; + + return sound; +} + +// Unload sound +void UnloadSound(Sound sound) +{ + alDeleteSources(1, &sound.source); + alDeleteBuffers(1, &sound.buffer); +} + +// Play a sound +void PlaySound(Sound sound) +{ + alSourcePlay(sound.source); // Play the sound + + printf("Playing sound!\n"); + + // Find the current position of the sound being played + // NOTE: Only work when the entire file is in a single buffer + //int byteOffset; + //alGetSourcei(sound.source, AL_BYTE_OFFSET, &byteOffset); + //float seconds = (float)byteOffset / sampleRate; // Number of seconds since the beginning of the sound +} + +// Play a sound with extended options +void PlaySoundEx(Sound sound, float timePosition, bool loop) +{ + // TODO: Review + + // Change the current position (e.g. skip some part of the sound) + // NOTE: Only work when the entire file is in a single buffer + //alSourcei(sound.source, AL_BYTE_OFFSET, int(position * sampleRate)); + + alSourcePlay(sound.source); // Play the sound + + if (loop) alSourcei(sound.source, AL_LOOPING, AL_TRUE); + else alSourcei(sound.source, AL_LOOPING, AL_FALSE); +} + +// Pause a sound +void PauseSound(Sound sound) +{ + alSourcePause(sound.source); +} + +// Stop reproducing a sound +void StopSound(Sound sound) +{ + alSourceStop(sound.source); +} + +// Load WAV file into Wave structure +static Wave LoadWAV(char *fileName) +{ + Wave wave; + FILE *wavFile; + + wavFile = fopen(fileName, "rb"); + + if (!wavFile) + { + printf("Could not load WAV file.\n"); + exit(1); + } + + unsigned char id[4]; // Four bytes to hold 'RIFF' and 'WAVE' (and other ids) + + unsigned int size = 0; // File size (useless) + + short format; + short channels; + short blockAlign; + short bitsPerSample; + + unsigned int formatLength; + unsigned int sampleRate; + unsigned int avgBytesSec; + unsigned int dataSize; + + fread(id, sizeof(unsigned char), 4, wavFile); // Read the first four bytes + + if ((id[0] != 'R') || (id[1] != 'I') || (id[2] != 'F') || (id[3] != 'F')) + { + printf("Invalid RIFF file.\n"); // If not "RIFF" id, exit + exit(1); + } + + fread(&size, sizeof(unsigned int), 1, wavFile); // Read file size + fread(id, sizeof(unsigned char), 4, wavFile); // Read the next id + + if ((id[0] != 'W') || (id[1] != 'A') || (id[2] != 'V') || (id[3] != 'E')) + { + printf("Invalid WAVE file.\n"); // If not "WAVE" id, exit + exit(1); + } + + fread(id, sizeof(unsigned char), 4, wavFile); // Read 4 bytes id "fmt " + fread(&formatLength, sizeof(unsigned int),1,wavFile); // Read format lenght + fread(&format, sizeof(short), 1, wavFile); // Read format tag + fread(&channels, sizeof(short), 1, wavFile); // Read num channels (1 mono, 2 stereo) + fread(&sampleRate, sizeof(unsigned int), 1, wavFile); // Read sample rate (44100, 22050, etc...) + fread(&avgBytesSec, sizeof(short), 1, wavFile); // Read average bytes per second (probably won't need this) + fread(&blockAlign, sizeof(short), 1, wavFile); // Read block alignment (probably won't need this) + fread(&bitsPerSample, sizeof(short), 1, wavFile); // Read bits per sample (8 bit or 16 bit) + + fread(id, sizeof(unsigned char), 4, wavFile); // Read 4 bytes id "data" + fread(&dataSize, sizeof(unsigned int), 1, wavFile); // Read data size (in bytes) + + wave.sampleRate = sampleRate; + wave.dataSize = dataSize; + wave.channels = channels; + wave.format = format; + + wave.data = (unsigned char *)malloc(sizeof(unsigned char) * dataSize); // Allocate the required bytes to store data + + fread(wave.data, sizeof(unsigned char), dataSize, wavFile); // Read the whole sound data chunk + + return wave; +} + +// Unload WAV file data +static void UnloadWAV(Wave wave) +{ + free(wave.data); +} + +// TODO: Ogg data loading +//static Ogg LoadOGG(char *fileName) { } + |
