| #include "util.h" |
| #include "get_audio.h" |
| #ifdef HAVEGTK |
| #include "gtkanal.h" |
| #include <gtk/gtk.h> |
| #endif |
| |
| #if (defined LIBSNDFILE || defined LAMESNDFILE) |
| |
| #ifdef _WIN32 |
| /* needed to set stdin to binary on windoze machines */ |
| #include <io.h> |
| #endif |
| |
| |
| |
| static FILE *musicin=NULL; /* input file pointer */ |
| static unsigned long num_samples; |
| static int samp_freq; |
| static int input_bitrate; |
| static int num_channels; |
| static int count_samples_carefully; |
| |
| int read_samples_pcm(lame_global_flags *gfp,short sample_buffer[2304],int frame_size, int samples_to_read); |
| int read_samples_mp3(lame_global_flags *gfp,FILE *musicin,short int mpg123pcm[2][1152],int num_chan); |
| |
| |
| |
| |
| |
| void lame_init_infile(lame_global_flags *gfp) |
| { |
| /* open the input file */ |
| count_samples_carefully=0; |
| OpenSndFile(gfp,gfp->inPath,gfp->in_samplerate,gfp->num_channels); |
| /* if GetSndSampleRate is non zero, use it to overwrite the default */ |
| if (GetSndSampleRate()) gfp->in_samplerate=GetSndSampleRate(); |
| if (GetSndChannels()) gfp->num_channels=GetSndChannels(); |
| gfp->num_samples = GetSndSamples(); |
| } |
| void lame_close_infile(lame_global_flags *gfp) |
| { |
| CloseSndFile(gfp); |
| } |
| |
| |
| |
| |
| /************************************************************************ |
| * |
| * lame_readframe() |
| * |
| * PURPOSE: reads a frame of audio data from a file to the buffer, |
| * aligns the data for future processing, and separates the |
| * left and right channels |
| * |
| * |
| ************************************************************************/ |
| int lame_readframe(lame_global_flags *gfp,short int Buffer[2][1152]) |
| { |
| int iread; |
| |
| /* note: if input is gfp->stereo and output is mono, get_audio() |
| * will return .5*(L+R) in channel 0, and nothing in channel 1. */ |
| iread = get_audio(gfp,Buffer,gfp->stereo); |
| |
| /* check to see if we overestimated/underestimated totalframes */ |
| if (iread==0) gfp->totalframes = Min(gfp->totalframes,gfp->frameNum+2); |
| if (gfp->frameNum > (gfp->totalframes-1)) gfp->totalframes = gfp->frameNum; |
| return iread; |
| } |
| |
| |
| |
| |
| |
| /************************************************************************ |
| * |
| * get_audio() |
| * |
| * PURPOSE: reads a frame of audio data from a file to the buffer, |
| * aligns the data for future processing, and separates the |
| * left and right channels |
| * |
| * |
| ************************************************************************/ |
| int get_audio(lame_global_flags *gfp,short buffer[2][1152],int stereo) |
| { |
| |
| int j; |
| short insamp[2304]; |
| int samples_read; |
| int framesize,samples_to_read; |
| static unsigned long num_samples_read; |
| unsigned long remaining; |
| int num_channels = gfp->num_channels; |
| |
| if (gfp->frameNum==0) { |
| num_samples_read=0; |
| num_samples= GetSndSamples(); |
| } |
| framesize = gfp->mode_gr*576; |
| |
| samples_to_read = framesize; |
| if (count_samples_carefully) { |
| /* if this flag has been set, then we are carefull to read |
| * exactly num_samples and no more. This is usefull for .wav and .aiff |
| * files which have id3 or other tags at the end. Note that if you |
| * are using LIBSNDFILE, this is not necessary */ |
| remaining=num_samples-Min(num_samples,num_samples_read); |
| if (remaining < (unsigned long)framesize) |
| samples_to_read = remaining; |
| } |
| |
| |
| if (gfp->input_format==sf_mp3) { |
| /* decode an mp3 file for the input */ |
| samples_read=read_samples_mp3(gfp,musicin,buffer,num_channels); |
| }else{ |
| samples_read = read_samples_pcm(gfp,insamp,num_channels*framesize,num_channels*samples_to_read); |
| samples_read /=num_channels; |
| |
| for(j=0;j<framesize;j++) { |
| buffer[0][j] = insamp[num_channels*j]; |
| if (num_channels==2) buffer[1][j] = insamp[2*j+1]; |
| else buffer[1][j]=0; |
| } |
| } |
| |
| /* dont count things in this case to avoid overflows */ |
| if (num_samples!=MAX_U_32_NUM) num_samples_read += samples_read; |
| return(samples_read); |
| |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| int GetSndBitrate(void) |
| { |
| return input_bitrate; |
| } |
| |
| |
| |
| |
| |
| |
| int read_samples_mp3(lame_global_flags *gfp,FILE *musicin,short int mpg123pcm[2][1152],int stereo) |
| { |
| #if (defined AMIGA_MPEGA || defined HAVEMPGLIB) |
| int j,out=0; |
| #ifdef HAVEGTK |
| static int framesize=0; |
| int ch; |
| #endif |
| |
| out=lame_decode_fromfile(musicin,mpg123pcm[0],mpg123pcm[1]); |
| /* out = -1: error, probably EOF */ |
| /* out = 0: not possible with lame_decode_fromfile() */ |
| /* out = number of output samples */ |
| |
| if (out==-1) { |
| for ( j = 0; j < 1152; j++ ) { |
| mpg123pcm[0][j] = 0; |
| mpg123pcm[1][j] = 0; |
| } |
| } |
| |
| |
| #ifdef HAVEGTK |
| if (gfp->gtkflag) { |
| framesize=1152; |
| if (out==576) framesize=576; |
| |
| /* add a delay of framesize-DECDELAY, which will make the total delay |
| * exactly one frame, so we can sync MP3 output with WAV input */ |
| |
| for ( ch = 0; ch < stereo; ch++ ) { |
| for ( j = 0; j < framesize-DECDELAY; j++ ) |
| pinfo->pcmdata2[ch][j] = pinfo->pcmdata2[ch][j+framesize]; |
| for ( j = 0; j < framesize; j++ ) |
| pinfo->pcmdata2[ch][j+framesize-DECDELAY] = mpg123pcm[ch][j]; |
| } |
| |
| pinfo->frameNum123 = gfp->frameNum-1; |
| pinfo->frameNum = gfp->frameNum; |
| } |
| #endif |
| if (out==-1) return 0; |
| else return out; |
| #else |
| fprintf(stderr,"Error: libmp3lame was not compiled with I/O support \n"); |
| exit(1); |
| #endif |
| } |
| #endif /* LAMESNDFILE or LIBSNDFILE */ |
| |
| |
| |
| |
| #ifdef LIBSNDFILE |
| /* |
| ** Copyright (C) 1999 Albert Faber |
| ** |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| * Boston, MA 02111-1307, USA. |
| */ |
| |
| |
| #include <stdio.h> |
| |
| /* External references */ |
| |
| static SNDFILE* gs_pSndFileIn=NULL; |
| static SF_INFO gs_wfInfo; |
| |
| |
| unsigned long GetSndSamples(void) |
| { |
| return gs_wfInfo.samples; |
| } |
| int GetSndSampleRate(void) |
| { |
| return gs_wfInfo.samplerate; |
| } |
| |
| int GetSndChannels(void) |
| { |
| return gs_wfInfo.channels; |
| } |
| |
| void CloseSndFile(lame_global_flags *gfp) |
| { |
| if (gfp->input_format==sf_mp3) { |
| #ifndef AMIGA_MPEGA |
| if (fclose(musicin) != 0){ |
| fprintf(stderr, "Could not close audio input file\n"); |
| exit(2); |
| } |
| #endif |
| }else{ |
| if (gs_pSndFileIn) |
| { |
| if (sf_close(gs_pSndFileIn) !=0) |
| { |
| fprintf(stderr, "Could not close sound file \n"); |
| exit(2); |
| } |
| } |
| } |
| } |
| |
| |
| |
| FILE * OpenSndFile(lame_global_flags *gfp,const char* lpszFileName, int default_samp, |
| int default_channels) |
| { |
| input_bitrate=0; |
| if (gfp->input_format==sf_mp3) { |
| #ifdef AMIGA_MPEGA |
| if (-1==lame_decode_initfile(lpszFileName,&num_channels,&samp_freq,&input_bitrate,&num_samples)) { |
| fprintf(stderr,"Error reading headers in mp3 input file %s.\n", lpszFileName); |
| exit(1); |
| } |
| #endif |
| #ifdef HAVEMPGLIB |
| if ((musicin = fopen(lpszFileName, "rb")) == NULL) { |
| fprintf(stderr, "Could not find \"%s\".\n", lpszFileName); |
| exit(1); |
| } |
| if (-1==lame_decode_initfile(musicin,&num_channels,&samp_freq,&input_bitrate,&num_samples)) { |
| fprintf(stderr,"Error reading headers in mp3 input file %s.\n", lpszFileName); |
| exit(1); |
| } |
| #endif |
| gs_wfInfo.samples=num_samples; |
| gs_wfInfo.channels=num_channels; |
| gs_wfInfo.samplerate=samp_freq; |
| |
| } else { |
| |
| /* Try to open the sound file */ |
| /* set some defaults incase input is raw PCM */ |
| gs_wfInfo.seekable=(gfp->input_format!=sf_raw); /* if user specified -r, set to not seekable */ |
| gs_wfInfo.samplerate=default_samp; |
| gs_wfInfo.pcmbitwidth=16; |
| gs_wfInfo.channels=default_channels; |
| if (DetermineByteOrder()==order_littleEndian) { |
| if (gfp->swapbytes) gs_wfInfo.format=SF_FORMAT_RAW_BE; |
| else gs_wfInfo.format=SF_FORMAT_RAW_LE; |
| } else { |
| if (gfp->swapbytes) gs_wfInfo.format=SF_FORMAT_RAW_LE; |
| else gs_wfInfo.format=SF_FORMAT_RAW_BE; |
| } |
| |
| gs_pSndFileIn=sf_open_read(lpszFileName,&gs_wfInfo); |
| |
| /* Check result */ |
| if (gs_pSndFileIn==NULL) |
| { |
| sf_perror(gs_pSndFileIn); |
| fprintf(stderr, "Could not open sound file \"%s\".\n", lpszFileName); |
| exit(1); |
| } |
| |
| if ((gs_wfInfo.format==SF_FORMAT_RAW_LE) || |
| (gs_wfInfo.format==SF_FORMAT_RAW_BE)) |
| gfp->input_format=sf_raw; |
| |
| #ifdef _DEBUG_SND_FILE |
| printf("\n\nSF_INFO structure\n"); |
| printf("samplerate :%d\n",gs_wfInfo.samplerate); |
| printf("samples :%d\n",gs_wfInfo.samples); |
| printf("channels :%d\n",gs_wfInfo.channels); |
| printf("pcmbitwidth :%d\n",gs_wfInfo.pcmbitwidth); |
| printf("format :"); |
| |
| /* new formats from sbellon@sbellon.de 1/2000 */ |
| if ((gs_wfInfo.format&SF_FORMAT_TYPEMASK)==SF_FORMAT_WAV) |
| printf("Microsoft WAV format (big endian). "); |
| if ((gs_wfInfo.format&SF_FORMAT_TYPEMASK)==SF_FORMAT_AIFF) |
| printf("Apple/SGI AIFF format (little endian). "); |
| if ((gs_wfInfo.format&SF_FORMAT_TYPEMASK)==SF_FORMAT_AU) |
| printf("Sun/NeXT AU format (big endian). "); |
| if ((gs_wfInfo.format&SF_FORMAT_TYPEMASK)==SF_FORMAT_AULE) |
| printf("DEC AU format (little endian). "); |
| if ((gs_wfInfo.format&SF_FORMAT_TYPEMASK)==SF_FORMAT_RAW) |
| printf("RAW PCM data. "); |
| if ((gs_wfInfo.format&SF_FORMAT_TYPEMASK)==SF_FORMAT_PAF) |
| printf("Ensoniq PARIS file format. "); |
| if ((gs_wfInfo.format&SF_FORMAT_TYPEMASK)==SF_FORMAT_SVX) |
| printf("Amiga IFF / SVX8 / SV16 format. "); |
| if ((gs_wfInfo.format&SF_FORMAT_TYPEMASK)==SF_FORMAT_NIST) |
| printf("Sphere NIST format. "); |
| |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM) |
| printf("PCM data in 8, 16, 24 or 32 bits."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) |
| printf("32 bit Intel x86 floats."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_ULAW) |
| printf("U-Law encoded."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_ALAW) |
| printf("A-Law encoded."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_IMA_ADPCM) |
| printf("IMA ADPCM."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_MS_ADPCM) |
| printf("Microsoft ADPCM."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_BE) |
| printf("Big endian PCM data."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_LE) |
| printf("Little endian PCM data."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_S8) |
| printf("Signed 8 bit PCM."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) |
| printf("Unsigned 8 bit PCM."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_SVX_FIB) |
| printf("SVX Fibonacci Delta encoding."); |
| if ((gs_wfInfo.format&SF_FORMAT_SUBMASK)==SF_FORMAT_SVX_EXP) |
| printf("SVX Exponential Delta encoding."); |
| |
| |
| |
| |
| printf("\n"); |
| printf("pcmbitwidth :%d\n",gs_wfInfo.pcmbitwidth); |
| printf("sections :%d\n",gs_wfInfo.sections); |
| printf("seekable :\n",gs_wfInfo.seekable); |
| #endif |
| } |
| |
| if (gs_wfInfo.samples==MAX_U_32_NUM) { |
| struct stat sb; |
| /* try to figure out num_samples */ |
| if (0==stat(lpszFileName,&sb)) { |
| /* try file size, assume 2 bytes per sample */ |
| if (gfp->input_format == sf_mp3) { |
| FLOAT totalseconds = (sb.st_size*8.0/(1000.0*GetSndBitrate())); |
| gs_wfInfo.samples= totalseconds*GetSndSampleRate(); |
| }else{ |
| gs_wfInfo.samples = sb.st_size/(2*GetSndChannels()); |
| } |
| } |
| } |
| return musicin; |
| } |
| |
| |
| /************************************************************************ |
| * |
| * read_samples() |
| * |
| * PURPOSE: reads the PCM samples from a file to the buffer |
| * |
| * SEMANTICS: |
| * Reads #samples_read# number of shorts from #musicin# filepointer |
| * into #sample_buffer[]#. Returns the number of samples read. |
| * |
| ************************************************************************/ |
| |
| int read_samples_pcm(lame_global_flags *gfp,short sample_buffer[2304],int frame_size,int samples_to_read) |
| { |
| int samples_read; |
| int rcode; |
| |
| samples_read=sf_read_short(gs_pSndFileIn,sample_buffer,samples_to_read); |
| |
| rcode = samples_read; |
| if (samples_read < frame_size) |
| { |
| /*fprintf(stderr,"Insufficient PCM input for one frame - fillout with zeros\n"); |
| */ |
| if (samples_read<0) samples_read=0; |
| for (; samples_read < frame_size; sample_buffer[samples_read++] = 0); |
| } |
| |
| if (8==gs_wfInfo.pcmbitwidth) |
| for (; samples_read >= 0; sample_buffer[samples_read] = sample_buffer[samples_read--] * 256); |
| |
| return(rcode); |
| } |
| |
| |
| #endif /* ifdef LIBSNDFILE */ |
| #ifdef LAMESNDFILE |
| |
| /************************************************************************ |
| ************************************************************************ |
| ************************************************************************ |
| ************************************************************************ |
| ************************************************************************ |
| ************************************************************************ |
| * |
| * OLD ISO/LAME routines follow. Used if you dont have LIBSNDFILE |
| * or for stdin/stdout support |
| * |
| ************************************************************************ |
| ************************************************************************ |
| ************************************************************************ |
| ************************************************************************ |
| ************************************************************************ |
| ************************************************************************/ |
| |
| /* Replacement for forward fseek(,,SEEK_CUR), because fseek() fails on pipes */ |
| int fskip(FILE *sf,long num_bytes,int dummy) |
| { |
| char data[1024]; |
| int nskip = 0; |
| while (num_bytes > 0) { |
| nskip = (num_bytes>1024) ? 1024 : num_bytes; |
| num_bytes -= fread(data,(size_t)1,(size_t)nskip,sf); |
| } |
| /* return 0 if last read was successful */ |
| return num_bytes; |
| } |
| |
| |
| |
| void CloseSndFile(lame_global_flags *gfp) |
| { |
| if (fclose(musicin) != 0){ |
| fprintf(stderr, "Could not close audio input file\n"); |
| exit(2); |
| } |
| } |
| |
| |
| unsigned long GetSndSamples(void) |
| { |
| return num_samples; |
| } |
| int GetSndSampleRate(void) |
| { |
| return samp_freq; |
| } |
| |
| int GetSndChannels(void) |
| { |
| return num_channels; |
| } |
| |
| |
| FILE * OpenSndFile(lame_global_flags *gfp,const char* inPath, int default_samp, |
| int default_channels) |
| { |
| struct stat sb; |
| void parse_file_header(lame_global_flags *gfp,FILE *sf); |
| /* set the defaults from info incase we cannot determine them from file */ |
| num_samples=MAX_U_32_NUM; |
| samp_freq=default_samp; |
| num_channels = default_channels; |
| |
| if (!strcmp(inPath, "-")) { |
| /* Read from standard input. */ |
| #ifdef __EMX__ |
| _fsetmode(stdin,"b"); |
| #elif (defined __BORLANDC__) |
| setmode(_fileno(stdin), O_BINARY); |
| #elif (defined __CYGWIN__) |
| setmode(fileno(stdin), _O_BINARY); |
| #elif (defined _WIN32) |
| _setmode(_fileno(stdin), _O_BINARY); |
| #endif |
| musicin = stdin; |
| } else { |
| if ((musicin = fopen(inPath, "rb")) == NULL) { |
| fprintf(stderr, "Could not find \"%s\".\n", inPath); |
| exit(1); |
| } |
| } |
| |
| input_bitrate=0; |
| if (gfp->input_format==sf_mp3) { |
| #ifdef AMIGA_MPEGA |
| if (-1==lame_decode_initfile(inPath,&num_channels,&samp_freq,&input_bitrate,&num_samples)) { |
| fprintf(stderr,"Error reading headers in mp3 input file %s.\n", inPath); |
| exit(1); |
| } |
| #endif |
| #ifdef HAVEMPGLIB |
| if (-1==lame_decode_initfile(musicin,&num_channels,&samp_freq,&input_bitrate,&num_samples)) { |
| fprintf(stderr,"Error reading headers in mp3 input file %s.\n", inPath); |
| exit(1); |
| } |
| #endif |
| }else{ |
| if (gfp->input_format != sf_raw) { |
| parse_file_header(gfp,musicin); |
| } |
| |
| if (gfp->input_format==sf_raw) { |
| /* assume raw PCM */ |
| fprintf(stderr, "Assuming raw pcm input file"); |
| if (gfp->swapbytes==TRUE) |
| fprintf(stderr, " : Forcing byte-swapping\n"); |
| else |
| fprintf(stderr, "\n"); |
| } |
| } |
| |
| if (num_samples==MAX_U_32_NUM && musicin != stdin) { |
| /* try to figure out num_samples */ |
| if (0==stat(inPath,&sb)) { |
| /* try file size, assume 2 bytes per sample */ |
| if (gfp->input_format == sf_mp3) { |
| FLOAT totalseconds = (sb.st_size*8.0/(1000.0*GetSndBitrate())); |
| num_samples= totalseconds*GetSndSampleRate(); |
| }else{ |
| num_samples = sb.st_size/(2*GetSndChannels()); |
| } |
| } |
| } |
| return musicin; |
| } |
| |
| |
| /************************************************************************ |
| * |
| * read_samples() |
| * |
| * PURPOSE: reads the PCM samples from a file to the buffer |
| * |
| * SEMANTICS: |
| * Reads #samples_read# number of shorts from #musicin# filepointer |
| * into #sample_buffer[]#. Returns the number of samples read. |
| * |
| ************************************************************************/ |
| |
| int read_samples_pcm(lame_global_flags *gfp,short sample_buffer[2304], int frame_size,int samples_to_read) |
| { |
| int samples_read; |
| int rcode; |
| int iswav=(gfp->input_format==sf_wave); |
| |
| samples_read = fread(sample_buffer, sizeof(short), samples_to_read, musicin); |
| if (ferror(musicin)) { |
| fprintf(stderr, "Error reading input file\n"); |
| exit(2); |
| } |
| |
| /* |
| Samples are big-endian. If this is a little-endian machine |
| we must swap |
| */ |
| if ( NativeByteOrder == order_unknown ) |
| { |
| NativeByteOrder = DetermineByteOrder(); |
| if ( NativeByteOrder == order_unknown ) |
| { |
| fprintf( stderr, "byte order not determined\n" ); |
| exit( 1 ); |
| } |
| } |
| /* intel=littleEndian */ |
| if (!iswav && ( NativeByteOrder == order_littleEndian )) |
| SwapBytesInWords( sample_buffer, samples_read ); |
| |
| if (iswav && ( NativeByteOrder == order_bigEndian )) |
| SwapBytesInWords( sample_buffer, samples_read ); |
| |
| if (gfp->swapbytes==TRUE) |
| SwapBytesInWords( sample_buffer, samples_read ); |
| |
| |
| rcode=samples_read; |
| if (samples_read < frame_size) { |
| if (samples_read<0) samples_read=0; |
| /*fprintf(stderr,"Insufficient PCM input for one frame - fillout with zeros\n"); |
| */ |
| for (; samples_read < frame_size; sample_buffer[samples_read++] = 0); |
| } |
| return(rcode); |
| } |
| |
| |
| |
| #define WAV_ID_RIFF 0x52494646 /* "RIFF" */ |
| #define WAV_ID_WAVE 0x57415645 /* "WAVE" */ |
| #define WAV_ID_FMT 0x666d7420 /* "fmt " */ |
| #define WAV_ID_DATA 0x64617461 /* "data" */ |
| |
| typedef struct fmt_chunk_data_struct { |
| short format_tag; /* Format category */ |
| u_short channels; /* Number of channels */ |
| u_long samples_per_sec; /* Sampling rate */ |
| u_long avg_bytes_per_sec; /* For buffer estimation */ |
| u_short block_align; /* Data block size */ |
| u_short bits_per_sample; /* for PCM data, anyway... */ |
| } fmt_chunk_data; |
| |
| |
| |
| |
| |
| |
| /************************************************************************ |
| * |
| * wave_check |
| * |
| * PURPOSE: Checks Wave header information to make sure it is valid. |
| * Exits if not. |
| * |
| ************************************************************************/ |
| |
| static void |
| wave_check(char *file_name, fmt_chunk_data *wave_info) |
| { |
| if (wave_info->bits_per_sample != 16) { |
| fprintf(stderr, "%d-bit sample-size is not supported!\n", |
| wave_info->bits_per_sample); |
| exit(1); |
| } |
| } |
| |
| |
| /***************************************************************************** |
| * |
| * Read Microsoft Wave headers |
| * |
| * By the time we get here the first 32-bits of the file have already been |
| * read, and we're pretty sure that we're looking at a WAV file. |
| * |
| *****************************************************************************/ |
| |
| static int |
| parse_wave_header(FILE *sf) |
| { |
| fmt_chunk_data wave_info; |
| int is_wav = 0; |
| long data_length = 0, file_length, subSize = 0; |
| int loop_sanity = 0; |
| |
| memset(&wave_info, 0, sizeof(wave_info)); |
| |
| file_length = Read32BitsHighLow(sf); |
| |
| if (Read32BitsHighLow(sf) != WAV_ID_WAVE) |
| return 0; |
| |
| for (loop_sanity = 0; loop_sanity < 20; ++loop_sanity) { |
| u_int type = Read32BitsHighLow(sf); |
| |
| if (type == WAV_ID_FMT) { |
| subSize = Read32BitsLowHigh(sf); |
| if (subSize < 16) { |
| /*fprintf(stderr, |
| "'fmt' chunk too short (only %ld bytes)!", subSize); */ |
| return 0; |
| } |
| |
| wave_info.format_tag = Read16BitsLowHigh(sf); |
| subSize -= 2; |
| wave_info.channels = Read16BitsLowHigh(sf); |
| subSize -= 2; |
| wave_info.samples_per_sec = Read32BitsLowHigh(sf); |
| subSize -= 4; |
| wave_info.avg_bytes_per_sec = Read32BitsLowHigh(sf); |
| subSize -= 4; |
| wave_info.block_align = Read16BitsLowHigh(sf); |
| subSize -= 2; |
| wave_info.bits_per_sample = Read16BitsLowHigh(sf); |
| subSize -= 2; |
| |
| /* fprintf(stderr, " skipping %d bytes\n", subSize); */ |
| |
| if (subSize > 0) { |
| if (fskip(sf, (long)subSize, SEEK_CUR) != 0 ) |
| return 0; |
| }; |
| |
| } else if (type == WAV_ID_DATA) { |
| subSize = Read32BitsLowHigh(sf); |
| data_length = subSize; |
| is_wav = 1; |
| /* We've found the audio data. Read no further! */ |
| break; |
| |
| } else { |
| subSize = Read32BitsLowHigh(sf); |
| if (fskip(sf, (long) subSize, SEEK_CUR) != 0 ) return 0; |
| } |
| } |
| |
| if (is_wav) { |
| /* make sure the header is sane */ |
| wave_check("name", &wave_info); |
| |
| num_channels = wave_info.channels; |
| samp_freq = wave_info.samples_per_sec; |
| num_samples = data_length / (wave_info.channels * wave_info.bits_per_sample / 8); |
| } |
| return is_wav; |
| } |
| |
| |
| |
| /************************************************************************ |
| * |
| * aiff_check |
| * |
| * PURPOSE: Checks AIFF header information to make sure it is valid. |
| * Exits if not. |
| * |
| ************************************************************************/ |
| |
| static void |
| aiff_check2(const char *file_name, IFF_AIFF *pcm_aiff_data) |
| { |
| if (pcm_aiff_data->sampleType != IFF_ID_SSND) { |
| fprintf(stderr, "Sound data is not PCM in \"%s\".\n", file_name); |
| exit(1); |
| } |
| |
| if (pcm_aiff_data->sampleSize != sizeof(short) * BITS_IN_A_BYTE) { |
| fprintf(stderr, "Sound data is not %d bits in \"%s\".\n", |
| (unsigned int) sizeof(short) * BITS_IN_A_BYTE, file_name); |
| exit(1); |
| } |
| |
| if (pcm_aiff_data->numChannels != 1 && |
| pcm_aiff_data->numChannels != 2) { |
| fprintf(stderr, "Sound data is not mono or stereo in \"%s\".\n", |
| file_name); |
| exit(1); |
| } |
| |
| if (pcm_aiff_data->blkAlgn.blockSize != 0) { |
| fprintf(stderr, "Block size is not %d bytes in \"%s\".\n", |
| 0, file_name); |
| exit(1); |
| } |
| |
| if (pcm_aiff_data->blkAlgn.offset != 0) { |
| fprintf(stderr, "Block offset is not %d bytes in \"%s\".\n", |
| 0, file_name); |
| exit(1); |
| } |
| } |
| |
| /***************************************************************************** |
| * |
| * Read Audio Interchange File Format (AIFF) headers. |
| * |
| * By the time we get here the first 32-bits of the file have already been |
| * read, and we're pretty sure that we're looking at an AIFF file. |
| * |
| *****************************************************************************/ |
| |
| static int |
| parse_aiff_header(FILE *sf) |
| { |
| int is_aiff = 0; |
| long chunkSize = 0, subSize = 0; |
| IFF_AIFF aiff_info; |
| |
| memset(&aiff_info, 0, sizeof(aiff_info)); |
| chunkSize = Read32BitsHighLow(sf); |
| |
| if ( Read32BitsHighLow(sf) != IFF_ID_AIFF ) |
| return 0; |
| |
| while ( chunkSize > 0 ) |
| { |
| u_int type = 0; |
| chunkSize -= 4; |
| |
| type = Read32BitsHighLow(sf); |
| |
| /* fprintf(stderr, |
| "found chunk type %08x '%4.4s'\n", type, (char*)&type); */ |
| |
| /* don't use a switch here to make it easier to use 'break' for SSND */ |
| if (type == IFF_ID_COMM) { |
| subSize = Read32BitsHighLow(sf); |
| chunkSize -= subSize; |
| |
| aiff_info.numChannels = Read16BitsHighLow(sf); |
| subSize -= 2; |
| aiff_info.numSampleFrames = Read32BitsHighLow(sf); |
| subSize -= 4; |
| aiff_info.sampleSize = Read16BitsHighLow(sf); |
| subSize -= 2; |
| aiff_info.sampleRate = ReadIeeeExtendedHighLow(sf); |
| subSize -= 10; |
| |
| if (fskip(sf, (long) subSize, SEEK_CUR) != 0 ) |
| return 0; |
| |
| } else if (type == IFF_ID_SSND) { |
| subSize = Read32BitsHighLow(sf); |
| chunkSize -= subSize; |
| |
| aiff_info.blkAlgn.offset = Read32BitsHighLow(sf); |
| subSize -= 4; |
| aiff_info.blkAlgn.blockSize = Read32BitsHighLow(sf); |
| subSize -= 4; |
| |
| if (fskip(sf, aiff_info.blkAlgn.offset, SEEK_CUR) != 0 ) |
| return 0; |
| |
| aiff_info.sampleType = IFF_ID_SSND; |
| is_aiff = 1; |
| |
| /* We've found the audio data. Read no further! */ |
| break; |
| |
| } else { |
| subSize = Read32BitsHighLow(sf); |
| chunkSize -= subSize; |
| |
| if (fskip(sf, (long) subSize, SEEK_CUR) != 0 ) |
| return 0; |
| } |
| } |
| |
| /* fprintf(stderr, "Parsed AIFF %d\n", is_aiff); */ |
| if (is_aiff) { |
| /* make sure the header is sane */ |
| aiff_check2("name", &aiff_info); |
| num_channels = aiff_info.numChannels; |
| samp_freq = aiff_info.sampleRate; |
| num_samples = aiff_info.numSampleFrames; |
| } |
| return is_aiff; |
| } |
| |
| |
| |
| /************************************************************************ |
| * |
| * parse_file_header |
| * |
| * PURPOSE: Read the header from a bytestream. Try to determine whether |
| * it's a WAV file or AIFF without rewinding, since rewind |
| * doesn't work on pipes and there's a good chance we're reading |
| * from stdin (otherwise we'd probably be using libsndfile). |
| * |
| * When this function returns, the file offset will be positioned at the |
| * beginning of the sound data. |
| * |
| ************************************************************************/ |
| |
| void parse_file_header(lame_global_flags *gfp,FILE *sf) |
| { |
| u_int type = 0; |
| type = Read32BitsHighLow(sf); |
| |
| /* fprintf(stderr, |
| "First word of input stream: %08x '%4.4s'\n", type, (char*) &type); */ |
| |
| count_samples_carefully=0; |
| gfp->input_format = sf_raw; |
| |
| if (type == WAV_ID_RIFF) { |
| /* It's probably a WAV file */ |
| if (parse_wave_header(sf)) { |
| gfp->input_format = sf_wave; |
| count_samples_carefully=1; |
| } |
| |
| } else if (type == IFF_ID_FORM) { |
| /* It's probably an AIFF file */ |
| if (parse_aiff_header(sf)) { |
| gfp->input_format = sf_aiff; |
| count_samples_carefully=1; |
| } |
| } |
| if (gfp->input_format==sf_raw) { |
| /* |
| ** Assume it's raw PCM. Since the audio data is assumed to begin |
| ** at byte zero, this will unfortunately require seeking. |
| */ |
| if (fseek(sf, 0L, SEEK_SET) != 0) { |
| /* ignore errors */ |
| } |
| gfp->input_format = sf_raw; |
| } |
| } |
| #endif /* LAMESNDFILE */ |
| |
| |