our current experimental Neutrino branch

git-svn-id: file:///home/bas/coolstream_public_svn/THIRDPARTY/applications/neutrino-experimental@27 e54a6e83-5905-42d5-8d5c-058d10e6a962
This commit is contained in:
mrcolor
2009-12-08 11:05:11 +00:00
commit bc5bd4154e
876 changed files with 193775 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
AM_CPPFLAGS = -fno-rtti -fno-exceptions
INCLUDES = \
-I$(top_srcdir)/src \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/src/zapit/include \
-I$(top_srcdir)/lib/libconfigfile \
-I$(top_srcdir)/lib/libcoolstream \
@FREETYPE_CFLAGS@ \
@VORBISIDEC_CFLAGS@
noinst_LIBRARIES = libneutrino_driver_audiodec.a
libneutrino_driver_audiodec_a_SOURCES = \
basedec.cpp \
cdrdec.cpp \
mp3dec.cpp \
oggdec.cpp \
wavdec.cpp \
tag.c \
crc.c \
vis.cpp

View File

@@ -0,0 +1,241 @@
/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2004 Zwen
base decoder class
Homepage: http://www.cyberphoria.org/
Kommentar:
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <basedec.h>
#include <cdrdec.h>
#include <mp3dec.h>
#include <oggdec.h>
#include <wavdec.h>
#include <linux/soundcard.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <driver/netfile.h>
#include <driver/audioplay.h> // for ShoutcastCallback()
#include <global.h>
#include <neutrino.h>
#include <zapit/client/zapittools.h>
unsigned int CBaseDec::mSamplerate=0;
void ShoutcastCallback(void *arg)
{
CAudioPlayer::getInstance()->sc_callback(arg);
}
CBaseDec::RetCode CBaseDec::DecoderBase(CAudiofile* const in,
const int OutputFd, State* const state,
time_t* const t,
unsigned int* const secondsToSkip)
{
RetCode Status = OK;
FILE* fp = fopen( in->Filename.c_str(), "r" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file %s for decoding.\n",
in->Filename.c_str() );
Status = INTERNAL_ERR;
}
/* jump to first audio frame; audio_start_pos is only set for FILE_MP3 */
else if ( in->MetaData.audio_start_pos &&
fseek( fp, in->MetaData.audio_start_pos, SEEK_SET ) == -1 )
{
fprintf( stderr, "fseek() failed.\n" );
Status = INTERNAL_ERR;
}
if ( Status == OK )
{
if( in->FileType == CFile::STREAM_AUDIO )
{
if ( fstatus( fp, ShoutcastCallback ) < 0 )
{
fprintf( stderr, "Error adding shoutcast callback: %s",
err_txt );
}
if(ftype(fp, (char *) "ogg"))
{
Status = COggDec::getInstance()->Decoder( fp, OutputFd, state,
&in->MetaData, t,
secondsToSkip );
}
else
{
Status = CMP3Dec::getInstance()->Decoder( fp, OutputFd, state,
&in->MetaData, t,
secondsToSkip );
}
}
else if( in->FileType == CFile::FILE_MP3)
{
Status = CMP3Dec::getInstance()->Decoder( fp, OutputFd, state,
&in->MetaData, t,
secondsToSkip );
}
else if( in->FileType == CFile::FILE_OGG )
{
Status = COggDec::getInstance()->Decoder( fp, OutputFd, state,
&in->MetaData, t,
secondsToSkip );
}
else if( in->FileType == CFile::FILE_WAV )
{
Status = CWavDec::getInstance()->Decoder( fp, OutputFd, state,
&in->MetaData, t,
secondsToSkip );
}
else if( in->FileType == CFile::FILE_CDR )
{
Status = CCdrDec::getInstance()->Decoder( fp, OutputFd, state,
&in->MetaData, t,
secondsToSkip );
}
else
{
fprintf( stderr, "DecoderBase: Supplied filetype is not " );
fprintf( stderr, "supported by Audioplayer.\n" );
Status = INTERNAL_ERR;
}
if ( fclose( fp ) == EOF )
{
fprintf( stderr, "Could not close file %s.\n",
in->Filename.c_str() );
}
}
return Status;
}
bool CBaseDec::GetMetaDataBase(CAudiofile* const in, const bool nice)
{
bool Status = true;
if ( in->FileType == CFile::FILE_MP3 || in->FileType == CFile::FILE_OGG ||
in->FileType == CFile::FILE_WAV || in->FileType == CFile::FILE_CDR )
{
FILE* fp = fopen( in->Filename.c_str(), "r" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file %s for meta data reading.\n",
in->Filename.c_str() );
Status = false;
}
else
{
if(in->FileType == CFile::FILE_MP3)
{
Status = CMP3Dec::getInstance()->GetMetaData(fp, nice,
&in->MetaData);
}
else if(in->FileType == CFile::FILE_OGG)
{
Status = COggDec::getInstance()->GetMetaData(fp, nice,
&in->MetaData);
}
else if(in->FileType == CFile::FILE_WAV)
{
Status = CWavDec::getInstance()->GetMetaData(fp, nice,
&in->MetaData);
}
else if(in->FileType == CFile::FILE_CDR)
{
Status = CCdrDec::getInstance()->GetMetaData(fp, nice,
&in->MetaData);
}
if ( fclose( fp ) == EOF )
{
fprintf( stderr, "Could not close file %s.\n",
in->Filename.c_str() );
}
}
}
else
{
fprintf( stderr, "GetMetaDataBase: Filetype is not supported for " );
fprintf( stderr, "meta data reading.\n" );
Status = false;
}
return Status;
}
bool CBaseDec::SetDSP(int soundfd, int fmt, unsigned int dsp_speed, unsigned int channels)
{
bool crit_error=false;
if (::ioctl(soundfd, SNDCTL_DSP_RESET))
printf("reset failed\n");
if(::ioctl(soundfd, SNDCTL_DSP_SETFMT, &fmt))
printf("setfmt failed\n");
if(::ioctl(soundfd, SNDCTL_DSP_CHANNELS, &channels))
printf("channel set failed\n");
if (dsp_speed != mSamplerate)
{
// mute audio to reduce pops when changing samplerate (avia_reset)
//bool was_muted = avs_mute(true);
if (::ioctl(soundfd, SNDCTL_DSP_SPEED, &dsp_speed))
{
printf("speed set failed\n");
crit_error=true;
}
else
{
#if 0
unsigned int rs = 0;
::ioctl(soundfd, SNDCTL_DSP_SPEED, &rs);
mSamplerate = dsp_speed;
// disable iec aka digi out (avia reset enables it again)
//g_Zapit->IecOff();
#endif
}
//usleep(400000);
//if (!was_muted)
// avs_mute(false);
}
//printf("Debug: SNDCTL_DSP_RESET %d / SNDCTL_DSP_SPEED %d / SNDCTL_DSP_CHANNELS %d / SNDCTL_DSP_SETFMT %d\n",
// SNDCTL_DSP_RESET, SNDCTL_DSP_SPEED, SNDCTL_DSP_CHANNELS, SNDCTL_DSP_SETFMT);
return crit_error;
}
bool CBaseDec::avs_mute(bool mute)
{
return true;
}
void CBaseDec::Init()
{
mSamplerate=0;
}

View File

@@ -0,0 +1,63 @@
/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2004 Zwen
Decoder base class
Homepage: http://www.dbox2.info/
Kommentar:
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __BASE_DEC__
#define __BASE_DEC__
#include <stdio.h>
#include <driver/audiofile.h>
#include <driver/audiometadata.h>
class CBaseDec
{
public:
enum State {STOP = 0, STOP_REQ, PLAY, PAUSE, FF, REV};
enum RetCode { OK = 0, READ_ERR, WRITE_ERR, DSPSET_ERR, DATA_ERR, INTERNAL_ERR };
// the follwing two methods have to be implemented for new decoders
//@param secondsToSkip: a value of 0 indicates that normal FF/REV operation was requested
// a value > 0 indicates that *one* jump forwards (FF) or backwards (REV) was requested
virtual RetCode Decoder(FILE *, const int, State* const, CAudioMetaData*, time_t* const, unsigned int* const)=0;
virtual bool GetMetaData(FILE *in, const bool nice, CAudioMetaData* m)=0;
static RetCode DecoderBase(CAudiofile* const in, const int OutputFd,
State* const state, time_t* const t,
unsigned int* const secondsToSkip);
static bool GetMetaDataBase(CAudiofile* const in, const bool nice);
static void Init();
CBaseDec(){};
static bool SetDSP(int soundfd, int fmt, unsigned int dsp_speed, unsigned int channels);
private:
static bool avs_mute(bool mute);
unsigned static int mSamplerate;
};
#endif

View File

@@ -0,0 +1,65 @@
/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2004 thegoodguy
Homepage: http://www.dbox2.info/
Kommentar:
cdr audio decoder
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <cdrdec.h>
CCdrDec* CCdrDec::getInstance()
{
static CCdrDec* CdrDec = NULL;
if (CdrDec == NULL)
{
CdrDec = new CCdrDec();
}
return CdrDec;
}
bool CCdrDec::SetMetaData(FILE* in, CAudioMetaData* m)
{
header_size = 0;
fseek(in, 0, SEEK_END);
int filesize = ftell(in);
m->type = CAudioMetaData::CDR;
m->bitrate = 44100 * 2 * 2 * 8;
m->samplerate = 44100;
mBitsPerSample = 16;
mChannels = 2;
m->total_time = filesize / (44100 * 2 * 2);
m->type_info = "CDR / 2 channels / 16 bit";
m->changed=true;
return true;
}

View File

@@ -0,0 +1,43 @@
/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2004 thegoodguy
cdr audio decoder
Homepage: http://www.dbox2.info/
Kommentar:
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CDR_DEC__
#define __CDR_DEC__
#include <driver/audiodec/wavdec.h>
class CCdrDec : public CWavDec
{
public:
static CCdrDec* getInstance();
protected:
virtual bool SetMetaData(FILE* in, CAudioMetaData* m);
};
#endif

109
src/driver/audiodec/crc.c Normal file
View File

@@ -0,0 +1,109 @@
/*
* madplay - MPEG audio decoder and player
* Copyright (C) 2000-2004 Robert Leslie
*
* 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: crc.c,v 1.1 2004/08/28 14:11:58 rasc Exp $
*/
#ifdef INCLUDE_UNUSED_STUFF
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
//# include "global.h"
# include "crc.h"
/*
* It would be nice to use the code in libmad to compute all CRC-16 values,
* but unfortunately the LAME tag uses reflected CRCs whereas MPEG audio
* frames do not. Therefore we are forced to write yet another CRC routine.
*/
static
unsigned short const crc_table[256] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};
/*
* NAME: crc->compute()
* DESCRIPTION: calculate reflected CRC-16 value (polynomial 0x8005)
*/
unsigned short crc_compute(char const *data, unsigned int length,
unsigned short init)
{
register unsigned int crc;
for (crc = init; length >= 8; length -= 8) {
crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
}
switch (length) {
case 7: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
case 6: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
case 5: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
case 4: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
case 3: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
case 2: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
case 1: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
case 0: break;
}
return crc;
}
#endif /* INCLUDE_UNUSED_STUFF */

29
src/driver/audiodec/crc.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* madplay - MPEG audio decoder and player
* Copyright (C) 2000-2004 Robert Leslie
*
* 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: crc.h,v 1.1 2004/08/28 14:11:58 rasc Exp $
*/
#ifdef INCLUDE_UNUSED_STUFF
# ifndef __CRC_H__
# define __CRC_H__
unsigned short crc_compute(char const *, unsigned int, unsigned short);
# endif /* __CRC_H__ */
#endif /* INCLUDE_UNUSED_STUFF */

274
src/driver/audiodec/fft.c Normal file
View File

@@ -0,0 +1,274 @@
/* fft.c: Iterative implementation of a FFT
* Copyright (C) 1999 Richard Boulton <richard@tartarus.org>
* Convolution stuff by Ralph Loader <suckfish@ihug.co.nz>
*
* 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.
*/
/*
* TODO
* Remove compiling in of FFT_BUFFER_SIZE? (Might slow things down, but would
* be nice to be able to change size at runtime.)
* Finish making / checking thread-safety.
* More optimisations.
*/
#include "fft.h"
#include <stdlib.h>
#include <math.h>
#ifndef PI
#ifdef M_PI
#define PI M_PI
#else
#define PI 3.14159265358979323846 /* pi */
#endif
#endif
/* ########### */
/* # Structs # */
/* ########### */
struct _struct_fft_state {
/* Temporary data stores to perform FFT in. */
float real[FFT_BUFFER_SIZE];
float imag[FFT_BUFFER_SIZE];
};
/* ############################# */
/* # Local function prototypes # */
/* ############################# */
static void fft_prepare(const sound_sample *input, float * re, float * im);
static void fft_calculate(float * re, float * im);
static void fft_output(const float *re, const float *im, float *output);
static int reverseBits(unsigned int initial);
/* #################### */
/* # Global variables # */
/* #################### */
/* Table to speed up bit reverse copy */
static unsigned int bitReverse[FFT_BUFFER_SIZE];
/* The next two tables could be made to use less space in memory, since they
* overlap hugely, but hey. */
static float sintable[FFT_BUFFER_SIZE / 2];
static float costable[FFT_BUFFER_SIZE / 2];
/* ############################## */
/* # Externally called routines # */
/* ############################## */
/* --------- */
/* FFT stuff */
/* --------- */
/*
* Initialisation routine - sets up tables and space to work in.
* Returns a pointer to internal state, to be used when performing calls.
* On error, returns NULL.
* The pointer should be freed when it is finished with, by fft_close().
*/
fft_state *fft_init(void) {
fft_state *state;
unsigned int i;
state = (fft_state *) malloc (sizeof(fft_state));
if(!state) return NULL;
for(i = 0; i < FFT_BUFFER_SIZE; i++) {
bitReverse[i] = reverseBits(i);
}
for(i = 0; i < FFT_BUFFER_SIZE / 2; i++) {
float j = 2 * PI * i / FFT_BUFFER_SIZE;
costable[i] = cos(j);
sintable[i] = sin(j);
}
return state;
}
/*
* Do all the steps of the FFT, taking as input sound data (as described in
* sound.h) and returning the intensities of each frequency as floats in the
* range 0 to ((FFT_BUFFER_SIZE / 2) * 32768) ^ 2
*
* FIXME - the above range assumes no frequencies present have an amplitude
* larger than that of the sample variation. But this is false: we could have
* a wave such that its maximums are always between samples, and it's just
* inside the representable range at the places samples get taken.
* Question: what _is_ the maximum value possible. Twice that value? Root
* two times that value? Hmmm. Think it depends on the frequency, too.
*
* The input array is assumed to have FFT_BUFFER_SIZE elements,
* and the output array is assumed to have (FFT_BUFFER_SIZE / 2 + 1) elements.
* state is a (non-NULL) pointer returned by fft_init.
*/
void fft_perform(const sound_sample *input, float *output, fft_state *state) {
/* Convert data from sound format to be ready for FFT */
fft_prepare(input, state->real, state->imag);
/* Do the actual FFT */
fft_calculate(state->real, state->imag);
/* Convert the FFT output into intensities */
fft_output(state->real, state->imag, output);
}
/*
* Free the state.
*/
void fft_close(fft_state *state) {
if(state) free(state);
}
/* ########################### */
/* # Locally called routines # */
/* ########################### */
/*
* Prepare data to perform an FFT on
*/
static void fft_prepare(const sound_sample *input, float * re, float * im) {
unsigned int i;
float *realptr = re;
float *imagptr = im;
/* Get input, in reverse bit order */
for(i = 0; i < FFT_BUFFER_SIZE; i++) {
*realptr++ = input[bitReverse[i]];
*imagptr++ = 0;
}
}
/*
* Take result of an FFT and calculate the intensities of each frequency
* Note: only produces half as many data points as the input had.
* This is roughly a consequence of the Nyquist sampling theorm thingy.
* (FIXME - make this comment better, and helpful.)
*
* The two divisions by 4 are also a consequence of this: the contributions
* returned for each frequency are split into two parts, one at i in the
* table, and the other at FFT_BUFFER_SIZE - i, except for i = 0 and
* FFT_BUFFER_SIZE which would otherwise get float (and then 4* when squared)
* the contributions.
*/
static void fft_output(const float * re, const float * im, float *output) {
float *outputptr = output;
const float *realptr = re;
const float *imagptr = im;
float *endptr = output + FFT_BUFFER_SIZE / 2;
#ifdef DEBUG
unsigned int i, j;
#endif
while(outputptr <= endptr) {
*outputptr = (*realptr * *realptr) + (*imagptr * *imagptr);
outputptr++; realptr++; imagptr++;
}
/* Do divisions to keep the constant and highest frequency terms in scale
* with the other terms. */
*output /= 4;
*endptr /= 4;
#ifdef DEBUG
printf("Recalculated input:\n");
for(i = 0; i < FFT_BUFFER_SIZE; i++) {
float val_real = 0;
float val_imag = 0;
for(j = 0; j < FFT_BUFFER_SIZE; j++) {
float fact_real = cos(- 2 * j * i * PI / FFT_BUFFER_SIZE);
float fact_imag = sin(- 2 * j * i * PI / FFT_BUFFER_SIZE);
val_real += fact_real * re[j] - fact_imag * im[j];
val_imag += fact_real * im[j] + fact_imag * re[j];
}
printf("%5d = %8f + i * %8f\n", i,
val_real / FFT_BUFFER_SIZE,
val_imag / FFT_BUFFER_SIZE);
}
printf("\n");
#endif
}
/*
* Actually perform the FFT
*/
static void fft_calculate(float * re, float * im) {
unsigned int i, j, k;
unsigned int exchanges;
float fact_real, fact_imag;
float tmp_real, tmp_imag;
unsigned int factfact;
/* Set up some variables to reduce calculation in the loops */
exchanges = 1;
factfact = FFT_BUFFER_SIZE / 2;
/* Loop through the divide and conquer steps */
for(i = FFT_BUFFER_SIZE_LOG; i != 0; i--) {
/* In this step, we have 2 ^ (i - 1) exchange groups, each with
* 2 ^ (FFT_BUFFER_SIZE_LOG - i) exchanges
*/
/* Loop through the exchanges in a group */
for(j = 0; j != exchanges; j++) {
/* Work out factor for this exchange
* factor ^ (exchanges) = -1
* So, real = cos(j * PI / exchanges),
* imag = sin(j * PI / exchanges)
*/
fact_real = costable[j * factfact];
fact_imag = sintable[j * factfact];
/* Loop through all the exchange groups */
for(k = j; k < FFT_BUFFER_SIZE; k += exchanges << 1) {
int k1 = k + exchanges;
/* newval[k] := val[k] + factor * val[k1]
* newval[k1] := val[k] - factor * val[k1]
**/
#ifdef DEBUG
printf("%d %d %d\n", i,j,k);
printf("Exchange %d with %d\n", k, k1);
printf("Factor %9f + i * %8f\n", fact_real, fact_imag);
#endif
/* FIXME - potential scope for more optimization here? */
tmp_real = fact_real * re[k1] - fact_imag * im[k1];
tmp_imag = fact_real * im[k1] + fact_imag * re[k1];
re[k1] = re[k] - tmp_real;
im[k1] = im[k] - tmp_imag;
re[k] += tmp_real;
im[k] += tmp_imag;
#ifdef DEBUG
for(k1 = 0; k1 < FFT_BUFFER_SIZE; k1++) {
printf("%5d = %8f + i * %8f\n", k1, real[k1], imag[k1]);
}
#endif
}
}
exchanges <<= 1;
factfact >>= 1;
}
}
static int reverseBits(unsigned int initial) {
unsigned int reversed = 0, loop;
for(loop = 0; loop < FFT_BUFFER_SIZE_LOG; loop++) {
reversed <<= 1;
reversed += (initial & 1);
initial >>= 1;
}
return reversed;
}

