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

📄 acm.c

📁 书中的主要程序文件。在打开例题的.dsw文件后,请读者在 tools菜单下的 Options 的 Directories 标签中选择 Executable files
💻 C
📖 第 1 页 / 共 5 页
字号:
//      NOTE! It is _assumed_ that the format is a valid IMA-ADPCM format
//      and that the following fields in the format structure are valid:
//
//          nChannels
//          nSamplesPerSec
//
//  Arguments:
//      LPWAVEFORMATEX pwfx: Pointer to format header.
//  
//  Return (UINT):
//      The return value is the block alignment that should be placed in
//      the pwfx->nBlockAlign field.
//
//--------------------------------------------------------------------------;

WORD FNLOCAL IMAAlgorithBlockAlign
(
    LPWAVEFORMATEX          pwfx
)
{
    UINT                uBlockAlign;
    UINT                uChannelShift;

    //
    //  The data must be an integral number of DWORDs for mono, an even
    //  number of DWORDs for stereo.
    //
    uChannelShift  = pwfx->nChannels >> 1;
    uBlockAlign    = 256 << uChannelShift;

    //
    //  choose a block alignment that makes sense for the sample rate
    //  that the original PCM data is. basically, this needs to be
    //  some reasonable number to allow efficient streaming, etc.
    //
    //  don't let block alignment get too small...
    //
    if (pwfx->nSamplesPerSec > 11025)
    {
        uBlockAlign *= (UINT)(pwfx->nSamplesPerSec / 11000);
    }

    //
    //  Just make sure that the alignment is valid.
    //
    ASSERT( 0 == uBlockAlign % (sizeof(DWORD)*pwfx->nChannels) );

    return (WORD)(uBlockAlign);
} // IMAAlgorithBlockAlign()


//--------------------------------------------------------------------------;
//  
//  WORD IMAAlgorithSamplesPerBlock
//  
//  Description:
//      This function computes the Samples Per Block that should be used
//      given the WAVEFORMATEX structure.
//
//      NOTE! It is _assumed_ that the format is a valid IMA-ADPCM format
//      and that the following fields in the format structure are valid:
//
//          nChannels       = must be 1 or 2!
//          nSamplesPerSec
//          nBlockAlign
//
//  Arguments:
//      LPWAVEFORMATEX pwfx: Pointer to format header.
//  
//  Return (DWORD):
//      The return value is the average bytes per second that should be
//      placed in the pwfx->nAvgBytesPerSec field.
//
//--------------------------------------------------------------------------;

WORD FNLOCAL IMAAlgorithSamplesPerBlock
(
    LPWAVEFORMATEX          pwfx
)
{
    UINT                uSamplesPerBlock;
    UINT                uChannelShift;
    UINT                uHeaderBytes;
    UINT                uBitsPerSample;

    //
    //
    //
    uChannelShift  = pwfx->nChannels >> 1;
    uHeaderBytes   = 4 << uChannelShift;
    uBitsPerSample = IMAALGORITH_BITS_PER_SAMPLE << uChannelShift;

    //
    //  compute the 'samples per block' that will be in the encoded
    //  ADPCM data blocks. this is determined by subtracting out the
    //  'other info' contained in each block--a block is composed of
    //  a header followed by the encoded data.
    //
    //  the block header is composed of the following data:
    //      2 bytes (16 bit) sample per channel
    //      1 byte for step table index per channel
    //      1 byte padding per channel (dword align)
    //
    //  this gives us (4 * uChannels) bytes of header information that
    //  contains our first full sample (so we add one below).
    //
    uSamplesPerBlock  = (pwfx->nBlockAlign - uHeaderBytes) * 8;
    uSamplesPerBlock /= uBitsPerSample;
    uSamplesPerBlock += 1;

    return (WORD)(uSamplesPerBlock);
} // IMAAlgorithSamplesPerBlock()


//--------------------------------------------------------------------------;
//  
//  UINT IMAAlgorithAvgBytesPerSec
//  
//  Description:
//      This function computes the Average Bytes Per Second that should
//      be used given the WAVEFORMATEX structure.
//
//      NOTE! It is _assumed_ that the format is a valid IMA-ADPCM format
//      and that the following fields in the format structure are valid:
//
//          nChannels       = must be 1 or 2!
//          nSamplesPerSec
//          nBlockAlign
//
//  Arguments:
//      LPWAVEFORMATEX pwfx: Pointer to format header.
//  
//  Return (DWORD):
//      The return value is the average bytes per second that should be
//      placed in the pwfx->nAvgBytesPerSec field.
//
//--------------------------------------------------------------------------;

DWORD FNLOCAL IMAAlgorithAvgBytesPerSec
(
    LPWAVEFORMATEX          pwfx
)
{
    DWORD               dwAvgBytesPerSec;
    UINT                uSamplesPerBlock;

    //
    //
    //
    uSamplesPerBlock = IMAAlgorithSamplesPerBlock(pwfx);

    
    //
    //  compute bytes per second including header bytes
    //
    dwAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) /
                            uSamplesPerBlock;

    return (dwAvgBytesPerSec);
} // IMAAlgorithAvgBytesPerSec()


//==========================================================================;
//
//
//
//
//==========================================================================;

//--------------------------------------------------------------------------;
//
//  LRESULT acmdDriverOpen
//
//  Description:
//      This function is used to handle the DRV_OPEN message for the ACM
//      driver. The driver is 'opened' for many reasons with the most common
//      being in preperation for conversion work. It is very important that
//      the driver be able to correctly handle multiple open driver
//      instances.
//
//      Read the comments for this function carefully!
//
//      Note that multiple _streams_ can (and will) be opened on a single
//      open _driver instance_. Do not store/create instance data that must
//      be unique for each stream in this function. See the acmdStreamOpen
//      function for information on conversion streams.
//
//  Arguments:
//      HDRVR hdrvr: Driver handle that will be returned to caller of the
//      OpenDriver function. Normally, this will be the ACM--but this is
//      not guaranteed. For example, if an ACM driver is implemented within
//      a waveform driver, then the driver will be opened by both MMSYSTEM
//      and the ACM.
//
//      LPACMDRVOPENDESC paod: Open description defining how the ACM driver
//      is being opened. This argument may be NULL--see the comments below
//      for more information.
//
//  Return (LRESULT):
//      The return value is non-zero if the open is successful. A zero
//      return signifies that the driver cannot be opened.
//
//--------------------------------------------------------------------------;

