Add Vorbis decoder
Additionally implemented better handling of the playback stopping procedure. Signed-off-by: Mahyar Koshkouei <mk@deltabeard.com>
This commit is contained in:
151
source/vorbis.c
Normal file
151
source/vorbis.c
Normal file
@@ -0,0 +1,151 @@
|
||||
#include <3ds.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vorbis.h"
|
||||
#include "playback.h"
|
||||
|
||||
static OggVorbis_File vorbisFile;
|
||||
static vorbis_info *vi;
|
||||
static int current_section;
|
||||
static FILE *f;
|
||||
static const size_t buffSize = 8 * 4096;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
f = fopen(file, "r");
|
||||
|
||||
if(ov_open(f, &vorbisFile, NULL, 0) < 0)
|
||||
goto out;
|
||||
|
||||
if((vi = ov_info(&vorbisFile, -1)) == NULL)
|
||||
goto out;
|
||||
|
||||
current_section = 0;
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sampling rate of Vorbis file.
|
||||
*
|
||||
* \return Sampling rate.
|
||||
*/
|
||||
uint32_t rateVorbis(void)
|
||||
{
|
||||
printf("Rate: %ld\n", vi->rate);
|
||||
return vi->rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of channels of Vorbis file.
|
||||
*
|
||||
* \return Number of channels for opened file.
|
||||
*/
|
||||
uint8_t channelVorbis(void)
|
||||
{
|
||||
printf("Rate: %d\n", vi->channels);
|
||||
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)
|
||||
{
|
||||
fclose(f);
|
||||
ov_clear(&vorbisFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
int samplesJustRead =
|
||||
ov_read(&vorbisFile, bufferOut, samplesToRead, ¤t_section);
|
||||
|
||||
if(samplesJustRead < 0)
|
||||
return samplesJustRead;
|
||||
else if(samplesJustRead == 0)
|
||||
{
|
||||
/* End of file reached. */
|
||||
break;
|
||||
}
|
||||
|
||||
samplesRead += samplesJustRead * 2;
|
||||
samplesToRead -= samplesJustRead * 2;
|
||||
bufferOut += samplesJustRead * 2;
|
||||
}
|
||||
|
||||
return samplesRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// TODO: Only free if a new file is selected to play.
|
||||
FILE *ft = fopen(in, "r");
|
||||
OggVorbis_File testvf;
|
||||
int err;
|
||||
|
||||
if(ft == NULL)
|
||||
return -1;
|
||||
|
||||
err = ov_test(ft, &testvf, NULL, 0);
|
||||
|
||||
fclose(ft);
|
||||
ov_clear(&testvf);
|
||||
return err;
|
||||
}
|
||||
Reference in New Issue
Block a user