Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members | Related Pages

sidplay.cpp

Go to the documentation of this file.
00001 //
00002 // /home/ms/sidplay/RCS/sidplay.cpp,v
00003 //
00004 
00005 #include <iostream.h>
00006 #include <iomanip.h>
00007 #include <fstream.h>
00008 #include <stdlib.h>
00009 #include <unistd.h>
00010 
00011 #include "player.h"
00012 #include "myendian.h"
00013 #include "audiodrv.h"
00014 
00015 #if defined(__amigaos__)
00016 #define EXIT_ERROR_STATUS (20)
00017 #else
00018 #define EXIT_ERROR_STATUS (-1)
00019 #endif
00020 
00021 // Error and status message numbers.
00022 enum
00023 {
00024         ERR_NOT_ENOUGH_MEMORY,
00025         ERR_SYNTAX,
00026         ERR_ENDIANESS
00027 };
00028 
00029 void error( char*, char* );  // print out a text in "ERROR: string1 'string2'" format.
00030 void printtext( int messageNum );
00031 
00032 static bool verboseOutput = false;
00033 
00034 int main(int argc, char *argv[])
00035 {
00036         cout 
00037                 << endl
00038                 << "SIDPLAY   Music player and C64 SID chip emulator   Version " << emu_version << endl
00039                 << "Copyright (c) 1994-1997 Michael Schwendt   All rights reserved." << endl
00040 #if defined(sgi)
00041                 << "Ported to SGI by <aagero@aage.priv.no>" << endl
00042 #elif defined(hpux)
00043             << "Ported to HP-UX by <esap@cs.tut.fi>" << endl
00044 #elif defined(__amigaos__)
00045             << "Ported to AmigaOS by <phillwooller@geocities.com>" << endl
00046 #endif  
00047                 << endl;
00048         
00049         // ======================================================================
00050         // INITIALIZE THE EMULATOR ENGINE
00051         // ======================================================================
00052 
00053         // Initialize the SID-Emulator Engine to defaults.
00054         emuEngine myEmuEngine;
00055         // Everything went okay ?
00056         if ( !myEmuEngine )
00057         {
00058                 // So far the only possible error.
00059                 printtext(ERR_NOT_ENOUGH_MEMORY);
00060         }
00061         if ( !myEmuEngine.verifyEndianess() )
00062         {
00063                 printtext(ERR_ENDIANESS);
00064         }
00065 
00066         // Get the default configuration.
00067         struct emuConfig myEmuConfig;
00068         myEmuEngine.getConfig(myEmuConfig);
00069 
00070         // ======================================================================
00071 
00072         if ( argc < 2 )             // at least one argument required
00073                 printtext(ERR_SYNTAX);
00074 
00075         uword selectedSong = 0;
00076         
00077         // Default audio settings.
00078         myEmuConfig.frequency = 22050;
00079         myEmuConfig.channels = SIDEMU_MONO;
00080         myEmuConfig.bitsPerSample = SIDEMU_8BIT;
00081         uword fragments = 16;
00082         uword fragSizeBase = 12;
00083         int forceBufSize = 0;  // get it from argument line
00084     
00085         ubyte infile = 0;
00086         
00087         // parse command line arguments
00088         int a = 1;
00089         while ((a < argc) && (argv[a] != NULL))  
00090         {
00091                 if ( argv[a][0] == '-')  
00092                 {
00093                         // reading from stdin
00094                         if ( strlen(argv[a]) == 1 ) 
00095                                 if ( infile == 0 )
00096                         {
00097                                 infile = a;
00098                                 break;
00099                         }
00100                         else
00101                                 printtext(ERR_SYNTAX);
00102                         switch ( argv[a][1] )
00103                         {
00104 #if defined(linux) || defined(__FreeBSD__) || defined(__amigaos__)
00105                          case '1':
00106                                 if ( argv[a][2] == '6' )
00107                                         myEmuConfig.bitsPerSample = SIDEMU_16BIT;
00108                                 break;
00109 #endif          
00110                          case 'c':
00111                                 myEmuConfig.forceSongSpeed = true;
00112                                 break;
00113                          case 'a':
00114                                 if ( argv[a][2] == '2' )
00115                                         myEmuConfig.memoryMode = MPU_BANK_SWITCHING;
00116                                 else
00117                                         myEmuConfig.memoryMode = MPU_PLAYSID_ENVIRONMENT;
00118                                 break;
00119                          case 'b':
00120                                 if ( argv[a][2] == 'n' )  
00121                                 {
00122                                         fragments = (unsigned)atoi(argv[a]+3);
00123                                         if (( fragments < 2 ) || ( fragments > 255 )) 
00124                                                 fragments = 2;
00125                                 }
00126                                 else if ( argv[a][2] == 's' )  
00127                                 {
00128                                         fragSizeBase = (unsigned)atoi(argv[a]+3);
00129                                         if (( fragSizeBase < 7 ) || ( fragSizeBase > 17 )) 
00130                                                 fragSizeBase = 14;
00131                                 }
00132                                 else
00133                                 {
00134                                         forceBufSize = atoi(argv[a]+2);
00135                                 }
00136                                 break;
00137                          case 'f':
00138                                 myEmuConfig.frequency = (udword)atol(argv[a]+2);
00139                                 break;
00140                          case 'h':
00141                                 printtext(ERR_SYNTAX);
00142                                 break;
00143                          case 'n':
00144                                 if ( argv[a][2] == 'f' )  
00145                                         myEmuConfig.emulateFilter = false;
00146                                 else
00147                                         myEmuConfig.clockSpeed = SIDTUNE_CLOCK_NTSC;
00148                                 break;
00149                          case 'o':
00150                                 selectedSong = atoi(argv[a]+2);
00151                                 break;
00152                          case 'p':
00153                                 if ( argv[a][2] == 'c' )  
00154                                 {
00155                                         myEmuConfig.autoPanning = SIDEMU_CENTEREDAUTOPANNING;
00156                                 }
00157                                 break;
00158                          case 's':
00159                                 myEmuConfig.channels = SIDEMU_STEREO;
00160                                 if ( argv[a][2] == 's' )  
00161                                 {
00162                                         myEmuConfig.volumeControl = SIDEMU_STEREOSURROUND;
00163                                 }
00164                                 break;
00165                          case 'v':
00166                                 verboseOutput = true;
00167                                 break;
00168                          default:
00169                                 printtext(ERR_SYNTAX);
00170                                 break;
00171                         }
00172                 }
00173                 else  
00174                 {
00175                         if ( infile == 0 )
00176                                 infile = a;  // filename argument
00177                         else
00178                                 printtext(ERR_SYNTAX);
00179                 }
00180                 a++;  // next argument
00181         };
00182         
00183         if (infile == 0)
00184         {
00185                 printtext(ERR_SYNTAX);
00186         }
00187 
00188         // ======================================================================
00189         // VALIDATE SID EMULATOR SETTINGS
00190         // ======================================================================
00191         
00192         if ((myEmuConfig.autoPanning!=SIDEMU_NONE) && (myEmuConfig.channels==SIDEMU_MONO))
00193         {
00194                 myEmuConfig.channels = SIDEMU_STEREO;  // sane
00195         }
00196         if ((myEmuConfig.autoPanning!=SIDEMU_NONE) && (myEmuConfig.volumeControl==SIDEMU_NONE))
00197         {
00198                 myEmuConfig.volumeControl = SIDEMU_FULLPANNING;  // working
00199         }
00200 
00201         // ======================================================================
00202         // INSTANTIATE A SIDTUNE OBJECT
00203         // ======================================================================
00204 
00205         sidTune myTune( argv[infile] );
00206         struct sidTuneInfo mySidInfo;
00207         myTune.getInfo( mySidInfo );
00208         if ( !myTune )  
00209         {
00210                 cerr << "SIDPLAY: " << mySidInfo.statusString << endl;
00211                 exit(EXIT_ERROR_STATUS);
00212         }
00213         else
00214         {
00215                 if (verboseOutput)
00216                 {
00217                         cout << "File format  : " << mySidInfo.formatString << endl;
00218                         cout << "Filenames    : " << mySidInfo.dataFileName << ", "
00219                                 << mySidInfo.infoFileName << endl;
00220                         cout << "Condition    : " << mySidInfo.statusString << endl;
00221                 }
00222                 cout << "--------------------------------------------------" << endl;
00223                 if ( mySidInfo.numberOfInfoStrings == 3 )
00224                 {
00225                         cout << "Name         : " << mySidInfo.nameString << endl;
00226                         cout << "Author       : " << mySidInfo.authorString << endl;
00227                         cout << "Copyright    : " << mySidInfo.copyrightString << endl;
00228                 }
00229                 else
00230                 {
00231                         for ( int infoi = 0; infoi < mySidInfo.numberOfInfoStrings; infoi++ )
00232                                 cout << "Description  : " << mySidInfo.infoString[infoi] << endl;
00233                 }
00234                 cout << "--------------------------------------------------" << endl;
00235                 if (verboseOutput)
00236                 {
00237                         cout << "Load address : $" << hex << setw(4) << setfill('0') 
00238                                 << mySidInfo.loadAddr << endl;
00239                         cout << "Init address : $" << hex << setw(4) << setfill('0') 
00240                                 << mySidInfo.initAddr << endl;
00241                         cout << "Play address : $" << hex << setw(4) << setfill('0') 
00242                                 << mySidInfo.playAddr << dec << endl;
00243                 }
00244         }
00245 
00246         // ======================================================================
00247         // CONFIGURE THE AUDIO DRIVER
00248         // ======================================================================
00249 
00250         // Instantiate the audio driver. The capabilities of the audio driver
00251         // can override the settings of the SID emulator.
00252         audioDriver myAudio;
00253         if ( !myAudio.IsThere() )
00254         {
00255                 cerr << "SIDPLAY: No audio device available !" << endl;
00256                 exit(EXIT_ERROR_STATUS);
00257         }
00258         // Open() does not accept the "bitsize" value on all platforms, e.g.
00259         // Sparcstations 5 and 10 tend to be 16-bit only at rates above 8000 Hz.
00260         if ( !myAudio.Open(myEmuConfig.frequency,myEmuConfig.bitsPerSample,
00261                                            myEmuConfig.channels,fragments,fragSizeBase))
00262         {
00263                 cerr << "SIDPLAY: " << myAudio.GetErrorString() << endl;
00264                 exit(EXIT_ERROR_STATUS);
00265         }
00266         if (verboseOutput)
00267         {
00268                 cout << "Block size   : " << (udword)myAudio.GetBlockSize() << endl
00269                         << "Fragments    : " << myAudio.GetFragments() << endl;
00270         }
00271         
00272         // ======================================================================
00273         // CONFIGURE THE EMULATOR ENGINE
00274         // ======================================================================
00275 
00276         // Configure the SID emulator according to the audio driver settings.
00277         myEmuConfig.frequency = myAudio.GetFrequency();
00278         myEmuConfig.bitsPerSample = myAudio.GetSamplePrecision();
00279         myEmuConfig.sampleFormat = myAudio.GetSampleEncoding();
00280         myEmuEngine.setConfig( myEmuConfig );
00281     // Print the relevant settings.
00282         if (verboseOutput)
00283         {
00284                 cout << "Frequency    : " << dec << myEmuConfig.frequency << " Hz" << endl;
00285                 cout << "SID Filter   : " << ((myEmuConfig.emulateFilter == true) ? "Yes" : "No") << endl;
00286                 if (myEmuConfig.memoryMode == MPU_PLAYSID_ENVIRONMENT)
00287                 {
00288                         cout << "Memory mode  : PlaySID (this is supposed to fix PlaySID-specific rips)" << endl;
00289                 }
00290                 else if (myEmuConfig.memoryMode == MPU_TRANSPARENT_ROM)
00291                 {
00292                         cout << "Memory mode  : Transparent ROM (SIDPLAY default)" << endl;
00293                 }
00294                 else if (myEmuConfig.memoryMode == MPU_BANK_SWITCHING)
00295                 {
00296                         cout << "Memory mode  : Bank Switching" << endl;
00297                 }
00298         }
00299         
00300         // ======================================================================
00301         // INITIALIZE THE EMULATOR ENGINE TO PREPARE PLAYING A SIDTUNE
00302         // ======================================================================
00303 
00304         extern bool sidEmuInitializeSong(emuEngine & thisEmuEngine, // added by AEH
00305                                                                           sidTune & thisTune,
00306                                                                           uword songNumber);
00307 
00308         if ( !sidEmuInitializeSong(myEmuEngine,myTune,selectedSong) )
00309         {
00310                 cerr << "SIDPLAY: SID Emulator Engine components not ready" << endl;
00311                 exit(EXIT_ERROR_STATUS);
00312         }
00313         // Read out the current settings of the sidtune.
00314         myTune.getInfo( mySidInfo );
00315         if ( !myTune )
00316         {
00317                 cerr << "SIDPLAY: " << mySidInfo.statusString << endl;
00318                 exit(EXIT_ERROR_STATUS);
00319         }
00320         cout << "Setting song : " << mySidInfo.currentSong
00321                 << " out of " << mySidInfo.songs
00322                 << " (default = " << mySidInfo.startSong << ')' << endl;
00323         if (verboseOutput)
00324         {
00325                 cout << "Song speed   : " << mySidInfo.speedString << endl;
00326         }
00327         
00328         // ======================================================================
00329         // KEEP UP A CONTINUOUS OUTPUT SAMPLE STREAM
00330         // ======================================================================
00331 
00332         int bufSize = myAudio.GetBlockSize();
00333         if (forceBufSize != 0)
00334         {
00335                 bufSize = forceBufSize;
00336                 if (verboseOutput)
00337                 {
00338                         cout << "Buffer size  : " << bufSize << endl;
00339                 }
00340         }
00341         ubyte* buffer;
00342         if ((buffer = new ubyte[bufSize]) == 0)
00343     {
00344                 printtext(ERR_NOT_ENOUGH_MEMORY);
00345             exit(EXIT_ERROR_STATUS);
00346     }
00347         cout << "Playing, press ^C to stop ..." << endl;
00348         for (;;)
00349         {
00350         myEmuEngine.FillBuffer(myTune, buffer, bufSize); // AEH changed
00351 //              sidEmuFillBuffer(myEmuEngine,myTune,buffer,bufSize);
00352                 myAudio.Play(buffer,bufSize);
00353         }
00354 
00355         // Will possibly never come this far.
00356         exit(0);
00357 }
00358 
00359 
00360 void error(char* s1, char* s2 = "")
00361 {
00362         cerr << "SIDPLAY: ERROR: " << s1 << ' ' << "'" << s2 << "'" << endl;
00363         exit(EXIT_ERROR_STATUS);
00364 }
00365 
00366 
00367 void printtext(int number)
00368 {
00369   switch (number)  
00370         {
00371          case ERR_ENDIANESS:
00372                 {
00373                         cerr << "SIDPLAY: ERROR: Hardware endianess improperly configured." << endl;
00374                         exit(EXIT_ERROR_STATUS);
00375                         break;
00376                 }
00377          case ERR_NOT_ENOUGH_MEMORY:
00378                 cerr << "SIDPLAY: ERROR: Not enough memory" << endl;
00379                 exit(EXIT_ERROR_STATUS);
00380          case ERR_SYNTAX:
00381                 cout << " syntax: sidplay [-<command>] <datafile>|-" << endl
00382                         << " commands: -h       display this screen" << endl
00383                         << "           -v       verbose output" << endl
00384                         << "           -f<num>  set frequency in Hz (default: 22050)" << endl
00385                         << "           -o<num>  set song number (default: preset)" << endl
00386                         << "           -a       improve PlaySID compatibility (read the docs !)" << endl
00387                         << "           -a2      bank switching mode (overrides -a)" << endl
00388 #if defined(linux) || defined(__FreeBSD__) || defined(__amigaos__)
00389                         << "           -16      enable 16-bit sample mixing" << endl
00390 #endif    
00391 #if defined(linux) || defined(__FreeBSD__) || defined(__amigaos__) || defined(hpux)
00392                         << "           -s       enable stereo replay" << endl
00393                         << "           -ss      enable stereo surround" << endl
00394                         << "           -pc      enable centered auto-panning (stereo only)" << endl
00395 #endif
00396                         << "           -nf      no SID filter emulation" << endl
00397                         << "           -n       set NTSC clock speed (default: PAL)" << endl
00398                         << "           -c       force song speed = clock speed (PAL/NTSC)" << endl
00399                         << "           -bn<num> set number of audio buffer fragments to use" << endl
00400                         << "           -bs<num> set size 2^<num> of audio buffer fragments" << endl
00401                         << "           -b<num>  set sample buffer size" << endl
00402                         << endl;
00403                 exit(EXIT_ERROR_STATUS);
00404          default:
00405                 cerr << "SIDPLAY: ERROR: Internal system error" << endl;
00406                 exit(EXIT_ERROR_STATUS);
00407         }
00408 }

Generated on Tue Feb 8 04:14:10 2005 for Esidplay by doxygen 1.3.3