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:
2
Makefile
2
Makefile
@@ -49,7 +49,7 @@ SOURCE_DIRS := source
|
|||||||
EXTRA_OUTPUT_FILES :=
|
EXTRA_OUTPUT_FILES :=
|
||||||
|
|
||||||
LIBRARY_DIRS := $(DEVKITPRO)/libctru $(DEVKITPRO)/portlibs/armv6k
|
LIBRARY_DIRS := $(DEVKITPRO)/libctru $(DEVKITPRO)/portlibs/armv6k
|
||||||
LIBRARIES := mpg123 opusfile opus ogg ctru m
|
LIBRARIES := mpg123 vorbisidec opusfile opus ogg ctru m
|
||||||
|
|
||||||
BUILD_FLAGS := -Wall -Wextra
|
BUILD_FLAGS := -Wall -Wextra
|
||||||
RUN_FLAGS :=
|
RUN_FLAGS :=
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ void playbackWatchdog(void* infoIn)
|
|||||||
svcWaitSynchronization(*info->errInfo->failEvent, U64_MAX);
|
svcWaitSynchronization(*info->errInfo->failEvent, U64_MAX);
|
||||||
svcClearEvent(*info->errInfo->failEvent);
|
svcClearEvent(*info->errInfo->failEvent);
|
||||||
|
|
||||||
if(*info->errInfo->error != 0)
|
if(*info->errInfo->error > 0)
|
||||||
{
|
{
|
||||||
consoleSelect(info->screen);
|
consoleSelect(info->screen);
|
||||||
printf("Error %d: %s", *info->errInfo->error,
|
printf("Error %d: %s", *info->errInfo->error,
|
||||||
@@ -66,6 +66,14 @@ void playbackWatchdog(void* infoIn)
|
|||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
else if (*info->errInfo->error == -1)
|
||||||
|
{
|
||||||
|
/* Used to signify that playback has stopped.
|
||||||
|
* Not technically an error.
|
||||||
|
*/
|
||||||
|
consoleSelect(info->screen);
|
||||||
|
puts("Stopped");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -391,8 +399,9 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
stopPlayback();
|
stopPlayback();
|
||||||
changeFile(NULL, &playbackInfo);
|
changeFile(NULL, &playbackInfo);
|
||||||
consoleSelect(&topScreen);
|
/* If the playback thread is currently playing, it will now
|
||||||
puts("Stopped");
|
* stop and tell the Watchdog thread to display "Stopped".
|
||||||
|
*/
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "mp3.h"
|
#include "mp3.h"
|
||||||
#include "opus.h"
|
#include "opus.h"
|
||||||
#include "playback.h"
|
#include "playback.h"
|
||||||
|
#include "vorbis.h"
|
||||||
#include "wav.h"
|
#include "wav.h"
|
||||||
|
|
||||||
static volatile bool stop = true;
|
static volatile bool stop = true;
|
||||||
@@ -89,9 +90,10 @@ int getFileType(const char *file)
|
|||||||
file_type = FILE_TYPE_OPUS;
|
file_type = FILE_TYPE_OPUS;
|
||||||
else if(isFlac(file) == 0)
|
else if(isFlac(file) == 0)
|
||||||
file_type = FILE_TYPE_FLAC;
|
file_type = FILE_TYPE_FLAC;
|
||||||
|
else if(isVorbis(file) == 0)
|
||||||
|
file_type = FILE_TYPE_OGG;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//file_type = FILE_TYPE_OGG;
|
|
||||||
errno = FILE_NOT_SUPPORTED;
|
errno = FILE_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +163,9 @@ void playFile(void* infoIn)
|
|||||||
setMp3(&decoder);
|
setMp3(&decoder);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FILE_TYPE_OGG:
|
||||||
|
setVorbis(&decoder);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -263,6 +268,11 @@ out:
|
|||||||
delete(info->file);
|
delete(info->file);
|
||||||
linearFree(buffer1);
|
linearFree(buffer1);
|
||||||
linearFree(buffer2);
|
linearFree(buffer2);
|
||||||
|
|
||||||
|
/* Signal Watchdog thread that we've stopped playing */
|
||||||
|
*info->errInfo->error = -1;
|
||||||
|
svcSignalEvent(*info->errInfo->failEvent);
|
||||||
|
|
||||||
threadExit(0);
|
threadExit(0);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
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;
|
||||||
|
}
|
||||||
21
source/vorbis.h
Normal file
21
source/vorbis.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#include <tremor/ivorbiscodec.h>
|
||||||
|
#include <tremor/ivorbisfile.h>
|
||||||
|
#include "playback.h"
|
||||||
|
|
||||||
|
void setVorbis(struct decoder_fn* decoder);
|
||||||
|
|
||||||
|
int initVorbis(const char* file);
|
||||||
|
|
||||||
|
uint32_t rateVorbis(void);
|
||||||
|
|
||||||
|
uint8_t channelVorbis(void);
|
||||||
|
|
||||||
|
uint64_t decodeVorbis(void* buffer);
|
||||||
|
|
||||||
|
void exitVorbis(void);
|
||||||
|
|
||||||
|
int playVorbis(const char* in);
|
||||||
|
|
||||||
|
uint64_t fillVorbisBuffer(char* bufferOut);
|
||||||
|
|
||||||
|
int isVorbis(const char* in);
|
||||||
Reference in New Issue
Block a user