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; }