riptracks.c
上传用户:xmgzy123
上传日期:2007-01-07
资源大小:373k
文件大小:26k
源码类别:

SCSI/ASPI

开发平台:

WINDOWS

  1. /*
  2.  * riptracks.c - Copyright (C) 1999,2000 Jay A. Key
  3.  *
  4.  * Contains the RipTrack() function.  The rip dialog proc, plus the
  5.  * read and encode threads are all contained in this file.  The read 
  6.  * thread is also responsible for jitter correction.  A good example of 
  7.  * how to rip a track from a CD via AKRip32.dll
  8.  *
  9.  **********************************************************************
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24.  *
  25.  */
  26. #include <windows.h>
  27. #include <stdio.h>
  28. #include <time.h>
  29. #include <malloc.h>
  30. #include "akrip/akrip32.h"
  31. #include "resources.h"
  32. #include "globals.h"
  33. #include "riptracks.h"
  34. #include "trackwnd.h"
  35. #include "bladedll.h"
  36. #include "gauge.h"
  37. #include "id3.h"
  38. #define _USE_LAME  0
  39. DWORD RipThread( LPENCODETHREAD pet );
  40. DWORD EncodeThread( LPENCODETHREAD pet );
  41. LPTRACKBUF newTrackBuf( DWORD numFrames );
  42. void RipTrack( HWND hDlg, int idx, LPADDTRACK lpAddTrack );
  43. int writeAndFlush( FILE *fp, BYTE *buf, int len );
  44. void writeWavHeader( FILE *fp, DWORD len );
  45. BOOL loadBladeEnc( void );
  46. void setRipTrackStatus( LPENCODETHREAD e );
  47. BOOL LoadEncoderFunctions( ENCODER nEncoder );
  48. void UpdateTime (long numWritten);
  49. BOOL isOldLameEnc( void );
  50. static ENCODETHREAD e;
  51. static ADDTRACK rtAddTrack;
  52. //static BOOL bSecond = FALSE;
  53. /*
  54.  * 1. initializes the common data structure
  55.  * 2. starts the threads
  56.  * 
  57.  * 
  58.  */
  59. void RipTrack( HWND hDlg, int idx, LPADDTRACK lpAddTrack )
  60. {
  61.   DWORD dwRipThreadID, dwEncThreadID;
  62.   static DWORD numBufFrames = 8;
  63.   static char outputName[MAX_PATH+1];
  64.   int iDirLen;                      // iNameLen, iTotal;
  65.   char *p;
  66.   ZeroMemory( &e, sizeof(e) );
  67.   e.idx = idx;
  68.   time( &e.tstart );
  69.   e.hDlg = hDlg;
  70.   wsprintf( outputName, "%s.%s", lpAddTrack->name,  bMP3?"mp3":"wav" );
  71.   SetDlgItemText( hDlg, IDT_TRACKNAME, outputName );
  72.   // we really need to check filename lengths here, but I'm just too damn
  73.   // tired right now
  74.   iDirLen = lstrlen( szMP3OutputDir );
  75.   //iNameLen = lstrlen( lpAddTrack->name );
  76.   //iTotal = iDirLen + iNameLen + 5;
  77.   if ( bMP3 )
  78.     lstrcpy( outputName, szMP3OutputDir );
  79.   else
  80.     lstrcpy( outputName, szWavOutputDir );
  81.   iDirLen = lstrlen( outputName );
  82.   if ( !iDirLen )
  83.     lstrcpy( outputName, ".\" );
  84.   if ( iDirLen && outputName[iDirLen-1] != '\' )
  85.     lstrcat( outputName, "\" );
  86.   // add the track name, and then replace illegal characters with a '_'
  87.   p = outputName + lstrlen( outputName );
  88.   lstrcat( outputName, lpAddTrack->name );
  89.   while( *p )
  90.     {
  91.       if ( !validFnameChar[(unsigned char)*p] )
  92. *p = '_';
  93.       p++;
  94.     }
  95.   // add the proper extension
  96.   p = outputName + lstrlen( outputName );
  97.   lstrcat( outputName, bMP3?".mp3":".wav" );
  98.   e.fpOut = fopen( outputName, "w+b" );
  99.   if ( !bMP3 )
  100.     writeWavHeader( e.fpOut, 0 );
  101.   if ( bMP3 && bWavMirror )
  102.     {
  103.       // change the extension to WAV (p was set to the terminating NULL)
  104.       lstrcpy( p, ".wav" );
  105.       e.fpWavMirror = fopen( outputName, "wb" );
  106.       writeWavHeader( e.fpWavMirror, 0 );
  107.     }
  108.   else
  109.     e.fpWavMirror = NULL;
  110.   if ( bMP3 )
  111.     {
  112.       switch( iEncoder )
  113. {
  114. case BLADE_ENC_DLL:
  115.   wsprintf( outputName, "%d kbps MP3 via BladeEnc DLL", wBitrate );
  116.   break;
  117. case LAME_ENC_DLL:
  118.   if ( isOldLameEnc() )
  119.     {
  120.       e.bOldLame = TRUE;
  121.     }
  122.   wsprintf( outputName, "%d kbps MP3 via Lame_Enc DLL", wBitrate );
  123.   if ( bVBR && !e.bOldLame )
  124.     wsprintf( outputName+lstrlen(outputName),
  125.       ", VBR max bitrate %d, VBR quality %d", wMaxBitrate,
  126.       nVBRQuality );
  127.   break;
  128. }
  129.     }
  130.   else
  131.     wsprintf( outputName, "WAV file" );
  132.   SetDlgItemText( hDlg, IDT_OUTPUTOPTTEXT, outputName );
  133.   ModifyCDParms( hCD, CDP_OVERLAP, numOverlap );
  134.   ModifyCDParms( hCD, CDP_JITTER, jitterCheck );
  135.   ModifyCDParms( hCD, CDP_READMODE, readMode );
  136.   e.startFrame = lpAddTrack->start;
  137.   e.trackLen = lpAddTrack->len;
  138.   e.endFrame = e.startFrame + e.trackLen;
  139.   InitializeCriticalSection( &e.cs );
  140.   e.hRipCancel = CreateEvent( NULL, FALSE, FALSE, NULL );
  141.   SendDlgItemMessage( hDlg, IDG_RIPPROG, GM_SETRANGE,
  142.       (WPARAM)((UINT)e.trackLen * 2352),
  143.       0L );
  144.   SendDlgItemMessage( hDlg, IDG_RIPPROG, GM_SETPOS, 0, 0L );
  145.   wrqInitQueue( &e.q, maxRip * 2352 * numBufFrames );
  146.   SendDlgItemMessage( hDlg, IDG_READBUF, GM_DISPPCT, (WPARAM)FALSE, 0L );
  147.   SendDlgItemMessage( hDlg, IDG_READBUF, GM_SETRANGE,
  148.       (WPARAM)wrqFreeSpace( &e.q ), 0L );
  149.   // Set ID3 info for track.  Album title and artist are set elsewhere
  150.   asSetID3Info( ID3_TITLE, lpAddTrack->name, 0 );
  151.   asSetID3Info( ID3_LEVEL, NULL, 1 );
  152. #if 0
  153.   asSetID3Info( ID3_YEAR, "1997", 0 );
  154.   asSetID3Info( ID3_GENRE, NULL, 17 );
  155. #endif
  156.   
  157.   e.aHandles[0] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)RipThread,
  158. (LPVOID)&e, 0, &dwRipThreadID );
  159.   e.aHandles[1] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)EncodeThread,
  160. (LPVOID)&e, 0, &dwEncThreadID );
  161. }
  162. BOOL RipTrackDlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  163. {
  164.   WORD wID;
  165.   //static BOOL bDone = FALSE;
  166.   static HWND hTrckWnd = NULL;
  167.   int idx = -1;
  168.   switch( uMsg )
  169.     {
  170.     case WM_DESTROY:
  171.       bRippingTracks = FALSE;
  172.       EndDialog( hWnd, 0 );
  173.       break;
  174.     case WM_TRACKDONE:
  175.       //bSecond = TRUE;
  176.       DeleteCriticalSection( &e.cs );
  177.       //CloseHandle( &e.hRipCancel );
  178.       wrqDeinitQueue( &e.q );
  179.       // set the status text for the last track ripped
  180.       setRipTrackStatus( &e );
  181.       // if more tracks to rip and the last one finished successfully,
  182.       // call RipTrack again
  183.       idx = SendMessage( hTrckWnd,WM_FINDNEXTTRACK,0,(LPARAM)&rtAddTrack);
  184.       if ( (idx != -1) && (e.status == EST_SUCCESS) )
  185. RipTrack( hWnd, idx, &rtAddTrack );
  186.       else
  187. {
  188.   bRippingTracks = FALSE;
  189.   EndDialog( hWnd, 0 );
  190. }
  191.       break;
  192.     case WM_INITDIALOG:
  193.       //bDone = FALSE;
  194.       //bSecond = FALSE;
  195.       hTrckWnd = (HWND)lParam;
  196.       bRippingTracks = TRUE;
  197.       idx = SendMessage(hTrckWnd,WM_FINDFIRSTTRACK,0,
  198.        (LPARAM)&rtAddTrack);
  199.       if ( idx != -1 )
  200. {
  201.   RipTrack( hWnd, idx, &rtAddTrack );
  202. }
  203.       else
  204. {
  205.   MessageBox( GetParent(hTrckWnd), "No tracks selected", "Warning!",
  206.       MB_ICONEXCLAMATION | MB_OK );
  207.   bRippingTracks = FALSE;
  208.   EndDialog( hWnd, 0 );
  209. }
  210.       break;
  211.     case WM_COMMAND:
  212.       wID = LOWORD( wParam );
  213.       if ( wID == IDBN_CANCELRIP || wID == 2 )
  214. {
  215.   if ( /* bDone || */ (MessageBox( hWnd, "Really stop?", "Abort?", MB_APPLMODAL | MB_YESNO | MB_ICONEXCLAMATION ) == IDYES) )
  216.     {
  217.       e.bForceRipExit = TRUE;
  218.       e.status = EST_ABORTED;
  219.       SetEvent( e.hRipCancel );
  220.       EnableWindow( GetDlgItem( hWnd, IDBN_CANCELRIP ),FALSE );
  221.     }
  222. }
  223.       return TRUE;
  224.     }
  225.   return FALSE;
  226. }
  227. BOOL RipTrackSegmentDlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  228. {
  229.   WORD wID;
  230.   switch( uMsg )
  231.     {
  232.     case WM_DESTROY:
  233.       bRippingTracks = FALSE;
  234.       EndDialog( hWnd, 0 );
  235.       break;
  236.     case WM_TRACKDONE:
  237.       DeleteCriticalSection( &e.cs );
  238.       wrqDeinitQueue( &e.q );
  239.       if ( e.status != EST_SUCCESS )
  240. {
  241. }
  242.       bRippingTracks = FALSE;
  243.       EndDialog( hWnd, 0 );
  244.       break;
  245.     case WM_INITDIALOG:
  246.       bRippingTracks = TRUE;
  247.       RipTrack( hWnd, -1, (LPADDTRACK)lParam );
  248.       break;
  249.     case WM_COMMAND:
  250.       wID = LOWORD( wParam );
  251.       if ( wID == IDBN_CANCELRIP || wID == 2 )
  252. {
  253.   if ( MessageBox( hWnd, "Really stop?", "Abort?", MB_APPLMODAL | MB_YESNO | MB_ICONEXCLAMATION ) == IDYES )
  254.     {
  255.       e.bForceRipExit = TRUE;
  256.       e.status = EST_ABORTED;
  257.       SetEvent( e.hRipCancel );
  258.       EnableWindow( GetDlgItem( hWnd, IDBN_CANCELRIP ),FALSE );
  259.     }
  260. }
  261.       return TRUE;
  262.     }
  263.   return FALSE;
  264. }
  265. LPTRACKBUF newTrackBuf( DWORD numFrames )
  266. {
  267.   LPTRACKBUF t;
  268.   int numAlloc;
  269.   numAlloc = (((int)numFrames)*2352) + TRACKBUFEXTRA;
  270.   t = (LPTRACKBUF)malloc( numAlloc );
  271.   if ( !t )
  272.     return NULL;
  273.   t->startFrame = 0;
  274.   t->numFrames = 0;
  275.   t->maxLen = numFrames * 2352;
  276.   t->len = 0;
  277.   t->status = 0;
  278.   t->startOffset = 0;
  279.   return t;
  280. }
  281. //#define _ALWAYS_READ_MAX
  282. /*
  283.  * Thread responsible for reading the data from the CD and placing it in
  284.  * a queue for the encode thread.
  285.  *
  286.  * trying a new strategy -- always read the full maxRip frames, and truncate
  287.  * if it's too many, but after the read.  Some of the SCSI read modes were
  288.  * crapping out on the last read when I suddenly requested a different number
  289.  * of frames.  To switch back to the old method, undefine _ALWAYS_READ_MAX
  290.  *
  291.  * CDRM_JITTERONERR uses two full-size TRACKBUFs on a rotating basis.  On the
  292.  * read it uses t1, and then on the next read switches to t2.  If an error
  293.  * is returned from the read function, then the buffer from the previous read
  294.  * is used to jitter correct the current one.
  295.  */
  296. DWORD RipThread( LPENCODETHREAD pet )
  297. {
  298.   LPTRACKBUF tbuf, t1, t2, tover, tTmp;
  299.   DWORD num2rip, dwStatus;
  300.   HANDLE hWait[2];
  301.   int retries;
  302.   BOOL useT1 = FALSE;
  303.   HWND hReadGauge;
  304.   BOOL bWaited;
  305.   //char buf[81];
  306.   hWait[0] = CreateEvent( NULL, FALSE, FALSE, NULL ); 
  307.   hWait[1] = pet->hRipCancel;
  308.   // initialize all buffers
  309.   tbuf = t1 = t2 = tover = tTmp = NULL;
  310.   tbuf = t1 = newTrackBuf( maxRip );
  311.   switch ( readMode )
  312.     {
  313.     case CDRM_JITTER:
  314.       tover = newTrackBuf( numOverlap );
  315.       break;
  316.     case CDRM_JITTERONERR:
  317.       t2 = newTrackBuf( maxRip );
  318.       break;
  319.     default:
  320.     case CDRM_NOJITTER:
  321.       readMode = CDRM_NOJITTER;
  322.       break;
  323.     }
  324.   num2rip = maxRip;
  325.   hReadGauge = GetDlgItem( e.hDlg, IDG_READBUF );
  326.   while( TRUE )
  327.     {
  328.       bWaited = FALSE;
  329.       if ( e.startFrame >= e.endFrame )
  330. break;
  331.       if ( e.bForceRipExit )
  332. {
  333.   e.bForceEncExit = TRUE;
  334.   goto asRipExit;
  335. }
  336.       EnterCriticalSection( &e.cs );
  337.       if ( e.endFrame - e.startFrame < maxRip )
  338. num2rip = e.endFrame - e.startFrame;
  339.       LeaveCriticalSection( &e.cs );
  340.       while( wrqFreeSpace( &e.q ) < 2352 * num2rip )
  341. {
  342.   bWaited = TRUE;
  343.   if ( e.bForceRipExit )
  344.     {
  345.       e.bForceEncExit = TRUE;
  346.       goto asRipExit;
  347.     }
  348.   ResetEvent( hWait[0] );
  349.   wrqSetWait( &e.q, hWait[0], 2352 * maxRip * 6 );
  350.   //WaitForSingleObject( hWait, 20000 );
  351.   WaitForMultipleObjects( 2, hWait, FALSE, 60000 );
  352.   if ( e.bForceRipExit )
  353.     {
  354.       e.bForceEncExit = TRUE;
  355.       goto asRipExit;
  356.     }
  357. }
  358.       switch( readMode )
  359. {
  360. case CDRM_JITTER:
  361.   EnterCriticalSection( &e.cs );
  362.   tbuf->startFrame = e.startFrame;
  363.   LeaveCriticalSection( &e.cs );
  364. #ifndef _ALWAYS_READ_MAX
  365.   tbuf->numFrames = num2rip;
  366. #else
  367.   tbuf->numFrames = maxRip;
  368. #endif
  369.   tbuf->startOffset = 0;
  370.   tbuf->len = 0;
  371.   //retries = 3;
  372.   //dwStatus = SS_ERR;
  373.   for( dwStatus = SS_ERR, retries = 3; dwStatus != SS_COMP && retries; retries-- )
  374.     {
  375.       dwStatus = ReadCDAudioLBAEx( hCD, tbuf, tover );
  376.     }
  377.   break;
  378. case CDRM_JITTERONERR:
  379.   if ( useT1 )
  380.     {
  381.       tbuf = t1;
  382.       tTmp = t2;
  383.     }
  384.   else
  385.     {
  386.       tbuf = t2;
  387.       tTmp = t1;
  388.     }
  389.   EnterCriticalSection( &e.cs );
  390.   tbuf->startFrame = e.startFrame;
  391.   LeaveCriticalSection( &e.cs );
  392. #ifndef _ALWAYS_READ_MAX
  393.   tbuf->numFrames = num2rip;
  394. #else
  395.   tbuf->numFrames = maxRip;
  396. #endif
  397.   tbuf->startOffset = 0;
  398.   tbuf->len = 0;
  399.   // try to force jitter correction after a wait
  400.   if ( !bWaited )
  401.     dwStatus = ReadCDAudioLBA( hCD, tbuf );
  402.   else
  403.     dwStatus = SS_ERR;
  404.   // after an error or a wait, dwStatus will be SS_ERR
  405.   if ( dwStatus == SS_ERR )
  406.     {
  407.       if ( tTmp->len )
  408. {
  409.   tTmp->startOffset += ((tTmp->numFrames - jitterCheck)*2352);
  410.   tTmp->startFrame += ( tTmp->numFrames - jitterCheck );
  411.   tTmp->numFrames = jitterCheck;
  412.   tTmp->len = jitterCheck * 2352;
  413. }
  414.       else
  415. tTmp->len = tTmp->startOffset = tTmp->numFrames;
  416.       for( retries = 3; (dwStatus != SS_COMP) && retries; retries-- )
  417. {
  418.   dwStatus = ReadCDAudioLBAEx( hCD, tbuf, tTmp );
  419. }
  420.     }
  421.   useT1 = !useT1;
  422.   break;
  423. case CDRM_NOJITTER:
  424.   EnterCriticalSection( &e.cs );
  425.   tbuf->startFrame = e.startFrame;
  426.   LeaveCriticalSection( &e.cs );
  427. #ifndef _ALWAYS_READ_MAX
  428.   tbuf->numFrames = num2rip;
  429. #else
  430.   tbuf->numFrames = maxRip;
  431. #endif
  432.   tbuf->startOffset = 0;
  433.   tbuf->len = 0;
  434.   //dwStatus = SS_ERR;
  435.   //retries = 3;
  436.   for( retries = 3, dwStatus = SS_ERR; (dwStatus != SS_COMP) && retries; retries -- )
  437.     dwStatus = ReadCDAudioLBA( hCD, tbuf );
  438.   break;
  439. }
  440.       if ( dwStatus != SS_COMP )
  441. {
  442.   // display the error here
  443.           e.status = EST_ERROR;
  444.   e.bForceEncExit = TRUE;
  445.   goto asRipExit;
  446. }
  447.       
  448. #ifdef _ALWAYS_READ_MAX
  449.       if ( (maxRip > num2rip) && (tbuf->numFrames > num2rip) )
  450. {
  451.   tbuf->numFrames = num2rip;
  452.   tbuf->len = tbuf->numFrames * 2352;
  453. }
  454. #endif
  455.       wrqEnqueue( &e.q, tbuf->buf + tbuf->startOffset, tbuf->len );
  456. #if 0
  457.       SendDlgItemMessage( e.hDlg, IDG_READBUF, GM_SETPOS,
  458.   (WPARAM)wrqNumUsed( &e.q ), 0L );
  459. #else
  460.       PostMessage( hReadGauge, GM_SETPOS, (WPARAM)wrqNumUsed( &e.q ), 0L );
  461. #endif
  462.       EnterCriticalSection( &e.cs );
  463.       e.startFrame += tbuf->numFrames;
  464.       LeaveCriticalSection( &e.cs );
  465.     }
  466.   
  467.   e.bNormalExit = TRUE;
  468.   ResetEvent( hWait[0] );
  469.   wrqSetWait( &e.q, hWait[0], e.q.dataLen - 500 );
  470.   WaitForSingleObject( hWait[0], 5000 );
  471.  asRipExit:
  472.   if ( WaitForSingleObject( e.aHandles[1], 120000 ) == WAIT_TIMEOUT )
  473.     {
  474.       e.bForceEncExit = TRUE;
  475.       if ( WaitForSingleObject( e.aHandles[1], 30000 ) == WAIT_TIMEOUT )
  476. {
  477.   TerminateThread( e.aHandles[1], 0xDEADBEEF );
  478. }
  479.     }
  480.   free( t1 );
  481.   if ( t2 )
  482.     free( t2 );
  483.   if ( tover )
  484.     free( tover );
  485.   time( &e.tnow );
  486.   CloseHandle( hWait[0] );
  487.   CloseHandle( hWait[1] );
  488. #if 0
  489.   if ( !e.bForceEncExit && !e.bForceRipExit )
  490.     PostMessage( e.hDlg, WM_TRACKDONE, 0, 0L );
  491.   else
  492.     PostMessage( e.hDlg, WM_DESTROY, 0, 0L );
  493. #else
  494.   PostMessage( e.hDlg, WM_TRACKDONE, 0, 0L );
  495. #endif
  496.   return 0xDEADBEEF;
  497. }
  498. DWORD EncodeThread( LPENCODETHREAD pet )
  499. {
  500.   BE_CONFIG b;
  501.   BE_ERR err;
  502.   HBE_STREAM hbeStream = 0;
  503.   DWORD dwSamples, dwSampleBytes, dwMP3BufferSize;
  504.   unsigned char *pInput = NULL, *pOutput = NULL;
  505.   DWORD numQueued, numWritten = 0;
  506.   DWORD totalWritten = 0;
  507.   //HWND hRipGauge, hReadGauge;
  508.   BOOL bStreamDirty = FALSE;
  509.   UpdateTime( -1 );
  510.   //hRipGauge = GetDlgItem( e.hDlg, IDG_RIPPROG );
  511.   //hReadGauge = GetDlgItem( e.hDlg, IDG_READBUF );
  512.   if ( bMP3 )
  513.     {
  514.       ZeroMemory( &b, sizeof(b) );
  515.       if ( iEncoder == BLADE_ENC_DLL || pet->bOldLame )
  516. {
  517.   b.dwConfig = BE_CONFIG_MP3;
  518.   b.format.mp3.dwSampleRate = 44100;
  519.   b.format.mp3.byMode = BE_MP3_MODE_STEREO;
  520.   b.format.mp3.wBitrate = wBitrate;
  521.   //b.format.mp3.wBitrate = 128;
  522.   b.format.mp3.bCRC = bCRC;
  523.   b.format.mp3.bPrivate = bPrivate;
  524.   b.format.mp3.bOriginal = bOriginal;
  525.   b.format.mp3.bCopyright = bCopyright;
  526. }
  527.       else if ( iEncoder == LAME_ENC_DLL )
  528. {
  529.   b.dwConfig = BE_CONFIG_LAME;
  530.   b.format.LHV1.dwStructVersion    = 1;
  531.   b.format.LHV1.dwStructSize       = sizeof(BE_CONFIG);
  532.   b.format.LHV1.dwSampleRate       = 44100;
  533.   b.format.LHV1.dwReSampleRate     = 0;
  534.   b.format.LHV1.nMode              = BE_MP3_MODE_STEREO;
  535.   b.format.LHV1.dwBitrate          = (DWORD)wBitrate;
  536.   b.format.LHV1.dwMaxBitrate       = 320;
  537.   b.format.LHV1.nQuality           = nQuality;
  538.   b.format.LHV1.dwMpegVersion      = MPEG1;
  539.   b.format.LHV1.bCRC               = bCRC;
  540.   b.format.LHV1.bPrivate           = bPrivate;
  541.   b.format.LHV1.bOriginal          = bOriginal;
  542.   b.format.LHV1.bCopyright         = bCopyright;
  543.   b.format.LHV1.bWriteVBRHeader    = bVBRHeader;
  544.   b.format.LHV1.bEnableVBR         = bVBR;
  545.   b.format.LHV1.nVBRQuality        = nVBRQuality;
  546. }
  547.       err = beInitStream( &b, &dwSamples, &dwMP3BufferSize, &hbeStream );
  548.       dwSampleBytes = 2 * dwSamples;
  549.       pInput = (unsigned char *)malloc( dwSampleBytes );
  550.       pOutput = (unsigned char *)malloc( dwMP3BufferSize );
  551.     }
  552.   else
  553.     pOutput = (unsigned char *)malloc( 32656 );
  554.   while( TRUE )
  555.     {
  556.       unsigned char *pTmp;
  557.       pTmp = pOutput;
  558.       if ( pet->bForceEncExit )
  559. break;
  560.       numQueued = wrqNumUsed( &pet->q );
  561.       if ( !numQueued && pet->bNormalExit )
  562. {
  563.   break;
  564. }
  565.       if ( !bMP3 )
  566. {
  567.   while( wrqNumUsed( &pet->q ) )
  568.     {
  569.       int numRead;
  570.       numRead = wrqDequeue( &pet->q, &pTmp, 32656 );
  571.       writeAndFlush( pet->fpOut, pTmp, numRead );
  572.       totalWritten += numRead;
  573.       UpdateTime( numRead );
  574.     }
  575. }
  576.       else  // encoding to MP3
  577. {
  578.   pTmp = pInput;
  579.   if ( numQueued >= dwSampleBytes || pet->bNormalExit )
  580.     {
  581.       DWORD num2dequeue = numQueued;
  582.       if ( num2dequeue > dwSampleBytes )
  583. num2dequeue = dwSampleBytes;
  584.       num2dequeue = wrqDequeue( &pet->q, &pTmp, num2dequeue );
  585.       if ( bWavMirror )
  586. {
  587.   writeAndFlush( pet->fpWavMirror, pTmp, num2dequeue );
  588.   totalWritten += num2dequeue;
  589. }
  590.       beEncodeChunk( hbeStream, num2dequeue/2, (PSHORT)pTmp,
  591.      pOutput, &numWritten );
  592.       fwrite( pOutput, 1, numWritten, pet->fpOut );
  593.       UpdateTime( num2dequeue );
  594.       bStreamDirty = TRUE;
  595.     }
  596. }
  597.     }
  598.   if ( pet->fpWavMirror && bWavMirror )
  599.     writeWavHeader( pet->fpWavMirror, totalWritten );
  600.   if ( !bMP3 )
  601.     writeWavHeader( pet->fpOut, totalWritten );
  602.   else
  603.     {
  604.       if ( hbeStream && bStreamDirty )
  605. {
  606.   beDeinitStream( hbeStream, pOutput, &numWritten );
  607.   if ( numWritten )
  608.     {
  609.       fwrite( pOutput, 1, numWritten, pet->fpOut );
  610.     }
  611.   beCloseStream( hbeStream );
  612. }
  613.       // write ID3 tag here
  614.       if ( bID3 )
  615. writeID3V1Tag( pet->fpOut );
  616.     }
  617.   if ( pInput )
  618.     free( pInput );
  619.   if ( pOutput )
  620.     free( pOutput );
  621.   fclose( pet->fpOut );
  622.   if ( pet->fpWavMirror && bWavMirror )
  623.     fclose( pet->fpWavMirror );
  624.   return 0xDEADBEEF;
  625. }
  626. int writeAndFlush( FILE *fp, BYTE *buf, int len )
  627. {
  628.   static int wafNumWritten = 0;
  629.   int retVal = 0;
  630.   wafNumWritten += len;
  631.   retVal = fwrite( buf, 1, len, fp );
  632.   if ( wafNumWritten > 20480 )
  633.     {
  634.       fflush( fp );
  635.       wafNumWritten = 0;
  636.     }
  637.   return retVal;
  638. }
  639. void writeWavHeader( FILE *fp, DWORD len )
  640. {
  641.   WAVHDR wav;
  642.   if ( !fp )
  643.     return;
  644.   memcpy( wav.riff, "RIFF", 4 );
  645.   wav.len = len + 44 - 8;
  646.   memcpy( wav.cWavFmt, "WAVEfmt ", 8 );
  647.   wav.dwHdrLen = 16;
  648.   wav.wFormat = 1;
  649.   wav.wNumChannels = 2;
  650.   wav.dwSampleRate = 44100;
  651.   wav.dwBytesPerSec = 44100*2*2;
  652.   wav.wBlockAlign = 4;
  653.   wav.wBitsPerSample = 16;
  654.   memcpy( wav.cData, "data", 4 );
  655.   wav.dwDataLen = len;
  656.   fseek( fp, 0, SEEK_SET );
  657.   fwrite( &wav, 1, sizeof(wav), fp );
  658. }
  659. BOOL loadBladeEnc( void )
  660. {
  661.   ENCODER i;
  662.   if ( hBladeDll && hLameDll )
  663.     return TRUE;
  664.   if ( !hLameDll )
  665.     hLameDll = LoadLibrary( "LAME_ENC.DLL" );
  666.   if ( !hBladeDll )
  667.     hBladeDll = LoadLibrary( "BLADEENC.DLL" );
  668.   // See if we can get addresses for the encoder functions, to determine
  669.   // what encoders are present
  670.   for( i = BLADE_ENC_DLL; i < MAXENCODER; i++ )
  671.     LoadEncoderFunctions( i );
  672.   if ( !hBladeDll && !hLameDll )
  673.     return FALSE;
  674.   if ( (iEncoder == NOENCODER ) || !LoadEncoderFunctions( iEncoder ) )
  675.     {
  676.       if ( hBladeDll && !hLameDll )
  677. iEncoder = BLADE_ENC_DLL;
  678.       else if ( hLameDll && !hBladeDll )
  679. iEncoder = LAME_ENC_DLL;
  680.       else
  681. iEncoder = BLADE_ENC_DLL;  // default if not read from registry
  682.       if ( !LoadEncoderFunctions( iEncoder ) )
  683. {
  684.   iEncoder = NOENCODER;
  685.   return FALSE;
  686. }
  687.       return TRUE;
  688.     }
  689.   return TRUE;
  690. }
  691. /*
  692.  * Calls GetProcAddress for the given encoder to obtain addresses for the
  693.  * encoder functions.  Returns FALSE if the DLL is not loaded, or if
  694.  * one or more function addresses cannot be loaded.
  695.  */
  696. BOOL LoadEncoderFunctions( ENCODER nEncoder )
  697. {
  698.   HANDLE hDll;
  699.   if ( nEncoder <= NOENCODER || nEncoder > MAXENCODER )
  700.     return FALSE;
  701.   switch( nEncoder )
  702.     {
  703.     case BLADE_ENC_DLL:
  704.       hDll = hBladeDll;
  705.       break;
  706.     case LAME_ENC_DLL:
  707.       hDll = hLameDll;
  708.       break;
  709.     case NOENCODER:
  710.     default:
  711.       return FALSE;
  712.     }
  713.   if ( !hDll )
  714.     return FALSE;
  715.   beInitStream = (BEINITSTREAM)GetProcAddress( hDll, "beInitStream" );
  716.   beEncodeChunk = (BEENCODECHUNK)GetProcAddress( hDll, "beEncodeChunk" );
  717.   beDeinitStream = (BEDEINITSTREAM)GetProcAddress( hDll, "beDeinitStream" );
  718.   beCloseStream = (BECLOSESTREAM)GetProcAddress( hDll, "beCloseStream" );
  719.   beVersion = (BEVERSION)GetProcAddress( hDll, "beVersion" );
  720.   if ( !beInitStream || !beEncodeChunk || !beDeinitStream ||
  721.        !beCloseStream || !beVersion )
  722.     {
  723.       switch( nEncoder )
  724. {
  725. case BLADE_ENC_DLL:
  726.   hBladeDll = NULL;
  727.   break;
  728. case LAME_ENC_DLL:
  729.   hLameDll = NULL;
  730.   break;
  731. case NOENCODER:
  732. default:
  733.   break;
  734. }
  735.       beInitStream = NULL;
  736.       beEncodeChunk = NULL;
  737.       beDeinitStream = NULL;
  738.       beCloseStream = NULL;
  739.       beVersion = NULL;
  740.       FreeLibrary( hDll );
  741.       return FALSE;
  742.     }  
  743.   return TRUE;
  744. }
  745. /***************************************************************************/
  746. /*                                                                         */
  747. /* UpdateTime                                                              */
  748. /*                                                                         */
  749. /* Update the elapsed/remaining time field on the dialog.  If we're        */
  750. /* supplied with negative bytes, we assume we're initialising our static   */
  751. /* variables.                                                              */
  752. /*                                                                         */
  753. /* Written by B. Thompson, January 27, 2000                                */
  754. /*                                                                         */
  755. /***************************************************************************/
  756. void UpdateTime (long numWritten)
  757. {
  758.   static
  759.   time_t   startTime = 0;              /* Start time stamp                 */
  760.   static
  761.   DWORD    totalWritten = 0;           /* Total bytes written              */
  762.   static
  763.   DWORD    timeLeft = 0;               /* Time remaining                   */
  764.   static
  765.   DWORD    numToWrite;                 /* Total number to be written       */
  766.   static
  767.   HWND     hRipGauge, hReadGauge;      /* Dialog controls                  */
  768.   double   timeLeftd;                  /* Improved calculational ability   */
  769.   time_t   currTime;                   /* Current time stamp               */
  770.   long     secsElapsed;                /* Elapsed seconds since last hour  */
  771.   long     secsLeft;                   /* Remaining seconds since last hour*/
  772.   char     estTime[24];                /* Estimated time                   */
  773.   if (numWritten < 0)
  774.     {                                                     /* Initialisation*/
  775.       time(&startTime);
  776.       totalWritten = 0;
  777.       numToWrite = e.trackLen * 2352;
  778.       hRipGauge = GetDlgItem(e.hDlg, IDG_RIPPROG);
  779.       hReadGauge = GetDlgItem(e.hDlg, IDG_READBUF);
  780.       return;
  781.     }                                                             /* End if*/
  782.   totalWritten += numWritten;
  783.   if (!totalWritten)
  784.     return;                                        /* Avoid divide by zero!*/
  785.   time(&currTime);
  786.   currTime -= startTime;                          /* Elapsed time (seconds)*/
  787.   if (currTime != timeLeft)
  788.     {                                        /* At least one second elapsed*/
  789.       timeLeftd = currTime;
  790.       timeLeftd *= numToWrite;
  791.       timeLeftd /= totalWritten;
  792.       timeLeftd -= currTime;
  793.       timeLeft = (DWORD)timeLeftd;
  794.       secsElapsed = currTime % 3600;
  795.       secsLeft = (long)(timeLeft % 3600);
  796. //    sprintf(estTime, "%i %i", totalWritten, numToWrite);
  797.       sprintf(estTime, "%li:%02li:%02li (%ld:%02ld:%02ld)",
  798.               currTime / 3600, secsElapsed / 60, secsElapsed % 60,
  799.               timeLeft / 3600, secsLeft / 60, secsLeft % 60);
  800.       SetDlgItemText(e.hDlg, IDT_ESTTIME, estTime);
  801.     }                                                             /* End if*/
  802.     timeLeft = currTime;                              /* For next iteration*/
  803. #if 0
  804.     SendDlgItemMessage( e.hDlg, IDG_RIPPROG, GM_SETDELTAPOS,
  805.                         (WPARAM)((UINT)numWritten), 0L );
  806.     SendDlgItemMessage( e.hDlg, IDG_READBUF, GM_SETPOS,
  807.                         (WPARAM)wrqNumUsed( &e.q ), 0L );
  808. #else
  809.     PostMessage( hRipGauge, GM_SETDELTAPOS, (WPARAM)((UINT)numWritten), 0L );
  810.     PostMessage( hReadGauge, GM_SETPOS, (WPARAM)wrqNumUsed( &e.q ), 0L );
  811. #endif
  812. }                                             /* End of UpdateTime function*/
  813. /*
  814.  * Returns TRUE if Lame_enc.dll is old enough to use the original BladeEnc
  815.  * interface.  Also returns TRUE if lame_enc isn't available...
  816.  */
  817. BOOL isOldLameEnc( void )
  818. {
  819.   BE_VERSION bev;
  820.   BEVERSION      pfnbeVersion;
  821.   DWORD dwEngine, dwDll;
  822.   if ( hLameDll )
  823.     {
  824.       pfnbeVersion = (BEVERSION)GetProcAddress( hLameDll, "beVersion" );
  825.       ZeroMemory( &bev, sizeof(bev) );
  826.       if ( pfnbeVersion )
  827. pfnbeVersion( &bev );
  828.       dwEngine = (((DWORD)bev.byMajorVersion)<<8) + bev.byMinorVersion;
  829.       dwDll = (((DWORD)bev.byDLLMajorVersion)<<8) + bev.byDLLMinorVersion;
  830.       if ( (dwEngine < 0x0336) || (dwDll < 0x0104) )
  831. return TRUE;
  832.       return FALSE;
  833.     }
  834.   return TRUE;
  835. }