mirror of
https://github.com/joel16/VitaShell.git
synced 2025-02-25 14:53:15 +00:00
Merge remote-tracking branch 'refs/remotes/TheOfficialFloW/master'
This commit is contained in:
commit
98ff051bfc
14
Makefile
14
Makefile
@ -1,15 +1,17 @@
|
||||
TITLE_ID = VITASHELL
|
||||
TARGET = VitaShell
|
||||
OBJS = main.o init.o io_process.o package_installer.o network_update.o archive.o photo.o file.o text.o hex.o sfo.o \
|
||||
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 \
|
||||
audioplayer.o minizip/unzip.o minizip/ioapi.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 \
|
||||
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/headphone.png resources/audio_previous.png resources/audio_pause.png \
|
||||
resources/audio_play.png resources/audio_next.png
|
||||
RESOURCES_TXT = resources/theme.txt resources/colors.txt resources/english_us.txt
|
||||
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
|
||||
OBJS += $(RESOURCES_PNG:.png=.o) $(RESOURCES_TXT:.txt=.o) $(RESOURCES_BIN:.bin=.o)
|
||||
|
||||
@ -39,7 +41,7 @@ ASFLAGS = $(CFLAGS)
|
||||
all: $(TARGET).vpk
|
||||
|
||||
%.vpk: eboot.bin
|
||||
vita-mksfoex -d PARENTAL_LEVEL=1 -s APP_VER=00.91 -s TITLE_ID=$(TITLE_ID) "$(TARGET)" param.sfo
|
||||
vita-mksfoex -d PARENTAL_LEVEL=1 -s APP_VER=00.95 -s TITLE_ID=$(TITLE_ID) "$(TARGET)" param.sfo
|
||||
vita-pack-vpk -s param.sfo -b eboot.bin \
|
||||
--add pkg/sce_sys/icon0.png=sce_sys/icon0.png \
|
||||
--add pkg/sce_sys/livearea/contents/bg.png=sce_sys/livearea/contents/bg.png \
|
||||
|
12
README.md
12
README.md
@ -15,6 +15,7 @@ You can customize those files:
|
||||
- **'ux0:VitaShell/theme/YOUR_THEME_NAME/wallpaperX.png'**: Wallpaper #X (X is a value from 2-10)
|
||||
- **'ux0:VitaShell/theme/YOUR_THEME_NAME/dialog.png'**: Dialog menu image (Can be any size. This image file will be stretched by VitaShell to fit the dialog box. Suggestion: Don't use motives, as it will not look good with wrong proportion).
|
||||
- **'ux0:VitaShell/theme/YOUR_THEME_NAME/context.png'**: Context menu image (Can be any size. Suggestion: It will look great if you add alpha channel to your image).
|
||||
- **'ux0:VitaShell/theme/YOUR_THEME_NAME/context_more.png'**: Context menu more image (Can be any size. Suggestion: It will look great if you add alpha channel to your image).
|
||||
- **'ux0:VitaShell/theme/YOUR_THEME_NAME/battery.png'**: Battery border icon
|
||||
- **'ux0:VitaShell/theme/YOUR_THEME_NAME/battery_bar_green.png'**: Green battery bar
|
||||
- **'ux0:VitaShell/theme/YOUR_THEME_NAME/battery_bar_red.png'**: Red battery bar
|
||||
@ -74,6 +75,17 @@ https://github.com/xy2iii/vitashell-themes
|
||||
|
||||
Be sure you pull request your customized design or language file there.
|
||||
|
||||
### Changelog 0.95 ###
|
||||
- Added ability to install update files as .vpk (for Vitamin).
|
||||
- Added patch to make .vpk installation appearing as full version instead of test version.
|
||||
- Added text editor by BigBoot (WIP).
|
||||
- Added 'More' entry to the context menu.
|
||||
- Added 'Install all' feature to install all packages available in the folder (by ribbid987).
|
||||
- Added 'Calculate SHA1' feature by xerpia64.
|
||||
- Added support for ftp promoting for https://github.com/soywiz/vitaorganizer.
|
||||
- Fixed 'Move' operation. Now it does integrate into folders and replace files.
|
||||
- Dropped GENERAL_COLOR, now all colors are adjustable.
|
||||
|
||||
### Changelog 0.91 ###
|
||||
- Added automatic network update. VitaShell will now notify you when there's a new update.
|
||||
You'll then be able to download it within the VitaShell application and it will update both
|
||||
|
48
archive.c
48
archive.c
@ -47,7 +47,7 @@ int fileListGetArchiveEntries(FileList *list, char *path) {
|
||||
|
||||
int i;
|
||||
for (i = 0; i < archive_list.length; i++) {
|
||||
if (archive_entry->name_length >= name_length && strncmp(archive_entry->name, archive_path, name_length) == 0) { // Needs a / at end
|
||||
if (archive_entry->name_length >= name_length && strncasecmp(archive_entry->name, archive_path, name_length) == 0) { // Needs a / at end
|
||||
char *p = strchr(archive_entry->name + name_length, '/'); // it's a sub-directory if it has got a slash
|
||||
|
||||
if (p)
|
||||
@ -134,7 +134,7 @@ int getArchivePathInfo(char *path, uint64_t *size, uint32_t *folders, uint32_t *
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extractArchivePath(char *src, char *dst, uint64_t *value, uint64_t max, void (* SetProgress)(uint64_t value, uint64_t max), int (* cancelHandler)()) {
|
||||
int extractArchivePath(char *src, char *dst, FileProcessParam *param) {
|
||||
if (!uf)
|
||||
return -1;
|
||||
|
||||
@ -151,15 +151,17 @@ int extractArchivePath(char *src, char *dst, uint64_t *value, uint64_t max, void
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (value)
|
||||
(*value)++;
|
||||
if (param) {
|
||||
if (param->value)
|
||||
(*param->value)++;
|
||||
|
||||
if (SetProgress)
|
||||
SetProgress(value ? *value : 0, max);
|
||||
|
||||
if (cancelHandler && cancelHandler()) {
|
||||
fileListEmpty(&list);
|
||||
return 0;
|
||||
if (param->SetProgress)
|
||||
param->SetProgress(param->value ? *param->value : 0, param->max);
|
||||
|
||||
if (param->cancelHandler && param->cancelHandler()) {
|
||||
fileListEmpty(&list);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
FileListEntry *entry = list.head->next; // Ignore ..
|
||||
@ -172,7 +174,7 @@ int extractArchivePath(char *src, char *dst, uint64_t *value, uint64_t max, void
|
||||
char *dst_path = malloc(strlen(dst) + strlen(entry->name) + 2);
|
||||
snprintf(dst_path, MAX_PATH_LENGTH, "%s%s", dst, entry->name);
|
||||
|
||||
int ret = extractArchivePath(src_path, dst_path, value, max, SetProgress, cancelHandler);
|
||||
int ret = extractArchivePath(src_path, dst_path, param);
|
||||
|
||||
free(dst_path);
|
||||
free(src_path);
|
||||
@ -211,19 +213,21 @@ int extractArchivePath(char *src, char *dst, uint64_t *value, uint64_t max, void
|
||||
return res;
|
||||
}
|
||||
|
||||
if (value)
|
||||
(*value) += read;
|
||||
if (param) {
|
||||
if (param->value)
|
||||
(*param->value) += read;
|
||||
|
||||
if (SetProgress)
|
||||
SetProgress(value ? *value : 0, max);
|
||||
if (param->SetProgress)
|
||||
param->SetProgress(param->value ? *param->value : 0, param->max);
|
||||
|
||||
if (cancelHandler && cancelHandler()) {
|
||||
free(buf);
|
||||
if (param->cancelHandler && param->cancelHandler()) {
|
||||
free(buf);
|
||||
|
||||
sceIoClose(fddst);
|
||||
archiveFileClose(fdsrc);
|
||||
sceIoClose(fddst);
|
||||
archiveFileClose(fdsrc);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,7 +255,7 @@ int archiveFileGetstat(const char *file, SceIoStat *stat) {
|
||||
|
||||
int i;
|
||||
for (i = 0; i < archive_list.length; i++) {
|
||||
if (archive_entry->name_length == name_length && strcmp(archive_entry->name, archive_path) == 0) {
|
||||
if (archive_entry->name_length == name_length && strcasecmp(archive_entry->name, archive_path) == 0) {
|
||||
if (stat) {
|
||||
//stat->st_mode =
|
||||
//stat->st_attr =
|
||||
@ -284,7 +288,7 @@ int archiveFileOpen(const char *file, int flags, SceMode mode) {
|
||||
|
||||
int i;
|
||||
for (i = 0; i < archive_list.length; i++) {
|
||||
if (archive_entry->name_length == name_length && strcmp(archive_entry->name, archive_path) == 0) {
|
||||
if (archive_entry->name_length == name_length && strcasecmp(archive_entry->name, archive_path) == 0) {
|
||||
// Set pos
|
||||
unzGoToFilePos64(uf, (unz64_file_pos *)&archive_entry->reserved);
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
int fileListGetArchiveEntries(FileList *list, char *path);
|
||||
|
||||
int getArchivePathInfo(char *path, uint64_t *size, uint32_t *folders, uint32_t *files);
|
||||
int extractArchivePath(char *src, char *dst, uint64_t *value, uint64_t max, void (* SetProgress)(uint64_t value, uint64_t max), int (* cancelHandler)());
|
||||
int extractArchivePath(char *src, char *dst, FileProcessParam *param);
|
||||
|
||||
int archiveFileGetstat(const char *file, SceIoStat *stat);
|
||||
int archiveFileOpen(const char *file, int flags, SceMode mode);
|
||||
|
655
audio/id3.c
Normal file
655
audio/id3.c
Normal file
@ -0,0 +1,655 @@
|
||||
#include <psp2/io/fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "id3.h"
|
||||
struct genre
|
||||
{
|
||||
int code;
|
||||
char text[112];
|
||||
};
|
||||
|
||||
struct genre genreList[] =
|
||||
{
|
||||
{0 , "Blues"}, {1 , "Classic Rock"}, {2 , "Country"}, {3 , "Dance"}, {4 , "Disco"}, {5 , "Funk"}, {6 , "Grunge"}, {7 , "Hip-Hop"}, {8 , "Jazz"}, {9 , "Metal"}, {10 , "New Age"},
|
||||
{11 , "Oldies"}, {12 , "Other"}, {13 , "Pop"}, {14 , "R&B"}, {15 , "Rap"}, {16 , "Reggae"}, {17 , "Rock"}, {18 , "Techno"}, {19 , "Industrial"}, {20 , "Alternative"},
|
||||
{21 , "Ska"}, {22 , "Death Metal"}, {23 , "Pranks"}, {24 , "Soundtrack"}, {25 , "Euro-Techno"}, {26 , "Ambient"}, {27 , "Trip-Hop"}, {28 , "Vocal"}, {29 , "Jazz+Funk"}, {30 , "Fusion"},
|
||||
{31 , "Trance"}, {32 , "Classical"}, {33 , "Instrumental"}, {34 , "Acid"}, {35 , "House"}, {36 , "Game"}, {37 , "Sound Clip"}, {38 , "Gospel"}, {39 , "Noise"}, {40 , "Alternative Rock"},
|
||||
{41 , "Bass"}, {42 , "Soul"}, {43 , "Punk"}, {44 , "Space"}, {45 , "Meditative"}, {46 , "Instrumental Pop"}, {47 , "Instrumental Rock"}, {48 , "Ethnic"}, {49 , "Gothic"}, {50 , "Darkwave"},
|
||||
{51 , "Techno-Industrial"}, {52 , "Electronic"}, {53 , "Pop-Folk"}, {54 , "Eurodance"}, {55 , "Dream"}, {56 , "Southern Rock"}, {57 , "Comedy"}, {58 , "Cult"}, {59 , "Gangsta"}, {60 , "Top 40"},
|
||||
{61 , "Christian Rap"}, {62 , "Pop/Funk"}, {63 , "Jungle"}, {64 , "Native US"}, {65 , "Cabaret"}, {66 , "New Wave"}, {67 , "Psychadelic"}, {68 , "Rave"}, {69 , "Showtunes"}, {70 , "Trailer"},
|
||||
{71 , "Lo-Fi"}, {72 , "Tribal"}, {73 , "Acid Punk"}, {74 , "Acid Jazz"}, {75 , "Polka"}, {76 , "Retro"}, {77 , "Musical"}, {78 , "Rock & Roll"}, {79 , "Hard Rock"}, {80 , "Folk"},
|
||||
{81 , "Folk-Rock"}, {82 , "National Folk"}, {83 , "Swing"}, {84 , "Fast Fusion"}, {85 , "Bebob"}, {86 , "Latin"}, {87 , "Revival"}, {88 , "Celtic"}, {89 , "Bluegrass"}, {90 , "Avantgarde"},
|
||||
{91 , "Gothic Rock"}, {92 , "Progressive Rock"}, {93 , "Psychedelic Rock"}, {94 , "Symphonic Rock"}, {95 , "Slow Rock"}, {96 , "Big Band"}, {97 , "Chorus"}, {98 , "Easy Listening"}, {99 , "Acoustic"},
|
||||
{100 , "Humour"}, {101 , "Speech"}, {102 , "Chanson"}, {103 , "Opera"}, {104 , "Chamber Music"}, {105 , "Sonata"}, {106 , "Symphony"}, {107 , "Booty Bass"}, {108 , "Primus"}, {109 , "Porn Groove"},
|
||||
{110 , "Satire"}, {111 , "Slow Jam"}, {112 , "Club"}, {113 , "Tango"}, {114 , "Samba"}, {115 , "Folklore"}, {116 , "Ballad"}, {117 , "Power Ballad"}, {118 , "Rhytmic Soul"}, {119 , "Freestyle"}, {120 , "Duet"},
|
||||
{121 , "Punk Rock"}, {122 , "Drum Solo"}, {123 , "A capella"}, {124 , "Euro-House"}, {125 , "Dance Hall"}, {126 , "Goa"}, {127 , "Drum & Bass"}, {128 , "Club-House"}, {129 , "Hardcore"}, {130 , "Terror"},
|
||||
{131 , "Indie"}, {132 , "BritPop"}, {133 , "Negerpunk"}, {134 , "Polsk Punk"}, {135 , "Beat"}, {136 , "Christian Gangsta"}, {137 , "Heavy Metal"}, {138 , "Black Metal"}, {139 , "Crossover"}, {140 , "Contemporary C"},
|
||||
{141 , "Christian Rock"}, {142 , "Merengue"}, {143 , "Salsa"}, {144 , "Thrash Metal"}, {145 , "Anime"}, {146 , "JPop"}, {147 , "SynthPop"}
|
||||
};
|
||||
int genreNumber = sizeof (genreList) / sizeof (struct genre);
|
||||
|
||||
|
||||
//Search for FF+D8+FF bytes (first bytes of a jpeg image)
|
||||
//Returns file position:
|
||||
int searchJPGstart(int fp, int delta){
|
||||
int retValue = -1;
|
||||
int i = 0;
|
||||
|
||||
unsigned char *tBuffer = malloc(sizeof(unsigned char) * (delta + 2));
|
||||
if (tBuffer == NULL)
|
||||
return -1;
|
||||
|
||||
int startPos = sceIoLseek(fp, 0, SCE_SEEK_CUR);
|
||||
sceIoRead(fp, tBuffer, delta + 2);
|
||||
sceIoLseek(fp, startPos, SCE_SEEK_SET);
|
||||
|
||||
unsigned char *buff = tBuffer;
|
||||
for (i=0; i<delta; i++){
|
||||
if(!memcmp(buff++, ID3_JPEG, 3)){
|
||||
retValue = startPos + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(tBuffer);
|
||||
return retValue;
|
||||
}
|
||||
|
||||
//Search for 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 bytes (first bytes of a PNG image)
|
||||
//Returns file position:
|
||||
int searchPNGstart(int fp, int delta){
|
||||
int retValue = -1;
|
||||
int i = 0;
|
||||
|
||||
unsigned char *tBuffer = malloc(sizeof(unsigned char) * (delta + 15));
|
||||
if (tBuffer == NULL)
|
||||
return -1;
|
||||
|
||||
int startPos = sceIoLseek(fp, 0, SCE_SEEK_CUR);
|
||||
sceIoRead(fp, tBuffer, delta + 15);
|
||||
sceIoLseek(fp, startPos, SCE_SEEK_SET);
|
||||
|
||||
unsigned char *buff = tBuffer;
|
||||
for (i=0; i<delta; i++){
|
||||
if(!memcmp(buff++, ID3_PNG, 16)){
|
||||
retValue = startPos + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(tBuffer);
|
||||
return retValue;
|
||||
}
|
||||
|
||||
// ID3v2 code taken from libID3 by Xart
|
||||
// http://www.xart.co.uk
|
||||
short int swapInt16BigToHost(short int arg)
|
||||
{
|
||||
short int i=0;
|
||||
int checkEndian = 1;
|
||||
if( 1 == *(char *)&checkEndian )
|
||||
{
|
||||
// Intel (little endian)
|
||||
i=arg;
|
||||
i=((i&0xFF00)>>8)|((i&0x00FF)<<8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PPC (big endian)
|
||||
i=arg;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int swapInt32BigToHost(int arg)
|
||||
{
|
||||
int i=0;
|
||||
int checkEndian = 1;
|
||||
if( 1 == *(char *)&checkEndian )
|
||||
{
|
||||
// Intel (little endian)
|
||||
i=arg;
|
||||
i=((i&0xFF000000)>>24)|((i&0x00FF0000)>>8)|((i&0x0000FF00)<<8)|((i&0x000000FF)<<24);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PPC (big endian)
|
||||
i=arg;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static void utf16_to_utf8(uint16_t *src, uint8_t *dst) {
|
||||
int i;
|
||||
for (i = 0; src[i]; i++) {
|
||||
if ((src[i] & 0xFF80) == 0) {
|
||||
*(dst++) = src[i] & 0xFF;
|
||||
} else if((src[i] & 0xF800) == 0) {
|
||||
*(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0;
|
||||
*(dst++) = (src[i] & 0x3F) | 0x80;
|
||||
} else if((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00) {
|
||||
*(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0;
|
||||
*(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80;
|
||||
*(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF);
|
||||
*(dst++) = (src[i + 1] & 0x3F) | 0x80;
|
||||
i += 1;
|
||||
} else {
|
||||
*(dst++) = ((src[i] >> 12) & 0xF) | 0xE0;
|
||||
*(dst++) = ((src[i] >> 6) & 0x3F) | 0x80;
|
||||
*(dst++) = (src[i] & 0x3F) | 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
//Reads tag data purging invalid characters:
|
||||
void readTagData(int fp, int tagLength, int maxTagLength, char *tagValue){
|
||||
if (tagLength > maxTagLength)
|
||||
tagLength = maxTagLength;
|
||||
|
||||
int i;
|
||||
int count = 0;
|
||||
unsigned short carattere16[tagLength/2+2];
|
||||
unsigned char carattere8[128];
|
||||
unsigned char* carattere = (unsigned char*)carattere16;
|
||||
char* utf8Tag;
|
||||
|
||||
strcpy(tagValue, "");
|
||||
tagValue[0] = '\0';
|
||||
|
||||
sceIoRead(fp, carattere, tagLength);
|
||||
carattere[tagLength] = '\0';
|
||||
carattere[tagLength+1] = '\0';
|
||||
|
||||
// unicode tag
|
||||
if ( carattere16[0] == 0xFEFF ) {
|
||||
// utf8Tag = miniConvUTF16LEConv( carattere16 + 1 );
|
||||
utf16_to_utf8(carattere16 + 1, carattere8);
|
||||
utf8Tag = (char*)carattere8;
|
||||
}
|
||||
// encode to utf8
|
||||
else {
|
||||
/* if ( miniConvHaveDefaultSubtitleConv() )
|
||||
utf8Tag = miniConvDefaultSubtitleConv( carattere );
|
||||
else */
|
||||
utf8Tag = (char*)carattere;
|
||||
}
|
||||
if ( utf8Tag == NULL || !strlen(utf8Tag)) {
|
||||
for (i=0; i<tagLength; i++){
|
||||
if (carattere[i] >= 0x20 && carattere[i] <= 0xfd) //<= 0x7f
|
||||
tagValue[count++] = carattere[i];
|
||||
}
|
||||
tagValue[count] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy( tagValue, utf8Tag );
|
||||
}
|
||||
}
|
||||
|
||||
int ID3v2TagSize(const char *mp3path)
|
||||
{
|
||||
int fp = 0;
|
||||
int size;
|
||||
char sig[3];
|
||||
|
||||
fp = sceIoOpen(mp3path, SCE_O_RDONLY, 0777);
|
||||
if (fp < 0) return 0;
|
||||
|
||||
sceIoRead(fp, sig, sizeof(sig));
|
||||
if (strncmp("ID3",sig,3) != 0) {
|
||||
sceIoClose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sceIoLseek(fp, 6, SCE_SEEK_SET);
|
||||
sceIoRead(fp, &size, sizeof(unsigned int));
|
||||
/*
|
||||
* The ID3 tag size is encoded with four bytes where the first bit
|
||||
* (bit 7) is set to zero in every byte, making a total of 28 bits. The zeroed
|
||||
* bits are ignored, so a 257 bytes long tag is represented as $00 00 02 01.
|
||||
*/
|
||||
|
||||
size = (unsigned int) swapInt32BigToHost((int)size);
|
||||
size = ( ( (size & 0x7f000000) >> 3 ) | ( (size & 0x7f0000) >> 2 ) | ( (size & 0x7f00) >> 1 ) | (size & 0x7f) );
|
||||
sceIoClose(fp);
|
||||
return size;
|
||||
}
|
||||
|
||||
int ID3v2(const char *mp3path)
|
||||
{
|
||||
char sig[3];
|
||||
unsigned short int version;
|
||||
|
||||
|
||||
int fp = sceIoOpen(mp3path, SCE_O_RDONLY, 0777);
|
||||
if (fp < 0) return 0;
|
||||
|
||||
sceIoRead(fp, sig, sizeof(sig));
|
||||
if (!strncmp("ID3",sig,3)) {
|
||||
sceIoRead(fp, &version, sizeof(unsigned short int));
|
||||
version = (unsigned short int) swapInt16BigToHost((short int)version);
|
||||
version /= 256;
|
||||
}
|
||||
sceIoClose(fp);
|
||||
|
||||
return (int)version;
|
||||
}
|
||||
|
||||
void ParseID3v2_2(const char *mp3path, struct ID3Tag *id3tag)
|
||||
{
|
||||
int fp = 0;
|
||||
|
||||
int size;
|
||||
int tag_length;
|
||||
char tag[3];
|
||||
char buffer[20];
|
||||
|
||||
//if(ID3v2(mp3path) == 2) {
|
||||
size = ID3v2TagSize(mp3path);
|
||||
fp = sceIoOpen(mp3path, SCE_O_RDONLY, 0777);
|
||||
if (fp < 0) return;
|
||||
sceIoLseek(fp, 10, SCE_SEEK_SET);
|
||||
|
||||
while (size != 0) {
|
||||
sceIoRead(fp, tag, 3);
|
||||
size -= 3;
|
||||
|
||||
/* read 3 byte big endian tag length */
|
||||
sceIoRead(fp, &tag_length, sizeof(unsigned int));
|
||||
sceIoLseek(fp, -1, SCE_SEEK_CUR);
|
||||
|
||||
tag_length = (unsigned int) swapInt32BigToHost((int)tag_length);
|
||||
tag_length = (tag_length / 256);
|
||||
size -= 3;
|
||||
|
||||
/* Perform checks for end of tags and tag length overflow or zero */
|
||||
if(*tag == 0 || tag_length > size || tag_length == 0) break;
|
||||
|
||||
if(!strncmp("TP1",tag,3)) /* Artist */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Artist);
|
||||
}
|
||||
else if(!strncmp("TT2",tag,3)) /* Title */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Title);
|
||||
}
|
||||
else if(!strncmp("TAL",tag,3)) /* Album */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Album);
|
||||
}
|
||||
else if(!strncmp("TRK",tag,3)) /* Track No. */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 8, id3tag->ID3TrackText);
|
||||
id3tag->ID3Track = atoi(id3tag->ID3TrackText);
|
||||
}
|
||||
else if(!strncmp("TYE",tag,3)) /* Year */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 12, id3tag->ID3Year);
|
||||
}
|
||||
else if(!strncmp("TLE",tag,3)) /* Length */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 264, buffer);
|
||||
id3tag->ID3Length = atoi(buffer);
|
||||
}
|
||||
else if(!strncmp("COM",tag,3)) /* Comment */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Comment);
|
||||
}
|
||||
else if(!strncmp("TCO",tag,3)) /* Genre */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3GenreText);
|
||||
if (id3tag->ID3GenreText[0] == '(' && id3tag->ID3GenreText[strlen(id3tag->ID3GenreText) - 1] == ')')
|
||||
{
|
||||
id3tag->ID3GenreText[0] = ' ';
|
||||
id3tag->ID3GenreText[strlen(id3tag->ID3GenreText) - 1] = '\0';
|
||||
int index = atoi(id3tag->ID3GenreText);
|
||||
if (index >= 0 && index < genreNumber)
|
||||
strcpy(id3tag->ID3GenreText, genreList[index].text);
|
||||
}
|
||||
}
|
||||
else if(!strncmp("PIC",tag,3)) /* Picture */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
sceIoLseek(fp, 5, SCE_SEEK_CUR);
|
||||
id3tag->ID3EncapsulatedPictureType = JPEG_IMAGE;
|
||||
id3tag->ID3EncapsulatedPictureOffset = searchJPGstart(fp, 0x100);
|
||||
if (id3tag->ID3EncapsulatedPictureOffset < 0){
|
||||
id3tag->ID3EncapsulatedPictureType = PNG_IMAGE;
|
||||
id3tag->ID3EncapsulatedPictureOffset = searchPNGstart(fp, 0x100);
|
||||
}
|
||||
tag_length = tag_length - (id3tag->ID3EncapsulatedPictureOffset - sceIoLseek(fp, 0, SCE_SEEK_CUR));
|
||||
id3tag->ID3EncapsulatedPictureLength = tag_length-6;
|
||||
sceIoLseek(fp, tag_length-6, SCE_SEEK_CUR);
|
||||
if (id3tag->ID3EncapsulatedPictureOffset < 0){
|
||||
id3tag->ID3EncapsulatedPictureType = 0;
|
||||
id3tag->ID3EncapsulatedPictureOffset = 0;
|
||||
id3tag->ID3EncapsulatedPictureLength = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sceIoLseek(fp, tag_length, SCE_SEEK_CUR);
|
||||
}
|
||||
size -= tag_length;
|
||||
}
|
||||
strcpy(id3tag->versionfound, "2.2");
|
||||
sceIoClose(fp);
|
||||
//}
|
||||
}
|
||||
|
||||
void ParseID3v2_3(const char *mp3path, struct ID3Tag *id3tag)
|
||||
{
|
||||
int fp = 0;
|
||||
|
||||
int size;
|
||||
int tag_length;
|
||||
char tag[4];
|
||||
char buffer[20];
|
||||
|
||||
//if(ID3v2(mp3path) == 3) {
|
||||
size = ID3v2TagSize(mp3path);
|
||||
fp = sceIoOpen(mp3path, SCE_O_RDONLY, 0777);
|
||||
if (fp < 0) return;
|
||||
sceIoLseek(fp, 10, SCE_SEEK_SET);
|
||||
|
||||
while (size != 0) {
|
||||
sceIoRead(fp, tag, 4);
|
||||
size -= 4;
|
||||
|
||||
/* read 4 byte big endian tag length */
|
||||
sceIoRead(fp, &tag_length, sizeof(unsigned int));
|
||||
tag_length = (unsigned int) swapInt32BigToHost((int)tag_length);
|
||||
size -= 4;
|
||||
|
||||
sceIoLseek(fp, 2, SCE_SEEK_CUR);
|
||||
size -= 2;
|
||||
|
||||
/* Perform checks for end of tags and tag length overflow or zero */
|
||||
if(*tag == 0 || tag_length > size || tag_length == 0) break;
|
||||
|
||||
if(!strncmp("TPE1",tag,4)) /* Artist */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Artist);
|
||||
}
|
||||
else if(!strncmp("TIT2",tag,4)) /* Title */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Title);
|
||||
}
|
||||
else if(!strncmp("TALB",tag,4)) /* Album */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Album);
|
||||
}
|
||||
else if(!strncmp("TRCK",tag,4)) /* Track No. */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 8, id3tag->ID3TrackText);
|
||||
id3tag->ID3Track = atoi(id3tag->ID3TrackText);
|
||||
}
|
||||
else if(!strncmp("TYER",tag,4)) /* Year */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 12, id3tag->ID3Year);
|
||||
}
|
||||
else if(!strncmp("TLEN",tag,4)) /* Length in milliseconds */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 264, buffer);
|
||||
id3tag->ID3Length = atol(buffer) / 1000;
|
||||
}
|
||||
else if(!strncmp("TCON",tag,4)) /* Genre */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3GenreText);
|
||||
if (id3tag->ID3GenreText[0] == '(' && id3tag->ID3GenreText[strlen(id3tag->ID3GenreText) - 1] == ')')
|
||||
{
|
||||
id3tag->ID3GenreText[0] = ' ';
|
||||
id3tag->ID3GenreText[strlen(id3tag->ID3GenreText) - 1] = '\0';
|
||||
int index = atoi(id3tag->ID3GenreText);
|
||||
if (index >= 0 && index < genreNumber)
|
||||
strcpy(id3tag->ID3GenreText, genreList[index].text);
|
||||
}
|
||||
}
|
||||
else if(!strncmp("COMM",tag,4)) /* Comment */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Comment);
|
||||
}
|
||||
else if(!strncmp("APIC",tag,4)) /* Picture */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
sceIoLseek(fp, 12, SCE_SEEK_CUR);
|
||||
id3tag->ID3EncapsulatedPictureType = JPEG_IMAGE;
|
||||
id3tag->ID3EncapsulatedPictureOffset = searchJPGstart(fp, 0x100);
|
||||
if (id3tag->ID3EncapsulatedPictureOffset < 0){
|
||||
id3tag->ID3EncapsulatedPictureType = PNG_IMAGE;
|
||||
id3tag->ID3EncapsulatedPictureOffset = searchPNGstart(fp, 0x100);
|
||||
}
|
||||
tag_length = tag_length - (id3tag->ID3EncapsulatedPictureOffset - sceIoLseek(fp, 0, SCE_SEEK_CUR));
|
||||
id3tag->ID3EncapsulatedPictureLength = tag_length-13;
|
||||
sceIoLseek(fp, tag_length-13, SCE_SEEK_CUR);
|
||||
if (id3tag->ID3EncapsulatedPictureOffset < 0){
|
||||
id3tag->ID3EncapsulatedPictureType = 0;
|
||||
id3tag->ID3EncapsulatedPictureOffset = 0;
|
||||
id3tag->ID3EncapsulatedPictureLength = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sceIoLseek(fp, tag_length, SCE_SEEK_CUR);
|
||||
}
|
||||
size -= tag_length;
|
||||
}
|
||||
strcpy(id3tag->versionfound, "2.3");
|
||||
sceIoClose(fp);
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
void ParseID3v2_4(const char *mp3path, struct ID3Tag *id3tag)
|
||||
{
|
||||
int fp = 0;
|
||||
|
||||
int size;
|
||||
int tag_length;
|
||||
char tag[4];
|
||||
char buffer[20];
|
||||
|
||||
//if(ID3v2(mp3path) == 4) {
|
||||
size = ID3v2TagSize(mp3path);
|
||||
fp = sceIoOpen(mp3path, SCE_O_RDONLY, 0777);
|
||||
if (fp < 0) return;
|
||||
sceIoLseek(fp, 10, SCE_SEEK_SET);
|
||||
|
||||
while (size != 0) {
|
||||
sceIoRead(fp, tag, 4);
|
||||
size -= 4;
|
||||
|
||||
/* read 4 byte big endian tag length */
|
||||
sceIoRead(fp, &tag_length, sizeof(unsigned int));
|
||||
tag_length = (unsigned int) swapInt32BigToHost((int)tag_length);
|
||||
size -= 4;
|
||||
|
||||
sceIoLseek(fp, 2, SCE_SEEK_CUR);
|
||||
size -= 2;
|
||||
|
||||
/* Perform checks for end of tags and tag length overflow or zero */
|
||||
if(*tag == 0 || tag_length > size || tag_length == 0) break;
|
||||
|
||||
if(!strncmp("TPE1",tag,4)) /* Artist */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Artist);
|
||||
}
|
||||
else if(!strncmp("TIT2",tag,4)) /* Title */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Title);
|
||||
}
|
||||
else if(!strncmp("TALB",tag,4)) /* Album */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Album);
|
||||
}
|
||||
else if(!strncmp("TRCK",tag,4)) /* Track No. */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 8, id3tag->ID3TrackText);
|
||||
id3tag->ID3Track = atoi(id3tag->ID3TrackText);
|
||||
}
|
||||
else if(!strncmp("TYER",tag,4)) /* Year */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 12, id3tag->ID3Year);
|
||||
}
|
||||
else if(!strncmp("TLEN",tag,4)) /* Length in milliseconds */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 264, buffer);
|
||||
id3tag->ID3Length = atol(buffer) / 1000;
|
||||
}
|
||||
else if(!strncmp("TCON",tag,4)) /* Genre */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3GenreText);
|
||||
}
|
||||
else if(!strncmp("COMM",tag,4)) /* Comment */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
readTagData(fp, tag_length - 1, 260, id3tag->ID3Comment);
|
||||
}
|
||||
else if(!strncmp("APIC",tag,4)) /* Picture */
|
||||
{
|
||||
sceIoLseek(fp, 1, SCE_SEEK_CUR);
|
||||
sceIoLseek(fp, 12, SCE_SEEK_CUR);
|
||||
id3tag->ID3EncapsulatedPictureType = JPEG_IMAGE;
|
||||
id3tag->ID3EncapsulatedPictureOffset = searchJPGstart(fp, 0x100);
|
||||
if (id3tag->ID3EncapsulatedPictureOffset < 0){
|
||||
id3tag->ID3EncapsulatedPictureType = PNG_IMAGE;
|
||||
id3tag->ID3EncapsulatedPictureOffset = searchPNGstart(fp, 0x100);
|
||||
}
|
||||
tag_length = tag_length - (id3tag->ID3EncapsulatedPictureOffset - sceIoLseek(fp, 0, SCE_SEEK_CUR));
|
||||
id3tag->ID3EncapsulatedPictureLength = tag_length-13;
|
||||
sceIoLseek(fp, tag_length-13, SCE_SEEK_CUR);
|
||||
if (id3tag->ID3EncapsulatedPictureOffset < 0){
|
||||
id3tag->ID3EncapsulatedPictureType = 0;
|
||||
id3tag->ID3EncapsulatedPictureOffset = 0;
|
||||
id3tag->ID3EncapsulatedPictureLength = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sceIoLseek(fp, tag_length, SCE_SEEK_CUR);
|
||||
}
|
||||
size -= tag_length;
|
||||
}
|
||||
strcpy(id3tag->versionfound, "2.4");
|
||||
sceIoClose(fp);
|
||||
//}
|
||||
}
|
||||
|
||||
int ParseID3v2(const char *mp3path, struct ID3Tag *id3tag)
|
||||
{
|
||||
switch (ID3v2(mp3path)) {
|
||||
case 2:
|
||||
ParseID3v2_2(mp3path, id3tag);
|
||||
break;
|
||||
case 3:
|
||||
ParseID3v2_3(mp3path, id3tag);
|
||||
break;
|
||||
case 4:
|
||||
ParseID3v2_4(mp3path, id3tag);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If no Title is found, uses filename - extension for Title. */
|
||||
/*if(*id3tag->ID3Title == 0) {
|
||||
strcpy(id3tag->ID3Title,strrchr(mp3path,'/') + 1);
|
||||
if (*strrchr(id3tag->ID3Title,'.') != 0) *strrchr(id3tag->ID3Title,'.') = 0;
|
||||
}*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ParseID3v1(const char *mp3path, struct ID3Tag *id3tag){
|
||||
int id3fd; //our local file descriptor
|
||||
char id3buffer[512];
|
||||
id3fd = sceIoOpen(mp3path, SCE_O_RDONLY, 0777);
|
||||
if (id3fd < 0)
|
||||
return -1;
|
||||
sceIoLseek(id3fd, -128, SEEK_END);
|
||||
sceIoRead(id3fd,id3buffer,128);
|
||||
|
||||
if (strstr(id3buffer,"TAG") != NULL){
|
||||
sceIoLseek(id3fd, -125, SEEK_END);
|
||||
sceIoRead(id3fd,id3tag->ID3Title,30);
|
||||
id3tag->ID3Title[30] = '\0';
|
||||
|
||||
sceIoLseek(id3fd, -95, SEEK_END);
|
||||
sceIoRead(id3fd,id3tag->ID3Artist,30);
|
||||
id3tag->ID3Artist[30] = '\0';
|
||||
|
||||
sceIoLseek(id3fd, -65, SEEK_END);
|
||||
sceIoRead(id3fd,id3tag->ID3Album,30);
|
||||
id3tag->ID3Album[30] = '\0';
|
||||
|
||||
sceIoLseek(id3fd, -35, SEEK_END);
|
||||
sceIoRead(id3fd,id3tag->ID3Year,4);
|
||||
id3tag->ID3Year[4] = '\0';
|
||||
|
||||
sceIoLseek(id3fd, -31, SEEK_END);
|
||||
sceIoRead(id3fd,id3tag->ID3Comment,30);
|
||||
id3tag->ID3Comment[30] = '\0';
|
||||
|
||||
sceIoLseek(id3fd, -1, SEEK_END);
|
||||
sceIoRead(id3fd,id3tag->ID3GenreCode,1);
|
||||
id3tag->ID3GenreCode[1] = '\0';
|
||||
|
||||
/* Track */
|
||||
if (*(id3tag->ID3Comment + 28) == 0 && *(id3tag->ID3Comment + 29) > 0) {
|
||||
id3tag->ID3Track = (int)*(id3tag->ID3Comment + 29);
|
||||
strcpy(id3tag->versionfound, "1.1");
|
||||
} else {
|
||||
id3tag->ID3Track = 1;
|
||||
strcpy(id3tag->versionfound, "1.0");
|
||||
}
|
||||
|
||||
if (((int)id3tag->ID3GenreCode[0] >= 0) & ((int)id3tag->ID3GenreCode[0] < genreNumber)){
|
||||
strcpy(id3tag->ID3GenreText, genreList[(int)id3tag->ID3GenreCode[0]].text);
|
||||
}
|
||||
else{
|
||||
strcpy(id3tag->ID3GenreText, "");
|
||||
}
|
||||
id3tag->ID3GenreText[30] = '\0';
|
||||
}else{
|
||||
sceIoClose(id3fd);
|
||||
return -1;
|
||||
}
|
||||
sceIoClose(id3fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Main function:
|
||||
int ParseID3(char *mp3path, struct ID3Tag *target)
|
||||
{
|
||||
memset(target, 0, sizeof(struct ID3Tag));
|
||||
|
||||
ParseID3v1(mp3path, target);
|
||||
ParseID3v2(mp3path, target);
|
||||
// if (!strlen(target->ID3Title))
|
||||
// getFileName(mp3path, target->ID3Title);
|
||||
return 0;
|
||||
}
|
43
audio/id3.h
Normal file
43
audio/id3.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef __id3_h
|
||||
#define __id3_h (1)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define JPEG_IMAGE 1
|
||||
#define PNG_IMAGE 2
|
||||
|
||||
#define ID3_JPEG (unsigned char [3]) \
|
||||
{ \
|
||||
0xFF,0xD8,0xFF \
|
||||
}
|
||||
|
||||
#define ID3_PNG (unsigned char [16]) \
|
||||
{ \
|
||||
0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52 \
|
||||
}
|
||||
struct ID3Tag {
|
||||
char ID3Title[260];
|
||||
char ID3Artist[260];
|
||||
char ID3Album[260];
|
||||
char ID3Year[12];
|
||||
char ID3Comment[260];
|
||||
char ID3GenreCode[12];
|
||||
char ID3GenreText[260];
|
||||
char versionfound[12];
|
||||
int ID3Track;
|
||||
char ID3TrackText[8];
|
||||
int ID3EncapsulatedPictureType;
|
||||
int ID3EncapsulatedPictureOffset; /* Offset address of an attached picture, NULL if no attached picture exists */
|
||||
int ID3EncapsulatedPictureLength;
|
||||
int ID3Length;
|
||||
};
|
||||
|
||||
int ID3v2TagSize(const char *mp3path);
|
||||
int ParseID3(char *mp3path, struct ID3Tag *target);
|
||||
|
||||
//Helper functions (used also by aa3mplayerME to read tags):
|
||||
void readTagData(int fp, int tagLength, int maxTagLength, char *tagValue);
|
||||
int swapInt32BigToHost(int arg);
|
||||
//short int swapInt16BigToHost(short int arg);
|
||||
|
||||
#endif
|
50
audio/info.h
Normal file
50
audio/info.h
Normal file
@ -0,0 +1,50 @@
|
||||
// LightMP3
|
||||
// Copyright (C) 2007,2008 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
|
||||
#ifndef __info_h
|
||||
#define __info_h (1)
|
||||
|
||||
struct fileInfo{
|
||||
int fileType;
|
||||
int defaultCPUClock;
|
||||
int needsME;
|
||||
double fileSize;
|
||||
char layer[12];
|
||||
int kbit;
|
||||
long instantBitrate;
|
||||
long hz;
|
||||
char mode[52];
|
||||
char emphasis[20];
|
||||
long length;
|
||||
char strLength[12];
|
||||
long frames;
|
||||
long framesDecoded;
|
||||
int encapsulatedPictureType;
|
||||
int encapsulatedPictureOffset;
|
||||
int encapsulatedPictureLength;
|
||||
char coverArtImageName[264];
|
||||
|
||||
//Tag/comments:
|
||||
char album[260];
|
||||
char title[260];
|
||||
char artist[260];
|
||||
char genre[260];
|
||||
char year[12];
|
||||
char trackNumber[8];
|
||||
};
|
||||
|
||||
#endif
|
864
audio/mp3player.c
Normal file
864
audio/mp3player.c
Normal file
@ -0,0 +1,864 @@
|
||||
// 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 <psp2/io/fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "id3.h"
|
||||
#include "mp3xing.h"
|
||||
#include "player.h"
|
||||
#include "vita_audio.h"
|
||||
#include "mp3player.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE !FALSE
|
||||
|
||||
/* This table represents the subband-domain filter characteristics. It
|
||||
* is initialized by the ParseArgs() function and is used as
|
||||
* coefficients against each subband samples when DoFilter is non-nul.
|
||||
*/
|
||||
static mad_fixed_t Filter[32];
|
||||
static double filterDouble[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
/* DoFilter is non-nul when the Filter table defines a filter bank to
|
||||
* be applied to the decoded audio subbands.
|
||||
*/
|
||||
static int DoFilter = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Global local variables
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
static struct mad_stream Stream;
|
||||
static struct mad_header Header;
|
||||
static struct mad_frame Frame;
|
||||
static struct mad_synth Synth;
|
||||
static mad_timer_t Timer;
|
||||
static int MP3_outputInProgress = 0;
|
||||
static int MP3_channels = 0;
|
||||
static int MP3_tagRead = 0;
|
||||
|
||||
// The following variables are maintained and updated by the tracker during playback
|
||||
static int MP3_isPlaying; // Set to true when a mod is being played
|
||||
static long MP3_suspendPosition = -1;
|
||||
static long MP3_suspendIsPlaying = 0;
|
||||
|
||||
typedef struct {
|
||||
short left;
|
||||
short right;
|
||||
} Sample;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// These are the public functions
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
static int myChannel;
|
||||
static int eos;
|
||||
|
||||
struct fileInfo MP3_info;
|
||||
|
||||
#define BOOST_OLD 0
|
||||
#define BOOST_NEW 1
|
||||
|
||||
static char MP3_fileName[264];
|
||||
static int MP3_volume_boost_type = BOOST_NEW;
|
||||
static double MP3_volume_boost = 0.0;
|
||||
static unsigned int MP3_volume_boost_old = 0;
|
||||
static double DB_forBoost = 1.0;
|
||||
static int MP3_playingSpeed = 0; // 0 = normal
|
||||
int MP3_defaultCPUClock = 70;
|
||||
static int MP3_fd = -1;
|
||||
|
||||
#define INPUT_BUFFER_SIZE 2048
|
||||
static unsigned char fileBuffer[INPUT_BUFFER_SIZE];
|
||||
static unsigned int samplesRead;
|
||||
static unsigned int MP3_filePos;
|
||||
static double MP3_newFilePos = -1;
|
||||
static double fileSize = 0;
|
||||
static double tagsize = 0;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Applies a frequency-domain filter to audio data in the subband-domain.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static void ApplyFilter(struct mad_frame *Frame){
|
||||
int Channel, Sample, Samples, SubBand;
|
||||
/* There is two application loops, each optimized for the number
|
||||
* of audio channels to process. The first alternative is for
|
||||
* two-channel frames, the second is for mono-audio.
|
||||
*/
|
||||
Samples = MAD_NSBSAMPLES(&Frame->header);
|
||||
if (Frame->header.mode != MAD_MODE_SINGLE_CHANNEL)
|
||||
for (Channel = 0; Channel < 2; Channel++)
|
||||
for (Sample = 0; Sample < Samples; Sample++)
|
||||
for (SubBand = 0; SubBand < 32; SubBand++)
|
||||
Frame->sbsample[Channel][Sample][SubBand] =
|
||||
mad_f_mul(Frame->sbsample[Channel][Sample][SubBand], Filter[SubBand]);
|
||||
else
|
||||
for (Sample = 0; Sample < Samples; Sample++)
|
||||
for (SubBand = 0; SubBand < 32; SubBand++)
|
||||
Frame->sbsample[0][Sample][SubBand] = mad_f_mul(Frame->sbsample[0][Sample][SubBand], Filter[SubBand]);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Converts a sample from libmad's fixed point number format to a signed
|
||||
// short (16 bits).
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
short convertSample(mad_fixed_t sample) {
|
||||
// round
|
||||
sample += (1L << (MAD_F_FRACBITS - 16));
|
||||
|
||||
// clip
|
||||
if (sample >= MAD_F_ONE)
|
||||
sample = MAD_F_ONE - 1;
|
||||
else if (sample < -MAD_F_ONE)
|
||||
sample = -MAD_F_ONE;
|
||||
|
||||
// quantize
|
||||
return sample >> (MAD_F_FRACBITS + 1 - 16);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Streaming functions (adapted from Ghoti's MusiceEngine.c):
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int fillFileBuffer() {
|
||||
// Find out how much to keep and how much to fill.
|
||||
const unsigned int bytesToKeep = Stream.bufend - Stream.next_frame;
|
||||
unsigned int bytesToFill = sizeof(fileBuffer) - bytesToKeep;
|
||||
|
||||
// Want to keep any bytes?
|
||||
if (bytesToKeep)
|
||||
memmove(fileBuffer, fileBuffer + sizeof(fileBuffer) - bytesToKeep, bytesToKeep);
|
||||
|
||||
// Read into the rest of the file buffer.
|
||||
unsigned char* bufferPos = fileBuffer + bytesToKeep;
|
||||
while (bytesToFill > 0){
|
||||
unsigned int bytesRead = sceIoRead(MP3_fd, bufferPos, bytesToFill);
|
||||
|
||||
if (bytesRead == 0x80010013) {
|
||||
MP3_suspend();
|
||||
MP3_resume();
|
||||
bytesRead = sceIoRead(MP3_fd, bufferPos, bytesToFill);
|
||||
}
|
||||
|
||||
// EOF?
|
||||
if (bytesRead <= 0)
|
||||
return 2;
|
||||
|
||||
// Adjust where we're writing to.
|
||||
bytesToFill -= bytesRead;
|
||||
bufferPos += bytesRead;
|
||||
MP3_filePos += bytesRead;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void decode() {
|
||||
while ((mad_frame_decode(&Frame, &Stream) == -1) && ((Stream.error == MAD_ERROR_BUFLEN) || (Stream.error == MAD_ERROR_BUFPTR))){
|
||||
int tmp;
|
||||
tmp = fillFileBuffer();
|
||||
if (tmp==2)
|
||||
eos = 1;
|
||||
mad_stream_buffer(&Stream, fileBuffer, sizeof(fileBuffer));
|
||||
}
|
||||
//Equalizers and volume boost (NEW METHOD):
|
||||
if (DoFilter || MP3_volume_boost)
|
||||
ApplyFilter(&Frame);
|
||||
|
||||
mad_timer_add(&Timer, Frame.header.duration);
|
||||
mad_synth_frame(&Synth, &Frame);
|
||||
}
|
||||
|
||||
void convertLeftSamples(Sample* first, Sample* last, const mad_fixed_t* src) {
|
||||
Sample* dst;
|
||||
for (dst = first; dst != last; ++dst){
|
||||
dst->left = convertSample(*src++);
|
||||
//Volume Boost (OLD METHOD):
|
||||
if (MP3_volume_boost_old)
|
||||
dst->left = volume_boost(&dst->left, &MP3_volume_boost_old);
|
||||
}
|
||||
}
|
||||
|
||||
void convertRightSamples(Sample* first, Sample* last, const mad_fixed_t* src) {
|
||||
Sample* dst;
|
||||
for (dst = first; dst != last; ++dst){
|
||||
dst->right = convertSample(*src++);
|
||||
//Volume Boost (OLD METHOD):
|
||||
if (MP3_volume_boost_old)
|
||||
dst->right = volume_boost(&dst->right, &MP3_volume_boost_old);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//MP3 Callback for audio:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static void MP3Callback(void *buffer, unsigned int samplesToWrite, void *pdata){
|
||||
Sample *destination = (Sample*)buffer;
|
||||
|
||||
if (MP3_isPlaying == TRUE) { // Playing , so mix up a buffer
|
||||
MP3_outputInProgress = 1;
|
||||
while (samplesToWrite > 0) {
|
||||
const unsigned int samplesAvailable = Synth.pcm.length - samplesRead;
|
||||
if (samplesAvailable > samplesToWrite) {
|
||||
convertLeftSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[0][samplesRead]);
|
||||
if (MP3_channels == 2)
|
||||
convertRightSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[1][samplesRead]);
|
||||
else
|
||||
convertRightSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[0][samplesRead]);
|
||||
|
||||
samplesRead += samplesToWrite;
|
||||
samplesToWrite = 0;
|
||||
|
||||
if (MP3_newFilePos >= 0)
|
||||
{
|
||||
if (!MP3_newFilePos)
|
||||
MP3_newFilePos = ID3v2TagSize(MP3_fileName);
|
||||
|
||||
if (sceIoLseek32(MP3_fd, MP3_newFilePos, SCE_SEEK_SET) != MP3_filePos){
|
||||
MP3_filePos = MP3_newFilePos;
|
||||
mad_timer_set(&Timer, (int)((float)MP3_info.length / 100.0 * MP3_GetPercentage()), 1, 1);
|
||||
}
|
||||
MP3_newFilePos = -1;
|
||||
}
|
||||
|
||||
//Check for playing speed:
|
||||
if (MP3_playingSpeed){
|
||||
if (sceIoLseek32(MP3_fd, 2 * INPUT_BUFFER_SIZE * MP3_playingSpeed, SCE_SEEK_CUR) != 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
|
||||
MP3_setPlayingSpeed(0);
|
||||
}
|
||||
}else{
|
||||
convertLeftSamples(destination, destination + samplesAvailable, &Synth.pcm.samples[0][samplesRead]);
|
||||
if (MP3_channels == 2)
|
||||
convertRightSamples(destination, destination + samplesAvailable, &Synth.pcm.samples[1][samplesRead]);
|
||||
else
|
||||
convertRightSamples(destination, destination + samplesAvailable, &Synth.pcm.samples[0][samplesRead]);
|
||||
|
||||
samplesRead = 0;
|
||||
decode();
|
||||
|
||||
destination += samplesAvailable;
|
||||
samplesToWrite -= samplesAvailable;
|
||||
}
|
||||
}
|
||||
MP3_outputInProgress = 0;
|
||||
} else { // Not Playing , so clear buffer
|
||||
int count;
|
||||
for (count = 0; count < samplesToWrite; count++){
|
||||
destination[count].left = 0;
|
||||
destination[count].right = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Init:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_Init(int channel){
|
||||
initAudioLib();
|
||||
myChannel = channel;
|
||||
MP3_isPlaying = FALSE;
|
||||
MP3_playingSpeed = 0;
|
||||
MP3_volume_boost = 0;
|
||||
MP3_volume_boost_old = 0;
|
||||
|
||||
initFileInfo(&MP3_info);
|
||||
MP3_tagRead = 0;
|
||||
|
||||
vitaAudioSetChannelCallback(myChannel, MP3Callback,0);
|
||||
|
||||
MIN_PLAYING_SPEED=-119;
|
||||
MAX_PLAYING_SPEED=119;
|
||||
|
||||
/* First the structures used by libmad must be initialized. */
|
||||
mad_stream_init(&Stream);
|
||||
mad_header_init(&Header);
|
||||
mad_frame_init(&Frame);
|
||||
mad_synth_init(&Synth);
|
||||
mad_timer_reset(&Timer);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Free tune
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_FreeTune(){
|
||||
sceIoClose(MP3_fd);
|
||||
MP3_fd = -1;
|
||||
/* Mad is no longer used, the structures that were initialized must
|
||||
* now be cleared.
|
||||
*/
|
||||
mad_synth_finish(&Synth);
|
||||
mad_header_finish(&Header);
|
||||
mad_frame_finish(&Frame);
|
||||
mad_stream_finish(&Stream);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Recupero le informazioni sul file:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void getMP3TagInfo(char *filename, struct fileInfo *targetInfo){
|
||||
//ID3:
|
||||
struct ID3Tag ID3;
|
||||
strcpy(MP3_fileName, filename);
|
||||
ParseID3(filename, &ID3);
|
||||
strcpy(targetInfo->title, ID3.ID3Title);
|
||||
strcpy(targetInfo->artist, ID3.ID3Artist);
|
||||
strcpy(targetInfo->album, ID3.ID3Album);
|
||||
strcpy(targetInfo->year, ID3.ID3Year);
|
||||
strcpy(targetInfo->genre, ID3.ID3GenreText);
|
||||
strcpy(targetInfo->trackNumber, ID3.ID3TrackText);
|
||||
targetInfo->length = ID3.ID3Length;
|
||||
targetInfo->encapsulatedPictureType = ID3.ID3EncapsulatedPictureType;
|
||||
targetInfo->encapsulatedPictureOffset = ID3.ID3EncapsulatedPictureOffset;
|
||||
targetInfo->encapsulatedPictureLength = ID3.ID3EncapsulatedPictureLength;
|
||||
|
||||
MP3_info = *targetInfo;
|
||||
MP3_tagRead = 1;
|
||||
|
||||
}
|
||||
|
||||
int MP3getInfo(){
|
||||
unsigned long FrameCount = 0;
|
||||
int fd;
|
||||
int bufferSize = 1024*496;
|
||||
uint8_t *localBuffer;
|
||||
|
||||
int has_xing = 0;
|
||||
struct xing xing;
|
||||
memset(&xing, 0, sizeof xing);
|
||||
|
||||
long singleDataRed = 0;
|
||||
struct mad_stream stream;
|
||||
struct mad_header header;
|
||||
int timeFromID3 = 0;
|
||||
float mediumBitrate = 0.0f;
|
||||
|
||||
if (!MP3_tagRead)
|
||||
getMP3TagInfo(MP3_fileName, &MP3_info);
|
||||
|
||||
mad_stream_init (&stream);
|
||||
mad_header_init (&header);
|
||||
|
||||
fd = sceIoOpen(MP3_fileName, SCE_O_RDONLY, 0777);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
long size = sceIoLseek(fd, 0, SCE_SEEK_END);
|
||||
sceIoLseek(fd, 0, SCE_SEEK_SET);
|
||||
|
||||
double startPos = ID3v2TagSize(MP3_fileName);
|
||||
//Check for xing frame:
|
||||
unsigned char *xing_buffer;
|
||||
xing_buffer = (unsigned char *)malloc(XING_BUFFER_SIZE);
|
||||
if (xing_buffer != NULL)
|
||||
{
|
||||
sceIoRead(fd, xing_buffer, XING_BUFFER_SIZE);
|
||||
if(parse_xing(xing_buffer, 0, &xing))
|
||||
{
|
||||
if (xing.flags & XING_FRAMES && xing.frames){
|
||||
has_xing = 1;
|
||||
bufferSize = 50 * 1024;
|
||||
}
|
||||
}
|
||||
free(xing_buffer);
|
||||
}
|
||||
|
||||
sceIoLseek32(fd, startPos, SCE_SEEK_SET);
|
||||
startPos = SeekNextFrameMP3(fd);
|
||||
size -= startPos;
|
||||
|
||||
if (size < bufferSize * 3)
|
||||
bufferSize = size;
|
||||
localBuffer = (unsigned char *) malloc(sizeof(unsigned char) * bufferSize);
|
||||
unsigned char *buff = localBuffer;
|
||||
|
||||
MP3_channels = 2;
|
||||
MP3_info.fileType = MP3_TYPE;
|
||||
MP3_info.defaultCPUClock = MP3_defaultCPUClock;
|
||||
MP3_info.needsME = 0;
|
||||
MP3_info.fileSize = size;
|
||||
MP3_info.framesDecoded = 0;
|
||||
|
||||
double totalBitrate = 0;
|
||||
int i = 0;
|
||||
|
||||
for (i=0; i<3; i++){
|
||||
memset(localBuffer, 0, bufferSize);
|
||||
singleDataRed = sceIoRead(fd, localBuffer, bufferSize);
|
||||
mad_stream_buffer (&stream, localBuffer, singleDataRed);
|
||||
|
||||
while (1){
|
||||
if (mad_header_decode (&header, &stream) == -1){
|
||||
if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN)
|
||||
break;
|
||||
else if (MAD_RECOVERABLE(stream.error)){
|
||||
continue;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Informazioni solo dal primo frame:
|
||||
if (FrameCount++ == 0){
|
||||
switch (header.layer) {
|
||||
case MAD_LAYER_I:
|
||||
strcpy(MP3_info.layer,"I");
|
||||
break;
|
||||
case MAD_LAYER_II:
|
||||
strcpy(MP3_info.layer,"II");
|
||||
break;
|
||||
case MAD_LAYER_III:
|
||||
strcpy(MP3_info.layer,"III");
|
||||
break;
|
||||
default:
|
||||
strcpy(MP3_info.layer,"unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
MP3_info.kbit = header.bitrate / 1000;
|
||||
MP3_info.instantBitrate = header.bitrate;
|
||||
MP3_info.hz = header.samplerate;
|
||||
switch (header.mode) {
|
||||
case MAD_MODE_SINGLE_CHANNEL:
|
||||
strcpy(MP3_info.mode, "single channel");
|
||||
MP3_channels = 1;
|
||||
break;
|
||||
case MAD_MODE_DUAL_CHANNEL:
|
||||
strcpy(MP3_info.mode, "dual channel");
|
||||
MP3_channels = 2;
|
||||
break;
|
||||
case MAD_MODE_JOINT_STEREO:
|
||||
strcpy(MP3_info.mode, "joint (MS/intensity) stereo");
|
||||
MP3_channels = 2;
|
||||
break;
|
||||
case MAD_MODE_STEREO:
|
||||
strcpy(MP3_info.mode, "normal LR stereo");
|
||||
MP3_channels = 2;
|
||||
break;
|
||||
default:
|
||||
strcpy(MP3_info.mode, "unknown");
|
||||
MP3_channels = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (header.emphasis) {
|
||||
case MAD_EMPHASIS_NONE:
|
||||
strcpy(MP3_info.emphasis,"no");
|
||||
break;
|
||||
case MAD_EMPHASIS_50_15_US:
|
||||
strcpy(MP3_info.emphasis,"50/15 us");
|
||||
break;
|
||||
case MAD_EMPHASIS_CCITT_J_17:
|
||||
strcpy(MP3_info.emphasis,"CCITT J.17");
|
||||
break;
|
||||
case MAD_EMPHASIS_RESERVED:
|
||||
strcpy(MP3_info.emphasis,"reserved(!)");
|
||||
break;
|
||||
default:
|
||||
strcpy(MP3_info.emphasis,"unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
//Check if lenght found in tag info:
|
||||
if (MP3_info.length > 0){
|
||||
timeFromID3 = 1;
|
||||
break;
|
||||
}
|
||||
if (has_xing)
|
||||
break;
|
||||
}
|
||||
|
||||
totalBitrate += header.bitrate;
|
||||
}
|
||||
if (size == bufferSize)
|
||||
break;
|
||||
else if (i==0)
|
||||
sceIoLseek(fd, startPos + size/3, SCE_SEEK_SET);
|
||||
else if (i==1)
|
||||
sceIoLseek(fd, startPos + 2 * size/3, SCE_SEEK_SET);
|
||||
|
||||
if (timeFromID3 || has_xing)
|
||||
break;
|
||||
}
|
||||
mad_header_finish (&header);
|
||||
mad_stream_finish (&stream);
|
||||
if (buff)
|
||||
free(buff);
|
||||
sceIoClose(fd);
|
||||
|
||||
int secs = 0;
|
||||
if (has_xing)
|
||||
{
|
||||
/* modify header.duration since we don't need it anymore */
|
||||
mad_timer_multiply(&header.duration, xing.frames);
|
||||
secs = mad_timer_count(header.duration, MAD_UNITS_SECONDS);
|
||||
MP3_info.length = secs;
|
||||
}
|
||||
else if (!MP3_info.length){
|
||||
mediumBitrate = totalBitrate / (float)FrameCount;
|
||||
secs = size * 8 / mediumBitrate;
|
||||
MP3_info.length = secs;
|
||||
}else{
|
||||
secs = MP3_info.length;
|
||||
}
|
||||
|
||||
//Formatto in stringa la durata totale:
|
||||
int h = secs / 3600;
|
||||
int m = (secs - h * 3600) / 60;
|
||||
int s = secs - h * 3600 - m * 60;
|
||||
snprintf(MP3_info.strLength, sizeof(MP3_info.strLength), "%2.2i:%2.2i:%2.2i", h, m, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//MP3_End
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_End(){
|
||||
MP3_Stop();
|
||||
vitaAudioSetChannelCallback(myChannel, 0,0);
|
||||
MP3_FreeTune();
|
||||
endAudioLib();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Load mp3 into memory:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_Load(char *filename){
|
||||
eos = 0;
|
||||
MP3_outputInProgress = 0;
|
||||
MP3_filePos = 0;
|
||||
fileSize = 0;
|
||||
samplesRead = 0;
|
||||
MP3_fd = sceIoOpen(filename, SCE_O_RDONLY, 0777);
|
||||
if (MP3_fd < 0)
|
||||
return ERROR_OPENING;
|
||||
fileSize = sceIoLseek32(MP3_fd, 0, SCE_SEEK_END);
|
||||
sceIoLseek32(MP3_fd, 0, SCE_SEEK_SET);
|
||||
tagsize = ID3v2TagSize(filename);
|
||||
sceIoLseek32(MP3_fd, tagsize, SCE_SEEK_SET);
|
||||
SeekNextFrameMP3(MP3_fd);
|
||||
|
||||
MP3_isPlaying = FALSE;
|
||||
|
||||
strcpy(MP3_fileName, filename);
|
||||
if (MP3getInfo() != 0){
|
||||
strcpy(MP3_fileName, "");
|
||||
sceIoClose(MP3_fd);
|
||||
MP3_fd = -1;
|
||||
return ERROR_OPENING;
|
||||
}
|
||||
|
||||
//Controllo il sample rate:
|
||||
if (vitaAudioSetFrequency(myChannel, MP3_info.hz) < 0)
|
||||
return ERROR_INVALID_SAMPLE_RATE;
|
||||
return OPENING_OK;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This function initialises for playing, and starts
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_Play(){
|
||||
//Azzero il timer:
|
||||
if (eos == 1){
|
||||
mad_timer_reset(&Timer);
|
||||
}
|
||||
|
||||
// See if I'm already playing
|
||||
if (MP3_isPlaying)
|
||||
return FALSE;
|
||||
|
||||
MP3_isPlaying = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Pause:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_Pause(){
|
||||
MP3_isPlaying = !MP3_isPlaying;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Stop:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_Stop(){
|
||||
//stop playing
|
||||
MP3_isPlaying = FALSE;
|
||||
while (MP3_outputInProgress == 1)
|
||||
sceKernelDelayThread(100000);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Get time string
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_GetTimeString(char *dest){
|
||||
mad_timer_string(Timer, dest, "%02lu:%02u:%02u", MAD_UNITS_HOURS, MAD_UNITS_MILLISECONDS, 0);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Get Percentage
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
float MP3_GetPercentage(){
|
||||
//Calcolo posizione in %:
|
||||
float perc = 0.0f;
|
||||
|
||||
if (fileSize > 0){
|
||||
perc = ((float)MP3_filePos - (float)tagsize) / ((float)fileSize - (float)tagsize) * 100.0;
|
||||
if (perc > 100)
|
||||
perc = 100;
|
||||
}
|
||||
return(perc);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Check EOS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_EndOfStream(){
|
||||
if (eos == 1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Get info on file:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct fileInfo *MP3_GetInfo(){
|
||||
return &MP3_info;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Get only tag info from a file:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct fileInfo MP3_GetTagInfoOnly(char *filename){
|
||||
struct fileInfo tempInfo;
|
||||
initFileInfo(&tempInfo);
|
||||
getMP3TagInfo(filename, &tempInfo);
|
||||
return tempInfo;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Set volume boost type:
|
||||
//NOTE: to be launched only once BEFORE setting boost volume or filter
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_setVolumeBoostType(char *boostType){
|
||||
if (strcmp(boostType, "OLD") == 0){
|
||||
MP3_volume_boost_type = BOOST_OLD;
|
||||
MAX_VOLUME_BOOST = 4;
|
||||
MIN_VOLUME_BOOST = 0;
|
||||
}else{
|
||||
MAX_VOLUME_BOOST = 15;
|
||||
MIN_VOLUME_BOOST = -MAX_VOLUME_BOOST;
|
||||
MP3_volume_boost_type = BOOST_NEW;
|
||||
}
|
||||
MP3_volume_boost_old = 0;
|
||||
MP3_volume_boost = 0;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Set volume boost:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_setVolumeBoost(int boost){
|
||||
if (MP3_volume_boost_type == BOOST_NEW){
|
||||
MP3_volume_boost_old = 0;
|
||||
MP3_volume_boost = boost;
|
||||
}else{
|
||||
MP3_volume_boost_old = boost;
|
||||
MP3_volume_boost = 0;
|
||||
}
|
||||
//Reapply the filter:
|
||||
MP3_setFilter(filterDouble, 0);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Get actual volume boost:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_getVolumeBoost(){
|
||||
if (MP3_volume_boost_type == BOOST_NEW){
|
||||
return(MP3_volume_boost);
|
||||
}else{
|
||||
return(MP3_volume_boost_old);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Set Filter:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_setFilter(double tFilter[32], int copyFilter){
|
||||
//Converto i db:
|
||||
double AmpFactor;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++){
|
||||
//Check for volume boost:
|
||||
if (MP3_volume_boost){
|
||||
AmpFactor=pow(10.,(tFilter[i] + MP3_volume_boost * DB_forBoost)/20);
|
||||
}else{
|
||||
AmpFactor=pow(10.,tFilter[i]/20);
|
||||
}
|
||||
if(AmpFactor>mad_f_todouble(MAD_F_MAX))
|
||||
{
|
||||
DoFilter = 0;
|
||||
return(0);
|
||||
}else{
|
||||
Filter[i]=mad_f_tofixed(AmpFactor);
|
||||
}
|
||||
if (copyFilter){
|
||||
filterDouble[i] = tFilter[i];
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int MP3_isFilterSupported(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Check if filter is enabled:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_isFilterEnabled(){
|
||||
return DoFilter;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Enable filter:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_enableFilter(){
|
||||
DoFilter = 1;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Disable filter:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_disableFilter(){
|
||||
DoFilter = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Get playing speed:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_getPlayingSpeed(){
|
||||
return MP3_playingSpeed;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Set playing speed:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_setPlayingSpeed(int playingSpeed){
|
||||
if (playingSpeed >= MIN_PLAYING_SPEED && playingSpeed <= MAX_PLAYING_SPEED){
|
||||
MP3_playingSpeed = playingSpeed;
|
||||
if (playingSpeed == 0)
|
||||
setVolume(myChannel, 0x8000);
|
||||
else
|
||||
setVolume(myChannel, FASTFORWARD_VOLUME);
|
||||
return 0;
|
||||
}else{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Set mute:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_setMute(int onOff){
|
||||
return setMute(myChannel, onOff);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Fade out:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MP3_fadeOut(float seconds){
|
||||
fadeOut(myChannel, seconds);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Manage suspend:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int MP3_suspend(){
|
||||
MP3_suspendPosition = MP3_filePos;
|
||||
MP3_suspendIsPlaying = MP3_isPlaying;
|
||||
/*MP3_Stop();
|
||||
MP3_FreeTune();*/
|
||||
|
||||
MP3_isPlaying = FALSE;
|
||||
mad_synth_finish(&Synth);
|
||||
mad_header_finish(&Header);
|
||||
mad_frame_finish(&Frame);
|
||||
mad_stream_finish(&Stream);
|
||||
|
||||
sceIoClose(MP3_fd);
|
||||
MP3_fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MP3_resume(){
|
||||
if (MP3_suspendPosition >= 0){
|
||||
mad_stream_init(&Stream);
|
||||
mad_header_init(&Header);
|
||||
mad_frame_init(&Frame);
|
||||
mad_synth_init(&Synth);
|
||||
mad_timer_reset(&Timer);
|
||||
MP3_fd = sceIoOpen(MP3_fileName, SCE_O_RDONLY, 0777);
|
||||
if (MP3_fd >= 0){
|
||||
MP3_filePos = MP3_suspendPosition;
|
||||
sceIoLseek32(MP3_fd, MP3_filePos, SCE_SEEK_SET);
|
||||
mad_timer_set(&Timer, (int)((float)MP3_info.length / 100.0 * MP3_GetPercentage()), 1, 1);
|
||||
MP3_isPlaying = MP3_suspendIsPlaying;
|
||||
}
|
||||
}
|
||||
MP3_suspendPosition = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
double MP3_getFilePosition()
|
||||
{
|
||||
return MP3_filePos;
|
||||
}
|
||||
|
||||
void MP3_setFilePosition(double position)
|
||||
{
|
||||
MP3_newFilePos = position;
|
||||
}
|
56
audio/mp3player.h
Normal file
56
audio/mp3player.h
Normal file
@ -0,0 +1,56 @@
|
||||
// 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 <mad.h>
|
||||
|
||||
extern int MP3_defaultCPUClock;
|
||||
|
||||
//private functions
|
||||
void MP3_Init(int channel);
|
||||
int MP3_Play();
|
||||
void MP3_Pause();
|
||||
int MP3_Stop();
|
||||
void MP3_End();
|
||||
void MP3_FreeTune();
|
||||
int MP3_Load(char *filename);
|
||||
void MP3_GetTimeString(char *dest);
|
||||
int MP3_EndOfStream();
|
||||
struct fileInfo *MP3_GetInfo();
|
||||
struct fileInfo MP3_GetTagInfoOnly(char *filename);
|
||||
int MP3_GetStatus();
|
||||
float MP3_GetPercentage();
|
||||
void MP3_setVolumeBoostType(char *boostType);
|
||||
void MP3_setVolumeBoost(int boost);
|
||||
int MP3_getVolumeBoost();
|
||||
int MP3_getPlayingSpeed();
|
||||
int MP3_setPlayingSpeed(int playingSpeed);
|
||||
int MP3_setMute(int onOff);
|
||||
void MP3_fadeOut(float seconds);
|
||||
|
||||
//Functions for filter (equalizer):
|
||||
int MP3_setFilter(double tFilter[32], int copyFilter);
|
||||
void MP3_enableFilter();
|
||||
void MP3_disableFilter();
|
||||
int MP3_isFilterEnabled();
|
||||
int MP3_isFilterSupported();
|
||||
|
||||
//Manage suspend:
|
||||
int MP3_suspend();
|
||||
int MP3_resume();
|
||||
|
||||
double MP3_getFilePosition();
|
||||
void MP3_setFilePosition(double position);
|
111
audio/mp3xing.c
Normal file
111
audio/mp3xing.c
Normal file
@ -0,0 +1,111 @@
|
||||
// LightMP3
|
||||
// Copyright (C) 2009 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "mp3xing.h"
|
||||
/*
|
||||
4-x Not used till string "Xing" (58 69 6E 67). This string is used as a main VBR file identifier. If it is not found, file is supposed to be CBR. This string can be placed at different locations according to values of MPEG and CHANNEL (ya, these from a few lines upwards):
|
||||
36-39 "Xing" for MPEG1 and CHANNEL != mono (mostly used)
|
||||
21-24 "Xing" for MPEG1 and CHANNEL == mono
|
||||
21-24 "Xing" for MPEG2 and CHANNEL != mono
|
||||
13-16 "Xing" for MPEG2 and CHANNEL == mono
|
||||
|
||||
After "Xing" string there are placed flags, number of frames in file and a size of file in Bytes. Each of these items has 4 Bytes and it is stored as 'int' number in memory. The first is the most significant Byte and the last is the least.
|
||||
Following schema is for MPEG1 and CHANNEL != mono:
|
||||
40-43 Flags
|
||||
Value Name Description
|
||||
00 00 00 01 Frames Flag set if value for number of frames in file is stored
|
||||
00 00 00 02 Bytes Flag set if value for filesize in Bytes is stored
|
||||
00 00 00 04 TOC Flag set if values for TOC (see below) are stored
|
||||
00 00 00 08 VBR Scale Flag set if values for VBR scale are stored
|
||||
All these values can be stored simultaneously.
|
||||
|
||||
44-47 Frames
|
||||
Number of frames in file (including the first info one)
|
||||
|
||||
48-51 Bytes
|
||||
File length in Bytes
|
||||
|
||||
52-151 TOC (Table of Contents)
|
||||
Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file.
|
||||
Each Byte has a value according this formula:
|
||||
(TOC[i] / 256) * fileLenInBytes
|
||||
So if song lasts eg. 240 sec. and you want to jump to 60. sec. (and file is 5 000 000 Bytes length) you can use:
|
||||
TOC[(60/240)*100] = TOC[25]
|
||||
and corresponding Byte in file is then approximately at:
|
||||
(TOC[25]/256) * 5000000
|
||||
|
||||
If you want to trim VBR file you should also reconstruct Frames, Bytes and TOC properly.
|
||||
|
||||
152-155 VBR Scale
|
||||
I dont know exactly system of storing of this values but this item probably doesnt have deeper meaning.
|
||||
*/
|
||||
|
||||
int xingSearchFrame(unsigned char *buffer, int startPos, int maxSearch)
|
||||
{
|
||||
int i = 0;
|
||||
for (i=0; i<maxSearch; i++)
|
||||
{
|
||||
if(!memcmp(buffer, XING_GUID, 4))
|
||||
return startPos;
|
||||
startPos++;
|
||||
buffer++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int xingGetFlags(unsigned char *buffer, int startPos)
|
||||
{
|
||||
buffer += startPos + 4;
|
||||
return buffer[0] + buffer[1] + buffer[2] + buffer[3];
|
||||
}
|
||||
|
||||
int xingGetFrameNumber(unsigned char *buffer, int startPos)
|
||||
{
|
||||
buffer += startPos + 8;
|
||||
char hexStr[9] = "";
|
||||
sprintf(hexStr, "%2.2X%2.2X%2.2X%2.2X", buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
return strtol(hexStr, NULL, 16);
|
||||
}
|
||||
|
||||
int xingGetFileSize(unsigned char *buffer, int startPos)
|
||||
{
|
||||
buffer += startPos + 12;
|
||||
char hexStr[9] = "";
|
||||
sprintf(hexStr, "%2.2X%2.2X%2.2X%2.2X", buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
return strtol(hexStr, NULL, 16);
|
||||
}
|
||||
|
||||
|
||||
int parse_xing(unsigned char *buffer, int startPos, struct xing *xing)
|
||||
{
|
||||
int pos = xingSearchFrame(buffer, startPos, XING_BUFFER_SIZE - 4);
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
|
||||
xing->flags = xingGetFlags(buffer, pos);
|
||||
if (xing->flags & 1)
|
||||
xing->frames = xingGetFrameNumber(buffer, pos);
|
||||
if (xing->flags & 2)
|
||||
xing->bytes = xingGetFileSize(buffer, pos);
|
||||
|
||||
/*if (xing->flags & 4)
|
||||
if (xing->flags & 8)*/
|
||||
return 1;
|
||||
}
|
44
audio/mp3xing.h
Normal file
44
audio/mp3xing.h
Normal file
@ -0,0 +1,44 @@
|
||||
// LightMP3
|
||||
// Copyright (C) 2009 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
|
||||
#ifndef __mp3xing_h
|
||||
#define __mp3xing_h (1)
|
||||
|
||||
#include <mad.h>
|
||||
|
||||
#define XING_BUFFER_SIZE 300
|
||||
#define XING_GUID (unsigned char [4]) \
|
||||
{ 0x58, 0x69, 0x6E, 0x67 }
|
||||
|
||||
struct xing {
|
||||
int flags;
|
||||
unsigned long frames;
|
||||
unsigned long bytes;
|
||||
unsigned char toc[100];
|
||||
long scale;
|
||||
};
|
||||
|
||||
enum {
|
||||
XING_FRAMES = 0x0001,
|
||||
XING_BYTES = 0x0002,
|
||||
XING_TOC = 0x0004,
|
||||
XING_SCALE = 0x0008
|
||||
};
|
||||
|
||||
int parse_xing(unsigned char *buffer, int startPos, struct xing *xing);
|
||||
|
||||
#endif
|
139
audio/player.c
Normal file
139
audio/player.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2016, TheFloW
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <psp2/io/fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "player.h"
|
||||
|
||||
int MAX_VOLUME_BOOST=15;
|
||||
int MIN_VOLUME_BOOST=-15;
|
||||
int MIN_PLAYING_SPEED=-119;
|
||||
int MAX_PLAYING_SPEED=119;
|
||||
|
||||
//Seek next valid frame
|
||||
//NOTE: this function comes from Music prx 0.55 source
|
||||
// all credits goes to joek2100.
|
||||
int SeekNextFrameMP3(SceUID fd)
|
||||
{
|
||||
int offset = 0;
|
||||
unsigned char buf[1024];
|
||||
unsigned char *pBuffer;
|
||||
int i;
|
||||
int size = 0;
|
||||
|
||||
offset = sceIoLseek32(fd, 0, SCE_SEEK_CUR);
|
||||
sceIoRead(fd, buf, sizeof(buf));
|
||||
if (!strncmp((char*)buf, "ID3", 3) || !strncmp((char*)buf, "ea3", 3)) //skip past id3v2 header, which can cause a false sync to be found
|
||||
{
|
||||
//get the real size from the syncsafe int
|
||||
size = buf[6];
|
||||
size = (size<<7) | buf[7];
|
||||
size = (size<<7) | buf[8];
|
||||
size = (size<<7) | buf[9];
|
||||
|
||||
size += 10;
|
||||
|
||||
if (buf[5] & 0x10) //has footer
|
||||
size += 10;
|
||||
}
|
||||
|
||||
sceIoLseek32(fd, offset, SCE_SEEK_SET); //now seek for a sync
|
||||
while(1)
|
||||
{
|
||||
offset = sceIoLseek32(fd, 0, SCE_SEEK_CUR);
|
||||
size = sceIoRead(fd, buf, sizeof(buf));
|
||||
|
||||
if (size <= 2)//at end of file
|
||||
return -1;
|
||||
|
||||
if (!strncmp((char*)buf, "EA3", 3))//oma mp3 files have non-safe ints in the EA3 header
|
||||
{
|
||||
sceIoLseek32(fd, (buf[4]<<8)+buf[5], SCE_SEEK_CUR);
|
||||
continue;
|
||||
}
|
||||
|
||||
pBuffer = buf;
|
||||
for( i = 0; i < size; i++)
|
||||
{
|
||||
//if this is a valid frame sync (0xe0 is for mpeg version 2.5,2+1)
|
||||
if ( (pBuffer[i] == 0xff) && ((pBuffer[i+1] & 0xE0) == 0xE0))
|
||||
{
|
||||
offset += i;
|
||||
sceIoLseek32(fd, offset, SCE_SEEK_SET);
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
//go back two bytes to catch any syncs that on the boundary
|
||||
sceIoLseek32(fd, -2, SCE_SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
short volume_boost(short *Sample, unsigned int *boost) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setVolume(int channel, int volume) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setMute(int channel, int onOff) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fadeOut(int channel, float seconds) {
|
||||
|
||||
}
|
||||
|
||||
int initAudioLib() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int endAudioLib() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initFileInfo(struct fileInfo *info){
|
||||
info->fileType = -1;
|
||||
info->defaultCPUClock = 0;
|
||||
info->needsME = 0;
|
||||
info->fileSize = 0;
|
||||
strcpy(info->layer, "");
|
||||
info->kbit = 0;
|
||||
info->instantBitrate = 0;
|
||||
info->hz = 0;
|
||||
strcpy(info->mode, "");
|
||||
strcpy(info->emphasis, "");
|
||||
info->length = 0;
|
||||
strcpy(info->strLength, "");
|
||||
info->frames = 0;
|
||||
info->framesDecoded = 0;
|
||||
info->encapsulatedPictureType = 0;
|
||||
info->encapsulatedPictureOffset = 0;
|
||||
info->encapsulatedPictureLength = 0;
|
||||
|
||||
strcpy(info->album, "");
|
||||
strcpy(info->title, "");
|
||||
strcpy(info->artist, "");
|
||||
strcpy(info->genre, "");
|
||||
strcpy(info->year, "");
|
||||
strcpy(info->trackNumber, "");
|
||||
strcpy(info->coverArtImageName, "");
|
||||
}
|
59
audio/player.h
Normal file
59
audio/player.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2016, TheFloW
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PLAYER_H__
|
||||
#define __PLAYER_H__
|
||||
|
||||
#include "info.h"
|
||||
|
||||
#define OPENING_OK 0
|
||||
#define ERROR_OPENING -1
|
||||
#define ERROR_INVALID_SAMPLE_RATE -2
|
||||
#define ERROR_MEMORY -3
|
||||
#define ERROR_CREATE_THREAD -4
|
||||
|
||||
#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
|
||||
|
||||
extern int MAX_VOLUME_BOOST;
|
||||
extern int MIN_VOLUME_BOOST;
|
||||
extern int MIN_PLAYING_SPEED;
|
||||
extern int MAX_PLAYING_SPEED;
|
||||
|
||||
int SeekNextFrameMP3(SceUID fd);
|
||||
|
||||
short volume_boost(short *Sample, unsigned int *boost);
|
||||
int setVolume(int channel, int volume);
|
||||
int setMute(int channel, int onOff);
|
||||
void fadeOut(int channel, float seconds);
|
||||
|
||||
int initAudioLib();
|
||||
int endAudioLib();
|
||||
|
||||
void initFileInfo(struct fileInfo *info);
|
||||
|
||||
#endif
|
514
audio/vita_audio.c
Normal file
514
audio/vita_audio.c
Normal file
@ -0,0 +1,514 @@
|
||||
#include <psp2/audioout.h>
|
||||
#include <psp2/kernel/threadmgr.h>
|
||||
#include <psp2/io/fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#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];
|
||||
|
||||
static short *vitaWavSamples;
|
||||
static unsigned long vitaWavReq;
|
||||
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;
|
||||
int handle;
|
||||
int volumeLeft;
|
||||
int volumeRight;
|
||||
vitaAudioCallback callback;
|
||||
void *data;
|
||||
|
||||
} vitaAudioChannelInfo;
|
||||
|
||||
static int vitaAudioReady = 0;
|
||||
static short vitaAudioSoundBuffer[VITA_NUM_AUDIO_CHANNELS][2][VITA_NUM_AUDIO_SAMPLES][2];
|
||||
|
||||
static vitaAudioChannelInfo vitaAudioStatus[VITA_NUM_AUDIO_CHANNELS];
|
||||
|
||||
static volatile int vitaAudioTerminate = 0;
|
||||
|
||||
int vitaAudioSetFrequency(int channel, unsigned short freq) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vitaAudioSetChannelCallback(int channel, vitaAudioCallback callback, void *data)
|
||||
{
|
||||
volatile vitaAudioChannelInfo *pci = &vitaAudioStatus[channel];
|
||||
|
||||
if (callback == 0)
|
||||
pci->callback = 0;
|
||||
else
|
||||
{
|
||||
pci->callback = callback;
|
||||
}
|
||||
}
|
||||
|
||||
static int vitaAudioOutBlocking(unsigned int channel, unsigned int left, unsigned int right, void *data)
|
||||
{
|
||||
if (!vitaAudioReady)
|
||||
return(-1);
|
||||
|
||||
if (channel >= VITA_NUM_AUDIO_CHANNELS)
|
||||
return(-1);
|
||||
|
||||
if (left > VITA_VOLUME_MAX)
|
||||
left = VITA_VOLUME_MAX;
|
||||
|
||||
if (right > VITA_VOLUME_MAX)
|
||||
right = VITA_VOLUME_MAX;
|
||||
|
||||
int vols2[2] = { left, right };
|
||||
sceAudioOutSetVolume(vitaAudioStatus[channel].handle, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vols2);
|
||||
return sceAudioOutOutput(vitaAudioStatus[channel].handle, data);
|
||||
}
|
||||
|
||||
static int vitaAudioChannelThread(int args, void *argp)
|
||||
{
|
||||
volatile int bufidx = 0;
|
||||
|
||||
int channel = *(int *) argp;
|
||||
|
||||
while (vitaAudioTerminate == 0)
|
||||
{
|
||||
void *bufptr = &vitaAudioSoundBuffer[channel][bufidx];
|
||||
vitaAudioCallback callback;
|
||||
callback = vitaAudioStatus[channel].callback;
|
||||
|
||||
if (callback)
|
||||
{
|
||||
callback(bufptr, VITA_NUM_AUDIO_SAMPLES, vitaAudioStatus[channel].data);
|
||||
} else {
|
||||
unsigned int *ptr=bufptr;
|
||||
int i;
|
||||
for (i=0; i<VITA_NUM_AUDIO_SAMPLES; ++i) *(ptr++)=0;
|
||||
}
|
||||
|
||||
vitaAudioOutBlocking(channel, vitaAudioStatus[channel].volumeLeft, vitaAudioStatus[channel].volumeRight, bufptr);
|
||||
|
||||
bufidx = (bufidx ? 0:1);
|
||||
}
|
||||
|
||||
sceKernelExitThread(0);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int vitaAudioInit(int priority)
|
||||
{
|
||||
int i, ret;
|
||||
int failed = 0;
|
||||
char str[32];
|
||||
|
||||
vitaAudioTerminate = 0;
|
||||
vitaAudioReady = 0;
|
||||
|
||||
for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
vitaAudioStatus[i].handle = -1;
|
||||
vitaAudioStatus[i].threadHandle = -1;
|
||||
vitaAudioStatus[i].volumeRight = VITA_VOLUME_MAX;
|
||||
vitaAudioStatus[i].volumeLeft = VITA_VOLUME_MAX;
|
||||
vitaAudioStatus[i].callback = 0;
|
||||
vitaAudioStatus[i].data = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if ((vitaAudioStatus[i].handle = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_BGM, VITA_NUM_AUDIO_SAMPLES, 44100, SCE_AUDIO_OUT_MODE_STEREO)) < 0)
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
{
|
||||
for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (vitaAudioStatus[i].handle != -1)
|
||||
sceAudioOutReleasePort(vitaAudioStatus[i].handle);
|
||||
|
||||
vitaAudioStatus[i].handle = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
vitaAudioReady = 1;
|
||||
|
||||
strcpy(str, "PgeAudioThread0");
|
||||
|
||||
for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
str[14] = '0' + i;
|
||||
vitaAudioStatus[i].threadHandle = sceKernelCreateThread(str, (void*)&vitaAudioChannelThread, priority, 0x10000, 0, 0, NULL);
|
||||
|
||||
if (vitaAudioStatus[i].threadHandle < 0)
|
||||
{
|
||||
vitaAudioStatus[i].threadHandle = -1;
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = sceKernelStartThread(vitaAudioStatus[i].threadHandle, sizeof(i), &i);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed)
|
||||
{
|
||||
vitaAudioTerminate = 1;
|
||||
|
||||
for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (vitaAudioStatus[i].threadHandle != -1)
|
||||
{
|
||||
sceKernelDeleteThread(vitaAudioStatus[i].threadHandle);
|
||||
}
|
||||
|
||||
vitaAudioStatus[i].threadHandle = -1;
|
||||
}
|
||||
|
||||
vitaAudioReady = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void vitaAudioShutdown(void)
|
||||
{
|
||||
int i;
|
||||
vitaAudioReady = 0;
|
||||
vitaAudioTerminate = 1;
|
||||
|
||||
for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (vitaAudioStatus[i].threadHandle != -1)
|
||||
{
|
||||
sceKernelDeleteThread(vitaAudioStatus[i].threadHandle);
|
||||
}
|
||||
|
||||
vitaAudioStatus[i].threadHandle = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < VITA_NUM_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (vitaAudioStatus[i].handle != -1)
|
||||
{
|
||||
sceAudioOutReleasePort(vitaAudioStatus[i].handle);
|
||||
vitaAudioStatus[i].handle = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wavout_snd_callback(void *_buf, unsigned int _reqn, void *pdata)
|
||||
{
|
||||
int i,slot;
|
||||
vitaWav *wi;
|
||||
unsigned long ptr, frac;
|
||||
short *buf = _buf;
|
||||
|
||||
vitaWavSamples = _buf;
|
||||
vitaWavReq = _reqn;
|
||||
|
||||
for(i = 0; i < _reqn; i++)
|
||||
{
|
||||
int outr = 0, outl = 0;
|
||||
|
||||
for(slot = 0; slot < VITA_WAV_MAX_SLOTS; slot++)
|
||||
{
|
||||
if(!vitaWavPlaying[slot]) continue;
|
||||
|
||||
wi = &vitaWavInfo[slot];
|
||||
frac = wi->playPtr_frac + wi->rateRatio;
|
||||
wi->playPtr = ptr = wi->playPtr + (frac>>16);
|
||||
wi->playPtr_frac = (frac & 0xffff);
|
||||
|
||||
if(ptr >= wi->sampleCount)
|
||||
{
|
||||
if(wi->loop)
|
||||
{
|
||||
wi->playPtr = 0;
|
||||
wi->playPtr_frac = 0;
|
||||
ptr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
vitaWavPlaying[slot] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
short *src16 = (short *)wi->data;
|
||||
unsigned char *src8 = (unsigned char *)wi->data;
|
||||
|
||||
if(wi->channels == 1)
|
||||
{
|
||||
if(wi->bitPerSample == 8)
|
||||
{
|
||||
outl += (src8[ptr] * 256) - 32768;
|
||||
outr += (src8[ptr] * 256) - 32768;
|
||||
}
|
||||
else
|
||||
{
|
||||
outl += src16[ptr];
|
||||
outr += src16[ptr];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(wi->bitPerSample == 8)
|
||||
{
|
||||
outl += (src8[ptr*2] * 256) - 32768;
|
||||
outr += (src8[ptr*2+1] * 256) - 32768;
|
||||
}
|
||||
else
|
||||
{
|
||||
outl += src16[ptr*2];
|
||||
outr += src16[ptr*2+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(outl < -32768)
|
||||
outl = -32768;
|
||||
else if (outl > 32767)
|
||||
outl = 32767;
|
||||
|
||||
if(outr < -32768)
|
||||
outr = -32768;
|
||||
else if (outr > 32767)
|
||||
outr = 32767;
|
||||
|
||||
*(buf++) = outl;
|
||||
*(buf++) = outr;
|
||||
}
|
||||
}
|
||||
|
||||
int vitaWavInit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
vitaAudioInit(0x40);
|
||||
|
||||
vitaAudioSetChannelCallback(0, wavout_snd_callback, 0);
|
||||
|
||||
for(i = 0; i < VITA_WAV_MAX_SLOTS; i++)
|
||||
vitaWavPlaying[i] = 0;
|
||||
|
||||
vitaWavInitFlag = 1;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void vitaWavShutdown(void)
|
||||
{
|
||||
if(vitaWavInitFlag)
|
||||
vitaAudioShutdown();
|
||||
}
|
||||
|
||||
void vitaWavStop(vitaWav *wav)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < VITA_WAV_MAX_SLOTS; i++)
|
||||
{
|
||||
if(wav->id == vitaWavId[i])
|
||||
vitaWavPlaying[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void vitaWavStopAll(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < VITA_WAV_MAX_SLOTS; i++)
|
||||
vitaWavPlaying[i] = 0;
|
||||
}
|
||||
|
||||
void vitaWavLoop(vitaWav *wav, unsigned int loop)
|
||||
{
|
||||
wav->loop = loop;
|
||||
}
|
||||
|
||||
int vitaWavPlay(vitaWav *wav)
|
||||
{
|
||||
if(!vitaWavInitFlag)
|
||||
return(0);
|
||||
|
||||
int i;
|
||||
|
||||
vitaWav *wid;
|
||||
|
||||
for(i = 0;i < VITA_WAV_MAX_SLOTS;i++)
|
||||
{
|
||||
if(vitaWavPlaying[i] == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(i == VITA_WAV_MAX_SLOTS)
|
||||
return(0);
|
||||
|
||||
wid = &vitaWavInfo[i];
|
||||
wid->channels = wav->channels;
|
||||
wid->sampleRate = wav->sampleRate;
|
||||
wid->sampleCount = wav->sampleCount;
|
||||
wid->dataLength = wav->dataLength;
|
||||
wid->data = wav->data;
|
||||
wid->rateRatio = wav->rateRatio;
|
||||
wid->playPtr = 0;
|
||||
wid->playPtr_frac = 0;
|
||||
wid->loop = wav->loop;
|
||||
wid->id = wav->id;
|
||||
vitaWavPlaying[i] = 1;
|
||||
vitaWavId[i] = wav->id;
|
||||
wid->bitPerSample = wav->bitPerSample;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static vitaWav *vitaWavLoadInternal(vitaWav *wav, unsigned char *wavfile, int size)
|
||||
{
|
||||
unsigned long channels;
|
||||
unsigned long samplerate;
|
||||
unsigned long blocksize;
|
||||
unsigned long bitpersample;
|
||||
unsigned long datalength;
|
||||
unsigned long samplecount;
|
||||
|
||||
if(memcmp(wavfile, "RIFF", 4) != 0)
|
||||
{
|
||||
free(wav);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
channels = *(short *)(wavfile+0x16);
|
||||
samplerate = *(long *)(wavfile+0x18);
|
||||
blocksize = *(short *)(wavfile+0x20);
|
||||
bitpersample = *(short *)(wavfile+0x22);
|
||||
|
||||
int i;
|
||||
|
||||
for(i = 0; memcmp(wavfile + 0x24 + i, "data", 4) != 0; i++)
|
||||
{
|
||||
if(i == 0xFF)
|
||||
{
|
||||
free(wav);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
datalength = *(unsigned long *)(wavfile + 0x28 + i);
|
||||
|
||||
if(datalength + 0x2c > size)
|
||||
{
|
||||
free(wav);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(channels != 2 && channels != 1)
|
||||
{
|
||||
free(wav);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(samplerate > 100000 || samplerate < 2000)
|
||||
{
|
||||
free(wav);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(channels == 2)
|
||||
{
|
||||
samplecount = datalength/(bitpersample>>2);
|
||||
}
|
||||
else
|
||||
{
|
||||
samplecount = datalength/((bitpersample>>2)>>1);
|
||||
}
|
||||
|
||||
if(samplecount <= 0)
|
||||
{
|
||||
free(wav);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wav->channels = channels;
|
||||
wav->sampleRate = samplerate;
|
||||
wav->sampleCount = samplecount;
|
||||
wav->dataLength = datalength;
|
||||
wav->data = wavfile + 0x2c;
|
||||
wav->rateRatio = (samplerate*0x4000)/11025;
|
||||
wav->playPtr = 0;
|
||||
wav->playPtr_frac= 0;
|
||||
wav->loop = 0;
|
||||
vitaWavIdFlag++;
|
||||
wav->id = vitaWavIdFlag;
|
||||
wav->bitPerSample = bitpersample;
|
||||
|
||||
return wav;
|
||||
}
|
||||
|
||||
vitaWav *vitaWavLoad(const char *filename)
|
||||
{
|
||||
unsigned long filelen;
|
||||
|
||||
unsigned char *wavfile;
|
||||
vitaWav *wav;
|
||||
|
||||
int fd = sceIoOpen(filename, SCE_O_RDONLY, 0777);
|
||||
|
||||
if(fd < 0)
|
||||
return NULL;
|
||||
|
||||
long lSize;
|
||||
|
||||
lSize = sceIoLseek32(fd, 0, SCE_SEEK_END);
|
||||
sceIoLseek32(fd, 0, SCE_SEEK_SET);
|
||||
|
||||
wav = malloc(lSize + sizeof(wav));
|
||||
wavfile = (unsigned char*)(wav) + sizeof(wav);
|
||||
|
||||
filelen = sceIoRead(fd, wavfile, lSize);
|
||||
|
||||
sceIoClose(fd);
|
||||
|
||||
return(vitaWavLoadInternal(wav, wavfile, filelen));
|
||||
}
|
||||
|
||||
vitaWav *vitaWavLoadMemory(const unsigned char *buffer, int size)
|
||||
{
|
||||
unsigned char *wavfile;
|
||||
vitaWav *wav;
|
||||
|
||||
wav = malloc(size + sizeof(wav));
|
||||
wavfile = (unsigned char*)(wav) + sizeof(wav);
|
||||
|
||||
memcpy(wavfile, (unsigned char*)buffer, size);
|
||||
|
||||
return(vitaWavLoadInternal(wav, wavfile, size));
|
||||
}
|
||||
|
||||
void vitaWavUnload(vitaWav *wav)
|
||||
{
|
||||
if(wav != NULL)
|
||||
free(wav);
|
||||
}
|
116
audio/vita_audio.h
Normal file
116
audio/vita_audio.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* vitaWav.h: Header for WAV audio playback
|
||||
* This file is part of the "Phoenix Game Engine".
|
||||
*
|
||||
* Copyright (C) 2007 Phoenix Game Engine
|
||||
* Copyright (C) 2007 InsertWittyName <tias_dp@hotmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VITA_AUDIO_H__
|
||||
#define __VITA_AUDIO_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @defgroup vitaWav WAV Library
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* A WAV file struct
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned long channels; /**< Number of channels */
|
||||
unsigned long sampleRate; /**< Sample rate */
|
||||
unsigned long sampleCount; /**< Sample count */
|
||||
unsigned long dataLength; /**< Data length */
|
||||
unsigned long rateRatio; /**< Rate ratio (sampleRate / 44100 * 0x10000) */
|
||||
unsigned long playPtr; /**< Internal */
|
||||
unsigned long playPtr_frac; /**< Internal */
|
||||
unsigned int loop; /**< Loop flag */
|
||||
unsigned char *data; /**< A pointer to the actual WAV data */
|
||||
unsigned long id; /**< The ID of the WAV */
|
||||
unsigned int bitPerSample; /**< The bit rate of the WAV */
|
||||
} vitaWav;
|
||||
|
||||
/**
|
||||
* Initialise the WAV playback
|
||||
*
|
||||
* @returns 1 on success.
|
||||
*/
|
||||
int vitaWavInit(void);
|
||||
|
||||
/**
|
||||
* Shutdown WAV playback
|
||||
*/
|
||||
void vitaWavShutdown(void);
|
||||
|
||||
/**
|
||||
* Load a WAV file
|
||||
*
|
||||
* @param filename - Path of the file to load.
|
||||
*
|
||||
* @returns A pointer to a ::vitaWav struct or NULL on error.
|
||||
*/
|
||||
vitaWav *vitaWavLoad(const char *filename);
|
||||
|
||||
/**
|
||||
* Load a WAV file from memory
|
||||
*
|
||||
* @param buffer - Buffer that contains the WAV data.
|
||||
*
|
||||
* @param size - Size of the buffer.
|
||||
*
|
||||
* @returns A pointer to a ::vitaWav struct or NULL on error.
|
||||
*/
|
||||
vitaWav *vitaWavLoadMemory(const unsigned char *buffer, int size);
|
||||
|
||||
/**
|
||||
* Unload a previously loaded WAV file
|
||||
*
|
||||
* @param wav - A valid ::vitaWav
|
||||
*/
|
||||
void vitaWavUnload(vitaWav *wav);
|
||||
|
||||
/**
|
||||
* Start playing a loaded WAV file
|
||||
*
|
||||
* @param wav A pointer to a valid ::vitaWav struct.
|
||||
*
|
||||
* @returns 1 on success
|
||||
*/
|
||||
int vitaWavPlay(vitaWav *wav);
|
||||
|
||||
/**
|
||||
* Stop playing a loaded WAV
|
||||
*
|
||||
* @param wav A pointer to a valid ::vitaWav struct.
|
||||
*
|
||||
* @returns 1 on success
|
||||
*/
|
||||
void vitaWavStop(vitaWav *wav);
|
||||
|
||||
/**
|
||||
* Stop playing all WAVs
|
||||
*/
|
||||
void vitaWavStopAll(void);
|
||||
|
||||
/**
|
||||
* Set the loop of the WAV playback
|
||||
*
|
||||
* @param wav - A pointer to a valid ::vitaWav struct.
|
||||
*
|
||||
* @param loop - Set to 1 to loop, 0 to playback once.
|
||||
*/
|
||||
void vitaWavLoop(vitaWav *wav, unsigned int loop);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // __PGEWAV_H__
|
582
audioplayer.c
582
audioplayer.c
@ -1,455 +1,181 @@
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2016
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "archive.h"
|
||||
#include "photo.h"
|
||||
#include "file.h"
|
||||
#include "theme.h"
|
||||
#include "utils.h"
|
||||
#include "audioplayer.h"
|
||||
|
||||
#define lerp(value, from_max, to_max) ((((value*10) * (to_max*10))/(from_max*10))/10)
|
||||
|
||||
static SceUID sEventAudioHolder = -1;
|
||||
static SceUID sThreadAudioHolder = -1;
|
||||
static AudioOutConfig sAudioOutConfigHolder;
|
||||
static bool sIsPausing = false;
|
||||
static bool sIsRunning = false;
|
||||
|
||||
static unsigned int sCodecType;
|
||||
static char *sInputFileName;
|
||||
|
||||
void setCodecType(unsigned int codecType) {
|
||||
sCodecType = codecType;
|
||||
}
|
||||
|
||||
void setInputFileName(char *file) {
|
||||
sInputFileName = file;
|
||||
}
|
||||
|
||||
void togglePause() {
|
||||
sIsPausing = !sIsPausing;
|
||||
}
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2016, TheFloW
|
||||
|
||||
bool isPausing() {
|
||||
return sIsPausing;
|
||||
}
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
void stopAudioThread() {
|
||||
sIsRunning = false;
|
||||
}
|
||||
|
||||
bool isRunning() {
|
||||
return sIsRunning;
|
||||
}
|
||||
|
||||
void resetAudioPlayer() {
|
||||
sIsRunning = true;
|
||||
sIsPausing = false;
|
||||
}
|
||||
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.
|
||||
|
||||
int initAudioDecoderByType(SceAudiodecCtrl *pAudiodecCtrl, AudioFileStream *pInputStream, AudioOutConfig *pAudioOutConfig, int codecType)
|
||||
{
|
||||
int returnValue = 0;
|
||||
pInputStream->offsetRead = 0;
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
pAudiodecCtrl->wordLength = SCE_AUDIODEC_WORD_LENGTH_16BITS;
|
||||
pAudiodecCtrl->size = sizeof(SceAudiodecCtrl);
|
||||
if (codecType == SCE_AUDIODEC_TYPE_MP3) {
|
||||
int sampleRateMpeg[4][3] = {
|
||||
{11025, 12000, 8000}, {0, 0, 0}, {22050, 24000, 16000}, {44100, 48000, 32000}
|
||||
};
|
||||
int audioChannelsMpeg[4] = {2, 2, 2, 1};
|
||||
|
||||
int sync = (pInputStream->pBuffer[0] & 0xFF) << 4 | (pInputStream->pBuffer[1] & 0xE0) >> 4;
|
||||
if (sync != 0xFFE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int version = (pInputStream->pBuffer[1] & 0x18) >> 3;
|
||||
pAudiodecCtrl->pInfo->mp3.version = version;
|
||||
int chMode = audioChannelsMpeg[(pInputStream->pBuffer[3] & 0xC0) >> 6];
|
||||
pAudiodecCtrl->pInfo->mp3.ch = chMode;
|
||||
pAudiodecCtrl->pInfo->size = sizeof(pAudiodecCtrl->pInfo->mp3);
|
||||
#include "main.h"
|
||||
#include "archive.h"
|
||||
#include "audioplayer.h"
|
||||
#include "file.h"
|
||||
#include "theme.h"
|
||||
#include "utils.h"
|
||||
|
||||
returnValue = sceAudiodecCreateDecoder(pAudiodecCtrl, SCE_AUDIODEC_TYPE_MP3);
|
||||
if (returnValue >= 0 && pAudioOutConfig != NULL) {
|
||||
int indexBitRate = sampleRateMpeg[(pInputStream->pBuffer[1] & 0x18) >> 3][(pInputStream->pBuffer[2] & 0x06) >> 2];
|
||||
pAudioOutConfig->samplingRate = indexBitRate;
|
||||
pAudioOutConfig->ch = pAudiodecCtrl->pInfo->mp3.ch;
|
||||
pAudioOutConfig->param = SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO;
|
||||
pAudioOutConfig->grain = pAudiodecCtrl->maxPcmSize / pAudiodecCtrl->pInfo->mp3.ch / sizeof(int16_t);
|
||||
}
|
||||
} else if (codecType == SCE_AUDIODEC_TYPE_AT9) {
|
||||
//TODO
|
||||
} else if (codecType == SCE_AUDIODEC_TYPE_AAC) {
|
||||
//TODO
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
#include "audio/id3.h"
|
||||
#include "audio/info.h"
|
||||
#include "audio/mp3player.h"
|
||||
|
||||
int decodeCurrentAudio(SceAudiodecCtrl *pAudiodecCtrl, AudioFileStream *pInputStream, AudioFileStream *pOutputBuffer)
|
||||
{
|
||||
int returnValue = 0;
|
||||
struct fileInfo *fileinfo = NULL;
|
||||
vita2d_texture *tex = NULL;
|
||||
|
||||
pAudiodecCtrl->pPcm = pOutputBuffer->pBuffer + pOutputBuffer->offsetWrite;
|
||||
pAudiodecCtrl->pEs = pInputStream->pBuffer + pInputStream->offsetRead;
|
||||
void getMp3Info(char *file) {
|
||||
char *buffer = NULL;
|
||||
|
||||
returnValue = sceAudiodecDecode(pAudiodecCtrl);
|
||||
if (returnValue >= 0) {
|
||||
pInputStream->offsetRead += pAudiodecCtrl->inputEsSize;
|
||||
pOutputBuffer->offsetWrite = (pOutputBuffer->offsetWrite + pOutputBuffer->sizeBuffer / 2) % pOutputBuffer->sizeBuffer;
|
||||
fileinfo = MP3_GetInfo();
|
||||
|
||||
if (tex) {
|
||||
vita2d_free_texture(tex);
|
||||
tex = NULL;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int initAudioOut(AudioOutConfig *pAudioOutConfig) {
|
||||
int returnValue = 0;
|
||||
if (pAudioOutConfig->portId < 0) {
|
||||
returnValue = sceAudioOutOpenPort(pAudioOutConfig->portType, pAudioOutConfig->grain, pAudioOutConfig->samplingRate, pAudioOutConfig->param);
|
||||
if (returnValue >= 0) {
|
||||
pAudioOutConfig->portId = returnValue;
|
||||
returnValue = sceAudioOutSetVolume(pAudioOutConfig->portId, (SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH), pAudioOutConfig->volume);
|
||||
switch (fileinfo->encapsulatedPictureType) {
|
||||
case JPEG_IMAGE:
|
||||
case PNG_IMAGE:
|
||||
{
|
||||
SceUID fd = sceIoOpen(file, SCE_O_RDONLY, 0);
|
||||
if (fd >= 0) {
|
||||
char *buffer = malloc(fileinfo->encapsulatedPictureLength);
|
||||
if (buffer) {
|
||||
sceIoLseek32(fd, fileinfo->encapsulatedPictureOffset, SCE_SEEK_SET);
|
||||
sceIoRead(fd, buffer, fileinfo->encapsulatedPictureLength);
|
||||
sceIoClose(fd);
|
||||
|
||||
if (fileinfo->encapsulatedPictureType == JPEG_IMAGE)
|
||||
tex = vita2d_load_JPEG_buffer(buffer, fileinfo->encapsulatedPictureLength);
|
||||
|
||||
if (fileinfo->encapsulatedPictureType == PNG_IMAGE)
|
||||
tex = vita2d_load_PNG_buffer(buffer);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int outputCurrentAudio(AudioOutConfig *pAudioOutConfig, AudioFileStream *pOutputStream) {
|
||||
int returnValue = 0;
|
||||
if (pOutputStream != NULL) {
|
||||
returnValue = sceAudioOutOutput(pAudioOutConfig->portId, pOutputStream->pBuffer + pOutputStream->offsetRead);
|
||||
if (returnValue >= 0) {
|
||||
pOutputStream->offsetRead = (pOutputStream->offsetRead + pOutputStream->sizeBuffer / 2) % pOutputStream->sizeBuffer;
|
||||
}
|
||||
} else {
|
||||
returnValue = sceAudioOutOutput(pAudioOutConfig->portId, NULL);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int audioOutThread(int argSize, void *pArgBlock) {
|
||||
int returnValue = 0;
|
||||
int pcmSize = 0;
|
||||
|
||||
AudioOutConfig *pAudioOutConfig;
|
||||
pAudioOutConfig = &sAudioOutConfigHolder;
|
||||
|
||||
AudioFileStream input;
|
||||
input.pNameFile = sInputFileName;
|
||||
input.sizeFile = 0;
|
||||
input.pBuffer = NULL;
|
||||
input.offsetRead = 0;
|
||||
input.offsetWrite = 0;
|
||||
int audioPlayer(char *file, int type, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos) {
|
||||
MP3_Init(0);
|
||||
MP3_Load(file);
|
||||
MP3_Play();
|
||||
|
||||
AudioFileStream output;
|
||||
output.sizeFile = 0;
|
||||
output.pBuffer = NULL;
|
||||
output.offsetRead = 0;
|
||||
output.offsetWrite = 0;
|
||||
getMp3Info(file);
|
||||
|
||||
SceAudiodecInfo audiodecInfo;
|
||||
SceAudiodecCtrl audiodecCtrl;
|
||||
memset(&audiodecInfo, 0, sizeof(SceAudiodecInfo));
|
||||
memset(&audiodecCtrl, 0, sizeof(SceAudiodecCtrl));
|
||||
audiodecCtrl.pInfo = &audiodecInfo;
|
||||
while (1) {
|
||||
readPad();
|
||||
|
||||
returnValue = getFileSize(input.pNameFile);
|
||||
if (returnValue > 0) {
|
||||
input.sizeFile = returnValue;
|
||||
int maxEsSize = 0;
|
||||
if (sCodecType == SCE_AUDIODEC_TYPE_MP3) {
|
||||
maxEsSize = SCE_AUDIODEC_MP3_MAX_ES_SIZE;
|
||||
} else if (sCodecType == SCE_AUDIODEC_TYPE_AT9) {
|
||||
maxEsSize = SCE_AUDIODEC_AT9_MAX_ES_SIZE;
|
||||
} else if (sCodecType == SCE_AUDIODEC_TYPE_AAC) {
|
||||
maxEsSize = SCE_AUDIODEC_AAC_MAX_ES_SIZE;
|
||||
}
|
||||
if(maxEsSize > 0) {
|
||||
input.sizeBuffer = SCE_AUDIODEC_ROUND_UP(input.sizeFile + maxEsSize);
|
||||
input.pBuffer = memalign(SCE_AUDIODEC_ALIGNMENT_SIZE, input.sizeBuffer);
|
||||
returnValue = ReadFile(input.pNameFile, input.pBuffer, input.sizeFile);
|
||||
if (returnValue >= 0) {
|
||||
input.offsetWrite = input.sizeFile;
|
||||
returnValue = initAudioDecoderByType(&audiodecCtrl, &input, pAudioOutConfig, sCodecType);
|
||||
if (returnValue >= 0) {
|
||||
pcmSize = sizeof(int16_t) * pAudioOutConfig->ch * pAudioOutConfig->grain;
|
||||
output.sizeBuffer = SCE_AUDIODEC_ROUND_UP(pcmSize) * 2;
|
||||
output.pBuffer = memalign(SCE_AUDIODEC_ALIGNMENT_SIZE, output.sizeBuffer);
|
||||
returnValue = initAudioOut(pAudioOutConfig);
|
||||
if (returnValue >= 0) {
|
||||
sceKernelSetEventFlag(sEventAudioHolder, 0x00000001U);
|
||||
//Playing Track :)
|
||||
while (isRunning()) {
|
||||
if(isPausing()) {
|
||||
sceKernelDelayThread(1000);
|
||||
} else {
|
||||
if (input.sizeFile <= input.offsetRead) {
|
||||
break;
|
||||
}
|
||||
|
||||
returnValue = decodeCurrentAudio(&audiodecCtrl, &input, &output);
|
||||
if (returnValue < 0) {
|
||||
break;
|
||||
}
|
||||
// Cancel
|
||||
if (pressed_buttons & SCE_CTRL_CANCEL) {
|
||||
break;
|
||||
}
|
||||
|
||||
returnValue = outputCurrentAudio(pAudioOutConfig, &output);
|
||||
if (returnValue < 0) {
|
||||
break;
|
||||
}
|
||||
// Previous/next song.
|
||||
if (MP3_EndOfStream() || pressed_buttons & SCE_CTRL_LTRIGGER || pressed_buttons & SCE_CTRL_RTRIGGER) {
|
||||
int available = 0;
|
||||
|
||||
int old_base_pos = *base_pos;
|
||||
int old_rel_pos = *rel_pos;
|
||||
FileListEntry *old_entry = entry;
|
||||
|
||||
int previous = pressed_buttons & SCE_CTRL_LTRIGGER;
|
||||
if (MP3_EndOfStream())
|
||||
previous = 0;
|
||||
|
||||
while (previous ? entry->previous : entry->next) {
|
||||
entry = previous ? entry->previous : entry->next;
|
||||
|
||||
if (previous) {
|
||||
if (*rel_pos > 0) {
|
||||
(*rel_pos)--;
|
||||
} else {
|
||||
if (*base_pos > 0) {
|
||||
(*base_pos)--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((*rel_pos + 1) < list->length) {
|
||||
if ((*rel_pos + 1) < MAX_POSITION) {
|
||||
(*rel_pos)++;
|
||||
} else {
|
||||
if ((*base_pos + *rel_pos + 1) < list->length) {
|
||||
(*base_pos)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
outputCurrentAudio(pAudioOutConfig, NULL);
|
||||
|
||||
if (pAudioOutConfig->portId >= 0) {
|
||||
returnValue = sceAudioOutReleasePort(pAudioOutConfig->portId);
|
||||
pAudioOutConfig->portId = -1;
|
||||
}
|
||||
|
||||
returnValue = sceAudiodecDeleteDecoder(&audiodecCtrl);
|
||||
if (output.pBuffer != NULL) {
|
||||
free(output.pBuffer);
|
||||
output.pBuffer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (input.pBuffer != NULL) {
|
||||
free(input.pBuffer);
|
||||
input.pBuffer = NULL;
|
||||
}
|
||||
if (!entry->is_folder) {
|
||||
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);
|
||||
available = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int shutdownAudioPlayer() {
|
||||
int returnValue = 0;
|
||||
|
||||
if (sThreadAudioHolder >= 0) {
|
||||
returnValue = sceKernelWaitThreadEnd(sThreadAudioHolder, NULL, NULL);
|
||||
returnValue = sceKernelDeleteThread(sThreadAudioHolder);
|
||||
sThreadAudioHolder = -1;
|
||||
}
|
||||
|
||||
if (sEventAudioHolder >= 0) {
|
||||
returnValue = sceKernelDeleteEventFlag(sEventAudioHolder);
|
||||
sEventAudioHolder = -1;
|
||||
}
|
||||
|
||||
returnValue = sceAudiodecTermLibrary(sCodecType);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int startAudioPlayer()
|
||||
{
|
||||
int returnValue = 0;
|
||||
|
||||
AudioOutConfig *pAudioOutConfig = &sAudioOutConfigHolder;
|
||||
|
||||
pAudioOutConfig->portId = -1;
|
||||
pAudioOutConfig->portType = SCE_AUDIO_OUT_PORT_TYPE_MAIN;
|
||||
pAudioOutConfig->samplingRate = 0;
|
||||
pAudioOutConfig->volume[0] = pAudioOutConfig->volume[1] = SCE_AUDIO_VOLUME_0DB / 4;
|
||||
pAudioOutConfig->ch = 0;
|
||||
pAudioOutConfig->param = 0;
|
||||
pAudioOutConfig->grain = 0;
|
||||
|
||||
SceAudiodecInitParam audiodecInitParam;
|
||||
memset(&audiodecInitParam, 0, sizeof(audiodecInitParam));
|
||||
|
||||
if(sCodecType == SCE_AUDIODEC_TYPE_AT9) {
|
||||
//TODO
|
||||
} else if (sCodecType == SCE_AUDIODEC_TYPE_MP3) {
|
||||
audiodecInitParam.size = sizeof(audiodecInitParam.mp3);
|
||||
audiodecInitParam.mp3.totalStreams = 1;
|
||||
} else if (sCodecType == SCE_AUDIODEC_TYPE_AAC) {
|
||||
//TODO
|
||||
} else {
|
||||
returnValue = -1;
|
||||
}
|
||||
|
||||
if (returnValue >= 0) {
|
||||
returnValue = sceAudiodecInitLibrary(sCodecType, &audiodecInitParam);
|
||||
if (returnValue >= 0) {
|
||||
returnValue = sceKernelCreateEventFlag("AudioOutThread", 0x00001000, 0, NULL);
|
||||
if (returnValue >= 0) {
|
||||
sEventAudioHolder = returnValue;
|
||||
returnValue = sceKernelCreateThread("AudioOutThread", (void*)&audioOutThread, 64, 0x1000U, 0, 0, NULL);
|
||||
if (returnValue >= 0) {
|
||||
sThreadAudioHolder = returnValue;
|
||||
returnValue = sceKernelStartThread(sThreadAudioHolder, 0, NULL);
|
||||
if (returnValue >= 0) {
|
||||
sceKernelWaitEventFlag(sEventAudioHolder, 0x00000001U, 0, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!available) {
|
||||
*base_pos = old_base_pos;
|
||||
*rel_pos = old_rel_pos;
|
||||
entry = old_entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Start drawing
|
||||
startDrawing(NULL);
|
||||
|
||||
// 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);
|
||||
|
||||
// Picture
|
||||
if (tex)
|
||||
vita2d_draw_texture_scale(tex, SHELL_MARGIN_X, 200.0f, 1.0f, 1.0f);
|
||||
|
||||
// Time
|
||||
char string[12];
|
||||
MP3_GetTimeString(string);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
if (returnValue < 0) {
|
||||
shutdownAudioPlayer();
|
||||
if (tex) {
|
||||
vita2d_free_texture(tex);
|
||||
tex = NULL;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
MP3_End();
|
||||
|
||||
int audioPlayer(char *file, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos, unsigned int codec_type, int showInterface) {
|
||||
int returnCode = 0;
|
||||
bool isTouched = false;
|
||||
|
||||
SceTouchData touch;
|
||||
|
||||
if(isRunning()) {
|
||||
stopAudioThread();
|
||||
returnCode = shutdownAudioPlayer();
|
||||
}
|
||||
|
||||
resetAudioPlayer();
|
||||
|
||||
setCodecType(codec_type);
|
||||
setInputFileName(file);
|
||||
|
||||
returnCode = startAudioPlayer();
|
||||
if(showInterface == 1) {
|
||||
// Main loop
|
||||
while (isRunning()) {
|
||||
readPad();
|
||||
sceTouchPeek(0, &touch, 1);
|
||||
|
||||
int checkPrevNexFlag = -1;
|
||||
|
||||
if (touch.reportNum > 0 && !isTouched) {
|
||||
int x = lerp(touch.report[0].x, 1920, SCREEN_WIDTH);
|
||||
int y = lerp(touch.report[0].y, 1088, SCREEN_HEIGHT);
|
||||
if(x >= SCREEN_WIDTH / 2 - 200 && x <= SCREEN_WIDTH / 2 - 80 && y >= SCREEN_HEIGHT - 170 && y <= SCREEN_HEIGHT - 50) {
|
||||
checkPrevNexFlag = 1;
|
||||
} else if(x >= SCREEN_WIDTH / 2 - 60 && x <= SCREEN_WIDTH / 2 + 60 && y >= SCREEN_HEIGHT - 170 && y <= SCREEN_HEIGHT - 50) {
|
||||
checkPrevNexFlag = 0;
|
||||
} else if(x >= SCREEN_WIDTH / 2 + 80 && x <= SCREEN_WIDTH / 2 + 200 && y >= SCREEN_HEIGHT - 170 && y <= SCREEN_HEIGHT - 50) {
|
||||
togglePause();
|
||||
}
|
||||
isTouched = true;
|
||||
} else if (touch.reportNum <= 0) {
|
||||
isTouched = false;
|
||||
}
|
||||
|
||||
// Pause or resume if START button pressed
|
||||
if (pressed_buttons & SCE_CTRL_START) {
|
||||
togglePause();
|
||||
}
|
||||
|
||||
// Exit if SELECT button pressed
|
||||
if (pressed_buttons & SCE_CTRL_CANCEL) {
|
||||
stopAudioThread();
|
||||
}
|
||||
|
||||
// Next if R Trigger pressed
|
||||
if (pressed_buttons & SCE_CTRL_RTRIGGER) {
|
||||
checkPrevNexFlag = 0;
|
||||
}
|
||||
|
||||
// Previous if L Trigger pressed
|
||||
if (pressed_buttons & SCE_CTRL_LTRIGGER) {
|
||||
checkPrevNexFlag = 1;
|
||||
}
|
||||
|
||||
if(checkPrevNexFlag >= 0) {
|
||||
int available = 0;
|
||||
|
||||
int old_base_pos = *base_pos;
|
||||
int old_rel_pos = *rel_pos;
|
||||
FileListEntry *old_entry = entry;
|
||||
while (checkPrevNexFlag ? entry->previous : entry->next) {
|
||||
entry = checkPrevNexFlag ? entry->previous : entry->next;
|
||||
if (checkPrevNexFlag) {
|
||||
if (*rel_pos > 0) {
|
||||
(*rel_pos)--;
|
||||
} else {
|
||||
if (*base_pos > 0) {
|
||||
(*base_pos)--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((*rel_pos + 1) < list->length) {
|
||||
if ((*rel_pos + 1) < MAX_POSITION) {
|
||||
(*rel_pos)++;
|
||||
} else {
|
||||
if ((*base_pos + *rel_pos + 1) < list->length) {
|
||||
(*base_pos)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry->is_folder) {
|
||||
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) {
|
||||
stopAudioThread();
|
||||
int returnCode = shutdownAudioPlayer();
|
||||
resetAudioPlayer();
|
||||
setCodecType(SCE_AUDIODEC_TYPE_MP3);
|
||||
setInputFileName(path);
|
||||
startAudioPlayer();
|
||||
available = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!available) {
|
||||
*base_pos = old_base_pos;
|
||||
*rel_pos = old_rel_pos;
|
||||
entry = old_entry;
|
||||
}
|
||||
}
|
||||
|
||||
// Start drawing
|
||||
startDrawing(NULL);
|
||||
int nameLength = strlen(entry->name);
|
||||
vita2d_pgf_draw_text(font, SCREEN_WIDTH / 2 - nameLength * 5.5, SCREEN_HEIGHT - 190, GENERAL_COLOR, 1.0f, entry->name);
|
||||
|
||||
vita2d_draw_texture(headphone_image, SCREEN_WIDTH / 2 - 150, 20);
|
||||
vita2d_draw_texture(audio_previous_image, SCREEN_WIDTH / 2 - 200, SCREEN_HEIGHT - 170);
|
||||
vita2d_draw_texture(audio_next_image, SCREEN_WIDTH / 2 - 60, SCREEN_HEIGHT - 170);
|
||||
if(isPausing()) {
|
||||
vita2d_draw_texture(audio_play_image, SCREEN_WIDTH / 2 + 80, SCREEN_HEIGHT - 170);
|
||||
} else {
|
||||
vita2d_draw_texture(audio_pause_image, SCREEN_WIDTH / 2 + 80, SCREEN_HEIGHT - 170);
|
||||
}
|
||||
|
||||
// End drawing
|
||||
endDrawing();
|
||||
|
||||
sceKernelDelayThread(1000);
|
||||
}
|
||||
|
||||
returnCode = shutdownAudioPlayer();
|
||||
resetAudioPlayer();
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,46 +1,24 @@
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2016
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2016, TheFloW
|
||||
|
||||
#ifndef __AUDIOPLAYER_H__
|
||||
#define __AUDIOPLAYER_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
typedef struct AudioFileStream {
|
||||
char *pNameFile;
|
||||
int sizeFile;
|
||||
|
||||
uint8_t *pBuffer;
|
||||
int offsetRead;
|
||||
int offsetWrite;
|
||||
int sizeBuffer;
|
||||
} AudioFileStream;
|
||||
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.
|
||||
|
||||
typedef struct AudioOutConfig {
|
||||
int portId;
|
||||
int portType;
|
||||
int ch;
|
||||
int volume[2];
|
||||
int samplingRate;
|
||||
int param;
|
||||
int grain;
|
||||
} AudioOutConfig;
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
extern int audioPlayer(char *file, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos, unsigned int codec_type, int showInterface);
|
||||
|
||||
#endif
|
||||
#ifndef __AUDIOPLAYER_H__
|
||||
#define __AUDIOPLAYER_H__
|
||||
|
||||
int audioPlayer(char *file, int type, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos);
|
||||
|
||||
#endif
|
68
bm.c
Normal file
68
bm.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
const char * boyer_moore(const char *haystack, const char *needle) {
|
||||
size_t plen = strlen(needle), slen = strlen(haystack);
|
||||
|
||||
if (plen > slen) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int skip[UCHAR_MAX+1];
|
||||
int i, j, k, * next;
|
||||
|
||||
/* calc skip table („bad rule“) */
|
||||
for (i = 0; i <= UCHAR_MAX; i++) {
|
||||
skip[i] = plen;
|
||||
}
|
||||
|
||||
for (i = 0; i < plen; i++) {
|
||||
skip[tolower((unsigned char)needle[i])] = plen - i - 1;
|
||||
}
|
||||
|
||||
|
||||
/* calc next table („good rule“) */
|
||||
next = (int*)malloc((plen+1) * sizeof(int));
|
||||
|
||||
for (j = 0; j <= plen; j++) {
|
||||
for (i = plen - 1; i >= 1; i--) {
|
||||
for (k = 1; k <= j; k++) {
|
||||
if (i - k < 0) {
|
||||
break;
|
||||
}
|
||||
if (tolower((unsigned char)needle[plen - k]) != tolower((unsigned char)needle[i - k])) {
|
||||
goto nexttry;
|
||||
}
|
||||
}
|
||||
goto matched;
|
||||
nexttry:
|
||||
;
|
||||
}
|
||||
matched:
|
||||
next[j] = plen - i;
|
||||
}
|
||||
|
||||
plen--;
|
||||
i = plen; /* position of last p letter in s */
|
||||
|
||||
while (i < slen) {
|
||||
j = 0; /* matched letter count */
|
||||
while (j <= plen) {
|
||||
if (tolower((unsigned char)haystack[i - j]) == tolower((unsigned char)needle[plen - j])) {
|
||||
j++;
|
||||
} else {
|
||||
i += skip[tolower((unsigned char)haystack[i - j])] > next[j] ? skip[tolower((unsigned char)haystack[i - j])] - j : next[j];
|
||||
goto newi;
|
||||
}
|
||||
}
|
||||
free(next);
|
||||
return haystack + i - plen;
|
||||
newi:
|
||||
;
|
||||
}
|
||||
free(next);
|
||||
return NULL;
|
||||
}
|
6
bm.h
Normal file
6
bm.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __BM_H__
|
||||
#define __BM_H__
|
||||
|
||||
char * boyer_moore(const char *haystack, const char *needle);
|
||||
|
||||
#endif
|
235
context_menu.c
Normal file
235
context_menu.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2016, TheFloW
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "context_menu.h"
|
||||
#include "theme.h"
|
||||
#include "language.h"
|
||||
#include "utils.h"
|
||||
|
||||
static int ctx_menu_mode = CONTEXT_MENU_CLOSED;
|
||||
static int ctx_menu_pos = -1;
|
||||
static int ctx_menu_more_pos = -1;
|
||||
static float ctx_cur_menu_width = 0.0f;
|
||||
|
||||
int getContextMenuPos() {
|
||||
return ctx_menu_pos;
|
||||
}
|
||||
|
||||
void setContextMenuPos(int pos) {
|
||||
ctx_menu_pos = pos;
|
||||
}
|
||||
|
||||
int getContextMenuMorePos() {
|
||||
return ctx_menu_more_pos;
|
||||
}
|
||||
|
||||
void setContextMenuMorePos(int pos) {
|
||||
ctx_menu_more_pos = pos;
|
||||
}
|
||||
|
||||
int getContextMenuMode() {
|
||||
return ctx_menu_mode;
|
||||
}
|
||||
|
||||
void setContextMenuMode(int mode) {
|
||||
ctx_menu_mode = mode;
|
||||
}
|
||||
|
||||
float easeOut(float x0, float x1, float a) {
|
||||
float dx = (x1 - x0);
|
||||
return ((dx * a) > 0.5f) ? (dx * a) : dx;
|
||||
}
|
||||
|
||||
void drawContextMenu(ContextMenu *ctx) {
|
||||
// Closing context menu
|
||||
if (ctx_menu_mode == CONTEXT_MENU_CLOSING) {
|
||||
if (ctx_cur_menu_width > 0.0f) {
|
||||
ctx_cur_menu_width -= easeOut(0.0f, ctx_cur_menu_width, 0.375f);
|
||||
} else {
|
||||
ctx_menu_mode = CONTEXT_MENU_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
// Opening context menu
|
||||
if (ctx_menu_mode == CONTEXT_MENU_OPENING) {
|
||||
if (ctx_cur_menu_width < ctx->menu_max_width) {
|
||||
ctx_cur_menu_width += easeOut(ctx_cur_menu_width, ctx->menu_max_width, 0.375f);
|
||||
} else {
|
||||
ctx_menu_mode = CONTEXT_MENU_OPENED;
|
||||
}
|
||||
}
|
||||
|
||||
// Closing context menu 'More'
|
||||
if (ctx_menu_mode == CONTEXT_MENU_MORE_CLOSING) {
|
||||
if (ctx_cur_menu_width > ctx->menu_max_width) {
|
||||
ctx_cur_menu_width -= easeOut(ctx->menu_max_width, ctx_cur_menu_width, 0.375f);
|
||||
} else {
|
||||
ctx_menu_mode = CONTEXT_MENU_MORE_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
// Opening context menu 'More'
|
||||
if (ctx_menu_mode == CONTEXT_MENU_MORE_OPENING) {
|
||||
if (ctx_cur_menu_width < ctx->menu_max_width + ctx->menu_more_max_width) {
|
||||
ctx_cur_menu_width += easeOut(ctx_cur_menu_width, ctx->menu_max_width + ctx->menu_more_max_width, 0.375f);
|
||||
} else {
|
||||
ctx_menu_mode = CONTEXT_MENU_MORE_OPENED;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw context menu
|
||||
if (ctx_menu_mode != CONTEXT_MENU_CLOSED) {
|
||||
if (ctx_cur_menu_width < ctx->menu_max_width) {
|
||||
vita2d_draw_texture_part(context_image, SCREEN_WIDTH - ctx_cur_menu_width, 0.0f, 0.0f, 0.0f, ctx_cur_menu_width, SCREEN_HEIGHT);
|
||||
} else {
|
||||
vita2d_draw_texture_part(context_image, SCREEN_WIDTH - ctx_cur_menu_width, 0.0f, 0.0f, 0.0f, ctx->menu_max_width, SCREEN_HEIGHT);
|
||||
vita2d_draw_texture_part(context_more_image, SCREEN_WIDTH - ctx_cur_menu_width + ctx->menu_max_width, 0.0f, 0.0f, 0.0f, ctx->menu_more_max_width, SCREEN_HEIGHT);
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ctx->n_menu_entries; i++) {
|
||||
if (ctx->menu_entries[i].visibility == CTX_VISIBILITY_UNUSED)
|
||||
continue;
|
||||
|
||||
float y = START_Y + (i * FONT_Y_SPACE);
|
||||
|
||||
uint32_t color = CONTEXT_MENU_TEXT_COLOR;
|
||||
|
||||
if (i == ctx_menu_pos) {
|
||||
if (ctx_menu_mode != CONTEXT_MENU_MORE_OPENED && ctx_menu_mode != CONTEXT_MENU_MORE_OPENING) {
|
||||
color = CONTEXT_MENU_FOCUS_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->menu_entries[i].visibility == CTX_VISIBILITY_INVISIBLE)
|
||||
color = INVISIBLE_COLOR;
|
||||
|
||||
// Draw entry text
|
||||
pgf_draw_text(SCREEN_WIDTH - ctx_cur_menu_width + CONTEXT_MENU_MARGIN, y, color, FONT_SIZE, language_container[ctx->menu_entries[i].name]);
|
||||
|
||||
// Draw arrow for 'More'
|
||||
if (i == ctx->more_pos) {
|
||||
char *arrow = NULL;
|
||||
if (ctx_menu_mode == CONTEXT_MENU_MORE_OPENED || ctx_menu_mode == CONTEXT_MENU_MORE_OPENING) {
|
||||
arrow = LEFT_ARROW;
|
||||
} else {
|
||||
arrow = RIGHT_ARROW;
|
||||
}
|
||||
|
||||
pgf_draw_text(SCREEN_WIDTH - ctx_cur_menu_width + ctx->menu_max_width - vita2d_pgf_text_width(font, FONT_SIZE, arrow) - CONTEXT_MENU_MARGIN, y, color, FONT_SIZE, arrow);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx_menu_mode == CONTEXT_MENU_MORE_CLOSING || ctx_menu_mode == CONTEXT_MENU_MORE_OPENED || ctx_menu_mode == CONTEXT_MENU_MORE_OPENING) {
|
||||
for (i = 0; i < ctx->n_menu_more_entries; i++) {
|
||||
if (ctx->menu_more_entries[i].visibility == CTX_VISIBILITY_UNUSED)
|
||||
continue;
|
||||
|
||||
float y = START_Y + ((ctx->more_pos + i) * FONT_Y_SPACE);
|
||||
|
||||
uint32_t color = CONTEXT_MENU_TEXT_COLOR;
|
||||
|
||||
if (i == ctx_menu_more_pos) {
|
||||
if (ctx_menu_mode != CONTEXT_MENU_MORE_CLOSING) {
|
||||
color = CONTEXT_MENU_FOCUS_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->menu_more_entries[i].visibility == CTX_VISIBILITY_INVISIBLE)
|
||||
color = INVISIBLE_COLOR;
|
||||
|
||||
// Draw entry text
|
||||
pgf_draw_text(SCREEN_WIDTH - ctx_cur_menu_width + ctx->menu_max_width + CONTEXT_MENU_MARGIN, y, color, FONT_SIZE, language_container[ctx->menu_more_entries[i].name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void contextMenuCtrl(ContextMenu *ctx) {
|
||||
if (hold_buttons & SCE_CTRL_UP || hold2_buttons & SCE_CTRL_LEFT_ANALOG_UP) {
|
||||
if (ctx_menu_mode == CONTEXT_MENU_OPENED) {
|
||||
int i;
|
||||
for (i = ctx->n_menu_entries - 1; i >= 0; i--) {
|
||||
if (ctx->menu_entries[i].visibility == CTX_VISIBILITY_VISIBLE) {
|
||||
if (i < ctx_menu_pos) {
|
||||
ctx_menu_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ctx_menu_mode == CONTEXT_MENU_MORE_OPENED) {
|
||||
int i;
|
||||
for (i = ctx->n_menu_more_entries - 1; i >= 0; i--) {
|
||||
if (ctx->menu_more_entries[i].visibility == CTX_VISIBILITY_VISIBLE) {
|
||||
if (i < ctx_menu_more_pos) {
|
||||
ctx_menu_more_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (hold_buttons & SCE_CTRL_DOWN || hold2_buttons & SCE_CTRL_LEFT_ANALOG_DOWN) {
|
||||
if (ctx_menu_mode == CONTEXT_MENU_OPENED) {
|
||||
int i;
|
||||
for (i = 0; i < ctx->n_menu_entries; i++) {
|
||||
if (ctx->menu_entries[i].visibility == CTX_VISIBILITY_VISIBLE) {
|
||||
if (i > ctx_menu_pos) {
|
||||
ctx_menu_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ctx_menu_mode == CONTEXT_MENU_MORE_OPENED) {
|
||||
int i;
|
||||
for (i = 0; i < ctx->n_menu_more_entries; i++) {
|
||||
if (ctx->menu_more_entries[i].visibility == CTX_VISIBILITY_VISIBLE) {
|
||||
if (i > ctx_menu_more_pos) {
|
||||
ctx_menu_more_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close
|
||||
if (pressed_buttons & SCE_CTRL_TRIANGLE) {
|
||||
ctx_menu_mode = CONTEXT_MENU_CLOSING;
|
||||
}
|
||||
|
||||
// Back
|
||||
if (pressed_buttons & SCE_CTRL_CANCEL || pressed_buttons & SCE_CTRL_LEFT) {
|
||||
if (ctx_menu_mode == CONTEXT_MENU_MORE_OPENED) {
|
||||
ctx_menu_mode = CONTEXT_MENU_MORE_CLOSING;
|
||||
} else {
|
||||
ctx_menu_mode = CONTEXT_MENU_CLOSING;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle
|
||||
if (pressed_buttons & SCE_CTRL_ENTER || pressed_buttons & SCE_CTRL_RIGHT) {
|
||||
if (ctx_menu_mode == CONTEXT_MENU_OPENED) {
|
||||
if (ctx->menuEnterCallback)
|
||||
ctx_menu_mode = ctx->menuEnterCallback(ctx_menu_pos, ctx->context);
|
||||
} else if (ctx_menu_mode == CONTEXT_MENU_MORE_OPENED) {
|
||||
if (ctx->menuMoreEnterCallback)
|
||||
ctx_menu_mode = ctx->menuMoreEnterCallback(ctx_menu_more_pos, ctx->context);
|
||||
}
|
||||
}
|
||||
}
|
70
context_menu.h
Normal file
70
context_menu.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2016, TheFloW
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CONTEXT_MENU_H__
|
||||
#define __CONTEXT_MENU_H__
|
||||
|
||||
#define RIGHT_ARROW "\xE2\x96\xB6"
|
||||
#define LEFT_ARROW "\xE2\x97\x80"
|
||||
|
||||
enum ContextMenuVisibilities {
|
||||
CTX_VISIBILITY_UNUSED,
|
||||
CTX_VISIBILITY_INVISIBLE,
|
||||
CTX_VISIBILITY_VISIBLE,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int name;
|
||||
int visibility;
|
||||
} MenuEntry;
|
||||
|
||||
typedef struct {
|
||||
MenuEntry *menu_entries;
|
||||
int n_menu_entries;
|
||||
MenuEntry *menu_more_entries;
|
||||
int n_menu_more_entries;
|
||||
float menu_max_width;
|
||||
float menu_more_max_width;
|
||||
int more_pos;
|
||||
int (* menuEnterCallback)(int pos, void* context);
|
||||
int (* menuMoreEnterCallback)(int pos, void* context);
|
||||
void *context;
|
||||
} ContextMenu;
|
||||
|
||||
enum ContextMenuModes {
|
||||
CONTEXT_MENU_CLOSED = 0,
|
||||
CONTEXT_MENU_CLOSING = 1,
|
||||
CONTEXT_MENU_OPENED = 2,
|
||||
CONTEXT_MENU_OPENING = 3,
|
||||
CONTEXT_MENU_MORE_CLOSED = 2,
|
||||
CONTEXT_MENU_MORE_CLOSING = 4,
|
||||
CONTEXT_MENU_MORE_OPENED = 5,
|
||||
CONTEXT_MENU_MORE_OPENING = 6,
|
||||
};
|
||||
|
||||
int getContextMenuPos();
|
||||
void setContextMenuPos(int pos);
|
||||
int getContextMenuMorePos();
|
||||
void setContextMenuMorePos(int pos);
|
||||
int getContextMenuMode();
|
||||
void setContextMenuMode(int mode);
|
||||
|
||||
void drawContextMenu(ContextMenu *ctx);
|
||||
void contextMenuCtrl(ContextMenu *ctx);
|
||||
|
||||
#endif
|
271
file.c
271
file.c
@ -20,6 +20,7 @@
|
||||
#include "archive.h"
|
||||
#include "file.h"
|
||||
#include "utils.h"
|
||||
#include "sha1.h"
|
||||
|
||||
static char *mount_points[] = {
|
||||
"app0:",
|
||||
@ -94,6 +95,59 @@ int getFileSize(char *pInputFileName)
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
int getFileSha1(char *pInputFileName, uint8_t *pSha1Out, FileProcessParam *param) {
|
||||
// Set up SHA1 context
|
||||
SHA1_CTX ctx;
|
||||
sha1_init(&ctx);
|
||||
|
||||
// Open the file to read, else return the error
|
||||
SceUID fd = sceIoOpen(pInputFileName, SCE_O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
// Open up the buffer for copying data into
|
||||
void *buf = malloc(TRANSFER_SIZE);
|
||||
|
||||
int read;
|
||||
|
||||
// Actually take the SHA1 sum
|
||||
while ((read = sceIoRead(fd, buf, TRANSFER_SIZE)) > 0) {
|
||||
sha1_update(&ctx, buf, read);
|
||||
|
||||
if (param) {
|
||||
// Defined in io_process.c, check to make sure pointer isn't null before incrementing
|
||||
if (param->value)
|
||||
(*param->value)++; // Note: Max value is filesize/TRANSFER_SIZE
|
||||
|
||||
if (param->SetProgress)
|
||||
param->SetProgress(param->value ? *param->value : 0, param->max);
|
||||
|
||||
// Check to see if param->cancelHandler exists, if so call it and free memory if cancelled
|
||||
if (param->cancelHandler && param->cancelHandler()) {
|
||||
free(buf);
|
||||
sceIoClose(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This is CPU intensive so the progress bar won't refresh unless we sleep
|
||||
// DIALOG_WAIT seemed too long for this application
|
||||
// so I set it to 1/2 of a second every 8192 TRANSFER_SIZE blocks
|
||||
if ((*param->value) % 8192 == 0)
|
||||
sceKernelDelayThread(500000);
|
||||
}
|
||||
}
|
||||
|
||||
// Final iteration of SHA1 sum, dump final value into pSha1Out buffer
|
||||
sha1_final(&ctx, pSha1Out);
|
||||
|
||||
// Free up file buffer
|
||||
free(buf);
|
||||
|
||||
// Close file proper
|
||||
sceIoClose(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int getPathInfo(char *path, uint64_t *size, uint32_t *folders, uint32_t *files) {
|
||||
SceUID dfd = sceIoDopen(path);
|
||||
if (dfd >= 0) {
|
||||
@ -109,7 +163,7 @@ int getPathInfo(char *path, uint64_t *size, uint32_t *folders, uint32_t *files)
|
||||
continue;
|
||||
|
||||
char *new_path = malloc(strlen(path) + strlen(dir.d_name) + 2);
|
||||
snprintf(new_path, MAX_PATH_LENGTH, "%s/%s", path, dir.d_name);
|
||||
snprintf(new_path, MAX_PATH_LENGTH, "%s%s%s", path, hasEndSlash(path) ? "" : "/", dir.d_name);
|
||||
|
||||
if (SCE_S_ISDIR(dir.d_stat.st_mode)) {
|
||||
int ret = getPathInfo(new_path, size, folders, files);
|
||||
@ -153,7 +207,7 @@ int getPathInfo(char *path, uint64_t *size, uint32_t *folders, uint32_t *files)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int removePath(char *path, uint64_t *value, uint64_t max, void (* SetProgress)(uint64_t value, uint64_t max), int (* cancelHandler)()) {
|
||||
int removePath(char *path, FileProcessParam *param) {
|
||||
SceUID dfd = sceIoDopen(path);
|
||||
if (dfd >= 0) {
|
||||
int res = 0;
|
||||
@ -168,10 +222,10 @@ int removePath(char *path, uint64_t *value, uint64_t max, void (* SetProgress)(u
|
||||
continue;
|
||||
|
||||
char *new_path = malloc(strlen(path) + strlen(dir.d_name) + 2);
|
||||
snprintf(new_path, MAX_PATH_LENGTH, "%s/%s", path, dir.d_name);
|
||||
snprintf(new_path, MAX_PATH_LENGTH, "%s%s%s", path, hasEndSlash(path) ? "" : "/", dir.d_name);
|
||||
|
||||
if (SCE_S_ISDIR(dir.d_stat.st_mode)) {
|
||||
int ret = removePath(new_path, value, max, SetProgress, cancelHandler);
|
||||
int ret = removePath(new_path, param);
|
||||
if (ret <= 0) {
|
||||
free(new_path);
|
||||
sceIoDclose(dfd);
|
||||
@ -185,16 +239,18 @@ int removePath(char *path, uint64_t *value, uint64_t max, void (* SetProgress)(u
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (value)
|
||||
(*value)++;
|
||||
if (param) {
|
||||
if (param->value)
|
||||
(*param->value)++;
|
||||
|
||||
if (SetProgress)
|
||||
SetProgress(value ? *value : 0, max);
|
||||
if (param->SetProgress)
|
||||
param->SetProgress(param->value ? *param->value : 0, param->max);
|
||||
|
||||
if (cancelHandler && cancelHandler()) {
|
||||
free(new_path);
|
||||
sceIoDclose(dfd);
|
||||
return 0;
|
||||
if (param->cancelHandler && param->cancelHandler()) {
|
||||
free(new_path);
|
||||
sceIoDclose(dfd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,44 +264,48 @@ int removePath(char *path, uint64_t *value, uint64_t max, void (* SetProgress)(u
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (value)
|
||||
(*value)++;
|
||||
if (param) {
|
||||
if (param->value)
|
||||
(*param->value)++;
|
||||
|
||||
if (SetProgress)
|
||||
SetProgress(value ? *value : 0, max);
|
||||
if (param->SetProgress)
|
||||
param->SetProgress(param->value ? *param->value : 0, param->max);
|
||||
|
||||
if (cancelHandler && cancelHandler()) {
|
||||
return 0;
|
||||
if (param->cancelHandler && param->cancelHandler()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int ret = sceIoRemove(path);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (value)
|
||||
(*value)++;
|
||||
if (param) {
|
||||
if (param->value)
|
||||
(*param->value)++;
|
||||
|
||||
if (SetProgress)
|
||||
SetProgress(value ? *value : 0, max);
|
||||
if (param->SetProgress)
|
||||
param->SetProgress(param->value ? *param->value : 0, param->max);
|
||||
|
||||
if (cancelHandler && cancelHandler()) {
|
||||
return 0;
|
||||
if (param->cancelHandler && param->cancelHandler()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int copyFile(char *src_path, char *dst_path, uint64_t *value, uint64_t max, void (* SetProgress)(uint64_t value, uint64_t max), int (* cancelHandler)()) {
|
||||
int copyFile(char *src_path, char *dst_path, FileProcessParam *param) {
|
||||
// The source and destination paths are identical
|
||||
if (strcmp(src_path, dst_path) == 0) {
|
||||
if (strcasecmp(src_path, dst_path) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The destination is a subfolder of the source folder
|
||||
int len = strlen(src_path);
|
||||
if (strncmp(src_path, dst_path, len) == 0 && dst_path[len] == '/') {
|
||||
return -1;
|
||||
if (strncasecmp(src_path, dst_path, len) == 0 && (dst_path[len] == '/' || dst_path[len - 1] == '/')) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
SceUID fdsrc = sceIoOpen(src_path, SCE_O_RDONLY, 0);
|
||||
@ -272,19 +332,21 @@ int copyFile(char *src_path, char *dst_path, uint64_t *value, uint64_t max, void
|
||||
return res;
|
||||
}
|
||||
|
||||
if (value)
|
||||
(*value) += read;
|
||||
if (param) {
|
||||
if (param->value)
|
||||
(*param->value) += read;
|
||||
|
||||
if (SetProgress)
|
||||
SetProgress(value ? *value : 0, max);
|
||||
if (param->SetProgress)
|
||||
param->SetProgress(param->value ? *param->value : 0, param->max);
|
||||
|
||||
if (cancelHandler && cancelHandler()) {
|
||||
free(buf);
|
||||
if (param->cancelHandler && param->cancelHandler()) {
|
||||
free(buf);
|
||||
|
||||
sceIoClose(fddst);
|
||||
sceIoClose(fdsrc);
|
||||
sceIoClose(fddst);
|
||||
sceIoClose(fdsrc);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,16 +358,16 @@ int copyFile(char *src_path, char *dst_path, uint64_t *value, uint64_t max, void
|
||||
return 1;
|
||||
}
|
||||
|
||||
int copyPath(char *src_path, char *dst_path, uint64_t *value, uint64_t max, void (* SetProgress)(uint64_t value, uint64_t max), int (* cancelHandler)()) {
|
||||
int copyPath(char *src_path, char *dst_path, FileProcessParam *param) {
|
||||
// The source and destination paths are identical
|
||||
if (strcmp(src_path, dst_path) == 0) {
|
||||
if (strcasecmp(src_path, dst_path) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The destination is a subfolder of the source folder
|
||||
int len = strlen(src_path);
|
||||
if (strncmp(src_path, dst_path, len) == 0 && dst_path[len] == '/') {
|
||||
return -1;
|
||||
if (strncasecmp(src_path, dst_path, len) == 0 && (dst_path[len] == '/' || dst_path[len - 1] == '/')) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
SceUID dfd = sceIoDopen(src_path);
|
||||
@ -316,15 +378,17 @@ int copyPath(char *src_path, char *dst_path, uint64_t *value, uint64_t max, void
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (value)
|
||||
(*value)++;
|
||||
if (param) {
|
||||
if (param->value)
|
||||
(*param->value)++;
|
||||
|
||||
if (SetProgress)
|
||||
SetProgress(value ? *value : 0, max);
|
||||
if (param->SetProgress)
|
||||
param->SetProgress(param->value ? *param->value : 0, param->max);
|
||||
|
||||
if (cancelHandler && cancelHandler()) {
|
||||
sceIoDclose(dfd);
|
||||
return 0;
|
||||
if (param->cancelHandler && param->cancelHandler()) {
|
||||
sceIoDclose(dfd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
@ -339,17 +403,17 @@ int copyPath(char *src_path, char *dst_path, uint64_t *value, uint64_t max, void
|
||||
continue;
|
||||
|
||||
char *new_src_path = malloc(strlen(src_path) + strlen(dir.d_name) + 2);
|
||||
snprintf(new_src_path, MAX_PATH_LENGTH, "%s/%s", src_path, dir.d_name);
|
||||
snprintf(new_src_path, MAX_PATH_LENGTH, "%s%s%s", src_path, hasEndSlash(src_path) ? "" : "/", dir.d_name);
|
||||
|
||||
char *new_dst_path = malloc(strlen(dst_path) + strlen(dir.d_name) + 2);
|
||||
snprintf(new_dst_path, MAX_PATH_LENGTH, "%s/%s", dst_path, dir.d_name);
|
||||
snprintf(new_dst_path, MAX_PATH_LENGTH, "%s%s%s", dst_path, hasEndSlash(dst_path) ? "" : "/", dir.d_name);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (SCE_S_ISDIR(dir.d_stat.st_mode)) {
|
||||
ret = copyPath(new_src_path, new_dst_path, value, max, SetProgress, cancelHandler);
|
||||
ret = copyPath(new_src_path, new_dst_path, param);
|
||||
} else {
|
||||
ret = copyFile(new_src_path, new_dst_path, value, max, SetProgress, cancelHandler);
|
||||
ret = copyFile(new_src_path, new_dst_path, param);
|
||||
}
|
||||
|
||||
free(new_dst_path);
|
||||
@ -364,7 +428,100 @@ int copyPath(char *src_path, char *dst_path, uint64_t *value, uint64_t max, void
|
||||
|
||||
sceIoDclose(dfd);
|
||||
} else {
|
||||
return copyFile(src_path, dst_path, value, max, SetProgress, cancelHandler);
|
||||
return copyFile(src_path, dst_path, param);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int movePath(char *src_path, char *dst_path, int flags, FileProcessParam *param) {
|
||||
// The source and destination paths are identical
|
||||
if (strcasecmp(src_path, dst_path) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The destination is a subfolder of the source folder
|
||||
int len = strlen(src_path);
|
||||
if (strncasecmp(src_path, dst_path, len) == 0 && (dst_path[len] == '/' || dst_path[len - 1] == '/')) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
int res = sceIoRename(src_path, dst_path);
|
||||
if (res == SCE_ERROR_ERRNO_EEXIST && flags & (MOVE_INTEGRATE | MOVE_REPLACE)) {
|
||||
// Src stat
|
||||
SceIoStat src_stat;
|
||||
memset(&src_stat, 0, sizeof(SceIoStat));
|
||||
res = sceIoGetstat(src_path, &src_stat);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
// Dst stat
|
||||
SceIoStat dst_stat;
|
||||
memset(&dst_stat, 0, sizeof(SceIoStat));
|
||||
res = sceIoGetstat(dst_path, &dst_stat);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
// Is dir
|
||||
int src_is_dir = SCE_S_ISDIR(src_stat.st_mode);
|
||||
int dst_is_dir = SCE_S_ISDIR(dst_stat.st_mode);
|
||||
|
||||
// One of them is a file and the other a directory, no replacement or integration possible
|
||||
if (src_is_dir != dst_is_dir)
|
||||
return -3;
|
||||
|
||||
// Replace file
|
||||
if (!src_is_dir && !dst_is_dir && flags & MOVE_REPLACE) {
|
||||
sceIoRemove(dst_path);
|
||||
|
||||
res = sceIoRename(src_path, dst_path);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Integrate directory
|
||||
if (src_is_dir && dst_is_dir && flags & MOVE_INTEGRATE) {
|
||||
SceUID dfd = sceIoDopen(src_path);
|
||||
if (dfd < 0)
|
||||
return dfd;
|
||||
|
||||
int res = 0;
|
||||
|
||||
do {
|
||||
SceIoDirent dir;
|
||||
memset(&dir, 0, sizeof(SceIoDirent));
|
||||
|
||||
res = sceIoDread(dfd, &dir);
|
||||
if (res > 0) {
|
||||
if (strcmp(dir.d_name, ".") == 0 || strcmp(dir.d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
char *new_src_path = malloc(strlen(src_path) + strlen(dir.d_name) + 2);
|
||||
snprintf(new_src_path, MAX_PATH_LENGTH, "%s%s%s", src_path, hasEndSlash(src_path) ? "" : "/", dir.d_name);
|
||||
|
||||
char *new_dst_path = malloc(strlen(dst_path) + strlen(dir.d_name) + 2);
|
||||
snprintf(new_dst_path, MAX_PATH_LENGTH, "%s%s%s", dst_path, hasEndSlash(dst_path) ? "" : "/", dir.d_name);
|
||||
|
||||
// Recursive move
|
||||
int ret = movePath(new_src_path, new_dst_path, flags, param);
|
||||
|
||||
free(new_dst_path);
|
||||
free(new_src_path);
|
||||
|
||||
if (ret <= 0) {
|
||||
sceIoDclose(dfd);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} while (res > 0);
|
||||
|
||||
sceIoDclose(dfd);
|
||||
|
||||
// Integrated, now remove this directory
|
||||
sceIoRmdir(src_path);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -417,7 +574,7 @@ FileListEntry *fileListFindEntry(FileList *list, char *name) {
|
||||
int name_length = strlen(name);
|
||||
|
||||
while (entry) {
|
||||
if (entry->name_length == name_length && strcmp(entry->name, name) == 0)
|
||||
if (entry->name_length == name_length && strcasecmp(entry->name, name) == 0)
|
||||
return entry;
|
||||
|
||||
entry = entry->next;
|
||||
@ -448,7 +605,7 @@ int fileListGetNumberByName(FileList *list, char *name) {
|
||||
int n = 0;
|
||||
|
||||
while (entry) {
|
||||
if (entry->name_length == name_length && strcmp(entry->name, name) == 0)
|
||||
if (entry->name_length == name_length && strcasecmp(entry->name, name) == 0)
|
||||
break;
|
||||
|
||||
n++;
|
||||
@ -554,7 +711,7 @@ int fileListRemoveEntryByName(FileList *list, char *name) {
|
||||
int name_length = strlen(name);
|
||||
|
||||
while (entry) {
|
||||
if (entry->name_length == name_length && strcmp(entry->name, name) == 0) {
|
||||
if (entry->name_length == name_length && strcasecmp(entry->name, name) == 0) {
|
||||
if (previous) {
|
||||
previous->next = entry->next;
|
||||
} else {
|
||||
@ -676,7 +833,7 @@ int fileListGetEntries(FileList *list, char *path) {
|
||||
return fileListGetArchiveEntries(list, path);
|
||||
}
|
||||
|
||||
if (strcmp(path, HOME_PATH) == 0) {
|
||||
if (strcasecmp(path, HOME_PATH) == 0) {
|
||||
return fileListGetMountPointEntries(list);
|
||||
}
|
||||
|
||||
|
22
file.h
22
file.h
@ -43,11 +43,23 @@ enum FileTypes {
|
||||
FILE_TYPE_ZIP,
|
||||
};
|
||||
|
||||
enum SortFlags {
|
||||
enum FileSortFlags {
|
||||
SORT_NONE,
|
||||
SORT_BY_NAME_AND_FOLDER,
|
||||
};
|
||||
|
||||
enum FileMoveFlags {
|
||||
MOVE_INTEGRATE = 0x1, // Integrate directories
|
||||
MOVE_REPLACE = 0x2, // Replace files
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint64_t *value;
|
||||
uint64_t max;
|
||||
void (* SetProgress)(uint64_t value, uint64_t max);
|
||||
int (* cancelHandler)();
|
||||
} FileProcessParam;
|
||||
|
||||
typedef struct FileListEntry {
|
||||
struct FileListEntry *next;
|
||||
struct FileListEntry *previous;
|
||||
@ -74,10 +86,12 @@ int ReadFile(char *file, void *buf, int size);
|
||||
int WriteFile(char *file, void *buf, int size);
|
||||
|
||||
int getFileSize(char *pInputFileName);
|
||||
int getFileSha1(char *pInputFileName, uint8_t *pSha1Out, FileProcessParam *param);
|
||||
int getPathInfo(char *path, uint64_t *size, uint32_t *folders, uint32_t *files);
|
||||
int removePath(char *path, uint64_t *value, uint64_t max, void (* SetProgress)(uint64_t value, uint64_t max), int (* cancelHandler)());
|
||||
int copyFile(char *src_path, char *dst_path, uint64_t *value, uint64_t max, void (* SetProgress)(uint64_t value, uint64_t max), int (* cancelHandler)());
|
||||
int copyPath(char *src_path, char *dst_path, uint64_t *value, uint64_t max, void (* SetProgress)(uint64_t value, uint64_t max), int (* cancelHandler)());
|
||||
int removePath(char *path, FileProcessParam *param);
|
||||
int copyFile(char *src_path, char *dst_path, FileProcessParam *param);
|
||||
int copyPath(char *src_path, char *dst_path, FileProcessParam *param);
|
||||
int movePath(char *src_path, char *dst_path, int flags, FileProcessParam *param);
|
||||
|
||||
int getFileType(char *file);
|
||||
|
||||
|
2
hex.c
2
hex.c
@ -327,7 +327,7 @@ int hexViewer(char *file) {
|
||||
if (offset >= size)
|
||||
break;
|
||||
|
||||
uint32_t color = GENERAL_COLOR;
|
||||
uint32_t color = HEX_COLOR;
|
||||
|
||||
int on_line = 0;
|
||||
if (rel_pos == (y * 0x10)) {
|
||||
|
19
ime_dialog.c
19
ime_dialog.c
@ -21,6 +21,7 @@
|
||||
#include "utils.h"
|
||||
|
||||
static int ime_dialog_running = 0;
|
||||
static int ime_dialog_option = 0;
|
||||
|
||||
static uint16_t ime_title_utf16[SCE_IME_DIALOG_MAX_TITLE_LENGTH];
|
||||
static uint16_t ime_initial_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH];
|
||||
@ -69,7 +70,7 @@ void utf8_to_utf16(uint8_t *src, uint16_t *dst) {
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
int initImeDialog(char *title, char *initial_text, int max_text_length) {
|
||||
int initImeDialog(char *title, char *initial_text, int max_text_length, int type, int option) {
|
||||
if (ime_dialog_running)
|
||||
return -1;
|
||||
|
||||
@ -82,15 +83,20 @@ int initImeDialog(char *title, char *initial_text, int max_text_length) {
|
||||
|
||||
param.supportedLanguages = 0x0001FFFF;
|
||||
param.languagesForced = SCE_TRUE;
|
||||
param.type = SCE_IME_TYPE_BASIC_LATIN;
|
||||
param.type = type;
|
||||
param.option = option;
|
||||
if (option == SCE_IME_OPTION_MULTILINE)
|
||||
param.dialogMode = SCE_IME_DIALOG_DIALOG_MODE_WITH_CANCEL;
|
||||
param.title = ime_title_utf16;
|
||||
param.maxTextLength = max_text_length;
|
||||
param.initialText = ime_initial_text_utf16;
|
||||
param.inputTextBuffer = ime_input_text_utf16;
|
||||
|
||||
int res = sceImeDialogInit(¶m);
|
||||
if (res >= 0)
|
||||
if (res >= 0) {
|
||||
ime_dialog_running = 1;
|
||||
ime_dialog_option = option;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -117,11 +123,12 @@ int updateImeDialog() {
|
||||
memset(&result, 0, sizeof(SceImeDialogResult));
|
||||
sceImeDialogGetResult(&result);
|
||||
|
||||
if (result.button == SCE_IME_DIALOG_BUTTON_CLOSE) {
|
||||
status = IME_DIALOG_RESULT_CANCELED;
|
||||
} else {
|
||||
if ((ime_dialog_option == SCE_IME_OPTION_MULTILINE && result.button == SCE_IME_DIALOG_BUTTON_CLOSE) ||
|
||||
(ime_dialog_option != SCE_IME_OPTION_MULTILINE && result.button == SCE_IME_DIALOG_BUTTON_ENTER)) {
|
||||
// Convert UTF16 to UTF8
|
||||
utf16_to_utf8(ime_input_text_utf16, ime_input_text_utf8);
|
||||
} else {
|
||||
status = IME_DIALOG_RESULT_CANCELED;
|
||||
}
|
||||
|
||||
sceImeDialogTerm();
|
||||
|
@ -24,7 +24,7 @@
|
||||
#define IME_DIALOG_RESULT_FINISHED 2
|
||||
#define IME_DIALOG_RESULT_CANCELED 3
|
||||
|
||||
int initImeDialog(char *title, char *initial_text, int max_text_length);
|
||||
int initImeDialog(char *title, char *initial_text, int max_text_length, int type, int option);
|
||||
uint16_t *getImeDialogInputTextUTF16();
|
||||
uint8_t *getImeDialogInputTextUTF8();
|
||||
int isImeDialogRunning();
|
||||
|
39
init.c
39
init.c
@ -21,6 +21,9 @@
|
||||
#include "file.h"
|
||||
#include "utils.h"
|
||||
|
||||
extern unsigned char _binary_resources_changeinfo_txt_start;
|
||||
extern unsigned char _binary_resources_changeinfo_txt_size;
|
||||
|
||||
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;
|
||||
@ -55,12 +58,6 @@ extern unsigned char _binary_resources_colors_txt_size;
|
||||
extern unsigned char _binary_resources_english_us_txt_start;
|
||||
extern unsigned char _binary_resources_english_us_txt_size;
|
||||
|
||||
extern unsigned char _binary_resources_headphone_png_start;
|
||||
extern unsigned char _binary_resources_audio_previous_png_start;
|
||||
extern unsigned char _binary_resources_audio_pause_png_start;
|
||||
extern unsigned char _binary_resources_audio_play_png_start;
|
||||
extern unsigned char _binary_resources_audio_next_png_start;
|
||||
|
||||
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 },
|
||||
@ -82,8 +79,6 @@ static DefaultFile default_files[] = {
|
||||
vita2d_pgf *font = NULL;
|
||||
char font_size_cache[256];
|
||||
|
||||
vita2d_texture *headphone_image = NULL, *audio_previous_image = NULL, *audio_pause_image = NULL, *audio_play_image = NULL, *audio_next_image = NULL;
|
||||
|
||||
// System params
|
||||
int language = 0, enter_button = 0, date_format = 0, time_format = 0;
|
||||
|
||||
@ -140,29 +135,13 @@ void initVita2dLib() {
|
||||
|
||||
font_size_cache[i] = vita2d_pgf_text_width(font, FONT_SIZE, character);
|
||||
}
|
||||
|
||||
headphone_image = vita2d_load_PNG_buffer(&_binary_resources_headphone_png_start);
|
||||
audio_previous_image = vita2d_load_PNG_buffer(&_binary_resources_audio_previous_png_start);
|
||||
audio_pause_image = vita2d_load_PNG_buffer(&_binary_resources_audio_pause_png_start);
|
||||
audio_play_image = vita2d_load_PNG_buffer(&_binary_resources_audio_play_png_start);
|
||||
audio_next_image = vita2d_load_PNG_buffer(&_binary_resources_audio_next_png_start);
|
||||
}
|
||||
|
||||
void finishVita2dLib() {
|
||||
vita2d_free_texture(headphone_image);
|
||||
vita2d_free_texture(audio_previous_image);
|
||||
vita2d_free_texture(audio_pause_image);
|
||||
vita2d_free_texture(audio_play_image);
|
||||
vita2d_free_texture(audio_next_image);
|
||||
vita2d_free_pgf(font);
|
||||
vita2d_fini();
|
||||
|
||||
font = NULL;
|
||||
headphone_image = NULL;
|
||||
audio_previous_image = NULL;
|
||||
audio_pause_image = NULL;
|
||||
audio_play_image = NULL;
|
||||
audio_next_image = NULL;
|
||||
}
|
||||
|
||||
void initNet() {
|
||||
@ -217,6 +196,7 @@ void initVitaShell() {
|
||||
|
||||
// Make VitaShell folders
|
||||
sceIoMkdir("ux0:VitaShell", 0777);
|
||||
sceIoMkdir("ux0:VitaShell/internal", 0777);
|
||||
sceIoMkdir("ux0:VitaShell/language", 0777);
|
||||
sceIoMkdir("ux0:VitaShell/theme", 0777);
|
||||
sceIoMkdir("ux0:VitaShell/theme/Default", 0777);
|
||||
@ -229,6 +209,17 @@ void initVitaShell() {
|
||||
if (sceIoGetstat(default_files[i].path, &stat) < 0)
|
||||
WriteFile(default_files[i].path, default_files[i].buffer, default_files[i].size);
|
||||
}
|
||||
|
||||
// Write changeinfo.xml file to patch
|
||||
SceIoStat stat;
|
||||
memset(&stat, 0, sizeof(stat));
|
||||
if (sceIoGetstat("ux0:patch/VITASHELL/sce_sys/changeinfo/changeinfo.xml", &stat) < 0 && (int)stat.st_size != (int)&_binary_resources_changeinfo_txt_size) {
|
||||
sceIoMkdir("ux0:patch", 0777);
|
||||
sceIoMkdir("ux0:patch/VITASHELL", 0777);
|
||||
sceIoMkdir("ux0:patch/VITASHELL/sce_sys", 0777);
|
||||
sceIoMkdir("ux0:patch/VITASHELL/sce_sys/changeinfo", 0777);
|
||||
WriteFile("ux0:patch/VITASHELL/sce_sys/changeinfo/changeinfo.xml", (void *)&_binary_resources_changeinfo_txt_start, (int)&_binary_resources_changeinfo_txt_size);
|
||||
}
|
||||
}
|
||||
|
||||
void finishVitaShell() {
|
||||
|
104
io_process.c
104
io_process.c
@ -140,7 +140,12 @@ int delete_thread(SceSize args_size, DeleteArguments *args) {
|
||||
snprintf(path, MAX_PATH_LENGTH, "%s%s", args->file_list->path, mark_entry->name);
|
||||
removeEndSlash(path);
|
||||
|
||||
int res = removePath(path, &value, folders + files, SetProgress, cancelHandler);
|
||||
FileProcessParam param;
|
||||
param.value = &value;
|
||||
param.max = folders + files;
|
||||
param.SetProgress = SetProgress;
|
||||
param.cancelHandler = cancelHandler;
|
||||
int res = removePath(path, ¶m);
|
||||
if (res <= 0) {
|
||||
closeWaitDialog();
|
||||
dialog_step = DIALOG_STEP_CANCELLED;
|
||||
@ -196,9 +201,10 @@ int copy_thread(SceSize args_size, CopyArguments *args) {
|
||||
for (i = 0; i < args->copy_list->length; i++) {
|
||||
snprintf(src_path, MAX_PATH_LENGTH, "%s%s", args->copy_list->path, copy_entry->name);
|
||||
snprintf(dst_path, MAX_PATH_LENGTH, "%s%s", args->file_list->path, copy_entry->name);
|
||||
removeEndSlash(src_path);
|
||||
removeEndSlash(dst_path);
|
||||
|
||||
int res = sceIoRename(src_path, dst_path);
|
||||
// TODO: if (res == SCE_ERROR_ERRNO_EEXIST) if folder
|
||||
int res = movePath(src_path, dst_path, MOVE_INTEGRATE | MOVE_REPLACE, NULL);
|
||||
if (res < 0) {
|
||||
closeWaitDialog();
|
||||
errorDialog(res);
|
||||
@ -269,8 +275,14 @@ int copy_thread(SceSize args_size, CopyArguments *args) {
|
||||
removeEndSlash(src_path);
|
||||
removeEndSlash(dst_path);
|
||||
|
||||
FileProcessParam param;
|
||||
param.value = &value;
|
||||
param.max = size + folders;
|
||||
param.SetProgress = SetProgress;
|
||||
param.cancelHandler = cancelHandler;
|
||||
|
||||
if (args->copy_mode == COPY_MODE_EXTRACT) {
|
||||
int res = extractArchivePath(src_path, dst_path, &value, size + folders, SetProgress, cancelHandler);
|
||||
int res = extractArchivePath(src_path, dst_path, ¶m);
|
||||
if (res <= 0) {
|
||||
closeWaitDialog();
|
||||
dialog_step = DIALOG_STEP_CANCELLED;
|
||||
@ -278,7 +290,7 @@ int copy_thread(SceSize args_size, CopyArguments *args) {
|
||||
goto EXIT;
|
||||
}
|
||||
} else {
|
||||
int res = copyPath(src_path, dst_path, &value, size + folders, SetProgress, cancelHandler);
|
||||
int res = copyPath(src_path, dst_path, ¶m);
|
||||
if (res <= 0) {
|
||||
closeWaitDialog();
|
||||
dialog_step = DIALOG_STEP_CANCELLED;
|
||||
@ -318,4 +330,84 @@ EXIT:
|
||||
powerUnlock();
|
||||
|
||||
return sceKernelExitDeleteThread(0);
|
||||
}
|
||||
}
|
||||
|
||||
int hash_thread(SceSize args_size, HashArguments *args) {
|
||||
SceUID thid = -1;
|
||||
|
||||
// Lock power timers
|
||||
powerLock();
|
||||
|
||||
// Set progress to 0%
|
||||
sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
|
||||
sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
|
||||
|
||||
uint64_t max = (uint64_t) (getFileSize(args->file_path)/(TRANSFER_SIZE));
|
||||
|
||||
// SHA1 process
|
||||
uint64_t value = 0;
|
||||
|
||||
// Spin off a thread to update the progress dialog
|
||||
thid = createStartUpdateThread(max);
|
||||
|
||||
FileProcessParam param;
|
||||
param.value = &value;
|
||||
param.max = max;
|
||||
param.SetProgress = SetProgress;
|
||||
param.cancelHandler = cancelHandler;
|
||||
|
||||
uint8_t sha1out[20];
|
||||
int res = getFileSha1(args->file_path, sha1out, ¶m);
|
||||
if (res <= 0) {
|
||||
// SHA1 Didn't complete successfully, or was cancelled
|
||||
closeWaitDialog();
|
||||
dialog_step = DIALOG_STEP_CANCELLED;
|
||||
errorDialog(res);
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
// Since we hit here, we're done. Set progress to 100%
|
||||
sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
|
||||
sceKernelDelayThread(COUNTUP_WAIT);
|
||||
|
||||
// Close
|
||||
closeWaitDialog();
|
||||
|
||||
char sha1msg[42];
|
||||
memset(sha1msg, 0, sizeof(sha1msg));
|
||||
|
||||
// Construct SHA1 sum string
|
||||
int i;
|
||||
for (i = 0; i < 20; i++) {
|
||||
char string[4];
|
||||
sprintf(string, "%02X", sha1out[i]);
|
||||
strcat(sha1msg, string);
|
||||
|
||||
if (i == 9)
|
||||
strcat(sha1msg, "\n");
|
||||
}
|
||||
|
||||
sha1msg[41] = '\0';
|
||||
|
||||
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK, sha1msg);
|
||||
dialog_step = DIALOG_STEP_HASH_DISPLAY;
|
||||
|
||||
// Wait for response
|
||||
while (dialog_step == DIALOG_STEP_HASH_DISPLAY) {
|
||||
sceKernelDelayThread(1000);
|
||||
}
|
||||
|
||||
closeWaitDialog();
|
||||
sceMsgDialogClose();
|
||||
|
||||
EXIT:
|
||||
|
||||
// Ensure the update thread ends gracefully
|
||||
if (thid >= 0)
|
||||
sceKernelWaitThreadEnd(thid, NULL, NULL);
|
||||
|
||||
powerUnlock();
|
||||
|
||||
// Kill current thread
|
||||
return sceKernelExitDeleteThread(0);
|
||||
}
|
||||
|
@ -45,6 +45,10 @@ typedef struct {
|
||||
int copy_mode;
|
||||
} CopyArguments;
|
||||
|
||||
typedef struct {
|
||||
char *file_path;
|
||||
} HashArguments;
|
||||
|
||||
void closeWaitDialog();
|
||||
int cancelHandler();
|
||||
void SetProgress(uint64_t value, uint64_t max);
|
||||
@ -52,5 +56,6 @@ SceUID createStartUpdateThread(uint64_t max);
|
||||
|
||||
int delete_thread(SceSize args_size, DeleteArguments *args);
|
||||
int copy_thread(SceSize args_size, CopyArguments *args);
|
||||
int hash_thread(SceSize args_size, HashArguments *args);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
44
language.c
44
language.c
@ -61,13 +61,37 @@ void loadLanguage(int id) {
|
||||
freeLanguageContainer();
|
||||
|
||||
#define LANGUAGE_ENTRY(name) { #name, CONFIG_TYPE_STRING, (void *)&language_container[name] }
|
||||
ConfigEntry language_entries[] = {
|
||||
ConfigEntry language_entries[] = {
|
||||
// General strings
|
||||
LANGUAGE_ENTRY(ERROR),
|
||||
LANGUAGE_ENTRY(OK),
|
||||
LANGUAGE_ENTRY(YES),
|
||||
LANGUAGE_ENTRY(NO),
|
||||
LANGUAGE_ENTRY(CANCEL),
|
||||
LANGUAGE_ENTRY(FOLDER),
|
||||
LANGUAGE_ENTRY(OFFSET),
|
||||
|
||||
// Progress strings
|
||||
LANGUAGE_ENTRY(MOVING),
|
||||
LANGUAGE_ENTRY(COPYING),
|
||||
LANGUAGE_ENTRY(DELETING),
|
||||
LANGUAGE_ENTRY(INSTALLING),
|
||||
LANGUAGE_ENTRY(DOWNLOADING),
|
||||
LANGUAGE_ENTRY(EXTRACTING),
|
||||
LANGUAGE_ENTRY(HASHING),
|
||||
|
||||
// Hex editor strings
|
||||
LANGUAGE_ENTRY(CUT),
|
||||
LANGUAGE_ENTRY(OPEN_HEX_EDITOR),
|
||||
|
||||
// Text editor strings
|
||||
LANGUAGE_ENTRY(EDIT_LINE),
|
||||
LANGUAGE_ENTRY(ENTER_SEARCH_TERM),
|
||||
LANGUAGE_ENTRY(CUT),
|
||||
LANGUAGE_ENTRY(INSERT_EMPTY_LINE),
|
||||
|
||||
// File browser context menu strings
|
||||
LANGUAGE_ENTRY(MORE),
|
||||
LANGUAGE_ENTRY(MARK_ALL),
|
||||
LANGUAGE_ENTRY(UNMARK_ALL),
|
||||
LANGUAGE_ENTRY(MOVE),
|
||||
@ -76,27 +100,29 @@ void loadLanguage(int id) {
|
||||
LANGUAGE_ENTRY(DELETE),
|
||||
LANGUAGE_ENTRY(RENAME),
|
||||
LANGUAGE_ENTRY(NEW_FOLDER),
|
||||
LANGUAGE_ENTRY(FOLDER),
|
||||
LANGUAGE_ENTRY(INSTALL_ALL),
|
||||
LANGUAGE_ENTRY(CALCULATE_SHA1),
|
||||
LANGUAGE_ENTRY(SEARCH),
|
||||
|
||||
// File browser strings
|
||||
LANGUAGE_ENTRY(COPIED_FILE),
|
||||
LANGUAGE_ENTRY(COPIED_FOLDER),
|
||||
LANGUAGE_ENTRY(COPIED_FILES_FOLDERS),
|
||||
LANGUAGE_ENTRY(MOVING),
|
||||
LANGUAGE_ENTRY(COPYING),
|
||||
LANGUAGE_ENTRY(DELETING),
|
||||
LANGUAGE_ENTRY(INSTALLING),
|
||||
LANGUAGE_ENTRY(DOWNLOADING),
|
||||
LANGUAGE_ENTRY(EXTRACTING),
|
||||
|
||||
// Dialog questions
|
||||
LANGUAGE_ENTRY(DELETE_FILE_QUESTION),
|
||||
LANGUAGE_ENTRY(DELETE_FOLDER_QUESTION),
|
||||
LANGUAGE_ENTRY(DELETE_FILES_FOLDERS_QUESTION),
|
||||
LANGUAGE_ENTRY(INSTALL_ALL_QUESTION),
|
||||
LANGUAGE_ENTRY(INSTALL_QUESTION),
|
||||
LANGUAGE_ENTRY(INSTALL_WARNING),
|
||||
LANGUAGE_ENTRY(HASH_FILE_QUESTION),
|
||||
|
||||
// Others
|
||||
LANGUAGE_ENTRY(SAVE_MODIFICATIONS),
|
||||
LANGUAGE_ENTRY(WIFI_ERROR),
|
||||
LANGUAGE_ENTRY(FTP_SERVER),
|
||||
LANGUAGE_ENTRY(SYS_INFO),
|
||||
LANGUAGE_ENTRY(INSTALL_ALL),
|
||||
LANGUAGE_ENTRY(UPDATE_QUESTION),
|
||||
};
|
||||
|
||||
|
41
language.h
41
language.h
@ -20,12 +20,35 @@
|
||||
#define __LANGUAGE_H__
|
||||
|
||||
enum LanguageContainer {
|
||||
// General strings
|
||||
ERROR,
|
||||
OK,
|
||||
YES,
|
||||
NO,
|
||||
CANCEL,
|
||||
FOLDER,
|
||||
|
||||
// Progress strings
|
||||
MOVING,
|
||||
COPYING,
|
||||
DELETING,
|
||||
INSTALLING,
|
||||
DOWNLOADING,
|
||||
EXTRACTING,
|
||||
HASHING,
|
||||
|
||||
// Hex editor strings
|
||||
OFFSET,
|
||||
OPEN_HEX_EDITOR,
|
||||
|
||||
// Text editor strings
|
||||
EDIT_LINE,
|
||||
ENTER_SEARCH_TERM,
|
||||
CUT,
|
||||
INSERT_EMPTY_LINE,
|
||||
|
||||
// File browser context menu strings
|
||||
MORE,
|
||||
MARK_ALL,
|
||||
UNMARK_ALL,
|
||||
MOVE,
|
||||
@ -34,27 +57,29 @@ enum LanguageContainer {
|
||||
DELETE,
|
||||
RENAME,
|
||||
NEW_FOLDER,
|
||||
FOLDER,
|
||||
INSTALL_ALL,
|
||||
CALCULATE_SHA1,
|
||||
SEARCH,
|
||||
|
||||
// File browser strings
|
||||
COPIED_FILE,
|
||||
COPIED_FOLDER,
|
||||
COPIED_FILES_FOLDERS,
|
||||
MOVING,
|
||||
COPYING,
|
||||
DELETING,
|
||||
INSTALLING,
|
||||
DOWNLOADING,
|
||||
EXTRACTING,
|
||||
|
||||
// Dialog questions
|
||||
DELETE_FILE_QUESTION,
|
||||
DELETE_FOLDER_QUESTION,
|
||||
DELETE_FILES_FOLDERS_QUESTION,
|
||||
INSTALL_ALL_QUESTION,
|
||||
INSTALL_QUESTION,
|
||||
INSTALL_WARNING,
|
||||
HASH_FILE_QUESTION,
|
||||
|
||||
// Others
|
||||
SAVE_MODIFICATIONS,
|
||||
WIFI_ERROR,
|
||||
FTP_SERVER,
|
||||
SYS_INFO,
|
||||
INSTALL_ALL,
|
||||
UPDATE_QUESTION,
|
||||
LANGUAGE_CONTRAINER_SIZE,
|
||||
};
|
||||
|
607
libmad/D.dat
Normal file
607
libmad/D.dat
Normal file
@ -0,0 +1,607 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: D.dat,v 1.9 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* These are the coefficients for the subband synthesis window. This is a
|
||||
* reordered version of Table B.3 from ISO/IEC 11172-3.
|
||||
*
|
||||
* Every value is parameterized so that shift optimizations can be made at
|
||||
* compile-time. For example, every value can be right-shifted 12 bits to
|
||||
* minimize multiply instruction times without any loss of accuracy.
|
||||
*/
|
||||
|
||||
{ PRESHIFT(0x00000000) /* 0.000000000 */, /* 0 */
|
||||
-PRESHIFT(0x0001d000) /* -0.000442505 */,
|
||||
PRESHIFT(0x000d5000) /* 0.003250122 */,
|
||||
-PRESHIFT(0x001cb000) /* -0.007003784 */,
|
||||
PRESHIFT(0x007f5000) /* 0.031082153 */,
|
||||
-PRESHIFT(0x01421000) /* -0.078628540 */,
|
||||
PRESHIFT(0x019ae000) /* 0.100311279 */,
|
||||
-PRESHIFT(0x09271000) /* -0.572036743 */,
|
||||
PRESHIFT(0x1251e000) /* 1.144989014 */,
|
||||
PRESHIFT(0x09271000) /* 0.572036743 */,
|
||||
PRESHIFT(0x019ae000) /* 0.100311279 */,
|
||||
PRESHIFT(0x01421000) /* 0.078628540 */,
|
||||
PRESHIFT(0x007f5000) /* 0.031082153 */,
|
||||
PRESHIFT(0x001cb000) /* 0.007003784 */,
|
||||
PRESHIFT(0x000d5000) /* 0.003250122 */,
|
||||
PRESHIFT(0x0001d000) /* 0.000442505 */,
|
||||
|
||||
PRESHIFT(0x00000000) /* 0.000000000 */,
|
||||
-PRESHIFT(0x0001d000) /* -0.000442505 */,
|
||||
PRESHIFT(0x000d5000) /* 0.003250122 */,
|
||||
-PRESHIFT(0x001cb000) /* -0.007003784 */,
|
||||
PRESHIFT(0x007f5000) /* 0.031082153 */,
|
||||
-PRESHIFT(0x01421000) /* -0.078628540 */,
|
||||
PRESHIFT(0x019ae000) /* 0.100311279 */,
|
||||
-PRESHIFT(0x09271000) /* -0.572036743 */,
|
||||
PRESHIFT(0x1251e000) /* 1.144989014 */,
|
||||
PRESHIFT(0x09271000) /* 0.572036743 */,
|
||||
PRESHIFT(0x019ae000) /* 0.100311279 */,
|
||||
PRESHIFT(0x01421000) /* 0.078628540 */,
|
||||
PRESHIFT(0x007f5000) /* 0.031082153 */,
|
||||
PRESHIFT(0x001cb000) /* 0.007003784 */,
|
||||
PRESHIFT(0x000d5000) /* 0.003250122 */,
|
||||
PRESHIFT(0x0001d000) /* 0.000442505 */ },
|
||||
|
||||
{ -PRESHIFT(0x00001000) /* -0.000015259 */, /* 1 */
|
||||
-PRESHIFT(0x0001f000) /* -0.000473022 */,
|
||||
PRESHIFT(0x000da000) /* 0.003326416 */,
|
||||
-PRESHIFT(0x00207000) /* -0.007919312 */,
|
||||
PRESHIFT(0x007d0000) /* 0.030517578 */,
|
||||
-PRESHIFT(0x0158d000) /* -0.084182739 */,
|
||||
PRESHIFT(0x01747000) /* 0.090927124 */,
|
||||
-PRESHIFT(0x099a8000) /* -0.600219727 */,
|
||||
PRESHIFT(0x124f0000) /* 1.144287109 */,
|
||||
PRESHIFT(0x08b38000) /* 0.543823242 */,
|
||||
PRESHIFT(0x01bde000) /* 0.108856201 */,
|
||||
PRESHIFT(0x012b4000) /* 0.073059082 */,
|
||||
PRESHIFT(0x0080f000) /* 0.031478882 */,
|
||||
PRESHIFT(0x00191000) /* 0.006118774 */,
|
||||
PRESHIFT(0x000d0000) /* 0.003173828 */,
|
||||
PRESHIFT(0x0001a000) /* 0.000396729 */,
|
||||
|
||||
-PRESHIFT(0x00001000) /* -0.000015259 */,
|
||||
-PRESHIFT(0x0001f000) /* -0.000473022 */,
|
||||
PRESHIFT(0x000da000) /* 0.003326416 */,
|
||||
-PRESHIFT(0x00207000) /* -0.007919312 */,
|
||||
PRESHIFT(0x007d0000) /* 0.030517578 */,
|
||||
-PRESHIFT(0x0158d000) /* -0.084182739 */,
|
||||
PRESHIFT(0x01747000) /* 0.090927124 */,
|
||||
-PRESHIFT(0x099a8000) /* -0.600219727 */,
|
||||
PRESHIFT(0x124f0000) /* 1.144287109 */,
|
||||
PRESHIFT(0x08b38000) /* 0.543823242 */,
|
||||
PRESHIFT(0x01bde000) /* 0.108856201 */,
|
||||
PRESHIFT(0x012b4000) /* 0.073059082 */,
|
||||
PRESHIFT(0x0080f000) /* 0.031478882 */,
|
||||
PRESHIFT(0x00191000) /* 0.006118774 */,
|
||||
PRESHIFT(0x000d0000) /* 0.003173828 */,
|
||||
PRESHIFT(0x0001a000) /* 0.000396729 */ },
|
||||
|
||||
{ -PRESHIFT(0x00001000) /* -0.000015259 */, /* 2 */
|
||||
-PRESHIFT(0x00023000) /* -0.000534058 */,
|
||||
PRESHIFT(0x000de000) /* 0.003387451 */,
|
||||
-PRESHIFT(0x00245000) /* -0.008865356 */,
|
||||
PRESHIFT(0x007a0000) /* 0.029785156 */,
|
||||
-PRESHIFT(0x016f7000) /* -0.089706421 */,
|
||||
PRESHIFT(0x014a8000) /* 0.080688477 */,
|
||||
-PRESHIFT(0x0a0d8000) /* -0.628295898 */,
|
||||
PRESHIFT(0x12468000) /* 1.142211914 */,
|
||||
PRESHIFT(0x083ff000) /* 0.515609741 */,
|
||||
PRESHIFT(0x01dd8000) /* 0.116577148 */,
|
||||
PRESHIFT(0x01149000) /* 0.067520142 */,
|
||||
PRESHIFT(0x00820000) /* 0.031738281 */,
|
||||
PRESHIFT(0x0015b000) /* 0.005294800 */,
|
||||
PRESHIFT(0x000ca000) /* 0.003082275 */,
|
||||
PRESHIFT(0x00018000) /* 0.000366211 */,
|
||||
|
||||
-PRESHIFT(0x00001000) /* -0.000015259 */,
|
||||
-PRESHIFT(0x00023000) /* -0.000534058 */,
|
||||
PRESHIFT(0x000de000) /* 0.003387451 */,
|
||||
-PRESHIFT(0x00245000) /* -0.008865356 */,
|
||||
PRESHIFT(0x007a0000) /* 0.029785156 */,
|
||||
-PRESHIFT(0x016f7000) /* -0.089706421 */,
|
||||
PRESHIFT(0x014a8000) /* 0.080688477 */,
|
||||
-PRESHIFT(0x0a0d8000) /* -0.628295898 */,
|
||||
PRESHIFT(0x12468000) /* 1.142211914 */,
|
||||
PRESHIFT(0x083ff000) /* 0.515609741 */,
|
||||
PRESHIFT(0x01dd8000) /* 0.116577148 */,
|
||||
PRESHIFT(0x01149000) /* 0.067520142 */,
|
||||
PRESHIFT(0x00820000) /* 0.031738281 */,
|
||||
PRESHIFT(0x0015b000) /* 0.005294800 */,
|
||||
PRESHIFT(0x000ca000) /* 0.003082275 */,
|
||||
PRESHIFT(0x00018000) /* 0.000366211 */ },
|
||||
|
||||
{ -PRESHIFT(0x00001000) /* -0.000015259 */, /* 3 */
|
||||
-PRESHIFT(0x00026000) /* -0.000579834 */,
|
||||
PRESHIFT(0x000e1000) /* 0.003433228 */,
|
||||
-PRESHIFT(0x00285000) /* -0.009841919 */,
|
||||
PRESHIFT(0x00765000) /* 0.028884888 */,
|
||||
-PRESHIFT(0x0185d000) /* -0.095169067 */,
|
||||
PRESHIFT(0x011d1000) /* 0.069595337 */,
|
||||
-PRESHIFT(0x0a7fe000) /* -0.656219482 */,
|
||||
PRESHIFT(0x12386000) /* 1.138763428 */,
|
||||
PRESHIFT(0x07ccb000) /* 0.487472534 */,
|
||||
PRESHIFT(0x01f9c000) /* 0.123474121 */,
|
||||
PRESHIFT(0x00fdf000) /* 0.061996460 */,
|
||||
PRESHIFT(0x00827000) /* 0.031845093 */,
|
||||
PRESHIFT(0x00126000) /* 0.004486084 */,
|
||||
PRESHIFT(0x000c4000) /* 0.002990723 */,
|
||||
PRESHIFT(0x00015000) /* 0.000320435 */,
|
||||
|
||||
-PRESHIFT(0x00001000) /* -0.000015259 */,
|
||||
-PRESHIFT(0x00026000) /* -0.000579834 */,
|
||||
PRESHIFT(0x000e1000) /* 0.003433228 */,
|
||||
-PRESHIFT(0x00285000) /* -0.009841919 */,
|
||||
PRESHIFT(0x00765000) /* 0.028884888 */,
|
||||
-PRESHIFT(0x0185d000) /* -0.095169067 */,
|
||||
PRESHIFT(0x011d1000) /* 0.069595337 */,
|
||||
-PRESHIFT(0x0a7fe000) /* -0.656219482 */,
|
||||
PRESHIFT(0x12386000) /* 1.138763428 */,
|
||||
PRESHIFT(0x07ccb000) /* 0.487472534 */,
|
||||
PRESHIFT(0x01f9c000) /* 0.123474121 */,
|
||||
PRESHIFT(0x00fdf000) /* 0.061996460 */,
|
||||
PRESHIFT(0x00827000) /* 0.031845093 */,
|
||||
PRESHIFT(0x00126000) /* 0.004486084 */,
|
||||
PRESHIFT(0x000c4000) /* 0.002990723 */,
|
||||
PRESHIFT(0x00015000) /* 0.000320435 */ },
|
||||
|
||||
{ -PRESHIFT(0x00001000) /* -0.000015259 */, /* 4 */
|
||||
-PRESHIFT(0x00029000) /* -0.000625610 */,
|
||||
PRESHIFT(0x000e3000) /* 0.003463745 */,
|
||||
-PRESHIFT(0x002c7000) /* -0.010848999 */,
|
||||
PRESHIFT(0x0071e000) /* 0.027801514 */,
|
||||
-PRESHIFT(0x019bd000) /* -0.100540161 */,
|
||||
PRESHIFT(0x00ec0000) /* 0.057617187 */,
|
||||
-PRESHIFT(0x0af15000) /* -0.683914185 */,
|
||||
PRESHIFT(0x12249000) /* 1.133926392 */,
|
||||
PRESHIFT(0x075a0000) /* 0.459472656 */,
|
||||
PRESHIFT(0x0212c000) /* 0.129577637 */,
|
||||
PRESHIFT(0x00e79000) /* 0.056533813 */,
|
||||
PRESHIFT(0x00825000) /* 0.031814575 */,
|
||||
PRESHIFT(0x000f4000) /* 0.003723145 */,
|
||||
PRESHIFT(0x000be000) /* 0.002899170 */,
|
||||
PRESHIFT(0x00013000) /* 0.000289917 */,
|
||||
|
||||
-PRESHIFT(0x00001000) /* -0.000015259 */,
|
||||
-PRESHIFT(0x00029000) /* -0.000625610 */,
|
||||
PRESHIFT(0x000e3000) /* 0.003463745 */,
|
||||
-PRESHIFT(0x002c7000) /* -0.010848999 */,
|
||||
PRESHIFT(0x0071e000) /* 0.027801514 */,
|
||||
-PRESHIFT(0x019bd000) /* -0.100540161 */,
|
||||
PRESHIFT(0x00ec0000) /* 0.057617187 */,
|
||||
-PRESHIFT(0x0af15000) /* -0.683914185 */,
|
||||
PRESHIFT(0x12249000) /* 1.133926392 */,
|
||||
PRESHIFT(0x075a0000) /* 0.459472656 */,
|
||||
PRESHIFT(0x0212c000) /* 0.129577637 */,
|
||||
PRESHIFT(0x00e79000) /* 0.056533813 */,
|
||||
PRESHIFT(0x00825000) /* 0.031814575 */,
|
||||
PRESHIFT(0x000f4000) /* 0.003723145 */,
|
||||
PRESHIFT(0x000be000) /* 0.002899170 */,
|
||||
PRESHIFT(0x00013000) /* 0.000289917 */ },
|
||||
|
||||
{ -PRESHIFT(0x00001000) /* -0.000015259 */, /* 5 */
|
||||
-PRESHIFT(0x0002d000) /* -0.000686646 */,
|
||||
PRESHIFT(0x000e4000) /* 0.003479004 */,
|
||||
-PRESHIFT(0x0030b000) /* -0.011886597 */,
|
||||
PRESHIFT(0x006cb000) /* 0.026535034 */,
|
||||
-PRESHIFT(0x01b17000) /* -0.105819702 */,
|
||||
PRESHIFT(0x00b77000) /* 0.044784546 */,
|
||||
-PRESHIFT(0x0b619000) /* -0.711318970 */,
|
||||
PRESHIFT(0x120b4000) /* 1.127746582 */,
|
||||
PRESHIFT(0x06e81000) /* 0.431655884 */,
|
||||
PRESHIFT(0x02288000) /* 0.134887695 */,
|
||||
PRESHIFT(0x00d17000) /* 0.051132202 */,
|
||||
PRESHIFT(0x0081b000) /* 0.031661987 */,
|
||||
PRESHIFT(0x000c5000) /* 0.003005981 */,
|
||||
PRESHIFT(0x000b7000) /* 0.002792358 */,
|
||||
PRESHIFT(0x00011000) /* 0.000259399 */,
|
||||
|
||||
-PRESHIFT(0x00001000) /* -0.000015259 */,
|
||||
-PRESHIFT(0x0002d000) /* -0.000686646 */,
|
||||
PRESHIFT(0x000e4000) /* 0.003479004 */,
|
||||
-PRESHIFT(0x0030b000) /* -0.011886597 */,
|
||||
PRESHIFT(0x006cb000) /* 0.026535034 */,
|
||||
-PRESHIFT(0x01b17000) /* -0.105819702 */,
|
||||
PRESHIFT(0x00b77000) /* 0.044784546 */,
|
||||
-PRESHIFT(0x0b619000) /* -0.711318970 */,
|
||||
PRESHIFT(0x120b4000) /* 1.127746582 */,
|
||||
PRESHIFT(0x06e81000) /* 0.431655884 */,
|
||||
PRESHIFT(0x02288000) /* 0.134887695 */,
|
||||
PRESHIFT(0x00d17000) /* 0.051132202 */,
|
||||
PRESHIFT(0x0081b000) /* 0.031661987 */,
|
||||
PRESHIFT(0x000c5000) /* 0.003005981 */,
|
||||
PRESHIFT(0x000b7000) /* 0.002792358 */,
|
||||
PRESHIFT(0x00011000) /* 0.000259399 */ },
|
||||
|
||||
{ -PRESHIFT(0x00001000) /* -0.000015259 */, /* 6 */
|
||||
-PRESHIFT(0x00031000) /* -0.000747681 */,
|
||||
PRESHIFT(0x000e4000) /* 0.003479004 */,
|
||||
-PRESHIFT(0x00350000) /* -0.012939453 */,
|
||||
PRESHIFT(0x0066c000) /* 0.025085449 */,
|
||||
-PRESHIFT(0x01c67000) /* -0.110946655 */,
|
||||
PRESHIFT(0x007f5000) /* 0.031082153 */,
|
||||
-PRESHIFT(0x0bd06000) /* -0.738372803 */,
|
||||
PRESHIFT(0x11ec7000) /* 1.120223999 */,
|
||||
PRESHIFT(0x06772000) /* 0.404083252 */,
|
||||
PRESHIFT(0x023b3000) /* 0.139450073 */,
|
||||
PRESHIFT(0x00bbc000) /* 0.045837402 */,
|
||||
PRESHIFT(0x00809000) /* 0.031387329 */,
|
||||
PRESHIFT(0x00099000) /* 0.002334595 */,
|
||||
PRESHIFT(0x000b0000) /* 0.002685547 */,
|
||||
PRESHIFT(0x00010000) /* 0.000244141 */,
|
||||
|
||||
-PRESHIFT(0x00001000) /* -0.000015259 */,
|
||||
-PRESHIFT(0x00031000) /* -0.000747681 */,
|
||||
PRESHIFT(0x000e4000) /* 0.003479004 */,
|
||||
-PRESHIFT(0x00350000) /* -0.012939453 */,
|
||||
PRESHIFT(0x0066c000) /* 0.025085449 */,
|
||||
-PRESHIFT(0x01c67000) /* -0.110946655 */,
|
||||
PRESHIFT(0x007f5000) /* 0.031082153 */,
|
||||
-PRESHIFT(0x0bd06000) /* -0.738372803 */,
|
||||
PRESHIFT(0x11ec7000) /* 1.120223999 */,
|
||||
PRESHIFT(0x06772000) /* 0.404083252 */,
|
||||
PRESHIFT(0x023b3000) /* 0.139450073 */,
|
||||
PRESHIFT(0x00bbc000) /* 0.045837402 */,
|
||||
PRESHIFT(0x00809000) /* 0.031387329 */,
|
||||
PRESHIFT(0x00099000) /* 0.002334595 */,
|
||||
PRESHIFT(0x000b0000) /* 0.002685547 */,
|
||||
PRESHIFT(0x00010000) /* 0.000244141 */ },
|
||||
|
||||
{ -PRESHIFT(0x00002000) /* -0.000030518 */, /* 7 */
|
||||
-PRESHIFT(0x00035000) /* -0.000808716 */,
|
||||
PRESHIFT(0x000e3000) /* 0.003463745 */,
|
||||
-PRESHIFT(0x00397000) /* -0.014022827 */,
|
||||
PRESHIFT(0x005ff000) /* 0.023422241 */,
|
||||
-PRESHIFT(0x01dad000) /* -0.115921021 */,
|
||||
PRESHIFT(0x0043a000) /* 0.016510010 */,
|
||||
-PRESHIFT(0x0c3d9000) /* -0.765029907 */,
|
||||
PRESHIFT(0x11c83000) /* 1.111373901 */,
|
||||
PRESHIFT(0x06076000) /* 0.376800537 */,
|
||||
PRESHIFT(0x024ad000) /* 0.143264771 */,
|
||||
PRESHIFT(0x00a67000) /* 0.040634155 */,
|
||||
PRESHIFT(0x007f0000) /* 0.031005859 */,
|
||||
PRESHIFT(0x0006f000) /* 0.001693726 */,
|
||||
PRESHIFT(0x000a9000) /* 0.002578735 */,
|
||||
PRESHIFT(0x0000e000) /* 0.000213623 */,
|
||||
|
||||
-PRESHIFT(0x00002000) /* -0.000030518 */,
|
||||
-PRESHIFT(0x00035000) /* -0.000808716 */,
|
||||
PRESHIFT(0x000e3000) /* 0.003463745 */,
|
||||
-PRESHIFT(0x00397000) /* -0.014022827 */,
|
||||
PRESHIFT(0x005ff000) /* 0.023422241 */,
|
||||
-PRESHIFT(0x01dad000) /* -0.115921021 */,
|
||||
PRESHIFT(0x0043a000) /* 0.016510010 */,
|
||||
-PRESHIFT(0x0c3d9000) /* -0.765029907 */,
|
||||
PRESHIFT(0x11c83000) /* 1.111373901 */,
|
||||
PRESHIFT(0x06076000) /* 0.376800537 */,
|
||||
PRESHIFT(0x024ad000) /* 0.143264771 */,
|
||||
PRESHIFT(0x00a67000) /* 0.040634155 */,
|
||||
PRESHIFT(0x007f0000) /* 0.031005859 */,
|
||||
PRESHIFT(0x0006f000) /* 0.001693726 */,
|
||||
PRESHIFT(0x000a9000) /* 0.002578735 */,
|
||||
PRESHIFT(0x0000e000) /* 0.000213623 */ },
|
||||
|
||||
{ -PRESHIFT(0x00002000) /* -0.000030518 */, /* 8 */
|
||||
-PRESHIFT(0x0003a000) /* -0.000885010 */,
|
||||
PRESHIFT(0x000e0000) /* 0.003417969 */,
|
||||
-PRESHIFT(0x003df000) /* -0.015121460 */,
|
||||
PRESHIFT(0x00586000) /* 0.021575928 */,
|
||||
-PRESHIFT(0x01ee6000) /* -0.120697021 */,
|
||||
PRESHIFT(0x00046000) /* 0.001068115 */,
|
||||
-PRESHIFT(0x0ca8d000) /* -0.791213989 */,
|
||||
PRESHIFT(0x119e9000) /* 1.101211548 */,
|
||||
PRESHIFT(0x05991000) /* 0.349868774 */,
|
||||
PRESHIFT(0x02578000) /* 0.146362305 */,
|
||||
PRESHIFT(0x0091a000) /* 0.035552979 */,
|
||||
PRESHIFT(0x007d1000) /* 0.030532837 */,
|
||||
PRESHIFT(0x00048000) /* 0.001098633 */,
|
||||
PRESHIFT(0x000a1000) /* 0.002456665 */,
|
||||
PRESHIFT(0x0000d000) /* 0.000198364 */,
|
||||
|
||||
-PRESHIFT(0x00002000) /* -0.000030518 */,
|
||||
-PRESHIFT(0x0003a000) /* -0.000885010 */,
|
||||
PRESHIFT(0x000e0000) /* 0.003417969 */,
|
||||
-PRESHIFT(0x003df000) /* -0.015121460 */,
|
||||
PRESHIFT(0x00586000) /* 0.021575928 */,
|
||||
-PRESHIFT(0x01ee6000) /* -0.120697021 */,
|
||||
PRESHIFT(0x00046000) /* 0.001068115 */,
|
||||
-PRESHIFT(0x0ca8d000) /* -0.791213989 */,
|
||||
PRESHIFT(0x119e9000) /* 1.101211548 */,
|
||||
PRESHIFT(0x05991000) /* 0.349868774 */,
|
||||
PRESHIFT(0x02578000) /* 0.146362305 */,
|
||||
PRESHIFT(0x0091a000) /* 0.035552979 */,
|
||||
PRESHIFT(0x007d1000) /* 0.030532837 */,
|
||||
PRESHIFT(0x00048000) /* 0.001098633 */,
|
||||
PRESHIFT(0x000a1000) /* 0.002456665 */,
|
||||
PRESHIFT(0x0000d000) /* 0.000198364 */ },
|
||||
|
||||
{ -PRESHIFT(0x00002000) /* -0.000030518 */, /* 9 */
|
||||
-PRESHIFT(0x0003f000) /* -0.000961304 */,
|
||||
PRESHIFT(0x000dd000) /* 0.003372192 */,
|
||||
-PRESHIFT(0x00428000) /* -0.016235352 */,
|
||||
PRESHIFT(0x00500000) /* 0.019531250 */,
|
||||
-PRESHIFT(0x02011000) /* -0.125259399 */,
|
||||
-PRESHIFT(0x003e6000) /* -0.015228271 */,
|
||||
-PRESHIFT(0x0d11e000) /* -0.816864014 */,
|
||||
PRESHIFT(0x116fc000) /* 1.089782715 */,
|
||||
PRESHIFT(0x052c5000) /* 0.323318481 */,
|
||||
PRESHIFT(0x02616000) /* 0.148773193 */,
|
||||
PRESHIFT(0x007d6000) /* 0.030609131 */,
|
||||
PRESHIFT(0x007aa000) /* 0.029937744 */,
|
||||
PRESHIFT(0x00024000) /* 0.000549316 */,
|
||||
PRESHIFT(0x0009a000) /* 0.002349854 */,
|
||||
PRESHIFT(0x0000b000) /* 0.000167847 */,
|
||||
|
||||
-PRESHIFT(0x00002000) /* -0.000030518 */,
|
||||
-PRESHIFT(0x0003f000) /* -0.000961304 */,
|
||||
PRESHIFT(0x000dd000) /* 0.003372192 */,
|
||||
-PRESHIFT(0x00428000) /* -0.016235352 */,
|
||||
PRESHIFT(0x00500000) /* 0.019531250 */,
|
||||
-PRESHIFT(0x02011000) /* -0.125259399 */,
|
||||
-PRESHIFT(0x003e6000) /* -0.015228271 */,
|
||||
-PRESHIFT(0x0d11e000) /* -0.816864014 */,
|
||||
PRESHIFT(0x116fc000) /* 1.089782715 */,
|
||||
PRESHIFT(0x052c5000) /* 0.323318481 */,
|
||||
PRESHIFT(0x02616000) /* 0.148773193 */,
|
||||
PRESHIFT(0x007d6000) /* 0.030609131 */,
|
||||
PRESHIFT(0x007aa000) /* 0.029937744 */,
|
||||
PRESHIFT(0x00024000) /* 0.000549316 */,
|
||||
PRESHIFT(0x0009a000) /* 0.002349854 */,
|
||||
PRESHIFT(0x0000b000) /* 0.000167847 */ },
|
||||
|
||||
{ -PRESHIFT(0x00002000) /* -0.000030518 */, /* 10 */
|
||||
-PRESHIFT(0x00044000) /* -0.001037598 */,
|
||||
PRESHIFT(0x000d7000) /* 0.003280640 */,
|
||||
-PRESHIFT(0x00471000) /* -0.017349243 */,
|
||||
PRESHIFT(0x0046b000) /* 0.017257690 */,
|
||||
-PRESHIFT(0x0212b000) /* -0.129562378 */,
|
||||
-PRESHIFT(0x0084a000) /* -0.032379150 */,
|
||||
-PRESHIFT(0x0d78a000) /* -0.841949463 */,
|
||||
PRESHIFT(0x113be000) /* 1.077117920 */,
|
||||
PRESHIFT(0x04c16000) /* 0.297210693 */,
|
||||
PRESHIFT(0x02687000) /* 0.150497437 */,
|
||||
PRESHIFT(0x0069c000) /* 0.025817871 */,
|
||||
PRESHIFT(0x0077f000) /* 0.029281616 */,
|
||||
PRESHIFT(0x00002000) /* 0.000030518 */,
|
||||
PRESHIFT(0x00093000) /* 0.002243042 */,
|
||||
PRESHIFT(0x0000a000) /* 0.000152588 */,
|
||||
|
||||
-PRESHIFT(0x00002000) /* -0.000030518 */,
|
||||
-PRESHIFT(0x00044000) /* -0.001037598 */,
|
||||
PRESHIFT(0x000d7000) /* 0.003280640 */,
|
||||
-PRESHIFT(0x00471000) /* -0.017349243 */,
|
||||
PRESHIFT(0x0046b000) /* 0.017257690 */,
|
||||
-PRESHIFT(0x0212b000) /* -0.129562378 */,
|
||||
-PRESHIFT(0x0084a000) /* -0.032379150 */,
|
||||
-PRESHIFT(0x0d78a000) /* -0.841949463 */,
|
||||
PRESHIFT(0x113be000) /* 1.077117920 */,
|
||||
PRESHIFT(0x04c16000) /* 0.297210693 */,
|
||||
PRESHIFT(0x02687000) /* 0.150497437 */,
|
||||
PRESHIFT(0x0069c000) /* 0.025817871 */,
|
||||
PRESHIFT(0x0077f000) /* 0.029281616 */,
|
||||
PRESHIFT(0x00002000) /* 0.000030518 */,
|
||||
PRESHIFT(0x00093000) /* 0.002243042 */,
|
||||
PRESHIFT(0x0000a000) /* 0.000152588 */ },
|
||||
|
||||
{ -PRESHIFT(0x00003000) /* -0.000045776 */, /* 11 */
|
||||
-PRESHIFT(0x00049000) /* -0.001113892 */,
|
||||
PRESHIFT(0x000d0000) /* 0.003173828 */,
|
||||
-PRESHIFT(0x004ba000) /* -0.018463135 */,
|
||||
PRESHIFT(0x003ca000) /* 0.014801025 */,
|
||||
-PRESHIFT(0x02233000) /* -0.133590698 */,
|
||||
-PRESHIFT(0x00ce4000) /* -0.050354004 */,
|
||||
-PRESHIFT(0x0ddca000) /* -0.866363525 */,
|
||||
PRESHIFT(0x1102f000) /* 1.063217163 */,
|
||||
PRESHIFT(0x04587000) /* 0.271591187 */,
|
||||
PRESHIFT(0x026cf000) /* 0.151596069 */,
|
||||
PRESHIFT(0x0056c000) /* 0.021179199 */,
|
||||
PRESHIFT(0x0074e000) /* 0.028533936 */,
|
||||
-PRESHIFT(0x0001d000) /* -0.000442505 */,
|
||||
PRESHIFT(0x0008b000) /* 0.002120972 */,
|
||||
PRESHIFT(0x00009000) /* 0.000137329 */,
|
||||
|
||||
-PRESHIFT(0x00003000) /* -0.000045776 */,
|
||||
-PRESHIFT(0x00049000) /* -0.001113892 */,
|
||||
PRESHIFT(0x000d0000) /* 0.003173828 */,
|
||||
-PRESHIFT(0x004ba000) /* -0.018463135 */,
|
||||
PRESHIFT(0x003ca000) /* 0.014801025 */,
|
||||
-PRESHIFT(0x02233000) /* -0.133590698 */,
|
||||
-PRESHIFT(0x00ce4000) /* -0.050354004 */,
|
||||
-PRESHIFT(0x0ddca000) /* -0.866363525 */,
|
||||
PRESHIFT(0x1102f000) /* 1.063217163 */,
|
||||
PRESHIFT(0x04587000) /* 0.271591187 */,
|
||||
PRESHIFT(0x026cf000) /* 0.151596069 */,
|
||||
PRESHIFT(0x0056c000) /* 0.021179199 */,
|
||||
PRESHIFT(0x0074e000) /* 0.028533936 */,
|
||||
-PRESHIFT(0x0001d000) /* -0.000442505 */,
|
||||
PRESHIFT(0x0008b000) /* 0.002120972 */,
|
||||
PRESHIFT(0x00009000) /* 0.000137329 */ },
|
||||
|
||||
{ -PRESHIFT(0x00003000) /* -0.000045776 */, /* 12 */
|
||||
-PRESHIFT(0x0004f000) /* -0.001205444 */,
|
||||
PRESHIFT(0x000c8000) /* 0.003051758 */,
|
||||
-PRESHIFT(0x00503000) /* -0.019577026 */,
|
||||
PRESHIFT(0x0031a000) /* 0.012115479 */,
|
||||
-PRESHIFT(0x02326000) /* -0.137298584 */,
|
||||
-PRESHIFT(0x011b5000) /* -0.069168091 */,
|
||||
-PRESHIFT(0x0e3dd000) /* -0.890090942 */,
|
||||
PRESHIFT(0x10c54000) /* 1.048156738 */,
|
||||
PRESHIFT(0x03f1b000) /* 0.246505737 */,
|
||||
PRESHIFT(0x026ee000) /* 0.152069092 */,
|
||||
PRESHIFT(0x00447000) /* 0.016708374 */,
|
||||
PRESHIFT(0x00719000) /* 0.027725220 */,
|
||||
-PRESHIFT(0x00039000) /* -0.000869751 */,
|
||||
PRESHIFT(0x00084000) /* 0.002014160 */,
|
||||
PRESHIFT(0x00008000) /* 0.000122070 */,
|
||||
|
||||
-PRESHIFT(0x00003000) /* -0.000045776 */,
|
||||
-PRESHIFT(0x0004f000) /* -0.001205444 */,
|
||||
PRESHIFT(0x000c8000) /* 0.003051758 */,
|
||||
-PRESHIFT(0x00503000) /* -0.019577026 */,
|
||||
PRESHIFT(0x0031a000) /* 0.012115479 */,
|
||||
-PRESHIFT(0x02326000) /* -0.137298584 */,
|
||||
-PRESHIFT(0x011b5000) /* -0.069168091 */,
|
||||
-PRESHIFT(0x0e3dd000) /* -0.890090942 */,
|
||||
PRESHIFT(0x10c54000) /* 1.048156738 */,
|
||||
PRESHIFT(0x03f1b000) /* 0.246505737 */,
|
||||
PRESHIFT(0x026ee000) /* 0.152069092 */,
|
||||
PRESHIFT(0x00447000) /* 0.016708374 */,
|
||||
PRESHIFT(0x00719000) /* 0.027725220 */,
|
||||
-PRESHIFT(0x00039000) /* -0.000869751 */,
|
||||
PRESHIFT(0x00084000) /* 0.002014160 */,
|
||||
PRESHIFT(0x00008000) /* 0.000122070 */ },
|
||||
|
||||
{ -PRESHIFT(0x00004000) /* -0.000061035 */, /* 13 */
|
||||
-PRESHIFT(0x00055000) /* -0.001296997 */,
|
||||
PRESHIFT(0x000bd000) /* 0.002883911 */,
|
||||
-PRESHIFT(0x0054c000) /* -0.020690918 */,
|
||||
PRESHIFT(0x0025d000) /* 0.009231567 */,
|
||||
-PRESHIFT(0x02403000) /* -0.140670776 */,
|
||||
-PRESHIFT(0x016ba000) /* -0.088775635 */,
|
||||
-PRESHIFT(0x0e9be000) /* -0.913055420 */,
|
||||
PRESHIFT(0x1082d000) /* 1.031936646 */,
|
||||
PRESHIFT(0x038d4000) /* 0.221984863 */,
|
||||
PRESHIFT(0x026e7000) /* 0.151962280 */,
|
||||
PRESHIFT(0x0032e000) /* 0.012420654 */,
|
||||
PRESHIFT(0x006df000) /* 0.026840210 */,
|
||||
-PRESHIFT(0x00053000) /* -0.001266479 */,
|
||||
PRESHIFT(0x0007d000) /* 0.001907349 */,
|
||||
PRESHIFT(0x00007000) /* 0.000106812 */,
|
||||
|
||||
-PRESHIFT(0x00004000) /* -0.000061035 */,
|
||||
-PRESHIFT(0x00055000) /* -0.001296997 */,
|
||||
PRESHIFT(0x000bd000) /* 0.002883911 */,
|
||||
-PRESHIFT(0x0054c000) /* -0.020690918 */,
|
||||
PRESHIFT(0x0025d000) /* 0.009231567 */,
|
||||
-PRESHIFT(0x02403000) /* -0.140670776 */,
|
||||
-PRESHIFT(0x016ba000) /* -0.088775635 */,
|
||||
-PRESHIFT(0x0e9be000) /* -0.913055420 */,
|
||||
PRESHIFT(0x1082d000) /* 1.031936646 */,
|
||||
PRESHIFT(0x038d4000) /* 0.221984863 */,
|
||||
PRESHIFT(0x026e7000) /* 0.151962280 */,
|
||||
PRESHIFT(0x0032e000) /* 0.012420654 */,
|
||||
PRESHIFT(0x006df000) /* 0.026840210 */,
|
||||
-PRESHIFT(0x00053000) /* -0.001266479 */,
|
||||
PRESHIFT(0x0007d000) /* 0.001907349 */,
|
||||
PRESHIFT(0x00007000) /* 0.000106812 */ },
|
||||
|
||||
{ -PRESHIFT(0x00004000) /* -0.000061035 */, /* 14 */
|
||||
-PRESHIFT(0x0005b000) /* -0.001388550 */,
|
||||
PRESHIFT(0x000b1000) /* 0.002700806 */,
|
||||
-PRESHIFT(0x00594000) /* -0.021789551 */,
|
||||
PRESHIFT(0x00192000) /* 0.006134033 */,
|
||||
-PRESHIFT(0x024c8000) /* -0.143676758 */,
|
||||
-PRESHIFT(0x01bf2000) /* -0.109161377 */,
|
||||
-PRESHIFT(0x0ef69000) /* -0.935195923 */,
|
||||
PRESHIFT(0x103be000) /* 1.014617920 */,
|
||||
PRESHIFT(0x032b4000) /* 0.198059082 */,
|
||||
PRESHIFT(0x026bc000) /* 0.151306152 */,
|
||||
PRESHIFT(0x00221000) /* 0.008316040 */,
|
||||
PRESHIFT(0x006a2000) /* 0.025909424 */,
|
||||
-PRESHIFT(0x0006a000) /* -0.001617432 */,
|
||||
PRESHIFT(0x00075000) /* 0.001785278 */,
|
||||
PRESHIFT(0x00007000) /* 0.000106812 */,
|
||||
|
||||
-PRESHIFT(0x00004000) /* -0.000061035 */,
|
||||
-PRESHIFT(0x0005b000) /* -0.001388550 */,
|
||||
PRESHIFT(0x000b1000) /* 0.002700806 */,
|
||||
-PRESHIFT(0x00594000) /* -0.021789551 */,
|
||||
PRESHIFT(0x00192000) /* 0.006134033 */,
|
||||
-PRESHIFT(0x024c8000) /* -0.143676758 */,
|
||||
-PRESHIFT(0x01bf2000) /* -0.109161377 */,
|
||||
-PRESHIFT(0x0ef69000) /* -0.935195923 */,
|
||||
PRESHIFT(0x103be000) /* 1.014617920 */,
|
||||
PRESHIFT(0x032b4000) /* 0.198059082 */,
|
||||
PRESHIFT(0x026bc000) /* 0.151306152 */,
|
||||
PRESHIFT(0x00221000) /* 0.008316040 */,
|
||||
PRESHIFT(0x006a2000) /* 0.025909424 */,
|
||||
-PRESHIFT(0x0006a000) /* -0.001617432 */,
|
||||
PRESHIFT(0x00075000) /* 0.001785278 */,
|
||||
PRESHIFT(0x00007000) /* 0.000106812 */ },
|
||||
|
||||
{ -PRESHIFT(0x00005000) /* -0.000076294 */, /* 15 */
|
||||
-PRESHIFT(0x00061000) /* -0.001480103 */,
|
||||
PRESHIFT(0x000a3000) /* 0.002487183 */,
|
||||
-PRESHIFT(0x005da000) /* -0.022857666 */,
|
||||
PRESHIFT(0x000b9000) /* 0.002822876 */,
|
||||
-PRESHIFT(0x02571000) /* -0.146255493 */,
|
||||
-PRESHIFT(0x0215c000) /* -0.130310059 */,
|
||||
-PRESHIFT(0x0f4dc000) /* -0.956481934 */,
|
||||
PRESHIFT(0x0ff0a000) /* 0.996246338 */,
|
||||
PRESHIFT(0x02cbf000) /* 0.174789429 */,
|
||||
PRESHIFT(0x0266e000) /* 0.150115967 */,
|
||||
PRESHIFT(0x00120000) /* 0.004394531 */,
|
||||
PRESHIFT(0x00662000) /* 0.024932861 */,
|
||||
-PRESHIFT(0x0007f000) /* -0.001937866 */,
|
||||
PRESHIFT(0x0006f000) /* 0.001693726 */,
|
||||
PRESHIFT(0x00006000) /* 0.000091553 */,
|
||||
|
||||
-PRESHIFT(0x00005000) /* -0.000076294 */,
|
||||
-PRESHIFT(0x00061000) /* -0.001480103 */,
|
||||
PRESHIFT(0x000a3000) /* 0.002487183 */,
|
||||
-PRESHIFT(0x005da000) /* -0.022857666 */,
|
||||
PRESHIFT(0x000b9000) /* 0.002822876 */,
|
||||
-PRESHIFT(0x02571000) /* -0.146255493 */,
|
||||
-PRESHIFT(0x0215c000) /* -0.130310059 */,
|
||||
-PRESHIFT(0x0f4dc000) /* -0.956481934 */,
|
||||
PRESHIFT(0x0ff0a000) /* 0.996246338 */,
|
||||
PRESHIFT(0x02cbf000) /* 0.174789429 */,
|
||||
PRESHIFT(0x0266e000) /* 0.150115967 */,
|
||||
PRESHIFT(0x00120000) /* 0.004394531 */,
|
||||
PRESHIFT(0x00662000) /* 0.024932861 */,
|
||||
-PRESHIFT(0x0007f000) /* -0.001937866 */,
|
||||
PRESHIFT(0x0006f000) /* 0.001693726 */,
|
||||
PRESHIFT(0x00006000) /* 0.000091553 */ },
|
||||
|
||||
{ -PRESHIFT(0x00005000) /* -0.000076294 */, /* 16 */
|
||||
-PRESHIFT(0x00068000) /* -0.001586914 */,
|
||||
PRESHIFT(0x00092000) /* 0.002227783 */,
|
||||
-PRESHIFT(0x0061f000) /* -0.023910522 */,
|
||||
-PRESHIFT(0x0002d000) /* -0.000686646 */,
|
||||
-PRESHIFT(0x025ff000) /* -0.148422241 */,
|
||||
-PRESHIFT(0x026f7000) /* -0.152206421 */,
|
||||
-PRESHIFT(0x0fa13000) /* -0.976852417 */,
|
||||
PRESHIFT(0x0fa13000) /* 0.976852417 */,
|
||||
PRESHIFT(0x026f7000) /* 0.152206421 */,
|
||||
PRESHIFT(0x025ff000) /* 0.148422241 */,
|
||||
PRESHIFT(0x0002d000) /* 0.000686646 */,
|
||||
PRESHIFT(0x0061f000) /* 0.023910522 */,
|
||||
-PRESHIFT(0x00092000) /* -0.002227783 */,
|
||||
PRESHIFT(0x00068000) /* 0.001586914 */,
|
||||
PRESHIFT(0x00005000) /* 0.000076294 */,
|
||||
|
||||
-PRESHIFT(0x00005000) /* -0.000076294 */,
|
||||
-PRESHIFT(0x00068000) /* -0.001586914 */,
|
||||
PRESHIFT(0x00092000) /* 0.002227783 */,
|
||||
-PRESHIFT(0x0061f000) /* -0.023910522 */,
|
||||
-PRESHIFT(0x0002d000) /* -0.000686646 */,
|
||||
-PRESHIFT(0x025ff000) /* -0.148422241 */,
|
||||
-PRESHIFT(0x026f7000) /* -0.152206421 */,
|
||||
-PRESHIFT(0x0fa13000) /* -0.976852417 */,
|
||||
PRESHIFT(0x0fa13000) /* 0.976852417 */,
|
||||
PRESHIFT(0x026f7000) /* 0.152206421 */,
|
||||
PRESHIFT(0x025ff000) /* 0.148422241 */,
|
||||
PRESHIFT(0x0002d000) /* 0.000686646 */,
|
||||
PRESHIFT(0x0061f000) /* 0.023910522 */,
|
||||
-PRESHIFT(0x00092000) /* -0.002227783 */,
|
||||
PRESHIFT(0x00068000) /* 0.001586914 */,
|
||||
PRESHIFT(0x00005000) /* 0.000076294 */ }
|
235
libmad/bit.c
Normal file
235
libmad/bit.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: bit.c,v 1.12 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
#include "libmad_config.h"
|
||||
|
||||
# include "libmad_global.h"
|
||||
|
||||
# ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
# else
|
||||
# define CHAR_BIT 8
|
||||
# endif
|
||||
|
||||
# include "bit.h"
|
||||
|
||||
/*
|
||||
* This is the lookup table for computing the CRC-check word.
|
||||
* As described in section 2.4.3.1 and depicted in Figure A.9
|
||||
* of ISO/IEC 11172-3, the generator polynomial is:
|
||||
*
|
||||
* G(X) = X^16 + X^15 + X^2 + 1
|
||||
*/
|
||||
static
|
||||
unsigned short const crc_table[256] = {
|
||||
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
|
||||
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
|
||||
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
|
||||
0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
|
||||
0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
|
||||
0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
|
||||
0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
|
||||
0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
|
||||
|
||||
0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
|
||||
0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
|
||||
0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
|
||||
0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
|
||||
0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
|
||||
0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
|
||||
0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
|
||||
0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
|
||||
|
||||
0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
|
||||
0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
|
||||
0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
|
||||
0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
|
||||
0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
|
||||
0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
|
||||
0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
|
||||
0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
|
||||
|
||||
0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
|
||||
0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
|
||||
0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
|
||||
0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
|
||||
0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
|
||||
0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
|
||||
0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
|
||||
0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
|
||||
};
|
||||
|
||||
# define CRC_POLY 0x8005
|
||||
|
||||
/*
|
||||
* NAME: bit->init()
|
||||
* DESCRIPTION: initialize bit pointer struct
|
||||
*/
|
||||
void mad_bit_init(struct mad_bitptr *bitptr, unsigned char const *byte)
|
||||
{
|
||||
bitptr->byte = byte;
|
||||
bitptr->cache = 0;
|
||||
bitptr->left = CHAR_BIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: bit->length()
|
||||
* DESCRIPTION: return number of bits between start and end points
|
||||
*/
|
||||
unsigned int mad_bit_length(struct mad_bitptr const *begin,
|
||||
struct mad_bitptr const *end)
|
||||
{
|
||||
return begin->left +
|
||||
CHAR_BIT * (end->byte - (begin->byte + 1)) + (CHAR_BIT - end->left);
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: bit->nextbyte()
|
||||
* DESCRIPTION: return pointer to next unprocessed byte
|
||||
*/
|
||||
unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *bitptr)
|
||||
{
|
||||
return bitptr->left == CHAR_BIT ? bitptr->byte : bitptr->byte + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: bit->skip()
|
||||
* DESCRIPTION: advance bit pointer
|
||||
*/
|
||||
void mad_bit_skip(struct mad_bitptr *bitptr, unsigned int len)
|
||||
{
|
||||
bitptr->byte += len / CHAR_BIT;
|
||||
bitptr->left -= len % CHAR_BIT;
|
||||
|
||||
if (bitptr->left > CHAR_BIT) {
|
||||
bitptr->byte++;
|
||||
bitptr->left += CHAR_BIT;
|
||||
}
|
||||
|
||||
if (bitptr->left < CHAR_BIT)
|
||||
bitptr->cache = *bitptr->byte;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: bit->read()
|
||||
* DESCRIPTION: read an arbitrary number of bits and return their UIMSBF value
|
||||
*/
|
||||
unsigned long mad_bit_read(struct mad_bitptr *bitptr, unsigned int len)
|
||||
{
|
||||
register unsigned long value;
|
||||
|
||||
if (bitptr->left == CHAR_BIT)
|
||||
bitptr->cache = *bitptr->byte;
|
||||
|
||||
if (len < bitptr->left) {
|
||||
value = (bitptr->cache & ((1 << bitptr->left) - 1)) >>
|
||||
(bitptr->left - len);
|
||||
bitptr->left -= len;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* remaining bits in current byte */
|
||||
|
||||
value = bitptr->cache & ((1 << bitptr->left) - 1);
|
||||
len -= bitptr->left;
|
||||
|
||||
bitptr->byte++;
|
||||
bitptr->left = CHAR_BIT;
|
||||
|
||||
/* more bytes */
|
||||
|
||||
while (len >= CHAR_BIT) {
|
||||
value = (value << CHAR_BIT) | *bitptr->byte++;
|
||||
len -= CHAR_BIT;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
bitptr->cache = *bitptr->byte;
|
||||
|
||||
value = (value << len) | (bitptr->cache >> (CHAR_BIT - len));
|
||||
bitptr->left -= len;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
# if 0
|
||||
/*
|
||||
* NAME: bit->write()
|
||||
* DESCRIPTION: write an arbitrary number of bits
|
||||
*/
|
||||
void mad_bit_write(struct mad_bitptr *bitptr, unsigned int len,
|
||||
unsigned long value)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
|
||||
ptr = (unsigned char *) bitptr->byte;
|
||||
|
||||
/* ... */
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* NAME: bit->crc()
|
||||
* DESCRIPTION: compute CRC-check word
|
||||
*/
|
||||
unsigned short mad_bit_crc(struct mad_bitptr bitptr, unsigned int len,
|
||||
unsigned short init)
|
||||
{
|
||||
register unsigned int crc;
|
||||
|
||||
for (crc = init; len >= 32; len -= 32) {
|
||||
register unsigned long data;
|
||||
|
||||
data = mad_bit_read(&bitptr, 32);
|
||||
|
||||
crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 24)) & 0xff];
|
||||
crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 16)) & 0xff];
|
||||
crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 8)) & 0xff];
|
||||
crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 0)) & 0xff];
|
||||
}
|
||||
|
||||
switch (len / 8) {
|
||||
case 3: crc = (crc << 8) ^
|
||||
crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff];
|
||||
case 2: crc = (crc << 8) ^
|
||||
crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff];
|
||||
case 1: crc = (crc << 8) ^
|
||||
crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff];
|
||||
|
||||
len %= 8;
|
||||
|
||||
case 0: break;
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
register unsigned int msb;
|
||||
|
||||
msb = mad_bit_read(&bitptr, 1) ^ (crc >> 15);
|
||||
|
||||
crc <<= 1;
|
||||
if (msb & 1)
|
||||
crc ^= CRC_POLY;
|
||||
}
|
||||
|
||||
return crc & 0xffff;
|
||||
}
|
47
libmad/bit.h
Normal file
47
libmad/bit.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: bit.h,v 1.12 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_BIT_H
|
||||
# define LIBMAD_BIT_H
|
||||
|
||||
struct mad_bitptr {
|
||||
unsigned char const *byte;
|
||||
unsigned short cache;
|
||||
unsigned short left;
|
||||
};
|
||||
|
||||
void mad_bit_init(struct mad_bitptr *, unsigned char const *);
|
||||
|
||||
# define mad_bit_finish(bitptr) /* nothing */
|
||||
|
||||
unsigned int mad_bit_length(struct mad_bitptr const *,
|
||||
struct mad_bitptr const *);
|
||||
|
||||
# define mad_bit_bitsleft(bitptr) ((bitptr)->left)
|
||||
unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *);
|
||||
|
||||
void mad_bit_skip(struct mad_bitptr *, unsigned int);
|
||||
unsigned long mad_bit_read(struct mad_bitptr *, unsigned int);
|
||||
void mad_bit_write(struct mad_bitptr *, unsigned int, unsigned long);
|
||||
|
||||
unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short);
|
||||
|
||||
# endif
|
580
libmad/decoder.c
Normal file
580
libmad/decoder.c
Normal file
@ -0,0 +1,580 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: decoder.c,v 1.22 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
# include "libmad_config.h"
|
||||
|
||||
# include "libmad_global.h"
|
||||
|
||||
# ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
# endif
|
||||
|
||||
# include <stdlib.h>
|
||||
|
||||
# ifdef HAVE_ERRNO_H
|
||||
# include <errno.h>
|
||||
# endif
|
||||
|
||||
# include "stream.h"
|
||||
# include "frame.h"
|
||||
# include "synth.h"
|
||||
# include "decoder.h"
|
||||
|
||||
/*
|
||||
* NAME: decoder->init()
|
||||
* DESCRIPTION: initialize a decoder object with callback routines
|
||||
*/
|
||||
void mad_decoder_init(struct mad_decoder *decoder, void *data,
|
||||
enum mad_flow (*input_func)(void *,
|
||||
struct mad_stream *),
|
||||
enum mad_flow (*header_func)(void *,
|
||||
struct mad_header const *),
|
||||
enum mad_flow (*filter_func)(void *,
|
||||
struct mad_stream const *,
|
||||
struct mad_frame *),
|
||||
enum mad_flow (*output_func)(void *,
|
||||
struct mad_header const *,
|
||||
struct mad_pcm *),
|
||||
enum mad_flow (*error_func)(void *,
|
||||
struct mad_stream *,
|
||||
struct mad_frame *),
|
||||
enum mad_flow (*message_func)(void *,
|
||||
void *, unsigned int *))
|
||||
{
|
||||
decoder->mode = -1;
|
||||
|
||||
decoder->options = 0;
|
||||
|
||||
decoder->async.pid = 0;
|
||||
decoder->async.in = -1;
|
||||
decoder->async.out = -1;
|
||||
|
||||
decoder->sync = 0;
|
||||
|
||||
decoder->cb_data = data;
|
||||
|
||||
decoder->input_func = input_func;
|
||||
decoder->header_func = header_func;
|
||||
decoder->filter_func = filter_func;
|
||||
decoder->output_func = output_func;
|
||||
decoder->error_func = error_func;
|
||||
decoder->message_func = message_func;
|
||||
}
|
||||
|
||||
int mad_decoder_finish(struct mad_decoder *decoder)
|
||||
{
|
||||
# if defined(USE_ASYNC)
|
||||
if (decoder->mode == MAD_DECODER_MODE_ASYNC && decoder->async.pid) {
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
close(decoder->async.in);
|
||||
|
||||
do
|
||||
pid = waitpid(decoder->async.pid, &status, 0);
|
||||
while (pid == -1 && errno == EINTR);
|
||||
|
||||
decoder->mode = -1;
|
||||
|
||||
close(decoder->async.out);
|
||||
|
||||
decoder->async.pid = 0;
|
||||
decoder->async.in = -1;
|
||||
decoder->async.out = -1;
|
||||
|
||||
if (pid == -1)
|
||||
return -1;
|
||||
|
||||
return (!WIFEXITED(status) || WEXITSTATUS(status)) ? -1 : 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# if defined(USE_ASYNC)
|
||||
static
|
||||
enum mad_flow send_io(int fd, void const *data, size_t len)
|
||||
{
|
||||
char const *ptr = data;
|
||||
ssize_t count;
|
||||
|
||||
while (len) {
|
||||
do
|
||||
count = write(fd, ptr, len);
|
||||
while (count == -1 && errno == EINTR);
|
||||
|
||||
if (count == -1)
|
||||
return MAD_FLOW_BREAK;
|
||||
|
||||
len -= count;
|
||||
ptr += count;
|
||||
}
|
||||
|
||||
return MAD_FLOW_CONTINUE;
|
||||
}
|
||||
|
||||
static
|
||||
enum mad_flow receive_io(int fd, void *buffer, size_t len)
|
||||
{
|
||||
char *ptr = buffer;
|
||||
ssize_t count;
|
||||
|
||||
while (len) {
|
||||
do
|
||||
count = read(fd, ptr, len);
|
||||
while (count == -1 && errno == EINTR);
|
||||
|
||||
if (count == -1)
|
||||
return (errno == EAGAIN) ? MAD_FLOW_IGNORE : MAD_FLOW_BREAK;
|
||||
else if (count == 0)
|
||||
return MAD_FLOW_STOP;
|
||||
|
||||
len -= count;
|
||||
ptr += count;
|
||||
}
|
||||
|
||||
return MAD_FLOW_CONTINUE;
|
||||
}
|
||||
|
||||
static
|
||||
enum mad_flow receive_io_blocking(int fd, void *buffer, size_t len)
|
||||
{
|
||||
int flags, blocking;
|
||||
enum mad_flow result;
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags == -1)
|
||||
return MAD_FLOW_BREAK;
|
||||
|
||||
blocking = flags & ~O_NONBLOCK;
|
||||
|
||||
if (blocking != flags &&
|
||||
fcntl(fd, F_SETFL, blocking) == -1)
|
||||
return MAD_FLOW_BREAK;
|
||||
|
||||
result = receive_io(fd, buffer, len);
|
||||
|
||||
if (flags != blocking &&
|
||||
fcntl(fd, F_SETFL, flags) == -1)
|
||||
return MAD_FLOW_BREAK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
enum mad_flow send(int fd, void const *message, unsigned int size)
|
||||
{
|
||||
enum mad_flow result;
|
||||
|
||||
/* send size */
|
||||
|
||||
result = send_io(fd, &size, sizeof(size));
|
||||
|
||||
/* send message */
|
||||
|
||||
if (result == MAD_FLOW_CONTINUE)
|
||||
result = send_io(fd, message, size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
enum mad_flow receive(int fd, void **message, unsigned int *size)
|
||||
{
|
||||
enum mad_flow result;
|
||||
unsigned int actual;
|
||||
|
||||
if (*message == 0)
|
||||
*size = 0;
|
||||
|
||||
/* receive size */
|
||||
|
||||
result = receive_io(fd, &actual, sizeof(actual));
|
||||
|
||||
/* receive message */
|
||||
|
||||
if (result == MAD_FLOW_CONTINUE) {
|
||||
if (actual > *size)
|
||||
actual -= *size;
|
||||
else {
|
||||
*size = actual;
|
||||
actual = 0;
|
||||
}
|
||||
|
||||
if (*size > 0) {
|
||||
if (*message == 0) {
|
||||
*message = malloc(*size);
|
||||
if (*message == 0)
|
||||
return MAD_FLOW_BREAK;
|
||||
}
|
||||
|
||||
result = receive_io_blocking(fd, *message, *size);
|
||||
}
|
||||
|
||||
/* throw away remainder of message */
|
||||
|
||||
while (actual && result == MAD_FLOW_CONTINUE) {
|
||||
char sink[256];
|
||||
unsigned int len;
|
||||
|
||||
len = actual > sizeof(sink) ? sizeof(sink) : actual;
|
||||
|
||||
result = receive_io_blocking(fd, sink, len);
|
||||
|
||||
actual -= len;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
enum mad_flow check_message(struct mad_decoder *decoder)
|
||||
{
|
||||
enum mad_flow result;
|
||||
void *message = 0;
|
||||
unsigned int size;
|
||||
|
||||
result = receive(decoder->async.in, &message, &size);
|
||||
|
||||
if (result == MAD_FLOW_CONTINUE) {
|
||||
if (decoder->message_func == 0)
|
||||
size = 0;
|
||||
else {
|
||||
result = decoder->message_func(decoder->cb_data, message, &size);
|
||||
|
||||
if (result == MAD_FLOW_IGNORE ||
|
||||
result == MAD_FLOW_BREAK)
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if (send(decoder->async.out, message, size) != MAD_FLOW_CONTINUE)
|
||||
result = MAD_FLOW_BREAK;
|
||||
}
|
||||
|
||||
if (message)
|
||||
free(message);
|
||||
|
||||
return result;
|
||||
}
|
||||
# endif
|
||||
|
||||
static
|
||||
enum mad_flow error_default(void *data, struct mad_stream *stream,
|
||||
struct mad_frame *frame)
|
||||
{
|
||||
int *bad_last_frame = data;
|
||||
|
||||
switch (stream->error) {
|
||||
case MAD_ERROR_BADCRC:
|
||||
if (*bad_last_frame)
|
||||
mad_frame_mute(frame);
|
||||
else
|
||||
*bad_last_frame = 1;
|
||||
|
||||
return MAD_FLOW_IGNORE;
|
||||
|
||||
default:
|
||||
return MAD_FLOW_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int run_sync(struct mad_decoder *decoder)
|
||||
{
|
||||
enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
|
||||
void *error_data;
|
||||
int bad_last_frame = 0;
|
||||
struct mad_stream *stream;
|
||||
struct mad_frame *frame;
|
||||
struct mad_synth *synth;
|
||||
int result = 0;
|
||||
|
||||
if (decoder->input_func == 0)
|
||||
return 0;
|
||||
|
||||
if (decoder->error_func) {
|
||||
error_func = decoder->error_func;
|
||||
error_data = decoder->cb_data;
|
||||
}
|
||||
else {
|
||||
error_func = error_default;
|
||||
error_data = &bad_last_frame;
|
||||
}
|
||||
|
||||
stream = &decoder->sync->stream;
|
||||
frame = &decoder->sync->frame;
|
||||
synth = &decoder->sync->synth;
|
||||
|
||||
mad_stream_init(stream);
|
||||
mad_frame_init(frame);
|
||||
mad_synth_init(synth);
|
||||
|
||||
mad_stream_options(stream, decoder->options);
|
||||
|
||||
do {
|
||||
switch (decoder->input_func(decoder->cb_data, stream)) {
|
||||
case MAD_FLOW_STOP:
|
||||
goto done;
|
||||
case MAD_FLOW_BREAK:
|
||||
goto fail;
|
||||
case MAD_FLOW_IGNORE:
|
||||
continue;
|
||||
case MAD_FLOW_CONTINUE:
|
||||
break;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
# if defined(USE_ASYNC)
|
||||
if (decoder->mode == MAD_DECODER_MODE_ASYNC) {
|
||||
switch (check_message(decoder)) {
|
||||
case MAD_FLOW_IGNORE:
|
||||
case MAD_FLOW_CONTINUE:
|
||||
break;
|
||||
case MAD_FLOW_BREAK:
|
||||
goto fail;
|
||||
case MAD_FLOW_STOP:
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
if (decoder->header_func) {
|
||||
if (mad_header_decode(&frame->header, stream) == -1) {
|
||||
if (!MAD_RECOVERABLE(stream->error))
|
||||
break;
|
||||
|
||||
switch (error_func(error_data, stream, frame)) {
|
||||
case MAD_FLOW_STOP:
|
||||
goto done;
|
||||
case MAD_FLOW_BREAK:
|
||||
goto fail;
|
||||
case MAD_FLOW_IGNORE:
|
||||
case MAD_FLOW_CONTINUE:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (decoder->header_func(decoder->cb_data, &frame->header)) {
|
||||
case MAD_FLOW_STOP:
|
||||
goto done;
|
||||
case MAD_FLOW_BREAK:
|
||||
goto fail;
|
||||
case MAD_FLOW_IGNORE:
|
||||
continue;
|
||||
case MAD_FLOW_CONTINUE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mad_frame_decode(frame, stream) == -1) {
|
||||
if (!MAD_RECOVERABLE(stream->error))
|
||||
break;
|
||||
|
||||
switch (error_func(error_data, stream, frame)) {
|
||||
case MAD_FLOW_STOP:
|
||||
goto done;
|
||||
case MAD_FLOW_BREAK:
|
||||
goto fail;
|
||||
case MAD_FLOW_IGNORE:
|
||||
break;
|
||||
case MAD_FLOW_CONTINUE:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
bad_last_frame = 0;
|
||||
|
||||
if (decoder->filter_func) {
|
||||
switch (decoder->filter_func(decoder->cb_data, stream, frame)) {
|
||||
case MAD_FLOW_STOP:
|
||||
goto done;
|
||||
case MAD_FLOW_BREAK:
|
||||
goto fail;
|
||||
case MAD_FLOW_IGNORE:
|
||||
continue;
|
||||
case MAD_FLOW_CONTINUE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mad_synth_frame(synth, frame);
|
||||
|
||||
if (decoder->output_func) {
|
||||
switch (decoder->output_func(decoder->cb_data,
|
||||
&frame->header, &synth->pcm)) {
|
||||
case MAD_FLOW_STOP:
|
||||
goto done;
|
||||
case MAD_FLOW_BREAK:
|
||||
goto fail;
|
||||
case MAD_FLOW_IGNORE:
|
||||
case MAD_FLOW_CONTINUE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (stream->error == MAD_ERROR_BUFLEN);
|
||||
|
||||
fail:
|
||||
result = -1;
|
||||
|
||||
done:
|
||||
mad_synth_finish(synth);
|
||||
mad_frame_finish(frame);
|
||||
mad_stream_finish(stream);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
# if defined(USE_ASYNC)
|
||||
static
|
||||
int run_async(struct mad_decoder *decoder)
|
||||
{
|
||||
pid_t pid;
|
||||
int ptoc[2], ctop[2], flags;
|
||||
|
||||
if (pipe(ptoc) == -1)
|
||||
return -1;
|
||||
|
||||
if (pipe(ctop) == -1) {
|
||||
close(ptoc[0]);
|
||||
close(ptoc[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
flags = fcntl(ptoc[0], F_GETFL);
|
||||
if (flags == -1 ||
|
||||
fcntl(ptoc[0], F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
close(ctop[0]);
|
||||
close(ctop[1]);
|
||||
close(ptoc[0]);
|
||||
close(ptoc[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
close(ctop[0]);
|
||||
close(ctop[1]);
|
||||
close(ptoc[0]);
|
||||
close(ptoc[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
decoder->async.pid = pid;
|
||||
|
||||
if (pid) {
|
||||
/* parent */
|
||||
|
||||
close(ptoc[0]);
|
||||
close(ctop[1]);
|
||||
|
||||
decoder->async.in = ctop[0];
|
||||
decoder->async.out = ptoc[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* child */
|
||||
|
||||
close(ptoc[1]);
|
||||
close(ctop[0]);
|
||||
|
||||
decoder->async.in = ptoc[0];
|
||||
decoder->async.out = ctop[1];
|
||||
|
||||
_exit(run_sync(decoder));
|
||||
|
||||
/* not reached */
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* NAME: decoder->run()
|
||||
* DESCRIPTION: run the decoder thread either synchronously or asynchronously
|
||||
*/
|
||||
int mad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode)
|
||||
{
|
||||
int result;
|
||||
int (*run)(struct mad_decoder *) = 0;
|
||||
|
||||
switch (decoder->mode = mode) {
|
||||
case MAD_DECODER_MODE_SYNC:
|
||||
run = run_sync;
|
||||
break;
|
||||
|
||||
case MAD_DECODER_MODE_ASYNC:
|
||||
# if defined(USE_ASYNC)
|
||||
run = run_async;
|
||||
# endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (run == 0)
|
||||
return -1;
|
||||
|
||||
decoder->sync = malloc(sizeof(*decoder->sync));
|
||||
if (decoder->sync == 0)
|
||||
return -1;
|
||||
|
||||
result = run(decoder);
|
||||
|
||||
free(decoder->sync);
|
||||
decoder->sync = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: decoder->message()
|
||||
* DESCRIPTION: send a message to and receive a reply from the decoder process
|
||||
*/
|
||||
int mad_decoder_message(struct mad_decoder *decoder,
|
||||
void *message, unsigned int *len)
|
||||
{
|
||||
# if defined(USE_ASYNC)
|
||||
if (decoder->mode != MAD_DECODER_MODE_ASYNC ||
|
||||
send(decoder->async.out, message, *len) != MAD_FLOW_CONTINUE ||
|
||||
receive(decoder->async.in, &message, len) != MAD_FLOW_CONTINUE)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
# else
|
||||
return -1;
|
||||
# endif
|
||||
}
|
91
libmad/decoder.h
Normal file
91
libmad/decoder.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: decoder.h,v 1.17 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_DECODER_H
|
||||
# define LIBMAD_DECODER_H
|
||||
|
||||
# include "stream.h"
|
||||
# include "frame.h"
|
||||
# include "synth.h"
|
||||
|
||||
enum mad_decoder_mode {
|
||||
MAD_DECODER_MODE_SYNC = 0,
|
||||
MAD_DECODER_MODE_ASYNC
|
||||
};
|
||||
|
||||
enum mad_flow {
|
||||
MAD_FLOW_CONTINUE = 0x0000, /* continue normally */
|
||||
MAD_FLOW_STOP = 0x0010, /* stop decoding normally */
|
||||
MAD_FLOW_BREAK = 0x0011, /* stop decoding and signal an error */
|
||||
MAD_FLOW_IGNORE = 0x0020 /* ignore the current frame */
|
||||
};
|
||||
|
||||
struct mad_decoder {
|
||||
enum mad_decoder_mode mode;
|
||||
|
||||
int options;
|
||||
|
||||
struct {
|
||||
long pid;
|
||||
int in;
|
||||
int out;
|
||||
} async;
|
||||
|
||||
struct {
|
||||
struct mad_stream stream;
|
||||
struct mad_frame frame;
|
||||
struct mad_synth synth;
|
||||
} *sync;
|
||||
|
||||
void *cb_data;
|
||||
|
||||
enum mad_flow (*input_func)(void *, struct mad_stream *);
|
||||
enum mad_flow (*header_func)(void *, struct mad_header const *);
|
||||
enum mad_flow (*filter_func)(void *,
|
||||
struct mad_stream const *, struct mad_frame *);
|
||||
enum mad_flow (*output_func)(void *,
|
||||
struct mad_header const *, struct mad_pcm *);
|
||||
enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
|
||||
enum mad_flow (*message_func)(void *, void *, unsigned int *);
|
||||
};
|
||||
|
||||
void mad_decoder_init(struct mad_decoder *, void *,
|
||||
enum mad_flow (*)(void *, struct mad_stream *),
|
||||
enum mad_flow (*)(void *, struct mad_header const *),
|
||||
enum mad_flow (*)(void *,
|
||||
struct mad_stream const *,
|
||||
struct mad_frame *),
|
||||
enum mad_flow (*)(void *,
|
||||
struct mad_header const *,
|
||||
struct mad_pcm *),
|
||||
enum mad_flow (*)(void *,
|
||||
struct mad_stream *,
|
||||
struct mad_frame *),
|
||||
enum mad_flow (*)(void *, void *, unsigned int *));
|
||||
int mad_decoder_finish(struct mad_decoder *);
|
||||
|
||||
# define mad_decoder_options(decoder, opts) \
|
||||
((void) ((decoder)->options = (opts)))
|
||||
|
||||
int mad_decoder_run(struct mad_decoder *, enum mad_decoder_mode);
|
||||
int mad_decoder_message(struct mad_decoder *, void *, unsigned int *);
|
||||
|
||||
# endif
|
79
libmad/fixed.c
Normal file
79
libmad/fixed.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: fixed.c,v 1.13 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
# include "libmad_config.h"
|
||||
|
||||
# include "libmad_global.h"
|
||||
|
||||
# include "fixed.h"
|
||||
|
||||
/*
|
||||
* NAME: fixed->abs()
|
||||
* DESCRIPTION: return absolute value of a fixed-point number
|
||||
*/
|
||||
mad_fixed_t mad_f_abs(mad_fixed_t x)
|
||||
{
|
||||
return x < 0 ? -x : x;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: fixed->div()
|
||||
* DESCRIPTION: perform division using fixed-point math
|
||||
*/
|
||||
mad_fixed_t mad_f_div(mad_fixed_t x, mad_fixed_t y)
|
||||
{
|
||||
mad_fixed_t q, r;
|
||||
unsigned int bits;
|
||||
|
||||
q = mad_f_abs(x / y);
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
|
||||
r = x % y;
|
||||
|
||||
if (y < 0) {
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
|
||||
if (q > mad_f_intpart(MAD_F_MAX) &&
|
||||
!(q == -mad_f_intpart(MAD_F_MIN) && r == 0 && (x < 0) != (y < 0)))
|
||||
return 0;
|
||||
|
||||
for (bits = MAD_F_FRACBITS; bits && r; --bits) {
|
||||
q <<= 1, r <<= 1;
|
||||
if (r >= y)
|
||||
r -= y, ++q;
|
||||
}
|
||||
|
||||
/* round */
|
||||
if (2 * r >= y)
|
||||
++q;
|
||||
|
||||
/* fix sign */
|
||||
if ((x < 0) != (y < 0))
|
||||
q = -q;
|
||||
|
||||
return q << bits;
|
||||
}
|
499
libmad/fixed.h
Normal file
499
libmad/fixed.h
Normal file
@ -0,0 +1,499 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: fixed.h,v 1.38 2004/02/17 02:02:03 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_FIXED_H
|
||||
# define LIBMAD_FIXED_H
|
||||
|
||||
# if SIZEOF_INT >= 4
|
||||
typedef signed int mad_fixed_t;
|
||||
|
||||
typedef signed int mad_fixed64hi_t;
|
||||
typedef unsigned int mad_fixed64lo_t;
|
||||
# else
|
||||
typedef signed long mad_fixed_t;
|
||||
|
||||
typedef signed long mad_fixed64hi_t;
|
||||
typedef unsigned long mad_fixed64lo_t;
|
||||
# endif
|
||||
|
||||
# if defined(_MSC_VER)
|
||||
# define mad_fixed64_t signed __int64
|
||||
# elif 1 || defined(__GNUC__)
|
||||
# define mad_fixed64_t signed long long
|
||||
# endif
|
||||
|
||||
# if defined(FPM_FLOAT)
|
||||
typedef double mad_sample_t;
|
||||
# else
|
||||
typedef mad_fixed_t mad_sample_t;
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Fixed-point format: 0xABBBBBBB
|
||||
* A == whole part (sign + 3 bits)
|
||||
* B == fractional part (28 bits)
|
||||
*
|
||||
* Values are signed two's complement, so the effective range is:
|
||||
* 0x80000000 to 0x7fffffff
|
||||
* -8.0 to +7.9999999962747097015380859375
|
||||
*
|
||||
* The smallest representable value is:
|
||||
* 0x00000001 == 0.0000000037252902984619140625 (i.e. about 3.725e-9)
|
||||
*
|
||||
* 28 bits of fractional accuracy represent about
|
||||
* 8.6 digits of decimal accuracy.
|
||||
*
|
||||
* Fixed-point numbers can be added or subtracted as normal
|
||||
* integers, but multiplication requires shifting the 64-bit result
|
||||
* from 56 fractional bits back to 28 (and rounding.)
|
||||
*
|
||||
* Changing the definition of MAD_F_FRACBITS is only partially
|
||||
* supported, and must be done with care.
|
||||
*/
|
||||
|
||||
# define MAD_F_FRACBITS 28
|
||||
|
||||
# if MAD_F_FRACBITS == 28
|
||||
# define MAD_F(x) ((mad_fixed_t) (x##L))
|
||||
# else
|
||||
# if MAD_F_FRACBITS < 28
|
||||
# warning "MAD_F_FRACBITS < 28"
|
||||
# define MAD_F(x) ((mad_fixed_t) \
|
||||
(((x##L) + \
|
||||
(1L << (28 - MAD_F_FRACBITS - 1))) >> \
|
||||
(28 - MAD_F_FRACBITS)))
|
||||
# elif MAD_F_FRACBITS > 28
|
||||
# error "MAD_F_FRACBITS > 28 not currently supported"
|
||||
# define MAD_F(x) ((mad_fixed_t) \
|
||||
((x##L) << (MAD_F_FRACBITS - 28)))
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# define MAD_F_MIN ((mad_fixed_t) -0x80000000L)
|
||||
# define MAD_F_MAX ((mad_fixed_t) +0x7fffffffL)
|
||||
|
||||
# define MAD_F_ONE MAD_F(0x10000000)
|
||||
|
||||
# define mad_f_tofixed(x) ((mad_fixed_t) \
|
||||
((x) * (double) (1L << MAD_F_FRACBITS) + 0.5))
|
||||
# define mad_f_todouble(x) ((double) \
|
||||
((x) / (double) (1L << MAD_F_FRACBITS)))
|
||||
|
||||
# define mad_f_intpart(x) ((x) >> MAD_F_FRACBITS)
|
||||
# define mad_f_fracpart(x) ((x) & ((1L << MAD_F_FRACBITS) - 1))
|
||||
/* (x should be positive) */
|
||||
|
||||
# define mad_f_fromint(x) ((x) << MAD_F_FRACBITS)
|
||||
|
||||
# define mad_f_add(x, y) ((x) + (y))
|
||||
# define mad_f_sub(x, y) ((x) - (y))
|
||||
|
||||
# if defined(FPM_FLOAT)
|
||||
# error "FPM_FLOAT not yet supported"
|
||||
|
||||
# undef MAD_F
|
||||
# define MAD_F(x) mad_f_todouble(x)
|
||||
|
||||
# define mad_f_mul(x, y) ((x) * (y))
|
||||
# define mad_f_scale64
|
||||
|
||||
# undef ASO_ZEROCHECK
|
||||
|
||||
# elif defined(FPM_64BIT)
|
||||
|
||||
/*
|
||||
* This version should be the most accurate if 64-bit types are supported by
|
||||
* the compiler, although it may not be the most efficient.
|
||||
*/
|
||||
# if defined(OPT_ACCURACY)
|
||||
# define mad_f_mul(x, y) \
|
||||
((mad_fixed_t) \
|
||||
((((mad_fixed64_t) (x) * (y)) + \
|
||||
(1L << (MAD_F_SCALEBITS - 1))) >> MAD_F_SCALEBITS))
|
||||
# else
|
||||
# define mad_f_mul(x, y) \
|
||||
((mad_fixed_t) (((mad_fixed64_t) (x) * (y)) >> MAD_F_SCALEBITS))
|
||||
# endif
|
||||
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
|
||||
/* --- Intel --------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_INTEL)
|
||||
|
||||
# if defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4035) /* no return value */
|
||||
static __forceinline
|
||||
mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y)
|
||||
{
|
||||
enum {
|
||||
fracbits = MAD_F_FRACBITS
|
||||
};
|
||||
|
||||
__asm {
|
||||
mov eax, x
|
||||
imul y
|
||||
shrd eax, edx, fracbits
|
||||
}
|
||||
|
||||
/* implicit return of eax */
|
||||
}
|
||||
# pragma warning(pop)
|
||||
|
||||
# define mad_f_mul mad_f_mul_inline
|
||||
# define mad_f_scale64
|
||||
# else
|
||||
/*
|
||||
* This Intel version is fast and accurate; the disposition of the least
|
||||
* significant bit depends on OPT_ACCURACY via mad_f_scale64().
|
||||
*/
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
asm ("imull %3" \
|
||||
: "=a" (lo), "=d" (hi) \
|
||||
: "%a" (x), "rm" (y) \
|
||||
: "cc")
|
||||
|
||||
# if defined(OPT_ACCURACY)
|
||||
/*
|
||||
* This gives best accuracy but is not very fast.
|
||||
*/
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
({ mad_fixed64hi_t __hi; \
|
||||
mad_fixed64lo_t __lo; \
|
||||
MAD_F_MLX(__hi, __lo, (x), (y)); \
|
||||
asm ("addl %2,%0\n\t" \
|
||||
"adcl %3,%1" \
|
||||
: "=rm" (lo), "=rm" (hi) \
|
||||
: "r" (__lo), "r" (__hi), "0" (lo), "1" (hi) \
|
||||
: "cc"); \
|
||||
})
|
||||
# endif /* OPT_ACCURACY */
|
||||
|
||||
# if defined(OPT_ACCURACY)
|
||||
/*
|
||||
* Surprisingly, this is faster than SHRD followed by ADC.
|
||||
*/
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed64hi_t __hi_; \
|
||||
mad_fixed64lo_t __lo_; \
|
||||
mad_fixed_t __result; \
|
||||
asm ("addl %4,%2\n\t" \
|
||||
"adcl %5,%3" \
|
||||
: "=rm" (__lo_), "=rm" (__hi_) \
|
||||
: "0" (lo), "1" (hi), \
|
||||
"ir" (1L << (MAD_F_SCALEBITS - 1)), "ir" (0) \
|
||||
: "cc"); \
|
||||
asm ("shrdl %3,%2,%1" \
|
||||
: "=rm" (__result) \
|
||||
: "0" (__lo_), "r" (__hi_), "I" (MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
# elif defined(OPT_INTEL)
|
||||
/*
|
||||
* Alternate Intel scaling that may or may not perform better.
|
||||
*/
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result; \
|
||||
asm ("shrl %3,%1\n\t" \
|
||||
"shll %4,%2\n\t" \
|
||||
"orl %2,%1" \
|
||||
: "=rm" (__result) \
|
||||
: "0" (lo), "r" (hi), \
|
||||
"I" (MAD_F_SCALEBITS), "I" (32 - MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
# else
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result; \
|
||||
asm ("shrdl %3,%2,%1" \
|
||||
: "=rm" (__result) \
|
||||
: "0" (lo), "r" (hi), "I" (MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
# endif /* OPT_ACCURACY */
|
||||
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
# endif
|
||||
|
||||
/* --- ARM ----------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_ARM)
|
||||
|
||||
/*
|
||||
* This ARM V4 version is as accurate as FPM_64BIT but much faster. The
|
||||
* least significant bit is properly rounded at no CPU cycle cost!
|
||||
*/
|
||||
# if 1
|
||||
/*
|
||||
* This is faster than the default implementation via MAD_F_MLX() and
|
||||
* mad_f_scale64().
|
||||
*/
|
||||
# define mad_f_mul(x, y) \
|
||||
({ mad_fixed64hi_t __hi; \
|
||||
mad_fixed64lo_t __lo; \
|
||||
mad_fixed_t __result; \
|
||||
asm ("smull %0, %1, %3, %4\n\t" \
|
||||
"movs %0, %0, lsr %5\n\t" \
|
||||
"adc %2, %0, %1, lsl %6" \
|
||||
: "=&r" (__lo), "=&r" (__hi), "=r" (__result) \
|
||||
: "%r" (x), "r" (y), \
|
||||
"M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
# endif
|
||||
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
asm ("smull %0, %1, %2, %3" \
|
||||
: "=&r" (lo), "=&r" (hi) \
|
||||
: "%r" (x), "r" (y))
|
||||
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
asm ("smlal %0, %1, %2, %3" \
|
||||
: "+r" (lo), "+r" (hi) \
|
||||
: "%r" (x), "r" (y))
|
||||
|
||||
# define MAD_F_MLN(hi, lo) \
|
||||
asm ("rsbs %0, %2, #0\n\t" \
|
||||
"rsc %1, %3, #0" \
|
||||
: "=r" (lo), "=r" (hi) \
|
||||
: "0" (lo), "1" (hi) \
|
||||
: "cc")
|
||||
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result; \
|
||||
asm ("movs %0, %1, lsr %3\n\t" \
|
||||
"adc %0, %0, %2, lsl %4" \
|
||||
: "=&r" (__result) \
|
||||
: "r" (lo), "r" (hi), \
|
||||
"M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
|
||||
/* --- MIPS ---------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_MIPS)
|
||||
|
||||
/*
|
||||
* This MIPS version is fast and accurate; the disposition of the least
|
||||
* significant bit depends on OPT_ACCURACY via mad_f_scale64().
|
||||
*/
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
asm ("mult %2,%3" \
|
||||
: "=l" (lo), "=h" (hi) \
|
||||
: "%r" (x), "r" (y))
|
||||
|
||||
# if defined(HAVE_MADD_ASM)
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
asm ("madd %2,%3" \
|
||||
: "+l" (lo), "+h" (hi) \
|
||||
: "%r" (x), "r" (y))
|
||||
# elif defined(HAVE_MADD16_ASM)
|
||||
/*
|
||||
* This loses significant accuracy due to the 16-bit integer limit in the
|
||||
* multiply/accumulate instruction.
|
||||
*/
|
||||
# define MAD_F_ML0(hi, lo, x, y) \
|
||||
asm ("mult %2,%3" \
|
||||
: "=l" (lo), "=h" (hi) \
|
||||
: "%r" ((x) >> 12), "r" ((y) >> 16))
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
asm ("madd16 %2,%3" \
|
||||
: "+l" (lo), "+h" (hi) \
|
||||
: "%r" ((x) >> 12), "r" ((y) >> 16))
|
||||
# define MAD_F_MLZ(hi, lo) ((mad_fixed_t) (lo))
|
||||
# endif
|
||||
|
||||
# if defined(OPT_SPEED)
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
((mad_fixed_t) ((hi) << (32 - MAD_F_SCALEBITS)))
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
# endif
|
||||
|
||||
/* --- SPARC --------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_SPARC)
|
||||
|
||||
/*
|
||||
* This SPARC V8 version is fast and accurate; the disposition of the least
|
||||
* significant bit depends on OPT_ACCURACY via mad_f_scale64().
|
||||
*/
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
asm ("smul %2, %3, %0\n\t" \
|
||||
"rd %%y, %1" \
|
||||
: "=r" (lo), "=r" (hi) \
|
||||
: "%r" (x), "rI" (y))
|
||||
|
||||
/* --- PowerPC ------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_PPC)
|
||||
|
||||
/*
|
||||
* This PowerPC version is fast and accurate; the disposition of the least
|
||||
* significant bit depends on OPT_ACCURACY via mad_f_scale64().
|
||||
*/
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
do { \
|
||||
asm ("mullw %0,%1,%2" \
|
||||
: "=r" (lo) \
|
||||
: "%r" (x), "r" (y)); \
|
||||
asm ("mulhw %0,%1,%2" \
|
||||
: "=r" (hi) \
|
||||
: "%r" (x), "r" (y)); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
# if defined(OPT_ACCURACY)
|
||||
/*
|
||||
* This gives best accuracy but is not very fast.
|
||||
*/
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
({ mad_fixed64hi_t __hi; \
|
||||
mad_fixed64lo_t __lo; \
|
||||
MAD_F_MLX(__hi, __lo, (x), (y)); \
|
||||
asm ("addc %0,%2,%3\n\t" \
|
||||
"adde %1,%4,%5" \
|
||||
: "=r" (lo), "=r" (hi) \
|
||||
: "%r" (lo), "r" (__lo), \
|
||||
"%r" (hi), "r" (__hi) \
|
||||
: "xer"); \
|
||||
})
|
||||
# endif
|
||||
|
||||
# if defined(OPT_ACCURACY)
|
||||
/*
|
||||
* This is slower than the truncating version below it.
|
||||
*/
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result, __round; \
|
||||
asm ("rotrwi %0,%1,%2" \
|
||||
: "=r" (__result) \
|
||||
: "r" (lo), "i" (MAD_F_SCALEBITS)); \
|
||||
asm ("extrwi %0,%1,1,0" \
|
||||
: "=r" (__round) \
|
||||
: "r" (__result)); \
|
||||
asm ("insrwi %0,%1,%2,0" \
|
||||
: "+r" (__result) \
|
||||
: "r" (hi), "i" (MAD_F_SCALEBITS)); \
|
||||
asm ("add %0,%1,%2" \
|
||||
: "=r" (__result) \
|
||||
: "%r" (__result), "r" (__round)); \
|
||||
__result; \
|
||||
})
|
||||
# else
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result; \
|
||||
asm ("rotrwi %0,%1,%2" \
|
||||
: "=r" (__result) \
|
||||
: "r" (lo), "i" (MAD_F_SCALEBITS)); \
|
||||
asm ("insrwi %0,%1,%2,0" \
|
||||
: "+r" (__result) \
|
||||
: "r" (hi), "i" (MAD_F_SCALEBITS)); \
|
||||
__result; \
|
||||
})
|
||||
# endif
|
||||
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
|
||||
/* --- Default ------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_DEFAULT)
|
||||
|
||||
/*
|
||||
* This version is the most portable but it loses significant accuracy.
|
||||
* Furthermore, accuracy is biased against the second argument, so care
|
||||
* should be taken when ordering operands.
|
||||
*
|
||||
* The scale factors are constant as this is not used with SSO.
|
||||
*
|
||||
* Pre-rounding is required to stay within the limits of compliance.
|
||||
*/
|
||||
# if defined(OPT_SPEED)
|
||||
# define mad_f_mul(x, y) (((x) >> 12) * ((y) >> 16))
|
||||
# else
|
||||
# define mad_f_mul(x, y) ((((x) + (1L << 11)) >> 12) * \
|
||||
(((y) + (1L << 15)) >> 16))
|
||||
# endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
# else
|
||||
# error "no FPM selected"
|
||||
# endif
|
||||
|
||||
/* default implementations */
|
||||
|
||||
# if !defined(mad_f_mul)
|
||||
# define mad_f_mul(x, y) \
|
||||
({ register mad_fixed64hi_t __hi; \
|
||||
register mad_fixed64lo_t __lo; \
|
||||
MAD_F_MLX(__hi, __lo, (x), (y)); \
|
||||
mad_f_scale64(__hi, __lo); \
|
||||
})
|
||||
# endif
|
||||
|
||||
# if !defined(MAD_F_MLA)
|
||||
# define MAD_F_ML0(hi, lo, x, y) ((lo) = mad_f_mul((x), (y)))
|
||||
# define MAD_F_MLA(hi, lo, x, y) ((lo) += mad_f_mul((x), (y)))
|
||||
# define MAD_F_MLN(hi, lo) ((lo) = -(lo))
|
||||
# define MAD_F_MLZ(hi, lo) ((void) (hi), (mad_fixed_t) (lo))
|
||||
# endif
|
||||
|
||||
# if !defined(MAD_F_ML0)
|
||||
# define MAD_F_ML0(hi, lo, x, y) MAD_F_MLX((hi), (lo), (x), (y))
|
||||
# endif
|
||||
|
||||
# if !defined(MAD_F_MLN)
|
||||
# define MAD_F_MLN(hi, lo) ((hi) = ((lo) = -(lo)) ? ~(hi) : -(hi))
|
||||
# endif
|
||||
|
||||
# if !defined(MAD_F_MLZ)
|
||||
# define MAD_F_MLZ(hi, lo) mad_f_scale64((hi), (lo))
|
||||
# endif
|
||||
|
||||
# if !defined(mad_f_scale64)
|
||||
# if defined(OPT_ACCURACY)
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
((((mad_fixed_t) \
|
||||
(((hi) << (32 - (MAD_F_SCALEBITS - 1))) | \
|
||||
((lo) >> (MAD_F_SCALEBITS - 1)))) + 1) >> 1)
|
||||
# else
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
((mad_fixed_t) \
|
||||
(((hi) << (32 - MAD_F_SCALEBITS)) | \
|
||||
((lo) >> MAD_F_SCALEBITS)))
|
||||
# endif
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
# endif
|
||||
|
||||
/* C routines */
|
||||
|
||||
mad_fixed_t mad_f_abs(mad_fixed_t);
|
||||
mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t);
|
||||
|
||||
# endif
|
501
libmad/frame.c
Normal file
501
libmad/frame.c
Normal file
@ -0,0 +1,501 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: frame.c,v 1.29 2004/02/04 22:59:19 rob Exp $
|
||||
*/
|
||||
|
||||
# include "libmad_config.h"
|
||||
|
||||
# include "libmad_global.h"
|
||||
|
||||
# include <stdlib.h>
|
||||
|
||||
# include "bit.h"
|
||||
# include "stream.h"
|
||||
# include "frame.h"
|
||||
# include "timer.h"
|
||||
# include "layer12.h"
|
||||
# include "layer3.h"
|
||||
|
||||
static
|
||||
unsigned long const bitrate_table[5][15] = {
|
||||
/* MPEG-1 */
|
||||
{ 0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, /* Layer I */
|
||||
256000, 288000, 320000, 352000, 384000, 416000, 448000 },
|
||||
{ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, /* Layer II */
|
||||
128000, 160000, 192000, 224000, 256000, 320000, 384000 },
|
||||
{ 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, /* Layer III */
|
||||
112000, 128000, 160000, 192000, 224000, 256000, 320000 },
|
||||
|
||||
/* MPEG-2 LSF */
|
||||
{ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, /* Layer I */
|
||||
128000, 144000, 160000, 176000, 192000, 224000, 256000 },
|
||||
{ 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, /* Layers */
|
||||
64000, 80000, 96000, 112000, 128000, 144000, 160000 } /* II & III */
|
||||
};
|
||||
|
||||
static
|
||||
unsigned int const samplerate_table[3] = { 44100, 48000, 32000 };
|
||||
|
||||
static
|
||||
int (*const decoder_table[3])(struct mad_stream *, struct mad_frame *) = {
|
||||
mad_layer_I,
|
||||
mad_layer_II,
|
||||
mad_layer_III
|
||||
};
|
||||
|
||||
/*
|
||||
* NAME: header->init()
|
||||
* DESCRIPTION: initialize header struct
|
||||
*/
|
||||
void mad_header_init(struct mad_header *header)
|
||||
{
|
||||
header->layer = 0;
|
||||
header->mode = 0;
|
||||
header->mode_extension = 0;
|
||||
header->emphasis = 0;
|
||||
|
||||
header->bitrate = 0;
|
||||
header->samplerate = 0;
|
||||
|
||||
header->crc_check = 0;
|
||||
header->crc_target = 0;
|
||||
|
||||
header->flags = 0;
|
||||
header->private_bits = 0;
|
||||
|
||||
header->duration = mad_timer_zero;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: frame->init()
|
||||
* DESCRIPTION: initialize frame struct
|
||||
*/
|
||||
void mad_frame_init(struct mad_frame *frame)
|
||||
{
|
||||
mad_header_init(&frame->header);
|
||||
|
||||
frame->options = 0;
|
||||
|
||||
frame->overlap = 0;
|
||||
mad_frame_mute(frame);
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: frame->finish()
|
||||
* DESCRIPTION: deallocate any dynamic memory associated with frame
|
||||
*/
|
||||
void mad_frame_finish(struct mad_frame *frame)
|
||||
{
|
||||
mad_header_finish(&frame->header);
|
||||
|
||||
if (frame->overlap) {
|
||||
free(frame->overlap);
|
||||
frame->overlap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: decode_header()
|
||||
* DESCRIPTION: read header data and following CRC word
|
||||
*/
|
||||
static
|
||||
int decode_header(struct mad_header *header, struct mad_stream *stream)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
header->flags = 0;
|
||||
header->private_bits = 0;
|
||||
|
||||
/* header() */
|
||||
|
||||
/* syncword */
|
||||
mad_bit_skip(&stream->ptr, 11);
|
||||
|
||||
/* MPEG 2.5 indicator (really part of syncword) */
|
||||
if (mad_bit_read(&stream->ptr, 1) == 0)
|
||||
header->flags |= MAD_FLAG_MPEG_2_5_EXT;
|
||||
|
||||
/* ID */
|
||||
if (mad_bit_read(&stream->ptr, 1) == 0)
|
||||
header->flags |= MAD_FLAG_LSF_EXT;
|
||||
else if (header->flags & MAD_FLAG_MPEG_2_5_EXT) {
|
||||
stream->error = MAD_ERROR_LOSTSYNC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* layer */
|
||||
header->layer = 4 - mad_bit_read(&stream->ptr, 2);
|
||||
|
||||
if (header->layer == 4) {
|
||||
stream->error = MAD_ERROR_BADLAYER;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* protection_bit */
|
||||
if (mad_bit_read(&stream->ptr, 1) == 0) {
|
||||
header->flags |= MAD_FLAG_PROTECTION;
|
||||
header->crc_check = mad_bit_crc(stream->ptr, 16, 0xffff);
|
||||
}
|
||||
|
||||
/* bitrate_index */
|
||||
index = mad_bit_read(&stream->ptr, 4);
|
||||
|
||||
if (index == 15) {
|
||||
stream->error = MAD_ERROR_BADBITRATE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->flags & MAD_FLAG_LSF_EXT)
|
||||
header->bitrate = bitrate_table[3 + (header->layer >> 1)][index];
|
||||
else
|
||||
header->bitrate = bitrate_table[header->layer - 1][index];
|
||||
|
||||
/* sampling_frequency */
|
||||
index = mad_bit_read(&stream->ptr, 2);
|
||||
|
||||
if (index == 3) {
|
||||
stream->error = MAD_ERROR_BADSAMPLERATE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
header->samplerate = samplerate_table[index];
|
||||
|
||||
if (header->flags & MAD_FLAG_LSF_EXT) {
|
||||
header->samplerate /= 2;
|
||||
|
||||
if (header->flags & MAD_FLAG_MPEG_2_5_EXT)
|
||||
header->samplerate /= 2;
|
||||
}
|
||||
|
||||
/* padding_bit */
|
||||
if (mad_bit_read(&stream->ptr, 1))
|
||||
header->flags |= MAD_FLAG_PADDING;
|
||||
|
||||
/* private_bit */
|
||||
if (mad_bit_read(&stream->ptr, 1))
|
||||
header->private_bits |= MAD_PRIVATE_HEADER;
|
||||
|
||||
/* mode */
|
||||
header->mode = 3 - mad_bit_read(&stream->ptr, 2);
|
||||
|
||||
/* mode_extension */
|
||||
header->mode_extension = mad_bit_read(&stream->ptr, 2);
|
||||
|
||||
/* copyright */
|
||||
if (mad_bit_read(&stream->ptr, 1))
|
||||
header->flags |= MAD_FLAG_COPYRIGHT;
|
||||
|
||||
/* original/copy */
|
||||
if (mad_bit_read(&stream->ptr, 1))
|
||||
header->flags |= MAD_FLAG_ORIGINAL;
|
||||
|
||||
/* emphasis */
|
||||
header->emphasis = mad_bit_read(&stream->ptr, 2);
|
||||
|
||||
# if defined(OPT_STRICT)
|
||||
/*
|
||||
* ISO/IEC 11172-3 says this is a reserved emphasis value, but
|
||||
* streams exist which use it anyway. Since the value is not important
|
||||
* to the decoder proper, we allow it unless OPT_STRICT is defined.
|
||||
*/
|
||||
if (header->emphasis == MAD_EMPHASIS_RESERVED) {
|
||||
stream->error = MAD_ERROR_BADEMPHASIS;
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* error_check() */
|
||||
|
||||
/* crc_check */
|
||||
if (header->flags & MAD_FLAG_PROTECTION)
|
||||
header->crc_target = mad_bit_read(&stream->ptr, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: free_bitrate()
|
||||
* DESCRIPTION: attempt to discover the bitstream's free bitrate
|
||||
*/
|
||||
static
|
||||
int free_bitrate(struct mad_stream *stream, struct mad_header const *header)
|
||||
{
|
||||
struct mad_bitptr keep_ptr;
|
||||
unsigned long rate = 0;
|
||||
unsigned int pad_slot, slots_per_frame;
|
||||
unsigned char const *ptr = 0;
|
||||
|
||||
keep_ptr = stream->ptr;
|
||||
|
||||
pad_slot = (header->flags & MAD_FLAG_PADDING) ? 1 : 0;
|
||||
slots_per_frame = (header->layer == MAD_LAYER_III &&
|
||||
(header->flags & MAD_FLAG_LSF_EXT)) ? 72 : 144;
|
||||
|
||||
while (mad_stream_sync(stream) == 0) {
|
||||
struct mad_stream peek_stream;
|
||||
struct mad_header peek_header;
|
||||
|
||||
peek_stream = *stream;
|
||||
peek_header = *header;
|
||||
|
||||
if (decode_header(&peek_header, &peek_stream) == 0 &&
|
||||
peek_header.layer == header->layer &&
|
||||
peek_header.samplerate == header->samplerate) {
|
||||
unsigned int N;
|
||||
|
||||
ptr = mad_bit_nextbyte(&stream->ptr);
|
||||
|
||||
N = ptr - stream->this_frame;
|
||||
|
||||
if (header->layer == MAD_LAYER_I) {
|
||||
rate = (unsigned long) header->samplerate *
|
||||
(N - 4 * pad_slot + 4) / 48 / 1000;
|
||||
}
|
||||
else {
|
||||
rate = (unsigned long) header->samplerate *
|
||||
(N - pad_slot + 1) / slots_per_frame / 1000;
|
||||
}
|
||||
|
||||
if (rate >= 8)
|
||||
break;
|
||||
}
|
||||
|
||||
mad_bit_skip(&stream->ptr, 8);
|
||||
}
|
||||
|
||||
stream->ptr = keep_ptr;
|
||||
|
||||
if (rate < 8 || (header->layer == MAD_LAYER_III && rate > 640)) {
|
||||
stream->error = MAD_ERROR_LOSTSYNC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream->freerate = rate * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: header->decode()
|
||||
* DESCRIPTION: read the next frame header from the stream
|
||||
*/
|
||||
int mad_header_decode(struct mad_header *header, struct mad_stream *stream)
|
||||
{
|
||||
register unsigned char const *ptr, *end;
|
||||
unsigned int pad_slot, N;
|
||||
|
||||
ptr = stream->next_frame;
|
||||
end = stream->bufend;
|
||||
|
||||
if (ptr == 0) {
|
||||
stream->error = MAD_ERROR_BUFPTR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* stream skip */
|
||||
if (stream->skiplen) {
|
||||
if (!stream->sync)
|
||||
ptr = stream->this_frame;
|
||||
|
||||
if (end - ptr < stream->skiplen) {
|
||||
stream->skiplen -= end - ptr;
|
||||
stream->next_frame = end;
|
||||
|
||||
stream->error = MAD_ERROR_BUFLEN;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ptr += stream->skiplen;
|
||||
stream->skiplen = 0;
|
||||
|
||||
stream->sync = 1;
|
||||
}
|
||||
|
||||
sync:
|
||||
/* synchronize */
|
||||
if (stream->sync) {
|
||||
if (end - ptr < MAD_BUFFER_GUARD) {
|
||||
stream->next_frame = ptr;
|
||||
|
||||
stream->error = MAD_ERROR_BUFLEN;
|
||||
goto fail;
|
||||
}
|
||||
else if (!(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0)) {
|
||||
/* mark point where frame sync word was expected */
|
||||
stream->this_frame = ptr;
|
||||
stream->next_frame = ptr + 1;
|
||||
|
||||
stream->error = MAD_ERROR_LOSTSYNC;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mad_bit_init(&stream->ptr, ptr);
|
||||
|
||||
if (mad_stream_sync(stream) == -1) {
|
||||
if (end - stream->next_frame >= MAD_BUFFER_GUARD)
|
||||
stream->next_frame = end - MAD_BUFFER_GUARD;
|
||||
|
||||
stream->error = MAD_ERROR_BUFLEN;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ptr = mad_bit_nextbyte(&stream->ptr);
|
||||
}
|
||||
|
||||
/* begin processing */
|
||||
stream->this_frame = ptr;
|
||||
stream->next_frame = ptr + 1; /* possibly bogus sync word */
|
||||
|
||||
mad_bit_init(&stream->ptr, stream->this_frame);
|
||||
|
||||
if (decode_header(header, stream) == -1)
|
||||
goto fail;
|
||||
|
||||
/* calculate frame duration */
|
||||
mad_timer_set(&header->duration, 0,
|
||||
32 * MAD_NSBSAMPLES(header), header->samplerate);
|
||||
|
||||
/* calculate free bit rate */
|
||||
if (header->bitrate == 0) {
|
||||
if ((stream->freerate == 0 || !stream->sync ||
|
||||
(header->layer == MAD_LAYER_III && stream->freerate > 640000)) &&
|
||||
free_bitrate(stream, header) == -1)
|
||||
goto fail;
|
||||
|
||||
header->bitrate = stream->freerate;
|
||||
header->flags |= MAD_FLAG_FREEFORMAT;
|
||||
}
|
||||
|
||||
/* calculate beginning of next frame */
|
||||
pad_slot = (header->flags & MAD_FLAG_PADDING) ? 1 : 0;
|
||||
|
||||
if (header->layer == MAD_LAYER_I)
|
||||
N = ((12 * header->bitrate / header->samplerate) + pad_slot) * 4;
|
||||
else {
|
||||
unsigned int slots_per_frame;
|
||||
|
||||
slots_per_frame = (header->layer == MAD_LAYER_III &&
|
||||
(header->flags & MAD_FLAG_LSF_EXT)) ? 72 : 144;
|
||||
|
||||
N = (slots_per_frame * header->bitrate / header->samplerate) + pad_slot;
|
||||
}
|
||||
|
||||
/* verify there is enough data left in buffer to decode this frame */
|
||||
if (N + MAD_BUFFER_GUARD > end - stream->this_frame) {
|
||||
stream->next_frame = stream->this_frame;
|
||||
|
||||
stream->error = MAD_ERROR_BUFLEN;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
stream->next_frame = stream->this_frame + N;
|
||||
|
||||
if (!stream->sync) {
|
||||
/* check that a valid frame header follows this frame */
|
||||
|
||||
ptr = stream->next_frame;
|
||||
if (!(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0)) {
|
||||
ptr = stream->next_frame = stream->this_frame + 1;
|
||||
goto sync;
|
||||
}
|
||||
|
||||
stream->sync = 1;
|
||||
}
|
||||
|
||||
header->flags |= MAD_FLAG_INCOMPLETE;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
stream->sync = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: frame->decode()
|
||||
* DESCRIPTION: decode a single frame from a bitstream
|
||||
*/
|
||||
int mad_frame_decode(struct mad_frame *frame, struct mad_stream *stream)
|
||||
{
|
||||
frame->options = stream->options;
|
||||
|
||||
/* header() */
|
||||
/* error_check() */
|
||||
|
||||
if (!(frame->header.flags & MAD_FLAG_INCOMPLETE) &&
|
||||
mad_header_decode(&frame->header, stream) == -1)
|
||||
goto fail;
|
||||
|
||||
/* audio_data() */
|
||||
|
||||
frame->header.flags &= ~MAD_FLAG_INCOMPLETE;
|
||||
|
||||
if (decoder_table[frame->header.layer - 1](stream, frame) == -1) {
|
||||
if (!MAD_RECOVERABLE(stream->error))
|
||||
stream->next_frame = stream->this_frame;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* ancillary_data() */
|
||||
|
||||
if (frame->header.layer != MAD_LAYER_III) {
|
||||
struct mad_bitptr next_frame;
|
||||
|
||||
mad_bit_init(&next_frame, stream->next_frame);
|
||||
|
||||
stream->anc_ptr = stream->ptr;
|
||||
stream->anc_bitlen = mad_bit_length(&stream->ptr, &next_frame);
|
||||
|
||||
mad_bit_finish(&next_frame);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
stream->anc_bitlen = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: frame->mute()
|
||||
* DESCRIPTION: zero all subband values so the frame becomes silent
|
||||
*/
|
||||
void mad_frame_mute(struct mad_frame *frame)
|
||||
{
|
||||
unsigned int s, sb;
|
||||
|
||||
for (s = 0; s < 36; ++s) {
|
||||
for (sb = 0; sb < 32; ++sb) {
|
||||
frame->sbsample[0][s][sb] =
|
||||
frame->sbsample[1][s][sb] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->overlap) {
|
||||
for (s = 0; s < 18; ++s) {
|
||||
for (sb = 0; sb < 32; ++sb) {
|
||||
(*frame->overlap)[0][sb][s] =
|
||||
(*frame->overlap)[1][sb][s] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
118
libmad/frame.h
Normal file
118
libmad/frame.h
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: frame.h,v 1.20 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_FRAME_H
|
||||
# define LIBMAD_FRAME_H
|
||||
|
||||
# include "fixed.h"
|
||||
# include "timer.h"
|
||||
# include "stream.h"
|
||||
|
||||
enum mad_layer {
|
||||
MAD_LAYER_I = 1, /* Layer I */
|
||||
MAD_LAYER_II = 2, /* Layer II */
|
||||
MAD_LAYER_III = 3 /* Layer III */
|
||||
};
|
||||
|
||||
enum mad_mode {
|
||||
MAD_MODE_SINGLE_CHANNEL = 0, /* single channel */
|
||||
MAD_MODE_DUAL_CHANNEL = 1, /* dual channel */
|
||||
MAD_MODE_JOINT_STEREO = 2, /* joint (MS/intensity) stereo */
|
||||
MAD_MODE_STEREO = 3 /* normal LR stereo */
|
||||
};
|
||||
|
||||
enum mad_emphasis {
|
||||
MAD_EMPHASIS_NONE = 0, /* no emphasis */
|
||||
MAD_EMPHASIS_50_15_US = 1, /* 50/15 microseconds emphasis */
|
||||
MAD_EMPHASIS_CCITT_J_17 = 3, /* CCITT J.17 emphasis */
|
||||
MAD_EMPHASIS_RESERVED = 2 /* unknown emphasis */
|
||||
};
|
||||
|
||||
struct mad_header {
|
||||
enum mad_layer layer; /* audio layer (1, 2, or 3) */
|
||||
enum mad_mode mode; /* channel mode (see above) */
|
||||
int mode_extension; /* additional mode info */
|
||||
enum mad_emphasis emphasis; /* de-emphasis to use (see above) */
|
||||
|
||||
unsigned long bitrate; /* stream bitrate (bps) */
|
||||
unsigned int samplerate; /* sampling frequency (Hz) */
|
||||
|
||||
unsigned short crc_check; /* frame CRC accumulator */
|
||||
unsigned short crc_target; /* final target CRC checksum */
|
||||
|
||||
int flags; /* flags (see below) */
|
||||
int private_bits; /* private bits (see below) */
|
||||
|
||||
mad_timer_t duration; /* audio playing time of frame */
|
||||
};
|
||||
|
||||
struct mad_frame {
|
||||
struct mad_header header; /* MPEG audio header */
|
||||
|
||||
int options; /* decoding options (from stream) */
|
||||
|
||||
mad_fixed_t sbsample[2][36][32]; /* synthesis subband filter samples */
|
||||
mad_fixed_t (*overlap)[2][32][18]; /* Layer III block overlap data */
|
||||
};
|
||||
|
||||
# define MAD_NCHANNELS(header) ((header)->mode ? 2 : 1)
|
||||
# define MAD_NSBSAMPLES(header) \
|
||||
((header)->layer == MAD_LAYER_I ? 12 : \
|
||||
(((header)->layer == MAD_LAYER_III && \
|
||||
((header)->flags & MAD_FLAG_LSF_EXT)) ? 18 : 36))
|
||||
|
||||
enum {
|
||||
MAD_FLAG_NPRIVATE_III = 0x0007, /* number of Layer III private bits */
|
||||
MAD_FLAG_INCOMPLETE = 0x0008, /* header but not data is decoded */
|
||||
|
||||
MAD_FLAG_PROTECTION = 0x0010, /* frame has CRC protection */
|
||||
MAD_FLAG_COPYRIGHT = 0x0020, /* frame is copyright */
|
||||
MAD_FLAG_ORIGINAL = 0x0040, /* frame is original (else copy) */
|
||||
MAD_FLAG_PADDING = 0x0080, /* frame has additional slot */
|
||||
|
||||
MAD_FLAG_I_STEREO = 0x0100, /* uses intensity joint stereo */
|
||||
MAD_FLAG_MS_STEREO = 0x0200, /* uses middle/side joint stereo */
|
||||
MAD_FLAG_FREEFORMAT = 0x0400, /* uses free format bitrate */
|
||||
|
||||
MAD_FLAG_LSF_EXT = 0x1000, /* lower sampling freq. extension */
|
||||
MAD_FLAG_MC_EXT = 0x2000, /* multichannel audio extension */
|
||||
MAD_FLAG_MPEG_2_5_EXT = 0x4000 /* MPEG 2.5 (unofficial) extension */
|
||||
};
|
||||
|
||||
enum {
|
||||
MAD_PRIVATE_HEADER = 0x0100, /* header private bit */
|
||||
MAD_PRIVATE_III = 0x001f /* Layer III private bits (up to 5) */
|
||||
};
|
||||
|
||||
void mad_header_init(struct mad_header *);
|
||||
|
||||
# define mad_header_finish(header) /* nothing */
|
||||
|
||||
int mad_header_decode(struct mad_header *, struct mad_stream *);
|
||||
|
||||
void mad_frame_init(struct mad_frame *);
|
||||
void mad_frame_finish(struct mad_frame *);
|
||||
|
||||
int mad_frame_decode(struct mad_frame *, struct mad_stream *);
|
||||
|
||||
void mad_frame_mute(struct mad_frame *);
|
||||
|
||||
# endif
|
3107
libmad/huffman.c
Normal file
3107
libmad/huffman.c
Normal file
File diff suppressed because it is too large
Load Diff
66
libmad/huffman.h
Normal file
66
libmad/huffman.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: huffman.h,v 1.11 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_HUFFMAN_H
|
||||
# define LIBMAD_HUFFMAN_H
|
||||
|
||||
union huffquad {
|
||||
struct {
|
||||
unsigned short final : 1;
|
||||
unsigned short bits : 3;
|
||||
unsigned short offset : 12;
|
||||
} ptr;
|
||||
struct {
|
||||
unsigned short final : 1;
|
||||
unsigned short hlen : 3;
|
||||
unsigned short v : 1;
|
||||
unsigned short w : 1;
|
||||
unsigned short x : 1;
|
||||
unsigned short y : 1;
|
||||
} value;
|
||||
unsigned short final : 1;
|
||||
};
|
||||
|
||||
union huffpair {
|
||||
struct {
|
||||
unsigned short final : 1;
|
||||
unsigned short bits : 3;
|
||||
unsigned short offset : 12;
|
||||
} ptr;
|
||||
struct {
|
||||
unsigned short final : 1;
|
||||
unsigned short hlen : 3;
|
||||
unsigned short x : 4;
|
||||
unsigned short y : 4;
|
||||
} value;
|
||||
unsigned short final : 1;
|
||||
};
|
||||
|
||||
struct hufftable {
|
||||
union huffpair const *table;
|
||||
unsigned short linbits;
|
||||
unsigned short startbits;
|
||||
};
|
||||
|
||||
extern union huffquad const *const mad_huff_quad_table[2];
|
||||
extern struct hufftable const mad_huff_pair_table[32];
|
||||
|
||||
# endif
|
62
libmad/imdct_s.dat
Normal file
62
libmad/imdct_s.dat
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: imdct_s.dat,v 1.8 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
/* 0 */ { MAD_F(0x09bd7ca0) /* 0.608761429 */,
|
||||
-MAD_F(0x0ec835e8) /* -0.923879533 */,
|
||||
-MAD_F(0x0216a2a2) /* -0.130526192 */,
|
||||
MAD_F(0x0fdcf549) /* 0.991444861 */,
|
||||
-MAD_F(0x061f78aa) /* -0.382683432 */,
|
||||
-MAD_F(0x0cb19346) /* -0.793353340 */ },
|
||||
|
||||
/* 6 */ { -MAD_F(0x0cb19346) /* -0.793353340 */,
|
||||
MAD_F(0x061f78aa) /* 0.382683432 */,
|
||||
MAD_F(0x0fdcf549) /* 0.991444861 */,
|
||||
MAD_F(0x0216a2a2) /* 0.130526192 */,
|
||||
-MAD_F(0x0ec835e8) /* -0.923879533 */,
|
||||
-MAD_F(0x09bd7ca0) /* -0.608761429 */ },
|
||||
|
||||
/* 1 */ { MAD_F(0x061f78aa) /* 0.382683432 */,
|
||||
-MAD_F(0x0ec835e8) /* -0.923879533 */,
|
||||
MAD_F(0x0ec835e8) /* 0.923879533 */,
|
||||
-MAD_F(0x061f78aa) /* -0.382683432 */,
|
||||
-MAD_F(0x061f78aa) /* -0.382683432 */,
|
||||
MAD_F(0x0ec835e8) /* 0.923879533 */ },
|
||||
|
||||
/* 7 */ { -MAD_F(0x0ec835e8) /* -0.923879533 */,
|
||||
-MAD_F(0x061f78aa) /* -0.382683432 */,
|
||||
MAD_F(0x061f78aa) /* 0.382683432 */,
|
||||
MAD_F(0x0ec835e8) /* 0.923879533 */,
|
||||
MAD_F(0x0ec835e8) /* 0.923879533 */,
|
||||
MAD_F(0x061f78aa) /* 0.382683432 */ },
|
||||
|
||||
/* 2 */ { MAD_F(0x0216a2a2) /* 0.130526192 */,
|
||||
-MAD_F(0x061f78aa) /* -0.382683432 */,
|
||||
MAD_F(0x09bd7ca0) /* 0.608761429 */,
|
||||
-MAD_F(0x0cb19346) /* -0.793353340 */,
|
||||
MAD_F(0x0ec835e8) /* 0.923879533 */,
|
||||
-MAD_F(0x0fdcf549) /* -0.991444861 */ },
|
||||
|
||||
/* 8 */ { -MAD_F(0x0fdcf549) /* -0.991444861 */,
|
||||
-MAD_F(0x0ec835e8) /* -0.923879533 */,
|
||||
-MAD_F(0x0cb19346) /* -0.793353340 */,
|
||||
-MAD_F(0x09bd7ca0) /* -0.608761429 */,
|
||||
-MAD_F(0x061f78aa) /* -0.382683432 */,
|
||||
-MAD_F(0x0216a2a2) /* -0.130526192 */ }
|
532
libmad/layer12.c
Normal file
532
libmad/layer12.c
Normal file
@ -0,0 +1,532 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: layer12.c,v 1.17 2004/02/05 09:02:39 rob Exp $
|
||||
*/
|
||||
|
||||
# include "libmad_config.h"
|
||||
|
||||
# include "libmad_global.h"
|
||||
|
||||
# ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
# else
|
||||
# define CHAR_BIT 8
|
||||
# endif
|
||||
|
||||
# include "fixed.h"
|
||||
# include "bit.h"
|
||||
# include "stream.h"
|
||||
# include "frame.h"
|
||||
# include "layer12.h"
|
||||
|
||||
/*
|
||||
* scalefactor table
|
||||
* used in both Layer I and Layer II decoding
|
||||
*/
|
||||
static
|
||||
mad_fixed_t const sf_table[64] = {
|
||||
# include "sf_table.dat"
|
||||
};
|
||||
|
||||
/* --- Layer I ------------------------------------------------------------- */
|
||||
|
||||
/* linear scaling table */
|
||||
static
|
||||
mad_fixed_t const linear_table[14] = {
|
||||
MAD_F(0x15555555), /* 2^2 / (2^2 - 1) == 1.33333333333333 */
|
||||
MAD_F(0x12492492), /* 2^3 / (2^3 - 1) == 1.14285714285714 */
|
||||
MAD_F(0x11111111), /* 2^4 / (2^4 - 1) == 1.06666666666667 */
|
||||
MAD_F(0x10842108), /* 2^5 / (2^5 - 1) == 1.03225806451613 */
|
||||
MAD_F(0x10410410), /* 2^6 / (2^6 - 1) == 1.01587301587302 */
|
||||
MAD_F(0x10204081), /* 2^7 / (2^7 - 1) == 1.00787401574803 */
|
||||
MAD_F(0x10101010), /* 2^8 / (2^8 - 1) == 1.00392156862745 */
|
||||
MAD_F(0x10080402), /* 2^9 / (2^9 - 1) == 1.00195694716243 */
|
||||
MAD_F(0x10040100), /* 2^10 / (2^10 - 1) == 1.00097751710655 */
|
||||
MAD_F(0x10020040), /* 2^11 / (2^11 - 1) == 1.00048851978505 */
|
||||
MAD_F(0x10010010), /* 2^12 / (2^12 - 1) == 1.00024420024420 */
|
||||
MAD_F(0x10008004), /* 2^13 / (2^13 - 1) == 1.00012208521548 */
|
||||
MAD_F(0x10004001), /* 2^14 / (2^14 - 1) == 1.00006103888177 */
|
||||
MAD_F(0x10002000) /* 2^15 / (2^15 - 1) == 1.00003051850948 */
|
||||
};
|
||||
|
||||
/*
|
||||
* NAME: I_sample()
|
||||
* DESCRIPTION: decode one requantized Layer I sample from a bitstream
|
||||
*/
|
||||
static
|
||||
mad_fixed_t I_sample(struct mad_bitptr *ptr, unsigned int nb)
|
||||
{
|
||||
mad_fixed_t sample;
|
||||
|
||||
sample = mad_bit_read(ptr, nb);
|
||||
|
||||
/* invert most significant bit, extend sign, then scale to fixed format */
|
||||
|
||||
sample ^= 1 << (nb - 1);
|
||||
sample |= -(sample & (1 << (nb - 1)));
|
||||
|
||||
sample <<= MAD_F_FRACBITS - (nb - 1);
|
||||
|
||||
/* requantize the sample */
|
||||
|
||||
/* s'' = (2^nb / (2^nb - 1)) * (s''' + 2^(-nb + 1)) */
|
||||
|
||||
sample += MAD_F_ONE >> (nb - 1);
|
||||
|
||||
return mad_f_mul(sample, linear_table[nb - 2]);
|
||||
|
||||
/* s' = factor * s'' */
|
||||
/* (to be performed by caller) */
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: layer->I()
|
||||
* DESCRIPTION: decode a single Layer I frame
|
||||
*/
|
||||
int mad_layer_I(struct mad_stream *stream, struct mad_frame *frame)
|
||||
{
|
||||
struct mad_header *header = &frame->header;
|
||||
unsigned int nch, bound, ch, s, sb, nb;
|
||||
unsigned char allocation[2][32], scalefactor[2][32];
|
||||
|
||||
nch = MAD_NCHANNELS(header);
|
||||
|
||||
bound = 32;
|
||||
if (header->mode == MAD_MODE_JOINT_STEREO) {
|
||||
header->flags |= MAD_FLAG_I_STEREO;
|
||||
bound = 4 + header->mode_extension * 4;
|
||||
}
|
||||
|
||||
/* check CRC word */
|
||||
|
||||
if (header->flags & MAD_FLAG_PROTECTION) {
|
||||
header->crc_check =
|
||||
mad_bit_crc(stream->ptr, 4 * (bound * nch + (32 - bound)),
|
||||
header->crc_check);
|
||||
|
||||
if (header->crc_check != header->crc_target &&
|
||||
!(frame->options & MAD_OPTION_IGNORECRC)) {
|
||||
stream->error = MAD_ERROR_BADCRC;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* decode bit allocations */
|
||||
|
||||
for (sb = 0; sb < bound; ++sb) {
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
nb = mad_bit_read(&stream->ptr, 4);
|
||||
|
||||
if (nb == 15) {
|
||||
stream->error = MAD_ERROR_BADBITALLOC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
allocation[ch][sb] = nb ? nb + 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (sb = bound; sb < 32; ++sb) {
|
||||
nb = mad_bit_read(&stream->ptr, 4);
|
||||
|
||||
if (nb == 15) {
|
||||
stream->error = MAD_ERROR_BADBITALLOC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
allocation[0][sb] =
|
||||
allocation[1][sb] = nb ? nb + 1 : 0;
|
||||
}
|
||||
|
||||
/* decode scalefactors */
|
||||
|
||||
for (sb = 0; sb < 32; ++sb) {
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
if (allocation[ch][sb]) {
|
||||
scalefactor[ch][sb] = mad_bit_read(&stream->ptr, 6);
|
||||
|
||||
# if defined(OPT_STRICT)
|
||||
/*
|
||||
* Scalefactor index 63 does not appear in Table B.1 of
|
||||
* ISO/IEC 11172-3. Nonetheless, other implementations accept it,
|
||||
* so we only reject it if OPT_STRICT is defined.
|
||||
*/
|
||||
if (scalefactor[ch][sb] == 63) {
|
||||
stream->error = MAD_ERROR_BADSCALEFACTOR;
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* decode samples */
|
||||
|
||||
for (s = 0; s < 12; ++s) {
|
||||
for (sb = 0; sb < bound; ++sb) {
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
nb = allocation[ch][sb];
|
||||
frame->sbsample[ch][s][sb] = nb ?
|
||||
mad_f_mul(I_sample(&stream->ptr, nb),
|
||||
sf_table[scalefactor[ch][sb]]) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (sb = bound; sb < 32; ++sb) {
|
||||
if ((nb = allocation[0][sb])) {
|
||||
mad_fixed_t sample;
|
||||
|
||||
sample = I_sample(&stream->ptr, nb);
|
||||
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
frame->sbsample[ch][s][sb] =
|
||||
mad_f_mul(sample, sf_table[scalefactor[ch][sb]]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (ch = 0; ch < nch; ++ch)
|
||||
frame->sbsample[ch][s][sb] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --- Layer II ------------------------------------------------------------ */
|
||||
|
||||
/* possible quantization per subband table */
|
||||
static
|
||||
struct {
|
||||
unsigned int sblimit;
|
||||
unsigned char const offsets[30];
|
||||
} const sbquant_table[5] = {
|
||||
/* ISO/IEC 11172-3 Table B.2a */
|
||||
{ 27, { 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, /* 0 */
|
||||
3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 } },
|
||||
/* ISO/IEC 11172-3 Table B.2b */
|
||||
{ 30, { 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, /* 1 */
|
||||
3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 } },
|
||||
/* ISO/IEC 11172-3 Table B.2c */
|
||||
{ 8, { 5, 5, 2, 2, 2, 2, 2, 2 } }, /* 2 */
|
||||
/* ISO/IEC 11172-3 Table B.2d */
|
||||
{ 12, { 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 } }, /* 3 */
|
||||
/* ISO/IEC 13818-3 Table B.1 */
|
||||
{ 30, { 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, /* 4 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }
|
||||
};
|
||||
|
||||
/* bit allocation table */
|
||||
static
|
||||
struct {
|
||||
unsigned short nbal;
|
||||
unsigned short offset;
|
||||
} const bitalloc_table[8] = {
|
||||
{ 2, 0 }, /* 0 */
|
||||
{ 2, 3 }, /* 1 */
|
||||
{ 3, 3 }, /* 2 */
|
||||
{ 3, 1 }, /* 3 */
|
||||
{ 4, 2 }, /* 4 */
|
||||
{ 4, 3 }, /* 5 */
|
||||
{ 4, 4 }, /* 6 */
|
||||
{ 4, 5 } /* 7 */
|
||||
};
|
||||
|
||||
/* offsets into quantization class table */
|
||||
static
|
||||
unsigned char const offset_table[6][15] = {
|
||||
{ 0, 1, 16 }, /* 0 */
|
||||
{ 0, 1, 2, 3, 4, 5, 16 }, /* 1 */
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, /* 2 */
|
||||
{ 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, /* 3 */
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 }, /* 4 */
|
||||
{ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } /* 5 */
|
||||
};
|
||||
|
||||
/* quantization class table */
|
||||
static
|
||||
struct quantclass {
|
||||
unsigned short nlevels;
|
||||
unsigned char group;
|
||||
unsigned char bits;
|
||||
mad_fixed_t C;
|
||||
mad_fixed_t D;
|
||||
} const qc_table[17] = {
|
||||
# include "qc_table.dat"
|
||||
};
|
||||
|
||||
/*
|
||||
* NAME: II_samples()
|
||||
* DESCRIPTION: decode three requantized Layer II samples from a bitstream
|
||||
*/
|
||||
static
|
||||
void II_samples(struct mad_bitptr *ptr,
|
||||
struct quantclass const *quantclass,
|
||||
mad_fixed_t output[3])
|
||||
{
|
||||
unsigned int nb, s, sample[3];
|
||||
|
||||
if ((nb = quantclass->group)) {
|
||||
unsigned int c, nlevels;
|
||||
|
||||
/* degrouping */
|
||||
c = mad_bit_read(ptr, quantclass->bits);
|
||||
nlevels = quantclass->nlevels;
|
||||
|
||||
for (s = 0; s < 3; ++s) {
|
||||
sample[s] = c % nlevels;
|
||||
c /= nlevels;
|
||||
}
|
||||
}
|
||||
else {
|
||||
nb = quantclass->bits;
|
||||
|
||||
for (s = 0; s < 3; ++s)
|
||||
sample[s] = mad_bit_read(ptr, nb);
|
||||
}
|
||||
|
||||
for (s = 0; s < 3; ++s) {
|
||||
mad_fixed_t requantized;
|
||||
|
||||
/* invert most significant bit, extend sign, then scale to fixed format */
|
||||
|
||||
requantized = sample[s] ^ (1 << (nb - 1));
|
||||
requantized |= -(requantized & (1 << (nb - 1)));
|
||||
|
||||
requantized <<= MAD_F_FRACBITS - (nb - 1);
|
||||
|
||||
/* requantize the sample */
|
||||
|
||||
/* s'' = C * (s''' + D) */
|
||||
|
||||
output[s] = mad_f_mul(requantized + quantclass->D, quantclass->C);
|
||||
|
||||
/* s' = factor * s'' */
|
||||
/* (to be performed by caller) */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: layer->II()
|
||||
* DESCRIPTION: decode a single Layer II frame
|
||||
*/
|
||||
int mad_layer_II(struct mad_stream *stream, struct mad_frame *frame)
|
||||
{
|
||||
struct mad_header *header = &frame->header;
|
||||
struct mad_bitptr start;
|
||||
unsigned int index, sblimit, nbal, nch, bound, gr, ch, s, sb;
|
||||
unsigned char const *offsets;
|
||||
unsigned char allocation[2][32], scfsi[2][32], scalefactor[2][32][3];
|
||||
mad_fixed_t samples[3];
|
||||
|
||||
nch = MAD_NCHANNELS(header);
|
||||
|
||||
if (header->flags & MAD_FLAG_LSF_EXT)
|
||||
index = 4;
|
||||
else if (header->flags & MAD_FLAG_FREEFORMAT)
|
||||
goto freeformat;
|
||||
else {
|
||||
unsigned long bitrate_per_channel;
|
||||
|
||||
bitrate_per_channel = header->bitrate;
|
||||
if (nch == 2) {
|
||||
bitrate_per_channel /= 2;
|
||||
|
||||
# if defined(OPT_STRICT)
|
||||
/*
|
||||
* ISO/IEC 11172-3 allows only single channel mode for 32, 48, 56, and
|
||||
* 80 kbps bitrates in Layer II, but some encoders ignore this
|
||||
* restriction. We enforce it if OPT_STRICT is defined.
|
||||
*/
|
||||
if (bitrate_per_channel <= 28000 || bitrate_per_channel == 40000) {
|
||||
stream->error = MAD_ERROR_BADMODE;
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
else { /* nch == 1 */
|
||||
if (bitrate_per_channel > 192000) {
|
||||
/*
|
||||
* ISO/IEC 11172-3 does not allow single channel mode for 224, 256,
|
||||
* 320, or 384 kbps bitrates in Layer II.
|
||||
*/
|
||||
stream->error = MAD_ERROR_BADMODE;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bitrate_per_channel <= 48000)
|
||||
index = (header->samplerate == 32000) ? 3 : 2;
|
||||
else if (bitrate_per_channel <= 80000)
|
||||
index = 0;
|
||||
else {
|
||||
freeformat:
|
||||
index = (header->samplerate == 48000) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
sblimit = sbquant_table[index].sblimit;
|
||||
offsets = sbquant_table[index].offsets;
|
||||
|
||||
bound = 32;
|
||||
if (header->mode == MAD_MODE_JOINT_STEREO) {
|
||||
header->flags |= MAD_FLAG_I_STEREO;
|
||||
bound = 4 + header->mode_extension * 4;
|
||||
}
|
||||
|
||||
if (bound > sblimit)
|
||||
bound = sblimit;
|
||||
|
||||
start = stream->ptr;
|
||||
|
||||
/* decode bit allocations */
|
||||
|
||||
for (sb = 0; sb < bound; ++sb) {
|
||||
nbal = bitalloc_table[offsets[sb]].nbal;
|
||||
|
||||
for (ch = 0; ch < nch; ++ch)
|
||||
allocation[ch][sb] = mad_bit_read(&stream->ptr, nbal);
|
||||
}
|
||||
|
||||
for (sb = bound; sb < sblimit; ++sb) {
|
||||
nbal = bitalloc_table[offsets[sb]].nbal;
|
||||
|
||||
allocation[0][sb] =
|
||||
allocation[1][sb] = mad_bit_read(&stream->ptr, nbal);
|
||||
}
|
||||
|
||||
/* decode scalefactor selection info */
|
||||
|
||||
for (sb = 0; sb < sblimit; ++sb) {
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
if (allocation[ch][sb])
|
||||
scfsi[ch][sb] = mad_bit_read(&stream->ptr, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* check CRC word */
|
||||
|
||||
if (header->flags & MAD_FLAG_PROTECTION) {
|
||||
header->crc_check =
|
||||
mad_bit_crc(start, mad_bit_length(&start, &stream->ptr),
|
||||
header->crc_check);
|
||||
|
||||
if (header->crc_check != header->crc_target &&
|
||||
!(frame->options & MAD_OPTION_IGNORECRC)) {
|
||||
stream->error = MAD_ERROR_BADCRC;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* decode scalefactors */
|
||||
|
||||
for (sb = 0; sb < sblimit; ++sb) {
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
if (allocation[ch][sb]) {
|
||||
scalefactor[ch][sb][0] = mad_bit_read(&stream->ptr, 6);
|
||||
|
||||
switch (scfsi[ch][sb]) {
|
||||
case 2:
|
||||
scalefactor[ch][sb][2] =
|
||||
scalefactor[ch][sb][1] =
|
||||
scalefactor[ch][sb][0];
|
||||
break;
|
||||
|
||||
case 0:
|
||||
scalefactor[ch][sb][1] = mad_bit_read(&stream->ptr, 6);
|
||||
/* fall through */
|
||||
|
||||
case 1:
|
||||
case 3:
|
||||
scalefactor[ch][sb][2] = mad_bit_read(&stream->ptr, 6);
|
||||
}
|
||||
|
||||
if (scfsi[ch][sb] & 1)
|
||||
scalefactor[ch][sb][1] = scalefactor[ch][sb][scfsi[ch][sb] - 1];
|
||||
|
||||
# if defined(OPT_STRICT)
|
||||
/*
|
||||
* Scalefactor index 63 does not appear in Table B.1 of
|
||||
* ISO/IEC 11172-3. Nonetheless, other implementations accept it,
|
||||
* so we only reject it if OPT_STRICT is defined.
|
||||
*/
|
||||
if (scalefactor[ch][sb][0] == 63 ||
|
||||
scalefactor[ch][sb][1] == 63 ||
|
||||
scalefactor[ch][sb][2] == 63) {
|
||||
stream->error = MAD_ERROR_BADSCALEFACTOR;
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* decode samples */
|
||||
|
||||
for (gr = 0; gr < 12; ++gr) {
|
||||
for (sb = 0; sb < bound; ++sb) {
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
if ((index = allocation[ch][sb])) {
|
||||
index = offset_table[bitalloc_table[offsets[sb]].offset][index - 1];
|
||||
|
||||
II_samples(&stream->ptr, &qc_table[index], samples);
|
||||
|
||||
for (s = 0; s < 3; ++s) {
|
||||
frame->sbsample[ch][3 * gr + s][sb] =
|
||||
mad_f_mul(samples[s], sf_table[scalefactor[ch][sb][gr / 4]]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (s = 0; s < 3; ++s)
|
||||
frame->sbsample[ch][3 * gr + s][sb] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (sb = bound; sb < sblimit; ++sb) {
|
||||
if ((index = allocation[0][sb])) {
|
||||
index = offset_table[bitalloc_table[offsets[sb]].offset][index - 1];
|
||||
|
||||
II_samples(&stream->ptr, &qc_table[index], samples);
|
||||
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
for (s = 0; s < 3; ++s) {
|
||||
frame->sbsample[ch][3 * gr + s][sb] =
|
||||
mad_f_mul(samples[s], sf_table[scalefactor[ch][sb][gr / 4]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
for (s = 0; s < 3; ++s)
|
||||
frame->sbsample[ch][3 * gr + s][sb] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
for (s = 0; s < 3; ++s) {
|
||||
for (sb = sblimit; sb < 32; ++sb)
|
||||
frame->sbsample[ch][3 * gr + s][sb] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
31
libmad/layer12.h
Normal file
31
libmad/layer12.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: layer12.h,v 1.10 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_LAYER12_H
|
||||
# define LIBMAD_LAYER12_H
|
||||
|
||||
# include "stream.h"
|
||||
# include "frame.h"
|
||||
|
||||
int mad_layer_I(struct mad_stream *, struct mad_frame *);
|
||||
int mad_layer_II(struct mad_stream *, struct mad_frame *);
|
||||
|
||||
# endif
|
2696
libmad/layer3.c
Normal file
2696
libmad/layer3.c
Normal file
File diff suppressed because it is too large
Load Diff
30
libmad/layer3.h
Normal file
30
libmad/layer3.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: layer3.h,v 1.10 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_LAYER3_H
|
||||
# define LIBMAD_LAYER3_H
|
||||
|
||||
# include "stream.h"
|
||||
# include "frame.h"
|
||||
|
||||
int mad_layer_III(struct mad_stream *, struct mad_frame *);
|
||||
|
||||
# endif
|
139
libmad/libmad_config.h
Normal file
139
libmad/libmad_config.h
Normal file
@ -0,0 +1,139 @@
|
||||
/* config.h. Generated by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to enable diagnostic debugging support. */
|
||||
/* #undef DEBUG */
|
||||
|
||||
/* Define to enable experimental code. */
|
||||
/* #undef EXPERIMENTAL */
|
||||
|
||||
/* Define to 1 if you have the <assert.h> header file. */
|
||||
#define HAVE_ASSERT_H 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
/* #undef HAVE_DLFCN_H */
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#define HAVE_ERRNO_H 1
|
||||
|
||||
/* Define to 1 if you have the `fcntl' function. */
|
||||
/* #undef HAVE_FCNTL */
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
/* #undef HAVE_FORK */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define if your MIPS CPU supports a 2-operand MADD16 instruction. */
|
||||
/* #undef HAVE_MADD16_ASM */
|
||||
|
||||
/* Define if your MIPS CPU supports a 2-operand MADD instruction. */
|
||||
/* #undef HAVE_MADD_ASM */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `pipe' function. */
|
||||
/* #undef HAVE_PIPE */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||
/* #undef HAVE_SYS_WAIT_H */
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
/* #undef HAVE_UNISTD_H */
|
||||
|
||||
/* Define to 1 if you have the `waitpid' function. */
|
||||
/* #undef HAVE_WAITPID */
|
||||
|
||||
/* Define to disable debugging assertions. */
|
||||
/* #undef NDEBUG */
|
||||
|
||||
/* Define to optimize for accuracy over speed. */
|
||||
/* #undef OPT_ACCURACY */
|
||||
|
||||
/* Define to optimize for speed over accuracy. */
|
||||
/* #undef OPT_SPEED */
|
||||
|
||||
/* Define to enable a fast subband synthesis approximation optimization. */
|
||||
/* #undef OPT_SSO */
|
||||
|
||||
/* Define to influence a strict interpretation of the ISO/IEC standards, even
|
||||
if this is in opposition with best accepted practices. */
|
||||
/* #undef OPT_STRICT */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "libmad"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "support@underbit.com"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "MPEG Audio Decoder"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "MPEG Audio Decoder 0.15.1b"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "libmad"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "0.15.1b"
|
||||
|
||||
/* The size of a `int', as computed by sizeof. */
|
||||
#define SIZEOF_INT 4
|
||||
|
||||
/* The size of a `long', as computed by sizeof. */
|
||||
#define SIZEOF_LONG 4
|
||||
|
||||
/* The size of a `long long', as computed by sizeof. */
|
||||
#define SIZEOF_LONG_LONG 8
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.15.1b"
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define as `__inline' if that's what the C compiler calls it, or to nothing
|
||||
if it is not supported. */
|
||||
#define inline __inline
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
/* #undef pid_t */
|
||||
|
||||
#define FPM_DEFAULT 1
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable:4018)
|
||||
#pragma warning (disable:4146)
|
||||
#pragma warning (disable:4244)
|
||||
#pragma warning (disable:4996)
|
||||
#endif
|
58
libmad/libmad_global.h
Normal file
58
libmad/libmad_global.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: global.h,v 1.11 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_GLOBAL_H
|
||||
# define LIBMAD_GLOBAL_H
|
||||
|
||||
/* conditional debugging */
|
||||
|
||||
# if defined(DEBUG) && defined(NDEBUG)
|
||||
# error "cannot define both DEBUG and NDEBUG"
|
||||
# endif
|
||||
|
||||
# if defined(DEBUG)
|
||||
# include <stdio.h>
|
||||
# endif
|
||||
|
||||
/* conditional features */
|
||||
|
||||
# if defined(OPT_SPEED) && defined(OPT_ACCURACY)
|
||||
# error "cannot optimize for both speed and accuracy"
|
||||
# endif
|
||||
|
||||
# if defined(OPT_SPEED) && !defined(OPT_SSO)
|
||||
# define OPT_SSO
|
||||
# endif
|
||||
|
||||
# if defined(HAVE_UNISTD_H) && defined(HAVE_WAITPID) && \
|
||||
defined(HAVE_FCNTL) && defined(HAVE_PIPE) && defined(HAVE_FORK)
|
||||
# define USE_ASYNC
|
||||
# endif
|
||||
|
||||
# if !defined(HAVE_ASSERT_H)
|
||||
# if defined(NDEBUG)
|
||||
# define assert(x) /* nothing */
|
||||
# else
|
||||
# define assert(x) do { if (!(x)) abort(); } while (0)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# endif
|
964
libmad/mad.h
Normal file
964
libmad/mad.h
Normal file
@ -0,0 +1,964 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* If you would like to negotiate alternate licensing terms, you may do
|
||||
* so by contacting: Underbit Technologies, Inc. <info@underbit.com>
|
||||
*/
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
# define FPM_INTEL
|
||||
|
||||
|
||||
|
||||
# define SIZEOF_INT 4
|
||||
# define SIZEOF_LONG 4
|
||||
# define SIZEOF_LONG_LONG 8
|
||||
|
||||
|
||||
/* Id: version.h,v 1.26 2004/01/23 09:41:33 rob Exp */
|
||||
|
||||
# ifndef LIBMAD_VERSION_H
|
||||
# define LIBMAD_VERSION_H
|
||||
|
||||
# define MAD_VERSION_MAJOR 0
|
||||
# define MAD_VERSION_MINOR 15
|
||||
# define MAD_VERSION_PATCH 1
|
||||
# define MAD_VERSION_EXTRA " (beta)"
|
||||
|
||||
# define MAD_VERSION_STRINGIZE(str) #str
|
||||
# define MAD_VERSION_STRING(num) MAD_VERSION_STRINGIZE(num)
|
||||
|
||||
# define MAD_VERSION MAD_VERSION_STRING(MAD_VERSION_MAJOR) "." \
|
||||
MAD_VERSION_STRING(MAD_VERSION_MINOR) "." \
|
||||
MAD_VERSION_STRING(MAD_VERSION_PATCH) \
|
||||
MAD_VERSION_EXTRA
|
||||
|
||||
# define MAD_PUBLISHYEAR "2000-2004"
|
||||
# define MAD_AUTHOR "Underbit Technologies, Inc."
|
||||
# define MAD_EMAIL "info@underbit.com"
|
||||
|
||||
extern char const mad_version[];
|
||||
extern char const mad_copyright[];
|
||||
extern char const mad_author[];
|
||||
extern char const mad_build[];
|
||||
|
||||
# endif
|
||||
|
||||
/* Id: fixed.h,v 1.38 2004/02/17 02:02:03 rob Exp */
|
||||
|
||||
# ifndef LIBMAD_FIXED_H
|
||||
# define LIBMAD_FIXED_H
|
||||
|
||||
# if SIZEOF_INT >= 4
|
||||
typedef signed int mad_fixed_t;
|
||||
|
||||
typedef signed int mad_fixed64hi_t;
|
||||
typedef unsigned int mad_fixed64lo_t;
|
||||
# else
|
||||
typedef signed long mad_fixed_t;
|
||||
|
||||
typedef signed long mad_fixed64hi_t;
|
||||
typedef unsigned long mad_fixed64lo_t;
|
||||
# endif
|
||||
|
||||
# if defined(_MSC_VER)
|
||||
# define mad_fixed64_t signed __int64
|
||||
# elif 1 || defined(__GNUC__)
|
||||
# define mad_fixed64_t signed long long
|
||||
# endif
|
||||
|
||||
# if defined(FPM_FLOAT)
|
||||
typedef double mad_sample_t;
|
||||
# else
|
||||
typedef mad_fixed_t mad_sample_t;
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Fixed-point format: 0xABBBBBBB
|
||||
* A == whole part (sign + 3 bits)
|
||||
* B == fractional part (28 bits)
|
||||
*
|
||||
* Values are signed two's complement, so the effective range is:
|
||||
* 0x80000000 to 0x7fffffff
|
||||
* -8.0 to +7.9999999962747097015380859375
|
||||
*
|
||||
* The smallest representable value is:
|
||||
* 0x00000001 == 0.0000000037252902984619140625 (i.e. about 3.725e-9)
|
||||
*
|
||||
* 28 bits of fractional accuracy represent about
|
||||
* 8.6 digits of decimal accuracy.
|
||||
*
|
||||
* Fixed-point numbers can be added or subtracted as normal
|
||||
* integers, but multiplication requires shifting the 64-bit result
|
||||
* from 56 fractional bits back to 28 (and rounding.)
|
||||
*
|
||||
* Changing the definition of MAD_F_FRACBITS is only partially
|
||||
* supported, and must be done with care.
|
||||
*/
|
||||
|
||||
# define MAD_F_FRACBITS 28
|
||||
|
||||
# if MAD_F_FRACBITS == 28
|
||||
# define MAD_F(x) ((mad_fixed_t) (x##L))
|
||||
# else
|
||||
# if MAD_F_FRACBITS < 28
|
||||
# warning "MAD_F_FRACBITS < 28"
|
||||
# define MAD_F(x) ((mad_fixed_t) \
|
||||
(((x##L) + \
|
||||
(1L << (28 - MAD_F_FRACBITS - 1))) >> \
|
||||
(28 - MAD_F_FRACBITS)))
|
||||
# elif MAD_F_FRACBITS > 28
|
||||
# error "MAD_F_FRACBITS > 28 not currently supported"
|
||||
# define MAD_F(x) ((mad_fixed_t) \
|
||||
((x##L) << (MAD_F_FRACBITS - 28)))
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# define MAD_F_MIN ((mad_fixed_t) -0x80000000L)
|
||||
# define MAD_F_MAX ((mad_fixed_t) +0x7fffffffL)
|
||||
|
||||
# define MAD_F_ONE MAD_F(0x10000000)
|
||||
|
||||
# define mad_f_tofixed(x) ((mad_fixed_t) \
|
||||
((x) * (double) (1L << MAD_F_FRACBITS) + 0.5))
|
||||
# define mad_f_todouble(x) ((double) \
|
||||
((x) / (double) (1L << MAD_F_FRACBITS)))
|
||||
|
||||
# define mad_f_intpart(x) ((x) >> MAD_F_FRACBITS)
|
||||
# define mad_f_fracpart(x) ((x) & ((1L << MAD_F_FRACBITS) - 1))
|
||||
/* (x should be positive) */
|
||||
|
||||
# define mad_f_fromint(x) ((x) << MAD_F_FRACBITS)
|
||||
|
||||
# define mad_f_add(x, y) ((x) + (y))
|
||||
# define mad_f_sub(x, y) ((x) - (y))
|
||||
|
||||
# if defined(FPM_FLOAT)
|
||||
# error "FPM_FLOAT not yet supported"
|
||||
|
||||
# undef MAD_F
|
||||
# define MAD_F(x) mad_f_todouble(x)
|
||||
|
||||
# define mad_f_mul(x, y) ((x) * (y))
|
||||
# define mad_f_scale64
|
||||
|
||||
# undef ASO_ZEROCHECK
|
||||
|
||||
# elif defined(FPM_64BIT)
|
||||
|
||||
/*
|
||||
* This version should be the most accurate if 64-bit types are supported by
|
||||
* the compiler, although it may not be the most efficient.
|
||||
*/
|
||||
# if defined(OPT_ACCURACY)
|
||||
# define mad_f_mul(x, y) \
|
||||
((mad_fixed_t) \
|
||||
((((mad_fixed64_t) (x) * (y)) + \
|
||||
(1L << (MAD_F_SCALEBITS - 1))) >> MAD_F_SCALEBITS))
|
||||
# else
|
||||
# define mad_f_mul(x, y) \
|
||||
((mad_fixed_t) (((mad_fixed64_t) (x) * (y)) >> MAD_F_SCALEBITS))
|
||||
# endif
|
||||
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
|
||||
/* --- Intel --------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_INTEL)
|
||||
|
||||
# if defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4035) /* no return value */
|
||||
static __forceinline
|
||||
mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y)
|
||||
{
|
||||
enum {
|
||||
fracbits = MAD_F_FRACBITS
|
||||
};
|
||||
|
||||
__asm {
|
||||
mov eax, x
|
||||
imul y
|
||||
shrd eax, edx, fracbits
|
||||
}
|
||||
|
||||
/* implicit return of eax */
|
||||
}
|
||||
# pragma warning(pop)
|
||||
|
||||
# define mad_f_mul mad_f_mul_inline
|
||||
# define mad_f_scale64
|
||||
# else
|
||||
/*
|
||||
* This Intel version is fast and accurate; the disposition of the least
|
||||
* significant bit depends on OPT_ACCURACY via mad_f_scale64().
|
||||
*/
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
asm ("imull %3" \
|
||||
: "=a" (lo), "=d" (hi) \
|
||||
: "%a" (x), "rm" (y) \
|
||||
: "cc")
|
||||
|
||||
# if defined(OPT_ACCURACY)
|
||||
/*
|
||||
* This gives best accuracy but is not very fast.
|
||||
*/
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
({ mad_fixed64hi_t __hi; \
|
||||
mad_fixed64lo_t __lo; \
|
||||
MAD_F_MLX(__hi, __lo, (x), (y)); \
|
||||
asm ("addl %2,%0\n\t" \
|
||||
"adcl %3,%1" \
|
||||
: "=rm" (lo), "=rm" (hi) \
|
||||
: "r" (__lo), "r" (__hi), "0" (lo), "1" (hi) \
|
||||
: "cc"); \
|
||||
})
|
||||
# endif /* OPT_ACCURACY */
|
||||
|
||||
# if defined(OPT_ACCURACY)
|
||||
/*
|
||||
* Surprisingly, this is faster than SHRD followed by ADC.
|
||||
*/
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed64hi_t __hi_; \
|
||||
mad_fixed64lo_t __lo_; \
|
||||
mad_fixed_t __result; \
|
||||
asm ("addl %4,%2\n\t" \
|
||||
"adcl %5,%3" \
|
||||
: "=rm" (__lo_), "=rm" (__hi_) \
|
||||
: "0" (lo), "1" (hi), \
|
||||
"ir" (1L << (MAD_F_SCALEBITS - 1)), "ir" (0) \
|
||||
: "cc"); \
|
||||
asm ("shrdl %3,%2,%1" \
|
||||
: "=rm" (__result) \
|
||||
: "0" (__lo_), "r" (__hi_), "I" (MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
# elif defined(OPT_INTEL)
|
||||
/*
|
||||
* Alternate Intel scaling that may or may not perform better.
|
||||
*/
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result; \
|
||||
asm ("shrl %3,%1\n\t" \
|
||||
"shll %4,%2\n\t" \
|
||||
"orl %2,%1" \
|
||||
: "=rm" (__result) \
|
||||
: "0" (lo), "r" (hi), \
|
||||
"I" (MAD_F_SCALEBITS), "I" (32 - MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
# else
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result; \
|
||||
asm ("shrdl %3,%2,%1" \
|
||||
: "=rm" (__result) \
|
||||
: "0" (lo), "r" (hi), "I" (MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
# endif /* OPT_ACCURACY */
|
||||
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
# endif
|
||||
|
||||
/* --- ARM ----------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_ARM)
|
||||
|
||||
/*
|
||||
* This ARM V4 version is as accurate as FPM_64BIT but much faster. The
|
||||
* least significant bit is properly rounded at no CPU cycle cost!
|
||||
*/
|
||||
# if 1
|
||||
/*
|
||||
* This is faster than the default implementation via MAD_F_MLX() and
|
||||
* mad_f_scale64().
|
||||
*/
|
||||
# define mad_f_mul(x, y) \
|
||||
({ mad_fixed64hi_t __hi; \
|
||||
mad_fixed64lo_t __lo; \
|
||||
mad_fixed_t __result; \
|
||||
asm ("smull %0, %1, %3, %4\n\t" \
|
||||
"movs %0, %0, lsr %5\n\t" \
|
||||
"adc %2, %0, %1, lsl %6" \
|
||||
: "=&r" (__lo), "=&r" (__hi), "=r" (__result) \
|
||||
: "%r" (x), "r" (y), \
|
||||
"M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
# endif
|
||||
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
asm ("smull %0, %1, %2, %3" \
|
||||
: "=&r" (lo), "=&r" (hi) \
|
||||
: "%r" (x), "r" (y))
|
||||
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
asm ("smlal %0, %1, %2, %3" \
|
||||
: "+r" (lo), "+r" (hi) \
|
||||
: "%r" (x), "r" (y))
|
||||
|
||||
# define MAD_F_MLN(hi, lo) \
|
||||
asm ("rsbs %0, %2, #0\n\t" \
|
||||
"rsc %1, %3, #0" \
|
||||
: "=r" (lo), "=r" (hi) \
|
||||
: "0" (lo), "1" (hi) \
|
||||
: "cc")
|
||||
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result; \
|
||||
asm ("movs %0, %1, lsr %3\n\t" \
|
||||
"adc %0, %0, %2, lsl %4" \
|
||||
: "=&r" (__result) \
|
||||
: "r" (lo), "r" (hi), \
|
||||
"M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \
|
||||
: "cc"); \
|
||||
__result; \
|
||||
})
|
||||
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
|
||||
/* --- MIPS ---------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_MIPS)
|
||||
|
||||
/*
|
||||
* This MIPS version is fast and accurate; the disposition of the least
|
||||
* significant bit depends on OPT_ACCURACY via mad_f_scale64().
|
||||
*/
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
asm ("mult %2,%3" \
|
||||
: "=l" (lo), "=h" (hi) \
|
||||
: "%r" (x), "r" (y))
|
||||
|
||||
# if defined(HAVE_MADD_ASM)
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
asm ("madd %2,%3" \
|
||||
: "+l" (lo), "+h" (hi) \
|
||||
: "%r" (x), "r" (y))
|
||||
# elif defined(HAVE_MADD16_ASM)
|
||||
/*
|
||||
* This loses significant accuracy due to the 16-bit integer limit in the
|
||||
* multiply/accumulate instruction.
|
||||
*/
|
||||
# define MAD_F_ML0(hi, lo, x, y) \
|
||||
asm ("mult %2,%3" \
|
||||
: "=l" (lo), "=h" (hi) \
|
||||
: "%r" ((x) >> 12), "r" ((y) >> 16))
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
asm ("madd16 %2,%3" \
|
||||
: "+l" (lo), "+h" (hi) \
|
||||
: "%r" ((x) >> 12), "r" ((y) >> 16))
|
||||
# define MAD_F_MLZ(hi, lo) ((mad_fixed_t) (lo))
|
||||
# endif
|
||||
|
||||
# if defined(OPT_SPEED)
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
((mad_fixed_t) ((hi) << (32 - MAD_F_SCALEBITS)))
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
# endif
|
||||
|
||||
/* --- SPARC --------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_SPARC)
|
||||
|
||||
/*
|
||||
* This SPARC V8 version is fast and accurate; the disposition of the least
|
||||
* significant bit depends on OPT_ACCURACY via mad_f_scale64().
|
||||
*/
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
asm ("smul %2, %3, %0\n\t" \
|
||||
"rd %%y, %1" \
|
||||
: "=r" (lo), "=r" (hi) \
|
||||
: "%r" (x), "rI" (y))
|
||||
|
||||
/* --- PowerPC ------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_PPC)
|
||||
|
||||
/*
|
||||
* This PowerPC version is fast and accurate; the disposition of the least
|
||||
* significant bit depends on OPT_ACCURACY via mad_f_scale64().
|
||||
*/
|
||||
# define MAD_F_MLX(hi, lo, x, y) \
|
||||
do { \
|
||||
asm ("mullw %0,%1,%2" \
|
||||
: "=r" (lo) \
|
||||
: "%r" (x), "r" (y)); \
|
||||
asm ("mulhw %0,%1,%2" \
|
||||
: "=r" (hi) \
|
||||
: "%r" (x), "r" (y)); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
# if defined(OPT_ACCURACY)
|
||||
/*
|
||||
* This gives best accuracy but is not very fast.
|
||||
*/
|
||||
# define MAD_F_MLA(hi, lo, x, y) \
|
||||
({ mad_fixed64hi_t __hi; \
|
||||
mad_fixed64lo_t __lo; \
|
||||
MAD_F_MLX(__hi, __lo, (x), (y)); \
|
||||
asm ("addc %0,%2,%3\n\t" \
|
||||
"adde %1,%4,%5" \
|
||||
: "=r" (lo), "=r" (hi) \
|
||||
: "%r" (lo), "r" (__lo), \
|
||||
"%r" (hi), "r" (__hi) \
|
||||
: "xer"); \
|
||||
})
|
||||
# endif
|
||||
|
||||
# if defined(OPT_ACCURACY)
|
||||
/*
|
||||
* This is slower than the truncating version below it.
|
||||
*/
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result, __round; \
|
||||
asm ("rotrwi %0,%1,%2" \
|
||||
: "=r" (__result) \
|
||||
: "r" (lo), "i" (MAD_F_SCALEBITS)); \
|
||||
asm ("extrwi %0,%1,1,0" \
|
||||
: "=r" (__round) \
|
||||
: "r" (__result)); \
|
||||
asm ("insrwi %0,%1,%2,0" \
|
||||
: "+r" (__result) \
|
||||
: "r" (hi), "i" (MAD_F_SCALEBITS)); \
|
||||
asm ("add %0,%1,%2" \
|
||||
: "=r" (__result) \
|
||||
: "%r" (__result), "r" (__round)); \
|
||||
__result; \
|
||||
})
|
||||
# else
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
({ mad_fixed_t __result; \
|
||||
asm ("rotrwi %0,%1,%2" \
|
||||
: "=r" (__result) \
|
||||
: "r" (lo), "i" (MAD_F_SCALEBITS)); \
|
||||
asm ("insrwi %0,%1,%2,0" \
|
||||
: "+r" (__result) \
|
||||
: "r" (hi), "i" (MAD_F_SCALEBITS)); \
|
||||
__result; \
|
||||
})
|
||||
# endif
|
||||
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
|
||||
/* --- Default ------------------------------------------------------------- */
|
||||
|
||||
# elif defined(FPM_DEFAULT)
|
||||
|
||||
/*
|
||||
* This version is the most portable but it loses significant accuracy.
|
||||
* Furthermore, accuracy is biased against the second argument, so care
|
||||
* should be taken when ordering operands.
|
||||
*
|
||||
* The scale factors are constant as this is not used with SSO.
|
||||
*
|
||||
* Pre-rounding is required to stay within the limits of compliance.
|
||||
*/
|
||||
# if defined(OPT_SPEED)
|
||||
# define mad_f_mul(x, y) (((x) >> 12) * ((y) >> 16))
|
||||
# else
|
||||
# define mad_f_mul(x, y) ((((x) + (1L << 11)) >> 12) * \
|
||||
(((y) + (1L << 15)) >> 16))
|
||||
# endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
# else
|
||||
# error "no FPM selected"
|
||||
# endif
|
||||
|
||||
/* default implementations */
|
||||
|
||||
# if !defined(mad_f_mul)
|
||||
# define mad_f_mul(x, y) \
|
||||
({ register mad_fixed64hi_t __hi; \
|
||||
register mad_fixed64lo_t __lo; \
|
||||
MAD_F_MLX(__hi, __lo, (x), (y)); \
|
||||
mad_f_scale64(__hi, __lo); \
|
||||
})
|
||||
# endif
|
||||
|
||||
# if !defined(MAD_F_MLA)
|
||||
# define MAD_F_ML0(hi, lo, x, y) ((lo) = mad_f_mul((x), (y)))
|
||||
# define MAD_F_MLA(hi, lo, x, y) ((lo) += mad_f_mul((x), (y)))
|
||||
# define MAD_F_MLN(hi, lo) ((lo) = -(lo))
|
||||
# define MAD_F_MLZ(hi, lo) ((void) (hi), (mad_fixed_t) (lo))
|
||||
# endif
|
||||
|
||||
# if !defined(MAD_F_ML0)
|
||||
# define MAD_F_ML0(hi, lo, x, y) MAD_F_MLX((hi), (lo), (x), (y))
|
||||
# endif
|
||||
|
||||
# if !defined(MAD_F_MLN)
|
||||
# define MAD_F_MLN(hi, lo) ((hi) = ((lo) = -(lo)) ? ~(hi) : -(hi))
|
||||
# endif
|
||||
|
||||
# if !defined(MAD_F_MLZ)
|
||||
# define MAD_F_MLZ(hi, lo) mad_f_scale64((hi), (lo))
|
||||
# endif
|
||||
|
||||
# if !defined(mad_f_scale64)
|
||||
# if defined(OPT_ACCURACY)
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
((((mad_fixed_t) \
|
||||
(((hi) << (32 - (MAD_F_SCALEBITS - 1))) | \
|
||||
((lo) >> (MAD_F_SCALEBITS - 1)))) + 1) >> 1)
|
||||
# else
|
||||
# define mad_f_scale64(hi, lo) \
|
||||
((mad_fixed_t) \
|
||||
(((hi) << (32 - MAD_F_SCALEBITS)) | \
|
||||
((lo) >> MAD_F_SCALEBITS)))
|
||||
# endif
|
||||
# define MAD_F_SCALEBITS MAD_F_FRACBITS
|
||||
# endif
|
||||
|
||||
/* C routines */
|
||||
|
||||
mad_fixed_t mad_f_abs(mad_fixed_t);
|
||||
mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t);
|
||||
|
||||
# endif
|
||||
|
||||
/* Id: bit.h,v 1.12 2004/01/23 09:41:32 rob Exp */
|
||||
|
||||
# ifndef LIBMAD_BIT_H
|
||||
# define LIBMAD_BIT_H
|
||||
|
||||
struct mad_bitptr {
|
||||
unsigned char const *byte;
|
||||
unsigned short cache;
|
||||
unsigned short left;
|
||||
};
|
||||
|
||||
void mad_bit_init(struct mad_bitptr *, unsigned char const *);
|
||||
|
||||
# define mad_bit_finish(bitptr) /* nothing */
|
||||
|
||||
unsigned int mad_bit_length(struct mad_bitptr const *,
|
||||
struct mad_bitptr const *);
|
||||
|
||||
# define mad_bit_bitsleft(bitptr) ((bitptr)->left)
|
||||
unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *);
|
||||
|
||||
void mad_bit_skip(struct mad_bitptr *, unsigned int);
|
||||
unsigned long mad_bit_read(struct mad_bitptr *, unsigned int);
|
||||
void mad_bit_write(struct mad_bitptr *, unsigned int, unsigned long);
|
||||
|
||||
unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short);
|
||||
|
||||
# endif
|
||||
|
||||
/* Id: timer.h,v 1.16 2004/01/23 09:41:33 rob Exp */
|
||||
|
||||
# ifndef LIBMAD_TIMER_H
|
||||
# define LIBMAD_TIMER_H
|
||||
|
||||
typedef struct {
|
||||
signed long seconds; /* whole seconds */
|
||||
unsigned long fraction; /* 1/MAD_TIMER_RESOLUTION seconds */
|
||||
} mad_timer_t;
|
||||
|
||||
extern mad_timer_t const mad_timer_zero;
|
||||
|
||||
# define MAD_TIMER_RESOLUTION 352800000UL
|
||||
|
||||
enum mad_units {
|
||||
MAD_UNITS_HOURS = -2,
|
||||
MAD_UNITS_MINUTES = -1,
|
||||
MAD_UNITS_SECONDS = 0,
|
||||
|
||||
/* metric units */
|
||||
|
||||
MAD_UNITS_DECISECONDS = 10,
|
||||
MAD_UNITS_CENTISECONDS = 100,
|
||||
MAD_UNITS_MILLISECONDS = 1000,
|
||||
|
||||
/* audio sample units */
|
||||
|
||||
MAD_UNITS_8000_HZ = 8000,
|
||||
MAD_UNITS_11025_HZ = 11025,
|
||||
MAD_UNITS_12000_HZ = 12000,
|
||||
|
||||
MAD_UNITS_16000_HZ = 16000,
|
||||
MAD_UNITS_22050_HZ = 22050,
|
||||
MAD_UNITS_24000_HZ = 24000,
|
||||
|
||||
MAD_UNITS_32000_HZ = 32000,
|
||||
MAD_UNITS_44100_HZ = 44100,
|
||||
MAD_UNITS_48000_HZ = 48000,
|
||||
|
||||
/* video frame/field units */
|
||||
|
||||
MAD_UNITS_24_FPS = 24,
|
||||
MAD_UNITS_25_FPS = 25,
|
||||
MAD_UNITS_30_FPS = 30,
|
||||
MAD_UNITS_48_FPS = 48,
|
||||
MAD_UNITS_50_FPS = 50,
|
||||
MAD_UNITS_60_FPS = 60,
|
||||
|
||||
/* CD audio frames */
|
||||
|
||||
MAD_UNITS_75_FPS = 75,
|
||||
|
||||
/* video drop-frame units */
|
||||
|
||||
MAD_UNITS_23_976_FPS = -24,
|
||||
MAD_UNITS_24_975_FPS = -25,
|
||||
MAD_UNITS_29_97_FPS = -30,
|
||||
MAD_UNITS_47_952_FPS = -48,
|
||||
MAD_UNITS_49_95_FPS = -50,
|
||||
MAD_UNITS_59_94_FPS = -60
|
||||
};
|
||||
|
||||
# define mad_timer_reset(timer) ((void) (*(timer) = mad_timer_zero))
|
||||
|
||||
int mad_timer_compare(mad_timer_t, mad_timer_t);
|
||||
|
||||
# define mad_timer_sign(timer) mad_timer_compare((timer), mad_timer_zero)
|
||||
|
||||
void mad_timer_negate(mad_timer_t *);
|
||||
mad_timer_t mad_timer_abs(mad_timer_t);
|
||||
|
||||
void mad_timer_set(mad_timer_t *, unsigned long, unsigned long, unsigned long);
|
||||
void mad_timer_add(mad_timer_t *, mad_timer_t);
|
||||
void mad_timer_multiply(mad_timer_t *, signed long);
|
||||
|
||||
signed long mad_timer_count(mad_timer_t, enum mad_units);
|
||||
unsigned long mad_timer_fraction(mad_timer_t, unsigned long);
|
||||
void mad_timer_string(mad_timer_t, char *, char const *,
|
||||
enum mad_units, enum mad_units, unsigned long);
|
||||
|
||||
# endif
|
||||
|
||||
/* Id: stream.h,v 1.20 2004/02/05 09:02:39 rob Exp */
|
||||
|
||||
# ifndef LIBMAD_STREAM_H
|
||||
# define LIBMAD_STREAM_H
|
||||
|
||||
|
||||
# define MAD_BUFFER_GUARD 8
|
||||
# define MAD_BUFFER_MDLEN (511 + 2048 + MAD_BUFFER_GUARD)
|
||||
|
||||
enum mad_error {
|
||||
MAD_ERROR_NONE = 0x0000, /* no error */
|
||||
|
||||
MAD_ERROR_BUFLEN = 0x0001, /* input buffer too small (or EOF) */
|
||||
MAD_ERROR_BUFPTR = 0x0002, /* invalid (null) buffer pointer */
|
||||
|
||||
MAD_ERROR_NOMEM = 0x0031, /* not enough memory */
|
||||
|
||||
MAD_ERROR_LOSTSYNC = 0x0101, /* lost synchronization */
|
||||
MAD_ERROR_BADLAYER = 0x0102, /* reserved header layer value */
|
||||
MAD_ERROR_BADBITRATE = 0x0103, /* forbidden bitrate value */
|
||||
MAD_ERROR_BADSAMPLERATE = 0x0104, /* reserved sample frequency value */
|
||||
MAD_ERROR_BADEMPHASIS = 0x0105, /* reserved emphasis value */
|
||||
|
||||
MAD_ERROR_BADCRC = 0x0201, /* CRC check failed */
|
||||
MAD_ERROR_BADBITALLOC = 0x0211, /* forbidden bit allocation value */
|
||||
MAD_ERROR_BADSCALEFACTOR = 0x0221, /* bad scalefactor index */
|
||||
MAD_ERROR_BADMODE = 0x0222, /* bad bitrate/mode combination */
|
||||
MAD_ERROR_BADFRAMELEN = 0x0231, /* bad frame length */
|
||||
MAD_ERROR_BADBIGVALUES = 0x0232, /* bad big_values count */
|
||||
MAD_ERROR_BADBLOCKTYPE = 0x0233, /* reserved block_type */
|
||||
MAD_ERROR_BADSCFSI = 0x0234, /* bad scalefactor selection info */
|
||||
MAD_ERROR_BADDATAPTR = 0x0235, /* bad main_data_begin pointer */
|
||||
MAD_ERROR_BADPART3LEN = 0x0236, /* bad audio data length */
|
||||
MAD_ERROR_BADHUFFTABLE = 0x0237, /* bad Huffman table select */
|
||||
MAD_ERROR_BADHUFFDATA = 0x0238, /* Huffman data overrun */
|
||||
MAD_ERROR_BADSTEREO = 0x0239 /* incompatible block_type for JS */
|
||||
};
|
||||
|
||||
# define MAD_RECOVERABLE(error) ((error) & 0xff00)
|
||||
|
||||
struct mad_stream {
|
||||
unsigned char const *buffer; /* input bitstream buffer */
|
||||
unsigned char const *bufend; /* end of buffer */
|
||||
unsigned long skiplen; /* bytes to skip before next frame */
|
||||
|
||||
int sync; /* stream sync found */
|
||||
unsigned long freerate; /* free bitrate (fixed) */
|
||||
|
||||
unsigned char const *this_frame; /* start of current frame */
|
||||
unsigned char const *next_frame; /* start of next frame */
|
||||
struct mad_bitptr ptr; /* current processing bit pointer */
|
||||
|
||||
struct mad_bitptr anc_ptr; /* ancillary bits pointer */
|
||||
unsigned int anc_bitlen; /* number of ancillary bits */
|
||||
|
||||
unsigned char (*main_data)[MAD_BUFFER_MDLEN];
|
||||
/* Layer III main_data() */
|
||||
unsigned int md_len; /* bytes in main_data */
|
||||
|
||||
int options; /* decoding options (see below) */
|
||||
enum mad_error error; /* error code (see above) */
|
||||
};
|
||||
|
||||
enum {
|
||||
MAD_OPTION_IGNORECRC = 0x0001, /* ignore CRC errors */
|
||||
MAD_OPTION_HALFSAMPLERATE = 0x0002 /* generate PCM at 1/2 sample rate */
|
||||
# if 0 /* not yet implemented */
|
||||
MAD_OPTION_LEFTCHANNEL = 0x0010, /* decode left channel only */
|
||||
MAD_OPTION_RIGHTCHANNEL = 0x0020, /* decode right channel only */
|
||||
MAD_OPTION_SINGLECHANNEL = 0x0030 /* combine channels */
|
||||
# endif
|
||||
};
|
||||
|
||||
void mad_stream_init(struct mad_stream *);
|
||||
void mad_stream_finish(struct mad_stream *);
|
||||
|
||||
# define mad_stream_options(stream, opts) \
|
||||
((void) ((stream)->options = (opts)))
|
||||
|
||||
void mad_stream_buffer(struct mad_stream *,
|
||||
unsigned char const *, unsigned long);
|
||||
void mad_stream_skip(struct mad_stream *, unsigned long);
|
||||
|
||||
int mad_stream_sync(struct mad_stream *);
|
||||
|
||||
char const *mad_stream_errorstr(struct mad_stream const *);
|
||||
|
||||
# endif
|
||||
|
||||
/* Id: frame.h,v 1.20 2004/01/23 09:41:32 rob Exp */
|
||||
|
||||
# ifndef LIBMAD_FRAME_H
|
||||
# define LIBMAD_FRAME_H
|
||||
|
||||
|
||||
enum mad_layer {
|
||||
MAD_LAYER_I = 1, /* Layer I */
|
||||
MAD_LAYER_II = 2, /* Layer II */
|
||||
MAD_LAYER_III = 3 /* Layer III */
|
||||
};
|
||||
|
||||
enum mad_mode {
|
||||
MAD_MODE_SINGLE_CHANNEL = 0, /* single channel */
|
||||
MAD_MODE_DUAL_CHANNEL = 1, /* dual channel */
|
||||
MAD_MODE_JOINT_STEREO = 2, /* joint (MS/intensity) stereo */
|
||||
MAD_MODE_STEREO = 3 /* normal LR stereo */
|
||||
};
|
||||
|
||||
enum mad_emphasis {
|
||||
MAD_EMPHASIS_NONE = 0, /* no emphasis */
|
||||
MAD_EMPHASIS_50_15_US = 1, /* 50/15 microseconds emphasis */
|
||||
MAD_EMPHASIS_CCITT_J_17 = 3, /* CCITT J.17 emphasis */
|
||||
MAD_EMPHASIS_RESERVED = 2 /* unknown emphasis */
|
||||
};
|
||||
|
||||
struct mad_header {
|
||||
enum mad_layer layer; /* audio layer (1, 2, or 3) */
|
||||
enum mad_mode mode; /* channel mode (see above) */
|
||||
int mode_extension; /* additional mode info */
|
||||
enum mad_emphasis emphasis; /* de-emphasis to use (see above) */
|
||||
|
||||
unsigned long bitrate; /* stream bitrate (bps) */
|
||||
unsigned int samplerate; /* sampling frequency (Hz) */
|
||||
|
||||
unsigned short crc_check; /* frame CRC accumulator */
|
||||
unsigned short crc_target; /* final target CRC checksum */
|
||||
|
||||
int flags; /* flags (see below) */
|
||||
int private_bits; /* private bits (see below) */
|
||||
|
||||
mad_timer_t duration; /* audio playing time of frame */
|
||||
};
|
||||
|
||||
struct mad_frame {
|
||||
struct mad_header header; /* MPEG audio header */
|
||||
|
||||
int options; /* decoding options (from stream) */
|
||||
|
||||
mad_fixed_t sbsample[2][36][32]; /* synthesis subband filter samples */
|
||||
mad_fixed_t (*overlap)[2][32][18]; /* Layer III block overlap data */
|
||||
};
|
||||
|
||||
# define MAD_NCHANNELS(header) ((header)->mode ? 2 : 1)
|
||||
# define MAD_NSBSAMPLES(header) \
|
||||
((header)->layer == MAD_LAYER_I ? 12 : \
|
||||
(((header)->layer == MAD_LAYER_III && \
|
||||
((header)->flags & MAD_FLAG_LSF_EXT)) ? 18 : 36))
|
||||
|
||||
enum {
|
||||
MAD_FLAG_NPRIVATE_III = 0x0007, /* number of Layer III private bits */
|
||||
MAD_FLAG_INCOMPLETE = 0x0008, /* header but not data is decoded */
|
||||
|
||||
MAD_FLAG_PROTECTION = 0x0010, /* frame has CRC protection */
|
||||
MAD_FLAG_COPYRIGHT = 0x0020, /* frame is copyright */
|
||||
MAD_FLAG_ORIGINAL = 0x0040, /* frame is original (else copy) */
|
||||
MAD_FLAG_PADDING = 0x0080, /* frame has additional slot */
|
||||
|
||||
MAD_FLAG_I_STEREO = 0x0100, /* uses intensity joint stereo */
|
||||
MAD_FLAG_MS_STEREO = 0x0200, /* uses middle/side joint stereo */
|
||||
MAD_FLAG_FREEFORMAT = 0x0400, /* uses free format bitrate */
|
||||
|
||||
MAD_FLAG_LSF_EXT = 0x1000, /* lower sampling freq. extension */
|
||||
MAD_FLAG_MC_EXT = 0x2000, /* multichannel audio extension */
|
||||
MAD_FLAG_MPEG_2_5_EXT = 0x4000 /* MPEG 2.5 (unofficial) extension */
|
||||
};
|
||||
|
||||
enum {
|
||||
MAD_PRIVATE_HEADER = 0x0100, /* header private bit */
|
||||
MAD_PRIVATE_III = 0x001f /* Layer III private bits (up to 5) */
|
||||
};
|
||||
|
||||
void mad_header_init(struct mad_header *);
|
||||
|
||||
# define mad_header_finish(header) /* nothing */
|
||||
|
||||
int mad_header_decode(struct mad_header *, struct mad_stream *);
|
||||
|
||||
void mad_frame_init(struct mad_frame *);
|
||||
void mad_frame_finish(struct mad_frame *);
|
||||
|
||||
int mad_frame_decode(struct mad_frame *, struct mad_stream *);
|
||||
|
||||
void mad_frame_mute(struct mad_frame *);
|
||||
|
||||
# endif
|
||||
|
||||
/* Id: synth.h,v 1.15 2004/01/23 09:41:33 rob Exp */
|
||||
|
||||
# ifndef LIBMAD_SYNTH_H
|
||||
# define LIBMAD_SYNTH_H
|
||||
|
||||
|
||||
struct mad_pcm {
|
||||
unsigned int samplerate; /* sampling frequency (Hz) */
|
||||
unsigned short channels; /* number of channels */
|
||||
unsigned short length; /* number of samples per channel */
|
||||
mad_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */
|
||||
};
|
||||
|
||||
struct mad_synth {
|
||||
mad_fixed_t filter[2][2][2][16][8]; /* polyphase filterbank outputs */
|
||||
/* [ch][eo][peo][s][v] */
|
||||
|
||||
unsigned int phase; /* current processing phase */
|
||||
|
||||
struct mad_pcm pcm; /* PCM output */
|
||||
};
|
||||
|
||||
/* single channel PCM selector */
|
||||
enum {
|
||||
MAD_PCM_CHANNEL_SINGLE = 0
|
||||
};
|
||||
|
||||
/* dual channel PCM selector */
|
||||
enum {
|
||||
MAD_PCM_CHANNEL_DUAL_1 = 0,
|
||||
MAD_PCM_CHANNEL_DUAL_2 = 1
|
||||
};
|
||||
|
||||
/* stereo PCM selector */
|
||||
enum {
|
||||
MAD_PCM_CHANNEL_STEREO_LEFT = 0,
|
||||
MAD_PCM_CHANNEL_STEREO_RIGHT = 1
|
||||
};
|
||||
|
||||
void mad_synth_init(struct mad_synth *);
|
||||
|
||||
# define mad_synth_finish(synth) /* nothing */
|
||||
|
||||
void mad_synth_mute(struct mad_synth *);
|
||||
|
||||
void mad_synth_frame(struct mad_synth *, struct mad_frame const *);
|
||||
|
||||
# endif
|
||||
|
||||
/* Id: decoder.h,v 1.17 2004/01/23 09:41:32 rob Exp */
|
||||
|
||||
# ifndef LIBMAD_DECODER_H
|
||||
# define LIBMAD_DECODER_H
|
||||
|
||||
|
||||
enum mad_decoder_mode {
|
||||
MAD_DECODER_MODE_SYNC = 0,
|
||||
MAD_DECODER_MODE_ASYNC
|
||||
};
|
||||
|
||||
enum mad_flow {
|
||||
MAD_FLOW_CONTINUE = 0x0000, /* continue normally */
|
||||
MAD_FLOW_STOP = 0x0010, /* stop decoding normally */
|
||||
MAD_FLOW_BREAK = 0x0011, /* stop decoding and signal an error */
|
||||
MAD_FLOW_IGNORE = 0x0020 /* ignore the current frame */
|
||||
};
|
||||
|
||||
struct mad_decoder {
|
||||
enum mad_decoder_mode mode;
|
||||
|
||||
int options;
|
||||
|
||||
struct {
|
||||
long pid;
|
||||
int in;
|
||||
int out;
|
||||
} async;
|
||||
|
||||
struct {
|
||||
struct mad_stream stream;
|
||||
struct mad_frame frame;
|
||||
struct mad_synth synth;
|
||||
} *sync;
|
||||
|
||||
void *cb_data;
|
||||
|
||||
enum mad_flow (*input_func)(void *, struct mad_stream *);
|
||||
enum mad_flow (*header_func)(void *, struct mad_header const *);
|
||||
enum mad_flow (*filter_func)(void *,
|
||||
struct mad_stream const *, struct mad_frame *);
|
||||
enum mad_flow (*output_func)(void *,
|
||||
struct mad_header const *, struct mad_pcm *);
|
||||
enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
|
||||
enum mad_flow (*message_func)(void *, void *, unsigned int *);
|
||||
};
|
||||
|
||||
void mad_decoder_init(struct mad_decoder *, void *,
|
||||
enum mad_flow (*)(void *, struct mad_stream *),
|
||||
enum mad_flow (*)(void *, struct mad_header const *),
|
||||
enum mad_flow (*)(void *,
|
||||
struct mad_stream const *,
|
||||
struct mad_frame *),
|
||||
enum mad_flow (*)(void *,
|
||||
struct mad_header const *,
|
||||
struct mad_pcm *),
|
||||
enum mad_flow (*)(void *,
|
||||
struct mad_stream *,
|
||||
struct mad_frame *),
|
||||
enum mad_flow (*)(void *, void *, unsigned int *));
|
||||
int mad_decoder_finish(struct mad_decoder *);
|
||||
|
||||
# define mad_decoder_options(decoder, opts) \
|
||||
((void) ((decoder)->options = (opts)))
|
||||
|
||||
int mad_decoder_run(struct mad_decoder *, enum mad_decoder_mode);
|
||||
int mad_decoder_message(struct mad_decoder *, void *, unsigned int *);
|
||||
|
||||
# endif
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
328
libmad/music_mad.c
Normal file
328
libmad/music_mad.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
SDL_mixer: An audio mixer library based on the SDL library
|
||||
Copyright (C) 1997-2004 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "music_mad.h"
|
||||
|
||||
mad_data *
|
||||
mad_openFile(const char *filename, SDL_AudioSpec *mixer) {
|
||||
SDL_RWops *rw;
|
||||
|
||||
rw = SDL_RWFromFile(filename, "rb");
|
||||
if (rw == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mad_openFileRW(rw, mixer);
|
||||
}
|
||||
|
||||
mad_data *
|
||||
mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer) {
|
||||
mad_data *mp3_mad;
|
||||
|
||||
mp3_mad = (mad_data *)malloc(sizeof(mad_data));
|
||||
mp3_mad->rw = rw;
|
||||
mad_stream_init(&mp3_mad->stream);
|
||||
mad_frame_init(&mp3_mad->frame);
|
||||
mad_synth_init(&mp3_mad->synth);
|
||||
mp3_mad->frames_read = 0;
|
||||
mad_timer_reset(&mp3_mad->next_frame_start);
|
||||
mp3_mad->volume = 128;
|
||||
mp3_mad->status = 0;
|
||||
mp3_mad->output_begin = 0;
|
||||
mp3_mad->output_end = 0;
|
||||
mp3_mad->mixer = *mixer;
|
||||
|
||||
return mp3_mad;
|
||||
}
|
||||
|
||||
void
|
||||
mad_closeFile(mad_data *mp3_mad) {
|
||||
SDL_FreeRW(mp3_mad->rw);
|
||||
mad_stream_finish(&mp3_mad->stream);
|
||||
mad_frame_finish(&mp3_mad->frame);
|
||||
mad_synth_finish(&mp3_mad->synth);
|
||||
|
||||
free(mp3_mad);
|
||||
}
|
||||
|
||||
/* Starts the playback. */
|
||||
void
|
||||
mad_start(mad_data *mp3_mad) {
|
||||
mp3_mad->status |= MS_playing;
|
||||
}
|
||||
|
||||
/* Stops the playback. */
|
||||
void
|
||||
mad_stop(mad_data *mp3_mad) {
|
||||
mp3_mad->status &= ~MS_playing;
|
||||
}
|
||||
|
||||
/* Returns true if the playing is engaged, false otherwise. */
|
||||
int
|
||||
mad_isPlaying(mad_data *mp3_mad) {
|
||||
return ((mp3_mad->status & MS_playing) != 0);
|
||||
}
|
||||
|
||||
/* Reads the next frame from the file. Returns true on success or
|
||||
false on failure. */
|
||||
static int
|
||||
read_next_frame(mad_data *mp3_mad) {
|
||||
if (mp3_mad->stream.buffer == NULL ||
|
||||
mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
|
||||
size_t read_size;
|
||||
size_t remaining;
|
||||
unsigned char *read_start;
|
||||
|
||||
/* There might be some bytes in the buffer left over from last
|
||||
time. If so, move them down and read more bytes following
|
||||
them. */
|
||||
if (mp3_mad->stream.next_frame != NULL) {
|
||||
remaining = mp3_mad->stream.bufend - mp3_mad->stream.next_frame;
|
||||
memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining);
|
||||
read_start = mp3_mad->input_buffer + remaining;
|
||||
read_size = MAD_INPUT_BUFFER_SIZE - remaining;
|
||||
|
||||
} else {
|
||||
read_size = MAD_INPUT_BUFFER_SIZE;
|
||||
read_start = mp3_mad->input_buffer;
|
||||
remaining = 0;
|
||||
}
|
||||
|
||||
/* Now read additional bytes from the input file. */
|
||||
read_size = SDL_RWread(mp3_mad->rw, read_start, 1, read_size);
|
||||
|
||||
if (read_size <= 0) {
|
||||
if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) {
|
||||
if (read_size == 0) {
|
||||
mp3_mad->status |= MS_input_eof;
|
||||
} else {
|
||||
mp3_mad->status |= MS_input_error;
|
||||
}
|
||||
|
||||
/* At the end of the file, we must stuff MAD_BUFFER_GUARD
|
||||
number of 0 bytes. */
|
||||
memset(read_start + read_size, 0, MAD_BUFFER_GUARD);
|
||||
read_size += MAD_BUFFER_GUARD;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now feed those bytes into the libmad stream. */
|
||||
mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer,
|
||||
read_size + remaining);
|
||||
mp3_mad->stream.error = MAD_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* Now ask libmad to extract a frame from the data we just put in
|
||||
its buffer. */
|
||||
if (mad_frame_decode(&mp3_mad->frame, &mp3_mad->stream)) {
|
||||
if (MAD_RECOVERABLE(mp3_mad->stream.error)) {
|
||||
return 0;
|
||||
|
||||
} else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
mp3_mad->status |= MS_decode_error;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mp3_mad->frames_read++;
|
||||
mad_timer_add(&mp3_mad->next_frame_start, mp3_mad->frame.header.duration);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Scale a MAD sample to 16 bits for output. */
|
||||
static signed int
|
||||
scale(mad_fixed_t sample) {
|
||||
/* round */
|
||||
sample += (1L << (MAD_F_FRACBITS - 16));
|
||||
|
||||
/* clip */
|
||||
if (sample >= MAD_F_ONE)
|
||||
sample = MAD_F_ONE - 1;
|
||||
else if (sample < -MAD_F_ONE)
|
||||
sample = -MAD_F_ONE;
|
||||
|
||||
/* quantize */
|
||||
return sample >> (MAD_F_FRACBITS + 1 - 16);
|
||||
}
|
||||
|
||||
/* Once the frame has been read, copies its samples into the output
|
||||
buffer. */
|
||||
static void
|
||||
decode_frame(mad_data *mp3_mad) {
|
||||
struct mad_pcm *pcm;
|
||||
unsigned int nchannels, nsamples;
|
||||
mad_fixed_t const *left_ch, *right_ch;
|
||||
unsigned char *out;
|
||||
|
||||
mad_synth_frame(&mp3_mad->synth, &mp3_mad->frame);
|
||||
pcm = &mp3_mad->synth.pcm;
|
||||
out = mp3_mad->output_buffer + mp3_mad->output_end;
|
||||
|
||||
if ((mp3_mad->status & MS_cvt_decoded) == 0) {
|
||||
mp3_mad->status |= MS_cvt_decoded;
|
||||
|
||||
/* The first frame determines some key properties of the stream.
|
||||
In particular, it tells us enough to set up the convert
|
||||
structure now. */
|
||||
SDL_BuildAudioCVT(&mp3_mad->cvt, AUDIO_S16, (Uint8)pcm->channels, mp3_mad->frame.header.samplerate, mp3_mad->mixer.format, mp3_mad->mixer.channels, mp3_mad->mixer.freq);
|
||||
}
|
||||
|
||||
/* pcm->samplerate contains the sampling frequency */
|
||||
|
||||
nchannels = pcm->channels;
|
||||
nsamples = pcm->length;
|
||||
left_ch = pcm->samples[0];
|
||||
right_ch = pcm->samples[1];
|
||||
|
||||
while (nsamples--) {
|
||||
signed int sample;
|
||||
|
||||
/* output sample(s) in 16-bit signed little-endian PCM */
|
||||
|
||||
sample = scale(*left_ch++);
|
||||
*out++ = ((sample >> 0) & 0xff);
|
||||
*out++ = ((sample >> 8) & 0xff);
|
||||
|
||||
if (nchannels == 2) {
|
||||
sample = scale(*right_ch++);
|
||||
*out++ = ((sample >> 0) & 0xff);
|
||||
*out++ = ((sample >> 8) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
mp3_mad->output_end = out - mp3_mad->output_buffer;
|
||||
/*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
|
||||
}
|
||||
|
||||
void
|
||||
mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
|
||||
int bytes_remaining;
|
||||
int num_bytes;
|
||||
Uint8 *out;
|
||||
|
||||
if ((mp3_mad->status & MS_playing) == 0) {
|
||||
/* We're not supposed to be playing, so send silence instead. */
|
||||
memset(stream, 0, len);
|
||||
return;
|
||||
}
|
||||
|
||||
out = stream;
|
||||
bytes_remaining = len;
|
||||
while (bytes_remaining > 0) {
|
||||
if (mp3_mad->output_end == mp3_mad->output_begin) {
|
||||
/* We need to get a new frame. */
|
||||
mp3_mad->output_begin = 0;
|
||||
mp3_mad->output_end = 0;
|
||||
if (!read_next_frame(mp3_mad)) {
|
||||
if ((mp3_mad->status & MS_error_flags) != 0) {
|
||||
/* Couldn't read a frame; either an error condition or
|
||||
end-of-file. Stop. */
|
||||
memset(out, 0, bytes_remaining);
|
||||
mp3_mad->status &= ~MS_playing;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
decode_frame(mp3_mad);
|
||||
|
||||
/* Now convert the frame data to the appropriate format for
|
||||
output. */
|
||||
mp3_mad->cvt.buf = mp3_mad->output_buffer;
|
||||
mp3_mad->cvt.len = mp3_mad->output_end;
|
||||
|
||||
mp3_mad->output_end = (int)(mp3_mad->output_end * mp3_mad->cvt.len_ratio);
|
||||
/*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
|
||||
SDL_ConvertAudio(&mp3_mad->cvt);
|
||||
}
|
||||
}
|
||||
|
||||
num_bytes = mp3_mad->output_end - mp3_mad->output_begin;
|
||||
if (bytes_remaining < num_bytes) {
|
||||
num_bytes = bytes_remaining;
|
||||
}
|
||||
|
||||
if (mp3_mad->volume == 128) {
|
||||
memcpy(out, mp3_mad->output_buffer + mp3_mad->output_begin, num_bytes);
|
||||
} else {
|
||||
SDL_MixAudio(out, mp3_mad->output_buffer + mp3_mad->output_begin,
|
||||
num_bytes, mp3_mad->volume);
|
||||
}
|
||||
out += num_bytes;
|
||||
mp3_mad->output_begin += num_bytes;
|
||||
bytes_remaining -= num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mad_seek(mad_data *mp3_mad, double position) {
|
||||
mad_timer_t target;
|
||||
int int_part;
|
||||
|
||||
int_part = (int)position;
|
||||
mad_timer_set(&target, int_part,
|
||||
(int)((position - int_part) * 1000000), 1000000);
|
||||
|
||||
if (mad_timer_compare(mp3_mad->next_frame_start, target) > 0) {
|
||||
/* In order to seek backwards in a VBR file, we have to rewind and
|
||||
start again from the beginning. This isn't necessary if the
|
||||
file happens to be CBR, of course; in that case we could seek
|
||||
directly to the frame we want. But I leave that little
|
||||
optimization for the future developer who discovers she really
|
||||
needs it. */
|
||||
mp3_mad->frames_read = 0;
|
||||
mad_timer_reset(&mp3_mad->next_frame_start);
|
||||
mp3_mad->status &= ~MS_error_flags;
|
||||
mp3_mad->output_begin = 0;
|
||||
mp3_mad->output_end = 0;
|
||||
|
||||
SDL_RWseek(mp3_mad->rw, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
/* Now we have to skip frames until we come to the right one.
|
||||
Again, only truly necessary if the file is VBR. */
|
||||
while (mad_timer_compare(mp3_mad->next_frame_start, target) < 0) {
|
||||
if (!read_next_frame(mp3_mad)) {
|
||||
if ((mp3_mad->status & MS_error_flags) != 0) {
|
||||
/* Couldn't read a frame; either an error condition or
|
||||
end-of-file. Stop. */
|
||||
mp3_mad->status &= ~MS_playing;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Here we are, at the beginning of the frame that contains the
|
||||
target time. Ehh, I say that's close enough. If we wanted to,
|
||||
we could get more precise by decoding the frame now and counting
|
||||
the appropriate number of samples out of it. */
|
||||
}
|
||||
|
||||
void
|
||||
mad_setVolume(mad_data *mp3_mad, int volume) {
|
||||
mp3_mad->volume = volume;
|
||||
}
|
68
libmad/music_mad.h
Normal file
68
libmad/music_mad.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
SDL_mixer: An audio mixer library based on the SDL library
|
||||
Copyright (C) 1997-2004 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
#include "mad.h"
|
||||
#include "SDL_rwops.h"
|
||||
#include "SDL_audio.h"
|
||||
|
||||
#define MAD_INPUT_BUFFER_SIZE (5*8192)
|
||||
#define MAD_OUTPUT_BUFFER_SIZE 8192
|
||||
|
||||
enum {
|
||||
MS_input_eof = 0x0001,
|
||||
MS_input_error = 0x0001,
|
||||
MS_decode_eof = 0x0002,
|
||||
MS_decode_error = 0x0004,
|
||||
MS_error_flags = 0x000f,
|
||||
|
||||
MS_playing = 0x0100,
|
||||
MS_cvt_decoded = 0x0200,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
SDL_RWops *rw;
|
||||
struct mad_stream stream;
|
||||
struct mad_frame frame;
|
||||
struct mad_synth synth;
|
||||
int frames_read;
|
||||
mad_timer_t next_frame_start;
|
||||
int volume;
|
||||
int status;
|
||||
int output_begin, output_end;
|
||||
SDL_AudioSpec mixer;
|
||||
SDL_AudioCVT cvt;
|
||||
|
||||
unsigned char input_buffer[MAD_INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
|
||||
unsigned char output_buffer[MAD_OUTPUT_BUFFER_SIZE];
|
||||
} mad_data;
|
||||
|
||||
mad_data *mad_openFile(const char *filename, SDL_AudioSpec *mixer);
|
||||
mad_data *mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer);
|
||||
void mad_closeFile(mad_data *mp3_mad);
|
||||
|
||||
void mad_start(mad_data *mp3_mad);
|
||||
void mad_stop(mad_data *mp3_mad);
|
||||
int mad_isPlaying(mad_data *mp3_mad);
|
||||
|
||||
void mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len);
|
||||
void mad_seek(mad_data *mp3_mad, double position);
|
||||
void mad_setVolume(mad_data *mp3_mad, int volume);
|
77
libmad/qc_table.dat
Normal file
77
libmad/qc_table.dat
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: qc_table.dat,v 1.7 2004/01/23 09:41:32 rob Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* These are the Layer II classes of quantization.
|
||||
* The table is derived from Table B.4 of ISO/IEC 11172-3.
|
||||
*/
|
||||
|
||||
{ 3, 2, 5,
|
||||
MAD_F(0x15555555) /* 1.33333333333 => 1.33333333209, e 0.00000000124 */,
|
||||
MAD_F(0x08000000) /* 0.50000000000 => 0.50000000000, e 0.00000000000 */ },
|
||||
{ 5, 3, 7,
|
||||
MAD_F(0x1999999a) /* 1.60000000000 => 1.60000000149, e -0.00000000149 */,
|
||||
MAD_F(0x08000000) /* 0.50000000000 => 0.50000000000, e 0.00000000000 */ },
|
||||
{ 7, 0, 3,
|
||||
MAD_F(0x12492492) /* 1.14285714286 => 1.14285714179, e 0.00000000107 */,
|
||||
MAD_F(0x04000000) /* 0.25000000000 => 0.25000000000, e 0.00000000000 */ },
|
||||
{ 9, 4, 10,
|
||||
MAD_F(0x1c71c71c) /* 1.77777777777 => 1.77777777612, e 0.00000000165 */,
|
||||
MAD_F(0x08000000) /* 0.50000000000 => 0.50000000000, e 0.00000000000 */ },
|
||||
{ 15, 0, 4,
|
||||
MAD_F(0x11111111) /* 1.06666666666 => 1.06666666642, e 0.00000000024 */,
|
||||
MAD_F(0x02000000) /* 0.12500000000 => 0.12500000000, e 0.00000000000 */ },
|
||||
{ 31, 0, 5,
|
||||
MAD_F(0x10842108) /* 1.03225806452 => 1.03225806355, e 0.00000000097 */,
|
||||
MAD_F(0x01000000) /* 0.06250000000 => 0.06250000000, e 0.00000000000 */ },
|
||||
{ 63, 0, 6,
|
||||
MAD_F(0x10410410) /* 1.01587301587 => 1.01587301493, e 0.00000000094 */,
|
||||
MAD_F(0x00800000) /* 0.03125000000 => 0.03125000000, e 0.00000000000 */ },
|
||||
{ 127, 0, 7,
|
||||
MAD_F(0x10204081) /* 1.00787401575 => 1.00787401572, e 0.00000000003 */,
|
||||
MAD_F(0x00400000) /* 0.01562500000 => 0.01562500000, e 0.00000000000 */ },
|
||||
{ 255, 0, 8,
|
||||
MAD_F(0x10101010) /* 1.00392156863 => 1.00392156839, e 0.00000000024 */,
|
||||
MAD_F(0x00200000) /* 0.00781250000 => 0.00781250000, e 0.00000000000 */ },
|
||||
{ 511, 0, 9,
|
||||
MAD_F(0x10080402) /* 1.00195694716 => 1.00195694715, e 0.00000000001 */,
|
||||
MAD_F(0x00100000) /* 0.00390625000 => 0.00390625000, e 0.00000000000 */ },
|
||||
{ 1023, 0, 10,
|
||||
MAD_F(0x10040100) /* 1.00097751711 => 1.00097751617, e 0.00000000094 */,
|
||||
MAD_F(0x00080000) /* 0.00195312500 => 0.00195312500, e 0.00000000000 */ },
|
||||
{ 2047, 0, 11,
|
||||
MAD_F(0x10020040) /* 1.00048851979 => 1.00048851967, e 0.00000000012 */,
|
||||
MAD_F(0x00040000) /* 0.00097656250 => 0.00097656250, e 0.00000000000 */ },
|
||||
{ 4095, 0, 12,
|
||||
MAD_F(0x10010010) /* 1.00024420024 => 1.00024420023, e 0.00000000001 */,
|
||||
MAD_F(0x00020000) /* 0.00048828125 => 0.00048828125, e 0.00000000000 */ },
|
||||
{ 8191, 0, 13,
|
||||
MAD_F(0x10008004) /* 1.00012208522 => 1.00012208521, e 0.00000000001 */,
|
||||
MAD_F(0x00010000) /* 0.00024414063 => 0.00024414062, e 0.00000000000 */ },
|
||||
{ 16383, 0, 14,
|
||||
MAD_F(0x10004001) /* 1.00006103888 => 1.00006103888, e -0.00000000000 */,
|
||||
MAD_F(0x00008000) /* 0.00012207031 => 0.00012207031, e -0.00000000000 */ },
|
||||
{ 32767, 0, 15,
|
||||
MAD_F(0x10002000) /* 1.00003051851 => 1.00003051758, e 0.00000000093 */,
|
||||
MAD_F(0x00004000) /* 0.00006103516 => 0.00006103516, e 0.00000000000 */ },
|
||||
{ 65535, 0, 16,
|
||||
MAD_F(0x10001000) /* 1.00001525902 => 1.00001525879, e 0.00000000023 */,
|
||||
MAD_F(0x00002000) /* 0.00003051758 => 0.00003051758, e 0.00000000000 */ }
|
8747
libmad/rq_table.dat
Normal file
8747
libmad/rq_table.dat
Normal file
File diff suppressed because it is too large
Load Diff
106
libmad/sf_table.dat
Normal file
106
libmad/sf_table.dat
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: sf_table.dat,v 1.7 2004/01/23 09:41:33 rob Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* These are the scalefactor values for Layer I and Layer II.
|
||||
* The values are from Table B.1 of ISO/IEC 11172-3.
|
||||
*
|
||||
* There is some error introduced by the 32-bit fixed-point representation;
|
||||
* the amount of error is shown. For 16-bit PCM output, this shouldn't be
|
||||
* too much of a problem.
|
||||
*
|
||||
* Strictly speaking, Table B.1 has only 63 entries (0-62), thus a strict
|
||||
* interpretation of ISO/IEC 11172-3 would suggest that a scalefactor index of
|
||||
* 63 is invalid. However, for better compatibility with current practices, we
|
||||
* add a 64th entry.
|
||||
*/
|
||||
|
||||
MAD_F(0x20000000), /* 2.000000000000 => 2.000000000000, e 0.000000000000 */
|
||||
MAD_F(0x1965fea5), /* 1.587401051968 => 1.587401051074, e 0.000000000894 */
|
||||
MAD_F(0x1428a2fa), /* 1.259921049895 => 1.259921051562, e -0.000000001667 */
|
||||
MAD_F(0x10000000), /* 1.000000000000 => 1.000000000000, e 0.000000000000 */
|
||||
MAD_F(0x0cb2ff53), /* 0.793700525984 => 0.793700527400, e -0.000000001416 */
|
||||
MAD_F(0x0a14517d), /* 0.629960524947 => 0.629960525781, e -0.000000000833 */
|
||||
MAD_F(0x08000000), /* 0.500000000000 => 0.500000000000, e 0.000000000000 */
|
||||
MAD_F(0x06597fa9), /* 0.396850262992 => 0.396850261837, e 0.000000001155 */
|
||||
|
||||
MAD_F(0x050a28be), /* 0.314980262474 => 0.314980261028, e 0.000000001446 */
|
||||
MAD_F(0x04000000), /* 0.250000000000 => 0.250000000000, e 0.000000000000 */
|
||||
MAD_F(0x032cbfd5), /* 0.198425131496 => 0.198425132781, e -0.000000001285 */
|
||||
MAD_F(0x0285145f), /* 0.157490131237 => 0.157490130514, e 0.000000000723 */
|
||||
MAD_F(0x02000000), /* 0.125000000000 => 0.125000000000, e 0.000000000000 */
|
||||
MAD_F(0x01965fea), /* 0.099212565748 => 0.099212564528, e 0.000000001220 */
|
||||
MAD_F(0x01428a30), /* 0.078745065618 => 0.078745067120, e -0.000000001501 */
|
||||
MAD_F(0x01000000), /* 0.062500000000 => 0.062500000000, e 0.000000000000 */
|
||||
|
||||
MAD_F(0x00cb2ff5), /* 0.049606282874 => 0.049606282264, e 0.000000000610 */
|
||||
MAD_F(0x00a14518), /* 0.039372532809 => 0.039372533560, e -0.000000000751 */
|
||||
MAD_F(0x00800000), /* 0.031250000000 => 0.031250000000, e 0.000000000000 */
|
||||
MAD_F(0x006597fb), /* 0.024803141437 => 0.024803142995, e -0.000000001558 */
|
||||
MAD_F(0x0050a28c), /* 0.019686266405 => 0.019686266780, e -0.000000000375 */
|
||||
MAD_F(0x00400000), /* 0.015625000000 => 0.015625000000, e 0.000000000000 */
|
||||
MAD_F(0x0032cbfd), /* 0.012401570719 => 0.012401569635, e 0.000000001084 */
|
||||
MAD_F(0x00285146), /* 0.009843133202 => 0.009843133390, e -0.000000000188 */
|
||||
|
||||
MAD_F(0x00200000), /* 0.007812500000 => 0.007812500000, e 0.000000000000 */
|
||||
MAD_F(0x001965ff), /* 0.006200785359 => 0.006200786680, e -0.000000001321 */
|
||||
MAD_F(0x001428a3), /* 0.004921566601 => 0.004921566695, e -0.000000000094 */
|
||||
MAD_F(0x00100000), /* 0.003906250000 => 0.003906250000, e 0.000000000000 */
|
||||
MAD_F(0x000cb2ff), /* 0.003100392680 => 0.003100391477, e 0.000000001202 */
|
||||
MAD_F(0x000a1451), /* 0.002460783301 => 0.002460781485, e 0.000000001816 */
|
||||
MAD_F(0x00080000), /* 0.001953125000 => 0.001953125000, e 0.000000000000 */
|
||||
MAD_F(0x00065980), /* 0.001550196340 => 0.001550197601, e -0.000000001262 */
|
||||
|
||||
MAD_F(0x00050a29), /* 0.001230391650 => 0.001230392605, e -0.000000000955 */
|
||||
MAD_F(0x00040000), /* 0.000976562500 => 0.000976562500, e 0.000000000000 */
|
||||
MAD_F(0x00032cc0), /* 0.000775098170 => 0.000775098801, e -0.000000000631 */
|
||||
MAD_F(0x00028514), /* 0.000615195825 => 0.000615194440, e 0.000000001385 */
|
||||
MAD_F(0x00020000), /* 0.000488281250 => 0.000488281250, e 0.000000000000 */
|
||||
MAD_F(0x00019660), /* 0.000387549085 => 0.000387549400, e -0.000000000315 */
|
||||
MAD_F(0x0001428a), /* 0.000307597913 => 0.000307597220, e 0.000000000693 */
|
||||
MAD_F(0x00010000), /* 0.000244140625 => 0.000244140625, e 0.000000000000 */
|
||||
|
||||
MAD_F(0x0000cb30), /* 0.000193774542 => 0.000193774700, e -0.000000000158 */
|
||||
MAD_F(0x0000a145), /* 0.000153798956 => 0.000153798610, e 0.000000000346 */
|
||||
MAD_F(0x00008000), /* 0.000122070313 => 0.000122070313, e 0.000000000000 */
|
||||
MAD_F(0x00006598), /* 0.000096887271 => 0.000096887350, e -0.000000000079 */
|
||||
MAD_F(0x000050a3), /* 0.000076899478 => 0.000076901168, e -0.000000001689 */
|
||||
MAD_F(0x00004000), /* 0.000061035156 => 0.000061035156, e 0.000000000000 */
|
||||
MAD_F(0x000032cc), /* 0.000048443636 => 0.000048443675, e -0.000000000039 */
|
||||
MAD_F(0x00002851), /* 0.000038449739 => 0.000038448721, e 0.000000001018 */
|
||||
|
||||
MAD_F(0x00002000), /* 0.000030517578 => 0.000030517578, e 0.000000000000 */
|
||||
MAD_F(0x00001966), /* 0.000024221818 => 0.000024221838, e -0.000000000020 */
|
||||
MAD_F(0x00001429), /* 0.000019224870 => 0.000019226223, e -0.000000001354 */
|
||||
MAD_F(0x00001000), /* 0.000015258789 => 0.000015258789, e -0.000000000000 */
|
||||
MAD_F(0x00000cb3), /* 0.000012110909 => 0.000012110919, e -0.000000000010 */
|
||||
MAD_F(0x00000a14), /* 0.000009612435 => 0.000009611249, e 0.000000001186 */
|
||||
MAD_F(0x00000800), /* 0.000007629395 => 0.000007629395, e -0.000000000000 */
|
||||
MAD_F(0x00000659), /* 0.000006055454 => 0.000006053597, e 0.000000001858 */
|
||||
|
||||
MAD_F(0x0000050a), /* 0.000004806217 => 0.000004805624, e 0.000000000593 */
|
||||
MAD_F(0x00000400), /* 0.000003814697 => 0.000003814697, e 0.000000000000 */
|
||||
MAD_F(0x0000032d), /* 0.000003027727 => 0.000003028661, e -0.000000000934 */
|
||||
MAD_F(0x00000285), /* 0.000002403109 => 0.000002402812, e 0.000000000296 */
|
||||
MAD_F(0x00000200), /* 0.000001907349 => 0.000001907349, e -0.000000000000 */
|
||||
MAD_F(0x00000196), /* 0.000001513864 => 0.000001512468, e 0.000000001396 */
|
||||
MAD_F(0x00000143), /* 0.000001201554 => 0.000001203269, e -0.000000001714 */
|
||||
MAD_F(0x00000000) /* this compatibility entry is not part of Table B.1 */
|
159
libmad/stream.c
Normal file
159
libmad/stream.c
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: stream.c,v 1.12 2004/02/05 09:02:39 rob Exp $
|
||||
*/
|
||||
|
||||
# include "libmad_config.h"
|
||||
|
||||
# include "libmad_global.h"
|
||||
|
||||
# include <stdlib.h>
|
||||
|
||||
# include "bit.h"
|
||||
# include "stream.h"
|
||||
|
||||
/*
|
||||
* NAME: stream->init()
|
||||
* DESCRIPTION: initialize stream struct
|
||||
*/
|
||||
void mad_stream_init(struct mad_stream *stream)
|
||||
{
|
||||
stream->buffer = 0;
|
||||
stream->bufend = 0;
|
||||
stream->skiplen = 0;
|
||||
|
||||
stream->sync = 0;
|
||||
stream->freerate = 0;
|
||||
|
||||
stream->this_frame = 0;
|
||||
stream->next_frame = 0;
|
||||
mad_bit_init(&stream->ptr, 0);
|
||||
|
||||
mad_bit_init(&stream->anc_ptr, 0);
|
||||
stream->anc_bitlen = 0;
|
||||
|
||||
stream->main_data = 0;
|
||||
stream->md_len = 0;
|
||||
|
||||
stream->options = 0;
|
||||
stream->error = MAD_ERROR_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: stream->finish()
|
||||
* DESCRIPTION: deallocate any dynamic memory associated with stream
|
||||
*/
|
||||
void mad_stream_finish(struct mad_stream *stream)
|
||||
{
|
||||
if (stream->main_data) {
|
||||
free(stream->main_data);
|
||||
stream->main_data = 0;
|
||||
}
|
||||
|
||||
mad_bit_finish(&stream->anc_ptr);
|
||||
mad_bit_finish(&stream->ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: stream->buffer()
|
||||
* DESCRIPTION: set stream buffer pointers
|
||||
*/
|
||||
void mad_stream_buffer(struct mad_stream *stream,
|
||||
unsigned char const *buffer, unsigned long length)
|
||||
{
|
||||
stream->buffer = buffer;
|
||||
stream->bufend = buffer + length;
|
||||
|
||||
stream->this_frame = buffer;
|
||||
stream->next_frame = buffer;
|
||||
|
||||
stream->sync = 1;
|
||||
|
||||
mad_bit_init(&stream->ptr, buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: stream->skip()
|
||||
* DESCRIPTION: arrange to skip bytes before the next frame
|
||||
*/
|
||||
void mad_stream_skip(struct mad_stream *stream, unsigned long length)
|
||||
{
|
||||
stream->skiplen += length;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: stream->sync()
|
||||
* DESCRIPTION: locate the next stream sync word
|
||||
*/
|
||||
int mad_stream_sync(struct mad_stream *stream)
|
||||
{
|
||||
register unsigned char const *ptr, *end;
|
||||
|
||||
ptr = mad_bit_nextbyte(&stream->ptr);
|
||||
end = stream->bufend;
|
||||
|
||||
while (ptr < end - 1 &&
|
||||
!(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0))
|
||||
++ptr;
|
||||
|
||||
if (end - ptr < MAD_BUFFER_GUARD)
|
||||
return -1;
|
||||
|
||||
mad_bit_init(&stream->ptr, ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: stream->errorstr()
|
||||
* DESCRIPTION: return a string description of the current error condition
|
||||
*/
|
||||
char const *mad_stream_errorstr(struct mad_stream const *stream)
|
||||
{
|
||||
switch (stream->error) {
|
||||
case MAD_ERROR_NONE: return "no error";
|
||||
|
||||
case MAD_ERROR_BUFLEN: return "input buffer too small (or EOF)";
|
||||
case MAD_ERROR_BUFPTR: return "invalid (null) buffer pointer";
|
||||
|
||||
case MAD_ERROR_NOMEM: return "not enough memory";
|
||||
|
||||
case MAD_ERROR_LOSTSYNC: return "lost synchronization";
|
||||
case MAD_ERROR_BADLAYER: return "reserved header layer value";
|
||||
case MAD_ERROR_BADBITRATE: return "forbidden bitrate value";
|
||||
case MAD_ERROR_BADSAMPLERATE: return "reserved sample frequency value";
|
||||
case MAD_ERROR_BADEMPHASIS: return "reserved emphasis value";
|
||||
|
||||
case MAD_ERROR_BADCRC: return "CRC check failed";
|
||||
case MAD_ERROR_BADBITALLOC: return "forbidden bit allocation value";
|
||||
case MAD_ERROR_BADSCALEFACTOR: return "bad scalefactor index";
|
||||
case MAD_ERROR_BADMODE: return "bad bitrate/mode combination";
|
||||
case MAD_ERROR_BADFRAMELEN: return "bad frame length";
|
||||
case MAD_ERROR_BADBIGVALUES: return "bad big_values count";
|
||||
case MAD_ERROR_BADBLOCKTYPE: return "reserved block_type";
|
||||
case MAD_ERROR_BADSCFSI: return "bad scalefactor selection info";
|
||||
case MAD_ERROR_BADDATAPTR: return "bad main_data_begin pointer";
|
||||
case MAD_ERROR_BADPART3LEN: return "bad audio data length";
|
||||
case MAD_ERROR_BADHUFFTABLE: return "bad Huffman table select";
|
||||
case MAD_ERROR_BADHUFFDATA: return "Huffman data overrun";
|
||||
case MAD_ERROR_BADSTEREO: return "incompatible block_type for JS";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
108
libmad/stream.h
Normal file
108
libmad/stream.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: stream.h,v 1.20 2004/02/05 09:02:39 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_STREAM_H
|
||||
# define LIBMAD_STREAM_H
|
||||
|
||||
# include "bit.h"
|
||||
|
||||
# define MAD_BUFFER_GUARD 8
|
||||
# define MAD_BUFFER_MDLEN (511 + 2048 + MAD_BUFFER_GUARD)
|
||||
|
||||
enum mad_error {
|
||||
MAD_ERROR_NONE = 0x0000, /* no error */
|
||||
|
||||
MAD_ERROR_BUFLEN = 0x0001, /* input buffer too small (or EOF) */
|
||||
MAD_ERROR_BUFPTR = 0x0002, /* invalid (null) buffer pointer */
|
||||
|
||||
MAD_ERROR_NOMEM = 0x0031, /* not enough memory */
|
||||
|
||||
MAD_ERROR_LOSTSYNC = 0x0101, /* lost synchronization */
|
||||
MAD_ERROR_BADLAYER = 0x0102, /* reserved header layer value */
|
||||
MAD_ERROR_BADBITRATE = 0x0103, /* forbidden bitrate value */
|
||||
MAD_ERROR_BADSAMPLERATE = 0x0104, /* reserved sample frequency value */
|
||||
MAD_ERROR_BADEMPHASIS = 0x0105, /* reserved emphasis value */
|
||||
|
||||
MAD_ERROR_BADCRC = 0x0201, /* CRC check failed */
|
||||
MAD_ERROR_BADBITALLOC = 0x0211, /* forbidden bit allocation value */
|
||||
MAD_ERROR_BADSCALEFACTOR = 0x0221, /* bad scalefactor index */
|
||||
MAD_ERROR_BADMODE = 0x0222, /* bad bitrate/mode combination */
|
||||
MAD_ERROR_BADFRAMELEN = 0x0231, /* bad frame length */
|
||||
MAD_ERROR_BADBIGVALUES = 0x0232, /* bad big_values count */
|
||||
MAD_ERROR_BADBLOCKTYPE = 0x0233, /* reserved block_type */
|
||||
MAD_ERROR_BADSCFSI = 0x0234, /* bad scalefactor selection info */
|
||||
MAD_ERROR_BADDATAPTR = 0x0235, /* bad main_data_begin pointer */
|
||||
MAD_ERROR_BADPART3LEN = 0x0236, /* bad audio data length */
|
||||
MAD_ERROR_BADHUFFTABLE = 0x0237, /* bad Huffman table select */
|
||||
MAD_ERROR_BADHUFFDATA = 0x0238, /* Huffman data overrun */
|
||||
MAD_ERROR_BADSTEREO = 0x0239 /* incompatible block_type for JS */
|
||||
};
|
||||
|
||||
# define MAD_RECOVERABLE(error) ((error) & 0xff00)
|
||||
|
||||
struct mad_stream {
|
||||
unsigned char const *buffer; /* input bitstream buffer */
|
||||
unsigned char const *bufend; /* end of buffer */
|
||||
unsigned long skiplen; /* bytes to skip before next frame */
|
||||
|
||||
int sync; /* stream sync found */
|
||||
unsigned long freerate; /* free bitrate (fixed) */
|
||||
|
||||
unsigned char const *this_frame; /* start of current frame */
|
||||
unsigned char const *next_frame; /* start of next frame */
|
||||
struct mad_bitptr ptr; /* current processing bit pointer */
|
||||
|
||||
struct mad_bitptr anc_ptr; /* ancillary bits pointer */
|
||||
unsigned int anc_bitlen; /* number of ancillary bits */
|
||||
|
||||
unsigned char (*main_data)[MAD_BUFFER_MDLEN];
|
||||
/* Layer III main_data() */
|
||||
unsigned int md_len; /* bytes in main_data */
|
||||
|
||||
int options; /* decoding options (see below) */
|
||||
enum mad_error error; /* error code (see above) */
|
||||
};
|
||||
|
||||
enum {
|
||||
MAD_OPTION_IGNORECRC = 0x0001, /* ignore CRC errors */
|
||||
MAD_OPTION_HALFSAMPLERATE = 0x0002 /* generate PCM at 1/2 sample rate */
|
||||
# if 0 /* not yet implemented */
|
||||
MAD_OPTION_LEFTCHANNEL = 0x0010, /* decode left channel only */
|
||||
MAD_OPTION_RIGHTCHANNEL = 0x0020, /* decode right channel only */
|
||||
MAD_OPTION_SINGLECHANNEL = 0x0030 /* combine channels */
|
||||
# endif
|
||||
};
|
||||
|
||||
void mad_stream_init(struct mad_stream *);
|
||||
void mad_stream_finish(struct mad_stream *);
|
||||
|
||||
# define mad_stream_options(stream, opts) \
|
||||
((void) ((stream)->options = (opts)))
|
||||
|
||||
void mad_stream_buffer(struct mad_stream *,
|
||||
unsigned char const *, unsigned long);
|
||||
void mad_stream_skip(struct mad_stream *, unsigned long);
|
||||
|
||||
int mad_stream_sync(struct mad_stream *);
|
||||
|
||||
char const *mad_stream_errorstr(struct mad_stream const *);
|
||||
|
||||
# endif
|
855
libmad/synth.c
Normal file
855
libmad/synth.c
Normal file
@ -0,0 +1,855 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: synth.c,v 1.25 2004/01/23 09:41:33 rob Exp $
|
||||
*/
|
||||
|
||||
# include "libmad_config.h"
|
||||
|
||||
# include "libmad_global.h"
|
||||
|
||||
# include "fixed.h"
|
||||
# include "frame.h"
|
||||
# include "synth.h"
|
||||
|
||||
/*
|
||||
* NAME: synth->init()
|
||||
* DESCRIPTION: initialize synth struct
|
||||
*/
|
||||
void mad_synth_init(struct mad_synth *synth)
|
||||
{
|
||||
mad_synth_mute(synth);
|
||||
|
||||
synth->phase = 0;
|
||||
|
||||
synth->pcm.samplerate = 0;
|
||||
synth->pcm.channels = 0;
|
||||
synth->pcm.length = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: synth->mute()
|
||||
* DESCRIPTION: zero all polyphase filterbank values, resetting synthesis
|
||||
*/
|
||||
void mad_synth_mute(struct mad_synth *synth)
|
||||
{
|
||||
unsigned int ch, s, v;
|
||||
|
||||
for (ch = 0; ch < 2; ++ch) {
|
||||
for (s = 0; s < 16; ++s) {
|
||||
for (v = 0; v < 8; ++v) {
|
||||
synth->filter[ch][0][0][s][v] = synth->filter[ch][0][1][s][v] =
|
||||
synth->filter[ch][1][0][s][v] = synth->filter[ch][1][1][s][v] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An optional optimization called here the Subband Synthesis Optimization
|
||||
* (SSO) improves the performance of subband synthesis at the expense of
|
||||
* accuracy.
|
||||
*
|
||||
* The idea is to simplify 32x32->64-bit multiplication to 32x32->32 such
|
||||
* that extra scaling and rounding are not necessary. This often allows the
|
||||
* compiler to use faster 32-bit multiply-accumulate instructions instead of
|
||||
* explicit 64-bit multiply, shift, and add instructions.
|
||||
*
|
||||
* SSO works like this: a full 32x32->64-bit multiply of two mad_fixed_t
|
||||
* values requires the result to be right-shifted 28 bits to be properly
|
||||
* scaled to the same fixed-point format. Right shifts can be applied at any
|
||||
* time to either operand or to the result, so the optimization involves
|
||||
* careful placement of these shifts to minimize the loss of accuracy.
|
||||
*
|
||||
* First, a 14-bit shift is applied with rounding at compile-time to the D[]
|
||||
* table of coefficients for the subband synthesis window. This only loses 2
|
||||
* bits of accuracy because the lower 12 bits are always zero. A second
|
||||
* 12-bit shift occurs after the DCT calculation. This loses 12 bits of
|
||||
* accuracy. Finally, a third 2-bit shift occurs just before the sample is
|
||||
* saved in the PCM buffer. 14 + 12 + 2 == 28 bits.
|
||||
*/
|
||||
|
||||
/* FPM_DEFAULT without OPT_SSO will actually lose accuracy and performance */
|
||||
|
||||
# if defined(FPM_DEFAULT) && !defined(OPT_SSO)
|
||||
# define OPT_SSO
|
||||
# endif
|
||||
|
||||
/* second SSO shift, with rounding */
|
||||
|
||||
# if defined(OPT_SSO)
|
||||
# define SHIFT(x) (((x) + (1L << 11)) >> 12)
|
||||
# else
|
||||
# define SHIFT(x) (x)
|
||||
# endif
|
||||
|
||||
/* possible DCT speed optimization */
|
||||
|
||||
# if defined(OPT_SPEED) && defined(MAD_F_MLX)
|
||||
# define OPT_DCTO
|
||||
# define MUL(x, y) \
|
||||
({ mad_fixed64hi_t hi; \
|
||||
mad_fixed64lo_t lo; \
|
||||
MAD_F_MLX(hi, lo, (x), (y)); \
|
||||
hi << (32 - MAD_F_SCALEBITS - 3); \
|
||||
})
|
||||
# else
|
||||
# undef OPT_DCTO
|
||||
# define MUL(x, y) mad_f_mul((x), (y))
|
||||
# endif
|
||||
|
||||
/*
|
||||
* NAME: dct32()
|
||||
* DESCRIPTION: perform fast in[32]->out[32] DCT
|
||||
*/
|
||||
static
|
||||
void dct32(mad_fixed_t const in[32], unsigned int slot,
|
||||
mad_fixed_t lo[16][8], mad_fixed_t hi[16][8])
|
||||
{
|
||||
mad_fixed_t t0, t1, t2, t3, t4, t5, t6, t7;
|
||||
mad_fixed_t t8, t9, t10, t11, t12, t13, t14, t15;
|
||||
mad_fixed_t t16, t17, t18, t19, t20, t21, t22, t23;
|
||||
mad_fixed_t t24, t25, t26, t27, t28, t29, t30, t31;
|
||||
mad_fixed_t t32, t33, t34, t35, t36, t37, t38, t39;
|
||||
mad_fixed_t t40, t41, t42, t43, t44, t45, t46, t47;
|
||||
mad_fixed_t t48, t49, t50, t51, t52, t53, t54, t55;
|
||||
mad_fixed_t t56, t57, t58, t59, t60, t61, t62, t63;
|
||||
mad_fixed_t t64, t65, t66, t67, t68, t69, t70, t71;
|
||||
mad_fixed_t t72, t73, t74, t75, t76, t77, t78, t79;
|
||||
mad_fixed_t t80, t81, t82, t83, t84, t85, t86, t87;
|
||||
mad_fixed_t t88, t89, t90, t91, t92, t93, t94, t95;
|
||||
mad_fixed_t t96, t97, t98, t99, t100, t101, t102, t103;
|
||||
mad_fixed_t t104, t105, t106, t107, t108, t109, t110, t111;
|
||||
mad_fixed_t t112, t113, t114, t115, t116, t117, t118, t119;
|
||||
mad_fixed_t t120, t121, t122, t123, t124, t125, t126, t127;
|
||||
mad_fixed_t t128, t129, t130, t131, t132, t133, t134, t135;
|
||||
mad_fixed_t t136, t137, t138, t139, t140, t141, t142, t143;
|
||||
mad_fixed_t t144, t145, t146, t147, t148, t149, t150, t151;
|
||||
mad_fixed_t t152, t153, t154, t155, t156, t157, t158, t159;
|
||||
mad_fixed_t t160, t161, t162, t163, t164, t165, t166, t167;
|
||||
mad_fixed_t t168, t169, t170, t171, t172, t173, t174, t175;
|
||||
mad_fixed_t t176;
|
||||
|
||||
/* costab[i] = cos(PI / (2 * 32) * i) */
|
||||
|
||||
# if defined(OPT_DCTO)
|
||||
# define costab1 MAD_F(0x7fd8878e)
|
||||
# define costab2 MAD_F(0x7f62368f)
|
||||
# define costab3 MAD_F(0x7e9d55fc)
|
||||
# define costab4 MAD_F(0x7d8a5f40)
|
||||
# define costab5 MAD_F(0x7c29fbee)
|
||||
# define costab6 MAD_F(0x7a7d055b)
|
||||
# define costab7 MAD_F(0x78848414)
|
||||
# define costab8 MAD_F(0x7641af3d)
|
||||
# define costab9 MAD_F(0x73b5ebd1)
|
||||
# define costab10 MAD_F(0x70e2cbc6)
|
||||
# define costab11 MAD_F(0x6dca0d14)
|
||||
# define costab12 MAD_F(0x6a6d98a4)
|
||||
# define costab13 MAD_F(0x66cf8120)
|
||||
# define costab14 MAD_F(0x62f201ac)
|
||||
# define costab15 MAD_F(0x5ed77c8a)
|
||||
# define costab16 MAD_F(0x5a82799a)
|
||||
# define costab17 MAD_F(0x55f5a4d2)
|
||||
# define costab18 MAD_F(0x5133cc94)
|
||||
# define costab19 MAD_F(0x4c3fdff4)
|
||||
# define costab20 MAD_F(0x471cece7)
|
||||
# define costab21 MAD_F(0x41ce1e65)
|
||||
# define costab22 MAD_F(0x3c56ba70)
|
||||
# define costab23 MAD_F(0x36ba2014)
|
||||
# define costab24 MAD_F(0x30fbc54d)
|
||||
# define costab25 MAD_F(0x2b1f34eb)
|
||||
# define costab26 MAD_F(0x25280c5e)
|
||||
# define costab27 MAD_F(0x1f19f97b)
|
||||
# define costab28 MAD_F(0x18f8b83c)
|
||||
# define costab29 MAD_F(0x12c8106f)
|
||||
# define costab30 MAD_F(0x0c8bd35e)
|
||||
# define costab31 MAD_F(0x0647d97c)
|
||||
# else
|
||||
# define costab1 MAD_F(0x0ffb10f2) /* 0.998795456 */
|
||||
# define costab2 MAD_F(0x0fec46d2) /* 0.995184727 */
|
||||
# define costab3 MAD_F(0x0fd3aac0) /* 0.989176510 */
|
||||
# define costab4 MAD_F(0x0fb14be8) /* 0.980785280 */
|
||||
# define costab5 MAD_F(0x0f853f7e) /* 0.970031253 */
|
||||
# define costab6 MAD_F(0x0f4fa0ab) /* 0.956940336 */
|
||||
# define costab7 MAD_F(0x0f109082) /* 0.941544065 */
|
||||
# define costab8 MAD_F(0x0ec835e8) /* 0.923879533 */
|
||||
# define costab9 MAD_F(0x0e76bd7a) /* 0.903989293 */
|
||||
# define costab10 MAD_F(0x0e1c5979) /* 0.881921264 */
|
||||
# define costab11 MAD_F(0x0db941a3) /* 0.857728610 */
|
||||
# define costab12 MAD_F(0x0d4db315) /* 0.831469612 */
|
||||
# define costab13 MAD_F(0x0cd9f024) /* 0.803207531 */
|
||||
# define costab14 MAD_F(0x0c5e4036) /* 0.773010453 */
|
||||
# define costab15 MAD_F(0x0bdaef91) /* 0.740951125 */
|
||||
# define costab16 MAD_F(0x0b504f33) /* 0.707106781 */
|
||||
# define costab17 MAD_F(0x0abeb49a) /* 0.671558955 */
|
||||
# define costab18 MAD_F(0x0a267993) /* 0.634393284 */
|
||||
# define costab19 MAD_F(0x0987fbfe) /* 0.595699304 */
|
||||
# define costab20 MAD_F(0x08e39d9d) /* 0.555570233 */
|
||||
# define costab21 MAD_F(0x0839c3cd) /* 0.514102744 */
|
||||
# define costab22 MAD_F(0x078ad74e) /* 0.471396737 */
|
||||
# define costab23 MAD_F(0x06d74402) /* 0.427555093 */
|
||||
# define costab24 MAD_F(0x061f78aa) /* 0.382683432 */
|
||||
# define costab25 MAD_F(0x0563e69d) /* 0.336889853 */
|
||||
# define costab26 MAD_F(0x04a5018c) /* 0.290284677 */
|
||||
# define costab27 MAD_F(0x03e33f2f) /* 0.242980180 */
|
||||
# define costab28 MAD_F(0x031f1708) /* 0.195090322 */
|
||||
# define costab29 MAD_F(0x0259020e) /* 0.146730474 */
|
||||
# define costab30 MAD_F(0x01917a6c) /* 0.098017140 */
|
||||
# define costab31 MAD_F(0x00c8fb30) /* 0.049067674 */
|
||||
# endif
|
||||
|
||||
t0 = in[0] + in[31]; t16 = MUL(in[0] - in[31], costab1);
|
||||
t1 = in[15] + in[16]; t17 = MUL(in[15] - in[16], costab31);
|
||||
|
||||
t41 = t16 + t17;
|
||||
t59 = MUL(t16 - t17, costab2);
|
||||
t33 = t0 + t1;
|
||||
t50 = MUL(t0 - t1, costab2);
|
||||
|
||||
t2 = in[7] + in[24]; t18 = MUL(in[7] - in[24], costab15);
|
||||
t3 = in[8] + in[23]; t19 = MUL(in[8] - in[23], costab17);
|
||||
|
||||
t42 = t18 + t19;
|
||||
t60 = MUL(t18 - t19, costab30);
|
||||
t34 = t2 + t3;
|
||||
t51 = MUL(t2 - t3, costab30);
|
||||
|
||||
t4 = in[3] + in[28]; t20 = MUL(in[3] - in[28], costab7);
|
||||
t5 = in[12] + in[19]; t21 = MUL(in[12] - in[19], costab25);
|
||||
|
||||
t43 = t20 + t21;
|
||||
t61 = MUL(t20 - t21, costab14);
|
||||
t35 = t4 + t5;
|
||||
t52 = MUL(t4 - t5, costab14);
|
||||
|
||||
t6 = in[4] + in[27]; t22 = MUL(in[4] - in[27], costab9);
|
||||
t7 = in[11] + in[20]; t23 = MUL(in[11] - in[20], costab23);
|
||||
|
||||
t44 = t22 + t23;
|
||||
t62 = MUL(t22 - t23, costab18);
|
||||
t36 = t6 + t7;
|
||||
t53 = MUL(t6 - t7, costab18);
|
||||
|
||||
t8 = in[1] + in[30]; t24 = MUL(in[1] - in[30], costab3);
|
||||
t9 = in[14] + in[17]; t25 = MUL(in[14] - in[17], costab29);
|
||||
|
||||
t45 = t24 + t25;
|
||||
t63 = MUL(t24 - t25, costab6);
|
||||
t37 = t8 + t9;
|
||||
t54 = MUL(t8 - t9, costab6);
|
||||
|
||||
t10 = in[6] + in[25]; t26 = MUL(in[6] - in[25], costab13);
|
||||
t11 = in[9] + in[22]; t27 = MUL(in[9] - in[22], costab19);
|
||||
|
||||
t46 = t26 + t27;
|
||||
t64 = MUL(t26 - t27, costab26);
|
||||
t38 = t10 + t11;
|
||||
t55 = MUL(t10 - t11, costab26);
|
||||
|
||||
t12 = in[2] + in[29]; t28 = MUL(in[2] - in[29], costab5);
|
||||
t13 = in[13] + in[18]; t29 = MUL(in[13] - in[18], costab27);
|
||||
|
||||
t47 = t28 + t29;
|
||||
t65 = MUL(t28 - t29, costab10);
|
||||
t39 = t12 + t13;
|
||||
t56 = MUL(t12 - t13, costab10);
|
||||
|
||||
t14 = in[5] + in[26]; t30 = MUL(in[5] - in[26], costab11);
|
||||
t15 = in[10] + in[21]; t31 = MUL(in[10] - in[21], costab21);
|
||||
|
||||
t48 = t30 + t31;
|
||||
t66 = MUL(t30 - t31, costab22);
|
||||
t40 = t14 + t15;
|
||||
t57 = MUL(t14 - t15, costab22);
|
||||
|
||||
t69 = t33 + t34; t89 = MUL(t33 - t34, costab4);
|
||||
t70 = t35 + t36; t90 = MUL(t35 - t36, costab28);
|
||||
t71 = t37 + t38; t91 = MUL(t37 - t38, costab12);
|
||||
t72 = t39 + t40; t92 = MUL(t39 - t40, costab20);
|
||||
t73 = t41 + t42; t94 = MUL(t41 - t42, costab4);
|
||||
t74 = t43 + t44; t95 = MUL(t43 - t44, costab28);
|
||||
t75 = t45 + t46; t96 = MUL(t45 - t46, costab12);
|
||||
t76 = t47 + t48; t97 = MUL(t47 - t48, costab20);
|
||||
|
||||
t78 = t50 + t51; t100 = MUL(t50 - t51, costab4);
|
||||
t79 = t52 + t53; t101 = MUL(t52 - t53, costab28);
|
||||
t80 = t54 + t55; t102 = MUL(t54 - t55, costab12);
|
||||
t81 = t56 + t57; t103 = MUL(t56 - t57, costab20);
|
||||
|
||||
t83 = t59 + t60; t106 = MUL(t59 - t60, costab4);
|
||||
t84 = t61 + t62; t107 = MUL(t61 - t62, costab28);
|
||||
t85 = t63 + t64; t108 = MUL(t63 - t64, costab12);
|
||||
t86 = t65 + t66; t109 = MUL(t65 - t66, costab20);
|
||||
|
||||
t113 = t69 + t70;
|
||||
t114 = t71 + t72;
|
||||
|
||||
/* 0 */ hi[15][slot] = SHIFT(t113 + t114);
|
||||
/* 16 */ lo[ 0][slot] = SHIFT(MUL(t113 - t114, costab16));
|
||||
|
||||
t115 = t73 + t74;
|
||||
t116 = t75 + t76;
|
||||
|
||||
t32 = t115 + t116;
|
||||
|
||||
/* 1 */ hi[14][slot] = SHIFT(t32);
|
||||
|
||||
t118 = t78 + t79;
|
||||
t119 = t80 + t81;
|
||||
|
||||
t58 = t118 + t119;
|
||||
|
||||
/* 2 */ hi[13][slot] = SHIFT(t58);
|
||||
|
||||
t121 = t83 + t84;
|
||||
t122 = t85 + t86;
|
||||
|
||||
t67 = t121 + t122;
|
||||
|
||||
t49 = (t67 * 2) - t32;
|
||||
|
||||
/* 3 */ hi[12][slot] = SHIFT(t49);
|
||||
|
||||
t125 = t89 + t90;
|
||||
t126 = t91 + t92;
|
||||
|
||||
t93 = t125 + t126;
|
||||
|
||||
/* 4 */ hi[11][slot] = SHIFT(t93);
|
||||
|
||||
t128 = t94 + t95;
|
||||
t129 = t96 + t97;
|
||||
|
||||
t98 = t128 + t129;
|
||||
|
||||
t68 = (t98 * 2) - t49;
|
||||
|
||||
/* 5 */ hi[10][slot] = SHIFT(t68);
|
||||
|
||||
t132 = t100 + t101;
|
||||
t133 = t102 + t103;
|
||||
|
||||
t104 = t132 + t133;
|
||||
|
||||
t82 = (t104 * 2) - t58;
|
||||
|
||||
/* 6 */ hi[ 9][slot] = SHIFT(t82);
|
||||
|
||||
t136 = t106 + t107;
|
||||
t137 = t108 + t109;
|
||||
|
||||
t110 = t136 + t137;
|
||||
|
||||
t87 = (t110 * 2) - t67;
|
||||
|
||||
t77 = (t87 * 2) - t68;
|
||||
|
||||
/* 7 */ hi[ 8][slot] = SHIFT(t77);
|
||||
|
||||
t141 = MUL(t69 - t70, costab8);
|
||||
t142 = MUL(t71 - t72, costab24);
|
||||
t143 = t141 + t142;
|
||||
|
||||
/* 8 */ hi[ 7][slot] = SHIFT(t143);
|
||||
/* 24 */ lo[ 8][slot] =
|
||||
SHIFT((MUL(t141 - t142, costab16) * 2) - t143);
|
||||
|
||||
t144 = MUL(t73 - t74, costab8);
|
||||
t145 = MUL(t75 - t76, costab24);
|
||||
t146 = t144 + t145;
|
||||
|
||||
t88 = (t146 * 2) - t77;
|
||||
|
||||
/* 9 */ hi[ 6][slot] = SHIFT(t88);
|
||||
|
||||
t148 = MUL(t78 - t79, costab8);
|
||||
t149 = MUL(t80 - t81, costab24);
|
||||
t150 = t148 + t149;
|
||||
|
||||
t105 = (t150 * 2) - t82;
|
||||
|
||||
/* 10 */ hi[ 5][slot] = SHIFT(t105);
|
||||
|
||||
t152 = MUL(t83 - t84, costab8);
|
||||
t153 = MUL(t85 - t86, costab24);
|
||||
t154 = t152 + t153;
|
||||
|
||||
t111 = (t154 * 2) - t87;
|
||||
|
||||
t99 = (t111 * 2) - t88;
|
||||
|
||||
/* 11 */ hi[ 4][slot] = SHIFT(t99);
|
||||
|
||||
t157 = MUL(t89 - t90, costab8);
|
||||
t158 = MUL(t91 - t92, costab24);
|
||||
t159 = t157 + t158;
|
||||
|
||||
t127 = (t159 * 2) - t93;
|
||||
|
||||
/* 12 */ hi[ 3][slot] = SHIFT(t127);
|
||||
|
||||
t160 = (MUL(t125 - t126, costab16) * 2) - t127;
|
||||
|
||||
/* 20 */ lo[ 4][slot] = SHIFT(t160);
|
||||
/* 28 */ lo[12][slot] =
|
||||
SHIFT((((MUL(t157 - t158, costab16) * 2) - t159) * 2) - t160);
|
||||
|
||||
t161 = MUL(t94 - t95, costab8);
|
||||
t162 = MUL(t96 - t97, costab24);
|
||||
t163 = t161 + t162;
|
||||
|
||||
t130 = (t163 * 2) - t98;
|
||||
|
||||
t112 = (t130 * 2) - t99;
|
||||
|
||||
/* 13 */ hi[ 2][slot] = SHIFT(t112);
|
||||
|
||||
t164 = (MUL(t128 - t129, costab16) * 2) - t130;
|
||||
|
||||
t166 = MUL(t100 - t101, costab8);
|
||||
t167 = MUL(t102 - t103, costab24);
|
||||
t168 = t166 + t167;
|
||||
|
||||
t134 = (t168 * 2) - t104;
|
||||
|
||||
t120 = (t134 * 2) - t105;
|
||||
|
||||
/* 14 */ hi[ 1][slot] = SHIFT(t120);
|
||||
|
||||
t135 = (MUL(t118 - t119, costab16) * 2) - t120;
|
||||
|
||||
/* 18 */ lo[ 2][slot] = SHIFT(t135);
|
||||
|
||||
t169 = (MUL(t132 - t133, costab16) * 2) - t134;
|
||||
|
||||
t151 = (t169 * 2) - t135;
|
||||
|
||||
/* 22 */ lo[ 6][slot] = SHIFT(t151);
|
||||
|
||||
t170 = (((MUL(t148 - t149, costab16) * 2) - t150) * 2) - t151;
|
||||
|
||||
/* 26 */ lo[10][slot] = SHIFT(t170);
|
||||
/* 30 */ lo[14][slot] =
|
||||
SHIFT((((((MUL(t166 - t167, costab16) * 2) -
|
||||
t168) * 2) - t169) * 2) - t170);
|
||||
|
||||
t171 = MUL(t106 - t107, costab8);
|
||||
t172 = MUL(t108 - t109, costab24);
|
||||
t173 = t171 + t172;
|
||||
|
||||
t138 = (t173 * 2) - t110;
|
||||
|
||||
t123 = (t138 * 2) - t111;
|
||||
|
||||
t139 = (MUL(t121 - t122, costab16) * 2) - t123;
|
||||
|
||||
t117 = (t123 * 2) - t112;
|
||||
|
||||
/* 15 */ hi[ 0][slot] = SHIFT(t117);
|
||||
|
||||
t124 = (MUL(t115 - t116, costab16) * 2) - t117;
|
||||
|
||||
/* 17 */ lo[ 1][slot] = SHIFT(t124);
|
||||
|
||||
t131 = (t139 * 2) - t124;
|
||||
|
||||
/* 19 */ lo[ 3][slot] = SHIFT(t131);
|
||||
|
||||
t140 = (t164 * 2) - t131;
|
||||
|
||||
/* 21 */ lo[ 5][slot] = SHIFT(t140);
|
||||
|
||||
t174 = (MUL(t136 - t137, costab16) * 2) - t138;
|
||||
|
||||
t155 = (t174 * 2) - t139;
|
||||
|
||||
t147 = (t155 * 2) - t140;
|
||||
|
||||
/* 23 */ lo[ 7][slot] = SHIFT(t147);
|
||||
|
||||
t156 = (((MUL(t144 - t145, costab16) * 2) - t146) * 2) - t147;
|
||||
|
||||
/* 25 */ lo[ 9][slot] = SHIFT(t156);
|
||||
|
||||
t175 = (((MUL(t152 - t153, costab16) * 2) - t154) * 2) - t155;
|
||||
|
||||
t165 = (t175 * 2) - t156;
|
||||
|
||||
/* 27 */ lo[11][slot] = SHIFT(t165);
|
||||
|
||||
t176 = (((((MUL(t161 - t162, costab16) * 2) -
|
||||
t163) * 2) - t164) * 2) - t165;
|
||||
|
||||
/* 29 */ lo[13][slot] = SHIFT(t176);
|
||||
/* 31 */ lo[15][slot] =
|
||||
SHIFT((((((((MUL(t171 - t172, costab16) * 2) -
|
||||
t173) * 2) - t174) * 2) - t175) * 2) - t176);
|
||||
|
||||
/*
|
||||
* Totals:
|
||||
* 80 multiplies
|
||||
* 80 additions
|
||||
* 119 subtractions
|
||||
* 49 shifts (not counting SSO)
|
||||
*/
|
||||
}
|
||||
|
||||
# undef MUL
|
||||
# undef SHIFT
|
||||
|
||||
/* third SSO shift and/or D[] optimization preshift */
|
||||
|
||||
# if defined(OPT_SSO)
|
||||
# if MAD_F_FRACBITS != 28
|
||||
# error "MAD_F_FRACBITS must be 28 to use OPT_SSO"
|
||||
# endif
|
||||
# define ML0(hi, lo, x, y) ((lo) = (x) * (y))
|
||||
# define MLA(hi, lo, x, y) ((lo) += (x) * (y))
|
||||
# define MLN(hi, lo) ((lo) = -(lo))
|
||||
# define MLZ(hi, lo) ((void) (hi), (mad_fixed_t) (lo))
|
||||
# define SHIFT(x) ((x) >> 2)
|
||||
# define PRESHIFT(x) ((MAD_F(x) + (1L << 13)) >> 14)
|
||||
# else
|
||||
# define ML0(hi, lo, x, y) MAD_F_ML0((hi), (lo), (x), (y))
|
||||
# define MLA(hi, lo, x, y) MAD_F_MLA((hi), (lo), (x), (y))
|
||||
# define MLN(hi, lo) MAD_F_MLN((hi), (lo))
|
||||
# define MLZ(hi, lo) MAD_F_MLZ((hi), (lo))
|
||||
# define SHIFT(x) (x)
|
||||
# if defined(MAD_F_SCALEBITS)
|
||||
# undef MAD_F_SCALEBITS
|
||||
# define MAD_F_SCALEBITS (MAD_F_FRACBITS - 12)
|
||||
# define PRESHIFT(x) (MAD_F(x) >> 12)
|
||||
# else
|
||||
# define PRESHIFT(x) MAD_F(x)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static
|
||||
mad_fixed_t const D[17][32] = {
|
||||
# include "D.dat"
|
||||
};
|
||||
|
||||
# if defined(ASO_SYNTH)
|
||||
void synth_full(struct mad_synth *, struct mad_frame const *,
|
||||
unsigned int, unsigned int);
|
||||
# else
|
||||
/*
|
||||
* NAME: synth->full()
|
||||
* DESCRIPTION: perform full frequency PCM synthesis
|
||||
*/
|
||||
static
|
||||
void synth_full(struct mad_synth *synth, struct mad_frame const *frame,
|
||||
unsigned int nch, unsigned int ns)
|
||||
{
|
||||
unsigned int phase, ch, s, sb, pe, po;
|
||||
mad_fixed_t *pcm1, *pcm2, (*filter)[2][2][16][8];
|
||||
mad_fixed_t const (*sbsample)[36][32];
|
||||
register mad_fixed_t (*fe)[8], (*fx)[8], (*fo)[8];
|
||||
register mad_fixed_t const (*Dptr)[32], *ptr;
|
||||
register mad_fixed64hi_t hi;
|
||||
register mad_fixed64lo_t lo;
|
||||
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
sbsample = &frame->sbsample[ch];
|
||||
filter = &synth->filter[ch];
|
||||
phase = synth->phase;
|
||||
pcm1 = synth->pcm.samples[ch];
|
||||
|
||||
for (s = 0; s < ns; ++s) {
|
||||
dct32((*sbsample)[s], phase >> 1,
|
||||
(*filter)[0][phase & 1], (*filter)[1][phase & 1]);
|
||||
|
||||
pe = phase & ~1;
|
||||
po = ((phase - 1) & 0xf) | 1;
|
||||
|
||||
/* calculate 32 samples */
|
||||
|
||||
fe = &(*filter)[0][ phase & 1][0];
|
||||
fx = &(*filter)[0][~phase & 1][0];
|
||||
fo = &(*filter)[1][~phase & 1][0];
|
||||
|
||||
Dptr = &D[0];
|
||||
|
||||
ptr = *Dptr + po;
|
||||
ML0(hi, lo, (*fx)[0], ptr[ 0]);
|
||||
MLA(hi, lo, (*fx)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fx)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fx)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fx)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fx)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fx)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fx)[7], ptr[ 2]);
|
||||
MLN(hi, lo);
|
||||
|
||||
ptr = *Dptr + pe;
|
||||
MLA(hi, lo, (*fe)[0], ptr[ 0]);
|
||||
MLA(hi, lo, (*fe)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fe)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fe)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fe)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fe)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fe)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fe)[7], ptr[ 2]);
|
||||
|
||||
*pcm1++ = SHIFT(MLZ(hi, lo));
|
||||
|
||||
pcm2 = pcm1 + 30;
|
||||
|
||||
for (sb = 1; sb < 16; ++sb) {
|
||||
++fe;
|
||||
++Dptr;
|
||||
|
||||
/* D[32 - sb][i] == -D[sb][31 - i] */
|
||||
|
||||
ptr = *Dptr + po;
|
||||
ML0(hi, lo, (*fo)[0], ptr[ 0]);
|
||||
MLA(hi, lo, (*fo)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fo)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fo)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fo)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fo)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fo)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fo)[7], ptr[ 2]);
|
||||
MLN(hi, lo);
|
||||
|
||||
ptr = *Dptr + pe;
|
||||
MLA(hi, lo, (*fe)[7], ptr[ 2]);
|
||||
MLA(hi, lo, (*fe)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fe)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fe)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fe)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fe)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fe)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fe)[0], ptr[ 0]);
|
||||
|
||||
*pcm1++ = SHIFT(MLZ(hi, lo));
|
||||
|
||||
ptr = *Dptr - pe;
|
||||
ML0(hi, lo, (*fe)[0], ptr[31 - 16]);
|
||||
MLA(hi, lo, (*fe)[1], ptr[31 - 14]);
|
||||
MLA(hi, lo, (*fe)[2], ptr[31 - 12]);
|
||||
MLA(hi, lo, (*fe)[3], ptr[31 - 10]);
|
||||
MLA(hi, lo, (*fe)[4], ptr[31 - 8]);
|
||||
MLA(hi, lo, (*fe)[5], ptr[31 - 6]);
|
||||
MLA(hi, lo, (*fe)[6], ptr[31 - 4]);
|
||||
MLA(hi, lo, (*fe)[7], ptr[31 - 2]);
|
||||
|
||||
ptr = *Dptr - po;
|
||||
MLA(hi, lo, (*fo)[7], ptr[31 - 2]);
|
||||
MLA(hi, lo, (*fo)[6], ptr[31 - 4]);
|
||||
MLA(hi, lo, (*fo)[5], ptr[31 - 6]);
|
||||
MLA(hi, lo, (*fo)[4], ptr[31 - 8]);
|
||||
MLA(hi, lo, (*fo)[3], ptr[31 - 10]);
|
||||
MLA(hi, lo, (*fo)[2], ptr[31 - 12]);
|
||||
MLA(hi, lo, (*fo)[1], ptr[31 - 14]);
|
||||
MLA(hi, lo, (*fo)[0], ptr[31 - 16]);
|
||||
|
||||
*pcm2-- = SHIFT(MLZ(hi, lo));
|
||||
|
||||
++fo;
|
||||
}
|
||||
|
||||
++Dptr;
|
||||
|
||||
ptr = *Dptr + po;
|
||||
ML0(hi, lo, (*fo)[0], ptr[ 0]);
|
||||
MLA(hi, lo, (*fo)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fo)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fo)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fo)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fo)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fo)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fo)[7], ptr[ 2]);
|
||||
|
||||
*pcm1 = SHIFT(-MLZ(hi, lo));
|
||||
pcm1 += 16;
|
||||
|
||||
phase = (phase + 1) % 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* NAME: synth->half()
|
||||
* DESCRIPTION: perform half frequency PCM synthesis
|
||||
*/
|
||||
static
|
||||
void synth_half(struct mad_synth *synth, struct mad_frame const *frame,
|
||||
unsigned int nch, unsigned int ns)
|
||||
{
|
||||
unsigned int phase, ch, s, sb, pe, po;
|
||||
mad_fixed_t *pcm1, *pcm2, (*filter)[2][2][16][8];
|
||||
mad_fixed_t const (*sbsample)[36][32];
|
||||
register mad_fixed_t (*fe)[8], (*fx)[8], (*fo)[8];
|
||||
register mad_fixed_t const (*Dptr)[32], *ptr;
|
||||
register mad_fixed64hi_t hi;
|
||||
register mad_fixed64lo_t lo;
|
||||
|
||||
for (ch = 0; ch < nch; ++ch) {
|
||||
sbsample = &frame->sbsample[ch];
|
||||
filter = &synth->filter[ch];
|
||||
phase = synth->phase;
|
||||
pcm1 = synth->pcm.samples[ch];
|
||||
|
||||
for (s = 0; s < ns; ++s) {
|
||||
dct32((*sbsample)[s], phase >> 1,
|
||||
(*filter)[0][phase & 1], (*filter)[1][phase & 1]);
|
||||
|
||||
pe = phase & ~1;
|
||||
po = ((phase - 1) & 0xf) | 1;
|
||||
|
||||
/* calculate 16 samples */
|
||||
|
||||
fe = &(*filter)[0][ phase & 1][0];
|
||||
fx = &(*filter)[0][~phase & 1][0];
|
||||
fo = &(*filter)[1][~phase & 1][0];
|
||||
|
||||
Dptr = &D[0];
|
||||
|
||||
ptr = *Dptr + po;
|
||||
ML0(hi, lo, (*fx)[0], ptr[ 0]);
|
||||
MLA(hi, lo, (*fx)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fx)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fx)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fx)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fx)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fx)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fx)[7], ptr[ 2]);
|
||||
MLN(hi, lo);
|
||||
|
||||
ptr = *Dptr + pe;
|
||||
MLA(hi, lo, (*fe)[0], ptr[ 0]);
|
||||
MLA(hi, lo, (*fe)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fe)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fe)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fe)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fe)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fe)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fe)[7], ptr[ 2]);
|
||||
|
||||
*pcm1++ = SHIFT(MLZ(hi, lo));
|
||||
|
||||
pcm2 = pcm1 + 14;
|
||||
|
||||
for (sb = 1; sb < 16; ++sb) {
|
||||
++fe;
|
||||
++Dptr;
|
||||
|
||||
/* D[32 - sb][i] == -D[sb][31 - i] */
|
||||
|
||||
if (!(sb & 1)) {
|
||||
ptr = *Dptr + po;
|
||||
ML0(hi, lo, (*fo)[0], ptr[ 0]);
|
||||
MLA(hi, lo, (*fo)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fo)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fo)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fo)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fo)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fo)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fo)[7], ptr[ 2]);
|
||||
MLN(hi, lo);
|
||||
|
||||
ptr = *Dptr + pe;
|
||||
MLA(hi, lo, (*fe)[7], ptr[ 2]);
|
||||
MLA(hi, lo, (*fe)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fe)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fe)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fe)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fe)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fe)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fe)[0], ptr[ 0]);
|
||||
|
||||
*pcm1++ = SHIFT(MLZ(hi, lo));
|
||||
|
||||
ptr = *Dptr - po;
|
||||
ML0(hi, lo, (*fo)[7], ptr[31 - 2]);
|
||||
MLA(hi, lo, (*fo)[6], ptr[31 - 4]);
|
||||
MLA(hi, lo, (*fo)[5], ptr[31 - 6]);
|
||||
MLA(hi, lo, (*fo)[4], ptr[31 - 8]);
|
||||
MLA(hi, lo, (*fo)[3], ptr[31 - 10]);
|
||||
MLA(hi, lo, (*fo)[2], ptr[31 - 12]);
|
||||
MLA(hi, lo, (*fo)[1], ptr[31 - 14]);
|
||||
MLA(hi, lo, (*fo)[0], ptr[31 - 16]);
|
||||
|
||||
ptr = *Dptr - pe;
|
||||
MLA(hi, lo, (*fe)[0], ptr[31 - 16]);
|
||||
MLA(hi, lo, (*fe)[1], ptr[31 - 14]);
|
||||
MLA(hi, lo, (*fe)[2], ptr[31 - 12]);
|
||||
MLA(hi, lo, (*fe)[3], ptr[31 - 10]);
|
||||
MLA(hi, lo, (*fe)[4], ptr[31 - 8]);
|
||||
MLA(hi, lo, (*fe)[5], ptr[31 - 6]);
|
||||
MLA(hi, lo, (*fe)[6], ptr[31 - 4]);
|
||||
MLA(hi, lo, (*fe)[7], ptr[31 - 2]);
|
||||
|
||||
*pcm2-- = SHIFT(MLZ(hi, lo));
|
||||
}
|
||||
|
||||
++fo;
|
||||
}
|
||||
|
||||
++Dptr;
|
||||
|
||||
ptr = *Dptr + po;
|
||||
ML0(hi, lo, (*fo)[0], ptr[ 0]);
|
||||
MLA(hi, lo, (*fo)[1], ptr[14]);
|
||||
MLA(hi, lo, (*fo)[2], ptr[12]);
|
||||
MLA(hi, lo, (*fo)[3], ptr[10]);
|
||||
MLA(hi, lo, (*fo)[4], ptr[ 8]);
|
||||
MLA(hi, lo, (*fo)[5], ptr[ 6]);
|
||||
MLA(hi, lo, (*fo)[6], ptr[ 4]);
|
||||
MLA(hi, lo, (*fo)[7], ptr[ 2]);
|
||||
|
||||
*pcm1 = SHIFT(-MLZ(hi, lo));
|
||||
pcm1 += 8;
|
||||
|
||||
phase = (phase + 1) % 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: synth->frame()
|
||||
* DESCRIPTION: perform PCM synthesis of frame subband samples
|
||||
*/
|
||||
void mad_synth_frame(struct mad_synth *synth, struct mad_frame const *frame)
|
||||
{
|
||||
unsigned int nch, ns;
|
||||
void (*synth_frame)(struct mad_synth *, struct mad_frame const *,
|
||||
unsigned int, unsigned int);
|
||||
|
||||
nch = MAD_NCHANNELS(&frame->header);
|
||||
ns = MAD_NSBSAMPLES(&frame->header);
|
||||
|
||||
synth->pcm.samplerate = frame->header.samplerate;
|
||||
synth->pcm.channels = nch;
|
||||
synth->pcm.length = 32 * ns;
|
||||
|
||||
synth_frame = synth_full;
|
||||
|
||||
if (frame->options & MAD_OPTION_HALFSAMPLERATE) {
|
||||
synth->pcm.samplerate /= 2;
|
||||
synth->pcm.length /= 2;
|
||||
|
||||
synth_frame = synth_half;
|
||||
}
|
||||
|
||||
synth_frame(synth, frame, nch, ns);
|
||||
|
||||
synth->phase = (synth->phase + ns) % 16;
|
||||
}
|
69
libmad/synth.h
Normal file
69
libmad/synth.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: synth.h,v 1.15 2004/01/23 09:41:33 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_SYNTH_H
|
||||
# define LIBMAD_SYNTH_H
|
||||
|
||||
# include "fixed.h"
|
||||
# include "frame.h"
|
||||
|
||||
struct mad_pcm {
|
||||
unsigned int samplerate; /* sampling frequency (Hz) */
|
||||
unsigned short channels; /* number of channels */
|
||||
unsigned short length; /* number of samples per channel */
|
||||
mad_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */
|
||||
};
|
||||
|
||||
struct mad_synth {
|
||||
mad_fixed_t filter[2][2][2][16][8]; /* polyphase filterbank outputs */
|
||||
/* [ch][eo][peo][s][v] */
|
||||
|
||||
unsigned int phase; /* current processing phase */
|
||||
|
||||
struct mad_pcm pcm; /* PCM output */
|
||||
};
|
||||
|
||||
/* single channel PCM selector */
|
||||
enum {
|
||||
MAD_PCM_CHANNEL_SINGLE = 0
|
||||
};
|
||||
|
||||
/* dual channel PCM selector */
|
||||
enum {
|
||||
MAD_PCM_CHANNEL_DUAL_1 = 0,
|
||||
MAD_PCM_CHANNEL_DUAL_2 = 1
|
||||
};
|
||||
|
||||
/* stereo PCM selector */
|
||||
enum {
|
||||
MAD_PCM_CHANNEL_STEREO_LEFT = 0,
|
||||
MAD_PCM_CHANNEL_STEREO_RIGHT = 1
|
||||
};
|
||||
|
||||
void mad_synth_init(struct mad_synth *);
|
||||
|
||||
# define mad_synth_finish(synth) /* nothing */
|
||||
|
||||
void mad_synth_mute(struct mad_synth *);
|
||||
|
||||
void mad_synth_frame(struct mad_synth *, struct mad_frame const *);
|
||||
|
||||
# endif
|
483
libmad/timer.c
Normal file
483
libmad/timer.c
Normal file
@ -0,0 +1,483 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: timer.c,v 1.18 2004/01/23 09:41:33 rob Exp $
|
||||
*/
|
||||
|
||||
# include "libmad_config.h"
|
||||
|
||||
# include "libmad_global.h"
|
||||
|
||||
# include <stdio.h>
|
||||
|
||||
# ifdef HAVE_ASSERT_H
|
||||
# include <assert.h>
|
||||
# endif
|
||||
|
||||
# include "timer.h"
|
||||
|
||||
mad_timer_t const mad_timer_zero = { 0, 0 };
|
||||
|
||||
/*
|
||||
* NAME: timer->compare()
|
||||
* DESCRIPTION: indicate relative order of two timers
|
||||
*/
|
||||
int mad_timer_compare(mad_timer_t timer1, mad_timer_t timer2)
|
||||
{
|
||||
signed long diff;
|
||||
|
||||
diff = timer1.seconds - timer2.seconds;
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
else if (diff > 0)
|
||||
return +1;
|
||||
|
||||
diff = timer1.fraction - timer2.fraction;
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
else if (diff > 0)
|
||||
return +1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: timer->negate()
|
||||
* DESCRIPTION: invert the sign of a timer
|
||||
*/
|
||||
void mad_timer_negate(mad_timer_t *timer)
|
||||
{
|
||||
timer->seconds = -timer->seconds;
|
||||
|
||||
if (timer->fraction) {
|
||||
timer->seconds -= 1;
|
||||
timer->fraction = MAD_TIMER_RESOLUTION - timer->fraction;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: timer->abs()
|
||||
* DESCRIPTION: return the absolute value of a timer
|
||||
*/
|
||||
mad_timer_t mad_timer_abs(mad_timer_t timer)
|
||||
{
|
||||
if (timer.seconds < 0)
|
||||
mad_timer_negate(&timer);
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: reduce_timer()
|
||||
* DESCRIPTION: carry timer fraction into seconds
|
||||
*/
|
||||
static
|
||||
void reduce_timer(mad_timer_t *timer)
|
||||
{
|
||||
timer->seconds += timer->fraction / MAD_TIMER_RESOLUTION;
|
||||
timer->fraction %= MAD_TIMER_RESOLUTION;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: gcd()
|
||||
* DESCRIPTION: compute greatest common denominator
|
||||
*/
|
||||
static
|
||||
unsigned long gcd(unsigned long num1, unsigned long num2)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
while (num2) {
|
||||
tmp = num2;
|
||||
num2 = num1 % num2;
|
||||
num1 = tmp;
|
||||
}
|
||||
|
||||
return num1;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: reduce_rational()
|
||||
* DESCRIPTION: convert rational expression to lowest terms
|
||||
*/
|
||||
static
|
||||
void reduce_rational(unsigned long *numer, unsigned long *denom)
|
||||
{
|
||||
unsigned long factor;
|
||||
|
||||
factor = gcd(*numer, *denom);
|
||||
|
||||
assert(factor != 0);
|
||||
|
||||
*numer /= factor;
|
||||
*denom /= factor;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: scale_rational()
|
||||
* DESCRIPTION: solve numer/denom == ?/scale avoiding overflowing
|
||||
*/
|
||||
static
|
||||
unsigned long scale_rational(unsigned long numer, unsigned long denom,
|
||||
unsigned long scale)
|
||||
{
|
||||
reduce_rational(&numer, &denom);
|
||||
reduce_rational(&scale, &denom);
|
||||
|
||||
assert(denom != 0);
|
||||
|
||||
if (denom < scale)
|
||||
return numer * (scale / denom) + numer * (scale % denom) / denom;
|
||||
if (denom < numer)
|
||||
return scale * (numer / denom) + scale * (numer % denom) / denom;
|
||||
|
||||
return numer * scale / denom;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: timer->set()
|
||||
* DESCRIPTION: set timer to specific (positive) value
|
||||
*/
|
||||
void mad_timer_set(mad_timer_t *timer, unsigned long seconds,
|
||||
unsigned long numer, unsigned long denom)
|
||||
{
|
||||
timer->seconds = seconds;
|
||||
if (numer >= denom && denom > 0) {
|
||||
timer->seconds += numer / denom;
|
||||
numer %= denom;
|
||||
}
|
||||
|
||||
switch (denom) {
|
||||
case 0:
|
||||
case 1:
|
||||
timer->fraction = 0;
|
||||
break;
|
||||
|
||||
case MAD_TIMER_RESOLUTION:
|
||||
timer->fraction = numer;
|
||||
break;
|
||||
|
||||
case 1000:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 1000);
|
||||
break;
|
||||
|
||||
case 8000:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 8000);
|
||||
break;
|
||||
|
||||
case 11025:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 11025);
|
||||
break;
|
||||
|
||||
case 12000:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 12000);
|
||||
break;
|
||||
|
||||
case 16000:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 16000);
|
||||
break;
|
||||
|
||||
case 22050:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 22050);
|
||||
break;
|
||||
|
||||
case 24000:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 24000);
|
||||
break;
|
||||
|
||||
case 32000:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 32000);
|
||||
break;
|
||||
|
||||
case 44100:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 44100);
|
||||
break;
|
||||
|
||||
case 48000:
|
||||
timer->fraction = numer * (MAD_TIMER_RESOLUTION / 48000);
|
||||
break;
|
||||
|
||||
default:
|
||||
timer->fraction = scale_rational(numer, denom, MAD_TIMER_RESOLUTION);
|
||||
break;
|
||||
}
|
||||
|
||||
if (timer->fraction >= MAD_TIMER_RESOLUTION)
|
||||
reduce_timer(timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: timer->add()
|
||||
* DESCRIPTION: add one timer to another
|
||||
*/
|
||||
void mad_timer_add(mad_timer_t *timer, mad_timer_t incr)
|
||||
{
|
||||
timer->seconds += incr.seconds;
|
||||
timer->fraction += incr.fraction;
|
||||
|
||||
if (timer->fraction >= MAD_TIMER_RESOLUTION)
|
||||
reduce_timer(timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: timer->multiply()
|
||||
* DESCRIPTION: multiply a timer by a scalar value
|
||||
*/
|
||||
void mad_timer_multiply(mad_timer_t *timer, signed long scalar)
|
||||
{
|
||||
mad_timer_t addend;
|
||||
unsigned long factor;
|
||||
|
||||
factor = scalar;
|
||||
if (scalar < 0) {
|
||||
factor = -scalar;
|
||||
mad_timer_negate(timer);
|
||||
}
|
||||
|
||||
addend = *timer;
|
||||
*timer = mad_timer_zero;
|
||||
|
||||
while (factor) {
|
||||
if (factor & 1)
|
||||
mad_timer_add(timer, addend);
|
||||
|
||||
mad_timer_add(&addend, addend);
|
||||
factor >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: timer->count()
|
||||
* DESCRIPTION: return timer value in selected units
|
||||
*/
|
||||
signed long mad_timer_count(mad_timer_t timer, enum mad_units units)
|
||||
{
|
||||
switch (units) {
|
||||
case MAD_UNITS_HOURS:
|
||||
return timer.seconds / 60 / 60;
|
||||
|
||||
case MAD_UNITS_MINUTES:
|
||||
return timer.seconds / 60;
|
||||
|
||||
case MAD_UNITS_SECONDS:
|
||||
return timer.seconds;
|
||||
|
||||
case MAD_UNITS_DECISECONDS:
|
||||
case MAD_UNITS_CENTISECONDS:
|
||||
case MAD_UNITS_MILLISECONDS:
|
||||
|
||||
case MAD_UNITS_8000_HZ:
|
||||
case MAD_UNITS_11025_HZ:
|
||||
case MAD_UNITS_12000_HZ:
|
||||
case MAD_UNITS_16000_HZ:
|
||||
case MAD_UNITS_22050_HZ:
|
||||
case MAD_UNITS_24000_HZ:
|
||||
case MAD_UNITS_32000_HZ:
|
||||
case MAD_UNITS_44100_HZ:
|
||||
case MAD_UNITS_48000_HZ:
|
||||
|
||||
case MAD_UNITS_24_FPS:
|
||||
case MAD_UNITS_25_FPS:
|
||||
case MAD_UNITS_30_FPS:
|
||||
case MAD_UNITS_48_FPS:
|
||||
case MAD_UNITS_50_FPS:
|
||||
case MAD_UNITS_60_FPS:
|
||||
case MAD_UNITS_75_FPS:
|
||||
return timer.seconds * (signed long) units +
|
||||
(signed long) scale_rational(timer.fraction, MAD_TIMER_RESOLUTION,
|
||||
units);
|
||||
|
||||
case MAD_UNITS_23_976_FPS:
|
||||
case MAD_UNITS_24_975_FPS:
|
||||
case MAD_UNITS_29_97_FPS:
|
||||
case MAD_UNITS_47_952_FPS:
|
||||
case MAD_UNITS_49_95_FPS:
|
||||
case MAD_UNITS_59_94_FPS:
|
||||
return (mad_timer_count(timer, -units) + 1) * 1000 / 1001;
|
||||
}
|
||||
|
||||
/* unsupported units */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: timer->fraction()
|
||||
* DESCRIPTION: return fractional part of timer in arbitrary terms
|
||||
*/
|
||||
unsigned long mad_timer_fraction(mad_timer_t timer, unsigned long denom)
|
||||
{
|
||||
timer = mad_timer_abs(timer);
|
||||
|
||||
switch (denom) {
|
||||
case 0:
|
||||
return timer.fraction ?
|
||||
MAD_TIMER_RESOLUTION / timer.fraction : MAD_TIMER_RESOLUTION + 1;
|
||||
|
||||
case MAD_TIMER_RESOLUTION:
|
||||
return timer.fraction;
|
||||
|
||||
default:
|
||||
return scale_rational(timer.fraction, MAD_TIMER_RESOLUTION, denom);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: timer->string()
|
||||
* DESCRIPTION: write a string representation of a timer using a template
|
||||
*/
|
||||
void mad_timer_string(mad_timer_t timer,
|
||||
char *dest, char const *format, enum mad_units units,
|
||||
enum mad_units fracunits, unsigned long subparts)
|
||||
{
|
||||
unsigned long hours, minutes, seconds, sub;
|
||||
unsigned int frac;
|
||||
|
||||
timer = mad_timer_abs(timer);
|
||||
|
||||
seconds = timer.seconds;
|
||||
frac = sub = 0;
|
||||
|
||||
switch (fracunits) {
|
||||
case MAD_UNITS_HOURS:
|
||||
case MAD_UNITS_MINUTES:
|
||||
case MAD_UNITS_SECONDS:
|
||||
break;
|
||||
|
||||
case MAD_UNITS_DECISECONDS:
|
||||
case MAD_UNITS_CENTISECONDS:
|
||||
case MAD_UNITS_MILLISECONDS:
|
||||
|
||||
case MAD_UNITS_8000_HZ:
|
||||
case MAD_UNITS_11025_HZ:
|
||||
case MAD_UNITS_12000_HZ:
|
||||
case MAD_UNITS_16000_HZ:
|
||||
case MAD_UNITS_22050_HZ:
|
||||
case MAD_UNITS_24000_HZ:
|
||||
case MAD_UNITS_32000_HZ:
|
||||
case MAD_UNITS_44100_HZ:
|
||||
case MAD_UNITS_48000_HZ:
|
||||
|
||||
case MAD_UNITS_24_FPS:
|
||||
case MAD_UNITS_25_FPS:
|
||||
case MAD_UNITS_30_FPS:
|
||||
case MAD_UNITS_48_FPS:
|
||||
case MAD_UNITS_50_FPS:
|
||||
case MAD_UNITS_60_FPS:
|
||||
case MAD_UNITS_75_FPS:
|
||||
{
|
||||
unsigned long denom;
|
||||
|
||||
denom = MAD_TIMER_RESOLUTION / fracunits;
|
||||
|
||||
frac = timer.fraction / denom;
|
||||
sub = scale_rational(timer.fraction % denom, denom, subparts);
|
||||
}
|
||||
break;
|
||||
|
||||
case MAD_UNITS_23_976_FPS:
|
||||
case MAD_UNITS_24_975_FPS:
|
||||
case MAD_UNITS_29_97_FPS:
|
||||
case MAD_UNITS_47_952_FPS:
|
||||
case MAD_UNITS_49_95_FPS:
|
||||
case MAD_UNITS_59_94_FPS:
|
||||
/* drop-frame encoding */
|
||||
/* N.B. this is only well-defined for MAD_UNITS_29_97_FPS */
|
||||
{
|
||||
unsigned long frame, cycle, d, m;
|
||||
|
||||
frame = mad_timer_count(timer, fracunits);
|
||||
|
||||
cycle = -fracunits * 60 * 10 - (10 - 1) * 2;
|
||||
|
||||
d = frame / cycle;
|
||||
m = frame % cycle;
|
||||
frame += (10 - 1) * 2 * d;
|
||||
if (m > 2)
|
||||
frame += 2 * ((m - 2) / (cycle / 10));
|
||||
|
||||
frac = frame % -fracunits;
|
||||
seconds = frame / -fracunits;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (units) {
|
||||
case MAD_UNITS_HOURS:
|
||||
minutes = seconds / 60;
|
||||
hours = minutes / 60;
|
||||
|
||||
sprintf(dest, format,
|
||||
hours,
|
||||
(unsigned int) (minutes % 60),
|
||||
(unsigned int) (seconds % 60),
|
||||
frac, sub);
|
||||
break;
|
||||
|
||||
case MAD_UNITS_MINUTES:
|
||||
minutes = seconds / 60;
|
||||
|
||||
sprintf(dest, format,
|
||||
minutes,
|
||||
(unsigned int) (seconds % 60),
|
||||
frac, sub);
|
||||
break;
|
||||
|
||||
case MAD_UNITS_SECONDS:
|
||||
sprintf(dest, format,
|
||||
seconds,
|
||||
frac, sub);
|
||||
break;
|
||||
|
||||
case MAD_UNITS_23_976_FPS:
|
||||
case MAD_UNITS_24_975_FPS:
|
||||
case MAD_UNITS_29_97_FPS:
|
||||
case MAD_UNITS_47_952_FPS:
|
||||
case MAD_UNITS_49_95_FPS:
|
||||
case MAD_UNITS_59_94_FPS:
|
||||
if (fracunits < 0) {
|
||||
/* not yet implemented */
|
||||
sub = 0;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
|
||||
case MAD_UNITS_DECISECONDS:
|
||||
case MAD_UNITS_CENTISECONDS:
|
||||
case MAD_UNITS_MILLISECONDS:
|
||||
|
||||
case MAD_UNITS_8000_HZ:
|
||||
case MAD_UNITS_11025_HZ:
|
||||
case MAD_UNITS_12000_HZ:
|
||||
case MAD_UNITS_16000_HZ:
|
||||
case MAD_UNITS_22050_HZ:
|
||||
case MAD_UNITS_24000_HZ:
|
||||
case MAD_UNITS_32000_HZ:
|
||||
case MAD_UNITS_44100_HZ:
|
||||
case MAD_UNITS_48000_HZ:
|
||||
|
||||
case MAD_UNITS_24_FPS:
|
||||
case MAD_UNITS_25_FPS:
|
||||
case MAD_UNITS_30_FPS:
|
||||
case MAD_UNITS_48_FPS:
|
||||
case MAD_UNITS_50_FPS:
|
||||
case MAD_UNITS_60_FPS:
|
||||
case MAD_UNITS_75_FPS:
|
||||
sprintf(dest, format, mad_timer_count(timer, units), sub);
|
||||
break;
|
||||
}
|
||||
}
|
100
libmad/timer.h
Normal file
100
libmad/timer.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* libmad - MPEG audio decoder library
|
||||
* Copyright (C) 2000-2004 Underbit Technologies, Inc.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: timer.h,v 1.16 2004/01/23 09:41:33 rob Exp $
|
||||
*/
|
||||
|
||||
# ifndef LIBMAD_TIMER_H
|
||||
# define LIBMAD_TIMER_H
|
||||
|
||||
typedef struct {
|
||||
signed long seconds; /* whole seconds */
|
||||
unsigned long fraction; /* 1/MAD_TIMER_RESOLUTION seconds */
|
||||
} mad_timer_t;
|
||||
|
||||
extern mad_timer_t const mad_timer_zero;
|
||||
|
||||
# define MAD_TIMER_RESOLUTION 352800000UL
|
||||
|
||||
enum mad_units {
|
||||
MAD_UNITS_HOURS = -2,
|
||||
MAD_UNITS_MINUTES = -1,
|
||||
MAD_UNITS_SECONDS = 0,
|
||||
|
||||
/* metric units */
|
||||
|
||||
MAD_UNITS_DECISECONDS = 10,
|
||||
MAD_UNITS_CENTISECONDS = 100,
|
||||
MAD_UNITS_MILLISECONDS = 1000,
|
||||
|
||||
/* audio sample units */
|
||||
|
||||
MAD_UNITS_8000_HZ = 8000,
|
||||
MAD_UNITS_11025_HZ = 11025,
|
||||
MAD_UNITS_12000_HZ = 12000,
|
||||
|
||||
MAD_UNITS_16000_HZ = 16000,
|
||||
MAD_UNITS_22050_HZ = 22050,
|
||||
MAD_UNITS_24000_HZ = 24000,
|
||||
|
||||
MAD_UNITS_32000_HZ = 32000,
|
||||
MAD_UNITS_44100_HZ = 44100,
|
||||
MAD_UNITS_48000_HZ = 48000,
|
||||
|
||||
/* video frame/field units */
|
||||
|
||||
MAD_UNITS_24_FPS = 24,
|
||||
MAD_UNITS_25_FPS = 25,
|
||||
MAD_UNITS_30_FPS = 30,
|
||||
MAD_UNITS_48_FPS = 48,
|
||||
MAD_UNITS_50_FPS = 50,
|
||||
MAD_UNITS_60_FPS = 60,
|
||||
|
||||
/* CD audio frames */
|
||||
|
||||
MAD_UNITS_75_FPS = 75,
|
||||
|
||||
/* video drop-frame units */
|
||||
|
||||
MAD_UNITS_23_976_FPS = -24,
|
||||
MAD_UNITS_24_975_FPS = -25,
|
||||
MAD_UNITS_29_97_FPS = -30,
|
||||
MAD_UNITS_47_952_FPS = -48,
|
||||
MAD_UNITS_49_95_FPS = -50,
|
||||
MAD_UNITS_59_94_FPS = -60
|
||||
};
|
||||
|
||||
# define mad_timer_reset(timer) ((void) (*(timer) = mad_timer_zero))
|
||||
|
||||
int mad_timer_compare(mad_timer_t, mad_timer_t);
|
||||
|
||||
# define mad_timer_sign(timer) mad_timer_compare((timer), mad_timer_zero)
|
||||
|
||||
void mad_timer_negate(mad_timer_t *);
|
||||
mad_timer_t mad_timer_abs(mad_timer_t);
|
||||
|
||||
void mad_timer_set(mad_timer_t *, unsigned long, unsigned long, unsigned long);
|
||||
void mad_timer_add(mad_timer_t *, mad_timer_t);
|
||||
void mad_timer_multiply(mad_timer_t *, signed long);
|
||||
|
||||
signed long mad_timer_count(mad_timer_t, enum mad_units);
|
||||
unsigned long mad_timer_fraction(mad_timer_t, unsigned long);
|
||||
void mad_timer_string(mad_timer_t, char *, char const *,
|
||||
enum mad_units, enum mad_units, unsigned long);
|
||||
|
||||
# endif
|
26
main.h
26
main.h
@ -64,11 +64,13 @@
|
||||
#define ENABLE_FILE_LOGGING 1
|
||||
|
||||
// VitaShell version major.minor
|
||||
#define VITASHELL_VERSION_MAJOR 0x0
|
||||
#define VITASHELL_VERSION_MINOR 0x91
|
||||
#define VITASHELL_VERSION_MAJOR 0x00
|
||||
#define VITASHELL_VERSION_MINOR 0x95
|
||||
|
||||
#define VITASHELL_VERSION ((VITASHELL_VERSION_MAJOR << 0x18) | (VITASHELL_VERSION_MINOR << 0x10))
|
||||
|
||||
#define VITASHELL_LASTDIR "ux0:VitaShell/internal/lastdir.txt"
|
||||
|
||||
#define ALIGN(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
@ -116,6 +118,7 @@
|
||||
#define SCROLL_BAR_MIN_HEIGHT 4.0f
|
||||
|
||||
// Context menu
|
||||
#define CONTEXT_MENU_MORE_MIN_WIDTH 200.0f
|
||||
#define CONTEXT_MENU_MIN_WIDTH 180.0f
|
||||
#define CONTEXT_MENU_MARGIN 20.0f
|
||||
#define CONTEXT_MENU_VELOCITY 10.0f
|
||||
@ -135,13 +138,6 @@
|
||||
|
||||
#define BIG_BUFFER_SIZE 16 * 1024 * 1024
|
||||
|
||||
enum ContextMenuModes {
|
||||
CONTEXT_MENU_CLOSED,
|
||||
CONTEXT_MENU_CLOSING,
|
||||
CONTEXT_MENU_OPENED,
|
||||
CONTEXT_MENU_OPENING,
|
||||
};
|
||||
|
||||
enum DialogSteps {
|
||||
DIALOG_STEP_NONE,
|
||||
|
||||
@ -153,6 +149,7 @@ enum DialogSteps {
|
||||
|
||||
DIALOG_STEP_FTP,
|
||||
|
||||
DIALOG_STEP_RENAME,
|
||||
DIALOG_STEP_NEW_FOLDER,
|
||||
|
||||
DIALOG_STEP_COPYING,
|
||||
@ -172,23 +169,24 @@ enum DialogSteps {
|
||||
DIALOG_STEP_INSTALLING,
|
||||
DIALOG_STEP_INSTALLED,
|
||||
|
||||
DIALOG_STEP_RENAME,
|
||||
|
||||
DIALOG_STEP_UPDATE_QUESTION,
|
||||
DIALOG_STEP_DOWNLOADING,
|
||||
DIALOG_STEP_DOWNLOADED,
|
||||
DIALOG_STEP_EXTRACTING,
|
||||
DIALOG_STEP_EXTRACTED,
|
||||
|
||||
DIALOG_STEP_HASH_QUESTION,
|
||||
DIALOG_STEP_HASH_CONFIRMED,
|
||||
DIALOG_STEP_HASHING,
|
||||
DIALOG_STEP_HASH_DISPLAY,
|
||||
};
|
||||
|
||||
extern vita2d_pgf *font;
|
||||
extern char font_size_cache[256];
|
||||
|
||||
extern vita2d_texture *headphone_image, *audio_previous_image, *audio_pause_image, *audio_play_image, *audio_next_image;
|
||||
|
||||
extern int SCE_CTRL_ENTER, SCE_CTRL_CANCEL;
|
||||
|
||||
extern int dialog_step;
|
||||
extern volatile int dialog_step;
|
||||
|
||||
extern int use_custom_config;
|
||||
|
||||
|
@ -58,10 +58,11 @@ int initMessageDialog(int type, char *msg, ...) {
|
||||
param.mode = SCE_MSG_DIALOG_MODE_USER_MSG;
|
||||
}
|
||||
|
||||
sceMsgDialogInit(¶m);
|
||||
|
||||
message_dialog_running = 1;
|
||||
message_dialog_type = type;
|
||||
int res = sceMsgDialogInit(¶m);
|
||||
if (res >= 0) {
|
||||
message_dialog_running = 1;
|
||||
message_dialog_type = type;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,7 +27,9 @@
|
||||
#include "utils.h"
|
||||
|
||||
#define BASE_ADDRESS "https://github.com/TheOfficialFloW/VitaShell/releases/download"
|
||||
#define VITASHELL_UPDATE_FILE "ux0:VitaShell/VitaShell.vpk"
|
||||
#define VERSION_URL "/0.1/version.bin"
|
||||
#define VITASHELL_UPDATE_FILE "ux0:VitaShell/internal/VitaShell.vpk"
|
||||
#define VITASHELL_VERSION_FILE "ux0:VitaShell/internal/version.bin"
|
||||
|
||||
extern unsigned char _binary_resources_updater_eboot_bin_start;
|
||||
extern unsigned char _binary_resources_updater_eboot_bin_size;
|
||||
@ -168,17 +170,23 @@ EXIT:
|
||||
int network_update_thread(SceSize args, void *argp) {
|
||||
sceHttpsDisableOption(SCE_HTTPS_FLAG_SERVER_VERIFY);
|
||||
|
||||
if (downloadFile(BASE_ADDRESS "/0.0/version.bin", "ux0:VitaShell/version.bin", NULL, 0, NULL, NULL) > 0) {
|
||||
uint64_t size = 0;
|
||||
if (getDownloadFileSize(BASE_ADDRESS VERSION_URL, &size) > 0 && size == sizeof(uint32_t)) {
|
||||
int res = downloadFile(BASE_ADDRESS VERSION_URL, VITASHELL_VERSION_FILE, NULL, 0, NULL, NULL);
|
||||
if (res <= 0)
|
||||
goto EXIT;
|
||||
|
||||
// Read version
|
||||
uint32_t version = 0;
|
||||
ReadFile("ux0:VitaShell/version.bin", &version, sizeof(uint32_t));
|
||||
sceIoRemove("ux0:VitaShell/version.bin");
|
||||
ReadFile(VITASHELL_VERSION_FILE, &version, sizeof(uint32_t));
|
||||
sceIoRemove(VITASHELL_VERSION_FILE);
|
||||
|
||||
// Only show update question if no dialog is running
|
||||
if (dialog_step == DIALOG_STEP_NONE) {
|
||||
// New update available
|
||||
if (version > VITASHELL_VERSION) {
|
||||
int major = version >> 0x18;
|
||||
int minor = version >> 0x10;
|
||||
int major = (version >> 0x18) & 0xFF;
|
||||
int minor = (version >> 0x10) & 0xFF;
|
||||
|
||||
char version_string[8];
|
||||
sprintf(version_string, "%X.%X", major, minor);
|
||||
@ -196,7 +204,7 @@ int network_update_thread(SceSize args, void *argp) {
|
||||
|
||||
// No
|
||||
if (dialog_step == DIALOG_STEP_NONE) {
|
||||
return 0;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
// Yes
|
||||
@ -205,12 +213,13 @@ int network_update_thread(SceSize args, void *argp) {
|
||||
}
|
||||
}
|
||||
|
||||
EXIT:
|
||||
return sceKernelExitDeleteThread(0);
|
||||
}
|
||||
|
||||
void installUpdater() {
|
||||
// Recursively clean up package_temp directory
|
||||
removePath(PACKAGE_PARENT, NULL, 0, NULL, NULL);
|
||||
removePath(PACKAGE_PARENT, NULL);
|
||||
sceIoMkdir(PACKAGE_PARENT, 0777);
|
||||
|
||||
// Make dirs
|
||||
@ -243,7 +252,7 @@ int update_extract_thread(SceSize args, void *argp) {
|
||||
installUpdater();
|
||||
|
||||
// Recursively clean up package_temp directory
|
||||
removePath(PACKAGE_PARENT, NULL, 0, NULL, NULL);
|
||||
removePath(PACKAGE_PARENT, NULL);
|
||||
sceIoMkdir(PACKAGE_PARENT, 0777);
|
||||
|
||||
// Open archive
|
||||
@ -267,7 +276,14 @@ int update_extract_thread(SceSize args, void *argp) {
|
||||
|
||||
// Extract process
|
||||
uint64_t value = 0;
|
||||
res = extractArchivePath(src_path, PACKAGE_DIR "/", &value, size + folders, SetProgress, cancelHandler);
|
||||
|
||||
FileProcessParam param;
|
||||
param.value = &value;
|
||||
param.max = size + folders;
|
||||
param.SetProgress = SetProgress;
|
||||
param.cancelHandler = cancelHandler;
|
||||
|
||||
res = extractArchivePath(src_path, PACKAGE_DIR "/", ¶m);
|
||||
if (res <= 0) {
|
||||
closeWaitDialog();
|
||||
dialog_step = DIALOG_STEP_CANCELLED;
|
||||
@ -303,4 +319,4 @@ EXIT:
|
||||
powerUnlock();
|
||||
|
||||
return sceKernelExitDeleteThread(0);
|
||||
}
|
||||
}
|
||||
|
@ -39,9 +39,102 @@ void loadScePaf() {
|
||||
sceSysmoduleLoadModuleInternalWithArg(0x80000008, sizeof(scepaf_argp), scepaf_argp, ptr);
|
||||
}
|
||||
|
||||
int patchRetailContents() {
|
||||
int res;
|
||||
|
||||
SceIoStat stat;
|
||||
memset(&stat, 0, sizeof(SceIoStat));
|
||||
res = sceIoGetstat(PACKAGE_DIR "/sce_sys/retail/livearea", &stat);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
res = sceIoRename(PACKAGE_DIR "/sce_sys/livearea", PACKAGE_DIR "/sce_sys/livearea_org");
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
res = sceIoRename(PACKAGE_DIR "/sce_sys/retail/livearea", PACKAGE_DIR "/sce_sys/livearea");
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int restoreRetailContents(char *titleid) {
|
||||
int res;
|
||||
char src_path[128], dst_path[128];
|
||||
|
||||
sprintf(src_path, "ux0:app/%s/sce_sys/livearea", titleid);
|
||||
sprintf(dst_path, "ux0:app/%s/sce_sys/retail/livearea", titleid);
|
||||
res = sceIoRename(src_path, dst_path);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
sprintf(src_path, "ux0:app/%s/sce_sys/livearea_org", titleid);
|
||||
sprintf(dst_path, "ux0:app/%s/sce_sys/livearea", titleid);
|
||||
res = sceIoRename(src_path, dst_path);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int promoteUpdate(char *path, char *titleid, char *category, void *sfo_buffer, int sfo_size) {
|
||||
int res;
|
||||
|
||||
// Update installation
|
||||
if (strcmp(category, "gp") == 0) {
|
||||
// Change category to 'gd'
|
||||
setSfoString(sfo_buffer, "CATEGORY", "gd");
|
||||
WriteFile(PACKAGE_DIR "/sce_sys/param.sfo", sfo_buffer, sfo_size);
|
||||
|
||||
// App path
|
||||
char app_path[MAX_PATH_LENGTH];
|
||||
snprintf(app_path, MAX_PATH_LENGTH, "ux0:app/%s", titleid);
|
||||
|
||||
/*
|
||||
Without the following trick, the livearea won't be updated and the game will even crash
|
||||
*/
|
||||
|
||||
// Integrate patch to app
|
||||
res = movePath(path, app_path, MOVE_INTEGRATE | MOVE_REPLACE, NULL);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
// Move app to promotion directory
|
||||
res = movePath(app_path, path, 0, NULL);
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int promote(char *path) {
|
||||
int res;
|
||||
|
||||
// Read param.sfo
|
||||
void *sfo_buffer = NULL;
|
||||
int sfo_size = allocateReadFile(PACKAGE_DIR "/sce_sys/param.sfo", &sfo_buffer);
|
||||
if (sfo_size < 0)
|
||||
return sfo_size;
|
||||
|
||||
// Get titleid
|
||||
char titleid[12];
|
||||
getSfoString(sfo_buffer, "TITLE_ID", titleid, sizeof(titleid));
|
||||
|
||||
// Get category
|
||||
char category[4];
|
||||
getSfoString(sfo_buffer, "CATEGORY", category, sizeof(category));
|
||||
|
||||
// Promote update
|
||||
promoteUpdate(path, titleid, category, sfo_buffer, sfo_size);
|
||||
|
||||
// Free sfo buffer
|
||||
free(sfo_buffer);
|
||||
|
||||
// Patch to use retail contents so the game is not shown as test version
|
||||
int patch_retail_contents = patchRetailContents();
|
||||
|
||||
loadScePaf();
|
||||
|
||||
res = sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_PROMOTER_UTIL);
|
||||
@ -78,7 +171,12 @@ int promote(char *path) {
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
return result;
|
||||
// Restore
|
||||
if (patch_retail_contents >= 0)
|
||||
restoreRetailContents(titleid);
|
||||
|
||||
// Using the promoteUpdate trick, we get 0x80870005 as result, but it installed correctly though, so return ok
|
||||
return result == 0x80870005 ? 0 : result;
|
||||
}
|
||||
|
||||
void fpkg_hmac(const uint8_t *data, unsigned int len, uint8_t hmac[16]) {
|
||||
@ -126,24 +224,29 @@ int makeHeadBin() {
|
||||
|
||||
// Get title id
|
||||
char titleid[12];
|
||||
memset(titleid, 0, sizeof(titleid));
|
||||
getSfoString(sfo_buffer, "TITLE_ID", titleid, sizeof(titleid));
|
||||
if (strlen(titleid) != 9) // Enforce TITLE_ID format
|
||||
|
||||
// Enforce TITLE_ID format
|
||||
if (strlen(titleid) != 9)
|
||||
return -2;
|
||||
|
||||
// Get content id
|
||||
char contentid[48];
|
||||
memset(contentid, 0, sizeof(contentid));
|
||||
getSfoString(sfo_buffer, "CONTENT_ID", contentid, sizeof(contentid));
|
||||
|
||||
// Free sfo buffer
|
||||
free(sfo_buffer);
|
||||
|
||||
// TODO: check category for update installation
|
||||
// TODO: use real content_id
|
||||
|
||||
// Allocate head.bin buffer
|
||||
uint8_t *head_bin = malloc(sizeof(base_head_bin));
|
||||
memcpy(head_bin, base_head_bin, sizeof(base_head_bin));
|
||||
|
||||
// Write full titleid
|
||||
char full_title_id[128];
|
||||
// Write full title id
|
||||
char full_title_id[48];
|
||||
snprintf(full_title_id, sizeof(full_title_id), "EP9000-%s_00-XXXXXXXXXXXXXXXX", titleid);
|
||||
strncpy((char *)&head_bin[0x30], full_title_id, 48);
|
||||
strncpy((char *)&head_bin[0x30], strlen(contentid) > 0 ? contentid : full_title_id, 48);
|
||||
|
||||
// hmac of pkg header
|
||||
len = ntohl(*(uint32_t *)&head_bin[0xD0]);
|
||||
@ -177,7 +280,7 @@ int installPackage(char *file) {
|
||||
int res;
|
||||
|
||||
// Recursively clean up package_temp directory
|
||||
removePath(PACKAGE_PARENT, NULL, 0, NULL, NULL);
|
||||
removePath(PACKAGE_PARENT, NULL);
|
||||
sceIoMkdir(PACKAGE_PARENT, 0777);
|
||||
|
||||
// Open archive
|
||||
@ -191,7 +294,7 @@ int installPackage(char *file) {
|
||||
addEndSlash(src_path);
|
||||
|
||||
// Extract process
|
||||
res = extractArchivePath(src_path, PACKAGE_DIR "/", NULL, 0, NULL, NULL);
|
||||
res = extractArchivePath(src_path, PACKAGE_DIR "/", NULL);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
@ -226,7 +329,7 @@ int install_thread(SceSize args_size, InstallArguments *args) {
|
||||
sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
|
||||
|
||||
// Recursively clean up package_temp directory
|
||||
removePath(PACKAGE_PARENT, NULL, 0, NULL, NULL);
|
||||
removePath(PACKAGE_PARENT, NULL);
|
||||
sceIoMkdir(PACKAGE_PARENT, 0777);
|
||||
|
||||
// Open archive
|
||||
@ -293,7 +396,14 @@ int install_thread(SceSize args_size, InstallArguments *args) {
|
||||
|
||||
// Extract process
|
||||
uint64_t value = 0;
|
||||
res = extractArchivePath(src_path, PACKAGE_DIR "/", &value, size + folders, SetProgress, cancelHandler);
|
||||
|
||||
FileProcessParam param;
|
||||
param.value = &value;
|
||||
param.max = size + folders;
|
||||
param.SetProgress = SetProgress;
|
||||
param.cancelHandler = cancelHandler;
|
||||
|
||||
res = extractArchivePath(src_path, PACKAGE_DIR "/", ¶m);
|
||||
if (res <= 0) {
|
||||
closeWaitDialog();
|
||||
dialog_step = DIALOG_STEP_CANCELLED;
|
||||
|
2
photo.c
2
photo.c
@ -352,7 +352,7 @@ int photoViewer(char *file, int type, FileList *list, FileListEntry *entry, int
|
||||
|
||||
// Zoom text
|
||||
if ((sceKernelGetProcessTimeWide() - time) < ZOOM_TEXT_TIME)
|
||||
pgf_draw_textf(SHELL_MARGIN_X, SCREEN_HEIGHT - 3.0f * SHELL_MARGIN_Y, GENERAL_COLOR, FONT_SIZE, "%.0f%%", zoom * 100.0f);
|
||||
pgf_draw_textf(SHELL_MARGIN_X, SCREEN_HEIGHT - 3.0f * SHELL_MARGIN_Y, PHOTO_ZOOM_COLOR, FONT_SIZE, "%.0f%%", zoom * 100.0f);
|
||||
|
||||
// End drawing
|
||||
endDrawing();
|
||||
|
@ -28,7 +28,7 @@
|
||||
<frame id="frame4">
|
||||
<liveitem>
|
||||
<text align="left" text-align="left" word-wrap="off" ellipsis="on">
|
||||
<str size="18" color="#ffffff" shadow="on">v0.91</str>
|
||||
<str size="18" color="#ffffff" shadow="on">v0.95</str>
|
||||
</text>
|
||||
</liveitem>
|
||||
</frame>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
135
resources/changeinfo.txt
Normal file
135
resources/changeinfo.txt
Normal file
@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<changeinfo>
|
||||
<changes app_ver="00.10">
|
||||
<![CDATA[
|
||||
- Initial release.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.20">
|
||||
<![CDATA[
|
||||
- Added ability to sign PSP homebrews.<br>
|
||||
- Added sleep prevention when using FTP, deleting and copying files.<br>
|
||||
- Added a scrollbar.<br>
|
||||
- Added date and time to info bar.<br>
|
||||
- Added correct enter and cancel buttons assignment.<br>
|
||||
- Added some cosmetic changes.<br>
|
||||
- Fixed crash when deleting marked entries.<br>
|
||||
- Copied entries now still rest in clipboard after pasting them.<br>
|
||||
- The application now cleans itself before launching homebrews.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.30">
|
||||
<![CDATA[
|
||||
- Added translation support. See translation_readme.txt for more details.<br>
|
||||
- Added move ability (only possible within same partition).<br>
|
||||
- Added tabulator support in text viewer.<br>
|
||||
- Removed 'Paste', 'Delete', 'Rename' and 'New folder' in read-only partitions.<br>
|
||||
- Fixed size string of files over 1GB.<br>
|
||||
- Fixed alphabetical sorting.<br>
|
||||
- Fixed battery percent bug being -1% on PSM Dev Assistant.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.40">
|
||||
<![CDATA[
|
||||
- Added experimental feature: Holding START to force exit homebrews.<br>
|
||||
- Added battery symbol by Ruben_Wolf.<br>
|
||||
- Switched to official PGF font.<br>
|
||||
- Changed triangle-menu animation to ease-out.<br>
|
||||
- Improved mark all/unmark all feature.<br>
|
||||
- Fixed percentage precision in progress bar.<br>
|
||||
- Fixed small bug in move operation.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.50">
|
||||
<![CDATA[
|
||||
- Increased homebrew force-exit compatbility and stability.<br>
|
||||
- Added network host mountpoint.<br>
|
||||
- Added ability to compile shader programs (use the _v.cg suffix for vertexes and _f.cg for fragments).<br>
|
||||
- Finished photo viewer. Use the right analog stick to zoom in/out. Left analog stick to move.<br>
|
||||
L/R to rotate and X/O to change display mode.<br>
|
||||
- Updated to newest vita2dlib which fixed many bugs with images.<br>
|
||||
- Improved 'New folder' by extending to 'New folder (X)', where 'X' is an increasing number.<br>
|
||||
- Improved message dialog texts.<br>
|
||||
- Limited filenames so it doesn't overlap with the size/folder text. <br>
|
||||
- Fixed infinite loop when copying the src to its subfolder by an error result.<br>
|
||||
- Fixed FTP client crashes and added support for Turboclient Android.<br>
|
||||
- Fixed alphabetical sorting, finally.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.60">
|
||||
<![CDATA[
|
||||
- Fixed size string of files, again.<br>
|
||||
- Optimized I/O operations regarding speed.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.70">
|
||||
<![CDATA[
|
||||
- Ported to HENkaku (support for renaming/creating folders and for analog stick for fast movement).<br>
|
||||
- Added custom dialogs.<br>
|
||||
- Added graphics by Freakler.<br>
|
||||
- Added possibility to use FTP in background.<br>
|
||||
- I/O operations can now be cancelled.<br>
|
||||
- Removed misc stuff, shader compiler, homebrew loading, PBOOT.PBP signing, network host.<br>
|
||||
- Fixed various bugs.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.80">
|
||||
<![CDATA[
|
||||
- Added support for >2GB zip archives (dropped support for 7zip and rar though).<br>
|
||||
- Added cache system for zipfs (faster file reading when browsing in zip archives).<br>
|
||||
- Added possibility to customize the application's UI.<br>
|
||||
- Added possibility to translate the application.<br>
|
||||
- Fixed 12h time conversion.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.85">
|
||||
<![CDATA[
|
||||
- Added customization possibility for ftp icon, battery, dialog and context menu.<br>
|
||||
- Added random wallpaper feature.<br>
|
||||
- Changed location of themes to 'ux0:VitaShell/theme/YOUR_THEME_NAME'.<br>
|
||||
- Fixed russian and korean language support.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.86">
|
||||
<![CDATA[
|
||||
- Added dialog box animation and aligned dialog box y to make it look better.<br>
|
||||
- Fixed wrong time string for files and folders. Thanks to persona5.<br>
|
||||
- Fixed INSTALL_WARNING text crash.<br>
|
||||
- Added default files creating.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.90">
|
||||
<![CDATA[
|
||||
- Added possibility to use specific background for file browser, hex editor, text editor, photo viewer.<br>
|
||||
- Added files and folder icons by littlebalup.<br>
|
||||
- Added charging battery icon by ribbid987.<br>
|
||||
- Added sfo reader by theorywrong.<br>
|
||||
- Added translation support for turkish (english_gb uses the same id as turkish, fix it Sony!).<br>
|
||||
- Fixed bug where copied files and folders of archives didn't stay on clipboard.<br>
|
||||
- Allow auto screen-off.<br>
|
||||
- System information trigger combo changed to START instead of L+R+START. System information can now also be translated, thanks to littlebalup.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.91">
|
||||
<![CDATA[
|
||||
- Added automatic network update. VitaShell will now notify you when there's a new update.<br>
|
||||
You'll then be able to download it within the VitaShell application and it will update both<br>
|
||||
molecularShell and VitaShell to the newest verison.<br>
|
||||
- Added text and audio file icon by littlebalup.<br>
|
||||
- Updated to latest libftpvita which fixed file size string > 2GB and added APPE command.<br>
|
||||
]]>
|
||||
</changes>
|
||||
<changes app_ver="00.95">
|
||||
<![CDATA[
|
||||
- Added ability to install update files as .vpk (for Vitamin).<br>
|
||||
- Added patch to make .vpk installation appearing as full version instead of test version.<br>
|
||||
- Added text editor by BigBoot (WIP).<br>
|
||||
- Added 'More' entry to the context menu.<br>
|
||||
- Added 'Install all' feature to install all packages available in the folder (by ribbid987).<br>
|
||||
- Added 'Calculate SHA1' feature by xerpia64.<br>
|
||||
- Added support for ftp promoting for https://github.com/soywiz/vitaorganizer.<br>
|
||||
- Fixed 'Move' operation. Now it does integrate into folders and replace files.<br>
|
||||
- Dropped GENERAL_COLOR, now all colors are adjustable.<br>
|
||||
]]>
|
||||
</changes>
|
||||
</changeinfo>
|
@ -1,22 +1,47 @@
|
||||
# VitaShell colors file
|
||||
|
||||
# Colors
|
||||
# Shell colors
|
||||
BACKGROUND_COLOR = 0xFF000000 # Black
|
||||
GENERAL_COLOR = 0xFFFFFFFF # White
|
||||
TITLE_COLOR = 0xFFFF007F # Violet
|
||||
PATH_COLOR = 0xFFBFBFBF # Litegray
|
||||
DATE_TIME_COLOR = 0xFFFFFFFF # White
|
||||
|
||||
# File browser colors
|
||||
FOCUS_COLOR = 0xFF00FF00 # Green
|
||||
FILE_COLOR = 0xFFFFFFFF # White
|
||||
SFO_COLOR = 0xFFFFFFFF # White
|
||||
TXT_COLOR = 0xFFFFFFFF # White
|
||||
FOLDER_COLOR = 0xFFFFFF00 # Cyan
|
||||
IMAGE_COLOR = 0xFF7F00FF # Rose
|
||||
ARCHIVE_COLOR = 0xFF007FFF # Orange
|
||||
SCROLL_BAR_COLOR = 0xFFFF7F00 # Azure
|
||||
SCROLL_BAR_BG_COLOR = 0xFF7F7F7F # Gray
|
||||
MARKED_COLOR = 0x4FFF7F00 # Azure
|
||||
INVISIBLE_COLOR = 0xFF3F3F3F # Darkgray #1
|
||||
DIALOG_BG_COLOR = 0xFF2F2F2F # Darkgray #2
|
||||
MARKED_COLOR = 0x4FFF7F00 # Azure with alpha
|
||||
|
||||
# Context menu colors
|
||||
CONTEXT_MENU_TEXT_COLOR = 0xFFFFFFFF # White
|
||||
CONTEXT_MENU_FOCUS_COLOR = 0xFF00FF00 # Green
|
||||
CONTEXT_MENU_COLOR = 0xFA2F2F2F # Darkgray #2 with alpha
|
||||
CONTEXT_MENU_MORE_COLOR = 0xFC282828 # Darkgray #3 with alpha
|
||||
INVISIBLE_COLOR = 0xFF3F3F3F # Darkgray #1
|
||||
|
||||
# Dialog colors
|
||||
DIALOG_COLOR = 0xFFFFFFFF # White
|
||||
DIALOG_BG_COLOR = 0xFF2F2F2F # Darkgray #2
|
||||
PROGRESS_BAR_COLOR = 0xFF00FF7F # Chartreuse
|
||||
PROGRESS_BAR_BG_COLOR = 0xFF7F7F7F # Gray
|
||||
|
||||
# Hex editor colors
|
||||
HEX_COLOR = 0xFFFFFFFF # White
|
||||
HEX_OFFSET_COLOR = 0xFFFFFF00 # Cyan
|
||||
HEX_NIBBLE_COLOR = 0xFF0000FF # Red
|
||||
HEX_NIBBLE_COLOR = 0xFF0000FF # Red
|
||||
|
||||
# Text editor colors
|
||||
TEXT_COLOR = 0xFFFFFFFF # White
|
||||
TEXT_FOCUS_COLOR = 0xFF00FF00 # Green
|
||||
TEXT_LINE_NUMBER_COLOR = 0xFF4F4F4F # Darkgray #3
|
||||
TEXT_LINE_NUMBER_COLOR_FOCUS = 0xFF7F7F7F # Gray
|
||||
TEXT_HIGHLIGHT_COLOR = 0xFF80F5FF # Yellow
|
||||
|
||||
# Photo viewer colors
|
||||
PHOTO_ZOOM_COLOR = 0xFFFFFFFF # White
|
@ -1,11 +1,34 @@
|
||||
# VitaShell language file
|
||||
|
||||
# General strings
|
||||
ERROR = "Error 0x%08X."
|
||||
OK = "OK"
|
||||
YES = "Yes"
|
||||
NO = "No"
|
||||
CANCEL = "Cancel"
|
||||
FOLDER = "Folder"
|
||||
|
||||
# Progress strings
|
||||
MOVING = "Moving..."
|
||||
COPYING = "Copying..."
|
||||
DELETING = "Deleting..."
|
||||
INSTALLING = "Installing..."
|
||||
DOWNLOADING = "Downloading..."
|
||||
EXTRACTING = "Extracting..."
|
||||
HASHING = "Hashing..."
|
||||
|
||||
# Hex editor strings
|
||||
OFFSET = "Offset"
|
||||
OPEN_HEX_EDITOR = "Open hex editor"
|
||||
|
||||
# Text editor strings
|
||||
EDIT_LINE = "Edit line"
|
||||
ENTER_SEARCH_TERM = "Enter search term"
|
||||
CUT = "Cut"
|
||||
INSERT_EMPTY_LINE = "Insert empty line"
|
||||
|
||||
# File browser context menu strings
|
||||
MORE = "More"
|
||||
MARK_ALL = "Mark all"
|
||||
UNMARK_ALL = "Unmark all"
|
||||
MOVE = "Move"
|
||||
@ -14,25 +37,27 @@ PASTE = "Paste"
|
||||
DELETE = "Delete"
|
||||
RENAME = "Rename"
|
||||
NEW_FOLDER = "New folder"
|
||||
FOLDER = "Folder"
|
||||
INSTALL_ALL = "Install all"
|
||||
CALCULATE_SHA1 = "Calculate SHA1"
|
||||
SEARCH = "Search"
|
||||
|
||||
# File browser strings
|
||||
COPIED_FILE = "Copied %d file."
|
||||
COPIED_FOLDER = "Copied %d folder."
|
||||
COPIED_FILES_FOLDERS = "Copied %d files/folders."
|
||||
MOVING = "Moving..."
|
||||
COPYING = "Copying..."
|
||||
DELETING = "Deleting..."
|
||||
INSTALLING = "Installing..."
|
||||
DOWNLOADING = "Downloading..."
|
||||
EXTRACTING = "Extracting..."
|
||||
|
||||
# Dialog questions
|
||||
DELETE_FILE_QUESTION = "Are you sure you want to delete this file?"
|
||||
DELETE_FOLDER_QUESTION = "Are you sure you want to delete this folder?"
|
||||
DELETE_FILES_FOLDERS_QUESTION = "Are you sure you want to delete these files/folders?"
|
||||
INSTALL_ALL_QUESTION = "Do you want to install all packages available in this folder?"
|
||||
INSTALL_QUESTION = "Do you want to install this package?"
|
||||
INSTALL_WARNING = "This package requests extended permissions.\It will have access to your personal information.\If you did not obtain it from a trusted source,\please proceed at your own caution.\\Would you like to continue the install?"
|
||||
HASH_FILE_QUESTION = "SHA1 hashing may take a long time. Continue?"
|
||||
|
||||
# Others
|
||||
SAVE_MODIFICATIONS = "Do you want to save your modifications?"
|
||||
WIFI_ERROR = "You must use Wi-Fi to do this."
|
||||
FTP_SERVER = "FTP server is now running at\ftp://%s:%i\\Press 'OK' to keep it in background.\Press 'Cancel' to disconnect."
|
||||
SYS_INFO = "System software: %s\Model: 0x%08X\MAC address: %s\IP address: %s\Memory card: %s/%s"
|
||||
INSTALL_ALL = "Install all"
|
||||
UPDATE_QUESTION = "VitaShell %s is now available.\\Do you want to update the application?"
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
38
sfo.c
38
sfo.c
@ -65,6 +65,42 @@ int getSfoString(void *buffer, char *name, char *string, int length) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
int setSfoValue(void *buffer, char *name, uint32_t value) {
|
||||
SfoHeader *header = (SfoHeader *)buffer;
|
||||
SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
|
||||
|
||||
if (header->magic != SFO_MAGIC)
|
||||
return -1;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < header->count; i++) {
|
||||
if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
|
||||
*(uint32_t *)(buffer + header->valofs + entries[i].dataofs) = value;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
int setSfoString(void *buffer, char *name, char *string) {
|
||||
SfoHeader *header = (SfoHeader *)buffer;
|
||||
SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
|
||||
|
||||
if (header->magic != SFO_MAGIC)
|
||||
return -1;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < header->count; i++) {
|
||||
if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
|
||||
strcpy(buffer + header->valofs + entries[i].dataofs, string);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
int SFOReader(char *file) {
|
||||
uint8_t *buffer = malloc(BIG_BUFFER_SIZE);
|
||||
if (!buffer)
|
||||
@ -129,7 +165,7 @@ int SFOReader(char *file) {
|
||||
for (i = 0; i < MAX_ENTRIES && (base_pos + i) < sfo_header->count; i++) {
|
||||
SfoEntry *entries = (SfoEntry *)(buffer + sizeof(SfoHeader) + (sizeof(SfoEntry) * (i + base_pos)));
|
||||
|
||||
uint32_t color = (rel_pos == i) ? FOCUS_COLOR : GENERAL_COLOR;
|
||||
uint32_t color = (rel_pos == i) ? TEXT_FOCUS_COLOR : TEXT_COLOR;
|
||||
|
||||
char *name = (char *)buffer + sfo_header->keyofs + entries->nameofs;
|
||||
pgf_draw_textf(SHELL_MARGIN_X, START_Y + (FONT_Y_SPACE * i), color, FONT_SIZE, "%s", name);
|
||||
|
4
sfo.h
4
sfo.h
@ -20,8 +20,6 @@
|
||||
#ifndef __SFO_H__
|
||||
#define __SFO_H__
|
||||
|
||||
// Struct from : http://www.vitadevwiki.com/index.php?title=System_File_Object_(SFO)_(PSF)
|
||||
|
||||
#define SFO_MAGIC 0x46535000
|
||||
|
||||
#define PSF_TYPE_BIN 0
|
||||
@ -47,6 +45,8 @@ typedef struct SfoEntry {
|
||||
|
||||
int getSfoValue(void *buffer, char *name, uint32_t *value);
|
||||
int getSfoString(void *buffer, char *name, char *string, int length);
|
||||
int setSfoValue(void *buffer, char *name, uint32_t value);
|
||||
int setSfoString(void *buffer, char *name, char *string);
|
||||
|
||||
int SFOReader(char *file);
|
||||
|
||||
|
18
text.h
18
text.h
@ -19,12 +19,22 @@
|
||||
#ifndef __TEXT_H__
|
||||
#define __TEXT_H__
|
||||
|
||||
#define MAX_LINES 1 * 1024 * 1024
|
||||
#define MAX_LINES 0x10000
|
||||
#define MAX_LINE_CHARACTERS 1024
|
||||
#define MAX_COPY_BUFFER_SIZE 1024
|
||||
|
||||
#define MAX_SELECTION 1024
|
||||
|
||||
#define TEXT_START_X 97.0f
|
||||
|
||||
#define MAX_SEARCH_RESULTS 1024 * 1024
|
||||
#define MIN_SEARCH_TERM_LENGTH 1
|
||||
|
||||
typedef struct TextListEntry {
|
||||
struct TextListEntry *next;
|
||||
struct TextListEntry *previous;
|
||||
int line_number;
|
||||
int selected;
|
||||
char line[MAX_LINE_CHARACTERS];
|
||||
} TextListEntry;
|
||||
|
||||
@ -34,6 +44,12 @@ typedef struct {
|
||||
int length;
|
||||
} TextList;
|
||||
|
||||
typedef struct CopyEntry {
|
||||
char line[MAX_LINE_CHARACTERS];
|
||||
} CopyEntry;
|
||||
|
||||
void initTextContextMenuWidth();
|
||||
|
||||
int textViewer(char *file);
|
||||
|
||||
#endif
|
82
theme.c
82
theme.c
@ -38,28 +38,54 @@ extern unsigned char _binary_resources_battery_bar_charge_png_start;
|
||||
extern unsigned char _binary_resources_colors_txt_start;
|
||||
extern unsigned char _binary_resources_colors_txt_size;
|
||||
|
||||
// Shell colors
|
||||
int BACKGROUND_COLOR;
|
||||
int GENERAL_COLOR;
|
||||
int TITLE_COLOR;
|
||||
int PATH_COLOR;
|
||||
int DATE_TIME_COLOR;
|
||||
|
||||
// File browser colors
|
||||
int FOCUS_COLOR;
|
||||
int FILE_COLOR;
|
||||
int SFO_COLOR;
|
||||
int TXT_COLOR;
|
||||
int FOLDER_COLOR;
|
||||
int IMAGE_COLOR;
|
||||
int ARCHIVE_COLOR;
|
||||
int SCROLL_BAR_COLOR;
|
||||
int SCROLL_BAR_BG_COLOR;
|
||||
int MARKED_COLOR;
|
||||
int INVISIBLE_COLOR;
|
||||
int DIALOG_BG_COLOR;
|
||||
|
||||
// Context menu colors
|
||||
int CONTEXT_MENU_TEXT_COLOR;
|
||||
int CONTEXT_MENU_FOCUS_COLOR;
|
||||
int CONTEXT_MENU_COLOR;
|
||||
int CONTEXT_MENU_MORE_COLOR;
|
||||
int INVISIBLE_COLOR;
|
||||
|
||||
// Dialog colors
|
||||
int DIALOG_COLOR;
|
||||
int DIALOG_BG_COLOR;
|
||||
int PROGRESS_BAR_COLOR;
|
||||
int PROGRESS_BAR_BG_COLOR;
|
||||
|
||||
// Hex editor colors
|
||||
int HEX_COLOR;
|
||||
int HEX_OFFSET_COLOR;
|
||||
int HEX_NIBBLE_COLOR;
|
||||
|
||||
// Text editor colors
|
||||
int TEXT_COLOR;
|
||||
int TEXT_FOCUS_COLOR;
|
||||
int TEXT_LINE_NUMBER_COLOR;
|
||||
int TEXT_LINE_NUMBER_COLOR_FOCUS;
|
||||
int TEXT_HIGHLIGHT_COLOR;
|
||||
|
||||
// Photo viewer colors
|
||||
int PHOTO_ZOOM_COLOR;
|
||||
|
||||
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, *battery_image = NULL, *battery_bar_red_image = 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;
|
||||
|
||||
@ -72,25 +98,51 @@ int wallpaper_count = 0;
|
||||
void loadTheme() {
|
||||
#define COLOR_ENTRY(name) { #name, CONFIG_TYPE_HEXDECIMAL, (void *)&name }
|
||||
ConfigEntry colors_entries[] = {
|
||||
// Shell colors
|
||||
COLOR_ENTRY(BACKGROUND_COLOR),
|
||||
COLOR_ENTRY(GENERAL_COLOR),
|
||||
COLOR_ENTRY(TITLE_COLOR),
|
||||
COLOR_ENTRY(PATH_COLOR),
|
||||
COLOR_ENTRY(DATE_TIME_COLOR),
|
||||
|
||||
// File browser colors
|
||||
COLOR_ENTRY(FOCUS_COLOR),
|
||||
COLOR_ENTRY(FILE_COLOR),
|
||||
COLOR_ENTRY(SFO_COLOR),
|
||||
COLOR_ENTRY(TXT_COLOR),
|
||||
COLOR_ENTRY(FOLDER_COLOR),
|
||||
COLOR_ENTRY(IMAGE_COLOR),
|
||||
COLOR_ENTRY(ARCHIVE_COLOR),
|
||||
COLOR_ENTRY(SCROLL_BAR_COLOR),
|
||||
COLOR_ENTRY(SCROLL_BAR_BG_COLOR),
|
||||
COLOR_ENTRY(MARKED_COLOR),
|
||||
COLOR_ENTRY(INVISIBLE_COLOR),
|
||||
COLOR_ENTRY(DIALOG_BG_COLOR),
|
||||
|
||||
// Context menu colors
|
||||
COLOR_ENTRY(CONTEXT_MENU_TEXT_COLOR),
|
||||
COLOR_ENTRY(CONTEXT_MENU_FOCUS_COLOR),
|
||||
COLOR_ENTRY(CONTEXT_MENU_COLOR),
|
||||
COLOR_ENTRY(CONTEXT_MENU_MORE_COLOR),
|
||||
COLOR_ENTRY(INVISIBLE_COLOR),
|
||||
|
||||
// Dialog colors
|
||||
COLOR_ENTRY(DIALOG_COLOR),
|
||||
COLOR_ENTRY(DIALOG_BG_COLOR),
|
||||
COLOR_ENTRY(PROGRESS_BAR_COLOR),
|
||||
COLOR_ENTRY(PROGRESS_BAR_BG_COLOR),
|
||||
|
||||
// Hex editor colors
|
||||
COLOR_ENTRY(HEX_COLOR),
|
||||
COLOR_ENTRY(HEX_OFFSET_COLOR),
|
||||
COLOR_ENTRY(HEX_NIBBLE_COLOR),
|
||||
|
||||
// Text editor colors
|
||||
COLOR_ENTRY(TEXT_COLOR),
|
||||
COLOR_ENTRY(TEXT_FOCUS_COLOR),
|
||||
COLOR_ENTRY(TEXT_LINE_NUMBER_COLOR),
|
||||
COLOR_ENTRY(TEXT_LINE_NUMBER_COLOR_FOCUS),
|
||||
COLOR_ENTRY(TEXT_HIGHLIGHT_COLOR),
|
||||
|
||||
// Photo viewer colors
|
||||
COLOR_ENTRY(PHOTO_ZOOM_COLOR),
|
||||
};
|
||||
|
||||
// Load default config file
|
||||
@ -144,6 +196,9 @@ void loadTheme() {
|
||||
snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/context.png", theme_name);
|
||||
context_image = vita2d_load_PNG_file(path);
|
||||
|
||||
snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/context_more.png", theme_name);
|
||||
context_more_image = vita2d_load_PNG_file(path);
|
||||
|
||||
snprintf(path, MAX_PATH_LENGTH, "ux0:VitaShell/theme/%s/battery.png", theme_name);
|
||||
battery_image = vita2d_load_PNG_file(path);
|
||||
|
||||
@ -241,6 +296,19 @@ void loadTheme() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!context_more_image) {
|
||||
context_more_image = vita2d_create_empty_texture(SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
void *data = vita2d_texture_get_datap(context_more_image);
|
||||
|
||||
int y;
|
||||
for (y = 0; y < SCREEN_HEIGHT; y++) {
|
||||
int x;
|
||||
for (x = 0; x < SCREEN_WIDTH; x++) {
|
||||
((uint32_t *)data)[x + SCREEN_WIDTH * y] = CONTEXT_MENU_MORE_COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!battery_image)
|
||||
battery_image = vita2d_load_PNG_buffer(&_binary_resources_battery_png_start);
|
||||
|
||||
|
34
theme.h
34
theme.h
@ -21,28 +21,54 @@
|
||||
|
||||
#define MAX_WALLPAPERS 10
|
||||
|
||||
// Shell colors
|
||||
extern int BACKGROUND_COLOR;
|
||||
extern int GENERAL_COLOR;
|
||||
extern int TITLE_COLOR;
|
||||
extern int PATH_COLOR;
|
||||
extern int DATE_TIME_COLOR;
|
||||
|
||||
// File browser colors
|
||||
extern int FOCUS_COLOR;
|
||||
extern int FILE_COLOR;
|
||||
extern int SFO_COLOR;
|
||||
extern int TXT_COLOR;
|
||||
extern int FOLDER_COLOR;
|
||||
extern int IMAGE_COLOR;
|
||||
extern int ARCHIVE_COLOR;
|
||||
extern int SCROLL_BAR_COLOR;
|
||||
extern int SCROLL_BAR_BG_COLOR;
|
||||
extern int MARKED_COLOR;
|
||||
extern int INVISIBLE_COLOR;
|
||||
extern int DIALOG_BG_COLOR;
|
||||
|
||||
// Context menu colors
|
||||
extern int CONTEXT_MENU_TEXT_COLOR;
|
||||
extern int CONTEXT_MENU_FOCUS_COLOR;
|
||||
extern int CONTEXT_MENU_COLOR;
|
||||
extern int CONTEXT_MENU_MORE_COLOR;
|
||||
extern int INVISIBLE_COLOR;
|
||||
|
||||
// Dialog colors
|
||||
extern int DIALOG_COLOR;
|
||||
extern int DIALOG_BG_COLOR;
|
||||
extern int PROGRESS_BAR_COLOR;
|
||||
extern int PROGRESS_BAR_BG_COLOR;
|
||||
|
||||
// Hex editor colors
|
||||
extern int HEX_COLOR;
|
||||
extern int HEX_OFFSET_COLOR;
|
||||
extern int HEX_NIBBLE_COLOR;
|
||||
|
||||
// Text editor colors
|
||||
extern int TEXT_COLOR;
|
||||
extern int TEXT_FOCUS_COLOR;
|
||||
extern int TEXT_LINE_NUMBER_COLOR;
|
||||
extern int TEXT_LINE_NUMBER_COLOR_FOCUS;
|
||||
extern int TEXT_HIGHLIGHT_COLOR;
|
||||
|
||||
// Photo viewer colors
|
||||
extern int PHOTO_ZOOM_COLOR;
|
||||
|
||||
extern vita2d_texture *folder_icon, *file_icon, *archive_icon, *image_icon, *audio_icon, *sfo_icon, *text_icon,
|
||||
*ftp_image, *dialog_image, *context_image, *battery_image, *battery_bar_red_image, *battery_bar_green_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;
|
||||
|
||||
extern vita2d_texture *wallpaper_image[MAX_WALLPAPERS];
|
||||
|
@ -277,7 +277,7 @@ int drawUncommonDialog() {
|
||||
for (i = 0; i < len + 1; i++) {
|
||||
if (uncommon_dialog.msg[i] == '\n') {
|
||||
uncommon_dialog.msg[i] = '\0';
|
||||
pgf_draw_text(uncommon_dialog.x + SHELL_MARGIN_X, string_y, GENERAL_COLOR, FONT_SIZE, string);
|
||||
pgf_draw_text(uncommon_dialog.x + SHELL_MARGIN_X, string_y, DIALOG_COLOR, FONT_SIZE, string);
|
||||
uncommon_dialog.msg[i] = '\n';
|
||||
|
||||
string = uncommon_dialog.msg + i + 1;
|
||||
@ -285,7 +285,7 @@ int drawUncommonDialog() {
|
||||
}
|
||||
|
||||
if (uncommon_dialog.msg[i] == '\0') {
|
||||
pgf_draw_text(uncommon_dialog.x + SHELL_MARGIN_X, string_y, GENERAL_COLOR, FONT_SIZE, string);
|
||||
pgf_draw_text(uncommon_dialog.x + SHELL_MARGIN_X, string_y, DIALOG_COLOR, FONT_SIZE, string);
|
||||
string_y += FONT_Y_SPACE;
|
||||
}
|
||||
}
|
||||
@ -319,7 +319,7 @@ int drawUncommonDialog() {
|
||||
|
||||
char string[8];
|
||||
sprintf(string, "%d%%", uncommon_dialog.progress);
|
||||
pgf_draw_text(CENTER(SCREEN_WIDTH, vita2d_pgf_text_width(font, FONT_SIZE, string)), string_y + FONT_Y_SPACE, GENERAL_COLOR, FONT_SIZE, string);
|
||||
pgf_draw_text(CENTER(SCREEN_WIDTH, vita2d_pgf_text_width(font, FONT_SIZE, string)), string_y + FONT_Y_SPACE, DIALOG_COLOR, FONT_SIZE, string);
|
||||
|
||||
string_y += 2.0f * FONT_Y_SPACE;
|
||||
}
|
||||
@ -329,7 +329,7 @@ int drawUncommonDialog() {
|
||||
case SCE_MSG_DIALOG_BUTTON_TYPE_YESNO:
|
||||
case SCE_MSG_DIALOG_BUTTON_TYPE_OK_CANCEL:
|
||||
case SCE_MSG_DIALOG_BUTTON_TYPE_CANCEL:
|
||||
pgf_draw_text(CENTER(SCREEN_WIDTH, vita2d_pgf_text_width(font, FONT_SIZE, button_string)), string_y + FONT_Y_SPACE, GENERAL_COLOR, FONT_SIZE, button_string);
|
||||
pgf_draw_text(CENTER(SCREEN_WIDTH, vita2d_pgf_text_width(font, FONT_SIZE, button_string)), string_y + FONT_Y_SPACE, DIALOG_COLOR, FONT_SIZE, button_string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
10
utils.c
10
utils.c
@ -23,6 +23,7 @@
|
||||
#include "theme.h"
|
||||
#include "language.h"
|
||||
#include "utils.h"
|
||||
#include "bm.h"
|
||||
|
||||
SceCtrlData pad;
|
||||
uint32_t old_buttons, current_buttons, pressed_buttons, hold_buttons, hold2_buttons, released_buttons;
|
||||
@ -206,6 +207,10 @@ int holdButtons(SceCtrlData *pad, uint32_t buttons, uint64_t time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hasEndSlash(char *path) {
|
||||
return path[strlen(path) - 1] == '/';
|
||||
}
|
||||
|
||||
int removeEndSlash(char *path) {
|
||||
int len = strlen(path);
|
||||
|
||||
@ -315,4 +320,9 @@ int launchAppByUriExit(char *titleid) {
|
||||
sceKernelExitProcess(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *strcasestr(const char *haystack, const char *needle) {
|
||||
return boyer_moore(haystack, needle);
|
||||
}
|
3
utils.h
3
utils.h
@ -60,6 +60,7 @@ void powerUnlock();
|
||||
void readPad();
|
||||
int holdButtons(SceCtrlData *pad, uint32_t buttons, uint64_t time);
|
||||
|
||||
int hasEndSlash(char *path);
|
||||
int removeEndSlash(char *path);
|
||||
int addEndSlash(char *path);
|
||||
|
||||
@ -73,4 +74,6 @@ int debugPrintf(char *text, ...);
|
||||
|
||||
int launchAppByUriExit(char *titleid);
|
||||
|
||||
char *strcasestr(const char *haystack, const char *needle);
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user