Files
mice-3ds/source/main.c
Mahyar Koshkouei ba680fb63a Cleanup
Removed some debugging code.

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

408 lines
6.7 KiB
C

/**
* ctrmus - 3DS Music Player
* Copyright (C) 2016 Mahyar Koshkouei
*
* This program comes with ABSOLUTELY NO WARRANTY and is free software. You are
* welcome to redistribute it under certain conditions; for details see the
* LICENSE file.
*/
#include <3ds.h>
#include <dirent.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "all.h"
#include "flac.h"
#include "main.h"
#include "opus.h"
#include "wav.h"
/* Default folder */
#define DEFAULT_DIR "sdmc:/"
/* Maximum number of lines that can be displayed */
#define MAX_LIST 28
enum file_types {
FILE_TYPE_ERROR = -1,
FILE_TYPE_WAV,
FILE_TYPE_FLAC,
FILE_TYPE_OGG,
FILE_TYPE_OPUS
};
int main(int argc, char **argv)
{
PrintConsole topScreen;
PrintConsole bottomScreen;
int fileMax;
int fileNum = 0;
int from = 0;
gfxInitDefault();
consoleInit(GFX_TOP, &topScreen);
consoleInit(GFX_BOTTOM, &bottomScreen);
consoleSelect(&bottomScreen);
chdir(DEFAULT_DIR);
chdir("MUSIC");
if(listDir(from, MAX_LIST, 0) < 0)
{
err_print("Unable to list directory.");
goto err;
}
fileMax = getNumberFiles();
consoleSelect(&topScreen);
puts("Playlist");
consoleSelect(&bottomScreen);
/**
* This allows for music to continue playing through the headphones whilst
* the 3DS is closed.
*/
aptSetSleepAllowed(false);
while(aptMainLoop())
{
u32 kDown;
hidScanInput();
gfxSwapBuffers();
gfxFlushBuffers();
gspWaitForVBlank();
kDown = hidKeysDown();
if(kDown & KEY_START)
break;
if((kDown & KEY_UP) && fileNum > 0)
{
fileNum--;
if(fileMax - fileNum >= from && from != 0)
from--;
}
if((kDown & KEY_DOWN) && fileNum < fileMax)
{
fileNum++;
if(fileNum >= MAX_LIST && fileMax - fileNum >= 0)
from++;
}
if(kDown & (KEY_DOWN | KEY_UP))
{
consoleClear();
if(listDir(from, MAX_LIST, fileNum) < 0)
{
err_print("Unable to list directory.");
}
}
/*
* Pressing B goes up a folder, as well as pressing A or R when ".."
* is selected.
*/
if((kDown & KEY_B) ||
((kDown & (KEY_A | KEY_R)) && (from == 0 && fileNum == 0)))
{
if(chdir("..") != 0)
err_print("chdir");
fileMax = getNumberFiles();
consoleClear();
if(listDir(from, MAX_LIST, fileNum) < 0)
{
err_print("Unable to list directory.");
}
continue;
}
if(kDown & (KEY_A | KEY_R))
{
int audioFileNum = 0;
DIR *dp;
struct dirent *ep;
char* wd = getcwd(NULL, 0);
/* TODO: Error out properly */
if(wd == NULL)
{
err_print("wd");
goto err;
}
dp = opendir(wd);
if(dp != NULL)
{
char* file = NULL;
while((ep = readdir(dp)) != NULL)
{
if(audioFileNum == fileNum - 1)
break;
audioFileNum++;
}
if(ep->d_type == DT_DIR)
{
/* file not allocated yet, so no need to clear it */
if(chdir(ep->d_name) != 0)
err_print("chdir");
fileNum = 0;
from = 0;
consoleClear();
fileMax = getNumberFiles();
if(listDir(from, MAX_LIST, fileNum) < 0)
{
err_print("Unable to list directory.");
}
closedir(dp);
free(wd);
continue;
}
if(asprintf(&file, "%s%s", wd, ep->d_name) == -1)
{
err_print("Constructing file name failed.");
file = NULL;
}
else
{
consoleSelect(&topScreen);
switch(getFileType(file))
{
case FILE_TYPE_WAV:
playWav(file);
break;
case FILE_TYPE_FLAC:
playFlac(file);
break;
case FILE_TYPE_OPUS:
playOpus(file);
break;
default:
consoleSelect(&bottomScreen);
printf("Unsupported File type.\n");
}
}
consoleSelect(&bottomScreen);
free(file);
free(wd);
if(closedir(dp) != 0)
err_print("Closing directory failed.");
}
else
err_print("Unable to open directory.");
}
}
out:
puts("Exiting...");
gfxExit();
return 0;
err:
puts("A fatal error occurred. Press START to exit.");
while(true)
{
u32 kDown;
hidScanInput();
kDown = hidKeysDown();
if(kDown & KEY_START)
break;
}
goto out;
}
/**
* 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;
printf("Dir: %.30s\n", wd);
if((dp = opendir(wd)) == NULL)
goto err;
if(from == 0)
printf("%c../\n", select == 0 ? '>' : ' ');
while((ep = readdir(dp)) != NULL)
{
fileNum++;
if(fileNum <= from)
continue;
if(fileNum == max + from)
break;
listed++;
printf("%c%.38s%s\n",
select == fileNum ? '>' : ' ',
ep->d_name,
ep->d_type == DT_DIR ? "/" : "");
}
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;
char* wd = getcwd(NULL, 0);
int ret = 0;
if(wd == NULL)
goto err;
if((dp = opendir(wd)) == NULL)
goto err;
while((ep = readdir(dp)) != NULL)
ret++;
closedir(dp);
out:
return ret;
err:
ret = -1;
goto out;
}
/**
* Obtains file type.
*
* \param file File location.
* \return File type, else negative.
*/
int getFileType(const char *file)
{
FILE* ftest = fopen(file, "rb");
int fileSig = 0;
enum file_types file_type = FILE_TYPE_ERROR;
if(ftest == NULL)
{
err_print("Opening file failed.");
printf("file: %s\n", file);
return -1;
}
if(fread(&fileSig, 4, 1, ftest) == 0)
{
err_print("Unable to read file.");
fclose(ftest);
return -1;
}
switch(fileSig)
{
// "RIFF"
case 0x46464952:
if(fseek(ftest, 4, SEEK_CUR) != 0)
{
err_print("Unable to seek.");
break;
}
// "WAVE"
// Check required as AVI file format also uses "RIFF".
if(fread(&fileSig, 4, 1, ftest) == 0)
{
err_print("Unable to read potential WAV file.");
break;
}
if(fileSig != 0x45564157)
break;
file_type = FILE_TYPE_WAV;
printf("File type is WAV.");
break;
// "fLaC"
case 0x43614c66:
file_type = FILE_TYPE_FLAC;
printf("File type is FLAC.");
break;
// "OggS"
case 0x5367674f:
if(isOpus(file) == 0)
{
printf("\nFile type is Opus.");
file_type = FILE_TYPE_OPUS;
}
else
{
file_type = FILE_TYPE_OGG;
printf("\nFile type is OGG.");
}
break;
}
fclose(ftest);
return file_type;
}