Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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;
}
}