How to use mmioDescend and mmioRead APIs with CreateFile API?


You want to use the mmioOpen function in order to obtain a file handle to read a .WAV file.  However, the MSDN documentation indicates that this is a deprecated function.  The suggested replacement API CreateFile does not provide a multimedia file handle, which you need. 

Your questions:

How to use mmioDescend(), mmioRead() with CreateFile()? or how to pass the regular FILE hander created by CreateFile() to mmioRead()?

Answer:

You cannot use the handle returned by the CreateFile API with any of the mmio* APIs. Here is the code snippet that will show you how to open a wave file (RIFF format) and parse the file header without using mmio* APIs.

// FileHeader will receive all the information in the file header and
// in the header of the format chunk.

typedef struct
{
ULONG Riff4CC; // "RIFF" 4-character code
ULONG FileSize; // total file size in bytes
ULONG Wave4CC; // "WAVE" 4-character code
ULONG Fmt4CC; // "fmt " 4-character code
ULONG FormatSize; // wave format size in bytes
} FileHeader;

// ChunkHeader will receive the information in the headers for the data
// chunks, and, if the file contains additional chunks, the headers for
// those chunks as well.

typedef struct
{
ULONG ChunkType;
ULONG ChunkSize;
} ChunkHeader;
// Any file smaller than this cannot possibly contain wave data.
#define MIN_WAVE_FILE_SIZE (sizeof(FileHeader)+sizeof(PCMWAVEFORMAT)+sizeof(ChunkHeader)+1)

// Macro to build FOURCC from first four characters in ASCII string
#define FOURCC(s) ((ULONG)(s[0] | (s[1]<<8) | (s[2]<<16) | (s[3]<<24)))

//
//-- Open wave file and parse file header.

//
void WaveFileReader(LPCWSTR pszFileName, BOOL repeat)
{
FILE pFile = NULL;
HRESULT hrStreamStatus = S_OK;
fpos_t dataChunkPosition = 0;
ULONG totalDataBytes = 0;
ULONG dataBytesRemaining = 0;
WAVEFORMATEXTENSIBLE wfx;
BOOL repeatMode = repeat;

ZeroMemory(&wfx, sizeof(wfx));

// Try to open the wave file.
if (_wfopen_s(&pFile, pszFileName, L"rb") != 0)
{
_tprintf(L"[ERROR] Failed to open file!...Exiting\n\n");
return;
}

// Copy header from wave file.
FileHeader fileHdr;

if (fread(&fileHdr, sizeof(fileHdr), 1, pFile) != 1)
{
_tprintf(L"[ERROR] Not a valid wave file!...Exiting\n\n");
return;
}

if (fileHdr.Riff4CC != FOURCC("RIFF"))
{
_tprintf(L"[WARNING] RIFF signature: Not Found\n");
} else {
_tprintf(L"RIFF signature: Found\n");
}

if (fileHdr.Wave4CC != FOURCC("WAVE"))
{
_tprintf(L"[WARNING] WAVE signature: Not Found\n");
} else {
_tprintf(L"WAVE signature: Found\n");
}

if (fileHdr.Fmt4CC != FOURCC("fmt "))
{
_tprintf(L"[WARNING] fmt signature: Not Found\n");
} else {
_tprintf(L"fmt signature: Found\n");
}

if (fileHdr.FileSize < MIN_WAVE_FILE_SIZE)
{
_tprintf(L"[WARNING] File size: %d (Minimum WAV file size supported is %d)\n", fileHdr.FileSize, MIN_WAVE_FILE_SIZE);

} else {
_tprintf(L"File size: %d\n", fileHdr.FileSize);
}

if (fileHdr.FormatSize < sizeof(PCMWAVEFORMAT))
{
_tprintf(L"[WARNING] Format size: %d (Smaller than size of PCMWAVEFORMAT %d)\n", fileHdr.FormatSize, sizeof(PCMWAVEFORMAT));

} else {
_tprintf(L"Format size: %d\n", fileHdr.FormatSize);
}

// Copy wave format descriptor from file.
if (fread(&wfx, min(fileHdr.FormatSize,sizeof(wfx)), 1, pFile) != 1)
{
_tprintf(L"[ERROR] Failed to copy wave format descriptor from the file!...Exiting\n\n");
return;
}

// Skip over any padding at the end of the format in the format chunk.
if (fileHdr.FormatSize > sizeof(wfx))
{
if (fseek(pFile, fileHdr.FormatSize-sizeof(wfx), SEEK_CUR) != 0)
{
_tprintf(L"[ERROR] Failed to skip over any padding at the end of the format in the format chunk!...Exiting\n\n");
return; // not a valid wave file
}
}

// If format type is PCMWAVEFORMAT, convert to valid WAVEFORMATEX structure.
if (wfx.Format.wFormatTag == WAVE_FORMAT_PCM)
{
wfx.Format.cbSize = 0;
}

// If format type is PCMWAVEFORMAT, convert to valid WAVEFORMATEX structure.
if (wfx.Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
{
wfx.Format.cbSize = 0;
}

// If format type is WAVEFORMATEX, convert to WAVEFORMATEXTENSIBLE.
if (wfx.Format.wFormatTag == WAVE_FORMAT_PCM ||
wfx.Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
{
if (wfx.Format.wFormatTag == WAVE_FORMAT_PCM)
{
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
}
else
{
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
}

wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;

if (wfx.Format.nChannels == 1)
{
wfx.dwChannelMask = SPEAKER_FRONT_CENTER;
}
else if (wfx.Format.nChannels == 2)
{
wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
}
else
{
_tprintf(L"[WARNING] WAVEFORMATEX structure is valid for representing wave formats with only 1 or 2 channels!...Exiting\n\n");
return;
}

wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);

_tprintf(L"cbSize (Format.cbSize): %d\n", wfx.Format.cbSize);

_tprintf(L"Valid bits per sample (Samples.wValidBitsPerSample): %d\n", wfx.Format.wBitsPerSample);

wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample;
}

// This wave file reader understands only PCM and IEEE float formats.
if (wfx.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE ||
wfx.SubFormat != KSDATAFORMAT_SUBTYPE_PCM &&
wfx.SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
{

_tprintf(L"[WARNING] Not a format that we can handle...Exiting\n\n");
return;
}

_tprintf (L"\tTrying to read wave data chunk header...\n");

ChunkHeader chunkHdr; // buffer for chunk header
for (;;)
{

if (fgetpos(pFile, &dataChunkPosition) != 0)
{
_tprintf(L"\t[ERROR] Failed to retrive data chunk position!...Exiting\n\n");
return;
}

// Read header at start of next chunk of file.
if (fread(&chunkHdr, sizeof(ChunkHeader), 1, pFile) != 1)
{
_tprintf(L"\t[ERROR] Failed to read header!...Exiting\n\n");
return;
}

if (chunkHdr.ChunkType == FOURCC("data"))
{
_tprintf(L"\tFound start of the data chunk\n");
break; // found start of data chunk
}

_tprintf (L"\tVerifying data chunk...");

// This is not a data chunk. Skip this chunk and go to the next chunk.
if (fseek(pFile, chunkHdr.ChunkSize, SEEK_CUR) != 0)
{
_tprintf (L"\t[ERROR] Invalid data chunk!...Exiting\n\n");
return;
} else {
_tprintf (L"done!\n");
}
}

// We've found the start of the data chunk.
totalDataBytes = chunkHdr.ChunkSize;
dataBytesRemaining = totalDataBytes;

_tprintf(L"Total data bytes: %d\n", totalDataBytes);

if (totalDataBytes == 0)
{
_tprintf(L"[ERROR] Invalid data bytes size!...Exiting\n\n");
return;
}

}

Comments (0)

Skip to main content