From da2e11f0a18f634313725a552597e2121722e142 Mon Sep 17 00:00:00 2001 From: TheFloW Date: Mon, 12 Sep 2016 15:49:51 +0200 Subject: [PATCH] Finished audio player. Added OGG playback. --- Makefile | 15 +- README.md | 1 + audio/mp3player.c | 18 +- audio/mp3player.h | 3 +- audio/mp3xing.h | 2 +- audio/oggplayer.c | 536 ++++++++++++++++++++++++++++++++++++++ audio/oggplayer.h | 55 ++++ audio/player.c | 165 +++++++++++- audio/player.h | 42 ++- audio/vita_audio.c | 15 +- audio/vita_audio.h | 13 + audioplayer.c | 178 ++++++++++--- file.c | 1 + file.h | 1 + init.c | 93 ++++--- language.c | 10 +- language.h | 7 + libmad/mad.h | 2 +- main.c | 8 +- main.h | 2 + network_update.c | 2 +- package_installer.c | 2 +- resources/colors.txt | 12 +- resources/cover.png | Bin 0 -> 73961 bytes resources/english_us.txt | 7 + resources/fastforward.png | Bin 0 -> 373 bytes resources/fastrewind.png | Bin 0 -> 393 bytes resources/pause.png | Bin 0 -> 179 bytes resources/play.png | Bin 0 -> 291 bytes resources/stop.png | Bin 0 -> 163 bytes theme.c | 86 ++++-- theme.h | 15 +- 32 files changed, 1150 insertions(+), 141 deletions(-) create mode 100644 audio/oggplayer.c create mode 100644 audio/oggplayer.h create mode 100644 resources/cover.png create mode 100644 resources/fastforward.png create mode 100644 resources/fastrewind.png create mode 100644 resources/pause.png create mode 100644 resources/play.png create mode 100644 resources/stop.png diff --git a/Makefile b/Makefile index afb6bb4..0495ea8 100644 --- a/Makefile +++ b/Makefile @@ -2,20 +2,19 @@ TITLE_ID = VITASHELL TARGET = VitaShell OBJS = main.o init.o io_process.o package_installer.o network_update.o context_menu.o archive.o photo.o audioplayer.o file.o text.o hex.o sfo.o \ uncommon_dialog.o message_dialog.o ime_dialog.o config.o theme.o language.o utils.o sha1.o \ - minizip/unzip.o minizip/ioapi.o bm.o audio/vita_audio.o audio/player.o audio/id3.o audio/mp3player.o audio/mp3xing.o \ + minizip/unzip.o minizip/ioapi.o bm.o audio/vita_audio.o audio/player.o audio/id3.o audio/oggplayer.o audio/mp3player.o audio/mp3xing.o \ libmad/bit.o libmad/decoder.o libmad/fixed.o libmad/frame.o \ libmad/huffman.o libmad/layer12.o libmad/layer3.o \ libmad/stream.o libmad/synth.o libmad/timer.o -RESOURCES_PNG = resources/folder_icon.png resources/file_icon.png resources/archive_icon.png resources/image_icon.png \ - resources/audio_icon.png resources/sfo_icon.png resources/text_icon.png\ - resources/ftp.png resources/battery.png resources/battery_bar_green.png resources/battery_bar_red.png \ - resources/battery_bar_charge.png -RESOURCES_TXT = resources/theme.txt resources/colors.txt resources/english_us.txt resources/changeinfo.txt -RESOURCES_BIN = resources/updater_eboot.bin resources/updater_param.bin +RESOURCES = resources +RESOURCES_PNG := $(foreach dir,$(RESOURCES), $(wildcard $(dir)/*.png)) +RESOURCES_TXT := $(foreach dir,$(RESOURCES), $(wildcard $(dir)/*.txt)) +RESOURCES_BIN := $(foreach dir,$(RESOURCES), $(wildcard $(dir)/*.bin)) + OBJS += $(RESOURCES_PNG:.png=.o) $(RESOURCES_TXT:.txt=.o) $(RESOURCES_BIN:.bin=.o) -LIBS = -lftpvita -lvita2d -lpng -ljpeg -lz -lm -lc \ +LIBS = -lvorbisfile -logg -lvorbis -lftpvita -lvita2d -lpng -ljpeg -lz -lm -lc \ -lSceAppMgr_stub -lSceAppUtil_stub -lSceCommonDialog_stub \ -lSceCtrl_stub -lSceDisplay_stub -lSceGxm_stub -lSceIme_stub \ -lSceHttp_stub -lSceKernel_stub -lSceNet_stub -lSceNetCtl_stub \ diff --git a/README.md b/README.md index ddf4d8f..93ffb66 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ Be sure you pull request your customized design or language file there. * vitasdk: https://github.com/vitasdk * vita2dlib: https://github.com/xerpi/vita2dlib * ftpvitalib https://github.com/xerpi/ftpvitalib +* EasyRPG libraries: https://ci.easyrpg.org/view/Toolchains/job/toolchain-vita/ ### Credits ### * Team Molecule for HENkaku diff --git a/audio/mp3player.c b/audio/mp3player.c index b288961..04ac793 100644 --- a/audio/mp3player.c +++ b/audio/mp3player.c @@ -16,6 +16,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include +#include #include #include #include @@ -26,7 +27,6 @@ #include "id3.h" #include "mp3xing.h" #include "player.h" -#include "vita_audio.h" #include "mp3player.h" #define FALSE 0 @@ -152,7 +152,7 @@ int fillFileBuffer() { // Read into the rest of the file buffer. unsigned char* bufferPos = fileBuffer + bytesToKeep; while (bytesToFill > 0){ - unsigned int bytesRead = sceIoRead(MP3_fd, bufferPos, bytesToFill); + int bytesRead = sceIoRead(MP3_fd, bufferPos, bytesToFill); if (bytesRead == 0x80010013) { MP3_suspend(); @@ -242,7 +242,14 @@ static void MP3Callback(void *buffer, unsigned int samplesToWrite, void *pdata){ //Check for playing speed: if (MP3_playingSpeed){ - if (sceIoLseek32(MP3_fd, 2 * INPUT_BUFFER_SIZE * MP3_playingSpeed, SCE_SEEK_CUR) != MP3_filePos){ + int res = sceIoLseek32(MP3_fd, 2 * INPUT_BUFFER_SIZE * MP3_playingSpeed, SCE_SEEK_CUR); + if (res == 0x80010013) { + MP3_suspend(); + MP3_resume(); + res = sceIoLseek32(MP3_fd, 2 * INPUT_BUFFER_SIZE * MP3_playingSpeed, SCE_SEEK_CUR); + } + + if (res != MP3_filePos){ MP3_filePos += 2 * INPUT_BUFFER_SIZE * MP3_playingSpeed; mad_timer_set(&Timer, (int)((float)MP3_info.length / 100.0 * MP3_GetPercentage()), 1, 1); }else @@ -580,6 +587,9 @@ int MP3_Load(char *filename){ return OPENING_OK; } +int MP3_IsPlaying() { + return MP3_isPlaying; +} /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This function initialises for playing, and starts @@ -637,7 +647,7 @@ float MP3_GetPercentage(){ float perc = 0.0f; if (fileSize > 0){ - perc = ((float)MP3_filePos - (float)tagsize) / ((float)fileSize - (float)tagsize) * 100.0; + perc = ((float)MP3_filePos) / ((float)fileSize - (float)tagsize) * 100.0; if (perc > 100) perc = 100; } diff --git a/audio/mp3player.h b/audio/mp3player.h index 6898d79..fec8070 100644 --- a/audio/mp3player.h +++ b/audio/mp3player.h @@ -15,12 +15,13 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -#include +#include "../libmad/mad.h" extern int MP3_defaultCPUClock; //private functions void MP3_Init(int channel); +int MP3_IsPlaying(); int MP3_Play(); void MP3_Pause(); int MP3_Stop(); diff --git a/audio/mp3xing.h b/audio/mp3xing.h index 26e60ff..61cbc56 100644 --- a/audio/mp3xing.h +++ b/audio/mp3xing.h @@ -18,7 +18,7 @@ #ifndef __mp3xing_h #define __mp3xing_h (1) -#include +#include "../libmad/mad.h" #define XING_BUFFER_SIZE 300 #define XING_GUID (unsigned char [4]) \ diff --git a/audio/oggplayer.c b/audio/oggplayer.c new file mode 100644 index 0000000..ea31ab0 --- /dev/null +++ b/audio/oggplayer.c @@ -0,0 +1,536 @@ +// LightMP3 +// Copyright (C) 2007 Sakya +// sakya_tg@yahoo.it +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +#include +#include +#include + +//#include "tremor/ivorbiscodec.h" //libtremor +//#include "tremor/ivorbisfile.h" //libtremor +#include //ogg-vorbis +#include //ogg-vorbis +#include "player.h" +#include "oggplayer.h" + +///////////////////////////////////////////////////////////////////////////////////////// +//Globals +///////////////////////////////////////////////////////////////////////////////////////// +static int OGG_audio_channel; +static int OGG_channels = 0; +static char OGG_fileName[264]; +static int OGG_file = -1; +static OggVorbis_File OGG_VorbisFile; +static int OGG_eos = 0; +static struct fileInfo OGG_info; +static int OGG_isPlaying = 0; +static unsigned int OGG_volume_boost = 0.0; +static double OGG_milliSeconds = 0.0; +static int OGG_playingSpeed = 0; // 0 = normal +static int OGG_playingDelta = 0; +static int outputInProgress = 0; +static long OGG_suspendPosition = -1; +static long OGG_suspendIsPlaying = 0; +int OGG_defaultCPUClock = 50; +static short OGG_mixBuffer[VITA_NUM_AUDIO_SAMPLES * 2 * 2]__attribute__ ((aligned(64))); +static unsigned long OGG_tempmixleft = 0; +static double OGG_newFilePos = -1; +static int OGG_tagRead = 0; + +///////////////////////////////////////////////////////////////////////////////////////// +//Audio callback +///////////////////////////////////////////////////////////////////////////////////////// +static void oggDecodeThread(void *_buf2, unsigned int numSamples, void *pdata){ + short *_buf = (short *)_buf2; + //static short OGG_mixBuffer[VITA_NUM_AUDIO_SAMPLES * 2 * 2]__attribute__ ((aligned(64))); + //static unsigned long OGG_tempmixleft = 0; + int current_section; + + if (OGG_isPlaying) { // Playing , so mix up a buffer + outputInProgress = 1; + while (OGG_tempmixleft < numSamples) { // Not enough in buffer, so we must mix more + unsigned long bytesRequired = (numSamples - OGG_tempmixleft) * 4; // 2channels, 16bit = 4 bytes per sample + //unsigned long ret = ov_read(&OGG_VorbisFile, (char *) &OGG_mixBuffer[OGG_tempmixleft * 2], bytesRequired, ¤t_section); //libtremor + unsigned long ret = ov_read(&OGG_VorbisFile, (char *) &OGG_mixBuffer[OGG_tempmixleft * 2], bytesRequired, 0, 2, 1, ¤t_section); //ogg-vorbis + if (!ret) { //EOF + OGG_isPlaying = 0; + OGG_eos = 1; + outputInProgress = 0; + return; + } else if (ret < 0) { + if (ret == OV_HOLE) + continue; + OGG_isPlaying = 0; + OGG_eos = 1; + outputInProgress = 0; + return; + } + OGG_tempmixleft += ret / 4; // back down to sample num + } + OGG_info.instantBitrate = ov_bitrate_instant(&OGG_VorbisFile); + OGG_milliSeconds = ov_time_tell(&OGG_VorbisFile); + + if (OGG_newFilePos >= 0) + { + ov_raw_seek(&OGG_VorbisFile, (ogg_int64_t)OGG_newFilePos); + OGG_newFilePos = -1; + } + + //Check for playing speed: + if (OGG_playingSpeed){ + if (ov_raw_seek(&OGG_VorbisFile, ov_raw_tell(&OGG_VorbisFile) + OGG_playingDelta) != 0) + OGG_setPlayingSpeed(0); + } + + if (OGG_tempmixleft >= numSamples) { // Buffer has enough, so copy across + int count, count2; + short *_buf2; + //Volume boost: + if (!OGG_volume_boost){ + for (count = 0; count < VITA_NUM_AUDIO_SAMPLES; count++) { + count2 = count + count; + _buf2 = _buf + count2; + *(_buf2) = OGG_mixBuffer[count2]; + *(_buf2 + 1) = OGG_mixBuffer[count2 + 1]; + } + }else{ + for (count = 0; count < VITA_NUM_AUDIO_SAMPLES; count++) { + count2 = count + count; + _buf2 = _buf + count2; + *(_buf2) = volume_boost(&OGG_mixBuffer[count2], &OGG_volume_boost); + *(_buf2 + 1) = volume_boost(&OGG_mixBuffer[count2 + 1], &OGG_volume_boost); + } + } + // Move the pointers + OGG_tempmixleft -= numSamples; + // Now shuffle the buffer along + for (count = 0; count < OGG_tempmixleft * 2; count++) + OGG_mixBuffer[count] = OGG_mixBuffer[numSamples * 2 + count]; + } + outputInProgress = 0; + } else { // Not Playing , so clear buffer + int count; + for (count = 0; count < numSamples * 2; count++) + *(_buf + count) = 0; + } +} + + +///////////////////////////////////////////////////////////////////////////////////////// +//Callback for vorbis +///////////////////////////////////////////////////////////////////////////////////////// +size_t ogg_callback_read(void *ptr, size_t size, size_t nmemb, void *datasource) +{ + int res = sceIoRead(*(int *) datasource, ptr, size * nmemb); + if (res == 0x80010013) { + OGG_suspend(); + OGG_resume(); + res = sceIoRead(*(int *) datasource, ptr, size * nmemb); + } + return res; +} +int ogg_callback_seek(void *datasource, ogg_int64_t offset, int whence) +{ + int res = sceIoLseek32(*(int *) datasource, (unsigned int) offset, whence); + if (res == 0x80010013) { + OGG_suspend(); + OGG_resume(); + res = sceIoLseek32(*(int *) datasource, (unsigned int) offset, whence); + } + return res; +} +long ogg_callback_tell(void *datasource) +{ + int res = sceIoLseek32(*(int *) datasource, 0, SEEK_CUR); + if (res == 0x80010013) { + OGG_suspend(); + OGG_resume(); + res = sceIoLseek32(*(int *) datasource, 0, SEEK_CUR); + } + return (long)res; +} +int ogg_callback_close(void *datasource) +{ + int res = sceIoClose(*(int *) datasource); + if (res == 0x80010013) { + OGG_suspend(); + OGG_resume(); + res = sceIoClose(*(int *) datasource); + } + return res; +} + +void readOggTagData(char *source, char *dest){ + int count = 0; + int i = 0; + + strcpy(dest, ""); + for (i=0; i= 0x20 && (unsigned char)source[i] <= 0xfd){ + dest[count] = source[i]; + if (++count >= 256) + break; + } + } + dest[count] = '\0'; +} + +void splitComment(char *comment, char *name, char *value){ + char *result = NULL; + result = strtok(comment, "="); + int count = 0; + + while(result != NULL && count < 2){ + if (strlen(result) > 0){ + switch (count){ + case 0: + strncpy(name, result, 30); + name[30] = '\0'; + break; + case 1: + readOggTagData(result, value); + value[256] = '\0'; + break; + } + count++; + } + result = strtok(NULL, "="); + } +} + +void getOGGTagInfo(OggVorbis_File *inVorbisFile, struct fileInfo *targetInfo){ + int i; + char name[31]; + char value[257]; + + vorbis_comment *comment = ov_comment(inVorbisFile, -1); + for (i=0;icomments; i++){ + splitComment(comment->user_comments[i], name, value); + if (!strcasecmp(name, "TITLE")) + strcpy(targetInfo->title, value); + else if(!strcasecmp(name, "ALBUM")) + strcpy(targetInfo->album, value); + else if(!strcasecmp(name, "ARTIST")) + strcpy(targetInfo->artist, value); + else if(!strcasecmp(name, "GENRE")) + strcpy(targetInfo->genre, value); + else if(!strcasecmp(name, "DATE") || !strcasecmp(name, "YEAR")){ + strncpy(targetInfo->year, value, 4); + targetInfo->year[4] = '\0'; + }else if(!strcasecmp(name, "TRACKNUMBER")){ + strncpy(targetInfo->trackNumber, value, 7); + targetInfo->trackNumber[7] = '\0'; + } + /*else if(!strcmp(name, "COVERART_UUENCODED")){ + FILE *out = fopen("ms0:/coverart.jpg", "wb"); + FILE *outEnc = fopen("ms0:/coverart.txt", "wb"); + unsigned char base64Buffer[MAX_IMAGE_DIMENSION]; + fwrite(&comment->user_comments[i][19], 1, comment->comment_lengths[i] - 19, outEnc); + int outChars = base64Decode(comment->comment_lengths[i], comment->user_comments[i], MAX_IMAGE_DIMENSION, base64Buffer); + fwrite(base64Buffer, 1, outChars, out); + fclose(outEnc); + fclose(out); + }*/ + } + + OGG_info = *targetInfo; + OGG_tagRead = 1; +} + +void OGGgetInfo(){ + //Estraggo le informazioni: + OGG_info.fileType = OGG_TYPE; + OGG_info.defaultCPUClock = OGG_defaultCPUClock; + OGG_info.needsME = 0; + + vorbis_info *vi = ov_info(&OGG_VorbisFile, -1); + OGG_info.kbit = vi->bitrate_nominal/1000; + OGG_info.instantBitrate = vi->bitrate_nominal; + OGG_info.hz = vi->rate; + OGG_info.length = (long)ov_time_total(&OGG_VorbisFile, -1)/1000; + if (vi->channels == 1){ + strcpy(OGG_info.mode, "single channel"); + OGG_channels = 1; + }else if (vi->channels == 2){ + strcpy(OGG_info.mode, "normal LR stereo"); + OGG_channels = 2; + } + strcpy(OGG_info.emphasis, "no"); + + int h = 0; + int m = 0; + int s = 0; + long secs = OGG_info.length; + h = secs / 3600; + m = (secs - h * 3600) / 60; + s = secs - h * 3600 - m * 60; + snprintf(OGG_info.strLength, sizeof(OGG_info.strLength), "%2.2i:%2.2i:%2.2i", h, m, s); + + if (!OGG_tagRead) + getOGGTagInfo(&OGG_VorbisFile, &OGG_info); +} + + +void OGG_Init(int channel){ + initAudioLib(); + MIN_PLAYING_SPEED=-119; + MAX_PLAYING_SPEED=119; + initFileInfo(&OGG_info); + OGG_tagRead = 0; + OGG_audio_channel = channel; + OGG_milliSeconds = 0.0; + OGG_tempmixleft = 0; + memset(OGG_mixBuffer, 0, sizeof(OGG_mixBuffer)); + vitaAudioSetChannelCallback(OGG_audio_channel, oggDecodeThread, NULL); +} + + +int OGG_Load(char *filename){ + outputInProgress = 0; + OGG_isPlaying = 0; + OGG_milliSeconds = 0; + OGG_eos = 0; + OGG_playingSpeed = 0; + OGG_playingDelta = 0; + strcpy(OGG_fileName, filename); + //Apro il file OGG: + OGG_file = sceIoOpen(OGG_fileName, SCE_O_RDONLY, 0777); + if (OGG_file >= 0) { + OGG_info.fileSize = sceIoLseek(OGG_file, 0, SCE_SEEK_END); + sceIoLseek(OGG_file, 0, SCE_SEEK_SET); + ov_callbacks ogg_callbacks; + + ogg_callbacks.read_func = ogg_callback_read; + ogg_callbacks.seek_func = ogg_callback_seek; + ogg_callbacks.close_func = ogg_callback_close; + ogg_callbacks.tell_func = ogg_callback_tell; + if (ov_open_callbacks(&OGG_file, &OGG_VorbisFile, NULL, 0, ogg_callbacks) < 0){ + sceIoClose(OGG_file); + OGG_file = -1; + return ERROR_OPENING; + } + }else{ + return ERROR_OPENING; + } + + OGGgetInfo(); + //Controllo il sample rate: + if (vitaAudioSetFrequency(OGG_audio_channel, OGG_info.hz) < 0){ + OGG_FreeTune(); + return ERROR_INVALID_SAMPLE_RATE; + } + return OPENING_OK; +} + +int OGG_IsPlaying() { + return OGG_isPlaying; +} + +int OGG_Play(){ + OGG_isPlaying = 1; + return 0; +} + +void OGG_Pause(){ + OGG_isPlaying = !OGG_isPlaying; +} + +int OGG_Stop(){ + OGG_isPlaying = 0; + //This is to be sure that oggDecodeThread isn't messing with &OGG_VorbisFile + while (outputInProgress == 1) + sceKernelDelayThread(100000); + return 0; +} + +void OGG_FreeTune(){ + ov_clear(&OGG_VorbisFile); + if (OGG_file >= 0) + sceIoClose(OGG_file); + OGG_file = -1; + OGG_tempmixleft = 0; + memset(OGG_mixBuffer, 0, sizeof(OGG_mixBuffer)); +} + +void OGG_GetTimeString(char *dest){ + char timeString[9]; + long secs = (long)OGG_milliSeconds/1000; + int h = secs / 3600; + int m = (secs - h * 3600) / 60; + int s = secs - h * 3600 - m * 60; + snprintf(timeString, sizeof(timeString), "%2.2i:%2.2i:%2.2i", h, m, s); + strcpy(dest, timeString); +} + + +int OGG_EndOfStream(){ + return OGG_eos; +} + +struct fileInfo *OGG_GetInfo(){ + return &OGG_info; +} + + +struct fileInfo OGG_GetTagInfoOnly(char *filename){ + int tempFile = -1; + OggVorbis_File vf; + struct fileInfo tempInfo; + + strcpy(OGG_fileName, filename); + initFileInfo(&tempInfo); + //Apro il file OGG: + tempFile = sceIoOpen(filename, SCE_O_RDONLY, 0777); + if (tempFile >= 0) { + //sceIoLseek(tempFile, 0, SCE_SEEK_SET); + ov_callbacks ogg_callbacks; + + ogg_callbacks.read_func = ogg_callback_read; + ogg_callbacks.seek_func = ogg_callback_seek; + ogg_callbacks.close_func = ogg_callback_close; + ogg_callbacks.tell_func = ogg_callback_tell; + + if (ov_open_callbacks(&tempFile, &vf, NULL, 0, ogg_callbacks) < 0){ + sceIoClose(tempFile); + return tempInfo; + } + getOGGTagInfo(&vf, &tempInfo); + ov_clear(&vf); + if (tempFile >= 0) + sceIoClose(tempFile); + } + + return tempInfo; +} + + +float OGG_GetPercentage(){ + float perc = 0.0f; + if (OGG_info.length){ + perc = (float)(OGG_milliSeconds/1000.0/(double)OGG_info.length*100.0); + if (perc > 100) + perc = 100; + } + return perc; +} + +void OGG_End(){ + OGG_Stop(); + vitaAudioSetChannelCallback(OGG_audio_channel, 0,0); + OGG_FreeTune(); + endAudioLib(); +} + +int OGG_setMute(int onOff){ + return setMute(OGG_audio_channel, onOff); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Fade out: +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OGG_fadeOut(float seconds){ + fadeOut(OGG_audio_channel, seconds); +} + + +void OGG_setVolumeBoost(int boost){ + OGG_volume_boost = boost; +} + +int OGG_getVolumeBoost(){ + return OGG_volume_boost; +} + + +int OGG_setPlayingSpeed(int playingSpeed){ + if (playingSpeed >= MIN_PLAYING_SPEED && playingSpeed <= MAX_PLAYING_SPEED){ + OGG_playingSpeed = playingSpeed; + if (playingSpeed == 0) + setVolume(OGG_audio_channel, 0x8000); + else + setVolume(OGG_audio_channel, FASTFORWARD_VOLUME); + OGG_playingDelta = VITA_NUM_AUDIO_SAMPLES * (int)(OGG_playingSpeed/2); + return 0; + }else{ + return -1; + } +} + +int OGG_getPlayingSpeed(){ + return OGG_playingSpeed; +} + +int OGG_GetStatus(){ + return 0; +} + +void OGG_setVolumeBoostType(char *boostType){ + //Only old method supported + MAX_VOLUME_BOOST = 4; + MIN_VOLUME_BOOST = 0; +} + + +//Functions for filter (equalizer): +int OGG_setFilter(double tFilter[32], int copyFilter){ + return 0; +} + +void OGG_enableFilter(){} + +void OGG_disableFilter(){} + +int OGG_isFilterSupported(){ + return 0; +} + +int OGG_isFilterEnabled(){ + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Manage suspend: +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int OGG_suspend(){ + OGG_suspendPosition = ov_raw_tell(&OGG_VorbisFile); + OGG_suspendIsPlaying = OGG_isPlaying; + //OGG_Stop(); + //OGG_FreeTune(); + OGG_End(); + return 0; +} + +int OGG_resume(){ + OGG_Init(OGG_audio_channel); + if (OGG_suspendPosition >= 0){ + if (OGG_Load(OGG_fileName) == OPENING_OK){ + if (ov_raw_seek(&OGG_VorbisFile, OGG_suspendPosition)) + OGG_isPlaying = OGG_suspendIsPlaying; + } + OGG_suspendPosition = -1; + } + return 0; +} + +double OGG_getFilePosition() +{ + return (double)ov_raw_tell(&OGG_VorbisFile); +} + +void OGG_setFilePosition(double position) +{ + OGG_newFilePos = position; +} diff --git a/audio/oggplayer.h b/audio/oggplayer.h new file mode 100644 index 0000000..c078db0 --- /dev/null +++ b/audio/oggplayer.h @@ -0,0 +1,55 @@ +// LightMP3 +// Copyright (C) 2007 Sakya +// sakya_tg@yahoo.it +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +extern int OGG_defaultCPUClock; + +//private functions +void OGG_Init(int channel); +int OGG_IsPlaying(); +int OGG_Play(); +void OGG_Pause(); +int OGG_Stop(); +void OGG_End(); +void OGG_FreeTune(); +int OGG_Load(char *filename); +void OGG_GetTimeString(char *dest); +int OGG_EndOfStream(); +struct fileInfo *OGG_GetInfo(); +struct fileInfo OGG_GetTagInfoOnly(char *filename); +int OGG_GetStatus(); +float OGG_GetPercentage(); +void OGG_setVolumeBoostType(char *boostType); +void OGG_setVolumeBoost(int boost); +int OGG_getVolumeBoost(); +int OGG_getPlayingSpeed(); +int OGG_setPlayingSpeed(int playingSpeed); +int OGG_setMute(int onOff); +void OGG_fadeOut(float seconds); + +//Functions for filter (equalizer): +int OGG_setFilter(double tFilter[32], int copyFilter); +void OGG_enableFilter(); +void OGG_disableFilter(); +int OGG_isFilterEnabled(); +int OGG_isFilterSupported(); + +//Manage suspend: +int OGG_suspend(); +int OGG_resume(); + +double OGG_getFilePosition(); +void OGG_setFilePosition(double position); diff --git a/audio/player.c b/audio/player.c index 34e568a..cc73c4c 100644 --- a/audio/player.c +++ b/audio/player.c @@ -17,16 +17,53 @@ */ #include +#include #include #include #include #include "player.h" +#include "mp3player.h" +#include "oggplayer.h" +#include "vita_audio.h" -int MAX_VOLUME_BOOST=15; -int MIN_VOLUME_BOOST=-15; -int MIN_PLAYING_SPEED=-119; -int MAX_PLAYING_SPEED=119; +#include "../file.h" + +int MUTED_VOLUME = 800; +int MAX_VOLUME_BOOST = 15; +int MIN_VOLUME_BOOST = -15; +int MIN_PLAYING_SPEED = -119; +int MAX_PLAYING_SPEED = 119; +int currentVolume = 0; + +void (* initFunct)(int); +int (* isPlayingFunct)(); +int (* loadFunct)(char *); +int (* playFunct)(); +void (* pauseFunct)(); +void (* endFunct)(); +void (* setVolumeBoostTypeFunct)(char*); +void (* setVolumeBoostFunct)(int); +struct fileInfo *(* getInfoFunct)(); +struct fileInfo (* getTagInfoFunct)(); +void (* getTimeStringFunct)(); +float (* getPercentageFunct)(); +int (* getPlayingSpeedFunct)(); +int (* setPlayingSpeedFunct)(int); +int (* endOfStreamFunct)(); + +int (* setMuteFunct)(int); +int (* setFilterFunct)(double[32], int copyFilter); +void (* enableFilterFunct)(); +void (* disableFilterFunct)(); +int (* isFilterEnabledFunct)(); +int (* isFilterSupportedFunct)(); +int (* suspendFunct)(); +int (* resumeFunct)(); +void (* fadeOutFunct)(float seconds); + +double (* getFilePositionFunct)(); +void (* setFilePositionFunct)(double positionInSecs); //Seek next valid frame //NOTE: this function comes from Music prx 0.55 source @@ -86,20 +123,136 @@ int SeekNextFrameMP3(SceUID fd) } } +int setAudioFunctions(int type) { + if (type == FILE_TYPE_OGG) { + //OGG Vorbis + initFunct = OGG_Init; + loadFunct = OGG_Load; + isPlayingFunct = OGG_IsPlaying; + playFunct = OGG_Play; + pauseFunct = OGG_Pause; + endFunct = OGG_End; + setVolumeBoostTypeFunct = OGG_setVolumeBoostType; + setVolumeBoostFunct = OGG_setVolumeBoost; + getInfoFunct = OGG_GetInfo; + getTagInfoFunct = OGG_GetTagInfoOnly; + getTimeStringFunct = OGG_GetTimeString; + getPercentageFunct = OGG_GetPercentage; + getPlayingSpeedFunct = OGG_getPlayingSpeed; + setPlayingSpeedFunct = OGG_setPlayingSpeed; + endOfStreamFunct = OGG_EndOfStream; + + setMuteFunct = OGG_setMute; + setFilterFunct = OGG_setFilter; + enableFilterFunct = OGG_enableFilter; + disableFilterFunct = OGG_disableFilter; + isFilterEnabledFunct = OGG_isFilterEnabled; + isFilterSupportedFunct = OGG_isFilterSupported; + + suspendFunct = OGG_suspend; + resumeFunct = OGG_resume; + fadeOutFunct = OGG_fadeOut; + + getFilePositionFunct = OGG_getFilePosition; + setFilePositionFunct = OGG_setFilePosition; + return 0; + } else if (type == FILE_TYPE_MP3) { + initFunct = MP3_Init; + loadFunct = MP3_Load; + isPlayingFunct = MP3_IsPlaying; + playFunct = MP3_Play; + pauseFunct = MP3_Pause; + endFunct = MP3_End; + setVolumeBoostTypeFunct = MP3_setVolumeBoostType; + setVolumeBoostFunct = MP3_setVolumeBoost; + getInfoFunct = MP3_GetInfo; + getTagInfoFunct = MP3_GetTagInfoOnly; + getTimeStringFunct = MP3_GetTimeString; + getPercentageFunct = MP3_GetPercentage; + getPlayingSpeedFunct = MP3_getPlayingSpeed; + setPlayingSpeedFunct = MP3_setPlayingSpeed; + endOfStreamFunct = MP3_EndOfStream; + + setMuteFunct = MP3_setMute; + setFilterFunct = MP3_setFilter; + enableFilterFunct = MP3_enableFilter; + disableFilterFunct = MP3_disableFilter; + isFilterEnabledFunct = MP3_isFilterEnabled; + isFilterSupportedFunct = MP3_isFilterSupported; + + suspendFunct = MP3_suspend; + resumeFunct = MP3_resume; + fadeOutFunct = MP3_fadeOut; + + getFilePositionFunct = MP3_getFilePosition; + setFilePositionFunct = MP3_setFilePosition; + + return 0; + } + + return -1; +} + +void unsetAudioFunctions() { + initFunct = NULL; + loadFunct = NULL; + playFunct = NULL; + pauseFunct = NULL; + endFunct = NULL; + setVolumeBoostTypeFunct = NULL; + setVolumeBoostFunct = NULL; + getInfoFunct = NULL; + getTagInfoFunct = NULL; + getTimeStringFunct = NULL; + getPercentageFunct = NULL; + getPlayingSpeedFunct = NULL; + setPlayingSpeedFunct = NULL; + endOfStreamFunct = NULL; + + setMuteFunct = NULL; + setFilterFunct = NULL; + enableFilterFunct = NULL; + disableFilterFunct = NULL; + isFilterEnabledFunct = NULL; + isFilterSupportedFunct = NULL; + + suspendFunct = NULL; + resumeFunct = NULL; + + getFilePositionFunct = NULL; + setFilePositionFunct = NULL; +} + short volume_boost(short *Sample, unsigned int *boost) { - return 0; + int intSample = *Sample * (*boost + 1); + if (intSample > 32767) + return 32767; + else if (intSample < -32768) + return -32768; + else + return intSample; } int setVolume(int channel, int volume) { + vitaAudioSetVolume(channel, volume, volume); return 0; } int setMute(int channel, int onOff) { + if (onOff) + setVolume(channel, MUTED_VOLUME); + else + setVolume(channel, VITA_VOLUME_MAX); return 0; } void fadeOut(int channel, float seconds) { - + int i = 0; + long timeToWait = (long)((seconds * 1000.0) / (float)currentVolume); + for (i=currentVolume; i>=0; i--){ + vitaAudioSetVolume(channel, i, i); + sceKernelDelayThread(timeToWait); + } } int initAudioLib() { diff --git a/audio/player.h b/audio/player.h index 225d7b1..7707203 100644 --- a/audio/player.h +++ b/audio/player.h @@ -19,7 +19,9 @@ #ifndef __PLAYER_H__ #define __PLAYER_H__ +#include "id3.h" #include "info.h" +#include "vita_audio.h" #define OPENING_OK 0 #define ERROR_OPENING -1 @@ -29,15 +31,9 @@ #define MP3_TYPE 0 #define OGG_TYPE 1 -#define AT3_TYPE 2 -#define FLAC_TYPE 3 -#define AAC_TYPE 4 -#define WMA_TYPE 5 #define UNK_TYPE -1 -#define FASTFORWARD_VOLUME 0x2200 -#define MAX_IMAGE_DIMENSION 300*1024 -#define DEFAULT_THREAD_STACK_SIZE 256*1024 +#define FASTFORWARD_VOLUME 0 // 0x2200 extern int MAX_VOLUME_BOOST; extern int MIN_VOLUME_BOOST; @@ -56,4 +52,36 @@ int endAudioLib(); void initFileInfo(struct fileInfo *info); +extern void (* initFunct)(int); +extern int (* loadFunct)(char *); +extern int (* isPlayingFunct)(); +extern int (* playFunct)(); +extern void (* pauseFunct)(); +extern void (* endFunct)(); +extern void (* setVolumeBoostTypeFunct)(char*); +extern void (* setVolumeBoostFunct)(int); +extern struct fileInfo *(* getInfoFunct)(); +extern struct fileInfo (* getTagInfoFunct)(); +extern void (* getTimeStringFunct)(); +extern float (* getPercentageFunct)(); +extern int (* getPlayingSpeedFunct)(); +extern int (* setPlayingSpeedFunct)(int); +extern int (* endOfStreamFunct)(); + +extern int (* setMuteFunct)(int); +extern int (* setFilterFunct)(double[32], int copyFilter); +extern void (* enableFilterFunct)(); +extern void (* disableFilterFunct)(); +extern int (* isFilterEnabledFunct)(); +extern int (* isFilterSupportedFunct)(); +extern int (* suspendFunct)(); +extern int (* resumeFunct)(); +extern void (* fadeOutFunct)(float seconds); + +extern double (* getFilePositionFunct)(); //Gets current file position in bytes +extern void (* setFilePositionFunct)(double position); //Set current file position in butes + +extern int setAudioFunctions(int type); +extern void unsetAudioFunctions(); + #endif \ No newline at end of file diff --git a/audio/vita_audio.c b/audio/vita_audio.c index 3546277..44a1c68 100644 --- a/audio/vita_audio.c +++ b/audio/vita_audio.c @@ -6,8 +6,6 @@ #include #include "vita_audio.h" -#define VITA_WAV_MAX_SLOTS 128 - static vitaWav vitaWavInfo[VITA_WAV_MAX_SLOTS]; static int vitaWavPlaying[VITA_WAV_MAX_SLOTS]; static int vitaWavId[VITA_WAV_MAX_SLOTS]; @@ -18,12 +16,6 @@ static int vitaWavIdFlag = 0; static int vitaWavInitFlag = 0; -#define VITA_NUM_AUDIO_CHANNELS 1 // 4 -#define VITA_NUM_AUDIO_SAMPLES 1024 -#define VITA_VOLUME_MAX 0x8000 - -typedef void (* vitaAudioCallback)(void *buf, unsigned int reqn, void *pdata); - typedef struct { int threadHandle; @@ -42,8 +34,13 @@ static vitaAudioChannelInfo vitaAudioStatus[VITA_NUM_AUDIO_CHANNELS]; static volatile int vitaAudioTerminate = 0; +void vitaAudioSetVolume(int channel, int left, int right) { + vitaAudioStatus[channel].volumeLeft = left; + vitaAudioStatus[channel].volumeRight = right; +} + int vitaAudioSetFrequency(int channel, unsigned short freq) { - return 0; + return sceAudioOutSetConfig(vitaAudioStatus[channel].handle, VITA_NUM_AUDIO_SAMPLES, freq, SCE_AUDIO_OUT_MODE_STEREO); } void vitaAudioSetChannelCallback(int channel, vitaAudioCallback callback, void *data) diff --git a/audio/vita_audio.h b/audio/vita_audio.h index e915421..6bf32d3 100644 --- a/audio/vita_audio.h +++ b/audio/vita_audio.h @@ -14,6 +14,14 @@ extern "C" { #endif +#define VITA_WAV_MAX_SLOTS 128 + +#define VITA_NUM_AUDIO_CHANNELS 1 // 4 +#define VITA_NUM_AUDIO_SAMPLES 1024 +#define VITA_VOLUME_MAX 0x8000 + +typedef void (* vitaAudioCallback)(void *buf, unsigned int reqn, void *pdata); + /** @defgroup vitaWav WAV Library * @{ */ @@ -109,6 +117,11 @@ void vitaWavLoop(vitaWav *wav, unsigned int loop); /** @} */ +void vitaAudioSetVolume(int channel, int left, int right); +int vitaAudioSetFrequency(int channel, unsigned short freq); +void vitaAudioSetChannelCallback(int channel, vitaAudioCallback callback, void *data); +int vitaAudioInit(int priority); + #ifdef __cplusplus } #endif // __cplusplus diff --git a/audioplayer.c b/audioplayer.c index afcbef7..02ea562 100644 --- a/audioplayer.c +++ b/audioplayer.c @@ -21,19 +21,18 @@ #include "audioplayer.h" #include "file.h" #include "theme.h" +#include "language.h" #include "utils.h" -#include "audio/id3.h" -#include "audio/info.h" -#include "audio/mp3player.h" +#include "audio/player.h" struct fileInfo *fileinfo = NULL; vita2d_texture *tex = NULL; -void getMp3Info(char *file) { +void getAudioInfo(char *file) { char *buffer = NULL; - fileinfo = MP3_GetInfo(); + fileinfo = getInfoFunct(); if (tex) { vita2d_free_texture(tex); @@ -58,6 +57,9 @@ void getMp3Info(char *file) { if (fileinfo->encapsulatedPictureType == PNG_IMAGE) tex = vita2d_load_PNG_buffer(buffer); + if (tex) + vita2d_texture_set_filters(tex, SCE_GXM_TEXTURE_FILTER_LINEAR, SCE_GXM_TEXTURE_FILTER_LINEAR); + free(buffer); } @@ -68,11 +70,20 @@ void getMp3Info(char *file) { } int audioPlayer(char *file, int type, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos) { - MP3_Init(0); - MP3_Load(file); - MP3_Play(); + static int speed_list[] = { -7, -3, -1, 0, 1, 3, 7 }; + #define N_SPEED (sizeof(speed_list) / sizeof(int)) - getMp3Info(file); + sceAppMgrAcquireBgmPort(); + + powerLock(); + + setAudioFunctions(type); + + initFunct(0); + loadFunct(file); + playFunct(); + + getAudioInfo(file); while (1) { readPad(); @@ -82,8 +93,51 @@ int audioPlayer(char *file, int type, FileList *list, FileListEntry *entry, int break; } + // Display off + if (pressed_buttons & SCE_CTRL_TRIANGLE) { + scePowerRequestDisplayOff(); + } + + // Toggle play/pause + if (pressed_buttons & SCE_CTRL_ENTER) { + if (isPlayingFunct() && getPlayingSpeedFunct() == 0) { + pauseFunct(); + } else { + setPlayingSpeedFunct(0); + playFunct(); + } + } + + if (pressed_buttons & SCE_CTRL_LEFT || pressed_buttons & SCE_CTRL_RIGHT) { + int speed = getPlayingSpeedFunct(); + + if (pressed_buttons & SCE_CTRL_LEFT) { + int i; + for (i = 0; i < N_SPEED; i++) { + if (speed_list[i] == speed) { + if (i > 0) + speed = speed_list[i - 1]; + break; + } + } + } + + if (pressed_buttons & SCE_CTRL_RIGHT) { + int i; + for (i = 0; i < N_SPEED; i++) { + if (speed_list[i] == speed) { + if (i < N_SPEED - 1) + speed = speed_list[i + 1]; + break; + } + } + } + + setPlayingSpeedFunct(speed); + } + // Previous/next song. - if (MP3_EndOfStream() || pressed_buttons & SCE_CTRL_LTRIGGER || pressed_buttons & SCE_CTRL_RTRIGGER) { + if (getPercentageFunct() == 100.0f || endOfStreamFunct() || pressed_buttons & SCE_CTRL_LTRIGGER || pressed_buttons & SCE_CTRL_RTRIGGER) { int available = 0; int old_base_pos = *base_pos; @@ -91,7 +145,11 @@ int audioPlayer(char *file, int type, FileList *list, FileListEntry *entry, int FileListEntry *old_entry = entry; int previous = pressed_buttons & SCE_CTRL_LTRIGGER; - if (MP3_EndOfStream()) + + if (getPercentageFunct() == 100.0f && !endOfStreamFunct()) + previous = 1; + + if (endOfStreamFunct()) previous = 0; while (previous ? entry->previous : entry->next) { @@ -121,12 +179,19 @@ int audioPlayer(char *file, int type, FileList *list, FileListEntry *entry, int char path[MAX_PATH_LENGTH]; snprintf(path, MAX_PATH_LENGTH, "%s%s", list->path, entry->name); int type = getFileType(path); - if (type == FILE_TYPE_MP3) { - MP3_End(); - MP3_Init(0); - MP3_Load(path); - MP3_Play(); - getMp3Info(path); + if (type == FILE_TYPE_MP3 || type == FILE_TYPE_OGG) { + file = path; + + endFunct(); + + setAudioFunctions(type); + + initFunct(0); + loadFunct(file); + playFunct(); + + getAudioInfo(file); + available = 1; break; } @@ -147,25 +212,68 @@ int audioPlayer(char *file, int type, FileList *list, FileListEntry *entry, int // Draw shell info drawShellInfo(file); - pgf_draw_textf(SHELL_MARGIN_X, START_Y + (0 * FONT_Y_SPACE), 0xFFFFFFFF, FONT_SIZE, fileinfo->artist); - pgf_draw_textf(SHELL_MARGIN_X, START_Y + (1 * FONT_Y_SPACE), 0xFFFFFFFF, FONT_SIZE, fileinfo->title); - pgf_draw_textf(SHELL_MARGIN_X, START_Y + (2 * FONT_Y_SPACE), 0xFFFFFFFF, FONT_SIZE, fileinfo->album); + float cover_size = MAX_ENTRIES * FONT_Y_SPACE; - // Picture - if (tex) - vita2d_draw_texture_scale(tex, SHELL_MARGIN_X, 200.0f, 1.0f, 1.0f); + // Cover + if (tex) { + vita2d_draw_texture_scale(tex, SHELL_MARGIN_X, START_Y, cover_size / vita2d_texture_get_width(tex), cover_size / vita2d_texture_get_height(tex)); + } else { + vita2d_draw_texture(cover_image, SHELL_MARGIN_X, START_Y); + } + + float x = 2.0f * SHELL_MARGIN_X + cover_size; + + pgf_draw_text(x, START_Y + (0 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, FONT_SIZE, language_container[TITLE]); + pgf_draw_text(x, START_Y + (1 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, FONT_SIZE, language_container[ALBUM]); + pgf_draw_text(x, START_Y + (2 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, FONT_SIZE, language_container[ARTIST]); + pgf_draw_text(x, START_Y + (3 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, FONT_SIZE, language_container[GENRE]); + pgf_draw_text(x, START_Y + (4 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, FONT_SIZE, language_container[YEAR]); + + pgf_draw_text(x + 120.0f, START_Y + (0 * FONT_Y_SPACE), AUDIO_INFO, FONT_SIZE, fileinfo->title[0] == '\0' ? "-" : fileinfo->title); + pgf_draw_text(x + 120.0f, START_Y + (1 * FONT_Y_SPACE), AUDIO_INFO, FONT_SIZE, fileinfo->album[0] == '\0' ? "-" : fileinfo->album); + pgf_draw_text(x + 120.0f, START_Y + (2 * FONT_Y_SPACE), AUDIO_INFO, FONT_SIZE, fileinfo->artist[0] == '\0' ? "-" : fileinfo->artist); + pgf_draw_text(x + 120.0f, START_Y + (3 * FONT_Y_SPACE), AUDIO_INFO, FONT_SIZE, fileinfo->genre[0] == '\0' ? "-" : fileinfo->genre); + pgf_draw_text(x + 120.0f, START_Y + (4 * FONT_Y_SPACE), AUDIO_INFO, FONT_SIZE, fileinfo->year[0] == '\0' ? "-" : fileinfo->year); + + float y = SCREEN_HEIGHT - 6.0f * SHELL_MARGIN_Y; + + // Icon + vita2d_texture *icon = NULL; + + if (getPlayingSpeedFunct() != 0) { + if (getPlayingSpeedFunct() < 0) { + icon = fastrewind_image; + } else { + icon = fastforward_image; + } + + pgf_draw_textf(x + 45.0f, y, AUDIO_SPEED, FONT_SIZE, "%dx", abs(getPlayingSpeedFunct() + (getPlayingSpeedFunct() < 0 ? -1 : 1))); + } else { + if (isPlayingFunct()) { + icon = play_image; + } else { + icon = pause_image; + } + } + + vita2d_draw_texture(icon, x, y + 3.0f); // Time - char string[12]; - MP3_GetTimeString(string); + char cur_time_string[12]; + getTimeStringFunct(cur_time_string); + + char string[32]; + sprintf(string, "%s / %s", cur_time_string, fileinfo->strLength); + float time_x = ALIGN_LEFT(SCREEN_WIDTH - SHELL_MARGIN_X, vita2d_pgf_text_width(font, FONT_SIZE, string)); + + int w = pgf_draw_text(time_x, y, AUDIO_TIME_CURRENT, FONT_SIZE, cur_time_string); + pgf_draw_text(time_x + (float)w, y, AUDIO_TIME_SLASH, FONT_SIZE, " /"); + pgf_draw_text(ALIGN_LEFT(SCREEN_WIDTH - SHELL_MARGIN_X, vita2d_pgf_text_width(font, FONT_SIZE, fileinfo->strLength)), y, AUDIO_TIME_TOTAL, FONT_SIZE, fileinfo->strLength); + + float width = SCREEN_WIDTH - 3.0f * SHELL_MARGIN_X - cover_size; + vita2d_draw_rectangle(x, (y) + FONT_Y_SPACE + 10.0f, width, 8, AUDIO_TIME_BAR_BG); + vita2d_draw_rectangle(x, (y) + FONT_Y_SPACE + 10.0f, getPercentageFunct() * width / 100.0f, 8, AUDIO_TIME_BAR); - pgf_draw_textf(SHELL_MARGIN_X, SCREEN_HEIGHT - 3.0f * SHELL_MARGIN_Y, PHOTO_ZOOM_COLOR, FONT_SIZE, "%s/%s", string, fileinfo->strLength); -/* - //float percent = MP3_GetPercentage(); - float width = uncommon_dialog.width - 2.0f * SHELL_MARGIN_X; - vita2d_draw_rectangle(uncommon_dialog.x + SHELL_MARGIN_X, string_y + 10.0f, width, UNCOMMON_DIALOG_PROGRESS_BAR_HEIGHT, PROGRESS_BAR_BG_COLOR); - vita2d_draw_rectangle(uncommon_dialog.x + SHELL_MARGIN_X, string_y + 10.0f, uncommon_dialog.progress * width / 100.0f, UNCOMMON_DIALOG_PROGRESS_BAR_HEIGHT, PROGRESS_BAR_COLOR); -*/ // End drawing endDrawing(); } @@ -175,7 +283,11 @@ int audioPlayer(char *file, int type, FileList *list, FileListEntry *entry, int tex = NULL; } - MP3_End(); + endFunct(); + + powerUnlock(); + + sceAppMgrReleaseBgmPort(); return 0; } \ No newline at end of file diff --git a/file.c b/file.c index d2b3949..76ee21f 100644 --- a/file.c +++ b/file.c @@ -538,6 +538,7 @@ static ExtensionType extension_types[] = { { ".JPG", FILE_TYPE_JPEG }, { ".JPEG", FILE_TYPE_JPEG }, { ".MP3", FILE_TYPE_MP3 }, + { ".OGG", FILE_TYPE_OGG }, { ".PNG", FILE_TYPE_PNG }, { ".SFO", FILE_TYPE_SFO }, { ".TXT", FILE_TYPE_TXT }, diff --git a/file.h b/file.h index 0c692aa..fadd9a6 100644 --- a/file.h +++ b/file.h @@ -35,6 +35,7 @@ enum FileTypes { FILE_TYPE_INI, FILE_TYPE_JPEG, FILE_TYPE_MP3, + FILE_TYPE_OGG, FILE_TYPE_PNG, FILE_TYPE_SFO, FILE_TYPE_TXT, diff --git a/init.c b/init.c index 49f179e..7d492bd 100644 --- a/init.c +++ b/init.c @@ -21,59 +21,56 @@ #include "file.h" #include "utils.h" -extern unsigned char _binary_resources_changeinfo_txt_start; -extern unsigned char _binary_resources_changeinfo_txt_size; +INCLUDE_EXTERN_RESOURCE(changeinfo_txt); -extern unsigned char _binary_resources_folder_icon_png_start; -extern unsigned char _binary_resources_folder_icon_png_size; -extern unsigned char _binary_resources_file_icon_png_start; -extern unsigned char _binary_resources_file_icon_png_size; -extern unsigned char _binary_resources_archive_icon_png_start; -extern unsigned char _binary_resources_archive_icon_png_size; -extern unsigned char _binary_resources_image_icon_png_start; -extern unsigned char _binary_resources_image_icon_png_size; -extern unsigned char _binary_resources_audio_icon_png_start; -extern unsigned char _binary_resources_audio_icon_png_size; -extern unsigned char _binary_resources_sfo_icon_png_start; -extern unsigned char _binary_resources_sfo_icon_png_size; -extern unsigned char _binary_resources_text_icon_png_start; -extern unsigned char _binary_resources_text_icon_png_size; -extern unsigned char _binary_resources_ftp_png_start; -extern unsigned char _binary_resources_ftp_png_size; -extern unsigned char _binary_resources_battery_png_start; -extern unsigned char _binary_resources_battery_png_size; -extern unsigned char _binary_resources_battery_bar_red_png_start; -extern unsigned char _binary_resources_battery_bar_red_png_size; -extern unsigned char _binary_resources_battery_bar_green_png_start; -extern unsigned char _binary_resources_battery_bar_green_png_size; -extern unsigned char _binary_resources_battery_bar_charge_png_start; -extern unsigned char _binary_resources_battery_bar_charge_png_size; - -extern unsigned char _binary_resources_theme_txt_start; -extern unsigned char _binary_resources_theme_txt_size; +INCLUDE_EXTERN_RESOURCE(folder_icon_png); +INCLUDE_EXTERN_RESOURCE(file_icon_png); +INCLUDE_EXTERN_RESOURCE(archive_icon_png); +INCLUDE_EXTERN_RESOURCE(image_icon_png); +INCLUDE_EXTERN_RESOURCE(audio_icon_png); +INCLUDE_EXTERN_RESOURCE(sfo_icon_png); +INCLUDE_EXTERN_RESOURCE(text_icon_png); +INCLUDE_EXTERN_RESOURCE(ftp_png); +INCLUDE_EXTERN_RESOURCE(battery_png); +INCLUDE_EXTERN_RESOURCE(battery_bar_red_png); +INCLUDE_EXTERN_RESOURCE(battery_bar_green_png); +INCLUDE_EXTERN_RESOURCE(battery_bar_charge_png); -extern unsigned char _binary_resources_colors_txt_start; -extern unsigned char _binary_resources_colors_txt_size; +INCLUDE_EXTERN_RESOURCE(cover_png); +INCLUDE_EXTERN_RESOURCE(play_png); +INCLUDE_EXTERN_RESOURCE(pause_png); +INCLUDE_EXTERN_RESOURCE(fastforward_png); +INCLUDE_EXTERN_RESOURCE(fastrewind_png); -extern unsigned char _binary_resources_english_us_txt_start; -extern unsigned char _binary_resources_english_us_txt_size; +INCLUDE_EXTERN_RESOURCE(theme_txt); +INCLUDE_EXTERN_RESOURCE(colors_txt); +INCLUDE_EXTERN_RESOURCE(english_us_txt); + +#define DEFAULT_FILE(pah, name) { "ux0:VitaShell/language/english_us.txt", (void *)&_binary_resources_##name##_start, (int)&_binary_resources_##name##_size } static DefaultFile default_files[] = { - { "ux0:VitaShell/language/english_us.txt", (void *)&_binary_resources_english_us_txt_start, (int)&_binary_resources_english_us_txt_size }, - { "ux0:VitaShell/theme/theme.txt", (void *)&_binary_resources_theme_txt_start, (int)&_binary_resources_theme_txt_size }, - { "ux0:VitaShell/theme/Default/colors.txt", (void *)&_binary_resources_colors_txt_start, (int)&_binary_resources_colors_txt_size }, - { "ux0:VitaShell/theme/Default/folder_icon.png", (void *)&_binary_resources_folder_icon_png_start, (int)&_binary_resources_folder_icon_png_size }, - { "ux0:VitaShell/theme/Default/file_icon.png", (void *)&_binary_resources_file_icon_png_start, (int)&_binary_resources_file_icon_png_size }, - { "ux0:VitaShell/theme/Default/archive_icon.png", (void *)&_binary_resources_archive_icon_png_start, (int)&_binary_resources_archive_icon_png_size }, - { "ux0:VitaShell/theme/Default/image_icon.png", (void *)&_binary_resources_image_icon_png_start, (int)&_binary_resources_image_icon_png_size }, - { "ux0:VitaShell/theme/Default/audio_icon.png", (void *)&_binary_resources_audio_icon_png_start, (int)&_binary_resources_audio_icon_png_size }, - { "ux0:VitaShell/theme/Default/sfo_icon.png", (void *)&_binary_resources_sfo_icon_png_start, (int)&_binary_resources_sfo_icon_png_size }, - { "ux0:VitaShell/theme/Default/text_icon.png", (void *)&_binary_resources_text_icon_png_start, (int)&_binary_resources_text_icon_png_size }, - { "ux0:VitaShell/theme/Default/ftp.png", (void *)&_binary_resources_ftp_png_start, (int)&_binary_resources_ftp_png_size }, - { "ux0:VitaShell/theme/Default/battery.png", (void *)&_binary_resources_battery_png_start, (int)&_binary_resources_battery_png_size }, - { "ux0:VitaShell/theme/Default/battery_bar_red.png", (void *)&_binary_resources_battery_bar_red_png_start, (int)&_binary_resources_battery_bar_red_png_size }, - { "ux0:VitaShell/theme/Default/battery_bar_green.png", (void *)&_binary_resources_battery_bar_green_png_start, (int)&_binary_resources_battery_bar_green_png_size }, - { "ux0:VitaShell/theme/Default/battery_bar_charge.png", (void *)&_binary_resources_battery_bar_charge_png_start, (int)&_binary_resources_battery_bar_charge_png_size }, + DEFAULT_FILE("ux0:VitaShell/language/english_us.txt", english_us_txt), + + DEFAULT_FILE("ux0:VitaShell/theme/theme.txt", theme_txt), + DEFAULT_FILE("ux0:VitaShell/theme/Default/colors.txt", colors_txt), + DEFAULT_FILE("ux0:VitaShell/theme/Default/folder_icon.png", folder_icon_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/file_icon.png", file_icon_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/archive_icon.png", archive_icon_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/image_icon.png", image_icon_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/audio_icon.png", audio_icon_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/sfo_icon.png", sfo_icon_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/text_icon.png", text_icon_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/ftp.png", ftp_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/battery.png", battery_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/battery_bar_red.png", battery_bar_red_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/battery_bar_green.png", battery_bar_green_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/battery_bar_charge.png", battery_bar_charge_png), + + DEFAULT_FILE("ux0:VitaShell/theme/Default/cover.png", cover_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/play.png", play_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/pause.png", pause_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/fastforward.png", fastforward_png), + DEFAULT_FILE("ux0:VitaShell/theme/Default/fastrewind.png", fastrewind_png), }; vita2d_pgf *font = NULL; diff --git a/language.c b/language.c index c793c47..e7e93b9 100644 --- a/language.c +++ b/language.c @@ -20,8 +20,7 @@ #include "config.h" #include "language.h" -extern unsigned char _binary_resources_english_us_txt_start; -extern unsigned char _binary_resources_english_us_txt_size; +INCLUDE_EXTERN_RESOURCE(english_us_txt); static char *lang[] ={ "japanese", @@ -80,6 +79,13 @@ void loadLanguage(int id) { LANGUAGE_ENTRY(EXTRACTING), LANGUAGE_ENTRY(HASHING), + // Audio player strings + LANGUAGE_ENTRY(TITLE), + LANGUAGE_ENTRY(ALBUM), + LANGUAGE_ENTRY(ARTIST), + LANGUAGE_ENTRY(GENRE), + LANGUAGE_ENTRY(YEAR), + // Hex editor strings LANGUAGE_ENTRY(CUT), LANGUAGE_ENTRY(OPEN_HEX_EDITOR), diff --git a/language.h b/language.h index 729408f..ec78f8f 100644 --- a/language.h +++ b/language.h @@ -37,6 +37,13 @@ enum LanguageContainer { EXTRACTING, HASHING, + // Audio player strings + TITLE, + ALBUM, + ARTIST, + GENRE, + YEAR, + // Hex editor strings OFFSET, OPEN_HEX_EDITOR, diff --git a/libmad/mad.h b/libmad/mad.h index 9ef6cc8..34423ca 100644 --- a/libmad/mad.h +++ b/libmad/mad.h @@ -24,7 +24,7 @@ extern "C" { # endif -# define FPM_INTEL +# define FPM_DEFAULT diff --git a/main.c b/main.c index 7f8f64d..b24ae7b 100644 --- a/main.c +++ b/main.c @@ -46,6 +46,8 @@ #include "utils.h" #include "sfo.h" +#include "audio/vita_audio.h" + int _newlib_heap_size_user = 64 * 1024 * 1024; #define MAX_DIR_LEVELS 1024 @@ -260,6 +262,8 @@ int handleFile(char *file, FileListEntry *entry) { int type = getFileType(file); switch (type) { + case FILE_TYPE_MP3: + case FILE_TYPE_OGG: case FILE_TYPE_VPK: case FILE_TYPE_ZIP: if (isInArchive()) @@ -283,6 +287,7 @@ int handleFile(char *file, FileListEntry *entry) { break; case FILE_TYPE_MP3: + case FILE_TYPE_OGG: res = audioPlayer(file, type, &file_list, entry, &base_pos, &rel_pos); break; @@ -1404,6 +1409,7 @@ int shellMain() { break; case FILE_TYPE_MP3: + case FILE_TYPE_OGG: color = IMAGE_COLOR; icon = audio_icon; break; @@ -1568,7 +1574,7 @@ int main(int argc, const char *argv[]) { initTextContextMenuWidth(); // Automatic network update - SceUID thid = sceKernelCreateThread("network_update_thread", (SceKernelThreadEntry)network_update_thread, 0x40, 0x10000, 0, 0, NULL); + SceUID thid = sceKernelCreateThread("network_update_thread", (SceKernelThreadEntry)network_update_thread, 0x10000100, 0x10000, 0, 0, NULL); if (thid >= 0) sceKernelStartThread(thid, 0, NULL); diff --git a/main.h b/main.h index a0a525a..335a60a 100644 --- a/main.h +++ b/main.h @@ -61,6 +61,8 @@ #include "functions.h" +#define INCLUDE_EXTERN_RESOURCE(name) extern unsigned char _binary_resources_##name##_start; extern unsigned char _binary_resources_##name##_size; \ + #define ENABLE_FILE_LOGGING 1 // VitaShell version major.minor diff --git a/network_update.c b/network_update.c index 47c086a..f802526 100644 --- a/network_update.c +++ b/network_update.c @@ -199,7 +199,7 @@ int network_update_thread(SceSize args, void *argp) { // Wait for response while (dialog_step == DIALOG_STEP_UPDATE_QUESTION) { - sceKernelDelayThread(1000); + sceKernelDelayThread(10 * 1000); } // No diff --git a/package_installer.c b/package_installer.c index 8ca8dc6..5ff2d9e 100644 --- a/package_installer.c +++ b/package_installer.c @@ -366,7 +366,7 @@ int install_thread(SceSize args_size, InstallArguments *args) { // Wait for response while (dialog_step == DIALOG_STEP_INSTALL_WARNING) { - sceKernelDelayThread(1000); + sceKernelDelayThread(10 * 1000); } // Cancelled diff --git a/resources/colors.txt b/resources/colors.txt index 9e1fdc5..5bdb24d 100644 --- a/resources/colors.txt +++ b/resources/colors.txt @@ -44,4 +44,14 @@ TEXT_LINE_NUMBER_COLOR_FOCUS = 0xFF7F7F7F # Gray TEXT_HIGHLIGHT_COLOR = 0xFF80F5FF # Yellow # Photo viewer colors -PHOTO_ZOOM_COLOR = 0xFFFFFFFF # White \ No newline at end of file +PHOTO_ZOOM_COLOR = 0xFFFFFFFF # White + +# Audio player colors +AUDIO_INFO_ASSIGN = 0xFFFFFF00 # Cyan +AUDIO_INFO = 0xFFFFFFFF # White +AUDIO_SPEED = 0xFFFFFFFF # White +AUDIO_TIME_CURRENT = 0xFF00FF00 # Green +AUDIO_TIME_SLASH = 0xFFFFFFFF # White +AUDIO_TIME_TOTAL = 0xFFFFFFFF # White +AUDIO_TIME_BAR = 0xFFFF7F00 # Azure +AUDIO_TIME_BAR_BG = 0xFF7F7F7F # Gray \ No newline at end of file diff --git a/resources/cover.png b/resources/cover.png new file mode 100644 index 0000000000000000000000000000000000000000..5aba2c4795b59c56fdc5f3259222870515b7dd77 GIT binary patch literal 73961 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 z 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 E5?;vk;`1 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 TNZZG900000NkvXXu0mjf;sBmX literal 0 HcmV?d00001 diff --git a/resources/fastrewind.png b/resources/fastrewind.png new file mode 100644 index 0000000000000000000000000000000000000000..7465bfd5fe6c251521be79a41e2ab4a2a730e5a6 GIT binary patch literal 393 zcmV;40e1e0P)N2bZe?^J zG%heMF)*zP3cvsW0R~A#K~zXft=2mV0x=MP;XR^<@rr6;VYeVQVqs&UwXnvSV3si? znWqpClz%^xO~{l|nu5j_I)|VZnsP4!w}H?Z#s>y|yv@I!Cx)RJ#skLlhw}iNJqwVA zt_1cr&fu`80ro=0_)-EzJqeHtX@RQV2q+Cnfu>#ys10#ISC0a%p&l@#hd>OSU|eAA z$*$CXEt@2?M}dgkX;tL^H87;tTH-rA^k#t8$4psbS8udQwBg=4XocpUK_jnQ2wi&~AYCfFurA8mOz+wF nDy_W;U}@kL{peg3>dCz?@f72A-9NNE00000NkvXXu0mjfH~^U} literal 0 HcmV?d00001 diff --git a/resources/pause.png b/resources/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..ac945a01d88e48443486c00d72186b57c1bc1bb3 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VOS+@4BLl<6e(pbstUx|zfk$L9 z0|Vbd5N6ylG5al0P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM&(L5k7uNxxA_Gqs z#}Etu< Tk!67nP%ne0tDnm{r-UW|F#$7H literal 0 HcmV?d00001 diff --git a/resources/play.png b/resources/play.png new file mode 100644 index 0000000000000000000000000000000000000000..8bb70237378c2a71c70dd45f436347cde397676e GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VOS+@4BLl<6e(pbstUx|zfk$L9 z0|Vbd5N6ylG5al0P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM&(L5k7uNxxq6MBV zjv*HQYp-tPYETehdmy*5{iW#Yg$s2%re$PguCUbj&2PiO{qdbhUCBph3tR5zG2I~^ z6O~&o?3gI1xmKgO<=u%k9?V_O#U6*aRSzUqGzB{d>M%}D;FW0ARXEHm zCVc5~>1oDma>mWv3ruS`W(ogu`jeuXATp`JGk{B@$?3ygnUDaEqTjzld~eC`)DSmI h%ibWnAt(L-^923E-NlvHwgKJB;OXk;vd$@?2>{F8WF!Cp literal 0 HcmV?d00001 diff --git a/resources/stop.png b/resources/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..394dfddbe0fe5bc98b1df8b17e8fc6c82036e38c GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1SFYWcSQjymUKs7M+SzC{oH>NS%G}c0*}aI z1_r)^Ak4U9V)k30pk#?_L`iUdT1k0gQ7S`0VrE{6US4X6f{C7io}s~7F0KPWMGBrS zjv*HQ$v^xV6BanU{~vf(rR`ouLob`eK>>-*P8Nm-E~|Ur@UY4Q)iQXx`njxgN@xNA DR3j}F literal 0 HcmV?d00001 diff --git a/theme.c b/theme.c index 2c6ef26..6e0cb41 100644 --- a/theme.c +++ b/theme.c @@ -22,21 +22,27 @@ #include "theme.h" #include "utils.h" -extern unsigned char _binary_resources_folder_icon_png_start; -extern unsigned char _binary_resources_file_icon_png_start; -extern unsigned char _binary_resources_archive_icon_png_start; -extern unsigned char _binary_resources_image_icon_png_start; -extern unsigned char _binary_resources_audio_icon_png_start; -extern unsigned char _binary_resources_sfo_icon_png_start; -extern unsigned char _binary_resources_text_icon_png_start; -extern unsigned char _binary_resources_ftp_png_start; -extern unsigned char _binary_resources_battery_png_start; -extern unsigned char _binary_resources_battery_bar_red_png_start; -extern unsigned char _binary_resources_battery_bar_green_png_start; -extern unsigned char _binary_resources_battery_bar_charge_png_start; +INCLUDE_EXTERN_RESOURCE(colors_txt); +INCLUDE_EXTERN_RESOURCE(colors_txt_size); -extern unsigned char _binary_resources_colors_txt_start; -extern unsigned char _binary_resources_colors_txt_size; +INCLUDE_EXTERN_RESOURCE(folder_icon_png); +INCLUDE_EXTERN_RESOURCE(file_icon_png); +INCLUDE_EXTERN_RESOURCE(archive_icon_png); +INCLUDE_EXTERN_RESOURCE(image_icon_png); +INCLUDE_EXTERN_RESOURCE(audio_icon_png); +INCLUDE_EXTERN_RESOURCE(sfo_icon_png); +INCLUDE_EXTERN_RESOURCE(text_icon_png); +INCLUDE_EXTERN_RESOURCE(ftp_png); +INCLUDE_EXTERN_RESOURCE(battery_png); +INCLUDE_EXTERN_RESOURCE(battery_bar_red_png); +INCLUDE_EXTERN_RESOURCE(battery_bar_green_png); +INCLUDE_EXTERN_RESOURCE(battery_bar_charge_png); + +INCLUDE_EXTERN_RESOURCE(cover_png); +INCLUDE_EXTERN_RESOURCE(play_png); +INCLUDE_EXTERN_RESOURCE(pause_png); +INCLUDE_EXTERN_RESOURCE(fastforward_png); +INCLUDE_EXTERN_RESOURCE(fastrewind_png); // Shell colors int BACKGROUND_COLOR; @@ -84,10 +90,20 @@ int TEXT_HIGHLIGHT_COLOR; // Photo viewer colors int PHOTO_ZOOM_COLOR; +// Audio player colors +int AUDIO_INFO_ASSIGN; +int AUDIO_INFO; +int AUDIO_SPEED; +int AUDIO_TIME_CURRENT; +int AUDIO_TIME_SLASH; +int AUDIO_TIME_TOTAL; +int AUDIO_TIME_BAR; +int AUDIO_TIME_BAR_BG; + vita2d_texture *folder_icon = NULL, *file_icon = NULL, *archive_icon = NULL, *image_icon = NULL, *audio_icon = NULL, *sfo_icon = NULL, *text_icon = NULL, *ftp_image = NULL, *dialog_image = NULL, *context_image = NULL, *context_more_image = NULL, *battery_image = NULL, *battery_bar_red_image = NULL, *battery_bar_green_image = NULL, *battery_bar_charge_image = NULL, *bg_browser_image = NULL, *bg_hex_image = NULL, - *bg_text_image = NULL, *bg_photo_image = NULL; + *bg_text_image = NULL, *bg_photo_image = NULL, *cover_image = NULL, *play_image = NULL, *pause_image = NULL, *fastforward_image = NULL, *fastrewind_image = NULL; vita2d_texture *wallpaper_image[MAX_WALLPAPERS]; @@ -143,6 +159,16 @@ void loadTheme() { // Photo viewer colors COLOR_ENTRY(PHOTO_ZOOM_COLOR), + + // Audio player colors + COLOR_ENTRY(AUDIO_INFO_ASSIGN), + COLOR_ENTRY(AUDIO_INFO), + COLOR_ENTRY(AUDIO_SPEED), + COLOR_ENTRY(AUDIO_TIME_CURRENT), + COLOR_ENTRY(AUDIO_TIME_SLASH), + COLOR_ENTRY(AUDIO_TIME_TOTAL), + COLOR_ENTRY(AUDIO_TIME_BAR), + COLOR_ENTRY(AUDIO_TIME_BAR_BG), }; // Load default config file @@ -223,6 +249,21 @@ void loadTheme() { snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/bg_photoviewer.png", theme_name); bg_photo_image = vita2d_load_PNG_file(path); + snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/cover.png", theme_name); + cover_image = vita2d_load_PNG_file(path); + + snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/play.png", theme_name); + play_image = vita2d_load_PNG_file(path); + + snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/pause.png", theme_name); + pause_image = vita2d_load_PNG_file(path); + + snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/fastforward.png", theme_name); + fastforward_image = vita2d_load_PNG_file(path); + + snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/fastrewind.png", theme_name); + fastrewind_image = vita2d_load_PNG_file(path); + // Wallpapers snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/wallpaper.png", theme_name); vita2d_texture *image = vita2d_load_PNG_file(path); @@ -320,4 +361,19 @@ void loadTheme() { if (!battery_bar_charge_image) battery_bar_charge_image = vita2d_load_PNG_buffer(&_binary_resources_battery_bar_charge_png_start); + + if (!cover_image) + cover_image = vita2d_load_PNG_buffer(&_binary_resources_cover_png_start); + + if (!play_image) + play_image = vita2d_load_PNG_buffer(&_binary_resources_play_png_start); + + if (!pause_image) + pause_image = vita2d_load_PNG_buffer(&_binary_resources_pause_png_start); + + if (!fastforward_image) + fastforward_image = vita2d_load_PNG_buffer(&_binary_resources_fastforward_png_start); + + if (!fastrewind_image) + fastrewind_image = vita2d_load_PNG_buffer(&_binary_resources_fastrewind_png_start); } \ No newline at end of file diff --git a/theme.h b/theme.h index ebb678d..47c8501 100644 --- a/theme.h +++ b/theme.h @@ -67,9 +67,20 @@ extern int TEXT_HIGHLIGHT_COLOR; // Photo viewer colors extern int PHOTO_ZOOM_COLOR; +// Audio player colors +extern int AUDIO_INFO_ASSIGN; +extern int AUDIO_INFO; +extern int AUDIO_SPEED; +extern int AUDIO_TIME_CURRENT; +extern int AUDIO_TIME_SLASH; +extern int AUDIO_TIME_TOTAL; +extern int AUDIO_TIME_BAR; +extern int AUDIO_TIME_BAR_BG; + extern vita2d_texture *folder_icon, *file_icon, *archive_icon, *image_icon, *audio_icon, *sfo_icon, *text_icon, - *ftp_image, *dialog_image, *context_image, *context_more_image, *battery_image, *battery_bar_red_image, *battery_bar_green_image, - *battery_bar_charge_image, *bg_browser_image, *bg_hex_image, *bg_text_image, *bg_photo_image; + *ftp_image, *dialog_image, *context_image, *context_more_image, *battery_image, *battery_bar_red_image, + *battery_bar_green_image, *battery_bar_charge_image, *bg_browser_image, *bg_hex_image, *bg_text_image, + *bg_photo_image, *cover_image, *play_image, *pause_image, *fastforward_image, *fastrewind_image; extern vita2d_texture *wallpaper_image[MAX_WALLPAPERS]; extern vita2d_texture *previous_wallpaper_image, *current_wallpaper_image;