blob: 3ebe1245626f55e8a32940f9325ffa69dc8b1aa6 [file] [log] [blame]
/*
* Copyright 2013 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <AL/al.h>
#include <AL/alc.h>
#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;
#ifdef TEST_ANIMATED_PITCH
// When testing animated pitch, start testing at a high pitch, and scale smaller.
float pitch = 1.3f;
#else
// When not testing animating the pitch value, play back at a slow rate.
float pitch = 0.5f;
#endif
void iter() {
ALuint buffer = 0;
ALint buffersProcessed = 0;
ALint buffersWereQueued = 0;
ALint buffersQueued = 0;
ALint state;
float testPitch;
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;
}
#ifdef TEST_ANIMATED_PITCH
pitch *= .999;
if (pitch < 0.5f)
pitch = 0.5f;
alSourcef(source, AL_PITCH, pitch);
alGetSourcef(source, AL_PITCH, &testPitch);
assert(pitch == testPitch);
#endif
// Exit once we've processed the entire clip.
if (offset >= size) {
#ifdef __EMSCRIPTEN__
REPORT_RESULT(0);
#endif
exit(0);
}
}
int main(int argc, char* argv[]) {
float testPitch;
//
// 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);
alSourcef(source, AL_PITCH, pitch);
alGetSourcef(source, AL_PITCH, &testPitch);
assert(pitch == testPitch);
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++;
}
ALint srcLen = 0;
alGetSourcei(source, 0x2009 /* AL_BYTE_LENGTH_SOFT */, &srcLen);
assert(srcLen == NUM_BUFFERS * BUFFER_SIZE);
#ifdef TEST_ANIMATED_PITCH
printf("You should hear a clip of the 1902 piano song \"The Entertainer\" played back at a high pitch rate, and animated to slow down to half playback speed.\n");
#else
printf("You should hear a clip of the 1902 piano song \"The Entertainer\" played back at half speed.\n");
#endif
//
// 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.
//
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(iter, 0, 0);
#else
while (1) {
iter();
usleep(16);
}
#endif
}