43
src/driver/audiodec/fft.h Normal file
View File

@@ -0,0 +1,43 @@
/* fft.h: Header for iterative implementation of a FFT
* Copyright (C) 1999 Richard Boulton <richard@tartarus.org>
*
* 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.
*/
#ifndef _FFT_H_
#define _FFT_H_
#define FFT_BUFFER_SIZE_LOG 9
#define FFT_BUFFER_SIZE (1 << FFT_BUFFER_SIZE_LOG)
/* sound sample - should be an signed 16 bit value */
typedef short int sound_sample;
#ifdef __cplusplus
extern "C" {
#endif
/* FFT library */
typedef struct _struct_fft_state fft_state;
fft_state *fft_init (void);
void fft_perform (const sound_sample *input, float *output, fft_state *state);
void fft_close (fft_state *state);
#ifdef __cplusplus
}
#endif
#endif /* _FFT_H_ */

View File

@@ -0,0 +1,528 @@
/* fix_fft.c - Fixed-point Fast Fourier Transform */
/*
fix_fft() perform FFT or inverse FFT
window() applies a Hanning window to the (time) input
fix_loud() calculates the loudness of the signal, for
each freq point. Result is an integer array,
units are dB (values will be negative).
iscale() scale an integer value by (numer/denom).
fix_mpy() perform fixed-point multiplication.
Sinewave[1024] sinewave normalized to 32767 (= 1.0).
Loudampl[100] Amplitudes for lopudnesses from 0 to -99 dB.
Low_pass Low-pass filter, cutoff at sample_freq / 4.
All data are fixed-point short integers, in which
-32768 to +32768 represent -1.0 to +1.0. Integer arithmetic
is used for speed, instead of the more natural floating-point.
For the forward FFT (time -> freq), fixed scaling is
performed to prevent arithmetic overflow, and to map a 0dB
sine/cosine wave (i.e. amplitude = 32767) to two -6dB freq
coefficients; the one in the lower half is reported as 0dB
by fix_loud(). The return value is always 0.
For the inverse FFT (freq -> time), fixed scaling cannot be
done, as two 0dB coefficients would sum to a peak amplitude of
64K, overflowing the 32k range of the fixed-point integers.
Thus, the fix_fft() routine performs variable scaling, and
returns a value which is the number of bits LEFT by which
the output must be shifted to get the actual amplitude
(i.e. if fix_fft() returns 3, each value of fr[] and fi[]
must be multiplied by 8 (2**3) for proper scaling.
Clearly, this cannot be done within the fixed-point short
integers. In practice, if the result is to be used as a
filter, the scale_shift can usually be ignored, as the
result will be approximately correctly normalized as is.
TURBO C, any memory model; uses inline assembly for speed
and for carefully-scaled arithmetic.
Written by: Tom Roberts 11/8/89
Made portable: Malcolm Slaney 12/15/94 malcolm@interval.com
Timing on a Macintosh PowerBook 180.... (using Symantec C6.0)
fix_fft (1024 points) 8 ticks
fft (1024 points - Using SANE) 112 Ticks
fft (1024 points - Using FPU) 11
*/
/* FIX_MPY() - fixed-point multiplication macro.
This macro is a statement, not an expression (uses asm).
BEWARE: make sure _DX is not clobbered by evaluating (A) or DEST.
args are all of type fixed.
Scaling ensures that 32767*32767 = 32767. */
#define dosFIX_MPY(DEST,A,B) { \
_DX = (B); \
_AX = (A); \
asm imul dx; \
asm add ax,ax; \
asm adc dx,dx; \
DEST = _DX; }
#define FIX_MPY(DEST,A,B) DEST = ((long)(A) * (long)(B))>>15
#define N_WAVE 1024 /* dimension of Sinewave[] */
#define LOG2_N_WAVE 10 /* log2(N_WAVE) */
#define N_LOUD 100 /* dimension of Loudampl[] */
#ifndef fixed
#define fixed short
#endif
extern fixed Sinewave[N_WAVE]; /* placed at end of this file for clarity */
extern fixed Loudampl[N_LOUD];
int db_from_ampl(fixed re, fixed im);
fixed fix_mpy(fixed a, fixed b);
/*
fix_fft() - perform fast Fourier transform.
if n>0 FFT is done, if n<0 inverse FFT is done
fr[n],fi[n] are real,imaginary arrays, INPUT AND RESULT.
size of data = 2**m
set inverse to 0=dft, 1=idft
*/
int fix_fft(fixed fr[], fixed fi[], int m, int inverse)
{
int mr,nn,i,j,l,k,istep, n, scale, shift;
fixed qr,qi,tr,ti,wr,wi;
n = 1<<m;
if(n > N_WAVE)
return -1;
mr = 0;
nn = n - 1;
scale = 0;
/* decimation in time - re-order data */
for(m=1; m<=nn; ++m) {
l = n;
do {
l >>= 1;
} while(mr+l > nn);
mr = (mr & (l-1)) + l;
if(mr <= m) continue;
tr = fr[m];
fr[m] = fr[mr];
fr[mr] = tr;
ti = fi[m];
fi[m] = fi[mr];
fi[mr] = ti;
}
l = 1;
k = LOG2_N_WAVE-1;
while(l < n) {
if(inverse) {
/* variable scaling, depending upon data */
shift = 0;
for(i=0; i<n; ++i) {
j = fr[i];
if(j < 0)
j = -j;
m = fi[i];
if(m < 0)
m = -m;
if(j > 16383 || m > 16383) {
shift = 1;
break;
}
}
if(shift)
++scale;
} else {
/* fixed scaling, for proper normalization -
there will be log2(n) passes, so this
results in an overall factor of 1/n,
distributed to maximize arithmetic accuracy. */
shift = 1;
}
/* it may not be obvious, but the shift will be performed
on each data point exactly once, during this pass. */
istep = l << 1;
for(m=0; m<l; ++m) {
j = m << k;
/* 0 <= j < N_WAVE/2 */
wr = Sinewave[j+N_WAVE/4];
wi = -Sinewave[j];
if(inverse)
wi = -wi;
if(shift) {
wr >>= 1;
wi >>= 1;
}
for(i=m; i<n; i+=istep) {
j = i + l;
tr = fix_mpy(wr,fr[j]) -
fix_mpy(wi,fi[j]);
ti = fix_mpy(wr,fi[j]) +
fix_mpy(wi,fr[j]);
qr = fr[i];
qi = fi[i];
if(shift) {
qr >>= 1;
qi >>= 1;
}
fr[j] = qr - tr;
fi[j] = qi - ti;
fr[i] = qr + tr;
fi[i] = qi + ti;
}
}
--k;
l = istep;
}
return scale;
}
/* window() - apply a Hanning window */
void window(fixed fr[], int n)
{
int i,j,k;
j = N_WAVE/n;
n >>= 1;
for(i=0,k=N_WAVE/4; i<n; ++i,k+=j)
FIX_MPY(fr[i],fr[i],16384-(Sinewave[k]>>1));
n <<= 1;
for(k-=j; i<n; ++i,k-=j)
FIX_MPY(fr[i],fr[i],16384-(Sinewave[k]>>1));
}
/* fix_loud() - compute loudness of freq-spectrum components.
n should be ntot/2, where ntot was passed to fix_fft();
6 dB is added to account for the omitted alias components.
scale_shift should be the result of fix_fft(), if the time-series
was obtained from an inverse FFT, 0 otherwise.
loud[] is the loudness, in dB wrt 32767; will be +10 to -N_LOUD.
*/
void fix_loud(fixed loud[], fixed fr[], fixed fi[], int n, int scale_shift)
{
int i, max;
max = 0;
if(scale_shift > 0)
max = 10;
scale_shift = (scale_shift+1) * 6;
for(i=0; i<n; ++i) {
loud[i] = db_from_ampl(fr[i],fi[i]) + scale_shift;
if(loud[i] > max)
loud[i] = max;
}
}
/* db_from_ampl() - find loudness (in dB) from
the complex amplitude.
*/
int db_from_ampl(fixed re, fixed im)
{
static long loud2[N_LOUD] = {0};
long v;
int i;
if(loud2[0] == 0) {
loud2[0] = (long)Loudampl[0] * (long)Loudampl[0];
for(i=1; i<N_LOUD; ++i) {
v = (long)Loudampl[i] * (long)Loudampl[i];
loud2[i] = v;
loud2[i-1] = (loud2[i-1]+v) / 2;
}
}
v = (long)re * (long)re + (long)im * (long)im;
for(i=0; i<N_LOUD; ++i)
if(loud2[i] <= v)
break;
return (-i);
}
/*
fix_mpy() - fixed-point multiplication
*/
fixed fix_mpy(fixed a, fixed b)
{
FIX_MPY(a,a,b);
return a;
}
/*
iscale() - scale an integer value by (numer/denom)
*/
int iscale(int value, int numer, int denom)
{
#ifdef DOS
asm mov ax,value
asm imul WORD PTR numer
asm idiv WORD PTR denom
return _AX;
#else
return (long) value * (long)numer/(long)denom;
#endif
}
/*
fix_dot() - dot product of two fixed arrays
*/
fixed fix_dot(fixed *hpa, fixed *pb, int n)
{
fixed *pa;
long sum;
register fixed a,b;
//unsigned int seg,off;
/* seg = FP_SEG(hpa);
off = FP_OFF(hpa);
seg += off>>4;
off &= 0x000F;
pa = MK_FP(seg,off);
*/
sum = 0L;
while(n--) {
a = *pa++;
b = *pb++;
FIX_MPY(a,a,b);
sum += a;
}
if(sum > 0x7FFF)
sum = 0x7FFF;
else if(sum < -0x7FFF)
sum = -0x7FFF;
return (fixed)sum;
#ifdef DOS
/* ASSUMES hpa is already normalized so FP_OFF(hpa) < 16 */
asm push ds
asm lds si,hpa
asm les di,pb
asm xor bx,bx
asm xor cx,cx
loop: /* intermediate values can overflow by a factor of 2 without
causing an error; the final value must not overflow! */
asm lodsw
.
asm imul word ptr es:[di]
asm add bx,ax
asm adc cx,dx
asm jo overflow
asm add di,2
asm dec word ptr n
asm jg loop
asm add bx,bx
asm adc cx,cx
asm jo overflow
asm pop ds
return _CX;
overflow:
asm mov cx,7FFFH
asm adc cx,0
asm pop ds
return _CX;
#endif
}
#if N_WAVE != 1024
ERROR: N_WAVE != 1024
#endif
fixed Sinewave[1024] = {
0, 201, 402, 603, 804, 1005, 1206, 1406,
1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011,
3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608,
4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195,
6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766,
7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319,
9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849,
11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353,
12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827,
14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268,
15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672,
16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036,
18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357,
19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631,
20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855,
22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027,
23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143,
24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201,
25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198,
26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132,
27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001,
28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802,
28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534,
29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195,
30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783,
30851, 30918, 30984, 31049,
31113, 31175, 31236, 31297,
31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735,
31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097,
32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382,
32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588,
32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717,
32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766,
32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736,
32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628,
32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441,
32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176,
32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833,
31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413,
31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918,
30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349,
30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706,
29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992,
28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208,
28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355,
27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437,
26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456,
25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413,
24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311,
23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153,
22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942,
20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680,
19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371,
18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017,
16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623,
15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191,
14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724,
12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227,
11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703,
9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156,
7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589,
6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006,
4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411,
3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808,
1607, 1406, 1206, 1005, 804, 603, 402, 201,
0, -201, -402, -603, -804, -1005, -1206, -1406,
-1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011,
-3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608,
-4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195,
-6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766,
-7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319,
-9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849,
-11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
-12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
-14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
-15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
-16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
-18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
-19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
-20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
-22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
-23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
-24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
-25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
-26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
-27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
-28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
-28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
-29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
-30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
-30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
-31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
-31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
-32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
-32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
-32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
-32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
-32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736,
-32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628,
-32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
-32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176,
-32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833,
-31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413,
-31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918,
-30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349,
-30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706,
-29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992,
-28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208,
-28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
-27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437,
-26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456,
-25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413,
-24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311,
-23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153,
-22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942,
-20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680,
-19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371,
-18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
-16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623,
-15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191,
-14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724,
-12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227,
-11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703,
-9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156,
-7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589,
-6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006,
-4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411,
-3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808,
-1607, -1406, -1206, -1005, -804, -603, -402, -201,
};
#if N_LOUD != 100
ERROR: N_LOUD != 100
#endif
fixed Loudampl[100] = {
32767, 29203, 26027, 23197, 20674, 18426, 16422, 14636,
13044, 11626, 10361, 9234, 8230, 7335, 6537, 5826,
5193, 4628, 4125, 3676, 3276, 2920, 2602, 2319,
2067, 1842, 1642, 1463, 1304, 1162, 1036, 923,
823, 733, 653, 582, 519, 462, 412, 367,
327, 292, 260, 231, 206, 184, 164, 146,
130, 116, 103, 92, 82, 73, 65, 58,
51, 46, 41, 36, 32, 29, 26, 23,
20, 18, 16, 14, 13, 11, 10, 9,
8, 7, 6, 5, 5, 4, 4, 3,
3, 2, 2, 2, 2, 1, 1, 1,
1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0,
};
#ifdef MAIN
#include <stdio.h>
#include <math.h>
#define M 4
#define N (1<<M)
main(){
fixed real[N], imag[N];
int i;
for (i=0; i<N; i++){
real[i] = 1000*cos(i*2*3.1415926535/N);
imag[i] = 0;
}
fix_fft(real, imag, M, 0;
for (i=0; i<N; i++){
printf("%d: %d, %d\n", i, real[i], imag[i]);
}
fix_fft(real, imag, M, 1);
for (i=0; i<N; i++){
printf("%d: %d, %d\n", i, real[i], imag[i]);
}
}
#endif /* MAIN */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2002 Bjoern Kalkbrenner <terminar@cyberphoria.org>
Copyright (C) 2002,2003 Dirch
Copyright (C) 2002,2003,2004 Zwen
libmad MP3 low-level core
Homepage: http://www.dbox2.info/
Kommentar:
based on
************************************
*** madlld -- Mad low-level *** v 1.0p1, 2002-01-08
*** demonstration/decoder *** (c) 2001, 2002 Bertrand Petit
************************************
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MP3_DEC__
#define __MP3_DEC__
#include <mad.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <basedec.h>
#include <driver/audiometadata.h>
extern "C"
{
#include "driver/audiodec/tag.h"
}
class CMP3Dec : public CBaseDec
{
private:
#if !((MAD_VERSION_MAJOR>=1) || \
((MAD_VERSION_MAJOR==0) && \
(((MAD_VERSION_MINOR==14) && \
(MAD_VERSION_PATCH>=2)) || \
(MAD_VERSION_MINOR>14))))
const char* MadErrorString(const struct mad_stream *Stream);
#endif
signed short MadFixedToSShort(const mad_fixed_t Fixed, bool left = false);
void CreateInfo(CAudioMetaData* const, const int);
bool GetMP3Info(FILE*, const bool, CAudioMetaData* const);
void GetID3(FILE*, CAudioMetaData* const);
long scanHeader( FILE*, struct mad_header* const, struct tag* const,
const bool );
public:
static CMP3Dec* getInstance();
virtual RetCode Decoder(FILE *InputFp, const int OutputFd,
State* const state, CAudioMetaData* m,
time_t* const t, unsigned int* const secondsToSkip);
bool GetMetaData(FILE *in, const bool nice, CAudioMetaData* const m);
CMP3Dec(){};
};
#endif

