PROCEDURE AnalyzeWav LPARAMETERS tcWavData * Author: William GC Steinford * Date: Dec 13, 2004 IF LEN(tcWavData) < 12 RETURN 'Empty Recording'+CHR(13)+tcWavData ENDIF * Verify the RIFF format as a WAVE file, and get overall length: LOCAL lcRiff, lcChunkLen, lnChunkLen, lcWave lcRiff = SUBSTR(tcWavData,1+0,4) lcChunkLen = SUBSTR(tcWavData,1+4,4) lcWave = SUBSTR(tcWavData,1+8,4) IF UPPER(lcRiff) != 'RIFF' OR UPPER(lcWave) != 'WAVE' RETURN 'Invalid Recording' ; +IIF( UPPER(lcRiff) != 'RIFF', CHR(13)+' "RIFF" missing', '' ) ; +IIF( UPPER(lcWave) != 'WAVE', CHR(13)+' "WAVE" missing', '' ) ; +CHR(13)+LEFT(tcWavData,100) ENDIF lnChunkLen = buf2dword( lcChunkLen ) IF LEN(tcWavData) < lnChunkLen+8 RETURN 'Invalid Recording.. Data is too short.' ; +CHR(13)+LEFT(tcWavData,100) ENDIF * Divide the tcWavData into Chunks: LOCAL laChunks[1], lnI, lnChunk, lcChunkSize, lnChunkSize, lnFmtChunk, lnDataChunk lnI = 13 && skip [RIFFxxxxWAVE] STORE 0 TO lnChunk, lnFmtChunk, lnDataChunk DO WHILE lnI < lnChunkLen-8 && we need a chunk size! lcChunkSize = SUBSTR( tcWavData, lnI+4, 4 ) lnChunkSize = buf2dword( lcChunkSize ) lnChunk = lnChunk+1 IF lnChunkSize+lnI+4>lnChunkLen+4+1 && lnChunkLen is 0 based, lnChunkSize is 1 based. RETURN 'Invalid Recording.. Chunk #'+TRANSFORM(lnChunk); +' ('+SUBSTR( tcWavData, lnI, 4 )+') Length is Invalid ('+TRANSFORM(lnChunkSize)+')' ; +CHR(13)+LEFT(tcWavData,100) ENDIF IF ALEN(laChunks) < lnChunk DIMENSION laChunks[lnChunk] ENDIF laChunks[lnChunk] = SUBSTR( tcWavData, lnI, 8+lnChunkSize ) && DescSize lnI = lnI+8+lnChunkSize DO CASE CASE UPPER(LEFT( laChunks[lnChunk], 4 ))='FMT ' lnFmtChunk = lnChunk CASE UPPER(LEFT( laChunks[lnChunk], 4 ))='DATA' lnDataChunk = lnChunk ENDCASE ENDDO IF lnFmtChunk=0 RETURN 'Invalid Recording' +CHR(13)+' "FMT" missing' ; +CHR(13)+LEFT(tcWavData,100) ENDIF IF lnDataChunk=0 RETURN 'Invalid Recording' +CHR(13)+' "DATA" missing' ; +CHR(13)+LEFT(tcWavData,100) ENDIF LOCAL lcFMT, lcSubChunk1Len, lcAudioFmt, lcChannels, ; lcSampleRateHz, lcBytesPerSec, lcBytesPerSamp, lcBitsPerSamp, ; lcData, lcSubChunk2Len, lcSndData lcFmt = SUBSTR(laChunks[lnFmtChunk],1+0,4) lcSubChunk1Len = SUBSTR(laChunks[lnFmtChunk],1+4,4) lcAudioFmt = SUBSTR(laChunks[lnFmtChunk],1+8,2) lcChannels = SUBSTR(laChunks[lnFmtChunk],1+10,2) lcSampleRateHz = SUBSTR(laChunks[lnFmtChunk],1+12,4) lcBytesPerSec = SUBSTR(laChunks[lnFmtChunk],1+16,4) lcBytesPerSamp = SUBSTR(laChunks[lnFmtChunk],1+20,2) lcBitsPerSamp = SUBSTR(laChunks[lnFmtChunk],1+22,2) * Translate the FMT character values into numbers: LOCAL lnSubChunk1Len, lnAudioFmt, lnChannels, ; lnSampleRateHz, lnBytesPerSec, lnBytesPerSamp, lnBitsPerSamp, ; lnSubChunk2Len lnSubChunk1Len = buf2dword( lcSubChunk1Len ) lnAudioFmt = buf2word( lcChannels ) lnChannels = buf2word( lcChannels ) lnSampleRateHz = buf2dword( lcSampleRateHz ) lnBytesPerSec = buf2dword( lcBytesPerSec ) lnBytesPerSamp = buf2dword( lcBytesPerSamp ) lnBitsPerSamp = buf2dword( lcBitsPerSamp ) * Process the Data Chunk: *lnSubChunk1Len = 16 && for PCM. Should interpret lcSubChunk1Len lcData = SUBSTR(laChunks[lnDataChunk],1+0,4) lcSubChunk2Len = SUBSTR(laChunks[lnDataChunk],1+4,4) lnSubChunk2Len = buf2dword( lcSubChunk2Len ) lcSndData = SUBSTR(laChunks[lnDataChunk],1+8) RETURN IIF(lnAudioFmt=1,'PCM Recording','Unknown Compression' ) + CHR(13) ; +' About '+TRANSFORM(lnSubChunk2Len/lnBytesPerSec)+' seconds long' +CHR(13) ; +' '+IIF(lnChannels=1,'Mono','Stereo') ; +' '+ TRANSFORM(lnSampleRateHz/1000, '999') +'kHz' ; +' '+ TRANSFORM(lnBitsPerSamp) +' bit'+CHR(13) ; +' avg '+ALLTRIM(TRANSFORM(lnBytesPerSec, '999,999,999')) +' bytes/sec'+CHR(13) ; +' '+ALLTRIM(TRANSFORM(lnBytesPerSamp, '999,999,999')) +' bytes/sample'+CHR(13) ; +' '+ALLTRIM(TRANSFORM(lnSubChunk2Len, '999,999,999')) +' bytes of sound' FUNCTION buf2word (lcBuffer) RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ; Asc(SUBSTR(lcBuffer, 2,1)) * 256 ENDFUNC * * * FUNCTION buf2dword(lcBuffer) RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ; Asc(SUBSTR(lcBuffer, 2,1)) * 256 +; Asc(SUBSTR(lcBuffer, 3,1)) * 65536 +; Asc(SUBSTR(lcBuffer, 4,1)) * 16777216 ENDFUNCadd a chr(10) character after the chr(13) in the return command