Subversion Repositories Kolibri OS

Compare Revisions

Ignore whitespace Rev 606 → Rev 646

/programs/media/ac97snd/ac97snd/ac97snd.vcproj
14,7 → 14,7
</Platforms>
<ToolFiles>
<ToolFile
RelativePath="../fasm.rules"
RelativePath="..\..\..\VStudio 8\Common7\IDE\fasm.rules"
/>
</ToolFiles>
<Configurations>
141,7 → 141,8
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
InlineFunctionExpansion="0"
EnableIntrinsicFunctions="false"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
166,7 → 167,7
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="$(OutDir)\sound.lib $(OutDir)\mpg.lib"
AdditionalDependencies="$(OutDir)\sound.lib $(OutDir)\mpg.lib $(OutDir)\ufmod.obj"
LinkIncremental="1"
GenerateManifest="false"
IgnoreAllDefaultLibraries="true"
221,6 → 222,17
<File
RelativePath=".\ac97wav.c"
>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="0"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\crt.c"
/programs/media/ac97snd/ac97snd/ac97wav.c
18,8 → 18,9
#include "ac97wav.h"
#include "../mpg/mpg123.h"
#include "../sound.h"
#include "../ufmod-codec.h" /* uFMOD integration */
void exit(); /* uFMOD integration */
 
 
#define MP3_ERROR_OUT_OF_BUFFER 5
int m_last_error;
 
29,8 → 30,11
 
void touch(char *buf, int size);
int mp3FindSync(byte* buf, int size, int* sync);
int stream_read_raw(struct reader *rd,unsigned char *buf, int size);
int stream_read_raw(struct reader *rd,unsigned char *buf, int size);
 
int __cdecl _stricmp (const char * dst, const char * src);
char *__cdecl strrchr (const char * string,int ch);
 
char *fname;
 
struct reader rd;
43,6 → 47,8
CTRL_INFO info;
 
FILEINFO fileinfo;
const char *filename;
const char *fileext;
 
int m_vol;
int l_vol=-700; //-7db
62,14 → 68,18
int outremain;
int totalout;
int done;
 
char header[] = "AC97 MP3 player";
char buttons_text[]=" Play Stop << >> Vol- Vol+";
char buttons_xm[] = " Play Stop Vol- Vol+"; /* uFMOD integration */
char buttons_wav[] = " Play Stop << >> Vol- Vol+"; /* uFMOD integration */
char *buttons_text = buttons_wav; /* uFMOD integration */
 
void play_xm(); /* uFMOD integration */
void (*snd_play)();
 
void draw_window()
{
int len; /* uFMOD integration */
BeginDraw();
 
DrawWindow(100,100,299,72,0x404040,3,0,0,0);
85,12 → 95,13
draw_bar(7,41,286,11,0x404040);
 
draw_bar(7,55,286,11,0x404040);
write_text(12,58,0x004000|FONT0, fname, strlen(fname));
write_text(11,57,0x00FF20|FONT0, fname, strlen(fname));
len = strlen(filename); /* uFMOD integration */
if(len > 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();
};
97,7 → 108,7
 
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 retval;
int err;
int ver;
unsigned char *ttl, *cur; /* uFMOD integration */
fname = argv[1];
debug_out_str("\n\rPlay file ");
157,29 → 169,75
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;
if (err = CreateBuffer(fmt,0, &hBuff))
206,6 → 264,7
continue;
 
case ST_EXIT:
uFMOD_StopSong(); /* uFMOD integration */
StopBuffer(hBuff);
DestroyBuffer(hBuff);
return 0;
217,7 → 276,7
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
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
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_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 *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
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
 
// debug_out_hex(fmt);
// debug_out_str("\x0D\x0A\x00");
 
 
 
/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}") = "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}"
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
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{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
{6BB005B0-3277-4C8C-950F-38E15A4E440C}.Release|Win32.ActiveCfg = Release|Win32
{6BB005B0-3277-4C8C-950F-38E15A4E440C}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
/programs/media/ac97snd/mpg/mpg.vcproj
14,7 → 14,7
</Platforms>
<ToolFiles>
<ToolFile
RelativePath="../fasm.rules"
RelativePath="..\..\..\VStudio 8\Common7\IDE\fasm.rules"
/>
</ToolFiles>
<Configurations>
229,6 → 229,16
<File
RelativePath=".\readers.c"
>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
EnableIntrinsicFunctions="true"
WholeProgramOptimization="true"
AssemblerOutput="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\tabinit.c"
/programs/media/ac97snd/mpg/mpg123.h
1,361 → 1,361
/*
mpg123: main code of the program (not of the decoder...)
 
copyright 1995-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.de
initially written by Michael Hipp
 
mpg123 defines
used source: musicout.h from mpegaudio package
*/
 
/*
mpg123: main code of the program (not of the decoder...)
 
copyright 1995-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.de
initially written by Michael Hipp
 
mpg123 defines
used source: musicout.h from mpegaudio package
*/
 
#ifdef __cplusplus
extern "C" {
#endif
 
#include <stdio.h>
#include <math.h>
#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 <stdio.h>
#include <math.h>
#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
}
/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;
};
/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