www.pudn.com > bladeenc-0.90.0-src.zip > main.c


/* 
			(c) Copyright 1998, 1999 - Tord Jansson 
			======================================= 
 
		This file is part of the BladeEnc MP3 Encoder, based on 
		ISO's reference code for MPEG Layer 3 compression. 
 
		This file doesn't contain any of the ISO reference code and 
		is copyright Tord Jansson (tord.jansson@swipnet.se). 
 
	BladeEnc is free software; you can redistribute this file 
	and/or modify it under the terms of the GNU Lesser General Public 
	License as published by the Free Software Foundation; either 
	version 2.1 of the License, or (at your option) any later version. 
 
*/ 
 
#include	 
#include     
#include     
#include     
#include    "system.h" 
#include	"codec.h" 
#include    "samplein.h" 
#include	"arglink.h" 
#include	"bladesys.h" 
 
 
#ifdef OS2 
#	define INCL_DOSFILEMGR 
#	define INCL_DOSERRORS 
#	define INCL_DOSPROCESS 
#	include  
#	include "os2key.h" 
#endif 
 
#if SYSTEM == MAC_OS 
#	include  
#	include  
 
	void DoEvent(EventRecord *i); 
	extern int gFriendliness; 
#endif 
 
 
extern	char *mystrupr(char * strng); 
 
 
 
enum 
{ 
	PROG_OFF, 
	PROG_BOTH_PERC_ETA, 
	PROG_FILE_GRAPH, 
	PROG_BATCH_GRAPH, 
	PROG_BOTH_GRAPH, 
	PROG_BOTH_SAMPLES, 
	PROG_BOTH_ETA, 
	PROG_FILE_RLEN, 
	PROG_FILE_NORETURN, 
}; 
 
 
/*____ Structure Definitions __________________________________________________*/ 
 
typedef struct  JobDef  Job; 
 
struct JobDef 
{ 
	CodecInitIn		sCodec; 
	SplIn         sInput; 
	Job         * psNext; 
	int           fDeleteSource; 
	char          outputFilename[MAX_NAMELEN]; 
	char          sourceFilename[MAX_NAMELEN]; 
}; 
 
 
/*____ Function Prototypes ____________________________________________________*/ 
 
int			printUsage( void ); 
int			validateJobs( Job * psJob ); 
argLink *	readGlobalSwitches( argLink * pArgLink ); 
argLink *	readLocalSwitches( argLink * pArgLink, Job * psJob ); 
int			addCommandlineJob( argLink ** pArgLink ); 
int			addFileToBatch( char * pFilename, char * pOutputFilename ); 
int			clearJobQueue( void ); 
int			removeJobQueueEntry( Job * psJob ); 
 
int			readL3EncCommandline( int argc, char * argv[] ); 
 
void		updateProgressIndicator( time_t startBatch, double batchLen, double batchDone, 
				                     time_t startFile, double fileLen, double fileDone,  
									 int progType, Job * psJob ); 
void		quit( int returnValue ); 
 
 
void		timerCalibrate( void ); 
time_t		timerStart( void ); 
float		timerStop( time_t startTime ); 
 
 
 
/*____ Static Data ____________________________________________________________*/ 
 
 
 
/* Parameters set through the commandline. */ 
 
int			wantedBitrate	= -1;             /* -1 = Unspecified. */ 
int			wantedCRC		= FALSE; 
int			wantedPrivate	= FALSE; 
int			wantedCopyright = FALSE; 
int			wantedOriginal	= TRUE; 
SampleType	wantedInputType = STEREO; 
int			wantedProgressBarRate = 2; 
int			wantedChannelSwap = FALSE; 
 
int			wantedDeleteSource = FALSE; 
 
#ifdef	WAIT_KEY 
	int     wantedQuit	= FALSE; 
	int		defWantedQuit = FALSE; 
#else 
	int		wantedQuit	= TRUE; 
	int		defWantedQuit = TRUE; 
#endif 
int			wantedQuiet = FALSE; 
int			wantedSTDOUT = FALSE; 
int			fPreparedSTDIN = FALSE; 
 
char		prioString[256]; 
char		* pPrioString = NULL; 
 
Job			* psJobQueue = NULL; 
 
char		outputDir[MAX_NAMELEN]; 
 
FILE		* textout; 
 
int			timerCalibrationValue;					/* Only used if PRECISE_TIMER is defined. */ 
 
int			progType = PROG_BOTH_PERC_ETA;				/* Style of the progress bar */ 
 
 
int			rawFrequency = 44100; 
int			rawChannels = 2; 
int			rawBits = 16; 
int			rawSigned = TRUE; 
int			rawByteorder = BYTEORDER; 
 
 
/*____ main() _________________________________________________________________*/ 
 
#if SYSTEM == MAC_OS 
int main_( int argc, char* argv[] )			/* Because the real main is somewhere else */ 
#else 
int main( int argc, char* argv[] ) 
#endif 
{ 
	int           samplesPerFrame; 
	int           nSamples; 
 
	short         readBuffer[2304]; 
	int           x; 
 
	char          input; 
	Job         * psTemp; 
 
	time_t        startTimeBatch, startTimeFile; 
	float		  seconds; 
	double        batchSamplesTotal = 0.0, batchSamplesRead = 0.0; 
	double		  fileSamplesRead; 
	int			  showProgressCnt = 0; 
 
	CodecInitOut *pCodecInfo; 
	char        * pBuffer; 
	uint          encodedChunkSize; 
	FILE        * fp; 
 
	char		  temp[256]; 
 
 
	argLink		* pArgLink, * pNextArg; 
 
#if SYSTEM == MAC_OS 
	long macTickStart = TickCount(); 
#endif 
 
	/* Setting default parameters. Might seem useless since most of them 
	   allready are predefined, but the MAC OS port uses main() as a subroutine 
	   which can be called multiple times. */ 
 
 
	wantedBitrate	= -1;             /* -1 = Unspecified. */ 
	wantedCRC		= FALSE; 
	wantedPrivate	= FALSE; 
	wantedCopyright = FALSE; 
	wantedOriginal	= TRUE; 
	wantedInputType = STEREO; 
	wantedProgressBarRate = 2; 
	wantedChannelSwap = FALSE; 
 
	wantedDeleteSource = FALSE; 
 
	wantedQuit	= defWantedQuit; 
	wantedQuiet = FALSE; 
	wantedSTDOUT = FALSE; 
	fPreparedSTDIN = FALSE; 
 
	pPrioString = NULL; 
 
	psJobQueue = NULL; 
 
 
	progType = PROG_BOTH_PERC_ETA;				/* Style of the progress bar */ 
 
	rawFrequency = 44100; 
	rawChannels = 2; 
	rawBits = 16; 
	rawSigned = TRUE; 
	rawByteorder = BYTEORDER; 
 
	textout = stdout; 
	outputDir[0] = 0; 
 
	/* Fix ArgLink */ 
 
	pArgLink = argv2ArgLink( argc-1, argv+1 ); 
 
	if( findStrInArgLink( pArgLink, "-NOCFG" ) == NULL ) 
		if( findConfigFile( argv[0], temp ) == TRUE ) 
			addFileContentToArgLink( &pArgLink, temp ); 
 
#ifdef	WILDCARDS 
	expandWildcards( &pArgLink ); 
#endif 
 
	pNextArg = readGlobalSwitches( pArgLink ); 
 
	/* Check for STDOUT */ 
 
	if( findStrInArgLink( pArgLink, "stdout" ) != NULL ) 
	{ 
		prepStdout(); 
		textout = stderr; 
	} 
 
 
	/* Print Text */ 
 
	if( !wantedQuiet ) 
	{ 
		fprintf( textout, "\n" ); 
		fprintf( textout, "BladeEnc 0.90    (c) Tord Jansson          Homepage: http://bladeenc.mp3.no\n" ); 
		fprintf( textout, "===============================================================================\n" ); 
		fprintf( textout, "BladeEnc is free software, distributed under the Lesser General Public License.\n" ); 
		fprintf( textout, "See the file COPYING, BladeEnc's homepage or www.fsf.org for more details.\n" ); 
		fprintf( textout, "\n" ); 
	} 
 
	/* Initialise batch */ 
 
	while( pNextArg != NULL ) 
	{ 
		x = addCommandlineJob( &pNextArg ); 
		if( x == FALSE ) 
		{ 
			deleteArgLink( pArgLink ); 
			quit( -1 ); 
		} 
	} 
 
	deleteArgLink( pArgLink ); 
 
	/* Validate job settings */ 
 
	x = validateJobs( psJobQueue ); 
	if( x == FALSE ) 
		quit( -2 ); 
 
 
	/* Make sure we don't have certain progress indicators if RAW file in batch */ 
 
	x = 0; 
	for( psTemp = psJobQueue ; psTemp != NULL ; psTemp = psTemp->psNext ) 
	{ 
		if( psTemp->sInput.filetype == RAW ) 
			x++; 
	} 
	if( x != 0 && progType != PROG_OFF && progType != PROG_FILE_RLEN ) 
		progType = PROG_FILE_RLEN; 
 
	/* Set priority */ 
 
	if( setPriority( pPrioString ) == FALSE ) 
	{ 
		fprintf( textout, "Error: '%s' is not a valid priority setting!\n", pPrioString ); 
		quit(	-1 ); 
	}; 
 
 
 
	/* Procedure if no files found */ 
 
	if( psJobQueue == NULL ) 
	{ 
		printUsage();                                                           /* No files on the commandline */ 
		quit( -1 ); 
	} 
 
 
	/* Print files to encode */ 
 
	for( x = 0, psTemp = psJobQueue ; psTemp != NULL ; x++, psTemp = psTemp->psNext ); 
	if( !wantedQuiet ) 
		fprintf( textout, "Files to encode: %d\n\n", x ); 
 
 
	/* Encode */ 
 
#ifdef	PRECISE_TIMER 
	timerCalibrate(); 
#endif 
 
	startTimeBatch = timerStart(); 
 
	for( psTemp = psJobQueue ; psTemp != NULL ; psTemp = psTemp->psNext ) 
		if( psTemp->sInput.length == 0xFFFFFFFF ) 
		{ 
			batchSamplesTotal = 0xFFFFFFFF; 
			break; 
		} 
		else 
			batchSamplesTotal += psTemp->sInput.length; 
 
 
	while( psJobQueue != NULL ) 
	{ 
		/* Print information */ 
 
		if( !wantedQuiet ) 
		{ 
			fprintf( textout, "Encoding:  %s\n", psJobQueue->sourceFilename ); 
			fprintf( textout, "Input:     %.1f kHz, %d bit, ", psJobQueue->sInput.freq/1000.f, psJobQueue->sInput.bits ); 
			if( psJobQueue->sInput.fReadStereo == TRUE ) 
				fprintf( textout, "stereo.\n" ); 
			else 
				fprintf( textout, "mono.\n" ); 
			fprintf( textout, "Output:    %d kBit, ", psJobQueue->sCodec.bitrate ); 
			if( psJobQueue->sCodec.mode == 0 ) 
				fprintf( textout, "stereo.\n\n" ); 
			else 
				fprintf( textout, "mono.\n\n" ); 
		} 
 
		/* Init a new job */ 
 
		startTimeFile = timerStart(); 
		fileSamplesRead = 0; 
		pCodecInfo = codecInit( &psJobQueue->sCodec ); 
		samplesPerFrame = pCodecInfo->nSamples; 
		pBuffer = (char *) malloc( pCodecInfo->bufferSize ); 
		if( strcmp( psJobQueue->outputFilename, "STDOUT" ) == 0 ) 
			fp = stdout; 
		else 
		{ 
			fp = fopen( psJobQueue->outputFilename, "wb" ); 
			if( fp == NULL ) 
			{ 
				/*  codecExit(); */ 
				closeInput( &psJobQueue->sInput ); 
				fprintf( textout, "ERROR: Couldn't create '%s'!\n", psJobQueue->outputFilename ); 
				quit( -1 ); 
			} 
		} 
 
		/* Encoding loop */ 
 
		while ( (nSamples = readSamples( &psJobQueue->sInput, samplesPerFrame, readBuffer)) > 0 ) 
		{ 
 
 
#if SYSTEM == MAC_OS	/* Stuff needed for Petteri Kamppuri's Mac OS port */ 
	 		if(macTickStart + gFriendliness < TickCount()) 
			{ 
	        	macTickStart = TickCount(); 
	 
	       		Boolean      	gotEvent; 
	         	EventRecord		event; 
	 
	         	gotEvent = GetNextEvent(everyEvent, &event); 
	         	if(gotEvent) 
				{ 
	            	SIOUXHandleOneEvent(&event); 
	           		DoEvent(&event); 
	         	} 
			} 
#endif 
 
			encodedChunkSize = codecEncodeChunk( nSamples, readBuffer, pBuffer ); 
			if( fwrite( pBuffer, 1, encodedChunkSize, fp ) != encodedChunkSize ) 
			{ 
				fprintf( textout, "ERROR: Couldn't write '%s'! Disc probably full.\n", psJobQueue->outputFilename ); 
				quit( -1 ); 
			} 
 
			batchSamplesRead += nSamples; 
			fileSamplesRead += nSamples; 
 
			if( !wantedQuiet ) 
			{ 
				showProgressCnt = (showProgressCnt+1) % wantedProgressBarRate; 
				if( showProgressCnt == 0 ) 
					updateProgressIndicator( startTimeBatch, batchSamplesTotal, batchSamplesRead, 
					                         startTimeFile, psJobQueue->sInput.length, fileSamplesRead,  
											 progType, psJobQueue ); 
			} 
			if( be_kbhit() != 0 ) 
			{ 
				input = be_getch(); 
				if( input == 27 ) 
				{ 
					fprintf( textout, "\r                                                                             \r" ); 
					fprintf( textout, "Quit, are you sure? (y/n)" ); 
					fflush( textout ); 
					input = be_getch(); 
					if( input == 'y' || input == 'Y' ) 
					{ 
						encodedChunkSize = codecExit( pBuffer ); 
						if( encodedChunkSize != 0 ) 
							if( fwrite( pBuffer, encodedChunkSize, 1, fp ) != 1 ) 
							{ 
								fprintf( textout, "ERROR: Couldn't write '%s'! Disc probably full.\n", psJobQueue->outputFilename ); 
								quit( -1 ); 
							} 
						free( pBuffer ); 
						closeInput( &psJobQueue->sInput ); 
						if( fp != stdout ) 
							fclose( fp ); 
						return  0; 
					} 
					else 
						fprintf( textout, "\r                                                                             \r" ); 
				} 
			} 
		} 
 
		/* File done */ 
 
 
		encodedChunkSize = codecExit( pBuffer ); 
		if( encodedChunkSize != 0 ) 
			if( fwrite( pBuffer, encodedChunkSize, 1, fp ) != 1 ) 
			{ 
				fprintf( textout, "ERROR: Couldn't write '%s'! Disc probably full.\n", psJobQueue->outputFilename ); 
				quit( -1 ); 
			} 
		if( fp != stdout ) 
			fclose( fp ); 
		free( pBuffer ); 
		if( psJobQueue->fDeleteSource == TRUE ) 
			remove( psJobQueue->sourceFilename ); 
		seconds = timerStop( startTimeFile ); 
		x = (int) seconds; 
		if( !wantedQuiet ) 
		{ 
			fprintf( textout, "\r                                                                             \r" ); 
			fprintf( textout, "Completed. Encoding time: %02d:%02d:%02d (%.2fX)\n\n", 
			         x/3600, (x/60)%60, x%60, ((float)fileSamplesRead) / 
			         ((psJobQueue->sInput.fReadStereo+1)*psJobQueue->sInput.freq*seconds) ); 
		} 
		removeJobQueueEntry( psJobQueue ); 
	} 
 
	/* Batch done */ 
 
	if( !wantedQuiet ) 
	{ 
		seconds = timerStop( startTimeBatch ); 
		fprintf( textout, "All operations completed. Total encoding time: %02d:%02d:%02d\n", 
		         (int) seconds/3600, (int)(seconds/60)%60, (int) seconds%60 ); 
 
		if( !wantedQuit ) 
		{ 
			fprintf( textout, "Press ENTER to exit..." ); 
			be_getch(); 
			fprintf( textout, "\n" ); 
		} 
	} 
 
	return 0; 
} 
 
 
 