LRESULT FNLOCAL acmdDriverOpen
(
    HDRVR                   hdrvr,
    LPACMDRVOPENDESC        paod
)
{
    PDRIVERINSTANCE     pdi;

    //
    //  the [optional] open description that is passed to this driver can
    //  be from multiple 'managers.' for example, AVI looks for installable
    //  drivers that are tagged with 'vidc' and 'vcap'. we need to verify
    //  that we are being opened as an Audio Compression Manager driver.
    //
    //  if paod is NULL, then the driver is being opened for some purpose
    //  other than converting (that is, there will be no stream open
    //  requests for this instance of being opened). the most common case
    //  of this is the Control Panel's Drivers option checking for Configur
    //  support (DRV_[QUERY]CONFIGURURE).
    //
    //  we want to succeed this open, but be able to know that this
    //  open instance is bogus for creating streams. for this purpose we
    //  leave most of the members of our instance structure that we 
    //  allocate below as zero...
    //
    if (NULL != paod)
    {
        //
        //  refuse to open if we are not being opened as an ACM driver.
        //  note that we do NOT modify the value of paod->dwError in this
        //  case.
        //
        if (ACMDRIVERDETAILS_FCCTYPE_AUDIOACM != paod->fccType)
        {
            return (0L);
        }
    }


    //
    //  we are being opened as an installable driver--we can allocate some
    //  instance data to be returned in dwId argument of the DriverProc;
    //  or simply return non-zero to succeed the open.
    //
    //  this driver allocates a small instance structure. note that we
    //  rely on allocating the memory as zero-initialized!
    //
    pdi = (PDRIVERINSTANCE)LocalAlloc(LPTR, sizeof(*pdi));
    if (NULL == pdi)
    {
        //
        //  if this open attempt was as an ACM driver, then return the
        //  reason we are failing in the open description structure..
        //
        if (NULL != paod)
        {
            paod->dwError = MMSYSERR_NOMEM;
        }

        //
        //  fail to open
        //
        return (0L);
    }


    //
    //  fill in our instance structure... note that this instance data
    //  can be anything that the ACM driver wishes to maintain the
    //  open driver instance. this data should not contain any information
    //  that must be maintained per open stream since multiple streams
    //  can be opened on a single driver instance.
    //
    //  also note that we do _not_ check the version of the ACM opening
    //  us (paod->dwVersion) to see if it is at least new enough to work
    //  with this driver (for example, if this driver required Version 3.0
    //  of the ACM and a Version 2.0 installation tried to open us). the
    //  reason we do not fail is to allow the ACM to get the driver details
    //  which contains the version of the ACM that is _required_ by this
    //  driver. the ACM will examine that value (in padd->vdwACM) and
    //  do the right thing for this driver... like not load it and inform
    //  the user of the problem.
    //
    pdi->hdrvr          = hdrvr;
    pdi->hinst          = GetDriverModuleHandle(hdrvr);  // Module handle.

    if (NULL != paod)
    {
        pdi->fnDriverProc = NULL;
        pdi->fccType      = paod->fccType;
        pdi->vdwACM       = paod->dwVersion;
        pdi->fdwOpen      = paod->dwFlags;

        paod->dwError     = MMSYSERR_NOERROR;
    }


#ifdef IMAALGORITH_USECONFIGUR
    //
    // Get Configur info for this driver.  If we're not passed an
    // an ACMDRVOPENDESC structure then we'll assume we are being
    // opened for Configururation and will put off getting the Configur
    // info until we receive the DRV_CONFIGURURE message.  Otherwise we
    // get the Configur info now using the alias passed through the
    // ACMDRVOPENDESC structure.
    //
    pdi->hkey = NULL;           // This is important!

    if (NULL != paod)
    {
#if defined(WIN32) && !defined(UNICODE)
        //
        //  We must translate the UNICODE alias name to an ANSI version
        //  that we can use.
        //
    	LPSTR	lpstr;
        int     iLen;

        //
        //  Calculate required length without calling UNICODE APIs or CRT.
        //
        iLen  = WideCharToMultiByte( GetACP(), 0, paod->pszAliasName,-1,
                                                    NULL, 0, NULL, NULL );

    	lpstr = (LPSTR)GlobalAllocPtr( GPTR, iLen );
	    if (NULL != lpstr)
	    {
            WideCharToMultiByte( GetACP(), 0, paod->pszAliasName, iLen,
                                    lpstr, iLen, NULL, NULL );
	    }
	    acmdDriverConfigurInit(pdi, lpstr);	// Note: OK to pass lpstr==NULL
	    if (NULL != lpstr)
	    {
	        GlobalFreePtr( lpstr );
	    }
#else
    	acmdDriverConfigurInit(pdi, paod->pszAliasName);
#endif // WIN32 && !UNICODE
    }
#else
    //
    //  Actually, fdwConfigur is not used - there is no Configururation data.
    //
    pdi->fdwConfigur    = 0L;
#endif // IMAALGORITH_USECONFIGUR

    //
    //  non-zero return is success for DRV_OPEN
    //
    return ((LRESULT)pdi);
} // acmdDriverOpen()


//--------------------------------------------------------------------------;
//
//  LRESULT acmdDriverClose
//
//  Description:
//      This function handles the DRV_CLOSE message for the ACM driver. The
//      driver receives a DRV_CLOSE message for each succeeded DRV_OPEN
//      message (see acmdDriverOpen). The driver will only receive a close
//      message for _successful_ opens.
//
//  Arguments:
//      PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
//      This structure is [optionally] allocated during the DRV_OPEN message
//      which is handled by the acmdDriverOpen function.
//
//  Return (LRESULT):

⌨️ 快捷键说明

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