paulo@0: /* paulo@0: paulo@0: ljvorbis.c paulo@0: Simple wrapper around vorbisfile for use with the Allegro library paulo@0: copyright 2006 Damian Yerrick paulo@0: based on vorbisfile example paulo@0: copyright 1994-2004 Xiph.Org Foundation paulo@0: licensed under a BSD style license set forth in COPYING-OGG.txt paulo@0: paulo@0: */ paulo@0: paulo@0: #define ALLEGRO_USE_CONSOLE paulo@0: #include paulo@0: #include "ljvorbis.h" paulo@0: paulo@0: #define VORBIS_BYTEDEPTH 2 // number of bytes per sample; 2 means 16-bit paulo@0: #define VORBIS_ENDIAN 0 // 0: x86/little; 2: ppc/big paulo@0: #define VORBIS_SIGNED 0 // 0: unsigned; 1: signed; Allegro uses unsigned paulo@0: paulo@0: LJVorbis *LJVorbis_open(const char *filename) { paulo@0: LJVorbis *ogg = malloc(sizeof(LJVorbis)); paulo@0: if (!ogg) { paulo@0: return NULL; paulo@0: } paulo@0: ogg->fp = fopen(filename, "rb"); paulo@0: if (!ogg->fp) { paulo@0: free(ogg); paulo@0: return NULL; paulo@0: } paulo@0: if (ov_open(ogg->fp, &(ogg->vf), NULL, 0) < 0) { paulo@0: fclose(ogg->fp); paulo@0: free(ogg); paulo@0: return NULL; paulo@0: } paulo@0: vorbis_info *vi=ov_info(&(ogg->vf),-1); paulo@0: ogg->rate = vi->rate; paulo@0: ogg->channels = vi->channels; paulo@0: ogg->length = ov_pcm_total(&(ogg->vf),-1); paulo@0: ogg->loopPoint = 0; paulo@0: ogg->voice = NULL; paulo@0: ogg->paused = 0; paulo@0: return ogg; paulo@0: } paulo@0: paulo@0: void LJVorbis_setLoop(LJVorbis *ogg, unsigned long int loopPoint) { paulo@0: if (ogg) { paulo@0: if (loopPoint < ogg->length) { paulo@0: ogg->loopPoint = loopPoint; paulo@0: } else { paulo@0: ogg->loopPoint = 0; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: int LJVorbis_start(LJVorbis *ogg, int bufferSize, int vol, int pan) { paulo@0: if (ogg) { paulo@0: paulo@0: // if restarting, stop first paulo@0: if (ogg->voice) { paulo@0: LJVorbis_stop(ogg); paulo@0: } paulo@0: ogg->voice = play_audio_stream(bufferSize, paulo@0: 8 * VORBIS_BYTEDEPTH, paulo@0: ogg->channels > 1, paulo@0: ogg->rate, paulo@0: vol, pan); paulo@0: ogg->bufferSize = bufferSize; paulo@0: if (!ogg->voice) { paulo@0: return -1; paulo@0: } paulo@0: ov_pcm_seek(&(ogg->vf), 0); paulo@0: return 0; paulo@0: } paulo@0: return -1; paulo@0: } paulo@0: paulo@0: void LJVorbis_stop(LJVorbis *ogg) { paulo@0: if (ogg && ogg->voice) { paulo@0: stop_audio_stream(ogg->voice); paulo@0: ogg->voice = NULL; paulo@0: } paulo@0: } paulo@0: paulo@0: void LJVorbis_close(LJVorbis *ogg) { paulo@0: if (ogg) { paulo@0: LJVorbis_stop(ogg); paulo@0: ov_clear(&(ogg->vf)); // finalize decoder and close the file paulo@0: // thanks kesiev for reminding me that ov_clear closes the file itself paulo@0: free(ogg); paulo@0: } paulo@0: } paulo@0: paulo@0: void LJVorbis_pause(LJVorbis *ogg, int value) { paulo@0: if (ogg && ogg->voice) { paulo@0: int hwVoice = ogg->voice->voice; paulo@0: voice_set_frequency(hwVoice, value ? 0 : ogg->rate); paulo@0: ogg->paused = value ? 1 : 0; paulo@0: } paulo@0: } paulo@0: paulo@0: int LJVorbis_poll(LJVorbis *ogg) { paulo@0: if (!ogg || !ogg->voice) { paulo@0: return -1; paulo@0: } paulo@0: char *buf = get_audio_stream_buffer(ogg->voice); paulo@0: int eofReached = 0; paulo@0: paulo@0: if (buf) { paulo@0: // the number of bytes left in this buffer paulo@0: long int bytesLeft = ogg->bufferSize * VORBIS_BYTEDEPTH * ogg->channels; paulo@0: paulo@0: while (bytesLeft > 0) { paulo@0: long ret=ov_read(&(ogg->vf), paulo@0: buf, paulo@0: bytesLeft, paulo@0: VORBIS_ENDIAN, paulo@0: VORBIS_BYTEDEPTH, paulo@0: VORBIS_SIGNED, paulo@0: &(ogg->bitstream)); paulo@0: if (ret == 0) { paulo@0: // try to seek back to the beginning of the file paulo@0: int pcmErr = ov_pcm_seek(&(ogg->vf), ogg->loopPoint); paulo@0: if (pcmErr) { paulo@0: /* EOF */ paulo@0: eofReached = 1; paulo@0: bytesLeft = 0; paulo@0: } paulo@0: } else if (ret < 0) { paulo@0: // Stream error. Just ignore it. paulo@0: } else { paulo@0: /* FIXME: handle sample rate changes, etc */ paulo@0: // advance forward in the buffer paulo@0: buf += ret; paulo@0: bytesLeft -= ret; paulo@0: } paulo@0: } paulo@0: free_audio_stream_buffer(ogg->voice); paulo@0: } paulo@0: return eofReached; paulo@0: } paulo@0: paulo@0: #ifdef LJVORBIS_DEMO paulo@0: int main(){ paulo@0: int eofReached = 0; paulo@0: LJVorbis *ogg = LJVorbis_open("AM-3P.ogg"); paulo@0: paulo@0: if (!ogg) { paulo@0: fprintf(stderr, "Could not open AM-3P.ogg.\n"); paulo@0: exit(1); paulo@0: } paulo@0: LJVorbis_setLoop(ogg, 650772); paulo@0: paulo@0: if (allegro_init() < 0 paulo@0: || install_timer() < 0 paulo@0: || set_gfx_mode(GFX_SAFE, 320, 200, 0, 0) < 0 paulo@0: || install_keyboard() < 0 paulo@0: || install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL) < 0) { paulo@0: allegro_exit(); paulo@0: LJVorbis_close(ogg); paulo@0: fprintf(stderr, "Could not start Allegro library: %s\n", allegro_error); paulo@0: exit(1); paulo@0: } paulo@0: paulo@0: /* Throw the comments plus a few lines about the bitstream we're paulo@0: decoding */ paulo@0: if (0) paulo@0: { paulo@0: char line1[80], line2[80]; paulo@0: paulo@0: usprintf(line1,"%d channels, %u Hz", ogg->channels, ogg->rate); paulo@0: usprintf(line2,"length: %lu samples", ogg->length); paulo@0: alert(line1, line2, "ready?", paulo@0: "Play", 0, 13, 0); paulo@0: } paulo@0: paulo@0: if (LJVorbis_start(ogg, 1024, 192, 128) < 0) { paulo@0: LJVorbis_close(ogg); paulo@0: alert("Could not allocate voice", paulo@0: "for playing audio.", paulo@0: "", paulo@0: "OK", 0, 13, 0); paulo@0: exit(1); paulo@0: } paulo@0: paulo@0: while(!eofReached){ paulo@0: eofReached = LJVorbis_poll(ogg); paulo@0: rest(16); paulo@0: paulo@0: if (keypressed()) { paulo@0: int scancode; paulo@0: ureadkey(&scancode); paulo@0: paulo@0: if (scancode == KEY_P) { paulo@0: LJVorbis_pause(ogg, !ogg->paused); paulo@0: } else if (scancode == KEY_ESC) { paulo@0: eofReached = 1; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: /* cleanup */ paulo@0: LJVorbis_close(ogg); paulo@0: return(0); paulo@0: } paulo@0: END_OF_MAIN(); paulo@0: #endif