/*____ quit() _________________________________________________________________*/ 
 
void    quit( int returnValue ) 
 
{ 
	if( !wantedQuit ) 
	{ 
		fprintf( textout, "Press ENTER to exit..." ); 
		be_getch(); 
		fprintf( textout, "\n" ); 
	} 
#if SYSTEM == MAC_OS 
	throw returnValue; 
#else 
	exit( returnValue ); 
#endif 
} 
 
 
 
/*____ timerCalibrate() _______________________________________________________*/ 
 
void	timerCalibrate( void ) 
{ 
	time_t	x, y; 
	int			i; 
 
	x = y = time( NULL ); 
	while( y == x ) 
		y = time( NULL ); 
 
	for( i = 0 ; y == time( NULL ) ; i++ ); 
	timerCalibrationValue = i; 
	printf( "Timer Calibration Value: %d\n", timerCalibrationValue ); 
} 
 
 
/*____ timerStart() ___________________________________________________________*/ 
 
time_t	timerStart( void ) 
{ 
	time_t	x, y; 
 
	x = y = time( NULL ); 
#ifdef	PRECISE_TIMER 
	while( y == x ) 
		y = time( NULL ); 
#endif 
	return	y; 
} 
 
/*____ timerStop() ____________________________________________________________*/ 
 
float	timerStop( time_t startTime ) 
{ 
	float		seconds; 
 
	time_t		stopTime = time( NULL ); 
#ifdef	PRECISE_TIMER 
	int			i; 
	for( i = 0 ; stopTime == time( NULL ) ; i++ ); 
#endif 
 
	seconds = (float) (stopTime - startTime); 
#ifdef	PRECISE_TIMER 
	seconds += ((float)(timerCalibrationValue - i))/timerCalibrationValue; 
 
	printf( "Exact seconds: %.5f\n", seconds ); 
#endif 
	return	seconds; 
} 
 
 
 
 
/*____ updateProgressIndicator() ______________________________________________*/ 
 
void    updateProgressIndicator( time_t startBatch, double batchLen, double batchDone, 
                                 time_t startFile, double fileLen, double fileDone,  
								 int progType, Job * psJob ) 
{ 
	time_t  currTime; 
	float   percentageFile, percentageBatch; 
	int     fileEta, batchEta; 
 
	char	temp[82]; 
	int		x, i; 
 
 
	static	char	wheel[4] = { '|' , '/' , '-' , '\\' }; 
	static	int		wheelindex = 0; 
	static	int		prevFileDone = -1; 
 
	currTime = time( NULL ); 
 
	switch( progType ) 
	{ 
		case PROG_BOTH_PERC_ETA: 
			percentageFile = (float) (fileDone / fileLen * 100); 
			if( percentageFile >= 100.f ) 
				percentageFile = (float) 99.9; 
 
			fileEta = (int) (((float)(currTime - startFile)) / fileDone * (fileLen - fileDone) ); 
 
			percentageBatch = (float)(batchDone / batchLen * 100); 
			batchEta = (int) (((float)(currTime - startBatch)) / batchDone * (batchLen - batchDone)); 
			fprintf( textout, "Status:   %4.1f%% done, ETA %02d:%02d:%02d          BATCH: %4.1f%% done, ETA %02d:%02d:%02d\r", 
					 percentageFile, fileEta/3600, (fileEta/60)%60, fileEta%60, 
					 percentageBatch, batchEta/3600, (batchEta/60)%60, batchEta%60 ); 
			fflush( textout ); 
			break; 
 
		case PROG_FILE_GRAPH: 
 
			strcpy( temp, "File progress: [..................................................]\r" ); 
			x = (int) (fileDone*50/fileLen); 
			memset( temp + 16, '*', x ); 
			if( x < 50 ) 
			{ 
				temp[16+x] = wheel[wheelindex]; 
				wheelindex = (wheelindex + 1) % 4; 
			} 
 
			fprintf( textout, temp ); 
			break; 
 
		case PROG_BATCH_GRAPH: 
 
			strcpy( temp, "Batch progress: [..................................................]\r" ); 
			x = (int) (batchDone*50/batchLen); 
			memset( temp + 16, '*', x ); 
			if( x < 50 ) 
			{ 
				temp[16+x] = wheel[wheelindex]; 
				wheelindex = (wheelindex + 1) % 4; 
			} 
 
			fprintf( textout, temp ); 
			break; 
 
		case PROG_BOTH_GRAPH: 
 
			strcpy( temp, "File: [.........................]   Batch: [.........................]\r" ); 
 
			x = (int) (fileDone*25/fileLen); 
			memset( temp + 7, '*', x ); 
 
			x = (int) (batchDone*25/batchLen); 
			memset( temp + 44, '*', x ); 
			if( x < 25 ) 
			{ 
				temp[7+x] = temp[44+x] = wheel[wheelindex]; 
				wheelindex = (wheelindex + 1) % 4; 
			} 
 
			fprintf( textout, temp ); 
			break; 
 
		case PROG_BOTH_SAMPLES: 
			 
			fprintf( textout, "Samples encoded:%10d / %d      BATCH:%10d / %d\r",  
					 (int) fileDone, (int) fileLen, (int) batchDone, (int) batchLen ); 
			break; 
 
		case PROG_BOTH_ETA: 
			fileEta = (int) (((float)(currTime - startFile)) / fileDone * (fileLen - fileDone) ); 
 
			batchEta = (int) (((float)(currTime - startBatch)) / batchDone * (batchLen - batchDone)); 
			fprintf( textout, "                >>> %02d:%02d:%02d <<<                >>> %02d:%02d:%02d <<<\r", 
					 fileEta/3600, (fileEta/60)%60, fileEta%60, 
					 batchEta/3600, (batchEta/60)%60, batchEta%60 ); 
			fflush( textout ); 
			break; 
 
 
		case PROG_FILE_RLEN: 
 
			x = (int) (fileDone / psJob->sCodec.frequency); 
			if( psJob->sCodec.mode != 3 ) 
				x /= 2; 
 
			fprintf( textout, "Encoded runlength (current file): %02d:%02d:%02d\r",  
			         x/3600, (x/60)%60, x%60 ); 
			break; 
 
		case PROG_FILE_NORETURN: 
 
			x = (int) (fileDone*70/fileLen);						 
			if( prevFileDone > x || prevFileDone == -1 ) 
			{ 
				prevFileDone = 0; 
				fprintf( textout, " |----------------------------------------------------------------------|\n |" ); 
				fflush( textout ); 
			} 
			for( i = prevFileDone ; i < x ; i++ ) 
			{ 
				fprintf( textout, "#" ); 
				fflush( textout ); 
			} 
 
			if( x == 70 ) 
				fprintf( textout, "|\n\n" ); 
			prevFileDone = x; 
			break; 
 
	} 
 
 
} 
 
/*____ setOutputDir() _______________________________________________________*/ 
 
void setOutputDir( char * pPath ) 
{ 
	int		i; 
 
	strcpy( outputDir, pPath ); 
	i = strlen( outputDir ) -1; 
	if( outputDir[i] != DIRECTORY_SEPARATOR ) 
	{ 
		outputDir[i+1] = DIRECTORY_SEPARATOR; 
		outputDir[i+2] = 0; 
	} 
} 
 
/*____ readGlobalSwitches() ___________________________________________________*/ 
 
argLink * readGlobalSwitches( argLink * pArgLink ) 
{ 
	char		arg[256]; 
	int			x, y; 
 
	for( ; pArgLink != NULL ; pArgLink = pArgLink->psNext ) 
	{ 
		strcpy( arg, pArgLink->pString ); 
		mystrupr( arg ); 
		if( arg[0] != '-' ) 
			return	pArgLink; 
		if( !strcmp( arg+1, "MONO" ) || !strcmp( arg+1, "DM" ) ) 
			wantedInputType = DOWNMIX_MONO; 
		else if( !strcmp( arg+1, "CRC" ) ) 
			wantedCRC = TRUE; 
		else if( !strcmp( arg+1, "PRIVATE" ) || !strcmp( arg+1, "P" ) ) 
			wantedPrivate = TRUE; 
		else if( !strcmp( arg+1, "COPYRIGHT" ) || !strcmp( arg+1, "C" ) ) 
			wantedCopyright = TRUE; 
		else if( !strcmp( arg+1, "ORIGINAL" ) ) 
			wantedOriginal = TRUE; 
		else if( !strcmp( arg+1, "COPY" ) ) 
			wantedOriginal = FALSE; 
		else if( !strcmp( arg+1, "DELETE" ) || !strcmp( arg+1, "DEL" ) ) 
			wantedDeleteSource = TRUE; 
		else if( !strcmp( arg+1, "QUIT" ) || !strcmp( arg+1, "Q" )) 
			wantedQuit = TRUE; 
		else if( !strcmp( arg+1, "SWAP" ) ) 
			wantedInputType = INVERSE_STEREO; 
		else if( !strcmp( arg+1, "LEFTMONO" ) || !strcmp( arg+1, "LM" )) 
			wantedInputType = LEFT_CHANNEL_MONO; 
		else if( !strcmp( arg+1, "RIGHTMONO" ) || !strcmp( arg+1, "RM" )) 
			wantedInputType = RIGHT_CHANNEL_MONO; 
		else if( !strcmp( arg+1, "QUIET" ) ) 
			wantedQuiet = TRUE; 
		else if( !strcmp( arg+1, "NOCFG" ) ) 
			;												/* simply do nothing... */ 
		else if( strstr( arg+1, "PROGRESS=" ) == arg+1 ) 
			progType = atoi( arg+10 ); 
		else if( strstr( arg+1, "OUTDIR=" ) == arg+1 ) 
			setOutputDir( pArgLink->pString + 8 ); 
		else if( strstr( arg+1, "REFRESH=" ) == arg+1 ) 
		{ 
			wantedProgressBarRate	= atoi( arg+9 ); 
			if( wantedProgressBarRate < 1 ) 
				wantedProgressBarRate = 1; 
		} 
#ifdef  PRIO 
		else if( strstr( arg+1, "PRIO=" ) == arg+1 ) 
		{ 
			strcpy( prioString, arg+6 ); 
			pPrioString = prioString; 
		} 
#endif 
		else if( !strcmp( arg+1, "RAWMONO" ) ) 
			rawChannels = 1; 
		else if( !strcmp( arg+1, "RAWSTEREO" ) ) 
			rawChannels = 2; 
		else if( !strcmp( arg+1, "RAWSIGNED" ) ) 
			rawSigned = TRUE; 
		else if( !strcmp( arg+1, "RAWUNSIGNED" ) ) 
			rawSigned = FALSE; 
		else if( strstr( arg+1, "RAWBITS=" ) == arg+1 ) 
		{ 
			rawBits = atoi( arg+9 ); 
			if( rawBits != 8 && rawBits != 16 ) 
				rawBits = 16; 
		} 
		else if( strstr( arg+1, "RAWFREQ=" ) == arg+1 ) 
		{ 
			rawFrequency = atoi( arg+9 ); 
		} 
		else if( strstr( arg+1, "RAWBYTEORDER=" ) == arg+1 ) 
		{ 
			if( strstr( arg+14, "LITTLE" ) == arg+14 ) 
				rawByteorder = LITTLE_ENDIAN; 
			if( strstr( arg+14, "BIG" ) == arg+14 ) 
				rawByteorder = BIG_ENDIAN; 
			if( strstr( arg+14, "DEFAULT" ) == arg+14 ) 
				rawByteorder = BYTEORDER; 
		} 
		else if( strstr( arg+1, "RAWCHANNELS=" ) == arg+1 ) 
		{ 
			rawChannels = atoi( arg+13 ); 
			if( rawChannels != 1 && rawChannels != 2 ) 
				rawChannels = 2; 
		} 
		else if( !strcmp( arg+1, "BR" ) ) 
		{ 
			pArgLink = pArgLink->psNext; 
			if( pArgLink == NULL ) 
				return	NULL; 
			wantedBitrate = atoi( pArgLink->pString ); 
			if( wantedBitrate > 1000 ) 
				wantedBitrate /= 1000; 
		} 
		else 
		{ 
			y = 0; 
			for( x = 1 ; arg[x] >= '0' && arg[x] <= '9' ; x++ ) 
				y = y * 10 + (arg[x] - '0'); 
			if( arg[x] == 0 ) 
			{ 
				wantedBitrate = y; 
				if( wantedBitrate > 1000 ) 
					wantedBitrate /= 1000; 
			} 
			else 
				return	pArgLink; 
		} 
	} 
	return  pArgLink; 
} 
 
 
/*____ readLocalSwitches() ___________________________________________________*/ 
 
argLink * readLocalSwitches( argLink * pArgLink, Job * psJob ) 
{ 
	char		arg[256]; 
	int			x, y; 
 
	for( ; pArgLink != NULL ; pArgLink = pArgLink->psNext ) 
	{ 
		strcpy( arg, pArgLink->pString ); 
		mystrupr( arg ); 
		if( arg[0] != '-' ) 
			return	pArgLink; 
		if( !strcmp( arg+1, "MONO" ) || !strcmp( arg+1, "DM" ) ) 
		{ 
			psJob->sInput.outputType = DOWNMIX_MONO; 
			psJob->sCodec.mode = 3; 
		} 
		else if( !strcmp( arg+1, "CRC" ) ) 
			psJob->sCodec.fCRC = TRUE; 
		else if( !strcmp( arg+1, "PRIVATE" ) || !strcmp( arg+1, "P" ) ) 
			psJob->sCodec.fPrivate = TRUE; 
		else if( !strcmp( arg+1, "COPYRIGHT" ) || !strcmp( arg+1, "C" ) ) 
			psJob->sCodec.fCopyright = TRUE; 
		else if( !strcmp( arg+1, "ORIGINAL" ) ) 
			psJob->sCodec.fOriginal = TRUE; 
		else if( !strcmp( arg+1, "COPY" ) ) 
			psJob->sCodec.fOriginal = FALSE; 
		else if( !strcmp( arg+1, "DELETE" ) || !strcmp( arg+1, "DEL" ) ) 
			psJob->fDeleteSource = TRUE; 
		else if( !strcmp( arg+1, "SWAP" ) ) 
		{ 
			if( psJob->sInput.fReadStereo == TRUE ) 
			{ 
				psJob->sInput.outputType = INVERSE_STEREO; 
				psJob->sCodec.mode = 3; 
			} 
		} 
		else if( !strcmp( arg+1, "LEFTMONO" ) || !strcmp( arg+1, "LM" )) 
		{ 
			if( psJob->sInput.fReadStereo == TRUE ) 
			{ 
				psJob->sInput.outputType = LEFT_CHANNEL_MONO; 
				psJob->sCodec.mode = 3; 
			} 
		} 
		else if( !strcmp( arg+1, "RIGHTMONO" ) || !strcmp( arg+1, "RM" )) 
		{ 
			if( psJob->sInput.fReadStereo == TRUE ) 
			{ 
				psJob->sInput.outputType = RIGHT_CHANNEL_MONO; 
				psJob->sCodec.mode = 3; 
			} 
		} 
		else if( !strcmp( arg+1, "RAWMONO" ) ) 
		{ 
			if( psJob->sInput.filetype == RAW ) 
				psJob->sInput.fReadStereo = FALSE; 
		} 
		else if( !strcmp( arg+1, "RAWSTEREO" ) ) 
		{ 
			if( psJob->sInput.filetype == RAW ) 
				psJob->sInput.fReadStereo = TRUE; 
		} 
		else if( !strcmp( arg+1, "RAWSIGNED" ) ) 
		{ 
			if( psJob->sInput.filetype == RAW ) 
				psJob->sInput.fSign = TRUE; 
 
		} 
		else if( !strcmp( arg+1, "RAWUNSIGNED" ) ) 
		{ 
			if( psJob->sInput.filetype == RAW ) 
				psJob->sInput.fSign = FALSE; 
 
		} 
		else if( strstr( arg+1, "RAWBITS=" ) == arg+1 ) 
		{ 
			if( psJob->sInput.filetype == RAW ) 
			{ 
				psJob->sInput.bits = atoi( arg+9 ); 
				if( psJob->sInput.bits != 8 && psJob->sInput.bits != 16 ) 
					psJob->sInput.bits = 16; 
			} 
		} 
		else if( strstr( arg+1, "RAWFREQ=" ) == arg+1 ) 
		{ 
			if( psJob->sInput.filetype == RAW ) 
				psJob->sInput.freq = atoi( arg+9 ); 
		} 
		else if( strstr( arg+1, "RAWBYTEORDER=" ) == arg+1 ) 
		{ 
			if( psJob->sInput.filetype == RAW ) 
			{ 
				if( strstr( arg+14, "LITTLE" ) == arg+14 ) 
					psJob->sInput.byteorder = LITTLE_ENDIAN; 
				if( strstr( arg+14, "BIG" ) == arg+14 ) 
					psJob->sInput.byteorder = BIG_ENDIAN; 
				if( strstr( arg+14, "DEFAULT" ) == arg+14 ) 
					psJob->sInput.byteorder = BYTEORDER; 
			} 
		} 
		else if( strstr( arg+1, "RAWCHANNELS=" ) == arg+1 ) 
		{ 
			if( psJob->sInput.filetype == RAW ) 
			{ 
				psJob->sInput.fReadStereo = atoi( arg+13 )-1; 
				if( psJob->sInput.fReadStereo != FALSE && psJob->sInput.fReadStereo != TRUE ) 
					psJob->sInput.fReadStereo = TRUE; 
			} 
		} 
 
		else if( !strcmp( arg+1, "BR" ) ) 
		{ 
			pArgLink = pArgLink->psNext; 
			if( pArgLink == NULL ) 
				return	pArgLink; 
			psJob->sCodec.bitrate = atoi( pArgLink->pString ); 
			if( psJob->sCodec.bitrate > 1000 ) 
			{ 
				psJob->sCodec.bitrate /= 1000; 
				wantedQuit = TRUE; 
			} 
		} 
		else if( !strcmp( arg+1, "HQ" ) ) 
		{ 
			wantedQuit = TRUE;																							/* Dummy for l3enc support */ 
		} 
		else 
		{ 
			y = 0; 
			for( x = 1 ; arg[x] >= '0' && arg[x] <= '9' ; x++ ) 
				y = y * 10 + (arg[x] - '0'); 
			if( arg[x] == 0 ) 
			{ 
				psJob->sCodec.bitrate = y; 
				if( psJob->sCodec.bitrate > 1000 ) 
					psJob->sCodec.bitrate /= 1000; 
			} 
			else 
				return	pArgLink; 
		} 
	} 
	return  pArgLink; 
} 
 
 
 
/*____ validateJobs() _________________________________________________________*/ 
 
int			validateJobs( Job * psJob ) 
{ 
	static  int     aValidBitrates[14] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 }; 
 
	int							i; 
	int							fOk = TRUE; 
 
	while( psJob != NULL && fOk ) 
	{ 
		fOk = FALSE; 
		for( i = 0 ; i < 14 ; i++ ) 
			if( wantedBitrate == aValidBitrates[i] ) 
				fOk = TRUE; 
 
		psJob = psJob->psNext; 
	} 
 
	if( fOk ) 
		return	TRUE; 
 
	fprintf( textout, "ERROR: %d is not a valid bitrate!\n\n", wantedBitrate ); 
 
	fprintf( textout, "Valid bitrates are:\n\n" ); 
 
	for( i = 0 ; i < 13 ; i++ ) 
		fprintf( textout, "%d, ", aValidBitrates[i] ); 
 
	fprintf( textout, "and %d kBit.\n", aValidBitrates[13] ); 
 
	return  FALSE; 
} 
 
 
/*____ printUsage() ___________________________________________________________*/ 
 
