From 38ed47b73c94b43ba0a837e60fdf2f95ace0870c Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Sun, 14 Oct 2007 17:38:57 +0000 Subject: [PATCH] uFMOD 1.25.1 from Quantum and some minor bugfixes git-svn-id: svn://kolibrios.org@646 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/media/ac97snd/ac97snd.sln | 16 +- programs/media/ac97snd/ac97snd/ac97snd.vcproj | 18 +- programs/media/ac97snd/ac97snd/ac97wav.c | 206 +- programs/media/ac97snd/mpg/mpg.vcproj | 12 +- programs/media/ac97snd/mpg/mpg123.h | 704 +++--- programs/media/ac97snd/mpg/readers.c | 1906 +++++++++-------- programs/media/ac97snd/ufmod-codec.h | 90 + 7 files changed, 1593 insertions(+), 1359 deletions(-) create mode 100644 programs/media/ac97snd/ufmod-codec.h diff --git a/programs/media/ac97snd/ac97snd.sln b/programs/media/ac97snd/ac97snd.sln index 06659561e7..2dae87d64c 100644 --- a/programs/media/ac97snd/ac97snd.sln +++ b/programs/media/ac97snd/ac97snd.sln @@ -1,22 +1,24 @@  Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ac97snd", "ac97snd\ac97snd.vcproj", "{5146AAEE-C15C-47C5-A245-64050C820145}" - ProjectSection(ProjectDependencies) = postProject - {6BB005B0-3277-4C8C-950F-38E15A4E440C} = {6BB005B0-3277-4C8C-950F-38E15A4E440C} - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpg", "mpg\mpg.vcproj", "{6BB005B0-3277-4C8C-950F-38E15A4E440C}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ac97snd", "ac97snd\ac97snd.vcproj", "{5146AAEE-C15C-47C5-A245-64050C820145}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5146AAEE-C15C-47C5-A245-64050C820145}.Release|Win32.ActiveCfg = Release|Win32 - {5146AAEE-C15C-47C5-A245-64050C820145}.Release|Win32.Build.0 = Release|Win32 + {6BB005B0-3277-4C8C-950F-38E15A4E440C}.Debug|Win32.ActiveCfg = Debug|Win32 + {6BB005B0-3277-4C8C-950F-38E15A4E440C}.Debug|Win32.Build.0 = Debug|Win32 {6BB005B0-3277-4C8C-950F-38E15A4E440C}.Release|Win32.ActiveCfg = Release|Win32 {6BB005B0-3277-4C8C-950F-38E15A4E440C}.Release|Win32.Build.0 = Release|Win32 + {5146AAEE-C15C-47C5-A245-64050C820145}.Debug|Win32.ActiveCfg = Debug|Win32 + {5146AAEE-C15C-47C5-A245-64050C820145}.Debug|Win32.Build.0 = Debug|Win32 + {5146AAEE-C15C-47C5-A245-64050C820145}.Release|Win32.ActiveCfg = Release|Win32 + {5146AAEE-C15C-47C5-A245-64050C820145}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/programs/media/ac97snd/ac97snd/ac97snd.vcproj b/programs/media/ac97snd/ac97snd/ac97snd.vcproj index 60da8ea256..9bf64a965a 100644 --- a/programs/media/ac97snd/ac97snd/ac97snd.vcproj +++ b/programs/media/ac97snd/ac97snd/ac97snd.vcproj @@ -14,7 +14,7 @@ @@ -141,7 +141,8 @@ + + + 47) len = 47; /* uFMOD integration */ + write_text(11,57,0x00FF20|FONT0, filename, len); /* uFMOD integration */ - write_text(8,8,0xFFFFFF|FONT0, header, strlen(header)); - write_text(12,28,0x404040|FONT0,buttons_text,strlen(buttons_text)); - write_text(11,27,0xA0FFA0|FONT0,buttons_text,strlen(buttons_text)); + write_text(8,8,FONT0, header, sizeof(header)-1); /* uFMOD integration */ + write_text(12,28,0x404040|FONT0,buttons_text,sizeof(buttons_wav)-1); /* uFMOD integration */ + write_text(11,27,0xA0FFA0|FONT0,buttons_text,sizeof(buttons_wav)-1); /* uFMOD integration */ EndDraw(); }; void draw_progress_bar() { DWORD x; - x = 287.0f * (float)(rd.filepos-rd.strremain)/(float)fileinfo.size; + x = (DWORD)(287.0f * (float)(rd.filepos-rd.strremain)/(float)fileinfo.size); /* uFMOD integration */ if(x==0) return; draw_bar(7,41,x,11,0xA0A0A0); draw_bar(x+7,41,287-x,11,0x404040); @@ -119,6 +130,7 @@ int main(int argc, char *argv[]) //int argc, char *argv[]) int retval; int err; int ver; + unsigned char *ttl, *cur; /* uFMOD integration */ fname = argv[1]; debug_out_str("\n\rPlay file "); @@ -157,28 +169,74 @@ int main(int argc, char *argv[]) //int argc, char *argv[]) create_reader(&rd, inpbuf, 0x10000); init_reader(&rd,fname); - - fmt = test_wav((WAVEHEADER*)testbuff); - if (fmt != 0) + + filename = strrchr(fname,'/')+1; + if( !(fileext = strrchr(filename,'.'))) + return 0; + + if(!_stricmp(fileext,".mp3")) { - snd_play = &play_wave; - set_reader(&rd, 44); - outbuf = UserAlloc(32*1024); - touch(outbuf, 32768); - } - else - { fmt = test_mp3(testbuff); - if(fmt ==0) return 0; - snd_play = &play_mp3; - - outremain = 0x40000 ; - outbuf = UserAlloc(outremain); - touch(outbuf, outremain); - make_decode_tables(32767); - init_layer2(); - init_layer3(32); - fr.single = -1; + fmt = test_mp3(testbuff); + if(!fmt) + { + debug_out_str("\n\rInvalid MP3 file"); + return 0; + }; + snd_play = &play_mp3; + outremain = 0x40000; + outbuf = UserAlloc(outremain); + touch(outbuf, outremain); + make_decode_tables(32767); + init_layer2(); + init_layer3(32); + fr.single = -1; + goto play; }; + + if(!_stricmp(fileext,".xm")) + { + if(uFMOD_LoadSong(fname)) + { + buttons_text = buttons_xm; /* uFMOD integration */ + fmt = PCM_2_16_48; /* uFMOD integration */ + snd_play = &play_xm; /* uFMOD integration */ + ttl = uFMOD_GetTitle(); /* uFMOD integration */ + cur = ttl; /* uFMOD integration */ + err = 0; /* uFMOD integration */ + while(*cur && *cur++ != ' ') err++; /* uFMOD integration */ + if(err){ /* uFMOD integration */ + cur = fname; /* uFMOD integration */ + while(*cur) cur++; /* uFMOD integration */ + *cur++ = ' '; /* uFMOD integration */ + *cur++ = '|'; /* uFMOD integration */ + *cur++ = ' '; /* uFMOD integration */ + while(*ttl) *cur++ = *ttl++; /* uFMOD integration */ + } + goto play; + } + debug_out_str("\n\rInvalid XM file"); + return 0; + }; + + if(!_stricmp(fileext, ".wav")) + { + fmt = test_wav((WAVEHEADER*)testbuff); + if(fmt) + { + snd_play = &play_wave; + set_reader(&rd, 44); + outbuf = UserAlloc(32*1024); + touch(outbuf, 32768); + goto play; + } + debug_out_str("\n\rInvalid WAV file"); + return 0; + }; + + debug_out_str("\n\rUsupported file"); + return 0; + +play: status = ST_PLAY; @@ -206,6 +264,7 @@ int main(int argc, char *argv[]) //int argc, char *argv[]) continue; case ST_EXIT: + uFMOD_StopSong(); /* uFMOD integration */ StopBuffer(hBuff); DestroyBuffer(hBuff); return 0; @@ -217,7 +276,7 @@ int main(int argc, char *argv[]) //int argc, char *argv[]) void touch(char *buf, int size) { int i; char a; - for ( i = 0;i < size; i+=4096) + for ( i = 0;i < size; i+=4096) //alloc all pages a = buf[i]; }; @@ -231,13 +290,20 @@ DWORD test_mp3(char *buf) if(!rd.head_read(&rd,&hdr)) return 0; if(!decode_header(&fr,hdr)) - { rd.strpos-=3; - rd.stream-=3; - rd.strremain+=3; - continue; + { + if((hdr & 0xffffff00) == 0x49443300) + { + int id3length = 0; + id3length = parse_new_id3(&rd, hdr); + continue; + }; + rd.strpos-=3; + rd.stream-=3; + rd.strremain+=3; + continue; }; break; - }; + }; first_sync = rd.filepos-rd.strremain-4; @@ -245,7 +311,7 @@ DWORD test_mp3(char *buf) whdr.riff_format = 0x45564157; whdr.wFormatTag = 0x01; whdr.nSamplesPerSec = freqs[fr.sampling_frequency]; - whdr.nChannels = 2; //mpginfo.channels; + whdr.nChannels = 2; whdr.wBitsPerSample = 16; return test_wav(&whdr); @@ -324,26 +390,35 @@ void play_mp3() }; void play_wave() -{ int retval; +{ int count; set_reader(&rd,44); - retval = 0; while(1) { if(status!=ST_PLAY) break; - if( !stream_read_raw(&rd,outbuf,32768)) - { done = 1; - break; - }; - WaveOut(hBuff,outbuf,32768); + if( count=stream_read_raw(&rd,outbuf,32768)) + { + WaveOut(hBuff,outbuf,count); + continue; + } + done = 1; + break; }; if(status != ST_EXIT) - status = ST_STOP; + status = ST_STOP; }; +void play_xm(){ /* uFMOD integration */ + while(status == ST_PLAY){ /* uFMOD integration */ + uFMOD_WaveOut(hBuff); /* uFMOD integration */ + delay(8); /* uFMOD integration */ + } /* uFMOD integration */ + if(status != ST_EXIT) status = ST_STOP; /* uFMOD integration */ +} /* uFMOD integration */ + void snd_stop() { StopBuffer(hBuff); @@ -519,7 +594,7 @@ void EndDraw() }; ///********* -void *memmove ( void * dst, void * src, int count) +void *memmove ( void * dst, void * src, unsigned int count) /* uFMOD integration */ { void *ret; ret = dst; @@ -555,6 +630,40 @@ void * __cdecl mem_cpy(void * dst,const void * src,size_t count) return(ret); } +char * __cdecl strrchr (const char * string,int ch) +{ + char *start = (char *)string; + + while (*string++) /* find end of string */ + ; + /* search towards front */ + while (--string != start && *string != (char)ch) + ; + + if (*string == (char)ch) /* char found ? */ + return( (char *)string ); + + return(NULL); +} + +int __cdecl _stricmp (const char * dst, const char * src) +{ + int f, l; + + do + { + if ( ((f = (unsigned char)(*(dst++))) >= 'A') && (f <= 'Z') ) + f -= 'A' - 'a'; + if ( ((l = (unsigned char)(*(src++))) >= 'A') && (l <= 'Z') ) + l -= 'A' - 'a'; + } + while ( f && (f == l) ); + + return(f - l); +} + + + // debug_out_str(formats[fmt]); // debug_out_str("\x0D\x0A\x00"); @@ -584,6 +693,3 @@ void * __cdecl mem_cpy(void * dst,const void * src,size_t count) // debug_out_hex(fmt); // debug_out_str("\x0D\x0A\x00"); - - - diff --git a/programs/media/ac97snd/mpg/mpg.vcproj b/programs/media/ac97snd/mpg/mpg.vcproj index 454e1b56c8..d80ff3ccb6 100644 --- a/programs/media/ac97snd/mpg/mpg.vcproj +++ b/programs/media/ac97snd/mpg/mpg.vcproj @@ -14,7 +14,7 @@ @@ -229,6 +229,16 @@ + + + -#include -#ifndef _AUDIO_H_ -#define _AUDIO_H_ - -typedef unsigned char byte; -#define off_t long - -//#define I486_OPT 1 - -#define SKIP_JUNK 1 -# define M_PI 3.14159265358979323846 -# define M_SQRT2 1.41421356237309504880 -# define REAL_IS_FLOAT -# define NEW_DCT9 - -#ifdef REAL_IS_FLOAT -# define real float -# define REAL_SCANF "%f" -# define REAL_PRINTF "%f" -#else -# define real double -# define REAL_SCANF "%lf" -# define REAL_PRINTF "%f" -#endif - -#ifndef DOUBLE_TO_REAL -# define DOUBLE_TO_REAL(x) (x) -#endif -#ifndef REAL_TO_SHORT -# define REAL_TO_SHORT(x) (x) -#endif -#ifndef REAL_PLUS_32767 -# define REAL_PLUS_32767 32767.0 -#endif -#ifndef REAL_MINUS_32768 -# define REAL_MINUS_32768 -32768.0 -#endif -#ifndef REAL_MUL -# define REAL_MUL(x, y) ((x) * (y)) -#endif - -#define INLINE -/* AUDIOBUFSIZE = n*64 with n=1,2,3 ... */ -#define AUDIOBUFSIZE 16384 - -#define FALSE 0 -#define TRUE 1 - -#define MAX_NAME_SIZE 81 -#define SBLIMIT 32 -#define SCALE_BLOCK 12 -#define SSLIMIT 18 - -#define MPG_MD_STEREO 0 -#define MPG_MD_JOINT_STEREO 1 -#define MPG_MD_DUAL_CHANNEL 2 -#define MPG_MD_MONO 3 - -/* I suspect that 32767 would be a better idea here, but Michael put this in... */ -#define MAXOUTBURST 32768 - -/* Pre Shift fo 16 to 8 bit converter table */ -#define AUSHIFT (3) - -struct bitstream_info -{ int bitindex; - unsigned char *wordpointer; -}; -extern struct bitstream_info bsi; - -struct reader -{ - char *hFile; - unsigned char *buffer; - unsigned char *stream; - int strpos; - int strremain; - int filelen; - int filepos; - - int (*head_read)(struct reader *,unsigned long *newhead); - int (*read_frame_body)(struct reader *,unsigned char *,int size); - }; - + +#include +#include +#ifndef _AUDIO_H_ +#define _AUDIO_H_ + +typedef unsigned char byte; +#define off_t long + +//#define I486_OPT 1 + +#define SKIP_JUNK 1 +# define M_PI 3.14159265358979323846 +# define M_SQRT2 1.41421356237309504880 +# define REAL_IS_FLOAT +# define NEW_DCT9 + +#ifdef REAL_IS_FLOAT +# define real float +# define REAL_SCANF "%f" +# define REAL_PRINTF "%f" +#else +# define real double +# define REAL_SCANF "%lf" +# define REAL_PRINTF "%f" +#endif + +#ifndef DOUBLE_TO_REAL +# define DOUBLE_TO_REAL(x) (x) +#endif +#ifndef REAL_TO_SHORT +# define REAL_TO_SHORT(x) (x) +#endif +#ifndef REAL_PLUS_32767 +# define REAL_PLUS_32767 32767.0 +#endif +#ifndef REAL_MINUS_32768 +# define REAL_MINUS_32768 -32768.0 +#endif +#ifndef REAL_MUL +# define REAL_MUL(x, y) ((x) * (y)) +#endif + +#define INLINE +/* AUDIOBUFSIZE = n*64 with n=1,2,3 ... */ +#define AUDIOBUFSIZE 16384 + +#define FALSE 0 +#define TRUE 1 + +#define MAX_NAME_SIZE 81 +#define SBLIMIT 32 +#define SCALE_BLOCK 12 +#define SSLIMIT 18 + +#define MPG_MD_STEREO 0 +#define MPG_MD_JOINT_STEREO 1 +#define MPG_MD_DUAL_CHANNEL 2 +#define MPG_MD_MONO 3 + +/* I suspect that 32767 would be a better idea here, but Michael put this in... */ +#define MAXOUTBURST 32768 + +/* Pre Shift fo 16 to 8 bit converter table */ +#define AUSHIFT (3) + +struct bitstream_info +{ int bitindex; + unsigned char *wordpointer; +}; +extern struct bitstream_info bsi; + +struct reader +{ + char *hFile; + unsigned char *buffer; + unsigned char *stream; + int strpos; + int strremain; + int filelen; + int filepos; + + int (*head_read)(struct reader *,unsigned long *newhead); + int (*read_frame_body)(struct reader *,unsigned char *,int size); + }; + int parse_new_id3(struct reader *rd, unsigned long newhead); - -struct al_table -{ short bits; - short d; -}; - -struct frame { - struct al_table *alloc; - int (*synth)(real *,int,unsigned char *,int *); - int (*synth_mono)(real *,unsigned char *,int *); - int stereo; /* I _think_ 1 for mono and 2 for stereo */ - int jsbound; - int single; - int II_sblimit; - int down_sample_sblimit; - int lsf; /* 0: MPEG 1.0; 1: MPEG 2.0/2.5 -- both used as bool and array index! */ - int mpeg25; - int down_sample; - int header_change; - int lay; - int (*do_layer)(struct frame *fr,byte *pcm_out, int *pcm_size); - int error_protection; - int bitrate_index; - int sampling_frequency; - int padding; - int extension; - int mode; - int mode_ext; - int copyright; - int original; - int emphasis; - int framesize; /* computed framesize */ - int vbr; /* 1 if variable bitrate was detected */ - unsigned long num; /* the nth frame in some stream... */ -}; - -#if 0 -struct parameter { - int aggressive; /* renice to max. priority */ - int shuffle; /* shuffle/random play */ - int remote; /* remote operation */ - int remote_err; /* remote operation to stderr */ - int outmode; /* where to out the decoded sampels */ - int quiet; /* shut up! */ - int xterm_title; /* Change xterm title to song names? */ - long usebuffer; /* second level buffer size */ - int tryresync; /* resync stream after error */ - int verbose; /* verbose level */ - int force_mono; - int force_stereo; - int force_8bit; - long force_rate; - int down_sample; - int checkrange; - long doublespeed; - long halfspeed; - int force_reopen; - long realtime; - char filename[256]; - long listentry; /* possibility to choose playback of one entry in playlist (0: off, > 0 : select, < 0; just show list*/ - int rva; /* (which) rva to do: <0: nothing, 0: radio/mix/track 1: album/audiophile */ - char* listname; /* name of playlist */ - int long_id3; -}; -#endif - -#if 0 -struct reader { - int (*init)(struct reader *); - void (*close)(struct reader *); - int (*head_read)(struct reader *,unsigned long *newhead); - int (*head_shift)(struct reader *,unsigned long *head); - long (*skip_bytes)(struct reader *,off_t len); - int (*read_frame_body)(struct reader *,unsigned char *,int size); - int (*back_bytes)(struct reader *,off_t bytes); - int (*back_frame)(struct reader *,struct frame *,long num); - off_t (*tell)(struct reader *); - void (*rewind)(struct reader *); - off_t filelen; - off_t filepos; - int filept; - int flags; - unsigned char id3buf[128]; -}; -#endif - -#define READER_FD_OPENED 0x1 -#define READER_ID3TAG 0x2 -#define READER_SEEKABLE 0x4 - -//extern void audio_flush(int, struct audio_info_struct *); - -//extern void print_header(struct frame *); -//extern void print_header_compact(struct frame *); -//extern void print_id3_tag(unsigned char *buf); - -//extern int split_dir_file(const char *path, char **dname, char **fname); - -extern unsigned int get1bit(void); -extern unsigned int getbits(int); -extern unsigned int getbits_fast(int); -//extern void backbits(int); -//extern int getbitoffset(void); -//extern int getbyte(void); - -//extern void set_pointer(long); - -//extern unsigned char *pcm_sample; -//extern int pcm_point; -//extern int audiobufsize; - -//extern int OutputDescriptor; - -#ifdef VARMODESUPPORT -extern int varmode; -extern int playlimit; -#endif - -struct gr_info_s { - int scfsi; - unsigned part2_3_length; - unsigned big_values; - unsigned scalefac_compress; - unsigned block_type; - unsigned mixed_block_flag; - unsigned table_select[3]; - unsigned subblock_gain[3]; - unsigned maxband[3]; - unsigned maxbandl; - unsigned maxb; - unsigned region1start; - unsigned region2start; - unsigned preflag; - unsigned scalefac_scale; - unsigned count1table_select; - real *full_gain[3]; - real *pow2gain; -}; - -struct III_sideinfo -{ - unsigned main_data_begin; - unsigned private_bits; - struct { - struct gr_info_s gr[2]; - } ch[2]; -}; - -extern int open_stream(char *,int fd); -extern void read_frame_init (struct frame* fr); -int read_frame(struct reader *rd, struct frame *fr); - - -/* why extern? */ -void prepare_audioinfo(struct frame *fr, struct audio_info_struct *nai); -int play_frame(int init,struct frame *fr); -int do_layer1(struct frame *fr,byte *pcm_sample, int *pcm_point); -int do_layer2(struct frame *fr,byte *pcm_sample, int *pcm_point); -int do_layer3(struct frame *fr,byte *pcm_sample, int *pcm_point); -extern void do_equalizer(real *bandPtr,int channel); - -#ifdef PENTIUM_OPT -extern int synth_1to1_pent (real *,int,unsigned char *); -#endif -extern int synth_1to1 (real *,int,unsigned char *,int *); -extern int synth_1to1_8bit (real *,int,unsigned char *,int *); -extern int synth_1to1_mono (real *,unsigned char *,int *); -extern int synth_1to1_mono2stereo (real *,unsigned char *,int *); -extern int synth_1to1_8bit_mono (real *,unsigned char *,int *); -extern int synth_1to1_8bit_mono2stereo (real *,unsigned char *,int *); - -extern int synth_2to1 (real *,int,unsigned char *,int *); -extern int synth_2to1_8bit (real *,int,unsigned char *,int *); -extern int synth_2to1_mono (real *,unsigned char *,int *); -extern int synth_2to1_mono2stereo (real *,unsigned char *,int *); -extern int synth_2to1_8bit_mono (real *,unsigned char *,int *); -extern int synth_2to1_8bit_mono2stereo (real *,unsigned char *,int *); - -extern int synth_4to1 (real *,int,unsigned char *,int *); -extern int synth_4to1_8bit (real *,int,unsigned char *,int *); -extern int synth_4to1_mono (real *,unsigned char *,int *); -extern int synth_4to1_mono2stereo (real *,unsigned char *,int *); -extern int synth_4to1_8bit_mono (real *,unsigned char *,int *); -extern int synth_4to1_8bit_mono2stereo (real *,unsigned char *,int *); - -extern int synth_ntom (real *,int,unsigned char *,int *); -extern int synth_ntom_8bit (real *,int,unsigned char *,int *); -extern int synth_ntom_mono (real *,unsigned char *,int *); -extern int synth_ntom_mono2stereo (real *,unsigned char *,int *); -extern int synth_ntom_8bit_mono (real *,unsigned char *,int *); -extern int synth_ntom_8bit_mono2stereo (real *,unsigned char *,int *); - -extern void rewindNbits(int bits); -extern int hsstell(void); -extern void set_pointer(long); -extern void huffman_decoder(int ,int *); -extern void huffman_count1(int,int *); -extern void print_stat(struct frame *fr,unsigned long no,long buffsize,struct audio_info_struct *ai); -extern int get_songlen(struct frame *fr,int no); - -extern void init_layer3(int); -extern void init_layer2(void); -extern void make_decode_tables(long scale); -extern int make_conv16to8_table(int); -extern void dct64(real *,real *,real *); - -#ifdef USE_MMX -extern void dct64_MMX(short *a,short *b,real *c); -extern int synth_1to1_MMX(real *, int, short *, short *, int *); -#endif - -extern int synth_ntom_set_step(long,long); - - -extern unsigned char *conv16to8; -extern long freqs[9]; -extern real muls[27][64]; -extern real decwin[512+32]; -#ifndef USE_MMX -extern real *pnts[5]; -#endif - -extern real equalizer[2][32]; -extern real equalizer_sum[2][32]; -extern int equalizer_cnt; - -extern struct audio_name audio_val2name[]; - -//extern struct parameter param; - -/* 486 optimizations */ -#define FIR_BUFFER_SIZE 128 -extern void dct64_486(int *a,int *b,real *c); -extern int synth_1to1_486(real *bandPtr,int channel,unsigned char *out,int nb_blocks); - -/* 3DNow! optimizations */ -#ifdef USE_3DNOW -extern int getcpuflags(void); -extern void dct36(real *,real *,real *,real *,real *); -extern void dct36_3dnow(real *,real *,real *,real *,real *); -extern int synth_1to1_3dnow(real *,int,unsigned char *,int *); -#endif - -/* avoid the SIGINT in terminal control */ -void next_track(void); -extern long outscale; - -#endif - -void set_pointer(long backstep); -int __stdcall create_reader(struct reader *rd,byte *buffer, int buffsize); -int __stdcall init_reader(struct reader *rd, char *file); -int __stdcall decode_header(struct frame *fr,unsigned long newhead); -int __stdcall set_reader(struct reader *rd, unsigned int filepos); + +struct al_table +{ short bits; + short d; +}; + +struct frame { + struct al_table *alloc; + int (*synth)(real *,int,unsigned char *,int *); + int (*synth_mono)(real *,unsigned char *,int *); + int stereo; /* I _think_ 1 for mono and 2 for stereo */ + int jsbound; + int single; + int II_sblimit; + int down_sample_sblimit; + int lsf; /* 0: MPEG 1.0; 1: MPEG 2.0/2.5 -- both used as bool and array index! */ + int mpeg25; + int down_sample; + int header_change; + int lay; + int (*do_layer)(struct frame *fr,byte *pcm_out, int *pcm_size); + int error_protection; + int bitrate_index; + int sampling_frequency; + int padding; + int extension; + int mode; + int mode_ext; + int copyright; + int original; + int emphasis; + int framesize; /* computed framesize */ + int vbr; /* 1 if variable bitrate was detected */ + unsigned long num; /* the nth frame in some stream... */ +}; + +#if 0 +struct parameter { + int aggressive; /* renice to max. priority */ + int shuffle; /* shuffle/random play */ + int remote; /* remote operation */ + int remote_err; /* remote operation to stderr */ + int outmode; /* where to out the decoded sampels */ + int quiet; /* shut up! */ + int xterm_title; /* Change xterm title to song names? */ + long usebuffer; /* second level buffer size */ + int tryresync; /* resync stream after error */ + int verbose; /* verbose level */ + int force_mono; + int force_stereo; + int force_8bit; + long force_rate; + int down_sample; + int checkrange; + long doublespeed; + long halfspeed; + int force_reopen; + long realtime; + char filename[256]; + long listentry; /* possibility to choose playback of one entry in playlist (0: off, > 0 : select, < 0; just show list*/ + int rva; /* (which) rva to do: <0: nothing, 0: radio/mix/track 1: album/audiophile */ + char* listname; /* name of playlist */ + int long_id3; +}; +#endif + +#if 0 +struct reader { + int (*init)(struct reader *); + void (*close)(struct reader *); + int (*head_read)(struct reader *,unsigned long *newhead); + int (*head_shift)(struct reader *,unsigned long *head); + long (*skip_bytes)(struct reader *,off_t len); + int (*read_frame_body)(struct reader *,unsigned char *,int size); + int (*back_bytes)(struct reader *,off_t bytes); + int (*back_frame)(struct reader *,struct frame *,long num); + off_t (*tell)(struct reader *); + void (*rewind)(struct reader *); + off_t filelen; + off_t filepos; + int filept; + int flags; + unsigned char id3buf[128]; +}; +#endif + +#define READER_FD_OPENED 0x1 +#define READER_ID3TAG 0x2 +#define READER_SEEKABLE 0x4 + +//extern void audio_flush(int, struct audio_info_struct *); + +//extern void print_header(struct frame *); +//extern void print_header_compact(struct frame *); +//extern void print_id3_tag(unsigned char *buf); + +//extern int split_dir_file(const char *path, char **dname, char **fname); + +extern unsigned int get1bit(void); +extern unsigned int getbits(int); +extern unsigned int getbits_fast(int); +//extern void backbits(int); +//extern int getbitoffset(void); +//extern int getbyte(void); + +//extern void set_pointer(long); + +//extern unsigned char *pcm_sample; +//extern int pcm_point; +//extern int audiobufsize; + +//extern int OutputDescriptor; + +#ifdef VARMODESUPPORT +extern int varmode; +extern int playlimit; +#endif + +struct gr_info_s { + int scfsi; + unsigned part2_3_length; + unsigned big_values; + unsigned scalefac_compress; + unsigned block_type; + unsigned mixed_block_flag; + unsigned table_select[3]; + unsigned subblock_gain[3]; + unsigned maxband[3]; + unsigned maxbandl; + unsigned maxb; + unsigned region1start; + unsigned region2start; + unsigned preflag; + unsigned scalefac_scale; + unsigned count1table_select; + real *full_gain[3]; + real *pow2gain; +}; + +struct III_sideinfo +{ + unsigned main_data_begin; + unsigned private_bits; + struct { + struct gr_info_s gr[2]; + } ch[2]; +}; + +extern int open_stream(char *,int fd); +extern void read_frame_init (struct frame* fr); +int read_frame(struct reader *rd, struct frame *fr); + + +/* why extern? */ +void prepare_audioinfo(struct frame *fr, struct audio_info_struct *nai); +int play_frame(int init,struct frame *fr); +int do_layer1(struct frame *fr,byte *pcm_sample, int *pcm_point); +int do_layer2(struct frame *fr,byte *pcm_sample, int *pcm_point); +int do_layer3(struct frame *fr,byte *pcm_sample, int *pcm_point); +extern void do_equalizer(real *bandPtr,int channel); + +#ifdef PENTIUM_OPT +extern int synth_1to1_pent (real *,int,unsigned char *); +#endif +extern int synth_1to1 (real *,int,unsigned char *,int *); +extern int synth_1to1_8bit (real *,int,unsigned char *,int *); +extern int synth_1to1_mono (real *,unsigned char *,int *); +extern int synth_1to1_mono2stereo (real *,unsigned char *,int *); +extern int synth_1to1_8bit_mono (real *,unsigned char *,int *); +extern int synth_1to1_8bit_mono2stereo (real *,unsigned char *,int *); + +extern int synth_2to1 (real *,int,unsigned char *,int *); +extern int synth_2to1_8bit (real *,int,unsigned char *,int *); +extern int synth_2to1_mono (real *,unsigned char *,int *); +extern int synth_2to1_mono2stereo (real *,unsigned char *,int *); +extern int synth_2to1_8bit_mono (real *,unsigned char *,int *); +extern int synth_2to1_8bit_mono2stereo (real *,unsigned char *,int *); + +extern int synth_4to1 (real *,int,unsigned char *,int *); +extern int synth_4to1_8bit (real *,int,unsigned char *,int *); +extern int synth_4to1_mono (real *,unsigned char *,int *); +extern int synth_4to1_mono2stereo (real *,unsigned char *,int *); +extern int synth_4to1_8bit_mono (real *,unsigned char *,int *); +extern int synth_4to1_8bit_mono2stereo (real *,unsigned char *,int *); + +extern int synth_ntom (real *,int,unsigned char *,int *); +extern int synth_ntom_8bit (real *,int,unsigned char *,int *); +extern int synth_ntom_mono (real *,unsigned char *,int *); +extern int synth_ntom_mono2stereo (real *,unsigned char *,int *); +extern int synth_ntom_8bit_mono (real *,unsigned char *,int *); +extern int synth_ntom_8bit_mono2stereo (real *,unsigned char *,int *); + +extern void rewindNbits(int bits); +extern int hsstell(void); +extern void set_pointer(long); +extern void huffman_decoder(int ,int *); +extern void huffman_count1(int,int *); +extern void print_stat(struct frame *fr,unsigned long no,long buffsize,struct audio_info_struct *ai); +extern int get_songlen(struct frame *fr,int no); + +extern void init_layer3(int); +extern void init_layer2(void); +extern void make_decode_tables(long scale); +extern int make_conv16to8_table(int); +extern void dct64(real *,real *,real *); + +#ifdef USE_MMX +extern void dct64_MMX(short *a,short *b,real *c); +extern int synth_1to1_MMX(real *, int, short *, short *, int *); +#endif + +extern int synth_ntom_set_step(long,long); + + +extern unsigned char *conv16to8; +extern long freqs[9]; +extern real muls[27][64]; +extern real decwin[512+32]; +#ifndef USE_MMX +extern real *pnts[5]; +#endif + +extern real equalizer[2][32]; +extern real equalizer_sum[2][32]; +extern int equalizer_cnt; + +extern struct audio_name audio_val2name[]; + +//extern struct parameter param; + +/* 486 optimizations */ +#define FIR_BUFFER_SIZE 128 +extern void dct64_486(int *a,int *b,real *c); +extern int synth_1to1_486(real *bandPtr,int channel,unsigned char *out,int nb_blocks); + +/* 3DNow! optimizations */ +#ifdef USE_3DNOW +extern int getcpuflags(void); +extern void dct36(real *,real *,real *,real *,real *); +extern void dct36_3dnow(real *,real *,real *,real *,real *); +extern int synth_1to1_3dnow(real *,int,unsigned char *,int *); +#endif + +/* avoid the SIGINT in terminal control */ +void next_track(void); +extern long outscale; + +#endif + +void set_pointer(long backstep); +int __stdcall create_reader(struct reader *rd,byte *buffer, int buffsize); +int __stdcall init_reader(struct reader *rd, char *file); +int __stdcall decode_header(struct frame *fr,unsigned long newhead); +int __stdcall set_reader(struct reader *rd, unsigned int filepos); double pow_test(double, double); void * __cdecl mem_cpy(void * dst,const void * src,size_t count); -void init_dct(); +void init_dct(); void reset_mpg(); #ifdef __cplusplus } diff --git a/programs/media/ac97snd/mpg/readers.c b/programs/media/ac97snd/mpg/readers.c index 046bbadbd7..9133f59e43 100644 --- a/programs/media/ac97snd/mpg/readers.c +++ b/programs/media/ac97snd/mpg/readers.c @@ -1,955 +1,969 @@ -#include "mpg123.h" -#include "..\kolibri.h" - -#define MAXFRAMESIZE 3456 - -static int fsizeold=0,ssize; -static unsigned char bsspace[2][MAXFRAMESIZE+512]; /* MAXFRAMESIZE */ -static unsigned char *bsbuf=bsspace[1],*bsbufold; -static int bsnum=0; - -static unsigned long oldhead = 0; -unsigned long firsthead=0; - -struct bitstream_info bsi; - -int tabsel_123[2][3][16] = { - { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, - {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, - {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} }, - - { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,}, - {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,}, - {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} } -}; - -int freqs[9] = { 44100, 48000, 32000, 22050, 24000, 16000 , 11025 , 12000 , 8000 }; - -int stream_head_read(struct reader *rd,unsigned long *newhead); -int stream_read_raw(struct reader *rd,unsigned char *buf, int size); - -void set_synth_functions(struct frame *fr) -{ -#ifdef USE_3DNOW - static func_dct36 funcs_dct36[2] = {dct36 , dct36_3dnow}; -#endif - - fr->synth = synth_1to1; - fr->synth_mono = synth_1to1_mono2stereo;; - -/* TODO: make autodetection for _all_ x86 optimizations (maybe just for i586+ and keep separate 486 build?) */ -#ifdef USE_3DNOW - /* check cpuflags bit 31 (3DNow!) and 23 (MMX) */ - if((param.stat_3dnow < 2) && - ((param.stat_3dnow == 1) || - (getcpuflags() & 0x80800000) == 0x80800000)) - { - fr->synth = funcs[2][ds]; /* 3DNow! optimized synth_1to1() */ - fr->dct36 = funcs_dct36[1]; /* 3DNow! optimized dct36() */ - } - else - { - fr->dct36 = funcs_dct36[0]; - } -#endif -} - -int __stdcall create_reader(struct reader *rd,byte *buffer, int buffsize) -{ rd->head_read = stream_head_read; - rd->read_frame_body = stream_read_raw; - - rd->buffer = buffer; - rd->stream = buffer; - rd->strpos = 0; - - rd->strremain = 0; - rd->filepos = 0; - return 1; -}; - -int __stdcall init_reader(struct reader *rd, char *file) -{ FILEINFO fileinfo; - int retval; - int bytes; - - rd->hFile = file; +#include "mpg123.h" +#include "..\kolibri.h" + +#define MAXFRAMESIZE 3456 + +static int fsizeold=0,ssize; +static unsigned char bsspace[2][MAXFRAMESIZE+512]; /* MAXFRAMESIZE */ +static unsigned char *bsbuf=bsspace[1],*bsbufold; +static int bsnum=0; + +static unsigned long oldhead = 0; +unsigned long firsthead=0; + +struct bitstream_info bsi; + +int tabsel_123[2][3][16] = { + { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, + {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, + {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} }, + + { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,}, + {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,}, + {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} } +}; + +int freqs[9] = { 44100, 48000, 32000, 22050, 24000, 16000 , 11025 , 12000 , 8000 }; + +int stream_head_read(struct reader *rd,unsigned long *newhead); +int stream_read_raw(struct reader *rd,unsigned char *buf, int size); + +void set_synth_functions(struct frame *fr) +{ +#ifdef USE_3DNOW + static func_dct36 funcs_dct36[2] = {dct36 , dct36_3dnow}; +#endif + + fr->synth = synth_1to1; + fr->synth_mono = synth_1to1_mono2stereo;; + +/* TODO: make autodetection for _all_ x86 optimizations (maybe just for i586+ and keep separate 486 build?) */ +#ifdef USE_3DNOW + /* check cpuflags bit 31 (3DNow!) and 23 (MMX) */ + if((param.stat_3dnow < 2) && + ((param.stat_3dnow == 1) || + (getcpuflags() & 0x80800000) == 0x80800000)) + { + fr->synth = funcs[2][ds]; /* 3DNow! optimized synth_1to1() */ + fr->dct36 = funcs_dct36[1]; /* 3DNow! optimized dct36() */ + } + else + { + fr->dct36 = funcs_dct36[0]; + } +#endif +} + +int __stdcall create_reader(struct reader *rd,byte *buffer, int buffsize) +{ rd->head_read = stream_head_read; + rd->read_frame_body = stream_read_raw; + + rd->buffer = buffer; + rd->stream = buffer; + rd->strpos = 0; + + rd->strremain = 0; + rd->filepos = 0; + return 1; +}; + +int __stdcall init_reader(struct reader *rd, char *file) +{ FILEINFO fileinfo; + int retval; + int bytes; + + rd->hFile = file; get_fileinfo(file, &fileinfo); - rd->filelen = fileinfo.size; - rd->strpos = 0; + rd->filelen = fileinfo.size; + rd->strpos = 0; retval=read_file (file,rd->buffer,0,0x10000,&bytes); + + if( (retval==0)||(retval==6)) + { + rd->strremain=bytes; + rd->filepos=bytes; + rd->strpos = 0; + return 1; + }; + return 0; +}; + +static int fill_reader(struct reader *rd) +{ int retval; + int bytes; + + if(rd->strremain > 0) + mem_cpy(rd->buffer,rd->stream,rd->strremain); + + rd->stream = rd->buffer; + retval=read_file (rd->hFile,rd->buffer+rd->strremain,rd->filepos, + 0x10000-rd->strremain,&bytes); + if( (retval==0)||(retval==6)) + { + rd->strremain+=bytes; + rd->filepos+=bytes; + rd->strpos = 0; + return bytes; + }; + return 0; +}; + +int __stdcall set_reader(struct reader *rd, unsigned int filepos) +{ int retval; + unsigned int bytes; + retval=read_file (rd->hFile,rd->buffer,filepos,0x10000,&bytes); + if( (retval==0)||(retval==6)) + { + rd->stream = rd->buffer; + rd->strremain=bytes; + rd->filepos=filepos+bytes; + rd->strpos = 0; + + fsizeold=0; + firsthead=0; + bsbufold = 0; + bsbuf = bsspace[1]; + bsnum = 0; + ssize=0; + oldhead=0; + memset(bsspace,0,sizeof(bsspace)); + return 1; + }; + return 0; +}; + +static int stream_head_read(struct reader *rd,unsigned long *newhead) +{ + if(rd->strremain < 4) + if( !fill_reader(rd)) + return 0; + *newhead = (rd->stream[0]<<24)|(rd->stream[1] << 16)| + (rd->stream[2] << 8)| rd->stream[3]; + rd->strpos+=4; + rd->stream+=4; + rd->strremain-=4; + return TRUE; +}; + +int stream_read_raw(struct reader *rd,unsigned char *buf, int size) +{ + + if(rd->strremain < size) fill_reader(rd); + + if(size > rd->strremain) size=rd->strremain; + + if(size>0) + { + mem_cpy(buf,rd->stream,size); + rd->strpos+=size; + rd->stream+=size; + rd->strremain-=size; + return size; + }; + return 0; +}; + +void set_pointer(long backstep) +{ + bsi.wordpointer = bsbuf + ssize - backstep; + if (backstep) + mem_cpy(bsi.wordpointer,bsbufold+fsizeold-backstep,backstep); + bsi.bitindex = 0; +} + +int head_check(unsigned long head) +{ if + ( + /* first 11 bits are set to 1 for frame sync */ + ((head & 0xffe00000) != 0xffe00000) + || + /* layer: 01,10,11 is 1,2,3; 00 is reserved */ + (!((head>>17)&3)) + || + /* 1111 means bad bitrate */ + (((head>>12)&0xf) == 0xf) + || + /* 0000 means free format... */ + (((head>>12)&0xf) == 0x0) + || + /* sampling freq: 11 is reserved */ + (((head>>10)&0x3) == 0x3 ) + /* here used to be a mpeg 2.5 check... re-enabled 2.5 decoding due to lack of evidence that it is really not good */ + ) + { + return FALSE; + } + /* if no check failed, the header is valid (hopefully)*/ + else + { + return TRUE; + } +} + +int __stdcall decode_header(struct frame *fr,unsigned long newhead) +{ + if(!head_check(newhead)) + return 0; + if( newhead & (1<<20) ) + { fr->lsf = (newhead & (1<<19)) ? 0x0 : 0x1; + fr->mpeg25 = 0; + } + else + { fr->lsf = 1; + fr->mpeg25 = 1; + }; + + fr->lay = 4-((newhead>>17)&3); + if(fr->mpeg25) + fr->sampling_frequency = 6 + ((newhead>>10)&0x3); + else + fr->sampling_frequency = ((newhead>>10)&0x3) + (fr->lsf*3); + fr->error_protection = ((newhead>>16)&0x1)^0x1; + + fr->bitrate_index = ((newhead>>12)&0xf); + fr->padding = ((newhead>>9)&0x1); + fr->extension = ((newhead>>8)&0x1); + fr->mode = ((newhead>>6)&0x3); + fr->mode_ext = ((newhead>>4)&0x3); + fr->copyright = ((newhead>>3)&0x1); + fr->original = ((newhead>>2)&0x1); + fr->emphasis = newhead & 0x3; + + fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2; + + oldhead = newhead; + + if(!fr->bitrate_index) + return (0); + + switch(fr->lay) + { case 1: + fr->do_layer = do_layer1; +#ifdef VARMODESUPPORT + if (varmode) { + error("Sorry, layer-1 not supported in varmode."); + return (0); + } +#endif + fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000; + fr->framesize /= freqs[fr->sampling_frequency]; + fr->framesize = ((fr->framesize+fr->padding)<<2)-4; + break; + case 2: + fr->do_layer = do_layer2; +#ifdef VARMODESUPPORT + if (varmode) { + error("Sorry, layer-2 not supported in varmode."); + return (0); + } +#endif + fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000; + fr->framesize /= freqs[fr->sampling_frequency]; + fr->framesize += fr->padding - 4; + break; + case 3: + fr->do_layer = do_layer3; + if(fr->lsf) + ssize = (fr->stereo == 1) ? 9 : 17; + else + ssize = (fr->stereo == 1) ? 17 : 32; + if(fr->error_protection) + ssize += 2; + fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000; + fr->framesize /= freqs[fr->sampling_frequency]<<(fr->lsf); + fr->framesize = fr->framesize + fr->padding - 4; + break; + default: + return (0); + } + if (fr->framesize > MAXFRAMESIZE) + return (0); + return 1; +} + + +int read_frame(struct reader *rd, struct frame *fr) +{ unsigned long newhead; + static unsigned char ssave[34]; + //off_t framepos; + fsizeold=fr->framesize; /* for Layer3 */ + +read_again: + + if(!rd->head_read(rd,&newhead)) + return FALSE; + + if(!decode_header(fr,newhead)) + { + if((newhead & 0xffffff00) == 0x49443300) + { + int id3length = 0; + id3length = parse_new_id3(rd, newhead); + goto read_again; + }; + rd->strpos-=3; + rd->stream-=3; + rd->strremain+=3; + goto read_again; + }; + +#if 0 + if(1 || oldhead != newhead || !oldhead) + { + +init_resync: + +#ifdef SKIP_JUNK + /* watch out for junk/tags on beginning of stream by invalid header */ + if(!firsthead && !head_check(newhead) && !free_format_header(newhead)) { + int i; + + /* check for id3v2; first three bytes (of 4) are "ID3" */ + if((newhead & (unsigned long) 0xffffff00) == (unsigned long) 0x49443300) + { + int id3length = 0; + id3length = parse_new_id3(newhead, rd); + goto read_again; + } + else if(param.verbose > 1) fprintf(stderr,"Note: Junk at the beginning (0x%08lx)\n",newhead); + + /* I even saw RIFF headers at the beginning of MPEG streams ;( */ + if(newhead == ('R'<<24)+('I'<<16)+('F'<<8)+'F') { + if(param.verbose > 1) fprintf(stderr, "Note: Looks like a RIFF header.\n"); + if(!rd->head_read(rd,&newhead)) + return 0; + while(newhead != ('d'<<24)+('a'<<16)+('t'<<8)+'a') { + if(!rd->head_shift(rd,&newhead)) + return 0; + } + if(!rd->head_read(rd,&newhead)) + return 0; + if(param.verbose > 1) fprintf(stderr,"Note: Skipped RIFF header!\n"); + goto read_again; + } + /* unhandled junk... just continue search for a header */ + /* step in byte steps through next 64K */ + for(i=0;i<65536;i++) { + if(!rd->head_shift(rd,&newhead)) + return 0; + /* if(head_check(newhead)) */ + if(head_check(newhead) && decode_header(fr, newhead)) + break; + } + if(i == 65536) { + if(!param.quiet) error("Giving up searching valid MPEG header after 64K of junk."); + return 0; + } + /* + * should we additionaly check, whether a new frame starts at + * the next expected position? (some kind of read ahead) + * We could implement this easily, at least for files. + */ + } +#endif + + /* first attempt of read ahead check to find the real first header; cannot believe what junk is out there! */ + /* for now, a spurious first free format header screws up here; need free format support for detecting false free format headers... */ + if(!firsthead && rd->flags & READER_SEEKABLE && head_check(newhead) && decode_header(fr, newhead)) + { + unsigned long nexthead = 0; + int hd = 0; + off_t start = rd->tell(rd); + debug1("doing ahead check with BPF %d", fr->framesize+4); + /* step framesize bytes forward and read next possible header*/ + if(rd->back_bytes(rd, -fr->framesize)) + { + error("cannot seek!"); + return 0; + } + hd = rd->head_read(rd,&nexthead); + if(rd->back_bytes(rd, rd->tell(rd)-start)) + { + error("cannot seek!"); + return 0; + } + if(!hd) + { + warning("cannot read next header, a one-frame stream? Duh..."); + } + else + { + debug2("does next header 0x%08lx match first 0x%08lx?", nexthead, newhead); + /* not allowing free format yet */ + if(!head_check(nexthead) || (nexthead & HDRCMPMASK) != (newhead & HDRCMPMASK)) + { + debug("No, the header was not valid, start from beginning..."); + /* try next byte for valid header */ + if(rd->back_bytes(rd, 3)) + { + error("cannot seek!"); + return 0; + } + goto read_again; + } + } + } + + /* why has this head check been avoided here before? */ + if(!head_check(newhead)) + { + if(!firsthead && free_format_header(newhead)) + { + error1("Header 0x%08lx seems to indicate a free format stream; I do not handle that yet", newhead); + goto read_again; + return 0; + } + /* and those ugly ID3 tags */ + if((newhead & 0xffffff00) == ('T'<<24)+('A'<<16)+('G'<<8)) { + rd->skip_bytes(rd,124); + if (param.verbose > 1) fprintf(stderr,"Note: Skipped ID3 Tag!\n"); + goto read_again; + } + /* duplicated code from above! */ + /* check for id3v2; first three bytes (of 4) are "ID3" */ + if((newhead & (unsigned long) 0xffffff00) == (unsigned long) 0x49443300) + { + int id3length = 0; + id3length = parse_new_id3(newhead, rd); + goto read_again; + } + else if (give_note) + { + fprintf(stderr,"Note: Illegal Audio-MPEG-Header 0x%08lx at offset 0x%lx.\n", newhead,rd->tell(rd)-4); + } + + if(give_note && (newhead & 0xffffff00) == ('b'<<24)+('m'<<16)+('p'<<8)) fprintf(stderr,"Note: Could be a BMP album art.\n"); + if (param.tryresync || do_recover) { + int try = 0; + /* TODO: make this more robust, I'd like to cat two mp3 fragments together (in a dirty way) and still have mpg123 beign able to decode all it somehow. */ + if(give_note) fprintf(stderr, "Note: Trying to resync...\n"); + /* Read more bytes until we find something that looks + reasonably like a valid header. This is not a + perfect strategy, but it should get us back on the + track within a short time (and hopefully without + too much distortion in the audio output). */ + do { + if(!rd->head_shift(rd,&newhead)) + return 0; + /* debug2("resync try %i, got newhead 0x%08lx", try, newhead); */ + if (!oldhead) + { + debug("going to init_resync..."); + goto init_resync; /* "considered harmful", eh? */ + } + /* we should perhaps collect a list of valid headers that occured in file... there can be more */ + /* Michael's new resync routine seems to work better with the one frame readahead (and some input buffering?) */ + } while + ( + ++try < RESYNC_LIMIT + && (newhead & HDRCMPMASK) != (oldhead & HDRCMPMASK) + && (newhead & HDRCMPMASK) != (firsthead & HDRCMPMASK) + ); + /* too many false positives + }while (!(head_check(newhead) && decode_header(fr, newhead))); */ + if(try == RESYNC_LIMIT) + { + error("giving up resync - your stream is not nice... perhaps an improved routine could catch up"); + return 0; + } + + if (give_note) + fprintf (stderr, "Note: Skipped %d bytes in input.\n", try); + } + else + { + error("not attempting to resync..."); + return (0); + } + } + + if (!firsthead) { + if(!decode_header(fr,newhead)) + { + error("decode header failed before first valid one, going to read again"); + goto read_again; + } + } + else + if(!decode_header(fr,newhead)) + { + error("decode header failed - goto resync"); + /* return 0; */ + goto init_resync; + } + } + else + fr->header_change = 0; +#endif + + bsbufold = bsbuf; + bsbuf = bsspace[bsnum]+512; + bsnum = (bsnum + 1) & 1; + /* if filepos is invalid, so is framepos */ + //framepos = rd->filepos - 4; + /* read main data into memory */ + /* 0 is error! */ + + if(rd->read_frame_body(rd,bsbuf,fr->framesize) < fr->framesize) + return 0; + +#if 0 + if(!firsthead) + { + /* following stuff is actually layer3 specific (in practice, not in theory) */ + if(fr->lay == 3) + { + /* + going to look for Xing or Info at some position after the header + MPEG 1 MPEG 2/2.5 (LSF) + Stereo, Joint Stereo, Dual Channel 32 17 + Mono 17 9 + + Also, how to avoid false positives? I guess I should interpret more of the header to rule that out(?). + I hope that ensuring all zeros until tag start is enough. + */ + size_t lame_offset = (fr->stereo == 2) ? (fr->lsf ? 17 : 32 ) : (fr->lsf ? 9 : 17); + if(fr->framesize >= 120+lame_offset) /* traditional Xing header is 120 bytes */ + { + size_t i; + int lame_type = 0; + /* only search for tag when all zero before it (apart from checksum) */ + for(i=2; i < lame_offset; ++i) if(bsbuf[i] != 0) break; + if(i == lame_offset) + { + if + ( + (bsbuf[lame_offset] == 'I') + && (bsbuf[lame_offset+1] == 'n') + && (bsbuf[lame_offset+2] == 'f') + && (bsbuf[lame_offset+3] == 'o') + ) + { + lame_type = 1; /* We still have to see what there is */ + } + else if + ( + (bsbuf[lame_offset] == 'X') + && (bsbuf[lame_offset+1] == 'i') + && (bsbuf[lame_offset+2] == 'n') + && (bsbuf[lame_offset+3] == 'g') + ) + { + lame_type = 2; + vbr = VBR; /* Xing header means always VBR */ + } + if(lame_type) + { + unsigned long xing_flags; + + /* we have one of these headers... */ + if(param.verbose > 1) fprintf(stderr, "Note: Xing/Lame/Info header detected\n"); + /* now interpret the Xing part, I have 120 bytes total for sure */ + /* there are 4 bytes for flags, but only the last byte contains known ones */ + lame_offset += 4; /* now first byte after Xing/Name */ + /* 4 bytes dword for flags */ + #define make_long(a, o) ((((unsigned long) a[o]) << 24) | (((unsigned long) a[o+1]) << 16) | (((unsigned long) a[o+2]) << 8) | ((unsigned long) a[o+3])) + /* 16 bit */ + #define make_short(a,o) ((((unsigned short) a[o]) << 8) | ((unsigned short) a[o+1])) + xing_flags = make_long(bsbuf, lame_offset); + lame_offset += 4; + debug1("Xing: flags 0x%08lx", xing_flags); + if(xing_flags & 1) /* frames */ + { + /* + In theory, one should use that value for skipping... + When I know the exact number of samples I could simply count in audio_flush, + but that's problematic with seeking and such. + I still miss the real solution for detecting the end. + */ + track_frames = make_long(bsbuf, lame_offset); + if(track_frames > TRACK_MAX_FRAMES) track_frames = 0; /* endless stream? */ + #ifdef GAPLESS + /* if no further info there, remove/add at least the decoder delay */ + if(param.gapless) + { + unsigned long length = track_frames * spf(fr); + if(length > 1) + layer3_gapless_init(DECODER_DELAY+GAP_SHIFT, length+DECODER_DELAY+GAP_SHIFT); + } + #endif + debug1("Xing: %lu frames", track_frames); + lame_offset += 4; + } + if(xing_flags & 0x2) /* bytes */ + { + #ifdef DEBUG + unsigned long xing_bytes = make_long(bsbuf, lame_offset); + debug1("Xing: %lu bytes", xing_bytes); + #endif + lame_offset += 4; + } + if(xing_flags & 0x4) /* TOC */ + { + lame_offset += 100; /* just skip */ + } + if(xing_flags & 0x8) /* VBR quality */ + { + #ifdef DEBUG + unsigned long xing_quality = make_long(bsbuf, lame_offset); + debug1("Xing: quality = %lu", xing_quality); + #endif + lame_offset += 4; + } + /* I guess that either 0 or LAME extra data follows */ + /* there may this crc16 be floating around... (?) */ + if(bsbuf[lame_offset] != 0) + { + unsigned char lame_vbr; + float replay_gain[2] = {0,0}; + float peak = 0; + float gain_offset = 0; /* going to be +6 for old lame that used 83dB */ + char nb[10]; + memcpy(nb, bsbuf+lame_offset, 9); + nb[9] = 0; + debug1("Info: Encoder: %s", nb); + if(!strncmp("LAME", nb, 4)) + { + gain_offset = 6; + debug("TODO: finish lame detetcion..."); + } + lame_offset += 9; + /* the 4 big bits are tag revision, the small bits vbr method */ + lame_vbr = bsbuf[lame_offset] & 15; + debug1("Info: rev %u", bsbuf[lame_offset] >> 4); + debug1("Info: vbr mode %u", lame_vbr); + lame_offset += 1; + switch(lame_vbr) + { + /* from rev1 proposal... not sure if all good in practice */ + case 1: + case 8: vbr = CBR; break; + case 2: + case 9: vbr = ABR; break; + default: vbr = VBR; /* 00==unknown is taken as VBR */ + } + /* skipping: lowpass filter value */ + lame_offset += 1; + /* replaygain */ + /* 32bit float: peak amplitude -- why did I parse it as int before??*/ + /* Ah, yes, lame seems to store it as int since some day in 2003; I've only seen zeros anyway until now, bah! */ + if + ( + (bsbuf[lame_offset] != 0) + || (bsbuf[lame_offset+1] != 0) + || (bsbuf[lame_offset+2] != 0) + || (bsbuf[lame_offset+3] != 0) + ) + { + debug("Wow! Is there _really_ a non-zero peak value? Now is it stored as float or int - how should I know?"); + peak = *(float*) (bsbuf+lame_offset); + } + debug1("Info: peak = %f (I won't use this)", peak); + peak = 0; /* until better times arrived */ + lame_offset += 4; + /* + ReplayGain values - lame only writes radio mode gain... + 16bit gain, 3 bits name, 3 bits originator, sign (1=-, 0=+), dB value*10 in 9 bits (fixed point) + ignore the setting if name or originator == 000! + radio 0 0 1 0 1 1 1 0 0 1 1 1 1 1 0 1 + audiophile 0 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 + */ + + for(i =0; i < 2; ++i) + { + unsigned char origin = (bsbuf[lame_offset] >> 2) & 0x7; /* the 3 bits after that... */ + if(origin != 0) + { + unsigned char gt = bsbuf[lame_offset] >> 5; /* only first 3 bits */ + if(gt == 1) gt = 0; /* radio */ + else if(gt == 2) gt = 1; /* audiophile */ + else continue; + /* get the 9 bits into a number, divide by 10, multiply sign... happy bit banging */ + replay_gain[0] = ((bsbuf[lame_offset] & 0x2) ? -0.1 : 0.1) * (make_short(bsbuf, lame_offset) & 0x1f); + } + lame_offset += 2; + } + debug1("Info: Radio Gain = %03.1fdB", replay_gain[0]); + debug1("Info: Audiophile Gain = %03.1fdB", replay_gain[1]); + for(i=0; i < 2; ++i) + { + if(rva_level[i] <= 0) + { + rva_peak[i] = 0; /* at some time the parsed peak should be used */ + rva_gain[i] = replay_gain[i]; + rva_level[i] = 0; + } + } + lame_offset += 1; /* skipping encoding flags byte */ + if(vbr == ABR) + { + abr_rate = bsbuf[lame_offset]; + debug1("Info: ABR rate = %u", abr_rate); + } + lame_offset += 1; + /* encoder delay and padding, two 12 bit values... lame does write them from int ...*/ + #ifdef GAPLESS + if(param.gapless) + { + /* + Temporary hack that doesn't work with seeking and also is not waterproof but works most of the time; + in future the lame delay/padding and frame number info should be passed to layer3.c and the junk samples avoided at the source. + */ + unsigned long length = track_frames * spf(fr); + unsigned long skipbegin = DECODER_DELAY + ((((int) bsbuf[lame_offset]) << 4) | (((int) bsbuf[lame_offset+1]) >> 4)); + unsigned long skipend = -DECODER_DELAY + (((((int) bsbuf[lame_offset+1]) << 8) | (((int) bsbuf[lame_offset+2]))) & 0xfff); + debug3("preparing gapless mode for layer3: length %lu, skipbegin %lu, skipend %lu", length, skipbegin, skipend); + if(length > 1) + layer3_gapless_init(skipbegin+GAP_SHIFT, (skipend < length) ? length-skipend+GAP_SHIFT : length+GAP_SHIFT); + } + #endif + } + /* switch buffer back ... */ + bsbuf = bsspace[bsnum]+512; + bsnum = (bsnum + 1) & 1; + goto read_again; + } + } + } + } /* end block for Xing/Lame/Info tag */ + firsthead = newhead; /* _now_ it's time to store it... the first real header */ + debug1("firsthead: %08lx", firsthead); + /* now adjust volume */ + do_rva(); + /* and print id3 info */ + if(!param.quiet) print_id3_tag(rd->flags & READER_ID3TAG ? rd->id3buf : NULL); + } +#endif + + bsi.bitindex = 0; + bsi.wordpointer = (unsigned char *) bsbuf; + set_synth_functions(fr); + if (fr->error_protection) + getbits(16); + return 1; +} + + +#if 0 + +static int stream_back_bytes(struct reader *rds, off_t bytes) +{ + if(stream_lseek(rds,-bytes,SEEK_CUR) < 0) + return -1; + /* you sure you want the buffer to resync here? */ + if(param.usebuffer) + buffer_resync(); + return 0; +} + + +/* this function strangely is define to seek num frames _back_ (and is called with -offset - duh!) */ +/* also... let that int be a long in future! */ +static int stream_back_frame(struct reader *rds,struct frame *fr,long num) +{ + if(rds->flags & READER_SEEKABLE) + { + unsigned long newframe, preframe; + if(num > 0) /* back! */ + { + if(num > fr->num) newframe = 0; + else newframe = fr->num-num; + } + else newframe = fr->num-num; + + /* two leading frames? hm, doesn't seem to be really needed... */ + /*if(newframe > 1) newframe -= 2; + else newframe = 0;*/ + + /* now seek to nearest leading index position and read from there until newframe is reached */ + if(stream_lseek(rds,frame_index_find(newframe, &preframe),SEEK_SET) < 0) + return -1; + + debug2("going to %lu; just got %lu", newframe, preframe); + + fr->num = preframe; + + while(fr->num < newframe) + { + /* try to be non-fatal now... frameNum only gets advanced on success anyway */ + if(!read_frame(fr)) break; + } + + /* this is not needed at last? */ + /*read_frame(fr); + read_frame(fr);*/ + + if(fr->lay == 3) { + set_pointer(512); + } + + debug1("arrived at %lu", fr->num); + + if(param.usebuffer) + buffer_resync(); + + return 0; + + } + else return -1; /* invalid, no seek happened */ +} + +static int stream_head_read(struct reader *rds,unsigned long *newhead) +{ + unsigned char hbuf[4]; + + if(fullread(rds,hbuf,4) != 4) + return FALSE; - if (retval) return 0; - - rd->strremain = bytes; - rd->filepos = bytes; - return 1; -}; - -static int fill_reader(struct reader *rd) -{ int retval; - int bytes; - - mem_cpy(rd->buffer,rd->stream,rd->strremain); - rd->stream = rd->buffer; - - retval=read_file (rd->hFile,rd->buffer+rd->strremain,rd->filepos, - 0x10000-rd->strremain,&bytes); - if (retval) return 0; - if(!bytes) return 0; - rd->strremain+=bytes; - rd->filepos+=bytes; - rd->strpos = 0; - return 1; -}; - -int __stdcall set_reader(struct reader *rd, unsigned int filepos) -{ int retval; - unsigned int bytes; - retval=read_file (rd->hFile,rd->buffer,filepos,0x10000,&bytes); - if (retval) return 0; - rd->stream = rd->buffer; - rd->strremain=bytes; - rd->filepos=filepos+bytes; - rd->strpos = 0; - - fsizeold=0; - firsthead=0; - bsbufold = 0; - bsbuf = bsspace[1]; - bsnum = 0; - ssize=0; - oldhead=0; - memset(bsspace,0,sizeof(bsspace)); - return 1; -}; - -static int stream_head_read(struct reader *rd,unsigned long *newhead) -{ - if(rd->strremain < 4) - if( !fill_reader(rd)) - return 0; - *newhead = (rd->stream[0]<<24)|(rd->stream[1] << 16)| - (rd->stream[2] << 8)| rd->stream[3]; - rd->strpos+=4; - rd->stream+=4; - rd->strremain-=4; - return TRUE; -}; - -int stream_read_raw(struct reader *rd,unsigned char *buf, int size) -{ - if(rd->strremain < size) - if( !fill_reader(rd)) - return 0; - - mem_cpy(buf,rd->stream,size); - rd->strpos+=size; - rd->stream+=size; - rd->strremain-=size; - return 1; -}; - -void set_pointer(long backstep) -{ - bsi.wordpointer = bsbuf + ssize - backstep; - if (backstep) - mem_cpy(bsi.wordpointer,bsbufold+fsizeold-backstep,backstep); - bsi.bitindex = 0; -} - -int head_check(unsigned long head) -{ if - ( - /* first 11 bits are set to 1 for frame sync */ - ((head & 0xffe00000) != 0xffe00000) - || - /* layer: 01,10,11 is 1,2,3; 00 is reserved */ - (!((head>>17)&3)) - || - /* 1111 means bad bitrate */ - (((head>>12)&0xf) == 0xf) - || - /* 0000 means free format... */ - (((head>>12)&0xf) == 0x0) - || - /* sampling freq: 11 is reserved */ - (((head>>10)&0x3) == 0x3 ) - /* here used to be a mpeg 2.5 check... re-enabled 2.5 decoding due to lack of evidence that it is really not good */ - ) - { - return FALSE; - } - /* if no check failed, the header is valid (hopefully)*/ - else - { - return TRUE; - } -} - -int __stdcall decode_header(struct frame *fr,unsigned long newhead) -{ - if(!head_check(newhead)) - return 0; - if( newhead & (1<<20) ) - { fr->lsf = (newhead & (1<<19)) ? 0x0 : 0x1; - fr->mpeg25 = 0; - } - else - { fr->lsf = 1; - fr->mpeg25 = 1; - }; - - fr->lay = 4-((newhead>>17)&3); - if(fr->mpeg25) - fr->sampling_frequency = 6 + ((newhead>>10)&0x3); - else - fr->sampling_frequency = ((newhead>>10)&0x3) + (fr->lsf*3); - fr->error_protection = ((newhead>>16)&0x1)^0x1; - - fr->bitrate_index = ((newhead>>12)&0xf); - fr->padding = ((newhead>>9)&0x1); - fr->extension = ((newhead>>8)&0x1); - fr->mode = ((newhead>>6)&0x3); - fr->mode_ext = ((newhead>>4)&0x3); - fr->copyright = ((newhead>>3)&0x1); - fr->original = ((newhead>>2)&0x1); - fr->emphasis = newhead & 0x3; - - fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2; - - oldhead = newhead; - - if(!fr->bitrate_index) - return (0); - - switch(fr->lay) - { case 1: - fr->do_layer = do_layer1; -#ifdef VARMODESUPPORT - if (varmode) { - error("Sorry, layer-1 not supported in varmode."); - return (0); - } -#endif - fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000; - fr->framesize /= freqs[fr->sampling_frequency]; - fr->framesize = ((fr->framesize+fr->padding)<<2)-4; - break; - case 2: - fr->do_layer = do_layer2; -#ifdef VARMODESUPPORT - if (varmode) { - error("Sorry, layer-2 not supported in varmode."); - return (0); - } -#endif - fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000; - fr->framesize /= freqs[fr->sampling_frequency]; - fr->framesize += fr->padding - 4; - break; - case 3: - fr->do_layer = do_layer3; - if(fr->lsf) - ssize = (fr->stereo == 1) ? 9 : 17; - else - ssize = (fr->stereo == 1) ? 17 : 32; - if(fr->error_protection) - ssize += 2; - fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000; - fr->framesize /= freqs[fr->sampling_frequency]<<(fr->lsf); - fr->framesize = fr->framesize + fr->padding - 4; - break; - default: - return (0); - } - if (fr->framesize > MAXFRAMESIZE) - return (0); - return 1; -} - - -int read_frame(struct reader *rd, struct frame *fr) -{ unsigned long newhead; - static unsigned char ssave[34]; - //off_t framepos; - fsizeold=fr->framesize; /* for Layer3 */ - -read_again: - - if(!rd->head_read(rd,&newhead)) - return FALSE; - - if(!decode_header(fr,newhead)) - { - if((newhead & 0xffffff00) == 0x49443300) - { - int id3length = 0; - id3length = parse_new_id3(rd, newhead); - goto read_again; - }; - rd->strpos-=3; - rd->stream-=3; - rd->strremain+=3; - goto read_again; - }; - -#if 0 - if(1 || oldhead != newhead || !oldhead) - { - -init_resync: - -#ifdef SKIP_JUNK - /* watch out for junk/tags on beginning of stream by invalid header */ - if(!firsthead && !head_check(newhead) && !free_format_header(newhead)) { - int i; - - /* check for id3v2; first three bytes (of 4) are "ID3" */ - if((newhead & (unsigned long) 0xffffff00) == (unsigned long) 0x49443300) - { - int id3length = 0; - id3length = parse_new_id3(newhead, rd); - goto read_again; - } - else if(param.verbose > 1) fprintf(stderr,"Note: Junk at the beginning (0x%08lx)\n",newhead); - - /* I even saw RIFF headers at the beginning of MPEG streams ;( */ - if(newhead == ('R'<<24)+('I'<<16)+('F'<<8)+'F') { - if(param.verbose > 1) fprintf(stderr, "Note: Looks like a RIFF header.\n"); - if(!rd->head_read(rd,&newhead)) - return 0; - while(newhead != ('d'<<24)+('a'<<16)+('t'<<8)+'a') { - if(!rd->head_shift(rd,&newhead)) - return 0; - } - if(!rd->head_read(rd,&newhead)) - return 0; - if(param.verbose > 1) fprintf(stderr,"Note: Skipped RIFF header!\n"); - goto read_again; - } - /* unhandled junk... just continue search for a header */ - /* step in byte steps through next 64K */ - for(i=0;i<65536;i++) { - if(!rd->head_shift(rd,&newhead)) - return 0; - /* if(head_check(newhead)) */ - if(head_check(newhead) && decode_header(fr, newhead)) - break; - } - if(i == 65536) { - if(!param.quiet) error("Giving up searching valid MPEG header after 64K of junk."); - return 0; - } - /* - * should we additionaly check, whether a new frame starts at - * the next expected position? (some kind of read ahead) - * We could implement this easily, at least for files. - */ - } -#endif - - /* first attempt of read ahead check to find the real first header; cannot believe what junk is out there! */ - /* for now, a spurious first free format header screws up here; need free format support for detecting false free format headers... */ - if(!firsthead && rd->flags & READER_SEEKABLE && head_check(newhead) && decode_header(fr, newhead)) - { - unsigned long nexthead = 0; - int hd = 0; - off_t start = rd->tell(rd); - debug1("doing ahead check with BPF %d", fr->framesize+4); - /* step framesize bytes forward and read next possible header*/ - if(rd->back_bytes(rd, -fr->framesize)) - { - error("cannot seek!"); - return 0; - } - hd = rd->head_read(rd,&nexthead); - if(rd->back_bytes(rd, rd->tell(rd)-start)) - { - error("cannot seek!"); - return 0; - } - if(!hd) - { - warning("cannot read next header, a one-frame stream? Duh..."); - } - else - { - debug2("does next header 0x%08lx match first 0x%08lx?", nexthead, newhead); - /* not allowing free format yet */ - if(!head_check(nexthead) || (nexthead & HDRCMPMASK) != (newhead & HDRCMPMASK)) - { - debug("No, the header was not valid, start from beginning..."); - /* try next byte for valid header */ - if(rd->back_bytes(rd, 3)) - { - error("cannot seek!"); - return 0; - } - goto read_again; - } - } - } - - /* why has this head check been avoided here before? */ - if(!head_check(newhead)) - { - if(!firsthead && free_format_header(newhead)) - { - error1("Header 0x%08lx seems to indicate a free format stream; I do not handle that yet", newhead); - goto read_again; - return 0; - } - /* and those ugly ID3 tags */ - if((newhead & 0xffffff00) == ('T'<<24)+('A'<<16)+('G'<<8)) { - rd->skip_bytes(rd,124); - if (param.verbose > 1) fprintf(stderr,"Note: Skipped ID3 Tag!\n"); - goto read_again; - } - /* duplicated code from above! */ - /* check for id3v2; first three bytes (of 4) are "ID3" */ - if((newhead & (unsigned long) 0xffffff00) == (unsigned long) 0x49443300) - { - int id3length = 0; - id3length = parse_new_id3(newhead, rd); - goto read_again; - } - else if (give_note) - { - fprintf(stderr,"Note: Illegal Audio-MPEG-Header 0x%08lx at offset 0x%lx.\n", newhead,rd->tell(rd)-4); - } - - if(give_note && (newhead & 0xffffff00) == ('b'<<24)+('m'<<16)+('p'<<8)) fprintf(stderr,"Note: Could be a BMP album art.\n"); - if (param.tryresync || do_recover) { - int try = 0; - /* TODO: make this more robust, I'd like to cat two mp3 fragments together (in a dirty way) and still have mpg123 beign able to decode all it somehow. */ - if(give_note) fprintf(stderr, "Note: Trying to resync...\n"); - /* Read more bytes until we find something that looks - reasonably like a valid header. This is not a - perfect strategy, but it should get us back on the - track within a short time (and hopefully without - too much distortion in the audio output). */ - do { - if(!rd->head_shift(rd,&newhead)) - return 0; - /* debug2("resync try %i, got newhead 0x%08lx", try, newhead); */ - if (!oldhead) - { - debug("going to init_resync..."); - goto init_resync; /* "considered harmful", eh? */ - } - /* we should perhaps collect a list of valid headers that occured in file... there can be more */ - /* Michael's new resync routine seems to work better with the one frame readahead (and some input buffering?) */ - } while - ( - ++try < RESYNC_LIMIT - && (newhead & HDRCMPMASK) != (oldhead & HDRCMPMASK) - && (newhead & HDRCMPMASK) != (firsthead & HDRCMPMASK) - ); - /* too many false positives - }while (!(head_check(newhead) && decode_header(fr, newhead))); */ - if(try == RESYNC_LIMIT) - { - error("giving up resync - your stream is not nice... perhaps an improved routine could catch up"); - return 0; - } - - if (give_note) - fprintf (stderr, "Note: Skipped %d bytes in input.\n", try); - } - else - { - error("not attempting to resync..."); - return (0); - } - } - - if (!firsthead) { - if(!decode_header(fr,newhead)) - { - error("decode header failed before first valid one, going to read again"); - goto read_again; - } - } - else - if(!decode_header(fr,newhead)) - { - error("decode header failed - goto resync"); - /* return 0; */ - goto init_resync; - } - } - else - fr->header_change = 0; -#endif - - bsbufold = bsbuf; - bsbuf = bsspace[bsnum]+512; - bsnum = (bsnum + 1) & 1; - /* if filepos is invalid, so is framepos */ - //framepos = rd->filepos - 4; - /* read main data into memory */ - /* 0 is error! */ - - if(!rd->read_frame_body(rd,bsbuf,fr->framesize)) - return 0; - -#if 0 - if(!firsthead) - { - /* following stuff is actually layer3 specific (in practice, not in theory) */ - if(fr->lay == 3) - { - /* - going to look for Xing or Info at some position after the header - MPEG 1 MPEG 2/2.5 (LSF) - Stereo, Joint Stereo, Dual Channel 32 17 - Mono 17 9 - - Also, how to avoid false positives? I guess I should interpret more of the header to rule that out(?). - I hope that ensuring all zeros until tag start is enough. - */ - size_t lame_offset = (fr->stereo == 2) ? (fr->lsf ? 17 : 32 ) : (fr->lsf ? 9 : 17); - if(fr->framesize >= 120+lame_offset) /* traditional Xing header is 120 bytes */ - { - size_t i; - int lame_type = 0; - /* only search for tag when all zero before it (apart from checksum) */ - for(i=2; i < lame_offset; ++i) if(bsbuf[i] != 0) break; - if(i == lame_offset) - { - if - ( - (bsbuf[lame_offset] == 'I') - && (bsbuf[lame_offset+1] == 'n') - && (bsbuf[lame_offset+2] == 'f') - && (bsbuf[lame_offset+3] == 'o') - ) - { - lame_type = 1; /* We still have to see what there is */ - } - else if - ( - (bsbuf[lame_offset] == 'X') - && (bsbuf[lame_offset+1] == 'i') - && (bsbuf[lame_offset+2] == 'n') - && (bsbuf[lame_offset+3] == 'g') - ) - { - lame_type = 2; - vbr = VBR; /* Xing header means always VBR */ - } - if(lame_type) - { - unsigned long xing_flags; - - /* we have one of these headers... */ - if(param.verbose > 1) fprintf(stderr, "Note: Xing/Lame/Info header detected\n"); - /* now interpret the Xing part, I have 120 bytes total for sure */ - /* there are 4 bytes for flags, but only the last byte contains known ones */ - lame_offset += 4; /* now first byte after Xing/Name */ - /* 4 bytes dword for flags */ - #define make_long(a, o) ((((unsigned long) a[o]) << 24) | (((unsigned long) a[o+1]) << 16) | (((unsigned long) a[o+2]) << 8) | ((unsigned long) a[o+3])) - /* 16 bit */ - #define make_short(a,o) ((((unsigned short) a[o]) << 8) | ((unsigned short) a[o+1])) - xing_flags = make_long(bsbuf, lame_offset); - lame_offset += 4; - debug1("Xing: flags 0x%08lx", xing_flags); - if(xing_flags & 1) /* frames */ - { - /* - In theory, one should use that value for skipping... - When I know the exact number of samples I could simply count in audio_flush, - but that's problematic with seeking and such. - I still miss the real solution for detecting the end. - */ - track_frames = make_long(bsbuf, lame_offset); - if(track_frames > TRACK_MAX_FRAMES) track_frames = 0; /* endless stream? */ - #ifdef GAPLESS - /* if no further info there, remove/add at least the decoder delay */ - if(param.gapless) - { - unsigned long length = track_frames * spf(fr); - if(length > 1) - layer3_gapless_init(DECODER_DELAY+GAP_SHIFT, length+DECODER_DELAY+GAP_SHIFT); - } - #endif - debug1("Xing: %lu frames", track_frames); - lame_offset += 4; - } - if(xing_flags & 0x2) /* bytes */ - { - #ifdef DEBUG - unsigned long xing_bytes = make_long(bsbuf, lame_offset); - debug1("Xing: %lu bytes", xing_bytes); - #endif - lame_offset += 4; - } - if(xing_flags & 0x4) /* TOC */ - { - lame_offset += 100; /* just skip */ - } - if(xing_flags & 0x8) /* VBR quality */ - { - #ifdef DEBUG - unsigned long xing_quality = make_long(bsbuf, lame_offset); - debug1("Xing: quality = %lu", xing_quality); - #endif - lame_offset += 4; - } - /* I guess that either 0 or LAME extra data follows */ - /* there may this crc16 be floating around... (?) */ - if(bsbuf[lame_offset] != 0) - { - unsigned char lame_vbr; - float replay_gain[2] = {0,0}; - float peak = 0; - float gain_offset = 0; /* going to be +6 for old lame that used 83dB */ - char nb[10]; - memcpy(nb, bsbuf+lame_offset, 9); - nb[9] = 0; - debug1("Info: Encoder: %s", nb); - if(!strncmp("LAME", nb, 4)) - { - gain_offset = 6; - debug("TODO: finish lame detetcion..."); - } - lame_offset += 9; - /* the 4 big bits are tag revision, the small bits vbr method */ - lame_vbr = bsbuf[lame_offset] & 15; - debug1("Info: rev %u", bsbuf[lame_offset] >> 4); - debug1("Info: vbr mode %u", lame_vbr); - lame_offset += 1; - switch(lame_vbr) - { - /* from rev1 proposal... not sure if all good in practice */ - case 1: - case 8: vbr = CBR; break; - case 2: - case 9: vbr = ABR; break; - default: vbr = VBR; /* 00==unknown is taken as VBR */ - } - /* skipping: lowpass filter value */ - lame_offset += 1; - /* replaygain */ - /* 32bit float: peak amplitude -- why did I parse it as int before??*/ - /* Ah, yes, lame seems to store it as int since some day in 2003; I've only seen zeros anyway until now, bah! */ - if - ( - (bsbuf[lame_offset] != 0) - || (bsbuf[lame_offset+1] != 0) - || (bsbuf[lame_offset+2] != 0) - || (bsbuf[lame_offset+3] != 0) - ) - { - debug("Wow! Is there _really_ a non-zero peak value? Now is it stored as float or int - how should I know?"); - peak = *(float*) (bsbuf+lame_offset); - } - debug1("Info: peak = %f (I won't use this)", peak); - peak = 0; /* until better times arrived */ - lame_offset += 4; - /* - ReplayGain values - lame only writes radio mode gain... - 16bit gain, 3 bits name, 3 bits originator, sign (1=-, 0=+), dB value*10 in 9 bits (fixed point) - ignore the setting if name or originator == 000! - radio 0 0 1 0 1 1 1 0 0 1 1 1 1 1 0 1 - audiophile 0 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 - */ - - for(i =0; i < 2; ++i) - { - unsigned char origin = (bsbuf[lame_offset] >> 2) & 0x7; /* the 3 bits after that... */ - if(origin != 0) - { - unsigned char gt = bsbuf[lame_offset] >> 5; /* only first 3 bits */ - if(gt == 1) gt = 0; /* radio */ - else if(gt == 2) gt = 1; /* audiophile */ - else continue; - /* get the 9 bits into a number, divide by 10, multiply sign... happy bit banging */ - replay_gain[0] = ((bsbuf[lame_offset] & 0x2) ? -0.1 : 0.1) * (make_short(bsbuf, lame_offset) & 0x1f); - } - lame_offset += 2; - } - debug1("Info: Radio Gain = %03.1fdB", replay_gain[0]); - debug1("Info: Audiophile Gain = %03.1fdB", replay_gain[1]); - for(i=0; i < 2; ++i) - { - if(rva_level[i] <= 0) - { - rva_peak[i] = 0; /* at some time the parsed peak should be used */ - rva_gain[i] = replay_gain[i]; - rva_level[i] = 0; - } - } - lame_offset += 1; /* skipping encoding flags byte */ - if(vbr == ABR) - { - abr_rate = bsbuf[lame_offset]; - debug1("Info: ABR rate = %u", abr_rate); - } - lame_offset += 1; - /* encoder delay and padding, two 12 bit values... lame does write them from int ...*/ - #ifdef GAPLESS - if(param.gapless) - { - /* - Temporary hack that doesn't work with seeking and also is not waterproof but works most of the time; - in future the lame delay/padding and frame number info should be passed to layer3.c and the junk samples avoided at the source. - */ - unsigned long length = track_frames * spf(fr); - unsigned long skipbegin = DECODER_DELAY + ((((int) bsbuf[lame_offset]) << 4) | (((int) bsbuf[lame_offset+1]) >> 4)); - unsigned long skipend = -DECODER_DELAY + (((((int) bsbuf[lame_offset+1]) << 8) | (((int) bsbuf[lame_offset+2]))) & 0xfff); - debug3("preparing gapless mode for layer3: length %lu, skipbegin %lu, skipend %lu", length, skipbegin, skipend); - if(length > 1) - layer3_gapless_init(skipbegin+GAP_SHIFT, (skipend < length) ? length-skipend+GAP_SHIFT : length+GAP_SHIFT); - } - #endif - } - /* switch buffer back ... */ - bsbuf = bsspace[bsnum]+512; - bsnum = (bsnum + 1) & 1; - goto read_again; - } - } - } - } /* end block for Xing/Lame/Info tag */ - firsthead = newhead; /* _now_ it's time to store it... the first real header */ - debug1("firsthead: %08lx", firsthead); - /* now adjust volume */ - do_rva(); - /* and print id3 info */ - if(!param.quiet) print_id3_tag(rd->flags & READER_ID3TAG ? rd->id3buf : NULL); - } -#endif - - bsi.bitindex = 0; - bsi.wordpointer = (unsigned char *) bsbuf; - set_synth_functions(fr); - if (fr->error_protection) - getbits(16); - return 1; -} - - -#if 0 - -static int stream_back_bytes(struct reader *rds, off_t bytes) -{ - if(stream_lseek(rds,-bytes,SEEK_CUR) < 0) - return -1; - /* you sure you want the buffer to resync here? */ - if(param.usebuffer) - buffer_resync(); - return 0; -} - - -/* this function strangely is define to seek num frames _back_ (and is called with -offset - duh!) */ -/* also... let that int be a long in future! */ -static int stream_back_frame(struct reader *rds,struct frame *fr,long num) -{ - if(rds->flags & READER_SEEKABLE) - { - unsigned long newframe, preframe; - if(num > 0) /* back! */ - { - if(num > fr->num) newframe = 0; - else newframe = fr->num-num; - } - else newframe = fr->num-num; - - /* two leading frames? hm, doesn't seem to be really needed... */ - /*if(newframe > 1) newframe -= 2; - else newframe = 0;*/ - - /* now seek to nearest leading index position and read from there until newframe is reached */ - if(stream_lseek(rds,frame_index_find(newframe, &preframe),SEEK_SET) < 0) - return -1; - - debug2("going to %lu; just got %lu", newframe, preframe); - - fr->num = preframe; - - while(fr->num < newframe) - { - /* try to be non-fatal now... frameNum only gets advanced on success anyway */ - if(!read_frame(fr)) break; - } - - /* this is not needed at last? */ - /*read_frame(fr); - read_frame(fr);*/ - - if(fr->lay == 3) { - set_pointer(512); - } - - debug1("arrived at %lu", fr->num); - - if(param.usebuffer) - buffer_resync(); - - return 0; - - } - else return -1; /* invalid, no seek happened */ -} - -static int stream_head_read(struct reader *rds,unsigned long *newhead) -{ - unsigned char hbuf[4]; - - if(fullread(rds,hbuf,4) != 4) - return FALSE; - - *newhead = ((unsigned long) hbuf[0] << 24) | - ((unsigned long) hbuf[1] << 16) | - ((unsigned long) hbuf[2] << 8) | - (unsigned long) hbuf[3]; - - return TRUE; -} - -static int stream_head_shift(struct reader *rds,unsigned long *head) -{ - unsigned char hbuf; - - if(fullread(rds,&hbuf,1) != 1) - return 0; - *head <<= 8; - *head |= hbuf; - *head &= 0xffffffff; - return 1; -} - -static off_t stream_skip_bytes(struct reader *rds,off_t len) -{ - if (rds->filelen >= 0) { - off_t ret = stream_lseek(rds, len, SEEK_CUR); - if (param.usebuffer) - buffer_resync(); - return ret; - } else if (len >= 0) { - unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */ - off_t ret; - while (len > 0) { - off_t num = len < sizeof(buf) ? len : sizeof(buf); - ret = fullread(rds, buf, num); - if (ret < 0) - return ret; - len -= ret; - } - return rds->filepos; - } else - return -1; -} - -static int stream_read_frame_body(struct reader *rds,unsigned char *buf, - int size) -{ - long l; - - if( (l=fullread(rds,buf,size)) != size) - { - if(l <= 0) - return 0; - memset(buf+l,0,size-l); - } - - return 1; -} - -static off_t stream_tell(struct reader *rds) -{ - return rds->filepos; -} - -static void stream_rewind(struct reader *rds) -{ - stream_lseek(rds,0,SEEK_SET); - if(param.usebuffer) - buffer_resync(); -} - -static off_t get_fileinfo(struct reader *rds,char *buf) -{ - off_t len; - - if((len=lseek(rds->filept,0,SEEK_END)) < 0) { - return -1; - } - if(lseek(rds->filept,-128,SEEK_END) < 0) - return -1; - if(fullread(rds,(unsigned char *)buf,128) != 128) { - return -1; - } - if(!strncmp(buf,"TAG",3)) { - len -= 128; - } - if(lseek(rds->filept,0,SEEK_SET) < 0) - return -1; - if(len <= 0) - return -1; - return len; -} - -#endif - - #define syncsafe_to_long(buf,res) \ - ( \ - (((buf)[0]|(buf)[1]|(buf)[2]|(buf)[3]) & 0x80) ? 0 : \ - (res = (((unsigned long) (buf)[0]) << 27) \ - | (((unsigned long) (buf)[1]) << 14) \ - | (((unsigned long) (buf)[2]) << 7) \ - | ((unsigned long) (buf)[3]) \ - ,1) \ - ) - + *newhead = ((unsigned long) hbuf[0] << 24) | + ((unsigned long) hbuf[1] << 16) | + ((unsigned long) hbuf[2] << 8) | + (unsigned long) hbuf[3]; + + return TRUE; +} + +static int stream_head_shift(struct reader *rds,unsigned long *head) +{ + unsigned char hbuf; + + if(fullread(rds,&hbuf,1) != 1) + return 0; + *head <<= 8; + *head |= hbuf; + *head &= 0xffffffff; + return 1; +} + +static off_t stream_skip_bytes(struct reader *rds,off_t len) +{ + if (rds->filelen >= 0) { + off_t ret = stream_lseek(rds, len, SEEK_CUR); + if (param.usebuffer) + buffer_resync(); + return ret; + } else if (len >= 0) { + unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */ + off_t ret; + while (len > 0) { + off_t num = len < sizeof(buf) ? len : sizeof(buf); + ret = fullread(rds, buf, num); + if (ret < 0) + return ret; + len -= ret; + } + return rds->filepos; + } else + return -1; +} + +static int stream_read_frame_body(struct reader *rds,unsigned char *buf, + int size) +{ + long l; + + if( (l=fullread(rds,buf,size)) != size) + { + if(l <= 0) + return 0; + memset(buf+l,0,size-l); + } + + return 1; +} + +static off_t stream_tell(struct reader *rds) +{ + return rds->filepos; +} + +static void stream_rewind(struct reader *rds) +{ + stream_lseek(rds,0,SEEK_SET); + if(param.usebuffer) + buffer_resync(); +} + +static off_t get_fileinfo(struct reader *rds,char *buf) +{ + off_t len; + + if((len=lseek(rds->filept,0,SEEK_END)) < 0) { + return -1; + } + if(lseek(rds->filept,-128,SEEK_END) < 0) + return -1; + if(fullread(rds,(unsigned char *)buf,128) != 128) { + return -1; + } + if(!strncmp(buf,"TAG",3)) { + len -= 128; + } + if(lseek(rds->filept,0,SEEK_SET) < 0) + return -1; + if(len <= 0) + return -1; + return len; +} + +#endif + + #define syncsafe_to_long(buf,res) \ + ( \ + (((buf)[0]|(buf)[1]|(buf)[2]|(buf)[3]) & 0x80) ? 0 : \ + (res = (((unsigned long) (buf)[0]) << 27) \ + | (((unsigned long) (buf)[1]) << 14) \ + | (((unsigned long) (buf)[2]) << 7) \ + | ((unsigned long) (buf)[3]) \ + ,1) \ + ) + int parse_new_id3(struct reader *rd, unsigned long header) { - #define UNSYNC_FLAG 128 - #define EXTHEAD_FLAG 64 - #define EXP_FLAG 32 - #define FOOTER_FLAG 16 - #define UNKNOWN_FLAGS 15 /* 00001111*/ - unsigned char buf[6]; - unsigned long length=0; - unsigned char flags = 0; - int ret = 1; - unsigned char* tagdata = NULL; - unsigned char major = header & 0xff; - - if(major == 0xff) return -1; - - if (!rd->read_frame_body(rd,buf,6)) - return 0; - if(buf[0] == 0xff) /* major version, will never be 0xff */ - return -1; - - /* second new byte are some nice flags, if these are invalid skip the whole thing */ - flags = buf[1]; - /* use 4 bytes from buf to construct 28bit uint value and return 1; return 0 if bytes are not syncsafe */ + #define UNSYNC_FLAG 128 + #define EXTHEAD_FLAG 64 + #define EXP_FLAG 32 + #define FOOTER_FLAG 16 + #define UNKNOWN_FLAGS 15 /* 00001111*/ + unsigned char buf[6]; + unsigned long length=0; + unsigned char flags = 0; + int ret = 1; + unsigned char* tagdata = NULL; + unsigned char major = header & 0xff; - if(!syncsafe_to_long(buf+2,length)) - return -1; - - - rd->strpos+=length; - rd->stream+=length; - rd->strremain-=length; - -#if 0 - /* skip if unknown version/scary flags, parse otherwise */ - if((flags & UNKNOWN_FLAGS) || (major > 4)) - { - /* going to skip because there are unknown flags set */ - if(!rds->skip_bytes(rds,length)) /* will not store data in backbuff! */ - - rd->strpos+=length; - rd->stream+=length; - rd->strremain-=length; - ret = 0; - }; -#endif + if(major == 0xff) return -1; + + if (rd->read_frame_body(rd,buf,6)<6) + return 0; + if(buf[0] == 0xff) /* major version, will never be 0xff */ + return -1; + + /* second new byte are some nice flags, if these are invalid skip the whole thing */ + flags = buf[1]; + /* use 4 bytes from buf to construct 28bit uint value and return 1; return 0 if bytes are not syncsafe */ + + if(!syncsafe_to_long(buf+2,length)) + return -1; + + + rd->strpos+=length; + rd->stream+=length; + rd->strremain-=length; + +#if 0 + /* skip if unknown version/scary flags, parse otherwise */ + if((flags & UNKNOWN_FLAGS) || (major > 4)) + { + /* going to skip because there are unknown flags set */ + if(!rds->skip_bytes(rds,length)) /* will not store data in backbuff! */ + + rd->strpos+=length; + rd->stream+=length; + rd->strremain-=length; + ret = 0; + }; +#endif return length; }; diff --git a/programs/media/ac97snd/ufmod-codec.h b/programs/media/ac97snd/ufmod-codec.h new file mode 100644 index 0000000000..0f382b50b6 --- /dev/null +++ b/programs/media/ac97snd/ufmod-codec.h @@ -0,0 +1,90 @@ +/* + uFMOD AC97SND codec header file + Target OS: KolibriOS + Compiler: Visual C + + NOTE: ufmod.obj should be rebuilt setting UF_MODE=AC97SND + in order to make it usable in AC97SND player. + + The Infinity Sound driver handle should be available as + a public symbol named hSound. It is so when using Serge's + sound.lib. +*/ + +#ifdef __cplusplus + extern "C" { +#endif + +/* HANDLE uFMOD_LoadSong(char *lpXM); + --- + Description: + --- + Loads the given XM song and starts playing it as soon as you + call uFMOD_WaveOut for the first time. It will stop any + currently playing song before loading the new one. Heap should + be initialized before calling this function! + --- + Parameters: + --- + lpXM + Specifies the filename of the song to load. + --- + Return Values: + --- + On success, returns a non zero value. Returns 0 on failure. +*/ +int __cdecl uFMOD_LoadSong(char*); + +/* int uFMOD_WaveOut(SNDBUF hBuff) + --- + Description: + --- + Updates the internal playback buffer. + --- + Parameters: + --- + hBuff + The Infinity Sound buffer to update. + --- + Remarks: + --- + Playback doesn't actually begin when calling uFMOD_LoadSong, + but when calling uFMOD_WaveOut after a successful uFMOD_LoadSong + call. Afterwards, you should call uFMOD_WaveOut repeatedly at + least once every 250 ms to prevent "buffer underruns". + uFMOD_WaveOut is a non-blocking function. + --- + Return Values: + --- + Returns non zero on error. +*/ +int __cdecl uFMOD_WaveOut(unsigned int); + +/* void uFMOD_StopSong(void) + --- + Description: + --- + Stops the currently playing song, freeing the associated + resources. + --- + Remarks: + --- + Does nothing if no song is playing at the time the call is made. +*/ +void __cdecl uFMOD_StopSong(); + +/* unsigned char* _uFMOD_GetTitle(void) + --- + Description: + --- + Returns the current song's title. + --- + Remarks: + --- + Not every song has a title, so be prepared to get an empty string. +*/ +unsigned char* __cdecl uFMOD_GetTitle(); + +#ifdef __cplusplus + } +#endif