#include #include #include #ifdef EMSCRIPTEN #include #include #include #else #include "../system/include/AL/al.h" #include "../system/include/AL/alc.h" #endif #define NUM_BUFFERS 4 #define BUFFER_SIZE 1470*10 ALCdevice* device = NULL; ALCcontext* context = NULL; // Audio source state. unsigned char* data = NULL; unsigned int size = 0; unsigned int offset = 0; unsigned int channels = 0; unsigned int frequency = 0; unsigned int bits = 0; ALenum format = 0; ALuint source = 0; void iter(void *arg) { ALuint buffer = 0; ALint buffersProcessed = 0; ALint buffersWereQueued = 0; ALint buffersQueued = 0; ALint state; alGetSourcei(source, AL_BUFFERS_PROCESSED, &buffersProcessed); while (offset < size && buffersProcessed--) { // unqueue the old buffer and validate the queue length alGetSourcei(source, AL_BUFFERS_QUEUED, &buffersWereQueued); alSourceUnqueueBuffers(source, 1, &buffer); assert(alGetError() == AL_NO_ERROR); int len = size - offset; if (len > BUFFER_SIZE) { len = BUFFER_SIZE; } alGetSourcei(source, AL_BUFFERS_QUEUED, &buffersQueued); assert(buffersQueued == buffersWereQueued - 1); // queue the new buffer and validate the queue length buffersWereQueued = buffersQueued; alBufferData(buffer, format, &data[offset], len, frequency); alSourceQueueBuffers(source, 1, &buffer); assert(alGetError() == AL_NO_ERROR); alGetSourcei(source, AL_BUFFERS_QUEUED, &buffersQueued); assert(buffersQueued == buffersWereQueued + 1); // make sure it's still playing alGetSourcei(source, AL_SOURCE_STATE, &state); assert(state == AL_PLAYING); offset += len; } // Exit once we've processed the entire clip. if (offset >= size) { #ifdef EMSCRIPTEN int result = 0; REPORT_RESULT(); #endif exit(0); } } int main(int argc, char* argv[]) { // // Setup the AL context. // device = alcOpenDevice(NULL); context = alcCreateContext(device, NULL); alcMakeContextCurrent(context); // // Read in the audio sample. // #ifdef EMSCRIPTEN FILE* fp = fopen("the_entertainer.wav", "rb"); #else FILE* fp = fopen("sounds/the_entertainer.wav", "rb"); #endif fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); data = (unsigned char*)malloc(size); fread(data, size, 1, fp); fclose(fp); offset = 12; // ignore the RIFF header offset += 8; // ignore the fmt header offset += 2; // ignore the format type channels = data[offset + 1] << 8; channels |= data[offset]; offset += 2; printf("Channels: %u\n", channels); frequency = data[offset + 3] << 24; frequency |= data[offset + 2] << 16; frequency |= data[offset + 1] << 8; frequency |= data[offset]; offset += 4; printf("Frequency: %u\n", frequency); offset += 6; // ignore block size and bps bits = data[offset + 1] << 8; bits |= data[offset]; offset += 2; printf("Bits: %u\n", bits); format = 0; if (bits == 8) { if (channels == 1) { format = AL_FORMAT_MONO8; } else if (channels == 2) { format = AL_FORMAT_STEREO8; } } else if (bits == 16) { if (channels == 1) { format = AL_FORMAT_MONO16; } else if (channels == 2) { format = AL_FORMAT_STEREO16; } } offset += 8; // ignore the data chunk // // Seed the buffers with some initial data. // ALuint buffers[NUM_BUFFERS]; alGenBuffers(NUM_BUFFERS, buffers); alGenSources(1, &source); ALint numBuffers = 0; while (numBuffers < NUM_BUFFERS && offset < size) { int len = size - offset; if (len > BUFFER_SIZE) { len = BUFFER_SIZE; } alBufferData(buffers[numBuffers], format, &data[offset], len, frequency); alSourceQueueBuffers(source, 1, &buffers[numBuffers]); assert(alGetError() == AL_NO_ERROR); offset += len; numBuffers++; } // // Start playing the source. // alSourcePlay(source); ALint state; alGetSourcei(source, AL_SOURCE_STATE, &state); assert(state == AL_PLAYING); alGetSourcei(source, AL_BUFFERS_QUEUED, &numBuffers); assert(numBuffers == NUM_BUFFERS); // // Cycle and refill the buffers until we're done. // #if EMSCRIPTEN emscripten_set_main_loop(iter, 0, 0); #else while (1) { iter(NULL); usleep(16); } #endif }