Add missing function headers

Signed-off-by: Mahyar Koshkouei <deltabeard@users.noreply.github.com>
This commit is contained in:
Mahyar Koshkouei
2017-02-14 22:45:18 +00:00
parent 295edd06f0
commit 65bb01ee72
8 changed files with 334 additions and 299 deletions

View File

@@ -2,6 +2,12 @@
#include <errno.h>
#include <string.h>
/**
* Return string describing error number. Extends strerror to include some
* custom errors used in ctrmus.
*
* \param err Error number.
*/
char* ctrmus_strerror(int err)
{
char* error;

View File

@@ -5,11 +5,25 @@
#define DECODER_INIT_FAIL 1001
#define FILE_NOT_SUPPORTED 1002
/**
* Struct to help error handling across threads.
*/
struct errInfo_t
{
/* errno code or from defines listed above */
volatile int* error;
Handle* failEvent;
/* Extra information regarding error (Must be NULL if unused) */
volatile char* errstr;
/* Event to trigger on error */
Handle* failEvent;
};
/**
* Return string describing error number. Extends strerror to include some
* custom errors used in ctrmus.
*
* \param err Error number.
*/
char* ctrmus_strerror(int err);

View File

@@ -2,6 +2,7 @@
#define DR_FLAC_IMPLEMENTATION
#include <./dr_libs/dr_flac.h>
#include "all.h"
#include "flac.h"

View File

@@ -22,6 +22,185 @@
volatile bool runThreads = true;
/**
* Prints the current key mappings to stdio.
*/
static void showControls(void)
{
printf("Button mappings:\n"
"Pause: L+R or L+Up\n"
"Stop: L+B\n"
"A: Open File\n"
"B: Go up folder\n"
"Start: Exit\n");
}
/**
* Allows the playback thread to return any error messages that it may
* encounter.
*
* \param infoIn Struct containing addresses of the event, the error code,
* and an optional error string.
*/
void playbackWatchdog(void* infoIn)
{
struct watchdogInfo* info = infoIn;
while(runThreads)
{
svcWaitSynchronization(*info->errInfo->failEvent, U64_MAX);
svcClearEvent(*info->errInfo->failEvent);
consoleSelect(info->screen);
if(*info->errInfo->error != 0)
{
printf("Error %d: %s", *info->errInfo->error,
ctrmus_strerror(*info->errInfo->error));
if(info->errInfo->errstr != NULL)
{
printf(" %s", info->errInfo->errstr);
delete(info->errInfo->errstr);
}
printf("\n");
}
}
return;
}
/**
* Stop the currently playing file (if there is one) and play another file.
*
* \param ep_file File to play.
* \param playbackInfo Information that the playback thread requires to
* play file.
*/
static int changeFile(const char* ep_file, struct playbackInfo_t* playbackInfo)
{
s32 prio;
static Thread thread = NULL;
/**
* If music is playing, stop it. Only one playback thread should be playing
* at any time.
*/
if(thread != NULL)
{
/* Tell the thread to stop playback before we join it */
stopPlayback();
threadJoin(thread, U64_MAX);
threadFree(thread);
thread = NULL;
/* free allocated file string */
delete(playbackInfo->file);
}
if(ep_file == NULL || playbackInfo == NULL)
return 0;
playbackInfo->file = strdup(ep_file);
printf("Playing: %s\n", playbackInfo->file);
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
thread = threadCreate(playFile, playbackInfo, 32 * 1024, prio - 1, -2, false);
return 0;
}
/**
* List current directory.
*
* \param from First entry in directory to list.
* \param max Maximum number of entries to list. Must be > 0.
* \param select File to show as selected. Must be > 0.
* \return Number of entries listed or negative on error.
*/
static int listDir(int from, int max, int select)
{
DIR *dp;
struct dirent *ep;
int fileNum = 0;
int listed = 0;
char* wd = getcwd(NULL, 0);
if(wd == NULL)
goto err;
consoleClear();
printf("Dir: %.33s\n", wd);
if((dp = opendir(wd)) == NULL)
goto err;
if(from == 0)
{
printf("%c../\n", select == 0 ? '>' : ' ');
listed++;
}
while((ep = readdir(dp)) != NULL)
{
fileNum++;
if(fileNum <= from)
continue;
listed++;
printf("%c%s%.37s%s\n",
select == fileNum ? '>' : ' ',
ep->d_type == DT_DIR ? "\x1b[34;1m" : "",
ep->d_name,
ep->d_type == DT_DIR ? "/\x1b[0m" : "");
if(fileNum == max + from)
break;
}
if(closedir(dp) != 0)
goto err;
out:
free(wd);
return listed;
err:
listed = -1;
goto out;
}
/**
* Get number of files in current working folder
*
* \return Number of files in current working folder, -1 on failure with
* errno set.
*/
int getNumberFiles(void)
{
DIR *dp;
struct dirent *ep;
int ret = 0;
if((dp = opendir(".")) == NULL)
goto err;
while((ep = readdir(dp)) != NULL)
ret++;
closedir(dp);
out:
return ret;
err:
ret = -1;
goto out;
}
int main(int argc, char **argv)
{
PrintConsole topScreen;
@@ -262,164 +441,3 @@ err:
goto out;
}
static void showControls(void)
{
printf("Button mappings:\n"
"Pause: L+R or L+Up\n"
"Stop: L+B\n"
"A: Open File\n"
"B: Go up folder\n"
"Start: Exit\n");
}
void playbackWatchdog(void* infoIn)
{
struct watchdogInfo* info = infoIn;
while(runThreads)
{
svcWaitSynchronization(*info->errInfo->failEvent, U64_MAX);
svcClearEvent(*info->errInfo->failEvent);
consoleSelect(info->screen);
if(*info->errInfo->error != 0)
{
printf("Error %d: %s", *info->errInfo->error,
ctrmus_strerror(*info->errInfo->error));
if(info->errInfo->errstr != NULL)
{
printf(" %s", info->errInfo->errstr);
delete(info->errInfo->errstr);
}
printf("\n");
}
}
return;
}
static int changeFile(const char* ep_file, struct playbackInfo_t* playbackInfo)
{
s32 prio;
static Thread thread = NULL;
/**
* If music is playing, stop it. Only one playback thread should be playing
* at any time.
*/
if(thread != NULL)
{
/* Tell the thread to stop playback before we join it */
stopPlayback();
threadJoin(thread, U64_MAX);
threadFree(thread);
thread = NULL;
/* free allocated file string */
delete(playbackInfo->file);
}
if(ep_file == NULL || playbackInfo == NULL)
return 0;
playbackInfo->file = strdup(ep_file);
printf("Playing: %s\n", playbackInfo->file);
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
thread = threadCreate(playFile, playbackInfo, 32 * 1024, prio - 1, -2, false);
return 0;
}
/**
* List current directory.
*
* \param from First entry in directory to list.
* \param max Maximum number of entries to list. Must be > 0.
* \param select File to show as selected. Must be > 0.
* \return Number of entries listed or negative on error.
*/
int listDir(int from, int max, int select)
{
DIR *dp;
struct dirent *ep;
int fileNum = 0;
int listed = 0;
char* wd = getcwd(NULL, 0);
if(wd == NULL)
goto err;
consoleClear();
printf("Dir: %.33s\n", wd);
if((dp = opendir(wd)) == NULL)
goto err;
if(from == 0)
{
printf("%c../\n", select == 0 ? '>' : ' ');
listed++;
}
while((ep = readdir(dp)) != NULL)
{
fileNum++;
if(fileNum <= from)
continue;
listed++;
printf("%c%s%.37s%s\n",
select == fileNum ? '>' : ' ',
ep->d_type == DT_DIR ? "\x1b[34;1m" : "",
ep->d_name,
ep->d_type == DT_DIR ? "/\x1b[0m" : "");
if(fileNum == max + from)
break;
}
if(closedir(dp) != 0)
goto err;
out:
free(wd);
return listed;
err:
listed = -1;
goto out;
}
/**
* Get number of files in current working folder
*
* \return Number of files in current working folder, -1 on failure with
* errno set.
*/
int getNumberFiles(void)
{
DIR *dp;
struct dirent *ep;
int ret = 0;
if((dp = opendir(".")) == NULL)
goto err;
while((ep = readdir(dp)) != NULL)
ret++;
closedir(dp);
out:
return ret;
err:
ret = -1;
goto out;
}

View File

@@ -10,8 +10,6 @@
#ifndef ctrmus_main_h
#define ctrmus_main_h
#include "playback.h"
/* Default folder */
#define DEFAULT_DIR "sdmc:/"
@@ -24,12 +22,15 @@ struct watchdogInfo
struct errInfo_t* errInfo;
};
/**
* Allows the playback thread to return any error messages that it may
* encounter.
*
* \param infoIn Struct containing addresses of the event, the error code,
* and an optional error string.
*/
void playbackWatchdog(void* infoIn);
static void showControls(void);
static int changeFile(const char* ep_file, struct playbackInfo_t* playbackInfo);
/**
* Get number of files in current working folder
*
@@ -38,14 +39,4 @@ static int changeFile(const char* ep_file, struct playbackInfo_t* playbackInfo);
*/
int getNumberFiles(void);
/**
* List current directory.
*
* \param from First entry in directory to list.
* \param max Maximum number of entries to list. Must be > 0.
* \param select File to show as selected. Must be > 0.
* \return Number of entries listed or negative on error.
*/
int listDir(int from, int max, int select);
#endif

View File

@@ -71,7 +71,8 @@ uint8_t channelOpus(void)
* Decode part of open Opus file.
*
* \param buffer Decoded output.
* \return Samples read for each channel.
* \return Samples read for each channel. 0 for end of file, negative
* for error.
*/
uint64_t decodeOpus(void* buffer)
{
@@ -104,11 +105,7 @@ uint64_t fillOpusBuffer(OggOpusFile* opusFile, int16_t* bufferOut)
samplesToRead > 120*48*2 ? 120*48*2 : samplesToRead);
if(samplesJustRead < 0)
{
/* TODO: Printing should not be done here. */
printf("\nFatal error decoding Opus: %d.", samplesJustRead);
return 0;
}
return samplesJustRead;
else if(samplesJustRead == 0)
{
/* End of file reached. */

View File

@@ -12,10 +12,118 @@
static volatile bool stop = false;
/**
* Pause or play current file.
*
* \return True if paused.
*/
bool togglePlayback(void)
{
bool paused = ndspChnIsPaused(CHANNEL);
ndspChnSetPaused(CHANNEL, !paused);
return !paused;
}
/**
* Stops current playback. Playback thread should exit as a result.
*/
void stopPlayback(void)
{
stop = true;
}
/**
* Returns whether music is playing or paused.
*/
bool isPlaying(void)
{
return !stop;
}
/**
* Obtains file type.
*
* \param file File location.
* \return File type, else negative and errno set.
*/
static int getFileType(const char *file)
{
FILE* ftest = fopen(file, "rb");
int fileSig = 0;
enum file_types file_type = FILE_TYPE_ERROR;
/* Failure opening file */
if(ftest == NULL)
return -1;
if(fread(&fileSig, 4, 1, ftest) == 0)
goto err;
switch(fileSig)
{
// "RIFF"
case 0x46464952:
if(fseek(ftest, 4, SEEK_CUR) != 0)
break;
// "WAVE"
// Check required as AVI file format also uses "RIFF".
if(fread(&fileSig, 4, 1, ftest) == 0)
break;
if(fileSig != 0x45564157)
break;
file_type = FILE_TYPE_WAV;
break;
// "fLaC"
case 0x43614c66:
file_type = FILE_TYPE_FLAC;
break;
// "OggS"
case 0x5367674f:
if(isOpus(file) == 0)
file_type = FILE_TYPE_OPUS;
else
{
//file_type = FILE_TYPE_OGG;
errno = FILE_NOT_SUPPORTED;
}
break;
default:
/*
* MP3 without ID3 tag, ID3v1 tag is at the end of file, or MP3
* with ID3 tag at the beginning of the file.
*/
if((fileSig << 16) == 0xFBFF0000 ||
(fileSig << 16) == 0xFAFF0000 ||
(fileSig << 8) == 0x33444900)
{
file_type = FILE_TYPE_MP3;
break;
}
/* TODO: Add this again at some point */
//printf("Unknown magic number: %#010x\n.", fileSig);
errno = FILE_NOT_SUPPORTED;
break;
}
err:
fclose(ftest);
return file_type;
}
/**
* Should only be called from a new thread only, and have only one playback
* thread at time. This function has not been written for more than one
* playback thread in mind.
*
* \param infoIn Playback information.
*/
void playFile(void* infoIn)
{
@@ -28,10 +136,6 @@ void playFile(void* infoIn)
int ret = -1;
const char* file = info->file;
//info->errInfo->errstr = strdup("Testing.");
//errno = 1001;
//goto err;
/* Reset previous stop command */
stop = false;
@@ -116,7 +220,7 @@ void playFile(void* infoIn)
{
size_t read = (*decoder.decode)(&buffer1[0]);
if(read == 0)
if(read <= 0)
{
lastbuf = true;
continue;
@@ -131,7 +235,7 @@ void playFile(void* infoIn)
{
size_t read = (*decoder.decode)(&buffer2[0]);
if(read == 0)
if(read <= 0)
{
lastbuf = true;
continue;
@@ -157,107 +261,6 @@ out:
err:
*info->errInfo->error = errno;
printf("%s:%d errno:%d %d\n", __func__, __LINE__, errno, *info->errInfo->error);
svcSignalEvent(*info->errInfo->failEvent);
goto out;
}
/**
* Pause or play current file.
*
* \return True if paused.
*/
bool togglePlayback(void)
{
bool paused = ndspChnIsPaused(CHANNEL);
ndspChnSetPaused(CHANNEL, !paused);
return !paused;
}
void stopPlayback(void)
{
stop = true;
}
bool isPlaying(void)
{
return !stop;
}
/**
* Obtains file type.
*
* \param file File location.
* \return File type, else negative and errno set.
*/
int getFileType(const char *file)
{
FILE* ftest = fopen(file, "rb");
int fileSig = 0;
enum file_types file_type = FILE_TYPE_ERROR;
/* Failure opening file */
if(ftest == NULL)
return -1;
if(fread(&fileSig, 4, 1, ftest) == 0)
goto err;
switch(fileSig)
{
// "RIFF"
case 0x46464952:
if(fseek(ftest, 4, SEEK_CUR) != 0)
break;
// "WAVE"
// Check required as AVI file format also uses "RIFF".
if(fread(&fileSig, 4, 1, ftest) == 0)
break;
if(fileSig != 0x45564157)
break;
file_type = FILE_TYPE_WAV;
break;
// "fLaC"
case 0x43614c66:
file_type = FILE_TYPE_FLAC;
break;
// "OggS"
case 0x5367674f:
if(isOpus(file) == 0)
file_type = FILE_TYPE_OPUS;
else
{
//file_type = FILE_TYPE_OGG;
errno = FILE_NOT_SUPPORTED;
}
break;
default:
/*
* MP3 without ID3 tag, ID3v1 tag is at the end of file, or MP3
* with ID3 tag at the beginning of the file.
*/
if((fileSig << 16) == 0xFBFF0000 ||
(fileSig << 16) == 0xFAFF0000 ||
(fileSig << 8) == 0x33444900)
{
file_type = FILE_TYPE_MP3;
break;
}
/* TODO: Add this again at some point */
//printf("Unknown magic number: %#010x\n.", fileSig);
errno = FILE_NOT_SUPPORTED;
break;
}
err:
fclose(ftest);
return file_type;
}

View File

@@ -17,6 +17,13 @@ struct playbackInfo_t
struct errInfo_t* errInfo;
};
/**
* Should only be called from a new thread only, and have only one playback
* thread at time. This function has not been written for more than one
* playback thread in mind.
*
* \param infoIn Playback information.
*/
void playFile(void* infoIn);
/**
@@ -26,16 +33,14 @@ void playFile(void* infoIn);
*/
bool togglePlayback(void);
/**
* Stops current playback. Playback thread should exit as a result.
*/
void stopPlayback(void);
/**
* Returns whether music is playing or paused.
*/
bool isPlaying(void);
/**
* Obtains file type.
*
* \param file File location.
* \return File type, else negative.
*/
int getFileType(const char *file);
#endif