#pragma comment(lib, "winmm.lib")
#include <windows.h>
#include <mmsystem.h>
#include "WaveIO.h"
// グローバル変数
static HWAVEOUT g_hwo;
static WAVEHDR g_wh;
int WioRead(WaveIO *pwio, LPCTSTR pcFile)
{
WAVEFORMATEX wfx;
MMCKINFO ckParent;
MMCKINFO ckSub;
MMRESULT mmr;
HMMIO hmmio;
long lRead;
DWORD dwData;
void *pvData;
short *psData;
u_char *pucData;
int i;
if (pwio->psWaveformData) {
free(pwio->psWaveformData);
pwio->psWaveformData = NULL;
}
// Open
hmmio = mmioOpen((LPTSTR)pcFile, NULL, MMIO_READ);
if (hmmio == NULL) {
return -1;
}
// RIFF
ckParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
mmr = mmioDescend(hmmio, &ckParent, NULL, MMIO_FINDRIFF);
if (mmr != MMSYSERR_NOERROR) {
return -2;
}
// fmt
ckSub.ckid = mmioFOURCC('f', 'm', 't', ' ');
mmr = mmioDescend(hmmio, &ckSub, &ckParent, MMIO_FINDCHUNK);
if (mmr != MMSYSERR_NOERROR) {
return -3;
}
lRead = mmioRead(hmmio, (HPSTR)&wfx, 16);
if (lRead != 16) {
return -4;
}
mmioAscend(hmmio, &ckSub, 0);
// data
ckSub.ckid = mmioFOURCC('d', 'a', 't', 'a');
mmr = mmioDescend(hmmio, &ckSub, &ckParent, MMIO_FINDCHUNK);
if (mmr != MMSYSERR_NOERROR) {
return -5;
}
dwData = ckSub.cksize;
pvData = malloc(dwData);
if (pvData == NULL) {
return -6;
}
lRead = mmioRead(hmmio, (HPSTR)pvData, dwData);
if (lRead != (long)dwData) {
return -7;
}
mmioAscend(hmmio, &ckSub, 0);
// RIFF
mmioAscend(hmmio, &ckParent, 0);
// Close
mmioClose(hmmio, 0);
// 1サンプルあたりビット数を16に変換
pwio->wChannels = wfx.nChannels;
pwio->dwSamplesPerSec = wfx.nSamplesPerSec;
if (wfx.wBitsPerSample == 8) {
psData = (short*)malloc(dwData * sizeof(short));
if (psData == NULL) {
return -8;
}
pucData = (u_char*)pvData;
for (i = 0; i < (int)dwData; i++) {
psData[i] = (pucData[i] - 128) * 256;
}
free(pvData);
pwio->wBitsPerSample = 16;
pwio->dwSampleLength = dwData * sizeof(short);
pwio->psWaveformData = psData;
} else {
pwio->wBitsPerSample = wfx.wBitsPerSample;
pwio->dwSampleLength = dwData;
pwio->psWaveformData = (short*)pvData;
}
return 0;
}
int WioWrite(const WaveIO *pwio, LPCTSTR pcFile)
{
WAVEFORMATEX wfx;
MMCKINFO ckParent;
MMCKINFO ckSub;
HMMIO hmmio;
DWORD dwData;
u_char *pucData;
short *psData;
int i;
// Open
hmmio = mmioOpen((LPTSTR)pcFile, NULL, MMIO_WRITE | MMIO_CREATE);
if (hmmio == NULL) {
return -1;
}
// RIFF
ckParent.cksize = 0; // ダミー
ckParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
mmioCreateChunk(hmmio, &ckParent, MMIO_CREATERIFF);
// fmt
ckSub.ckid = mmioFOURCC('f', 'm', 't', ' ');
ckSub.cksize = sizeof(WAVEFORMATEX);
mmioCreateChunk(hmmio, &ckSub, 0);
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.wBitsPerSample = pwio->wBitsPerSample;
wfx.nChannels = pwio->wChannels;
wfx.nSamplesPerSec = pwio->dwSamplesPerSec;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
wfx.cbSize = 0;
mmioWrite(hmmio, (char *)&wfx, sizeof(WAVEFORMATEX));
mmioAscend(hmmio, &ckSub, 0);
// fact
ckSub.ckid = mmioFOURCC('f', 'a', 'c', 't');
ckSub.cksize = sizeof(DWORD);
mmioCreateChunk(hmmio, &ckSub, 0);
mmioWrite(hmmio, (char *)&(pwio->dwSampleLength), sizeof(DWORD));
mmioAscend(hmmio, &ckSub, 0);
// data
ckSub.ckid = mmioFOURCC('d', 'a', 't', 'a');
ckSub.cksize = 0; // ダミー
mmioCreateChunk(hmmio, &ckSub, 0);
if (pwio->wBitsPerSample == 8) {
dwData = pwio->dwSampleLength / 2;
pucData = malloc(dwData * sizeof(u_char));
if (pucData == NULL) {
return -2;
}
psData = pwio->psWaveformData;
for (i = 0; i < (int)dwData; i++) {
pucData[i] = (32768 + psData[i]) / 256;
}
mmioWrite(hmmio, (const char*)pucData, dwData);
free(pucData);
} else {
mmioWrite(hmmio, (char *)(pwio->psWaveformData), pwio->dwSampleLength);
}
mmioAscend(hmmio, &ckSub, 0);
// RIFF
mmioAscend(hmmio, &ckParent, 0);
// Close
mmioFlush(hmmio, 0);
mmioClose(hmmio, 0);
return 0;
}
int WioPlay(const WaveIO *pwio, HWND hWnd)
{
WAVEFORMATEX wfx;
MMRESULT mmr;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.wBitsPerSample = pwio->wBitsPerSample;
wfx.nChannels = pwio->wChannels;
wfx.nSamplesPerSec = pwio->dwSamplesPerSec;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
wfx.cbSize = 0;
if (hWnd) {
mmr = waveOutOpen(&g_hwo, WAVE_MAPPER, &wfx, (DWORD_PTR)hWnd, 0, CALLBACK_WINDOW);
} else {
mmr = waveOutOpen(&g_hwo, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);
}
if (mmr != MMSYSERR_NOERROR) {
return -1;
}
memset(&g_wh, 0, sizeof(WAVEHDR));
g_wh.lpData = (LPSTR)(pwio->psWaveformData);
g_wh.dwBufferLength = pwio->dwSampleLength;
mmr = waveOutPrepareHeader(g_hwo, &g_wh, sizeof(WAVEHDR));
if (mmr != MMSYSERR_NOERROR) {
return -2;
}
mmr = waveOutWrite(g_hwo, &g_wh, sizeof(WAVEHDR));
if (mmr != MMSYSERR_NOERROR) {
return -3;
}
return 0;
}
int WioStop(const WaveIO *pwio)
{
MMRESULT mmr;
mmr = waveOutReset(g_hwo);
if (mmr != MMSYSERR_NOERROR) {
return -1;
}
mmr = waveOutUnprepareHeader(g_hwo, &g_wh, sizeof(WAVEHDR));
if (mmr != MMSYSERR_NOERROR) {
return -2;
}
mmr = waveOutClose(g_hwo);
if (mmr != MMSYSERR_NOERROR) {
return -3;
}
return 0;
}