int     printUsage( void ) 
{ 
	fprintf( textout, "Usage: bladeenc [global switches] input1 [output1 [switches]] input2 ...\n" ); 
	fprintf( textout, "\n" ); 
	fprintf( textout, "General switches:\n" ); 
	fprintf( textout, "  -[kbit], -br [kbit]  Set MP3 bitrate. Default is 128 (64 for mono output).\n" ); 
	fprintf( textout, "  -crc                 Include checksum data in MP3 file.\n" ); 
	fprintf( textout, "  -delete, -del        Delete sample after successful encoding.\n" ); 
	fprintf( textout, "  -private, -p         Set the private-flag in the output file.\n" ); 
	fprintf( textout, "  -copyright, -c       Set the copyright-flag in the output file.\n" ); 
	fprintf( textout, "  -copy                Clears the original-flag in the output file.\n" ); 
	fprintf( textout, "  -mono, -dm           Produce mono MP3 files by combining stereo channels.\n" ); 
	fprintf( textout, "  -leftmono, -lm       Produce mono MP3 files from left stereo channel only.\n" ); 
	fprintf( textout, "  -rightmono, -rm      Produce mono MP3 files from right stereo channel only.\n" ); 
	fprintf( textout, "  -swap                Swap left and right stereo channels.\n" ); 
	fprintf( textout, "  -rawfreq=[freq]      Specify frequency for RAW samples. Default is 44100.\n" ); 
	fprintf( textout, "  -rawbits=[bits]      Specify bits per channel for RAW samples. Default is 16.\n" ); 
	fprintf( textout, "  -rawmono             Specifies that RAW samples are in mono, not stereo.\n" ); 
    fprintf( textout, "  -rawstereo           Specifies that RAW samples are in stereo (default).\n" ); 
	fprintf( textout, "  -rawsigned           Specifies that RAW samples are signed (default).\n" ); 
	fprintf( textout, "  -rawunsigned         Specifies that RAW samples are unsigned.\n" ); 
#ifdef	PAUSE_25_LINES 
	fprintf( textout, "Press ENTER to continue..." ); 
	fflush( textout ); 
	be_getch(); 
	fprintf( textout, "\n" ); 
#endif 
	fprintf( textout, "  -rawbyteorder=[order]Specifies byteorder for RAW samples, LITTLE or BIG.\n" ); 
	fprintf( textout, "  -rawchannels=[1/2]   Specifies number of channels for RAW samples. Does\n" ); 
	fprintf( textout, "                       the same as -rawmono and -rawstereo respectively.\n" ); 
	fprintf( textout, "\n" ); 
	fprintf( textout, "Global only switches:\n" ); 
	fprintf( textout, "  -quit, -q            Quit without waiting for keypress when finished.\n" ); 
	fprintf( textout, "  -outdir=[dir]        Save MP3 files in specified directory.\n" ); 
	fprintf( textout, "  -quiet               Disable screen output.\n" ); 
	fprintf( textout, "  -nocfg               Don't take settings from the config-file.\n" ); 
#ifdef  PRIO 
	fprintf( textout, "  -prio=[prio]         Sets the task priority for BladeEnc. Valid settings are\n" ); 
	fprintf( textout, "                       HIGHEST, HIGHER, NORMAL, LOWER, LOWEST(default) and IDLE\n" ); 
#endif 
	fprintf( textout, "  -refresh=[rate]      Refresh rate for progress indicator. 1=fastest, 2=def.\n" ); 
	fprintf( textout, "  -progress=[0-8]      Which progress indicator to use. 0=Off, 1=Default.\n" ); 
	fprintf( textout, "\n" ); 
	fprintf( textout, "Input/output files can be replaced with STDIN and STDOUT respectively.\n" ); 
#ifdef  DRAG_DROP 
	fprintf( textout, "To make a normal 128kBit MP3, just drag-n-drop your WAV onto the BladeEnc icon.\n" ); 
#endif 
	fprintf( textout, "\n" ); 
 
	return  TRUE; 
} 
 
/*____ addCommandlineJob() ____________________________________________________*/ 
 
int	addCommandlineJob( argLink ** ppArgLink ) 
{ 
	char	temp[256]; 
	Job	* psOp, * psTemp; 
	int		x; 
	argLink	* pArgLink; 
 
	pArgLink = * ppArgLink; 
	 
 
	psOp = (Job *) malloc( sizeof( Job ) ); 
	psOp->psNext = NULL; 
 
 
	/* Open Input File              */ 
 
	strcpy( temp, pArgLink->pString ); 
	mystrupr( temp ); 
	if( strcmp( temp, "STDIN" ) == 0 ) 
	{ 
		if( !fPreparedSTDIN ) 
		{ 
			prepStdin(); 
			fPreparedSTDIN = TRUE; 
		} 
		strcpy( psOp->sourceFilename, "Standard input stream" ); 
		x = openInput( &psOp->sInput, NULL ); 
	} 
	else 
	{ 
		strcpy( psOp->sourceFilename, pArgLink->pString ); 
		x = openInput( &psOp->sInput, pArgLink->pString ); 
	} 
 
	if( x != TRUE ) 
	{ 
		switch( psOp->sInput.errcode ) 
		{ 
		case	-1: 
			fprintf( textout, "ERROR: '%s' is not a WAV or AIFF file!\n", psOp->sourceFilename ); 
			break; 
		case	-2: 
			fprintf( textout, "ERROR: Couldn't open '%s'!\n", psOp->sourceFilename ); 
			break; 
		case	-3: 
			fprintf( textout, "ERROR: Unexpected end of file '%s'!\n", psOp->sourceFilename ); 
			break; 
		case	-5: 
			fprintf( textout, "ERROR: Necessary chunk missing in '%s'!\n", psOp->sourceFilename ); 
			break; 
		case	-6: 
			fprintf( textout, "ERROR: Sample '%s' is of an unknown subtype!\n", psOp->sourceFilename ); 
			break; 
		default: 
			fprintf( textout, "ERROR: Unknown error while opening '%s'!\n", psOp->sourceFilename ); 
 
		} 
		free( psOp ); 
		return  FALSE; 
	} 
 
	/* If RAW, set default values */ 
 
	if( psOp->sInput.filetype == RAW ) 
	{ 
		psOp->sInput.freq = rawFrequency; 
		psOp->sInput.outputFreq = rawFrequency; 
		psOp->sInput.fReadStereo = rawChannels-1; 
		psOp->sInput.bits = rawBits; 
		psOp->sInput.fSign = rawSigned; 
		psOp->sInput.byteorder = rawByteorder; 
	} 
 
	/*		*/ 
 
	if( !psOp->sInput.fReadStereo && (wantedInputType == STEREO || wantedInputType == INVERSE_STEREO) ) 
		psOp->sInput.outputType = DOWNMIX_MONO; 
	else 
		psOp->sInput.outputType = wantedInputType; 
 
 
	/* Set sCodec.mode (MONO or STEREO) */ 
 
	if( psOp->sInput.outputType == DOWNMIX_MONO || psOp->sInput.outputType == LEFT_CHANNEL_MONO 
	        || psOp->sInput.outputType == RIGHT_CHANNEL_MONO ) 
		psOp->sCodec.mode = 3;                                                   /* Force to mono... */ 
	else 
	{ 
		psOp->sCodec.mode = 0; 
	} 
 
	/* Set frequency */ 
 
	if( psOp->sInput.freq != 44100 && psOp->sInput.freq != 48000 
	        && psOp->sInput.freq != 32000 ) 
	{ 
		fprintf( textout, "ERROR: Sample '%s' is not in 32, 44.1 or 48 kHz!\n", psOp->sourceFilename ); 
		closeInput( &(psOp->sInput) ); 
		free( psOp ); 
		return  FALSE; 
	} 
 
	psOp->sCodec.frequency = psOp->sInput.freq; 
 
	/* Set bitrate */ 
 
	if( wantedBitrate == -1 ) 
	{ 
		if( psOp->sCodec.mode == 3 ) 
			wantedBitrate = 64; 
		else 
			wantedBitrate = 128; 
	} 
	else 
		psOp->sCodec.bitrate = wantedBitrate; 
 
 
	/* Set other parameters */ 
 
	psOp->sCodec.bitrate = wantedBitrate; 
 
	psOp->sCodec.fPrivate = wantedPrivate; 
	psOp->sCodec.fCRC = wantedCRC; 
	psOp->sCodec.fCopyright = wantedCopyright; 
	psOp->sCodec.fOriginal = wantedOriginal; 
	psOp->fDeleteSource = wantedDeleteSource; 
 
 
	/* Set unsupported parameters */ 
 
	psOp->sCodec.emphasis = 0; 
 
	pArgLink = pArgLink->psNext; 
 
	/* Check for output specification and set output name */ 
 
	psOp->outputFilename[0] = 0; 
	if( pArgLink != NULL ) 
	{ 
		strcpy( temp, pArgLink->pString ); 
		mystrupr( temp ); 
		if( !strcmp( temp, "STDOUT" ) ) 
		{ 
			wantedSTDOUT = TRUE; 
			strcpy( psOp->outputFilename, "STDOUT" ); 
			pArgLink = pArgLink->psNext; 
		} 
		else if( strlen( temp ) >= 4 && !strcmp( temp+strlen(temp)-4, ".MP3" ) ) 
		{ 
			strcpy( psOp->outputFilename, pArgLink->pString ); 
			pArgLink = pArgLink->psNext; 
		} 
	} 
 
	/* Generate output name if not allready set */ 
 
	if( psOp->outputFilename[0] == 0 ) 
	{ 
		if( outputDir[0] != 0 ) 
		{ 
			strcpy( psOp->outputFilename, outputDir ); 
 
			strcpy( temp, psOp->sourceFilename ); 
			x = strlen( temp ); 
			while( temp[x] != '.' && x >=0 && temp[x] != DIRECTORY_SEPARATOR ) 
				x--; 
 
			if( temp[x] == DIRECTORY_SEPARATOR ) 
				x = strlen(temp); 
 
			if( x >= 0 ) 
				strcpy( temp + x, ".mp3" ); 
			else 
			{ 
				x = strlen( temp ); 
				strcat( temp, ".mp3" ); 
			} 
 
			while( x >= 0 && temp[x] != '\\' && temp[x] != '/' && temp[x] != ':' ) 
				x--; 
			x++; 
 
			strcat( psOp->outputFilename, temp + x ); 
		} 
		else 
		{ 
			strcpy( temp, psOp->sourceFilename ); 
			x = strlen( temp ); 
			while( temp[x] != '.' && x >=0 && temp[x] != DIRECTORY_SEPARATOR ) 
				x--; 
 
			if( temp[x] == DIRECTORY_SEPARATOR ) 
				x = strlen(temp); 
 
			if( x >= 0 ) 
				strcpy( temp + x, ".mp3" ); 
			else 
				strcat( temp, ".mp3" ); 
 
			strcpy( psOp->outputFilename, temp ); 
		} 
	} 
 
 
	/* Read local switches */ 
 
	pArgLink = readLocalSwitches( pArgLink, psOp ); 
 
 
	/* Put this Job in the batch */ 
 
	if( psJobQueue == NULL ) 
		psJobQueue = psOp; 
	else 
	{ 
		psTemp = psJobQueue; 
		while( psTemp->psNext != NULL ) 
			psTemp = psTemp->psNext; 
		psTemp->psNext = psOp; 
	} 
 
	* ppArgLink = pArgLink; 
	return  TRUE; 
} 
 
 
/*____ clearJobQueue() ________________________________________________________*/ 
 
int     clearJobQueue( void ) 
{ 
	while( psJobQueue != NULL ) 
		removeJobQueueEntry( psJobQueue ); 
	return  TRUE; 
} 
 
 
/*____ removeQueueEntry() _____________________________________________________*/ 
 
int removeJobQueueEntry( Job * psJob ) 
{ 
	Job     * psPrev; 
 
	/* Unlink specified entry */ 
 
	if( psJob == psJobQueue ) 
		psJobQueue = psJob->psNext; 
	else 
	{ 
		psPrev = psJobQueue; 
		while( psPrev->psNext != psJobQueue && psPrev->psNext != NULL ) 
			psPrev = psPrev->psNext; 
 
		if( psPrev->psNext == NULL ) 
			return  FALSE; 
 
		psPrev->psNext = psJob->psNext; 
	} 
 
	/* Close open file, free the entry and return. */ 
 
	closeInput( &psJob->sInput ); 
	free( psJob ); 
	return  TRUE; 
}