View File

@@ -0,0 +1,348 @@
/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2004 Sania, Zwen
Homepage: http://www.dbox2.info/
Kommentar:
ogg vorbis audio decoder
uses tremor libvorbisidec
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <oggdec.h>
#include <linux/soundcard.h>
#include <algorithm>
#include <sstream>
#include <driver/netfile.h>
#include <audio_cs.h>
extern cAudio * audioDecoder;
#define ProgName "OggDec"
// nr of msecs to skip in ff/rev mode
#define MSECS_TO_SKIP 3000
// nr of msecs to play in ff/rev mode
#define MSECS_TO_PLAY 200
/* at first, define our own callback functions used in */
/* tremor to access the data. These functions are simple mappers */
size_t ogg_read(void *buf, size_t size, size_t nmemb, void *data)
{
return fread(buf, size, nmemb, (FILE*)data);
}
int ogg_seek(void *data, ogg_int64_t offset, int whence)
{
return fseek((FILE*)data, (long)offset, whence);
}
int ogg_close(void *data)
{
return 0;
}
long ogg_tell(void *data)
{
return ftell((FILE*)data);
}
#define PCMBUFFER 4096 //4096 max for libtremor
#define MAX_OUTPUT_SAMPLES 2048 /* AVIA_GT_PCM_MAX_SAMPLES-1 */
CBaseDec::RetCode COggDec::Decoder(FILE *in, const int OutputFd, State* const state, CAudioMetaData* meta_data, time_t* const time_played, unsigned int* const secondsToSkip)
{
OggVorbis_File vf;
int bitstream, rval;
ogg_int64_t jumptime=0;
Status=OK;
mOutputFd = OutputFd;
mState = state;
mTimePlayed=time_played;
if (!Open(in, &vf))
{
Status=DATA_ERR;
return Status;
}
SetMetaData(&vf, meta_data);
audioDecoder->PrepareClipPlay(ov_info(&vf,0)->channels, ov_info(&vf,0)->rate, 16, 1);
/* up and away ... */
mSlotSize = MAX_OUTPUT_SAMPLES * 2 * ov_info(&vf,0)->channels;
for(int i = 0 ; i < DECODE_SLOTS ; i++)
{
if ((mPcmSlots[i] = (char*) malloc(mSlotSize)) == NULL)
{
for (int j = i - 1; j >= 0; j--)
{
free(mPcmSlots[j]);
}
Status=INTERNAL_ERR;
return Status;
}
mSlotTime[i]=0;
}
mReadSlot=mWriteSlot=0;
pthread_t OutputThread;
if (pthread_create (&OutputThread, 0, OutputDsp, (void *) this) != 0 )
{
for(int i = 0 ; i < DECODE_SLOTS ; i++)
free(mPcmSlots[i]);
Status=INTERNAL_ERR;
return Status;
}
int bytes;
State oldstate=*state;
do
{
// clear buffer on state change
if(oldstate!=*state)
{
if(*state!=PAUSE && (*state!=PLAY || oldstate!=PAUSE))
{
mWriteSlot=mReadSlot=0;
oldstate=*state;
}
}
while((mWriteSlot+1)%DECODE_SLOTS == mReadSlot)
{
usleep(10000);
}
bytes=0;
if(mSeekable)
#ifdef DBOX
mSlotTime[mWriteSlot] = ov_time_tell(&vf);
#else
mSlotTime[mWriteSlot] = (ogg_int64_t)(1000 * ov_time_tell(&vf));
#endif
do
{
#ifdef DBOX
rval = ov_read(&vf, mPcmSlots[mWriteSlot]+bytes, mSlotSize-bytes, &bitstream);
#else
rval = ov_read(&vf, mPcmSlots[mWriteSlot]+bytes, mSlotSize-bytes, 0, 2, 1, &bitstream);
#endif
bytes+=rval;
//printf("Ogg: read buf 0x%x size %d / %d done %d\n", mPcmSlots[mWriteSlot]+bytes, rval, mSlotSize, bytes);
} while (rval > 0 && bytes !=mSlotSize);
//printf("\n");
int actMSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip * 1000 : MSECS_TO_SKIP;
if((*state==FF || *state==REV) && mSeekable )
{
if((std::abs((long int)( mSlotTime[mWriteSlot]-jumptime))) > MSECS_TO_PLAY)
{
if(*state==FF)
{
ov_time_seek_page(&vf, mSlotTime[mWriteSlot] + actMSecsToSkip);
jumptime=mSlotTime[mWriteSlot]+actMSecsToSkip;
}
else
{
if(mSlotTime[mWriteSlot] < actMSecsToSkip)
{
ov_time_seek(&vf, 0);
*state=PLAY;
}
else
{
ov_time_seek_page(&vf, mSlotTime[mWriteSlot] - actMSecsToSkip);
jumptime=mSlotTime[mWriteSlot]-actMSecsToSkip;
}
}
}
if (*secondsToSkip != 0) {
*state=PLAY;
}
}
if(bytes == mSlotSize)
mWriteSlot=(mWriteSlot+1) % DECODE_SLOTS;
} while (rval != 0 && *state!=STOP_REQ && Status==OK);
//printf("COggDec::Decoder: read loop stop, rval %d state %d status %d\n", rval, *state, Status);
// let buffer run dry
while(rval==0 && *state!=STOP_REQ && Status==OK && mReadSlot != mWriteSlot)
usleep(100000);
//pthread_cancel(OutputThread);
//printf("COggDec::Decoder: OutputThread join\n");
Status = WRITE_ERR;
pthread_join(OutputThread, NULL);
//printf("COggDec::Decoder: OutputThread join done\n");
audioDecoder->StopClip();
for(int i = 0 ; i < DECODE_SLOTS ; i++)
free(mPcmSlots[i]);
/* clean up the junk from the party */
ov_clear(&vf);
/* and drive home ;) */
return Status;
}
void* COggDec::OutputDsp(void * arg)
{
COggDec* dec = (COggDec*) arg;
while(dec->Status == OK/*true*/)
{
while(dec->mReadSlot==dec->mWriteSlot || *dec->mState==PAUSE)
{
if(dec->Status != OK)
return NULL;
usleep(10000);
}
//if (write(dec->mOutputFd, dec->mPcmSlots[dec->mReadSlot], dec->mSlotSize) != dec->mSlotSize)
if (audioDecoder->WriteClip((unsigned char *)dec->mPcmSlots[dec->mReadSlot], dec->mSlotSize) != dec->mSlotSize)
{
fprintf(stderr,"%s: PCM write error (%s).\n", ProgName, strerror(errno));
dec->Status=WRITE_ERR;
break;
}
*dec->mTimePlayed = (int)(dec->mSlotTime[dec->mReadSlot]/1000);
dec->mReadSlot=(dec->mReadSlot+1)%DECODE_SLOTS;
}
return NULL;
}
bool COggDec::GetMetaData(FILE *in, const bool nice, CAudioMetaData* m)
{
OggVorbis_File vf;
if (!Open(in, &vf))
{
return false;
}
SetMetaData(&vf, m);
ov_clear(&vf);
return true;
}
COggDec* COggDec::getInstance()
{
static COggDec* OggDec = NULL;
if(OggDec == NULL)
{
OggDec = new COggDec();
}
return OggDec;
}
void COggDec::ParseUserComments(vorbis_comment* vc, CAudioMetaData* m)
{
for(int i=0; i < vc->comments ; i++)
{
char* search;
if((search=strstr(vc->user_comments[i],"Artist"))!=NULL ||
(search=strstr(vc->user_comments[i],"ARTIST"))!=NULL)
m->artist = search+7;
else if((search=strstr(vc->user_comments[i],"Album"))!=NULL ||
(search=strstr(vc->user_comments[i],"ALBUM"))!=NULL)
m->album = search+6;
else if((search=strstr(vc->user_comments[i],"Title"))!=NULL ||
(search=strstr(vc->user_comments[i],"TITLE"))!=NULL)
m->title = search+6;
else if((search=strstr(vc->user_comments[i],"Genre"))!=NULL ||
(search=strstr(vc->user_comments[i],"GENRE"))!=NULL)
m->genre = search+6;
else if((search=strstr(vc->user_comments[i],"Date"))!=NULL ||
(search=strstr(vc->user_comments[i],"DATE"))!=NULL)
m->date = search+5;
else if((search=strstr(vc->user_comments[i],"TrackNumber"))!=NULL ||
(search=strstr(vc->user_comments[i],"TRACKNUMBER"))!=NULL)
m->track = search+12;
}
}
void COggDec::SetMetaData(OggVorbis_File* vf, CAudioMetaData* m)
{
/* Set Metadata */
m->type = CAudioMetaData::OGG;
m->bitrate = ov_info(vf,0)->bitrate_nominal;
m->samplerate = ov_info(vf,0)->rate;
if(mSeekable)
#ifdef DBOX
m->total_time = (time_t) ov_time_total(vf, 0) / 1000;
#else
m->total_time = (time_t) ov_time_total(vf, 0);
#endif
std::stringstream ss;
ss << "OGG V." << ov_info(vf,0)->version << " / " << ov_info(vf,0)->channels << "channel(s)";
m->type_info = ss.str();
ParseUserComments(ov_comment(vf, 0), m);
m->changed=true;
}
bool COggDec::Open(FILE* in, OggVorbis_File* vf)
{
int rval;
ov_callbacks cb;
/* we need to use our own functions, because we have */
/* the netfile layer hooked in here. If we would not */
/* provide callbacks, the tremor lib and the netfile */
/* layer would clash and steal each other the data */
/* from the stream ! */
cb.read_func = ogg_read;
cb.seek_func = ogg_seek;
cb.close_func = ogg_close;
cb.tell_func = ogg_tell;
/* test the dope ... */
//rval = ov_test_callbacks((void*)in, vf, NULL, 0, cb);
rval = ov_open_callbacks(in, vf, NULL, 0, cb);
/* and tell our friends about the quality of the stuff */
// initialize the sound device here
if(rval<0)
{
switch(rval)
{
/* err_txt from netfile.cpp */
case OV_EREAD: sprintf(err_txt, "media read error"); break;
case OV_ENOTVORBIS: sprintf(err_txt, "no vorbis stream"); break;
case OV_EVERSION: sprintf(err_txt, "incompatible vorbis version"); break;
case OV_EBADHEADER: sprintf(err_txt, "invalid bvorbis bitstream header"); break;
case OV_EFAULT: sprintf(err_txt, "internal logic fault (tremor)"); break;
default: sprintf(err_txt, "unknown error, code: %d", rval);
}
fprintf(stderr,"%s: %s\n", ProgName, err_txt);
return false;
}
/* finish the opening and ignite the joint */
//ov_test_open(vf);
if(ov_seekable(vf))
mSeekable = true;
else
mSeekable = false;
return true;
}

