⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 riptracks.c

📁 读取音乐光盘磁道为磁盘文件的DLL源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * riptracks.c - Copyright (C) 1999,2000 Jay A. Key
 *
 * Contains the RipTrack() function.  The rip dialog proc, plus the
 * read and encode threads are all contained in this file.  The read 
 * thread is also responsible for jitter correction.  A good example of 
 * how to rip a track from a CD via AKRip32.dll
 *
 **********************************************************************
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <malloc.h>
#include "akrip/akrip32.h"
#include "resources.h"
#include "globals.h"
#include "riptracks.h"
#include "trackwnd.h"
#include "bladedll.h"
#include "gauge.h"
#include "id3.h"

#define _USE_LAME  0

DWORD RipThread( LPENCODETHREAD pet );
DWORD EncodeThread( LPENCODETHREAD pet );
LPTRACKBUF newTrackBuf( DWORD numFrames );
void RipTrack( HWND hDlg, int idx, LPADDTRACK lpAddTrack );
int writeAndFlush( FILE *fp, BYTE *buf, int len );
void writeWavHeader( FILE *fp, DWORD len );
BOOL loadBladeEnc( void );
void setRipTrackStatus( LPENCODETHREAD e );
BOOL LoadEncoderFunctions( ENCODER nEncoder );
void UpdateTime (long numWritten);
BOOL isOldLameEnc( void );

static ENCODETHREAD e;
static ADDTRACK rtAddTrack;
//static BOOL bSecond = FALSE;

/*
 * 1. initializes the common data structure
 * 2. starts the threads
 * 
 * 
 */
void RipTrack( HWND hDlg, int idx, LPADDTRACK lpAddTrack )
{
  DWORD dwRipThreadID, dwEncThreadID;
  static DWORD numBufFrames = 8;
  static char outputName[MAX_PATH+1];
  int iDirLen;                      // iNameLen, iTotal;
  char *p;

  ZeroMemory( &e, sizeof(e) );

  e.idx = idx;

  time( &e.tstart );

  e.hDlg = hDlg;

  wsprintf( outputName, "%s.%s", lpAddTrack->name,  bMP3?"mp3":"wav" );
  SetDlgItemText( hDlg, IDT_TRACKNAME, outputName );

  // we really need to check filename lengths here, but I'm just too damn
  // tired right now
  iDirLen = lstrlen( szMP3OutputDir );
  //iNameLen = lstrlen( lpAddTrack->name );
  //iTotal = iDirLen + iNameLen + 5;

  if ( bMP3 )
    lstrcpy( outputName, szMP3OutputDir );
  else
    lstrcpy( outputName, szWavOutputDir );

  iDirLen = lstrlen( outputName );
  if ( !iDirLen )
    lstrcpy( outputName, ".\\" );
  if ( iDirLen && outputName[iDirLen-1] != '\\' )
    lstrcat( outputName, "\\" );

  // add the track name, and then replace illegal characters with a '_'
  p = outputName + lstrlen( outputName );
  lstrcat( outputName, lpAddTrack->name );
  while( *p )
    {
      if ( !validFnameChar[(unsigned char)*p] )
	*p = '_';
      p++;
    }

  // add the proper extension
  p = outputName + lstrlen( outputName );
  lstrcat( outputName, bMP3?".mp3":".wav" );

  e.fpOut = fopen( outputName, "w+b" );
  if ( !bMP3 )
    writeWavHeader( e.fpOut, 0 );

  if ( bMP3 && bWavMirror )
    {
      // change the extension to WAV (p was set to the terminating NULL)
      lstrcpy( p, ".wav" );
      e.fpWavMirror = fopen( outputName, "wb" );
      writeWavHeader( e.fpWavMirror, 0 );
    }
  else
    e.fpWavMirror = NULL;

  if ( bMP3 )
    {
      switch( iEncoder )
	{
	case BLADE_ENC_DLL:
	  wsprintf( outputName, "%d kbps MP3 via BladeEnc DLL", wBitrate );
	  break;
	case LAME_ENC_DLL:
	  if ( isOldLameEnc() )
	    {
	      e.bOldLame = TRUE;
	    }
	  wsprintf( outputName, "%d kbps MP3 via Lame_Enc DLL", wBitrate );
	  if ( bVBR && !e.bOldLame )
	    wsprintf( outputName+lstrlen(outputName),
		      ", VBR max bitrate %d, VBR quality %d", wMaxBitrate,
		      nVBRQuality );
	  break;
	}
    }
  else
    wsprintf( outputName, "WAV file" );
  SetDlgItemText( hDlg, IDT_OUTPUTOPTTEXT, outputName );

  ModifyCDParms( hCD, CDP_OVERLAP, numOverlap );
  ModifyCDParms( hCD, CDP_JITTER, jitterCheck );
  ModifyCDParms( hCD, CDP_READMODE, readMode );

  e.startFrame = lpAddTrack->start;
  e.trackLen = lpAddTrack->len;
  e.endFrame = e.startFrame + e.trackLen;

  InitializeCriticalSection( &e.cs );

  e.hRipCancel = CreateEvent( NULL, FALSE, FALSE, NULL );

  SendDlgItemMessage( hDlg, IDG_RIPPROG, GM_SETRANGE,
		      (WPARAM)((UINT)e.trackLen * 2352),
		      0L );
  SendDlgItemMessage( hDlg, IDG_RIPPROG, GM_SETPOS, 0, 0L );

  wrqInitQueue( &e.q, maxRip * 2352 * numBufFrames );

  SendDlgItemMessage( hDlg, IDG_READBUF, GM_DISPPCT, (WPARAM)FALSE, 0L );
  SendDlgItemMessage( hDlg, IDG_READBUF, GM_SETRANGE,
		      (WPARAM)wrqFreeSpace( &e.q ), 0L );

  // Set ID3 info for track.  Album title and artist are set elsewhere
  asSetID3Info( ID3_TITLE, lpAddTrack->name, 0 );
  asSetID3Info( ID3_LEVEL, NULL, 1 );
#if 0
  asSetID3Info( ID3_YEAR, "1997", 0 );
  asSetID3Info( ID3_GENRE, NULL, 17 );
#endif
  

  e.aHandles[0] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)RipThread,
				(LPVOID)&e, 0, &dwRipThreadID );
  e.aHandles[1] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)EncodeThread,
				(LPVOID)&e, 0, &dwEncThreadID );
}


BOOL RipTrackDlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
  WORD wID;
  //static BOOL bDone = FALSE;
  static HWND hTrckWnd = NULL;
  int idx = -1;

  switch( uMsg )
    {
    case WM_DESTROY:
      bRippingTracks = FALSE;
      EndDialog( hWnd, 0 );
      break;

    case WM_TRACKDONE:
      //bSecond = TRUE;
      DeleteCriticalSection( &e.cs );
      //CloseHandle( &e.hRipCancel );
      wrqDeinitQueue( &e.q );
      // set the status text for the last track ripped
      setRipTrackStatus( &e );
      // if more tracks to rip and the last one finished successfully,
      // call RipTrack again
      idx = SendMessage( hTrckWnd,WM_FINDNEXTTRACK,0,(LPARAM)&rtAddTrack);
      if ( (idx != -1) && (e.status == EST_SUCCESS) )
	RipTrack( hWnd, idx, &rtAddTrack );
      else
	{
	  bRippingTracks = FALSE;
	  EndDialog( hWnd, 0 );
	}
      break;

    case WM_INITDIALOG:
      //bDone = FALSE;
      //bSecond = FALSE;
      hTrckWnd = (HWND)lParam;
      bRippingTracks = TRUE;
      idx = SendMessage(hTrckWnd,WM_FINDFIRSTTRACK,0,
			       (LPARAM)&rtAddTrack);
      if ( idx != -1 )
	{
	  RipTrack( hWnd, idx, &rtAddTrack );
	}
      else
	{
	  MessageBox( GetParent(hTrckWnd), "No tracks selected", "Warning!",
		      MB_ICONEXCLAMATION | MB_OK );
	  bRippingTracks = FALSE;
	  EndDialog( hWnd, 0 );
	}
      break;

    case WM_COMMAND:
      wID = LOWORD( wParam );
      if ( wID == IDBN_CANCELRIP || wID == 2 )
	{
	  if ( /* bDone || */ (MessageBox( hWnd, "Really stop?", "Abort?", MB_APPLMODAL | MB_YESNO | MB_ICONEXCLAMATION ) == IDYES) )
	    {
	      e.bForceRipExit = TRUE;
	      e.status = EST_ABORTED;
	      SetEvent( e.hRipCancel );
	      EnableWindow( GetDlgItem( hWnd, IDBN_CANCELRIP ),FALSE );
	    }
	}
      return TRUE;
    }

  return FALSE;
}


BOOL RipTrackSegmentDlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
  WORD wID;

  switch( uMsg )
    {
    case WM_DESTROY:
      bRippingTracks = FALSE;
      EndDialog( hWnd, 0 );
      break;

    case WM_TRACKDONE:
      DeleteCriticalSection( &e.cs );
      wrqDeinitQueue( &e.q );
      if ( e.status != EST_SUCCESS )
	{
	}
      bRippingTracks = FALSE;
      EndDialog( hWnd, 0 );
      break;

    case WM_INITDIALOG:
      bRippingTracks = TRUE;
      RipTrack( hWnd, -1, (LPADDTRACK)lParam );
      break;

    case WM_COMMAND:
      wID = LOWORD( wParam );
      if ( wID == IDBN_CANCELRIP || wID == 2 )
	{
	  if ( MessageBox( hWnd, "Really stop?", "Abort?", MB_APPLMODAL | MB_YESNO | MB_ICONEXCLAMATION ) == IDYES )
	    {
	      e.bForceRipExit = TRUE;
	      e.status = EST_ABORTED;
	      SetEvent( e.hRipCancel );
	      EnableWindow( GetDlgItem( hWnd, IDBN_CANCELRIP ),FALSE );
	    }
	}
      return TRUE;
    }

  return FALSE;
}


LPTRACKBUF newTrackBuf( DWORD numFrames )
{
  LPTRACKBUF t;
  int numAlloc;

  numAlloc = (((int)numFrames)*2352) + TRACKBUFEXTRA;

  t = (LPTRACKBUF)malloc( numAlloc );

  if ( !t )
    return NULL;

  t->startFrame = 0;
  t->numFrames = 0;
  t->maxLen = numFrames * 2352;
  t->len = 0;
  t->status = 0;
  t->startOffset = 0;

  return t;
}


//#define _ALWAYS_READ_MAX
/*
 * Thread responsible for reading the data from the CD and placing it in
 * a queue for the encode thread.
 *
 * trying a new strategy -- always read the full maxRip frames, and truncate
 * if it's too many, but after the read.  Some of the SCSI read modes were
 * crapping out on the last read when I suddenly requested a different number
 * of frames.  To switch back to the old method, undefine _ALWAYS_READ_MAX
 *
 * CDRM_JITTERONERR uses two full-size TRACKBUFs on a rotating basis.  On the
 * read it uses t1, and then on the next read switches to t2.  If an error
 * is returned from the read function, then the buffer from the previous read
 * is used to jitter correct the current one.
 */
