開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Win32 コンソール アプリケーション
プロジェクト名 WaveIO
アプリケーションの種類 コンソール アプリケーション
追加のオプション 空のプロジェクト
文字セット Unicode

WaveIO.h
// windows.h
 
typedef struct tagWaveIO {
	WORD	wBitsPerSample;
	WORD	wChannels;
	DWORD	dwSamplesPerSec;	// サンプリングレート
	DWORD	dwSampleLength;
	short	*psWaveformData;
} WaveIO;
 
// 関数プロトタイプ宣言
int WioRead(WaveIO *pwio, LPCTSTR pcFile);
int WioWrite(const WaveIO *pwio, LPCTSTR pcFile);
int WioPlay(const WaveIO *pwio, HWND hWnd);
int WioStop(const WaveIO *pwio);
 

WaveIO.c
#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;
}
 

sample.c
#include <tchar.h>
#include <Windows.h>
#include "WaveIO.h"
 
int _tmain()
{
	WaveIO	wio;
	int	iRet;
 
	wio.psWaveformData = NULL;
	iRet = WioRead(&wio, _T("sample.wav"));
	if (iRet) {
		_ftprintf(stderr, _T("WioRead\n"));
		return 1;
	}
 
	iRet = WioPlay(&wio, NULL);
	if (iRet) {
		_ftprintf(stderr, _T("WioPlay\n"));
		return 1;
	}
 
	// wait
 
	iRet = WioWrite(&wio, _T("sample2.wav"));
	if (iRet) {
		_ftprintf(stderr, _T("WioWrite\n"));
		return 1;
	}
 
	free(wio.psWaveformData);
 
	return 0;
}
 
最終更新:2012年09月01日 16:45