View File

@@ -0,0 +1,78 @@
/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2002,2003,2004 Sania,Zwen
ogg vorbis audio decoder
Homepage: http://www.dbox2.info/
Kommentar:
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __OGG_DEC__
#define __OGG_DEC__
//#define DBOX
#include <mad.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <basedec.h>
#include <driver/audiometadata.h>
#ifdef DBOX
#include <tremor/ogg.h>
#include <tremor/ivorbisfile.h>
#else
#include <ogg/ogg.h>
#include <vorbis/vorbisfile.h>
#endif
#define DECODE_SLOTS 30
class COggDec : public CBaseDec
{
public:
static COggDec* getInstance();
virtual RetCode Decoder(FILE *, const int, State* const, CAudioMetaData*, time_t* const, unsigned int* const);
bool GetMetaData(FILE *in, const bool nice, CAudioMetaData* m);
COggDec(){};
private:
void ParseUserComments(vorbis_comment*, CAudioMetaData*);
bool Open(FILE* , OggVorbis_File*);
void SetMetaData(OggVorbis_File*, CAudioMetaData*);
RetCode Status;
char* mPcmSlots[DECODE_SLOTS];
ogg_int64_t mSlotTime[DECODE_SLOTS];
int mWriteSlot;
int mReadSlot;
int mSlotSize;
int mOutputFd;
State* mState;
bool mSeekable;
time_t* mTimePlayed;
static void* OutputDsp(void *);
};
#endif

