📄 mp3decode.cpp
字号:
/*
This file is part of MP3DecodeDLL for Symbian.
MP3DecodeDLL for Symbian
Copyright (C) 2004 Denis Mingulov <denis@mingulov.com>
MP3DecodeDLL for Symbian 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.
MP3DecodeDLL for Symbian 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 MP3DecodeDLL for Symbian; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "string.h"
#include "MP3Decode.h"
#define BUFFERSIZE 512
#include "math.h"
CMP3Decode::CMP3Decode() : bFileOpened(EFalse), iFileSession(NULL), iResampleRate(8000)
{
}
CMP3Decode::~CMP3Decode()
{
Close();
delete iInputBuf;
}
CMP3Decode * CMP3Decode::NewL()
{
CMP3Decode* iMP3Decode = CMP3Decode::NewLC();
CleanupStack::Pop(iMP3Decode);
return iMP3Decode;
}
CMP3Decode * CMP3Decode::NewLC()
{
CMP3Decode* iMP3Decode = new (ELeave) CMP3Decode();
CleanupStack::PushL(iMP3Decode);
iMP3Decode->ConstructL();
return iMP3Decode;
}
void CMP3Decode::ConstructL()
{
iInputBuf = new TPtr8((TUint8*)InputBuffer2, INPUT_BUFFER_SIZE, INPUT_BUFFER_SIZE);
}
TInt CMP3Decode::Open(RFs &aFileServer, const TDesC &aFileName)
{
iFileSession = &aFileServer;
strFileNameMP3.Copy(aFileName);
TInt iErr = InitMP3();
if(iErr)
bFileOpened = EFalse;
else
bFileOpened = ETrue;
return iErr;
}
TInt CMP3Decode::Close()
{
if(bFileOpened)
{
CloseMP3();
}
return 0;
}
TInt CMP3Decode::SetResampleRate(TInt aResampleRate)
{
iResampleRate = aResampleRate;
return 0;
}
TInt CMP3Decode::SetEqualizer (TInt aEq60, TInt aEq170, TInt aEq310, TInt aEq600, TInt aEq1K, TInt aEq3K, TInt aEq6K, TInt aEq12K, TInt aEq14K, TInt aEq16K, TInt aEqZero, TInt aEqDiv)
{
// 60, 170, 310, 600, 1K, 3K
iEqualizer[0] = mad_f_tofixed (pow (10,((double)(aEq60-aEqZero))/(double)aEqDiv));
iEqualizer[1] = mad_f_tofixed (pow (10,((double)(aEq170-aEqZero))/(double)aEqDiv));
iEqualizer[2] = mad_f_tofixed (pow (10,((double)(aEq310-aEqZero))/(double)aEqDiv));
iEqualizer[3] = mad_f_tofixed (pow (10,((double)(aEq600-aEqZero))/(double)aEqDiv));
iEqualizer[4] = mad_f_tofixed (pow (10,((double)(aEq1K-aEqZero))/(double)aEqDiv));
iEqualizer[5] = mad_f_tofixed (pow (10,((double)(aEq3K-aEqZero))/(double)aEqDiv));
//6K
iEqualizer[6] = mad_f_tofixed (pow (10,((double)(aEq6K-aEqZero))/(double)aEqDiv));
iEqualizer[7] = iEqualizer[6];
//12K
iEqualizer[8] = mad_f_tofixed (pow (10,((double)(aEq12K-aEqZero))/(double)aEqDiv));
iEqualizer[9] = iEqualizer[8];
iEqualizer[10] = iEqualizer[8];
iEqualizer[11] = iEqualizer[8];
//14K
iEqualizer[12] = mad_f_tofixed (pow (10,((double)(aEq14K-aEqZero))/(double)aEqDiv));
iEqualizer[13] = iEqualizer[12];
iEqualizer[14] = iEqualizer[12];
iEqualizer[15] = iEqualizer[12];
iEqualizer[16] = iEqualizer[12];
iEqualizer[17] = iEqualizer[12];
iEqualizer[18] = iEqualizer[12];
iEqualizer[19] = iEqualizer[12];
//16K
iEqualizer[20] = mad_f_tofixed (pow (10,((double)(aEq16K-aEqZero))/(double)aEqDiv));
iEqualizer[21] = iEqualizer[20];
iEqualizer[22] = iEqualizer[20];
iEqualizer[23] = iEqualizer[20];
iEqualizer[24] = iEqualizer[20];
iEqualizer[25] = iEqualizer[20];
iEqualizer[26] = iEqualizer[20];
iEqualizer[27] = iEqualizer[20];
iEqualizer[28] = iEqualizer[20];
iEqualizer[29] = iEqualizer[20];
iEqualizer[30] = iEqualizer[20];
iEqualizer[31] = iEqualizer[20];
return 0;
}
TInt CMP3Decode::GetFileLength()
{
TInt iLength=0;
if(iFile.Size(iLength)==KErrNone)
{
return iLength;
}
else
{
return 0;
}
}
TInt CMP3Decode::GetFilePosition()
{
TInt iPos=0;
if(iFile.Seek(ESeekCurrent, iPos)==KErrNone)
{
return iPos;
}
else
{
return 0;
}
}
TInt CMP3Decode::InitMP3()
{
TInt iErr=0;
iErr = iFile.Open(*iFileSession,strFileNameMP3,EFileRead|EFileShareReadersOnly);
SetEqualizer(100,100,100,100,100,100,100,100,100,100,100,20);
/* First the structures used by libmad must be initialized. */
mad_stream_init(&Stream);
mad_frame_init(&Frame);
mad_synth_init(&Synth);
mad_timer_reset(&Timer);
Status=0;
iOutputBufferCurrent=0;
return iErr;
}
TInt CMP3Decode::CloseMP3()
{
iFile.Close();
/* Mad is no longer used, the structures that were initialized must
* now be cleared.
*/
mad_synth_finish(&Synth);
mad_frame_finish(&Frame);
mad_stream_finish(&Stream);
return 0;
}
TInt CMP3Decode::DecodeOneFrame(TDes& aBuffer)
{
int iErr = DecodeOneFrameLow();
if(iErr==0&&iOutputBufferLength[iOutputBufferCurrent]==0)
{
iErr = DecodeOneFrameLow();
}
aBuffer.Copy((const TUint16*)OutputBuffer[iOutputBufferCurrent],iOutputBufferLength[iOutputBufferCurrent]);
return iErr;
}
int CMP3Decode::DecodeOneFrameLow()
// based on sources of
// madplay - MPEG audio decoder and player
// Copyright (C) 2000-2004 Robert Leslie
{
TInt16 *OutputPtr=OutputBuffer[iOutputBufferCurrent];
TInt16 *OutputBufferEnd=OutputPtr+OUTPUT_BUFFER_SIZE;
int iCycle=0;
iOutputBufferLength[iOutputBufferCurrent]=0;
for(iCycle=0;iCycle<1;iCycle++)
{
/* The input bucket must be filled if it becomes empty or if
* it's the first execution of the loop.
*/
if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN)
{
size_t ReadSize, ReadSize2,
Remaining;
unsigned char *ReadStart;
/* {2} libmad may not consume all bytes of the input
* buffer. If the last frame in the buffer is not wholly
* contained by it, then that frame's start is pointed by
* the next_frame member of the Stream structure. This
* common situation occurs when mad_frame_decode() fails,
* sets the stream error code to MAD_ERROR_BUFLEN, and
* sets the next_frame pointer to a non NULL value. (See
* also the comment marked {4} bellow.)
*
* When this occurs, the remaining unused bytes must be
* put back at the beginning of the buffer and taken in
* account before refilling the buffer. This means that
* the input buffer must be large enough to hold a whole
* frame at the highest observable bit-rate (currently 448
* kb/s). XXX=XXX Is 2016 bytes the size of the largest
* frame? (448000*(1152/32000))/8
*/
if(Stream.next_frame!=NULL)
{
// iFilePos+=Stream.next_frame-Stream.buffer;
Remaining=Stream.bufend-Stream.next_frame;
memmove(InputBuffer,Stream.next_frame,Remaining);
ReadStart=InputBuffer+Remaining;
ReadSize=INPUT_BUFFER_SIZE-Remaining;
/* ReadSize=INPUT_BUFFER_SIZE,
ReadStart=InputBuffer,
Remaining=0;*/
}
else
ReadSize=INPUT_BUFFER_SIZE,
ReadStart=InputBuffer,
Remaining=0;
/* Fill-in the buffer. If an error occurs print a message
* and leave the decoding loop. If the end of stream is
* reached we also leave the loop but the return status is
* left untouched.
*/
// fprintf(stderr,"file pos: %x\n",iFilePos);
// fseek(fr,iFilePos,SEEK_SET);
iInputBuf->SetLength(INPUT_BUFFER_SIZE);
iFile.Read(*iInputBuf,ReadSize);
// ReadSize=fread(ReadStart,1,ReadSize,fr);
ReadSize2=ReadSize;
ReadSize=iInputBuf->Length();
memmove(ReadStart,InputBuffer2,ReadSize);
if(ReadSize<=0)
{
// if(ferror(fr))
{
// fprintf(stderr,"%s: read error on bitstream (%s)\n",
// ProgName,strerror(errno));
// Status=1;
}
// if(feof(fr))
;//fprintf(stderr,"%s: end of input stream\n",ProgName);
return 1;
// break;
}
/* {3} When decoding the last frame of a file, it must be
* followed by MAD_BUFFER_GUARD zero bytes if one wants to
* decode that last frame. When the end of file is
* detected we append that quantity of bytes at the end of
* the available data. Note that the buffer can't overflow
* as the guard size was allocated but not used the the
* buffer managment code. (See also the comment marked
* {1}.)
*
* In a message to the mad-dev mailing list on May 29th,
* 2001, Rob leslie explains the guard zone as follows:
*
* "The reason for MAD_BUFFER_GUARD has to do with the
* way decoding is performed. In Layer III, Huffman
* decoding may inadvertently read a few bytes beyond
* the end of the buffer in the case of certain invalid
* input. This is not detected until after the fact. To
* prevent this from causing problems, and also to
* ensure the next frame's main_data_begin pointer is
* always accessible, MAD requires MAD_BUFFER_GUARD
* (currently 8) bytes to be present in the buffer past
* the end of the current frame in order to decode the
* frame."
*/
// if(feof(fr))
if(ReadSize!=ReadSize2)
{
memset(ReadStart+ReadSize,0,MAD_BUFFER_GUARD);
ReadSize+=MAD_BUFFER_GUARD;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -