nuclear@47: #include nuclear@47: #include nuclear@69: #include nuclear@47: #include nuclear@47: #include nuclear@47: #include "openal.h" nuclear@47: #include "sample.h" nuclear@47: nuclear@48: nuclear@48: #define CHECK_ERROR \ nuclear@48: do { \ nuclear@48: unsigned int err = alGetError(); \ nuclear@48: if(err != 0) { \ nuclear@48: fprintf(stderr, "%s:%d: AL error: %#x\n", __FILE__, __LINE__, err); \ nuclear@48: abort(); \ nuclear@48: } \ nuclear@48: } while(0) nuclear@48: nuclear@48: nuclear@47: AudioSample::AudioSample() nuclear@47: { nuclear@47: albuffer = 0; nuclear@47: } nuclear@47: nuclear@47: AudioSample::~AudioSample() nuclear@47: { nuclear@47: destroy(); nuclear@47: } nuclear@47: nuclear@47: void AudioSample::destroy() nuclear@47: { nuclear@47: if(albuffer) { nuclear@47: alDeleteBuffers(1, &albuffer); nuclear@47: albuffer = 0; nuclear@47: } nuclear@47: } nuclear@47: nuclear@47: bool AudioSample::load(const char *fname) nuclear@47: { nuclear@47: OggVorbis_File vf; nuclear@47: if(ov_fopen(fname, &vf) != 0) { nuclear@47: fprintf(stderr, "failed to open ogg/vorbis file: %s\n", fname); nuclear@47: return false; nuclear@47: } nuclear@47: vorbis_info *vinfo = ov_info(&vf, -1); nuclear@47: ALenum alfmt = vinfo->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; nuclear@47: nuclear@47: printf("loading sample: %s: %ld samples/s, %s (%d chan)\n", fname, vinfo->rate, nuclear@47: vinfo->channels == 1 ? "mono" : "stereo", vinfo->channels); nuclear@47: nuclear@48: long num_samples = ov_pcm_total(&vf, -1) * vinfo->channels; nuclear@47: int16_t *samples = new int16_t[num_samples]; nuclear@47: nuclear@47: long bufsz = num_samples * sizeof *samples; nuclear@47: long total_read = 0; nuclear@47: while(total_read < bufsz) { nuclear@47: int bitstream; nuclear@47: long rd = ov_read(&vf, (char*)samples + total_read, bufsz, 0, 2, 1, &bitstream); nuclear@47: if(!rd) { nuclear@47: bufsz = total_read; nuclear@47: printf("%s: unexpected eof while reading: %s\n", __FUNCTION__, fname); nuclear@47: } else { nuclear@47: total_read += rd; nuclear@47: } nuclear@47: } nuclear@47: nuclear@47: assert(alGetError() == AL_NO_ERROR); nuclear@47: nuclear@47: unsigned int bufobj = 0; nuclear@47: alGenBuffers(1, &bufobj); nuclear@47: if(alGetError()) { nuclear@47: fprintf(stderr, "failed to create OpenAL buffer\n"); nuclear@47: goto err; nuclear@47: } nuclear@47: nuclear@47: alBufferData(bufobj, alfmt, samples, bufsz, vinfo->rate); nuclear@48: CHECK_ERROR; nuclear@47: if(alGetError()) { nuclear@47: fprintf(stderr, "failed to load sample data into OpenAL buffer: %u\n", bufobj); nuclear@47: goto err; nuclear@47: } nuclear@47: nuclear@47: ov_clear(&vf); nuclear@47: delete [] samples; nuclear@47: nuclear@47: destroy(); // cleanup previous buffer if any nuclear@47: albuffer = bufobj; nuclear@47: return true; nuclear@47: nuclear@47: err: nuclear@47: delete [] samples; nuclear@47: ov_clear(&vf); nuclear@47: if(bufobj) { nuclear@47: alDeleteBuffers(1, &bufobj); nuclear@47: } nuclear@47: return false; nuclear@47: } nuclear@48: nuclear@48: AudioSample *load_audio_sample(const char *fname) nuclear@48: { nuclear@48: AudioSample *s = new AudioSample; nuclear@48: nuclear@48: if(!s->load(fname)) { nuclear@48: delete s; nuclear@48: s = 0; nuclear@48: } nuclear@48: return s; nuclear@48: } nuclear@48: nuclear@48: void destroy_audio_sample(AudioSample *s) nuclear@48: { nuclear@48: delete s; nuclear@48: }