331
src/driver/audiodec/tag.c Normal file
View File

@@ -0,0 +1,331 @@
/*
* madplay - MPEG audio decoder and player
* Copyright (C) 2000-2004 Robert Leslie
*
* 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: tag.c,v 1.1 2004/08/28 14:11:58 rasc Exp $
*/
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
//# include "global.h"
# include <mad.h>
#ifdef INCLUDE_UNUSED_STUFF
# include <driver/audiodec/crc.h>
#endif /* INCLUDE_UNUSED_STUFF */
# include <driver/audiodec/tag.h>
# define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
# define INFO_MAGIC (('I' << 24) | ('n' << 16) | ('f' << 8) | 'o')
# define LAME_MAGIC (('L' << 24) | ('A' << 16) | ('M' << 8) | 'E')
/*
* NAME: tag->init()
* DESCRIPTION: initialize tag structure
*/
void tag_init(struct tag *tag)
{
tag->flags = 0;
#ifdef INCLUDE_UNUSED_STUFF
tag->encoder[0] = 0;
#endif /* INCLUDE_UNUSED_STUFF */
}
/*
* NAME: parse_xing()
* DESCRIPTION: parse a Xing VBR tag
*/
static
int parse_xing(struct tag_xing *xing,
struct mad_bitptr *ptr, unsigned int *bitlen)
{
if (*bitlen < 32)
goto fail;
xing->flags = mad_bit_read(ptr, 32);
*bitlen -= 32;
if (xing->flags & TAG_XING_FRAMES) {
if (*bitlen < 32)
goto fail;
xing->frames = mad_bit_read(ptr, 32);
*bitlen -= 32;
}
if (xing->flags & TAG_XING_BYTES) {
if (*bitlen < 32)
goto fail;
xing->bytes = mad_bit_read(ptr, 32);
*bitlen -= 32;
}
if (xing->flags & TAG_XING_TOC) {
int i;
if (*bitlen < 800)
goto fail;
for (i = 0; i < 100; ++i)
xing->toc[i] = mad_bit_read(ptr, 8);
*bitlen -= 800;
}
if (xing->flags & TAG_XING_SCALE) {
if (*bitlen < 32)
goto fail;
xing->scale = mad_bit_read(ptr, 32);
*bitlen -= 32;
}
return 0;
fail:
xing->flags = 0;
return -1;
}
#ifdef INCLUDE_UNUSED_STUFF
/*
* NAME: tag->parse_rgain()
* DESCRIPTION: parse a 16-bit Replay Gain field
*/
void tag_parse_rgain(struct tag_rgain *rgain, struct mad_bitptr *ptr)
{
int negative;
rgain->name = mad_bit_read(ptr, 3);
rgain->originator = mad_bit_read(ptr, 3);
negative = mad_bit_read(ptr, 1);
rgain->adjustment = mad_bit_read(ptr, 9);
if (negative)
rgain->adjustment = -rgain->adjustment;
}
/*
* NAME: parse_lame()
* DESCRIPTION: parse a LAME tag
*/
static
int parse_lame(struct tag_lame *lame,
struct mad_bitptr *ptr, unsigned int *bitlen,
unsigned short crc)
{
struct mad_bitptr save = *ptr;
if (*bitlen < 36 * 8)
goto fail;
/* bytes $9A-$A4: Encoder short VersionString */
mad_bit_skip(ptr, 9 * 8);
/* byte $A5: Info Tag revision + VBR method */
lame->revision = mad_bit_read(ptr, 4);
if (lame->revision == 15)
goto fail;
lame->vbr_method = mad_bit_read(ptr, 4);
/* byte $A6: Lowpass filter value (Hz) */
lame->lowpass_filter = mad_bit_read(ptr, 8) * 100;
/* bytes $A7-$AA: 32 bit "Peak signal amplitude" */
lame->peak = mad_bit_read(ptr, 32) << 5;
/* bytes $AB-$AC: 16 bit "Radio Replay Gain" */
tag_parse_rgain(&lame->replay_gain[0], ptr);
/* bytes $AD-$AE: 16 bit "Audiophile Replay Gain" */
tag_parse_rgain(&lame->replay_gain[1], ptr);
/* byte $AF: Encoding flags + ATH Type */
lame->flags = mad_bit_read(ptr, 4);
lame->ath_type = mad_bit_read(ptr, 4);
/* byte $B0: if ABR {specified bitrate} else {minimal bitrate} */
lame->bitrate = mad_bit_read(ptr, 8);
/* bytes $B1-$B3: Encoder delays */
lame->start_delay = mad_bit_read(ptr, 12);
lame->end_padding = mad_bit_read(ptr, 12);
/* byte $B4: Misc */
lame->source_samplerate = mad_bit_read(ptr, 2);
if (mad_bit_read(ptr, 1))
lame->flags |= TAG_LAME_UNWISE;
lame->stereo_mode = mad_bit_read(ptr, 3);
lame->noise_shaping = mad_bit_read(ptr, 2);
/* byte $B5: MP3 Gain */
lame->gain = mad_bit_read(ptr, 8);
/* bytes $B6-B7: Preset and surround info */
mad_bit_skip(ptr, 2);
lame->surround = mad_bit_read(ptr, 3);
lame->preset = mad_bit_read(ptr, 11);
/* bytes $B8-$BB: MusicLength */
lame->music_length = mad_bit_read(ptr, 32);
/* bytes $BC-$BD: MusicCRC */
lame->music_crc = mad_bit_read(ptr, 16);
/* bytes $BE-$BF: CRC-16 of Info Tag */
if (mad_bit_read(ptr, 16) != crc)
goto fail;
*bitlen -= 36 * 8;
return 0;
fail:
*ptr = save;
return -1;
}
#endif /* INCLUDE_UNUSED_STUFF */
/*
* NAME: tag->parse()
* DESCRIPTION: parse Xing/LAME tag(s)
*/
int tag_parse(struct tag *tag, struct mad_stream const *stream)
{
struct mad_bitptr ptr = stream->anc_ptr;
struct mad_bitptr start = ptr;
unsigned int bitlen = stream->anc_bitlen;
unsigned long magic;
#ifdef INCLUDE_UNUSED_STUFF
int i;
#endif /* INCLUDE_UNUSED_STUFF */
if (bitlen < 32)
return -1;
magic = mad_bit_read(&ptr, 32);
bitlen -= 32;
if (magic != XING_MAGIC
&& magic != INFO_MAGIC
&& magic != LAME_MAGIC)
{
/*
* Due to an unfortunate historical accident, a Xing VBR tag may be
* misplaced in a stream with CRC protection. We check for this by
* assuming the tag began two octets prior and the high bits of the
* following flags field are always zero.
*/
if (magic != ((XING_MAGIC << 16) & 0xffffffffL)
&& magic != ((INFO_MAGIC << 16) & 0xffffffffL))
return -1;
magic >>= 16;
/* backtrack the bit pointer */
ptr = start;
mad_bit_skip(&ptr, 16);
bitlen += 16;
}
if ((magic & 0x0000ffffL) == (XING_MAGIC & 0x0000ffffL))
tag->flags |= TAG_VBR;
/* Xing tag */
if (magic == LAME_MAGIC) {
ptr = start;
bitlen += 32;
}
else if (parse_xing(&tag->xing, &ptr, &bitlen) == 0)
tag->flags |= TAG_XING;
#ifdef INCLUDE_UNUSED_STUFF
/* encoder string */
if (bitlen >= 20 * 8) {
start = ptr;
for (i = 0; i < 20; ++i) {
tag->encoder[i] = mad_bit_read(&ptr, 8);
if (tag->encoder[i] == 0)
break;
/* keep only printable ASCII chars */
if (tag->encoder[i] < 0x20 || tag->encoder[i] >= 0x7f) {
tag->encoder[i] = 0;
break;
}
}
tag->encoder[20] = 0;
ptr = start;
}
/* LAME tag */
if (stream->next_frame - stream->this_frame >= 192 &&
parse_lame(&tag->lame, &ptr, &bitlen,
crc_compute(stream->this_frame, 190, 0x0000)) == 0) {
tag->flags |= TAG_LAME;
tag->encoder[9] = 0;
}
else {
for (i = 0; i < 20; ++i) {
if (tag->encoder[i] == 0)
break;
/* stop at padding chars */
if (tag->encoder[i] == 0x55) {
tag->encoder[i] = 0;
break;
}
}
}
#endif /* INCLUDE_UNUSED_STUFF */
return 0;
}