DWORD RipThread( LPENCODETHREAD pet )
{
  LPTRACKBUF tbuf, t1, t2, tover, tTmp;
  DWORD num2rip, dwStatus;
  HANDLE hWait[2];
  int retries;
  BOOL useT1 = FALSE;
  HWND hReadGauge;
  BOOL bWaited;
  //char buf[81];

  hWait[0] = CreateEvent( NULL, FALSE, FALSE, NULL ); 
  hWait[1] = pet->hRipCancel;

  // initialize all buffers
  tbuf = t1 = t2 = tover = tTmp = NULL;

  tbuf = t1 = newTrackBuf( maxRip );
  switch ( readMode )
    {
    case CDRM_JITTER:
      tover = newTrackBuf( numOverlap );
      break;
    case CDRM_JITTERONERR:
      t2 = newTrackBuf( maxRip );
      break;
    default:
    case CDRM_NOJITTER:
      readMode = CDRM_NOJITTER;
      break;
    }

  num2rip = maxRip;

  hReadGauge = GetDlgItem( e.hDlg, IDG_READBUF );

  while( TRUE )
    {
      bWaited = FALSE;

      if ( e.startFrame >= e.endFrame )
	break;

      if ( e.bForceRipExit )
	{
	  e.bForceEncExit = TRUE;
	  goto asRipExit;
	}

      EnterCriticalSection( &e.cs );
      if ( e.endFrame - e.startFrame < maxRip )
	num2rip = e.endFrame - e.startFrame;
      LeaveCriticalSection( &e.cs );

      while( wrqFreeSpace( &e.q ) < 2352 * num2rip )
	{
	  bWaited = TRUE;
	  if ( e.bForceRipExit )
	    {
	      e.bForceEncExit = TRUE;
	      goto asRipExit;
	    }
	  ResetEvent( hWait[0] );
	  wrqSetWait( &e.q, hWait[0], 2352 * maxRip * 6 );
	  //WaitForSingleObject( hWait, 20000 );
	  WaitForMultipleObjects( 2, hWait, FALSE, 60000 );
	  if ( e.bForceRipExit )
	    {
	      e.bForceEncExit = TRUE;
	      goto asRipExit;
	    }
	}

      switch( readMode )
	{
	case CDRM_JITTER:
	  EnterCriticalSection( &e.cs );
	  tbuf->startFrame = e.startFrame;
	  LeaveCriticalSection( &e.cs );
#ifndef _ALWAYS_READ_MAX
	  tbuf->numFrames = num2rip;
#else
	  tbuf->numFrames = maxRip;
#endif
	  tbuf->startOffset = 0;
	  tbuf->len = 0;
	  //retries = 3;
	  //dwStatus = SS_ERR;
	  for( dwStatus = SS_ERR, retries = 3; dwStatus != SS_COMP && retries; retries-- )
	    {
	      dwStatus = ReadCDAudioLBAEx( hCD, tbuf, tover );
	    }
	  break;

	case CDRM_JITTERONERR:
	  if ( useT1 )
	    {
	      tbuf = t1;
	      tTmp = t2;
	    }
	  else
	    {
	      tbuf = t2;
	      tTmp = t1;
	    }
	  EnterCriticalSection( &e.cs );
	  tbuf->startFrame = e.startFrame;
	  LeaveCriticalSection( &e.cs );

#ifndef _ALWAYS_READ_MAX
	  tbuf->numFrames = num2rip;
#else
	  tbuf->numFrames = maxRip;
#endif
	  tbuf->startOffset = 0;
	  tbuf->len = 0;

	  // try to force jitter correction after a wait
	  if ( !bWaited )
	    dwStatus = ReadCDAudioLBA( hCD, tbuf );
	  else
	    dwStatus = SS_ERR;

	  // after an error or a wait, dwStatus will be SS_ERR
	  if ( dwStatus == SS_ERR )
	    {
	      if ( tTmp->len )
		{
		  tTmp->startOffset += ((tTmp->numFrames - jitterCheck)*2352);
		  tTmp->startFrame += ( tTmp->numFrames - jitterCheck );
		  tTmp->numFrames = jitterCheck;
		  tTmp->len = jitterCheck * 2352;
		}
	      else
		tTmp->len = tTmp->startOffset = tTmp->numFrames;

	      for( retries = 3; (dwStatus != SS_COMP) && retries; retries-- )
		{
		  dwStatus = ReadCDAudioLBAEx( hCD, tbuf, tTmp );
		}
	    }
	  useT1 = !useT1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -