2016-09-12 08:06:43 +00:00
|
|
|
// LightMP3
|
|
|
|
// Copyright (C) 2007 Sakya
|
|
|
|
// sakya_tg@yahoo.it
|
2016-09-11 14:59:31 +00:00
|
|
|
//
|
2016-09-12 08:06:43 +00:00
|
|
|
// 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
|
2016-09-11 14:59:31 +00:00
|
|
|
#include <psp2/io/fcntl.h>
|
2016-09-12 13:49:51 +00:00
|
|
|
#include <psp2/kernel/threadmgr.h>
|
2016-09-11 14:59:31 +00:00
|
|
|
#include <stdlib.h>
|
2016-09-12 08:06:43 +00:00
|
|
|
#include <stdio.h>
|
2016-09-11 14:59:31 +00:00
|
|
|
#include <string.h>
|
2016-09-12 08:06:43 +00:00
|
|
|
#include <limits.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "id3.h"
|
|
|
|
#include "mp3xing.h"
|
|
|
|
#include "player.h"
|
|
|
|
#include "mp3player.h"
|
2016-09-11 14:59:31 +00:00
|
|
|
|
|
|
|
#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.
|
|
|
|
*/
|
2016-09-12 08:06:43 +00:00
|
|
|
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};
|
2016-09-11 14:59:31 +00:00
|
|
|
|
|
|
|
/* DoFilter is non-nul when the Filter table defines a filter bank to
|
|
|
|
* be applied to the decoded audio subbands.
|
|
|
|
*/
|
2016-09-12 08:06:43 +00:00
|
|
|
static int DoFilter = 0;
|
2016-09-11 14:59:31 +00:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Global local variables
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
2016-09-12 08:06:43 +00:00
|
|
|
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
|
2018-08-27 15:16:07 +00:00
|
|
|
static int MP3_isPlaying; // Set to true when a mod is being played
|
2016-09-12 08:06:43 +00:00
|
|
|
static long MP3_suspendPosition = -1;
|
|
|
|
static long MP3_suspendIsPlaying = 0;
|
|
|
|
|
|
|
|
typedef struct {
|
2018-08-27 15:16:07 +00:00
|
|
|
short left;
|
|
|
|
short right;
|
2016-09-12 08:06:43 +00:00
|
|
|
} Sample;
|
2016-09-11 14:59:31 +00:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// These are the public functions
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
static int myChannel;
|
|
|
|
static int eos;
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
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){
|
2016-09-11 14:59:31 +00:00
|
|
|
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)
|
2018-08-27 15:16:07 +00:00
|
|
|
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]);
|
2016-09-11 14:59:31 +00:00
|
|
|
else
|
2018-08-27 15:16:07 +00:00
|
|
|
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]);
|
2016-09-11 14:59:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Converts a sample from libmad's fixed point number format to a signed
|
|
|
|
// short (16 bits).
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
short convertSample(mad_fixed_t sample) {
|
2018-08-27 15:16:07 +00:00
|
|
|
// round
|
|
|
|
sample += (1L << (MAD_F_FRACBITS - 16));
|
2016-09-12 08:06:43 +00:00
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
// clip
|
|
|
|
if (sample >= MAD_F_ONE)
|
|
|
|
sample = MAD_F_ONE - 1;
|
|
|
|
else if (sample < -MAD_F_ONE)
|
|
|
|
sample = -MAD_F_ONE;
|
2016-09-11 14:59:31 +00:00
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
// quantize
|
|
|
|
return sample >> (MAD_F_FRACBITS + 1 - 16);
|
2016-09-11 14:59:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Streaming functions (adapted from Ghoti's MusiceEngine.c):
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int fillFileBuffer() {
|
2018-08-27 15:16:07 +00:00
|
|
|
// 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){
|
|
|
|
int bytesRead = sceIoRead(MP3_fd, bufferPos, bytesToFill);
|
|
|
|
|
|
|
|
if (bytesRead == 0x80010013) {
|
|
|
|
MP3_fd = sceIoOpen(MP3_fileName, SCE_O_RDONLY, 0777);
|
|
|
|
if (MP3_fd >= 0) {
|
|
|
|
sceIoLseek32(MP3_fd, MP3_filePos, SCE_SEEK_SET);
|
|
|
|
}
|
2016-09-12 15:43:08 +00:00
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
bytesRead = sceIoRead(MP3_fd, bufferPos, bytesToFill);
|
|
|
|
}
|
2016-09-11 14:59:31 +00:00
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
// EOF?
|
|
|
|
if (bytesRead <= 0)
|
|
|
|
return 2;
|
2016-09-12 08:06:43 +00:00
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
// Adjust where we're writing to.
|
|
|
|
bytesToFill -= bytesRead;
|
|
|
|
bufferPos += bytesRead;
|
|
|
|
MP3_filePos += bytesRead;
|
|
|
|
}
|
|
|
|
return 0;
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void decode() {
|
2018-08-27 15:16:07 +00:00
|
|
|
while ((mad_frame_decode(&Frame, &Stream) == -1) && ((Stream.error == MAD_ERROR_BUFLEN) || (Stream.error == MAD_ERROR_BUFPTR))){
|
|
|
|
int tmp;
|
|
|
|
tmp = fillFileBuffer();
|
|
|
|
if (tmp==2)
|
2016-09-12 08:06:43 +00:00
|
|
|
eos = 1;
|
2018-08-27 15:16:07 +00:00
|
|
|
mad_stream_buffer(&Stream, fileBuffer, sizeof(fileBuffer));
|
|
|
|
}
|
2016-09-12 08:06:43 +00:00
|
|
|
//Equalizers and volume boost (NEW METHOD):
|
|
|
|
if (DoFilter || MP3_volume_boost)
|
|
|
|
ApplyFilter(&Frame);
|
|
|
|
|
|
|
|
mad_timer_add(&Timer, Frame.header.duration);
|
2018-08-27 15:16:07 +00:00
|
|
|
mad_synth_frame(&Synth, &Frame);
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void convertLeftSamples(Sample* first, Sample* last, const mad_fixed_t* src) {
|
2018-08-27 15:16:07 +00:00
|
|
|
Sample* dst;
|
|
|
|
for (dst = first; dst != last; ++dst){
|
|
|
|
dst->left = convertSample(*src++);
|
2016-09-12 08:06:43 +00:00
|
|
|
//Volume Boost (OLD METHOD):
|
|
|
|
if (MP3_volume_boost_old)
|
|
|
|
dst->left = volume_boost(&dst->left, &MP3_volume_boost_old);
|
2016-09-11 14:59:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
void convertRightSamples(Sample* first, Sample* last, const mad_fixed_t* src) {
|
2018-08-27 15:16:07 +00:00
|
|
|
Sample* dst;
|
|
|
|
for (dst = first; dst != last; ++dst){
|
|
|
|
dst->right = convertSample(*src++);
|
2016-09-12 08:06:43 +00:00
|
|
|
//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;
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
if (MP3_isPlaying == TRUE) { // Playing , so mix up a buffer
|
2016-09-12 08:06:43 +00:00
|
|
|
MP3_outputInProgress = 1;
|
2018-08-27 15:16:07 +00:00
|
|
|
while (samplesToWrite > 0) {
|
2016-09-12 08:06:43 +00:00
|
|
|
const unsigned int samplesAvailable = Synth.pcm.length - samplesRead;
|
|
|
|
if (samplesAvailable > samplesToWrite) {
|
|
|
|
convertLeftSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[0][samplesRead]);
|
2018-08-27 15:16:07 +00:00
|
|
|
if (MP3_channels == 2)
|
|
|
|
convertRightSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[1][samplesRead]);
|
|
|
|
else
|
|
|
|
convertRightSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[0][samplesRead]);
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
samplesRead += samplesToWrite;
|
|
|
|
samplesToWrite = 0;
|
|
|
|
|
|
|
|
if (MP3_newFilePos >= 0)
|
|
|
|
{
|
|
|
|
if (!MP3_newFilePos)
|
|
|
|
MP3_newFilePos = ID3v2TagSize(MP3_fileName);
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
int res = sceIoLseek32(MP3_fd, MP3_newFilePos, SCE_SEEK_SET);
|
|
|
|
if (res == 0x80010013) {
|
|
|
|
MP3_fd = sceIoOpen(MP3_fileName, SCE_O_RDONLY, 0777);
|
|
|
|
if (MP3_fd >= 0) {
|
|
|
|
sceIoLseek32(MP3_fd, MP3_filePos, SCE_SEEK_SET);
|
|
|
|
}
|
2016-09-12 15:43:08 +00:00
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
res = sceIoLseek32(MP3_fd, MP3_newFilePos, SCE_SEEK_SET);
|
|
|
|
}
|
2016-09-12 15:43:08 +00:00
|
|
|
|
|
|
|
if (res != MP3_filePos){
|
2016-09-12 08:06:43 +00:00
|
|
|
MP3_filePos = MP3_newFilePos;
|
|
|
|
mad_timer_set(&Timer, (int)((float)MP3_info.length / 100.0 * MP3_GetPercentage()), 1, 1);
|
|
|
|
}
|
|
|
|
MP3_newFilePos = -1;
|
|
|
|
}
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
//Check for playing speed:
|
2016-09-12 08:06:43 +00:00
|
|
|
if (MP3_playingSpeed){
|
2018-08-27 15:16:07 +00:00
|
|
|
int res = sceIoLseek32(MP3_fd, 2 * INPUT_BUFFER_SIZE * MP3_playingSpeed, SCE_SEEK_CUR);
|
|
|
|
if (res == 0x80010013) {
|
|
|
|
MP3_fd = sceIoOpen(MP3_fileName, SCE_O_RDONLY, 0777);
|
|
|
|
if (MP3_fd >= 0) {
|
|
|
|
sceIoLseek32(MP3_fd, MP3_filePos, SCE_SEEK_SET);
|
|
|
|
}
|
|
|
|
|
|
|
|
res = sceIoLseek32(MP3_fd, 2 * INPUT_BUFFER_SIZE * MP3_playingSpeed, SCE_SEEK_CUR);
|
|
|
|
}
|
2016-09-12 13:49:51 +00:00
|
|
|
|
|
|
|
if (res != MP3_filePos){
|
2016-09-12 08:06:43 +00:00
|
|
|
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]);
|
2018-08-27 15:16:07 +00:00
|
|
|
if (MP3_channels == 2)
|
|
|
|
convertRightSamples(destination, destination + samplesAvailable, &Synth.pcm.samples[1][samplesRead]);
|
|
|
|
else
|
|
|
|
convertRightSamples(destination, destination + samplesAvailable, &Synth.pcm.samples[0][samplesRead]);
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
samplesRead = 0;
|
|
|
|
decode();
|
|
|
|
|
|
|
|
destination += samplesAvailable;
|
|
|
|
samplesToWrite -= samplesAvailable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MP3_outputInProgress = 0;
|
2018-08-27 15:16:07 +00:00
|
|
|
} else { // Not Playing , so clear buffer
|
|
|
|
int count;
|
|
|
|
for (count = 0; count < samplesToWrite; count++){
|
|
|
|
destination[count].left = 0;
|
|
|
|
destination[count].right = 0;
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Init:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void MP3_Init(int channel){
|
|
|
|
initAudioLib();
|
2016-09-11 14:59:31 +00:00
|
|
|
myChannel = channel;
|
2016-09-12 08:06:43 +00:00
|
|
|
MP3_isPlaying = FALSE;
|
2018-08-27 15:16:07 +00:00
|
|
|
MP3_playingSpeed = 0;
|
|
|
|
MP3_volume_boost = 0;
|
2016-09-12 08:06:43 +00:00
|
|
|
MP3_volume_boost_old = 0;
|
|
|
|
|
|
|
|
initFileInfo(&MP3_info);
|
|
|
|
MP3_tagRead = 0;
|
|
|
|
|
2016-09-11 14:59:31 +00:00
|
|
|
vitaAudioSetChannelCallback(myChannel, MP3Callback,0);
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
MIN_PLAYING_SPEED=-119;
|
|
|
|
MAX_PLAYING_SPEED=119;
|
|
|
|
|
2016-09-11 14:59:31 +00:00
|
|
|
/* First the structures used by libmad must be initialized. */
|
|
|
|
mad_stream_init(&Stream);
|
2018-08-27 15:16:07 +00:00
|
|
|
mad_header_init(&Header);
|
2016-09-11 14:59:31 +00:00
|
|
|
mad_frame_init(&Frame);
|
|
|
|
mad_synth_init(&Synth);
|
|
|
|
mad_timer_reset(&Timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Free tune
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void MP3_FreeTune(){
|
|
|
|
sceIoClose(MP3_fd);
|
|
|
|
MP3_fd = -1;
|
2016-09-11 14:59:31 +00:00
|
|
|
/* Mad is no longer used, the structures that were initialized must
|
|
|
|
* now be cleared.
|
|
|
|
*/
|
|
|
|
mad_synth_finish(&Synth);
|
2016-09-12 08:06:43 +00:00
|
|
|
mad_header_finish(&Header);
|
2016-09-11 14:59:31 +00:00
|
|
|
mad_frame_finish(&Frame);
|
|
|
|
mad_stream_finish(&Stream);
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
2016-09-11 14:59:31 +00:00
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//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);
|
2018-08-27 15:16:07 +00:00
|
|
|
targetInfo->length = ID3.ID3Length;
|
2016-09-12 08:06:43 +00:00
|
|
|
targetInfo->encapsulatedPictureType = ID3.ID3EncapsulatedPictureType;
|
|
|
|
targetInfo->encapsulatedPictureOffset = ID3.ID3EncapsulatedPictureOffset;
|
|
|
|
targetInfo->encapsulatedPictureLength = ID3.ID3EncapsulatedPictureLength;
|
|
|
|
|
|
|
|
MP3_info = *targetInfo;
|
|
|
|
MP3_tagRead = 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int MP3getInfo(){
|
2018-08-27 15:16:07 +00:00
|
|
|
unsigned long FrameCount = 0;
|
2016-09-12 08:06:43 +00:00
|
|
|
int fd;
|
|
|
|
int bufferSize = 1024*496;
|
|
|
|
uint8_t *localBuffer;
|
|
|
|
|
|
|
|
int has_xing = 0;
|
|
|
|
struct xing xing;
|
2018-08-27 15:16:07 +00:00
|
|
|
memset(&xing, 0, sizeof xing);
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
long singleDataRed = 0;
|
2018-08-27 15:16:07 +00:00
|
|
|
struct mad_stream stream;
|
|
|
|
struct mad_header header;
|
2016-09-12 08:06:43 +00:00
|
|
|
int timeFromID3 = 0;
|
|
|
|
float mediumBitrate = 0.0f;
|
|
|
|
|
|
|
|
if (!MP3_tagRead)
|
|
|
|
getMP3TagInfo(MP3_fileName, &MP3_info);
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
mad_stream_init (&stream);
|
|
|
|
mad_header_init (&header);
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
fd = sceIoOpen(MP3_fileName, SCE_O_RDONLY, 0777);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
long size = sceIoLseek(fd, 0, SCE_SEEK_END);
|
2016-09-12 08:06:43 +00:00
|
|
|
sceIoLseek(fd, 0, SCE_SEEK_SET);
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
double startPos = ID3v2TagSize(MP3_fileName);
|
2016-09-12 08:06:43 +00:00
|
|
|
//Check for xing frame:
|
2018-08-27 15:16:07 +00:00
|
|
|
unsigned char *xing_buffer;
|
|
|
|
xing_buffer = (unsigned char *)malloc(XING_BUFFER_SIZE);
|
|
|
|
if (xing_buffer != NULL)
|
|
|
|
{
|
2016-09-12 08:06:43 +00:00
|
|
|
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);
|
2016-09-11 14:59:31 +00:00
|
|
|
}
|
2016-09-12 08:06:43 +00:00
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
sceIoLseek32(fd, startPos, SCE_SEEK_SET);
|
2016-09-12 08:06:43 +00:00
|
|
|
startPos = SeekNextFrameMP3(fd);
|
|
|
|
size -= startPos;
|
|
|
|
|
|
|
|
if (size < bufferSize * 3)
|
|
|
|
bufferSize = size;
|
|
|
|
localBuffer = (unsigned char *) malloc(sizeof(unsigned char) * bufferSize);
|
|
|
|
unsigned char *buff = localBuffer;
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
MP3_channels = 2;
|
|
|
|
MP3_info.fileType = MP3_TYPE;
|
2016-09-12 08:06:43 +00:00
|
|
|
MP3_info.defaultCPUClock = MP3_defaultCPUClock;
|
|
|
|
MP3_info.needsME = 0;
|
2018-08-27 15:16:07 +00:00
|
|
|
MP3_info.fileSize = size;
|
2016-09-12 08:06:43 +00:00
|
|
|
MP3_info.framesDecoded = 0;
|
|
|
|
|
|
|
|
double totalBitrate = 0;
|
|
|
|
int i = 0;
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
for (i=0; i<3; i++){
|
2016-09-12 08:06:43 +00:00
|
|
|
memset(localBuffer, 0, bufferSize);
|
|
|
|
singleDataRed = sceIoRead(fd, localBuffer, bufferSize);
|
2018-08-27 15:16:07 +00:00
|
|
|
mad_stream_buffer (&stream, localBuffer, singleDataRed);
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
while (1){
|
2018-08-27 15:16:07 +00:00
|
|
|
if (mad_header_decode (&header, &stream) == -1){
|
2016-09-12 08:06:43 +00:00
|
|
|
if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN)
|
|
|
|
break;
|
2018-08-27 15:16:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
//Check if lenght found in tag info:
|
|
|
|
if (MP3_info.length > 0){
|
|
|
|
timeFromID3 = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (has_xing)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
totalBitrate += header.bitrate;
|
2018-08-27 15:16:07 +00:00
|
|
|
}
|
2016-09-12 08:06:43 +00:00
|
|
|
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;
|
2018-08-27 15:16:07 +00:00
|
|
|
}
|
|
|
|
mad_header_finish (&header);
|
|
|
|
mad_stream_finish (&stream);
|
2016-09-12 08:06:43 +00:00
|
|
|
if (buff)
|
2018-08-27 15:16:07 +00:00
|
|
|
free(buff);
|
2016-09-12 08:06:43 +00:00
|
|
|
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);
|
2018-08-27 15:16:07 +00:00
|
|
|
MP3_info.length = secs;
|
|
|
|
}
|
2016-09-12 08:06:43 +00:00
|
|
|
else if (!MP3_info.length){
|
2018-08-27 15:16:07 +00:00
|
|
|
mediumBitrate = totalBitrate / (float)FrameCount;
|
|
|
|
secs = size * 8 / mediumBitrate;
|
2016-09-12 08:06:43 +00:00
|
|
|
MP3_info.length = secs;
|
|
|
|
}else{
|
|
|
|
secs = MP3_info.length;
|
|
|
|
}
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
//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);
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
return 0;
|
2016-09-11 14:59:31 +00:00
|
|
|
}
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//MP3_End
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void MP3_End(){
|
2016-09-11 14:59:31 +00:00
|
|
|
MP3_Stop();
|
|
|
|
vitaAudioSetChannelCallback(myChannel, 0,0);
|
|
|
|
MP3_FreeTune();
|
2016-09-12 08:06:43 +00:00
|
|
|
endAudioLib();
|
2016-09-11 14:59:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Load mp3 into memory:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int MP3_Load(char *filename){
|
2016-09-11 14:59:31 +00:00
|
|
|
eos = 0;
|
2018-08-27 15:16:07 +00:00
|
|
|
MP3_outputInProgress = 0;
|
2016-09-12 08:06:43 +00:00
|
|
|
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);
|
2018-08-27 15:16:07 +00:00
|
|
|
sceIoLseek32(MP3_fd, 0, SCE_SEEK_SET);
|
|
|
|
tagsize = ID3v2TagSize(filename);
|
|
|
|
sceIoLseek32(MP3_fd, tagsize, SCE_SEEK_SET);
|
2016-09-12 08:06:43 +00:00
|
|
|
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;
|
2016-09-11 14:59:31 +00:00
|
|
|
}
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
//Controllo il sample rate:
|
|
|
|
if (vitaAudioSetFrequency(myChannel, MP3_info.hz) < 0)
|
|
|
|
return ERROR_INVALID_SAMPLE_RATE;
|
|
|
|
return OPENING_OK;
|
2016-09-11 14:59:31 +00:00
|
|
|
}
|
|
|
|
|
2016-09-12 13:49:51 +00:00
|
|
|
int MP3_IsPlaying() {
|
2018-08-27 15:16:07 +00:00
|
|
|
return MP3_isPlaying;
|
2016-09-12 13:49:51 +00:00
|
|
|
}
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
2016-09-11 14:59:31 +00:00
|
|
|
// This function initialises for playing, and starts
|
2016-09-12 08:06:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int MP3_Play(){
|
2018-08-27 15:16:07 +00:00
|
|
|
//Azzero il timer:
|
2016-09-12 08:06:43 +00:00
|
|
|
if (eos == 1){
|
2018-08-27 15:16:07 +00:00
|
|
|
mad_timer_reset(&Timer);
|
|
|
|
}
|
2016-09-11 14:59:31 +00:00
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
// See if I'm already playing
|
2016-09-12 08:06:43 +00:00
|
|
|
if (MP3_isPlaying)
|
2018-08-27 15:16:07 +00:00
|
|
|
return FALSE;
|
2016-09-11 14:59:31 +00:00
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
MP3_isPlaying = TRUE;
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
return TRUE;
|
2016-09-11 14:59:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Pause:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void MP3_Pause(){
|
|
|
|
MP3_isPlaying = !MP3_isPlaying;
|
|
|
|
}
|
|
|
|
|
2016-09-11 14:59:31 +00:00
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Stop:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int MP3_Stop(){
|
|
|
|
//stop playing
|
|
|
|
MP3_isPlaying = FALSE;
|
|
|
|
while (MP3_outputInProgress == 1)
|
|
|
|
sceKernelDelayThread(100000);
|
2016-09-11 14:59:31 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Get time string
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void MP3_GetTimeString(char *dest){
|
2016-09-11 14:59:31 +00:00
|
|
|
mad_timer_string(Timer, dest, "%02lu:%02u:%02u", MAD_UNITS_HOURS, MAD_UNITS_MILLISECONDS, 0);
|
|
|
|
}
|
|
|
|
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Get Percentage
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
float MP3_GetPercentage(){
|
2018-08-27 15:16:07 +00:00
|
|
|
//Calcolo posizione in %:
|
|
|
|
float perc = 0.0f;
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
if (fileSize > 0){
|
2016-09-12 13:49:51 +00:00
|
|
|
perc = ((float)MP3_filePos) / ((float)fileSize - (float)tagsize) * 100.0;
|
2016-09-12 08:06:43 +00:00
|
|
|
if (perc > 100)
|
|
|
|
perc = 100;
|
|
|
|
}
|
|
|
|
return(perc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Check EOS
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int MP3_EndOfStream(){
|
2016-09-11 14:59:31 +00:00
|
|
|
if (eos == 1)
|
2018-08-27 15:16:07 +00:00
|
|
|
return 1;
|
2016-09-12 08:06:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Get info on file:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct fileInfo *MP3_GetInfo(){
|
2018-08-27 15:16:07 +00:00
|
|
|
return &MP3_info;
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Get only tag info from a file:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct fileInfo MP3_GetTagInfoOnly(char *filename){
|
|
|
|
struct fileInfo tempInfo;
|
|
|
|
initFileInfo(&tempInfo);
|
|
|
|
getMP3TagInfo(filename, &tempInfo);
|
2018-08-27 15:16:07 +00:00
|
|
|
return tempInfo;
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//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){
|
2018-08-27 15:16:07 +00:00
|
|
|
return(MP3_volume_boost);
|
2016-09-12 08:06:43 +00:00
|
|
|
}else{
|
|
|
|
return(MP3_volume_boost_old);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Set Filter:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int MP3_setFilter(double tFilter[32], int copyFilter){
|
2018-08-27 15:16:07 +00:00
|
|
|
//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);
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int MP3_isFilterSupported(){
|
2018-08-27 15:16:07 +00:00
|
|
|
return 1;
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Check if filter is enabled:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int MP3_isFilterEnabled(){
|
2018-08-27 15:16:07 +00:00
|
|
|
return DoFilter;
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Enable filter:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void MP3_enableFilter(){
|
2018-08-27 15:16:07 +00:00
|
|
|
DoFilter = 1;
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Disable filter:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void MP3_disableFilter(){
|
2018-08-27 15:16:07 +00:00
|
|
|
DoFilter = 0;
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Get playing speed:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int MP3_getPlayingSpeed(){
|
2018-08-27 15:16:07 +00:00
|
|
|
return MP3_playingSpeed;
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Set playing speed:
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int MP3_setPlayingSpeed(int playingSpeed){
|
2018-08-27 15:16:07 +00:00
|
|
|
if (playingSpeed >= MIN_PLAYING_SPEED && playingSpeed <= MAX_PLAYING_SPEED){
|
|
|
|
MP3_playingSpeed = playingSpeed;
|
|
|
|
if (playingSpeed == 0)
|
2016-09-12 08:06:43 +00:00
|
|
|
setVolume(myChannel, 0x8000);
|
2018-08-27 15:16:07 +00:00
|
|
|
else
|
|
|
|
setVolume(myChannel, FASTFORWARD_VOLUME);
|
|
|
|
return 0;
|
|
|
|
}else{
|
|
|
|
return -1;
|
|
|
|
}
|
2016-09-12 08:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//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;
|
2018-08-27 15:16:07 +00:00
|
|
|
/*MP3_Stop();
|
2016-09-12 08:06:43 +00:00
|
|
|
MP3_FreeTune();*/
|
|
|
|
|
2018-08-27 15:16:07 +00:00
|
|
|
MP3_isPlaying = FALSE;
|
2016-09-12 08:06:43 +00:00
|
|
|
mad_synth_finish(&Synth);
|
|
|
|
mad_header_finish(&Header);
|
|
|
|
mad_frame_finish(&Frame);
|
|
|
|
mad_stream_finish(&Stream);
|
|
|
|
|
|
|
|
sceIoClose(MP3_fd);
|
2018-08-27 15:16:07 +00:00
|
|
|
MP3_fd = -1;
|
2016-09-11 14:59:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2016-09-12 08:06:43 +00:00
|
|
|
|
|
|
|
int MP3_resume(){
|
2018-08-27 15:16:07 +00:00
|
|
|
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;
|
2016-09-12 08:06:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
double MP3_getFilePosition()
|
|
|
|
{
|
|
|
|
return MP3_filePos;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MP3_setFilePosition(double position)
|
|
|
|
{
|
|
|
|
MP3_newFilePos = position;
|
|
|
|
}
|