183
src/driver/audiodec/tag.h Normal file
View File

@@ -0,0 +1,183 @@
/*
* madplay - MPEG audio decoder and player
* Copyright (C) 2000-2004 Robert Leslie
*
* 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: tag.h,v 1.1 2004/08/28 14:11:58 rasc Exp $
*/
# ifndef __TAG_H__
# define __TAG_H__
# include <mad.h>
enum {
TAG_XING = 0x0001,
TAG_LAME = 0x0002,
TAG_VBR = 0x0100
};
enum {
TAG_XING_FRAMES = 0x00000001L,
TAG_XING_BYTES = 0x00000002L,
TAG_XING_TOC = 0x00000004L,
TAG_XING_SCALE = 0x00000008L
};
#ifdef INCLUDE_UNUSED_STUFF
enum {
TAG_LAME_NSPSYTUNE = 0x01,
TAG_LAME_NSSAFEJOINT = 0x02,
TAG_LAME_NOGAP_NEXT = 0x04,
TAG_LAME_NOGAP_PREV = 0x08,
TAG_LAME_UNWISE = 0x10
};
enum tag_lame_vbr {
TAG_LAME_VBR_CONSTANT = 1,
TAG_LAME_VBR_ABR = 2,
TAG_LAME_VBR_METHOD1 = 3,
TAG_LAME_VBR_METHOD2 = 4,
TAG_LAME_VBR_METHOD3 = 5,
TAG_LAME_VBR_METHOD4 = 6,
TAG_LAME_VBR_CONSTANT2PASS = 8,
TAG_LAME_VBR_ABR2PASS = 9
};
enum tag_lame_source {
TAG_LAME_SOURCE_32LOWER = 0x00,
TAG_LAME_SOURCE_44_1 = 0x01,
TAG_LAME_SOURCE_48 = 0x02,
TAG_LAME_SOURCE_HIGHER48 = 0x03
};
enum tag_lame_mode {
TAG_LAME_MODE_MONO = 0x00,
TAG_LAME_MODE_STEREO = 0x01,
TAG_LAME_MODE_DUAL = 0x02,
TAG_LAME_MODE_JOINT = 0x03,
TAG_LAME_MODE_FORCE = 0x04,
TAG_LAME_MODE_AUTO = 0x05,
TAG_LAME_MODE_INTENSITY = 0x06,
TAG_LAME_MODE_UNDEFINED = 0x07
};
enum tag_lame_surround {
TAG_LAME_SURROUND_NONE = 0,
TAG_LAME_SURROUND_DPL = 1,
TAG_LAME_SURROUND_DPL2 = 2,
TAG_LAME_SURROUND_AMBISONIC = 3
};
enum tag_lame_preset {
TAG_LAME_PRESET_NONE = 0,
TAG_LAME_PRESET_V9 = 410,
TAG_LAME_PRESET_V8 = 420,
TAG_LAME_PRESET_V7 = 430,
TAG_LAME_PRESET_V6 = 440,
TAG_LAME_PRESET_V5 = 450,
TAG_LAME_PRESET_V4 = 460,
TAG_LAME_PRESET_V3 = 470,
TAG_LAME_PRESET_V2 = 480,
TAG_LAME_PRESET_V1 = 490,
TAG_LAME_PRESET_V0 = 500,
TAG_LAME_PRESET_R3MIX = 1000,
TAG_LAME_PRESET_STANDARD = 1001,
TAG_LAME_PRESET_EXTREME = 1002,
TAG_LAME_PRESET_INSANE = 1003,
TAG_LAME_PRESET_STANDARD_FAST = 1004,
TAG_LAME_PRESET_EXTREME_FAST = 1005,
TAG_LAME_PRESET_MEDIUM = 1006,
TAG_LAME_PRESET_MEDIUM_FAST = 1007
};
#endif /* INCLUDE_UNUSED_STUFF */
struct tag_xing {
long flags; /* valid fields (see below) */
unsigned long frames; /* total number of frames */
unsigned long bytes; /* total number of bytes */
unsigned char toc[100]; /* 100-point seek table */
long scale; /* VBR quality indicator (0 best - 100 worst) */
};
#ifdef INCLUDE_UNUSED_STUFF
enum tag_rgain_name {
TAG_RGAIN_NAME_NOT_SET = 0x0,
TAG_RGAIN_NAME_RADIO = 0x1,
TAG_RGAIN_NAME_AUDIOPHILE = 0x2
};
enum tag_rgain_originator {
TAG_RGAIN_ORIGINATOR_UNSPECIFIED = 0x0,
TAG_RGAIN_ORIGINATOR_PRESET = 0x1,
TAG_RGAIN_ORIGINATOR_USER = 0x2,
TAG_RGAIN_ORIGINATOR_AUTOMATIC = 0x3
};
struct tag_rgain {
enum tag_rgain_name name;
enum tag_rgain_originator originator;
signed short adjustment;
};
struct tag_lame {
unsigned char revision;
unsigned char flags;
enum tag_lame_vbr vbr_method;
unsigned short lowpass_filter;
mad_fixed_t peak;
struct tag_rgain replay_gain[2];
unsigned char ath_type;
unsigned char bitrate;
unsigned short start_delay;
unsigned short end_padding;
enum tag_lame_source source_samplerate;
enum tag_lame_mode stereo_mode;
unsigned char noise_shaping;
signed char gain;
enum tag_lame_surround surround;
enum tag_lame_preset preset;
unsigned long music_length;
unsigned short music_crc;
};
#endif /* INCLUDE_UNUSED_STUFF */
struct tag {
int flags;
struct tag_xing xing;
#ifdef INCLUDE_UNUSED_STUFF
struct tag_lame lame;
char encoder[21];
#endif /* INCLUDE_UNUSED_STUFF */
};
void tag_init(struct tag *);
# define tag_finish(tag) /* nothing */
int tag_parse(struct tag *, struct mad_stream const *);
#ifdef INCLUDE_UNUSED_STUFF
void tag_parse_rgain(struct tag_rgain *, struct mad_bitptr *);
#endif /* INCLUDE_UNUSED_STUFF */
# endif /* __TAG_H__ */

185
src/driver/audiodec/vis.cpp Normal file
View File

@@ -0,0 +1,185 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <global.h>
#include <neutrino.h>
#include <driver/vfd.h>
#include "int_fft.c"
typedef signed short gint16;
typedef int gint;
typedef float gfloat;
typedef double gdouble;
#define NUM_BANDS 16
#define WIDTH (120/NUM_BANDS)
#define HEIGHT 64
#define FALL 2
#define FALLOFF 1
static int bar_heights[NUM_BANDS];
static int falloffs[NUM_BANDS];
static gdouble scale = 0;
static gint xscale128[] = { 0, 1, 2, 3, 4, 6, 8, 9, 10, 14, 20, 27, 37, 50, 67, 94, 127 };
static gint xscale256[] = { 0, 1, 2, 3, 5, 7, 10, 14, 20, 28, 40, 54, 74, 101, 137, 187, 255 };
static gint xscale512[] = { 0, 2, 4, 6, 10, 14, 20, 28, 40, 56, 80, 108, 148, 202, 274, 374, 510 };
//#define DEBUG
#if HAVE_DBOX2
#define SAMPLES 256
#define LOG 8
#define xscale xscale128
#else
#define SAMPLES 512
#define LOG 9
#define xscale xscale256
#endif
static void do_fft(gint16 out_data[], gint16 in_data[])
{
gint16 im[SAMPLES];
memset(im, 0, sizeof(im));
window(in_data, SAMPLES);
fix_fft(in_data, im, LOG, 0);
fix_loud(out_data, in_data, im, SAMPLES/2, 0);
}
static int threshold = -60;
void sanalyzer_render_freq (gint16 in_data[])
{
#if 0
gint i, c;
gint y;
gint16 freq_data[1024];
static int fl = 0;
#ifdef DEBUG
struct timeval tv1, tv2;
gettimeofday (&tv1, NULL);
#endif
do_fft (freq_data, in_data);
CVFD::getInstance ()->Clear ();
#ifdef DEBUG
//gettimeofday (&tv1, NULL);
#endif
for (i = 0; i < NUM_BANDS; i++) {
y = 0;
#if 0 // using max value
for (c = xscale[i]; c < xscale[i + 1]; c++) {
if(freq_data[c] > threshold) {
int val = freq_data[c]-threshold;
if (val > y)
y = val;
}
}
#else
int val = 0;
int cnt = 0;
for (c = xscale[i]; c < xscale[i + 1]; c++) {
if(freq_data[c] > threshold) {
val += freq_data[c]-threshold;
cnt++;
}
}
if(cnt) y = val/cnt;
#endif
if (y > HEIGHT - 1)
y = HEIGHT - 1;
if (y > bar_heights[i])
bar_heights[i] = y;
else if (bar_heights[i] > FALL)
bar_heights[i] -= FALL;
else
bar_heights[i] = 0;
if (y > falloffs[i])
falloffs[i] = y;
else if (falloffs[i] > FALLOFF) {
fl ++;
if(fl > 2) {
fl = 0;
falloffs[i] -= FALLOFF;
}
}
else
falloffs[i] = 0;
CVFD::getInstance ()->drawBar (i*WIDTH, 64-falloffs[i]-5, WIDTH, 2);
y = bar_heights[i];
CVFD::getInstance ()->drawBar (i*WIDTH, 64-y, WIDTH, y);
}
#ifdef DEBUG
gettimeofday (&tv2, NULL);
printf("Calc takes %dns\n", (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec));
#endif
CVFD::getInstance ()->Update ();
#endif
}
#if 0
void sanalyzer_render_vu (gint16 in_data[2][512])
{
long delay_value;
int a = 0,b = 0, c;
float max = 32767.50;
float db_min = (float) -91;
float channel_data[2] = { 0.0, 0.0};
static int olda = 0, oldb = 0;
return;
#ifdef DEBUG
//struct timeval tv1, tv2;
//gettimeofday (&tv1, NULL);
#endif
for (c = 0; c < 512; c += 2) {
channel_data[0] += (float) (in_data[0][c] * in_data[0][c]);
channel_data[1] += (float) (in_data[1][c] * in_data[1][c]);
}
channel_data[0] = 20 * log10 (sqrt (channel_data[0] / 256.0) / max);
channel_data[1] = 20 * log10 (sqrt (channel_data[1] / 256.0) / max);
a = channel_data[0] + 91;
b = channel_data[1] + 91;
//printf ("channel0: %d\n", a);
//printf ("channel1: %d\n", b);
#ifdef DEBUG
//gettimeofday (&tv2, NULL);
//printf("Calc takes %dms\n", (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000);
#endif
if(a != olda || b != oldb) {
CVFD::getInstance ()->Clear ();
CVFD::getInstance ()->drawBar (0, 8, a, 20);
CVFD::getInstance ()->drawBar (0, 36, b, 20);
#ifdef DEBUG
//gettimeofday (&tv1, NULL);
#endif
CVFD::getInstance ()->Update ();
#ifdef DEBUG
//gettimeofday (&tv2, NULL);
//int ms = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000;
//if(ms) printf("Update takes %dms\n", ms);
#endif
}
return;
}
#endif

