Sample Code
Windows Driver Samples/ Msfilter Sample Codec/ C++/ msfilter.c/
//==========================================================================; // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR // PURPOSE. // // Copyright (c) 1992-1994 Microsoft Corporation // //--------------------------------------------------------------------------; // // msfilter.c // // Description: // This file contains filter routines for doing simple // volume and echo. // // // //==========================================================================; #include <windows.h> #include <windowsx.h> #include <mmsystem.h> #include <mmreg.h> #include <msacm.h> #include <msacmdrv.h> #include "codec.h" #include "msfilter.h" //--------------------------------------------------------------------------; // // LRESULT msfilterVolume // // Description: // This function handles the ACMDM_STREAM_CONVERT message. This is the // whole purpose of writing an ACM driver--to convert data. This message // is sent after a stream has been opened (the driver receives and // succeeds the ACMDM_STREAM_OPEN message). // // Arguments: // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the // conversion stream. This structure was allocated by the ACM and // filled with the most common instance data needed for conversions. // The information in this structure is exactly the same as it was // during the ACMDM_STREAM_OPEN message--so it is not necessary // to re-verify the information referenced by this structure. // // LPACMDRVSTREAMHEADER padsh: Pointer to stream header structure // that defines the source data and destination buffer to convert. // // Return (LRESULT): // The return value is zero (MMSYSERR_NOERROR) if this function // succeeds with no errors. The return value is a non-zero error code // if the function fails. // //--------------------------------------------------------------------------; LRESULT FNGLOBAL msfilterVolume ( LPACMDRVSTREAMINSTANCE padsi, LPACMDRVSTREAMHEADER padsh ) { LPVOLUMEWAVEFILTER pwfVol; HPSHORT hpiSrc; HPSHORT hpiDst; HPBYTE hpbSrc; HPBYTE hpbDst; LONG lSrc, lDst; LONG lAmp; LONG lDone, lSize; DWORD dw; pwfVol = (LPVOLUMEWAVEFILTER)padsi->pwfltr; // // Source and dest sizes are the same for volume. // block align source // dw = PCM_BYTESTOSAMPLES(padsi->pwfxSrc, padsh->cbSrcLength); dw = PCM_SAMPLESTOBYTES(padsi->pwfxSrc, dw); padsh->cbSrcLengthUsed = dw; lSize = (LONG)dw; lAmp = pwfVol->dwVolume; if( padsi->pwfxSrc->wBitsPerSample == 8 ) { hpbSrc = (HPBYTE)padsh->pbSrc; hpbDst = (HPBYTE)padsh->pbDst; for( lDone = 0; lDone < lSize; lDone++ ) { lSrc = ((short)(WORD)(*hpbSrc)) - 128; lDst = ((lSrc * lAmp) / 65536L) + 128; if( lDst < 0 ) { lDst = 0; } else if( lDst > 255 ) { lDst = 255; } *hpbDst = (BYTE)lDst; if( lDone < (lSize - 1) ) { // Will advance to invalid ptr on last sample // So do not advance on last sample. hpbSrc++; hpbDst++; } } } else { hpiSrc = (HPSHORT)(padsh->pbSrc); hpiDst = (HPSHORT)(padsh->pbDst); for( lDone = 0; lDone < lSize; lDone += sizeof(short) ) { lDst = ((((LONG)(int)(*hpiSrc)) * (lAmp/2)) / 32768L); if( lDst < -32768 ) { lDst = -32768; } else if( lDst > 32767 ) { lDst = 32767; } *hpiDst = (short)lDst; if( lDone < (lSize - 1) ) { // Will advance to invalid ptr on last sample // So do not advance on last sample. hpiSrc++; hpiDst++; } } } padsh->cbDstLengthUsed = lDone; return (MMSYSERR_NOERROR); } //--------------------------------------------------------------------------; // // LRESULT msfilterEcho // // Description: // This function handles the ACMDM_STREAM_CONVERT message. This is the // whole purpose of writing an ACM driver--to convert data. This message // is sent after a stream has been opened (the driver receives and // succeeds the ACMDM_STREAM_OPEN message). // // Arguments: // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the // conversion stream. This structure was allocated by the ACM and // filled with the most common instance data needed for conversions. // The information in this structure is exactly the same as it was // during the ACMDM_STREAM_OPEN message--so it is not necessary // to re-verify the information referenced by this structure. // // LPACMDRVSTREAMHEADER padsh: Pointer to stream header structure // that defines the source data and destination buffer to convert. // // Return (LRESULT): // The return value is zero (MMSYSERR_NOERROR) if this function // succeeds with no errors. The return value is a non-zero error code // if the function fails. // //--------------------------------------------------------------------------; LRESULT FNGLOBAL msfilterEcho ( LPACMDRVSTREAMINSTANCE padsi, LPACMDRVSTREAMHEADER padsh ) { PSTREAMINSTANCE psi; LPECHOWAVEFILTER pwfEcho; DWORD dw; HPSHORT hpiHistory; HPSHORT hpiSrc; HPSHORT hpiDst; HPBYTE hpbHistory; HPBYTE hpbSrc; HPBYTE hpbDst; LONG lSrc, lHist, lDst; LONG lAmp, lDelay; LONG lDone1, lDone2, lSize, lDelaySize; BOOL fStart; BOOL fEnd; DWORD cbDstLength; fStart = (0 != (ACM_STREAMCONVERTF_START & padsh->fdwConvert)); fEnd = (0 != (ACM_STREAMCONVERTF_END & padsh->fdwConvert)); pwfEcho = (LPECHOWAVEFILTER)padsi->pwfltr; lAmp = pwfEcho->dwVolume; psi = (PSTREAMINSTANCE)padsi->dwDriver; lDone1 = 0; lDone2 = 0; lDelay = psi->dwPlace; lDelaySize = padsi->pwfxSrc->nBlockAlign * (padsi->pwfxSrc->nSamplesPerSec * pwfEcho->dwDelay / 1000); // If this is a start buffer, then zero out the history if(fStart) { hpbHistory = psi->hpbHistory; for( lDone1 = 0; lDone1 < lDelaySize; lDone1++ ) { hpbHistory[lDone1] = 0; } psi->dwPlace = 0L; psi->dwHistoryDone = 0L; } // // Source and dest sizes are the same for volume. // block align source // dw = PCM_BYTESTOSAMPLES(padsi->pwfxSrc, padsh->cbSrcLength); dw = PCM_SAMPLESTOBYTES(padsi->pwfxSrc, dw); padsh->cbSrcLengthUsed = dw; lSize = (LONG)dw; cbDstLength = PCM_BYTESTOSAMPLES(padsi->pwfxDst, padsh->cbDstLength); cbDstLength = PCM_SAMPLESTOBYTES(padsi->pwfxDst, cbDstLength); if( padsi->pwfxSrc->wBitsPerSample == 8 ) { hpbHistory = psi->hpbHistory; hpbSrc = (HPBYTE)padsh->pbSrc; hpbDst = (HPBYTE)padsh->pbDst; for( lDone1 = 0; lDone1 < lSize; lDone1++ ) { lSrc = ((short)(WORD)(*hpbSrc)) - 128; lHist = ((short)(char)(hpbHistory[lDelay])); lDst = lSrc + lHist + 128; if( lDst < 0 ) { lDst = 0; } else if( lDst > 255 ) { lDst = 255; } *hpbDst = (BYTE)lDst; lHist = (((lDst-128) * lAmp) / 65536L); if( lHist < -128 ) { lHist = -128; } else if( lHist > 127 ) { lHist = 127; } hpbHistory[lDelay] = (BYTE)lHist; lDelay++; if( lDelay >= lDelaySize ) { lDelay = 0; } if( lDone1 < (lSize - 1) ) { // Will advance to invalid ptr on last sample // So do not advance on last sample. hpbSrc++; hpbDst++; } } // If this is the end block and there is room, // then output the last echo if(fEnd && ((DWORD)lDone1 < cbDstLength) ) { lSize = cbDstLength - lDone1; if( lSize > (lDelaySize - (LONG)(psi->dwHistoryDone)) ) { lSize = lDelaySize - psi->dwHistoryDone; } if( lSize < 0 ) { /* ERROR */ lSize = 0; } for( lDone2 = 0; lDone2 < lSize; lDone2++ ) { *hpbDst = (BYTE)((short)(char)(hpbHistory[lDelay]) + 128); lDelay++; if( lDelay >= lDelaySize ) { lDelay = 0; } if( lDone2 < (lSize - 1) ) { // Will advance to invalid ptr on last sample // So do not advance on last sample. hpbSrc++; hpbDst++; } (psi->dwHistoryDone)++; } } } else { hpiHistory = (HPSHORT)(psi->hpbHistory); hpiSrc = (HPSHORT)(padsh->pbSrc); hpiDst = (HPSHORT)(padsh->pbDst); for( lDone1 = 0; lDone1 < lSize; lDone1 += sizeof(short) ) { lDst = (LONG)(*hpiSrc) + (LONG)(hpiHistory[lDelay]); if( lDst < -32768 ) { lDst = -32768; } else if( lDst > 32767 ) { lDst = 32767; } *hpiDst = (short)lDst; lHist = ( ( lDst * (lAmp/2)) / 32768L); if( lHist < -32768 ) { lHist = -32768; } else if( lHist > 32767 ) { lHist = 32767; } hpiHistory[lDelay] = (short)lHist; lDelay++; if( (LONG)(lDelay * sizeof(short)) >= lDelaySize ) { lDelay = 0; } if( lDone1 < (lSize - 1) ) { // Will advance to invalid ptr on last sample // So do not advance on last sample. hpiSrc++; hpiDst++; } } // If this is the end block and there is room, // then output the last echo if(fEnd && ((DWORD)lDone1 < cbDstLength) ) { lSize = cbDstLength - lDone1; if( lSize > (lDelaySize - (LONG)(psi->dwHistoryDone)) ) { lSize = lDelaySize - psi->dwHistoryDone; } if( lSize < 0 ) { /* ERROR */ lSize = 0; } for( lDone2 = 0; lDone2 < lSize; lDone2 += sizeof(short) ) { *hpiDst = hpiHistory[lDelay]; lDelay++; if( (LONG)(lDelay * sizeof(short)) >= lDelaySize ) { lDelay = 0; } if( lDone2 < (lSize - 1) ) { // Will advance to invalid ptr on last sample // So do not advance on last sample. hpiSrc++; hpiDst++; } psi->dwHistoryDone += sizeof(short); } } } // Reset the new point/place in the history psi->dwPlace = lDelay; padsh->cbDstLengthUsed = lDone1 + lDone2; return (MMSYSERR_NOERROR); }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials