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

sid2wav.cpp

Go to the documentation of this file.
00001 //
00002 // /home/ms/sidplay/RCS/sid2wav.cpp,v
00003 //
00004 // --------------------------------------------------------------------------
00005 //
00006 // --- SIDPLAY to .WAV/.AU ---
00007 //
00008 // Copyright (c) 1994-97 Michael Schwendt and Adam Lorentzon.
00009 // All rights reserved.
00010 // InterNet email: <Michael_Schwendt@public.uni-hamburg.de>
00011 //                 Adam Lorentzon   <d93-alo@nada.kth.se>
00012 //
00013 // Some /u-law specific code 'borrowed' from tracker 4.43 by Marc Espie.
00014 //
00015 // Redistribution and use  in source and  binary forms, either  unchanged or
00016 // modified, are permitted provided that the following conditions are met:
00017 //
00018 // (1)  Redistributions  of  source  code  must  retain  the above copyright
00019 // notice, this list of conditions and the following disclaimer.
00020 //
00021 // (2) Redistributions  in binary  form must  reproduce the  above copyright
00022 // notice,  this  list  of  conditions  and  the following disclaimer in the
00023 // documentation and/or other materials provided with the distribution.
00024 //
00025 // THIS SOFTWARE  IS PROVIDED  BY THE  AUTHOR ``AS  IS'' AND  ANY EXPRESS OR
00026 // IMPLIED  WARRANTIES,  INCLUDING,   BUT  NOT  LIMITED   TO,  THE   IMPLIED
00027 // WARRANTIES OF MERCHANTABILITY  AND FITNESS FOR  A PARTICULAR PURPOSE  ARE
00028 // DISCLAIMED.  IN NO EVENT SHALL  THE AUTHOR OR CONTRIBUTORS BE LIABLE  FOR
00029 // ANY DIRECT,  INDIRECT, INCIDENTAL,  SPECIAL, EXEMPLARY,  OR CONSEQUENTIAL
00030 // DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS
00031 // OR SERVICES;  LOSS OF  USE, DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION)
00032 // HOWEVER  CAUSED  AND  ON  ANY  THEORY  OF LIABILITY, WHETHER IN CONTRACT,
00033 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  IN
00034 // ANY  WAY  OUT  OF  THE  USE  OF  THIS  SOFTWARE,  EVEN  IF ADVISED OF THE
00035 // POSSIBILITY OF SUCH DAMAGE.
00036 // --------------------------------------------------------------------------
00037 
00038 #include <iostream.h>
00039 #include <iomanip.h>
00040 #include <fstream.h>
00041 
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044 #include <string.h>
00045 #ifdef __MSDOS__
00046   #include <dir.h>
00047 #endif
00048 #include <time.h>
00049 
00050 #include "player.h"
00051 #include "myendian.h"
00052 
00053 #if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
00054 #error Have to define the endianess of the cpu.
00055 #endif
00056 
00057 #if defined(__amigaos__)
00058 #define EXIT_ERROR_STATUS (20)
00059 #else
00060 #define EXIT_ERROR_STATUS (-1)
00061 #endif
00062 
00063 const char s2w_version[] = "1.7.2";
00064 
00065 enum
00066 {
00067         TXT_TITLE,
00068     ERR_NOT_ENOUGH_MEMORY,
00069     ERR_SYNTAX, ERR_ENGINE,
00070         ERR_ENDIANESS
00071 };
00072 
00073 const int FLAG_STDIN = 0x01;
00074 const int FLAG_ULAW = 0x08;
00075 
00076 static int flags;
00077 
00078 struct wav_hdr                  // little endian
00079 {
00080         char main_chunk[4];         // 'RIFF'
00081         udword length;              // filelength
00082         char chunk_type[4];         // 'WAVE'
00083         
00084         char sub_chunk[4];          // 'fmt '
00085         udword clength;             // length of sub_chunk, always 16 bytes
00086         uword  format;              // currently always = 1 = PCM-Code
00087         uword  modus;               // 1 = mono, 2 = stereo
00088         udword samplefreq;          // sample-frequency
00089         udword bytespersec;         // frequency * bytespersmpl  
00090         uword  bytespersmpl;        // bytes per sample; 1 = 8-bit, 2 = 16-bit
00091         uword  bitspersmpl;
00092         char data_chunk[4];         // keyword, begin of data chunk; = 'data'
00093         udword data_length;         // length of data
00094 };
00095 
00096 struct au_hdr                   // big endian
00097 {
00098         char id[4];                 // '.snd'
00099         udword hdrlength;           // const 0x18
00100         udword length;              // data length
00101         udword format;              // 1=ulaw
00102         udword frequency;
00103         udword channels;            // 1=mono, 2=stereo
00104         // Cool Edit v1.50 saves au files with a header that contains an extra
00105         // 4 byte field at the end. It has been filled with zeros in the
00106         // cases I've come across. This makes hdrlength 0x1C.
00107 };
00108 
00109 // Default WAV header: PCM, mono, 22050 Hz, 8-bit
00110 #if defined(IS_LITTLE_ENDIAN)
00111 wav_hdr my_wav_hdr =
00112 {
00113         {'R','I','F','F'}, 0, {'W','A','V','E'},
00114         {'f','m','t',' '}, 16, 1, 1, 22050, 22050, 1, 8,
00115         {'d','a','t','a'}, 0
00116 };
00117 #else
00118 wav_hdr my_wav_hdr =
00119 { 
00120         {'R','I','F','F'}, 0, {'W','A','V','E'},
00121         {'f','m','t',' '}, 
00122         convertEndianess ((udword)16),
00123         convertEndianess ((uword)1),
00124         convertEndianess ((uword)1),
00125         convertEndianess ((udword)22050),
00126         convertEndianess ((udword)22050),
00127         convertEndianess ((uword)1),
00128         convertEndianess ((uword)8),
00129         {'d','a','t','a'}, 0
00130 };
00131 #endif
00132 
00133 #if defined(IS_LITTLE_ENDIAN) 
00134 au_hdr my_au_hdr =
00135 { 
00136         {'.','s','n','d'},
00137         convertEndianess ((udword)0x18),
00138         0,
00139         convertEndianess ((udword)1),
00140         convertEndianess ((udword)8000),           // 8000bytes = 0x1F40, 8012=0x1F4C
00141         convertEndianess ((udword)1)
00142 };
00143 #else
00144 au_hdr my_au_hdr =
00145 {
00146         {'.','s','n','d'}, 0x18, 0, 1, 8000, 1
00147 };
00148 #endif
00149 
00150 static int fadein_seconds,
00151     fadein_step,
00152     fadein_count,
00153     fadein_currentlevel,
00154     fadeout_seconds,
00155     fadeout_step,
00156     fadeout_count,
00157     fadeout_currentlevel,
00158     fadelevel;
00159 
00160 
00161 void error( char*, char* );
00162 void printtext( int );
00163 
00164 void (*fadeout_buffer)( ubyte*, udword );
00165 void (*fadein_buffer)( ubyte*, udword );
00166 
00167 void fadeout_buffer_8( ubyte*, udword );
00168 void fadein_buffer_8( ubyte*, udword );
00169 void fadeout_buffer_16( ubyte*, udword );
00170 void fadein_buffer_16( ubyte*, udword );
00171 void buffer2ulaw( ubyte* samplebuffer, udword samplebuffersize );
00172 void endianswitch_buffer( ubyte* samplebuffer, udword samplebuffersize );
00173 
00174 
00175 int main(int argc, char *argv[])
00176 {
00177         // Title.
00178         printtext(TXT_TITLE);
00179         
00180         // ======================================================================
00181         // INITIALIZE THE EMULATOR ENGINE
00182         // ======================================================================
00183 
00184         // Initialize the SID-Emulator Engine to defaults.
00185         emuEngine myEmuEngine;
00186         // Everything went okay ?
00187         if ( !myEmuEngine )
00188         {
00189                 // So far the only possible error.
00190                 printtext(ERR_NOT_ENOUGH_MEMORY);
00191         }
00192         if ( !myEmuEngine.verifyEndianess() )
00193         {
00194                 printtext(ERR_ENDIANESS);
00195         }
00196         
00197         struct emuConfig myEmuConfig;
00198         myEmuEngine.returnConfig(myEmuConfig);
00199 
00200         // ======================================================================
00201         // CONFIGURE THE EMULATOR ENGINE
00202         // ======================================================================
00203 
00204         // Defaults.
00205         myEmuConfig.frequency = 22050;
00206         myEmuConfig.channels = SIDEMU_MONO;
00207         myEmuConfig.bitsPerSample = SIDEMU_8BIT;
00208         flags = 0;
00209         uword selectedSong = 0;
00210         int seconds = 60;
00211         int beginSeconds = 0;
00212         fadein_seconds = 0;
00213         fadeout_seconds = 2;
00214         fadeout_buffer = fadeout_buffer_8;
00215         fadein_buffer = fadein_buffer_8;
00216         int muteVal = 0;
00217 
00218         // File argument numbers.
00219         int infile = 0, outfile = 0;
00220   
00221         // Parse command line arguments.
00222         for ( int a = 1; a < argc; a++)
00223         {
00224                 if ( argv[a][0] == '-')
00225                 {
00226 #ifndef __MSDOS__
00227                         // Reading from stdin.
00228                         if ( strlen(argv[a]) == 1 )
00229                         {
00230                                 if ( infile == 0 )
00231                                 {
00232                                         infile = a;
00233                                         flags |= FLAG_STDIN;
00234                                 }
00235                                 else
00236                                 {
00237                                         printtext(ERR_SYNTAX);
00238                                 }
00239                                 break;
00240                         }
00241 #endif
00242                         if ( strncasecmp( &argv[a][1], "fout", 4 ) == 0 )
00243                         {
00244                                 fadeout_seconds = atoi(argv[a]+5);
00245                         }
00246                         else if ( strncasecmp( &argv[a][1], "fin", 3 ) == 0 )
00247                         {
00248                                 fadein_seconds = atoi(argv[a]+4);
00249                         }
00250                         else if ( strncasecmp( &argv[a][1], "nf", 2 ) == 0 )
00251                         {
00252                                 myEmuConfig.emulateFilter = false;
00253                         }
00254                         else if ( strncasecmp( &argv[a][1], "a2", 2 ) == 0 )
00255                         {
00256                                 myEmuConfig.memoryMode = MPU_BANK_SWITCHING;
00257                         }
00258                         else if ( strncasecmp( &argv[a][1], "a", 1 ) == 0 )
00259                         {
00260                                 myEmuConfig.memoryMode = MPU_PLAYSID_ENVIRONMENT;
00261                         }
00262                         else if ( strncasecmp( &argv[a][1], "b", 1 ) == 0 )
00263                         {
00264                                 beginSeconds = atoi(argv[a]+2);
00265                         }
00266                         else if ( strncasecmp( &argv[a][1], "f", 1 ) == 0 )
00267                         {
00268                                 myEmuConfig.frequency = (ulong)atoi(argv[a]+2);
00269                         }
00270                         else if ( strncasecmp( &argv[a][1], "h", 1 ) == 0 )
00271                         {
00272                                 printtext(ERR_SYNTAX);
00273                         }
00274                         else if ( strncasecmp( &argv[a][1], "m", 1 ) == 0 )
00275                         {
00276                                 for ( ubyte j = 2; j < strlen(argv[a]); j++ )
00277                                 {
00278                                         if ( (argv[a][j]>='1') && (argv[a][j]<='4') )
00279                                         {
00280                                                 muteVal |= (1 << argv[a][j]-'1');
00281                                         }
00282                                 }
00283                                 myEmuConfig.volumeControl = SIDEMU_VOLCONTROL;
00284                         }
00285                         else if ( strncasecmp( &argv[a][1], "n", 1 ) == 0 )
00286                         {
00287                                 myEmuConfig.clockSpeed = SIDTUNE_CLOCK_NTSC;
00288                                 myEmuConfig.forceSongSpeed = true;
00289                         }
00290                         else if ( strncasecmp( &argv[a][1], "o", 1 ) == 0 )
00291                         {
00292                                 selectedSong = atoi(argv[a]+2);
00293                         }
00294                         else if ( strncasecmp( &argv[a][1], "t", 1 ) == 0 )
00295                         {
00296                                 seconds = atoi(argv[a]+2);
00297                         }
00298                         else if ( strncasecmp( &argv[a][1], "ss", 2 ) == 0 )
00299                         {
00300                                 myEmuConfig.channels = SIDEMU_STEREO;
00301                                 myEmuConfig.volumeControl = SIDEMU_STEREOSURROUND;
00302                         }
00303                         else if ( strncasecmp( &argv[a][1], "s", 1 ) == 0 )
00304                         {
00305                                 myEmuConfig.channels = SIDEMU_STEREO;
00306                         }
00307                         else if ( strncasecmp( &argv[a][1], "u", 1 ) == 0 )
00308                         {
00309                                 flags |= FLAG_ULAW;
00310                         }
00311                         else if ( strncasecmp( &argv[a][1], "16", 2 ) == 0 )
00312                         {
00313                                 myEmuConfig.bitsPerSample = SIDEMU_16BIT;
00314                         }
00315                         else  
00316                         {
00317                                 printtext(ERR_SYNTAX);
00318                         }
00319                 }
00320                 else
00321                 {
00322                         // Set filename argument number.
00323                         if ( infile == 0 )
00324                         {
00325                                 infile = a;
00326                         }
00327                         else if ( outfile == 0 )
00328                         {
00329                                 outfile = a;
00330                         }
00331                         else
00332                         {
00333                                 printtext(ERR_SYNTAX);
00334                         }
00335                 }
00336         }
00337         
00338         if ( infile == 0 )
00339         {
00340                 printtext(ERR_SYNTAX); 
00341         }
00342 
00343         //
00344         
00345         if (flags & FLAG_ULAW)
00346         {
00347                 myEmuConfig.frequency = 8000;          // 8000 or 8012??
00348                 myEmuConfig.channels = SIDEMU_MONO;
00349                 myEmuConfig.bitsPerSample = SIDEMU_16BIT;
00350         }
00351         if (myEmuConfig.bitsPerSample == SIDEMU_16BIT)
00352         {
00353                 fadeout_buffer = fadeout_buffer_16;
00354                 fadein_buffer = fadein_buffer_16;
00355         }
00356 
00357 #ifdef __MSDOS__  
00358         char outpathname[MAXPATH];
00359         if ( outfile == 0 )
00360         {
00361                 char indrive[MAXDRIVE], inpath[MAXDIR], inname[MAXFILE], inext[MAXEXT];
00362                 fnsplit(argv[infile], indrive, inpath, inname, inext);
00363                 fnmerge(outpathname, indrive, inpath, inname, ".wav");
00364         }
00365         else
00366         {
00367                 strcpy(outpathname, argv[outfile]);
00368         }
00369 #else
00370         char* outpathname;
00371         if ( outfile == 0 )
00372         {
00373                 outpathname = new char[ strlen(argv[infile]) +4 +1];
00374                 strcpy( outpathname, argv[infile] );
00375                 if ( flags & FLAG_ULAW )
00376                 {
00377                         strcat( outpathname, ".au" );
00378                 }
00379                 else
00380                 {
00381                         strcat( outpathname, ".wav" );
00382                 }
00383         }
00384         else
00385         {
00386                 if (( outpathname = strdup( argv[outfile] )) == 0 )
00387                 {
00388                         printtext(ERR_NOT_ENOUGH_MEMORY);
00389                 }
00390         }
00391 #endif
00392 
00393         // Create the sidtune object.
00394         sidTune myTune( argv[infile] );
00395         struct sidTuneInfo mySidInfo;
00396         myTune.returnInfo( mySidInfo );
00397         if ( !myTune )  
00398         {
00399                 cerr << mySidInfo.statusString << endl;
00400                 exit(EXIT_ERROR_STATUS);
00401         }
00402         else
00403         {
00404                 cout << "File format  : " << mySidInfo.formatString << endl;
00405                 cout << "Condition    : " << mySidInfo.statusString << endl;
00406                 if ( mySidInfo.numberOfInfoStrings == 3 )
00407                 {
00408                         cout << "Name         : " << mySidInfo.nameString << endl;
00409                         cout << "Author       : " << mySidInfo.authorString << endl;
00410                         cout << "Copyright    : " << mySidInfo.copyrightString << endl;
00411                 }
00412                 else
00413                 {
00414                         for ( int infoi = 0; infoi < mySidInfo.numberOfInfoStrings; infoi++ )
00415                         {
00416                                 cout << "Description  : " << mySidInfo.infoString[infoi] << endl;
00417                         }
00418                 }
00419                 cout << "Load address : $" << hex << setw(4) << setfill('0') 
00420                         << mySidInfo.loadAddr << endl;
00421                 cout << "Init address : $" << hex << setw(4) << setfill('0') 
00422                         << mySidInfo.initAddr << endl;
00423                 cout << "Play address : $" << hex << setw(4) << setfill('0') 
00424                         << mySidInfo.playAddr << dec << endl;
00425         }
00426         
00427         // Alter the SIDPLAY Emulator Engine settings.
00428         myEmuConfig.sampleFormat = (myEmuConfig.bitsPerSample == SIDEMU_16BIT) ?  SIDEMU_SIGNED_PCM : SIDEMU_UNSIGNED_PCM;
00429         myEmuEngine.setConfig(myEmuConfig);
00430         // Here mute the voices, if requested.
00431         if (myEmuConfig.volumeControl == SIDEMU_VOLCONTROL)
00432         {
00433                 for ( int voice = 1; voice <= 4; voice++ )
00434                 {
00435                         if ( (muteVal & (1<<(voice-1))) != 0 )
00436                         {
00437                                 myEmuEngine.setVoiceVolume(voice,0,0,0);
00438                         }
00439                 }
00440         }
00441         // Get the current settings. We ignore the return value, because this code is
00442         // supposed to allow only valid settings.
00443         myEmuEngine.returnConfig(myEmuConfig);
00444     // Print the relevant settings.
00445         cout << "SID Filter   : " << ((myEmuConfig.emulateFilter == true) ? "Yes" : "No") << endl;
00446         if (myEmuConfig.memoryMode == MPU_PLAYSID_ENVIRONMENT)
00447         {
00448                 cout << "Memory mode  : PlaySID (this is supposed to fix PlaySID-specific rips)" << endl;
00449         }
00450         else if (myEmuConfig.memoryMode == MPU_TRANSPARENT_ROM)
00451         {
00452                 cout << "Memory mode  : Transparent ROM (SIDPLAY default)" << endl;
00453         }
00454         else if (myEmuConfig.memoryMode == MPU_BANK_SWITCHING)
00455         {
00456                 cout << "Memory mode  : Bank Switching" << endl;
00457         }
00458     cout << "Frequency    : " << dec << myEmuConfig.frequency << " Hz" << endl;
00459         cout << "Bits/sample  : ";
00460         if (flags & FLAG_ULAW)
00461         {
00462                 cout << "8 (u-law)" << endl;
00463         }
00464         else
00465         {
00466             cout << dec << myEmuConfig.bitsPerSample << endl;
00467         }
00468         cout << "Channels     : " << ((myEmuConfig.channels == SIDEMU_MONO) ? "Mono" : "Stereo") << endl;
00469   
00470         myTune.setInfo( mySidInfo );
00471 
00472         if ( !sidEmuInitializeSong(myEmuEngine,myTune,selectedSong) )
00473         {
00474                 cerr << "ERROR: SID Emulator Engine components not ready" << endl;
00475                 exit(EXIT_ERROR_STATUS);
00476         }
00477         myTune.returnInfo( mySidInfo );
00478         if ( !myTune )
00479         {
00480                 cerr << mySidInfo.statusString;
00481                 exit(EXIT_ERROR_STATUS);
00482         }
00483         cout << "Setting song : " << mySidInfo.currentSong
00484                 << " out of " << mySidInfo.songs
00485                 << " (default = " << mySidInfo.startSong << ')' << endl;
00486         cout << "Song speed   : " << mySidInfo.speedString << endl;
00487 
00488         cout << "WAV length   : " << seconds << " second";
00489         if ( seconds > 1 )
00490         {
00491                 cout << 's';
00492         }
00493         cout << endl;
00494 
00495         // Open output file stream.
00496         ofstream tofile( outpathname, ios::out | ios::bin | ios::trunc | ios::noreplace );
00497         if ( !tofile )
00498         {
00499                 cerr << "ERROR: Cannot create output file " << "'" << outpathname << "', "
00500                         << "probably already exits" << endl;
00501                 exit(EXIT_ERROR_STATUS);
00502         }
00503         cout << "Output file  : " << outpathname << endl;
00504 
00505         udword samplebuffersize;
00506         udword datalength;
00507         uword  headersize;
00508         
00509         if (flags & FLAG_ULAW)
00510         {
00511                 datalength = seconds * myEmuConfig.frequency;
00512 #if defined(IS_LITTLE_ENDIAN)
00513                 my_au_hdr.length = convertEndianess (datalength);
00514 #else
00515                 my_au_hdr.length = datalength;
00516 #endif
00517                 samplebuffersize = myEmuConfig.frequency * 2;
00518                 headersize = sizeof(au_hdr);
00519                 tofile.write( &my_au_hdr, headersize );
00520         }
00521         else
00522         {
00523                 udword bytesPerSample = myEmuConfig.channels*myEmuConfig.bitsPerSample/8;
00524                 udword bytesPerSecond = myEmuConfig.frequency*bytesPerSample;
00525                 datalength = seconds * bytesPerSecond;
00526                 samplebuffersize = bytesPerSecond;
00527                 headersize = sizeof(wav_hdr);
00528 #if defined (IS_LITTLE_ENDIAN)
00529                 my_wav_hdr.bitspersmpl = myEmuConfig.bitsPerSample;
00530                 my_wav_hdr.bytespersmpl = bytesPerSample;
00531                 my_wav_hdr.samplefreq = myEmuConfig.frequency;
00532                 my_wav_hdr.modus = myEmuConfig.channels;
00533                 my_wav_hdr.bytespersec = bytesPerSecond;
00534                 my_wav_hdr.length = datalength + headersize - 8;
00535                 my_wav_hdr.data_length = datalength;
00536 #else    
00537                 my_wav_hdr.bitspersmpl = convertEndianess ((uword)myEmuConfig.bitsPerSample);
00538                 my_wav_hdr.bytespersmpl = convertEndianess ((uword)bytesPerSample);
00539                 my_wav_hdr.samplefreq = convertEndianess (myEmuConfig.frequency);
00540                 my_wav_hdr.modus = convertEndianess ((uword)myEmuConfig.channels);
00541                 my_wav_hdr.bytespersec = convertEndianess ((udword)bytesPerSecond);
00542                 my_wav_hdr.length = convertEndianess (datalength + headersize - 8);
00543                 my_wav_hdr.data_length = convertEndianess (datalength);
00544 #endif    
00545                 tofile.write( &my_wav_hdr, headersize );
00546         }
00547   
00548         // Make a buffer that holds 1 second of audio data.
00549         ubyte* samplebuffer = new ubyte[samplebuffersize];
00550         if ( samplebuffer == 0 )
00551         {
00552                 printtext(ERR_NOT_ENOUGH_MEMORY);
00553         }
00554         
00555         // Calculate fadein and -out variables.
00556         if ( seconds == 0 )
00557         {
00558                 seconds = 60; // force the default
00559         }
00560         if ( seconds < fadein_seconds )
00561         {
00562                 fadein_seconds = seconds /2;
00563         }
00564         if ( seconds < fadeout_seconds )
00565         {
00566                 fadeout_seconds = seconds /2;
00567         }
00568         if (( fadein_seconds + fadeout_seconds  ) > seconds )
00569         {
00570                 fadein_seconds = 0;
00571                 fadeout_seconds = 0;
00572         }
00573         fadein_currentlevel = 0;
00574         fadelevel = ( fadeout_currentlevel = 128 );
00575         fadein_step = ( fadein_seconds * samplebuffersize / (myEmuConfig.bitsPerSample/8) ) / fadelevel;
00576         fadeout_step = ( fadeout_seconds * samplebuffersize / (myEmuConfig.bitsPerSample/8) ) / fadelevel;
00577         fadeout_count = ( fadein_count = 0 );
00578 
00579         cout << endl;
00580         cout << "Generating sample data...don't interrupt !" << endl;
00581         
00582         if (beginSeconds > 0)
00583                 cout << "Skipping seconds : ";
00584         int skipped = 0;
00585         while (skipped < beginSeconds)
00586         {
00587                 sidEmuFillBuffer( myEmuEngine, myTune, samplebuffer, samplebuffersize );
00588                 skipped++;
00589                 // Print progress report.
00590                 cout << setw(5) << setfill(' ') << skipped << "\b\b\b\b\b" << flush;
00591         };
00592         if (beginSeconds > 0)
00593                 cout << endl;
00594         
00595         cout << "Length of output file (bytes) : ";
00596 
00597         datalength = 0;
00598 
00599         for ( int sec = 0; sec < seconds; sec++ )
00600         {
00601                 sidEmuFillBuffer( myEmuEngine, myTune, samplebuffer, samplebuffersize );
00602                 if ( sec < ( fadein_seconds ))
00603                         (*fadein_buffer)( samplebuffer, samplebuffersize );
00604                 if ( sec >= ( seconds - fadeout_seconds ))
00605                         (*fadeout_buffer)( samplebuffer, samplebuffersize );
00606                 if (flags & FLAG_ULAW)
00607                 {
00608                         buffer2ulaw(samplebuffer, samplebuffersize);
00609                         tofile.write( samplebuffer, samplebuffersize / 2 );
00610                 } 
00611                 else
00612                 {
00613 #if defined(IS_BIG_ENDIAN)
00614                         if (myEmuConfig.bitsPerSample == SIDEMU_16BIT)
00615                         {
00616                                 endianswitch_buffer( samplebuffer, samplebuffersize );
00617                         }
00618 #endif
00619                         tofile.write( samplebuffer, samplebuffersize );
00620                 }
00621           
00622                 // Print progress report.
00623                 cout << setw(10) << setfill(' ') << ( datalength + headersize) << "\b\b\b\b\b\b\b\b\b\b" << flush;
00624         
00625                 if (flags & FLAG_ULAW)
00626                         datalength += samplebuffersize / 2;
00627                 else
00628                         datalength += samplebuffersize;
00629         }
00630         // Finish progress report.
00631         cout << setw(10) << setfill(' ') << ( datalength + headersize) << endl;
00632         tofile.close();
00633         delete[] outpathname;
00634         delete[] samplebuffer;
00635 
00636         cout << endl << "Please do not forget to give the credits whenever using a waveform created" << endl
00637                 << "by this application !" << endl << endl;
00638 
00639         return 0;
00640 }
00641 
00642 
00643 void fadeout_buffer_8( ubyte* samplebuffer, udword samplebuffersize )
00644 {
00645         for ( udword i = 0; i < samplebuffersize; i++ )
00646     {
00647                 sbyte sam = (sbyte)( 0x80 ^ *(samplebuffer +i));
00648                 sword modsam = sam * fadeout_currentlevel;
00649                 modsam /= fadelevel;
00650                 sam = (sbyte)modsam;
00651                 *(samplebuffer +i) = 0x80 ^ sam;
00652                 
00653                 fadeout_count++;
00654                 if ( fadeout_count >= fadeout_step )
00655                 {
00656                         if ( fadeout_currentlevel > 0 )
00657                         {
00658                                 fadeout_currentlevel--;
00659                         }
00660                         fadeout_count = 0;
00661                 }
00662         }
00663 }
00664 
00665 void fadeout_buffer_16( ubyte* samplebuffer, udword samplebuffersize )
00666 {
00667         sword *buf = (sword *)samplebuffer;
00668         samplebuffersize /= 2;
00669         for ( udword i = 0; i < samplebuffersize; i++ )
00670         {
00671                 sword sam = *(buf +i);
00672                 sdword modsam = sam * fadeout_currentlevel;
00673                 modsam /= fadelevel;
00674                 sam = (sword)modsam;
00675                 *(buf +i) = sam;
00676                 
00677                 fadeout_count++;
00678                 if ( fadeout_count >= fadeout_step )
00679                 {
00680                         if ( fadeout_currentlevel > 0 )
00681                         {
00682                                 fadeout_currentlevel--;
00683                         }
00684                         fadeout_count = 0;
00685                 }
00686         }
00687 }
00688 
00689 void fadein_buffer_8( ubyte* samplebuffer, udword samplebuffersize )
00690 {
00691         for ( udword i = 0; i < samplebuffersize; i++ )
00692         {
00693                 sbyte sam = (sbyte)( 0x80 ^ *(samplebuffer +i));
00694                 sword modsam = sam * fadein_currentlevel;
00695                 modsam /= fadelevel;
00696                 sam = (sbyte)modsam;
00697                 *(samplebuffer +i) = 0x80 ^ sam;
00698                 
00699                 fadein_count++;
00700                 if ( fadein_count >= fadein_step )
00701                 {
00702                         if ( fadein_currentlevel < fadelevel )
00703                         {
00704                                 fadein_currentlevel++;
00705                         }
00706                         fadein_count = 0;
00707                 }
00708         }
00709 }
00710 
00711 void fadein_buffer_16( ubyte* samplebuffer, udword samplebuffersize )
00712 {
00713         sword *buf = (sword *)samplebuffer;
00714         samplebuffersize /= 2;
00715         for ( udword i = 0; i < samplebuffersize; i++ )
00716         {
00717                 sword sam = *(buf +i);
00718                 sdword modsam = sam * fadein_currentlevel;
00719                 modsam /= fadelevel;
00720                 sam = (sword)modsam;
00721                 *(buf +i) = sam;
00722                 
00723                 fadein_count++;
00724                 if ( fadein_count >= fadein_step )
00725                 {
00726                         if ( fadein_currentlevel < fadelevel )
00727                         {
00728                                 fadein_currentlevel++;
00729                         }
00730                         fadein_count = 0;
00731                 }
00732         }
00733 }
00734 
00735 void error(char* s1, char* s2 = "")
00736 {
00737         cerr << "ERROR: " << s1 << ' ' << "'" << s2 << "'" << endl;
00738         exit(EXIT_ERROR_STATUS);
00739 }
00740 
00741 
00742 void printtext(int number)
00743 {
00744         switch (number)  
00745         {
00746          case TXT_TITLE:
00747                 {
00748                         cout << "SID2WAV   Synthetic Waveform Generator   " << "Portable Version " << s2w_version << "/" << emu_version << endl
00749                                 << "Copyright (c) 1994-97   All rights reserved." << endl
00750                                 << "Authors: Michael Schwendt <sidplay@geocities.com>" << endl
00751                                 << "         Adam Lorentzon   <d93-alo@nada.kth.se>" << endl
00752 #if defined(__amigaos__)
00753                                 << "AmigaOS port: <phillwooller@geocities.com>" << endl
00754 #endif
00755                                 << endl;
00756                         break;
00757                 }
00758          case ERR_ENDIANESS:
00759                 {
00760                         cerr << "ERROR: Hardware endianess improperly configured." << endl;
00761                         exit(EXIT_ERROR_STATUS);
00762                         break;
00763                 }
00764          case ERR_ENGINE:  // currently the only reason the engine would fail
00765          case ERR_NOT_ENOUGH_MEMORY:
00766                 {
00767                         cerr << "ERROR: Not enough memory" << endl;
00768                         exit(EXIT_ERROR_STATUS);
00769                         break;
00770                 }
00771          case ERR_SYNTAX:
00772                 {
00773 #ifdef __MSDOS__
00774                         cout << " syntax: sid2wav [-<commands>] <datafile> [outputfile]" << endl
00775 #else
00776                         cout << " syntax: sid2wav [-<commands>] <datafile>|- [outputfile]" << endl
00777 #endif
00778                                 << " commands: -h         display this screen" << endl
00779                                 << "           -f<num>    set frequency in Hz (default: 22050)" << endl
00780                                 << "           -16        16-bit (default: 8-bit)" << endl
00781                                 << "           -s         stereo (default: mono)" << endl
00782                                 << "           -ss        enable stereo surround" << endl
00783                                 << "           -u         au output (8000Hz mono 8-bit u-law)" << endl
00784                                 << "           -o<num>    set song number (default: preset)" << endl
00785                                 << "           -a         improve PlaySID compatibility (not recommended)" << endl
00786                                 << "           -a2        bank switching mode (overrides -a)" << endl
00787                                 << "           -nf        no SID filter emulation" << endl
00788                                 << "           -n         enable NTSC-clock speed for VBI tunes (not recommended)" << endl
00789                                 << "           -m<num>    mute voices out of 1,2,3,4 (default: none)" << endl
00790                                 << "                      example: -m13 (voice 1 and 3 off)" << endl
00791                                 << "           -t<num>    set seconds to play (default: 60)" << endl
00792                                 << "           -b<num>    begin <num> seconds into the song (default: 0)" << endl
00793                                 << "           -fin<num>  fade-in-time in seconds (default: 0)" << endl
00794                                 << "           -fout<num> fade-out-time in seconds (default: 2)" << endl
00795                                 << endl;
00796                         exit(EXIT_ERROR_STATUS);
00797                         break;
00798                 }
00799          default:
00800                 {
00801                         cerr << "ERROR: Internal system error" << endl;
00802                         exit(EXIT_ERROR_STATUS);
00803                         break;
00804                 }
00805         }
00806 }
00807 
00808 
00809 
00810 
00811 
00812 
00813 
00814 
00815 
00816 
00817 
00818 
00819 
00820 
00821 
00822 // ------------ Beginning of code 'borrowed' from tracker 4.43 by Marc Espie.
00823 
00824 // The only modifications to the code were a few changes from C style
00825 // to C++ style to please the compiler.
00826 
00827 
00828 short seg_end[8] = 
00829 {
00830         0xFF, 0x1FF, 0x3FF, 0x7FF,
00831         0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
00832 };
00833 
00834 int search(int val, short *table, int size)
00835 {
00836         int     i;
00837         
00838         for (i = 0; i < size; i++) 
00839         {
00840                 if (val <= *table++)
00841                 {
00842                         return i;
00843                 }
00844         }
00845         return size;
00846 }
00847 
00848 const int BIAS = 0x84;              // Bias for linear code.
00849 
00850 // linear2ulaw() - Convert a linear PCM value to u-law
00851 //
00852 // In order to simplify the encoding process, the original linear magnitude
00853 // is biased by adding 33 which shifts the encoding range from (0 - 8158) to
00854 // (33 - 8191). The result can be seen in the following encoding table:
00855 //
00856 //      Biased Linear Input Code        Compressed Code
00857 //      ------------------------        ---------------
00858 //      00000001wxyza                   000wxyz
00859 //      0000001wxyzab                   001wxyz
00860 //      000001wxyzabc                   010wxyz
00861 //      00001wxyzabcd                   011wxyz
00862 //      0001wxyzabcde                   100wxyz
00863 //      001wxyzabcdef                   101wxyz
00864 //      01wxyzabcdefg                   110wxyz
00865 //      1wxyzabcdefgh                   111wxyz
00866 //
00867 // Each biased linear code has a leading 1 which identifies the segment
00868 // number. The value of the segment number is equal to 7 minus the number
00869 // of leading 0's. The quantization interval is directly available as the
00870 // four bits wxyz. // The trailing bits (a - h) are ignored.
00871 //
00872 // Ordinarily the complement of the resulting code word is used for
00873 // transmission, and so the code word is complemented before it is returned.
00874 //
00875 // For further information see John C. Bellamy's Digital Telephony, 1982,
00876 // John Wiley & Sons, pps 98-111 and 472-476.
00877 
00878 unsigned char linear2ulaw(int pcm_val)
00879 // int pcm_val; // 2's complement (16-bit range)
00880 {
00881         int     mask;
00882         int     seg;
00883         unsigned char uval;
00884         
00885         // Get the sign and the magnitude of the value.
00886         if (pcm_val < 0) 
00887     {
00888                 pcm_val = BIAS - pcm_val;
00889                 mask = 0x7F;
00890     }
00891         else 
00892     {
00893                 pcm_val += BIAS;
00894                 mask = 0xFF;
00895     }
00896   
00897         // Convert the scaled magnitude to segment number.
00898         seg = search(pcm_val, seg_end, 8);
00899   
00900         // Combine the sign, segment, quantization bits;
00901         // and complement the code word.
00902 
00903         if (seg >= 8)           // out of range, return maximum value.
00904         {
00905                 return 0x7F ^ mask;
00906         }
00907         else
00908         {
00909                 uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
00910                 return uval ^ mask;
00911         }
00912 }
00913 
00914 //
00915 // ------------------- End of code 'borrowed' from tracker 4.43 by Marc Espie
00916 
00917 
00918 
00919 
00920 
00921 
00922 
00923 
00924 
00925 
00926 
00927 
00928 
00929 //
00930 // Assume incoming data is 16-bit signed values.
00931 // Samplebuffersize is the size in bytes of the buffer samplebuffer
00932 //
00933 void buffer2ulaw( ubyte* samplebuffer, udword samplebuffersize )
00934 {
00935         sword *wordbuffer = (sword *) samplebuffer;
00936         udword numsamples = samplebuffersize / 2;
00937         for (udword i = 0; i < numsamples; i++)
00938         {
00939                 samplebuffer[i] = linear2ulaw ((~wordbuffer[i]) + 1);  // two's complement
00940         }
00941 }
00942 
00943 
00944 //
00945 // Incoming data is 16-bit values which needs an endian-switch
00946 // Samplebuffersize is the size in bytes of the buffer samplebuffer
00947 //
00948 void endianswitch_buffer( ubyte* samplebuffer, udword samplebuffersize )
00949 {
00950         uword *wordbuffer = (uword *) samplebuffer;
00951         udword numsamples = samplebuffersize / 2;
00952         for (udword i = 0; i < numsamples; i++)
00953         {
00954                 wordbuffer[i] = convertEndianess (wordbuffer[i]);
00955         }
00956 }

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