Files
mice-3ds/source/opus.c
Mahyar Koshkouei 4f4228bd0a Fix Opus not decoding at correct rate
Fixed an issue whereby Opus files would decode at the original sampling
rate rather than the sampling rate of the Opus file itself which should
always be 48000.

[Opus Custom](https://wiki.xiph.org/OpusFAQ#What_is_Opus_Custom.3F) is
not supported.

Signed-off-by: Mahyar Koshkouei <deltabeard@users.noreply.github.com>
2017-03-11 16:10:01 +00:00

137 lines
2.5 KiB
C

#include <3ds.h>
#include <stdlib.h>
#include <string.h>
#include "opus.h"
#include "playback.h"
static OggOpusFile* opusFile;
static const OpusHead* opusHead;
static const size_t buffSize = 32 * 1024;
/**
* Set decoder parameters for Opus.
*
* \param decoder Structure to store parameters.
*/
void setOpus(struct decoder_fn* decoder)
{
decoder->init = &initOpus;
decoder->rate = &rateOpus;
decoder->channels = &channelOpus;
decoder->buffSize = buffSize;
decoder->decode = &decodeOpus;
decoder->exit = &exitOpus;
}
/**
* Initialise Opus decoder.
*
* \param file Location of opus file to play.
* \return 0 on success, else failure.
*/
int initOpus(const char* file)
{
int err = 0;
if((opusFile = op_open_file(file, &err)) == NULL)
goto out;
if((err = op_current_link(opusFile)) < 0)
goto out;
opusHead = op_head(opusFile, err);
out:
return err;
}
/**
* Get sampling rate of Opus file.
*
* \return Sampling rate. Should be 48000.
*/
uint32_t rateOpus(void)
{
return 48000;
}
/**
* Get number of channels of Opus file.
*
* \return Number of channels for opened file, so always be 2.
*/
uint8_t channelOpus(void)
{
/* Opus decoder always returns stereo stream */
return 2;
}
/**
* Decode part of open Opus file.
*
* \param buffer Decoded output.
* \return Samples read for each channel. 0 for end of file, negative
* for error.
*/
uint64_t decodeOpus(void* buffer)
{
return fillOpusBuffer(opusFile, buffer);
}
/**
* Free Opus decoder.
*/
void exitOpus(void)
{
op_free(opusFile);
}
/**
* Decode Opus file to fill buffer.
*
* \param opusFile File to decode.
* \param bufferOut Pointer to buffer.
* \return Samples read per channel.
*/
uint64_t fillOpusBuffer(OggOpusFile* opusFile, int16_t* bufferOut)
{
uint64_t samplesRead = 0;
int samplesToRead = buffSize;
while(samplesToRead > 0)
{
int samplesJustRead = op_read_stereo(opusFile, bufferOut,
samplesToRead > 120*48*2 ? 120*48*2 : samplesToRead);
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 Opus.
*
* \param in Input file.
* \return 0 if Opus file, else not or failure.
*/
int isOpus(const char* in)
{
int err = 0;
OggOpusFile* opusTest = op_test_file(in, &err);
op_free(opusTest);
return err;
}