View File

@@ -0,0 +1,213 @@
/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2004 Zwen
Homepage: http://www.dbox2.info/
Kommentar:
wav audio decoder
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <cstdlib>
#include <cstring>
#include <errno.h>
#include <unistd.h>
#include <wavdec.h>
#include <sstream>
#include <driver/audioplay.h>
#include <linux/soundcard.h>
#define ProgName "WavDec"
// nr of msecs to skip in ff/rev mode
#define MSECS_TO_SKIP 3000
// nr of msecs to play in ff/rev mode
#define MSECS_TO_PLAY 200
struct WavHeader
{
char ChunkID[4];
int ChunkSize;
char Format[4];
char Subchunk1ID[4];
int Subchunk1Size;
short AudioFormat;
short NumChannels;
int SampleRate;
int ByteRate;
short BlockAlign;
short BitsPerSample;
char Subchunk2ID[4];
int Subchunk2Size;
} __attribute__ ((packed));
int endianTest=1;
#define Swap32IfBE(l) \
(*(char *)&endianTest ? (l) : \
((((l) & 0xff000000) >> 24) | \
(((l) & 0x00ff0000) >> 8) | \
(((l) & 0x0000ff00) << 8) | \
(((l) & 0x000000ff) << 24)))
#define Swap16IfBE(l) \
(*(char *)&endianTest ? (l) : \
((((l) & 0xff00) >> 8) | \
(((l) & 0x00ff) << 8)))
#define MAX_OUTPUT_SAMPLES 1022 /* AVIA_GT_PCM_MAX_SAMPLES-1 */
CBaseDec::RetCode CWavDec::Decoder(FILE *in, int OutputFd, State* state, CAudioMetaData* meta_data, time_t* time_played, unsigned int* secondsToSkip)
{
char* buffer;
RetCode Status=OK;
if (!SetMetaData(in, meta_data))
{
Status=DATA_ERR;
return Status;
}
fseek(in, header_size, SEEK_SET);
int fmt;
switch(mBitsPerSample)
{
case 8 : fmt = AFMT_U8;
break;
case 16 : fmt = header_size == 0 ? AFMT_S16_BE : AFMT_S16_LE;
break;
default:
printf("%s: wrong bits per sample (%d)\n", ProgName, mBitsPerSample);
Status=DATA_ERR;
return Status;
}
if (SetDSP(OutputFd, fmt, meta_data->samplerate , mChannels))
{
Status=DSPSET_ERR;
return Status;
}
int actSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip : MSECS_TO_SKIP / 1000;
unsigned int oldSecsToSkip = *secondsToSkip;
int jumppos=0;
int bytes;
int bytes_to_play = (int) (1.0 * MSECS_TO_PLAY / 1000 * meta_data->bitrate / 8);
int bytes_to_skip = (int) (1.0 * actSecsToSkip * meta_data->bitrate / 8);
int buffersize = MAX_OUTPUT_SAMPLES * mChannels * mBitsPerSample / 8;
buffer = (char*) malloc (buffersize);
do
{
while(*state==PAUSE)
usleep(10000);
if(*state==FF || *state==REV)
{
if (oldSecsToSkip != *secondsToSkip)
{
actSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip : MSECS_TO_SKIP / 1000;
bytes_to_skip = (int) (1.0 * actSecsToSkip * meta_data->bitrate / 8);
oldSecsToSkip = *secondsToSkip;
}
//printf("skipping %d secs and %d bytes\n",actSecsToSkip,bytes_to_skip);
if(std::abs(ftell(in)-jumppos) > bytes_to_play)
{
if(*state==FF)
{
fseek(in, bytes_to_skip, SEEK_CUR);
jumppos=ftell(in);
}
else
{
if(ftell(in) < bytes_to_skip)
{
fseek(in, header_size, SEEK_SET);
*state=PLAY;
}
else
{
fseek(in, -bytes_to_skip, SEEK_CUR);
jumppos=ftell(in);
}
}
}
// if a custom value was set we only jump once
if (*secondsToSkip != 0) {
*state=PLAY;
}
}
bytes = fread(buffer, 1, buffersize, in);
if (write(OutputFd, buffer, bytes) != bytes)
{
fprintf(stderr,"%s: PCM write error (%s).\n", ProgName, strerror(errno));
Status=WRITE_ERR;
}
*time_played = (meta_data->bitrate!=0) ? (ftell(in)-header_size)*8/meta_data->bitrate : 0;
} while (bytes > 0 && *state!=STOP_REQ && Status==OK);
free(buffer);
return Status;
}
bool CWavDec::GetMetaData(FILE *in, const bool nice, CAudioMetaData* m)
{
return SetMetaData(in, m);
}
CWavDec* CWavDec::getInstance()
{
static CWavDec* WavDec = NULL;
if(WavDec == NULL)
{
WavDec = new CWavDec();
}
return WavDec;
}
bool CWavDec::SetMetaData(FILE* in, CAudioMetaData* m)
{
/* Set Metadata */
struct WavHeader wh;
header_size = 44;
fseek(in, 0, SEEK_END);
int filesize = ftell(in);
fseek(in, 0, SEEK_SET);
if(fread(&wh, sizeof(wh), 1, in)!=1)
return false;
if(memcmp(wh.ChunkID, "RIFF", 4)!=0 ||
memcmp(wh.Format, "WAVE", 4)!=0 ||
Swap16IfBE(wh.AudioFormat) != 1)
{
printf("%s: wrong format (header)\n", ProgName);
return false;
}
m->type = CAudioMetaData::WAV;
m->bitrate = Swap32IfBE(wh.ByteRate)*8;
m->samplerate = Swap32IfBE(wh.SampleRate);
mBitsPerSample = Swap16IfBE(wh.BitsPerSample);
mChannels = Swap16IfBE(wh.NumChannels);
m->total_time = (m->bitrate!=0) ? (filesize-header_size)*8 / m->bitrate : 0;
std::stringstream ss;
ss << "Riff/Wave / " << mChannels << "channel(s) / " << mBitsPerSample << "bit";
m->type_info = ss.str();
m->changed=true;
return true;
}

View File

@@ -0,0 +1,54 @@
/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2004 Zwen
wav audio decoder
Homepage: http://www.dbox2.info/
Kommentar:
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WAV_DEC__
#define __WAV_DEC__
#include <stdio.h>
#include <driver/audiodec/basedec.h>
class CWavDec : public CBaseDec
{
public:
static CWavDec* getInstance();
virtual RetCode Decoder(FILE *,int , State* , CAudioMetaData* m, time_t* t, unsigned int* secondsToSkip);
bool GetMetaData(FILE *in, const bool nice, CAudioMetaData* m);
CWavDec(){};
protected:
virtual bool SetMetaData(FILE* in, CAudioMetaData* m);
int mBitsPerSample;
int mChannels;
int header_size;
};
#endif