#include #include #include #include "vorbis.h" #include "playback.h" static OggVorbis_File vorbisFile; static vorbis_info *vi; static FILE *f; static const size_t buffSize = 8 * 4096; static int initVorbis(const char* file); static uint32_t rateVorbis(void); static uint8_t channelVorbis(void); static uint64_t decodeVorbis(void* buffer); static void exitVorbis(void); static uint64_t fillVorbisBuffer(char* bufferOut); /** * Set decoder parameters for Vorbis. * * \param decoder Structure to store parameters. */ void setVorbis(struct decoder_fn* decoder) { decoder->init = &initVorbis; decoder->rate = &rateVorbis; decoder->channels = &channelVorbis; decoder->buffSize = buffSize; decoder->decode = &decodeVorbis; decoder->exit = &exitVorbis; } /** * Initialise Vorbis decoder. * * \param file Location of vorbis file to play. * \return 0 on success, else failure. */ int initVorbis(const char* file) { int err = -1; if((f = fopen(file, "rb")) == NULL) goto out; if(ov_open(f, &vorbisFile, NULL, 0) < 0) goto out; if((vi = ov_info(&vorbisFile, -1)) == NULL) goto out; err = 0; out: return err; } /** * Get sampling rate of Vorbis file. * * \return Sampling rate. */ uint32_t rateVorbis(void) { return vi->rate; } /** * Get number of channels of Vorbis file. * * \return Number of channels for opened file. */ uint8_t channelVorbis(void) { return vi->channels; } /** * Decode part of open Vorbis file. * * \param buffer Decoded output. * \return Samples read for each channel. 0 for end of file, negative * for error. */ uint64_t decodeVorbis(void* buffer) { return fillVorbisBuffer(buffer); } /** * Free Vorbis decoder. */ void exitVorbis(void) { ov_clear(&vorbisFile); fclose(f); } /** * Decode Vorbis file to fill buffer. * * \param opusFile File to decode. * \param bufferOut Pointer to buffer. * \return Samples read per channel. */ uint64_t fillVorbisBuffer(char* bufferOut) { uint64_t samplesRead = 0; int samplesToRead = buffSize; while(samplesToRead > 0) { static int current_section; int samplesJustRead = ov_read(&vorbisFile, bufferOut, samplesToRead > 4096 ? 4096 : samplesToRead, ¤t_section); if(samplesJustRead < 0) return samplesJustRead; else if(samplesJustRead == 0) { /* End of file reached. */ break; } samplesRead += samplesJustRead; samplesToRead -= samplesJustRead; bufferOut += samplesJustRead; } return samplesRead / sizeof(int16_t); } /** * Checks if the input file is Vorbis. * * \param in Input file. * \return 0 if Vorbis file, else not or failure. */ int isVorbis(const char *in) { FILE *ft = fopen(in, "r"); OggVorbis_File testvf; int err; if(ft == NULL) return -1; err = ov_test(ft, &testvf, NULL, 0); ov_clear(&testvf); fclose(ft); return err; }