開発環境 Microsoft Visual Studio Community 2017
実行環境 Microsoft Windows 10 Home (64-bit)
プロジェクトの種類 Visual C++ / 空のプロジェクト
プロジェクト名 waveloop3

waveloop3.cpp
// プロジェクトのプロパティ
// Unicode文字セット
 
#pragma comment(lib, "winmm")
 
#include <Windows.h>
#include <wchar.h>
#include <vector>
#include "Resource.h"
 
using namespace std;
 
typedef struct {
	int msec;
	int freq;
} Sequence;
 
#define SAMPLE_RATE 44100
#define BUFFERS 2
#define BUF_LEN 2048
#define TIMEBASE 24
 
// 関数プロトタイプ宣言
void Trace(LPCWSTR format, ...);
INT_PTR CALLBACK MainDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
void Init();
void Timer(HWND hDlg);
void GenerateWaveForm(LPWAVEHDR pwh);
 
void Play(HWND hDlg);
void Stop(HWND hDlg);
void SetFreq(int freq);
 
// グローバル変数
HWAVEOUT hwo = NULL;
WAVEHDR wh[BUFFERS];
BYTE waveform[BUFFERS][BUF_LEN];
bool playing = false;
int wavefreq;
int phase;
vector<Sequence> seq;
int nseq;
DWORD start;
 
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAINDLG), NULL, MainDlg);
	return 0;
}
 
void Trace(LPCWSTR format, ...)
{
	va_list arg_ptr;
	WCHAR buffer[256];
 
	va_start(arg_ptr, format);
	int size = _vsnwprintf_s(buffer, _TRUNCATE, format, arg_ptr);
	va_end(arg_ptr);
	OutputDebugString(buffer);
}
 
INT_PTR CALLBACK MainDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	INT_PTR ret = TRUE;	// メッセージを処理した
 
	switch (message) {
	case MM_WOM_DONE:
		if (playing) {
			Timer(hDlg);
			GenerateWaveForm((LPWAVEHDR)lParam);
		}
		break;
	//case MM_WOM_OPEN:
	//case MM_WOM_CLOSE:
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDC_PLAY:
			Play(hDlg);
			break;
		case IDC_STOP:
			Stop(hDlg);
			break;
		case IDCANCEL:
			EndDialog(hDlg, IDCANCEL);
			break;
		}
		break;
	case WM_INITDIALOG:
		Init();
		ret = TRUE;		// SetFocusでフォーカスを設定した場合はFALSE
		break;
	case WM_CLOSE:
		Stop(hDlg);
		ret = FALSE;
		break;
	default:
		ret = FALSE;	// メッセージを処理しなかった
	}
 
	return ret;
}
 
void Init()
{
	int tempo = 120;
	int notes[] = {
		60, 24,
		62, 24,
		64, 24,
		65, 24,
		64, 24,
		62, 24,
		60, 24,
		0, 24,
	};
 
	Sequence s;
	int elapse = 100;	// wait
	for (int i = 0; i < _countof(notes); i += 2) {
		int gate = (int)((notes[i + 1] / (double)TIMEBASE) * (60.0 / tempo) * 1000);
 
		s.msec = elapse;
		s.freq = (notes[i] == 0) ? 0 : (int)(440 * pow(2, (notes[i] - 69) / 12.0));
		seq.push_back(s);
 
		elapse += gate;
	}
	s.msec = elapse;
	s.freq = 0;
	seq.push_back(s);
}
 
void Timer(HWND hDlg)
{
	int dur = (int)(GetTickCount() - start);
	if (seq[nseq].msec <= dur) {
		SetFreq(seq[nseq].freq);
		nseq++;
		if ((int)(seq.size()) <= nseq) Stop(hDlg);
	}
}
 
void GenerateWaveForm(LPWAVEHDR pwh)
{
	LPBYTE data = (LPBYTE)(pwh->lpData);
	for (int i = 0; i < BUF_LEN; i++) {
		phase += wavefreq;
		if (SAMPLE_RATE <= phase) phase -= SAMPLE_RATE;
		double t = phase / (double)SAMPLE_RATE;
		data[i] = 128 + (t < 0.5 ? 1 : -1) * 10;
	}
	waveOutWrite(hwo, pwh, sizeof WAVEHDR);
}
 
////
 
void Play(HWND hDlg)
{
	Trace(L"Play()\n");
	EnableWindow(GetDlgItem(hDlg, IDC_PLAY), FALSE);
	playing = true;
 
	SetFreq(0);
	nseq = 0;
	start = GetTickCount();
 
	MMRESULT mmr;
	WAVEFORMATEX wfx;
	wfx.wFormatTag = WAVE_FORMAT_PCM;
	wfx.nChannels = 1;
	wfx.nSamplesPerSec = SAMPLE_RATE;
	wfx.nAvgBytesPerSec = SAMPLE_RATE;
	wfx.nBlockAlign = 1;
	wfx.wBitsPerSample = 8;
	wfx.cbSize = 0;
	mmr = waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD_PTR)hDlg, NULL, CALLBACK_WINDOW);
	Trace(L"waveOutOpen: %u\n", mmr);
 
	for (int i = 0; i < BUFFERS; i++) {
		LPWAVEHDR pwh = wh + i;
		pwh->lpData = (LPSTR)(waveform[i]);
		pwh->dwBufferLength = BUF_LEN;
		pwh->dwFlags = 0;
		mmr = waveOutPrepareHeader(hwo, pwh, sizeof WAVEHDR);
		Trace(L"waveOutPrepareHeader: %d %u\n", i, mmr);
 
		GenerateWaveForm(pwh);
	}
}
 
void Stop(HWND hDlg)
{
	Trace(L"Stop()\n");
	EnableWindow(GetDlgItem(hDlg, IDC_PLAY), TRUE);
	playing = false;
 
	if (hwo) {
		MMRESULT mmr;
		mmr = waveOutReset(hwo);
		Trace(L"waveOutReset: %u\n", mmr);
 
		for (int i = 0; i < BUFFERS; i++) {
			mmr = waveOutUnprepareHeader(hwo, wh + i, sizeof WAVEHDR);
			Trace(L"waveOutUnprepareHeader: %d %u\n", i, mmr);
		}
 
		mmr = waveOutClose(hwo);
		Trace(L"waveOutClose: %u\n", mmr);
		hwo = NULL;
	}
}
 
void SetFreq(int freq)
{
	wavefreq = freq;
	phase = 0;
}
 

Resource.h
#define IDD_MAINDLG	100
//#define IDT_TIMER	101
 
#define IDC_STATIC	-1
#define IDC_PLAY	1000
#define IDC_STOP	1001
 

waveloop3.rc
// resource script
#include <windows.h>
#include "resource.h"
 
IDD_MAINDLG DIALOGEX 100, 100, 320, 200
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "waveloop3"
FONT 9, "MS UI Gothic"
BEGIN
PUSHBUTTON		"Play(&P)", IDC_PLAY, 10, 10, 50, 15
PUSHBUTTON		"Stop(&S)", IDC_STOP, 70, 10, 50, 15
END
 
最終更新:2018年05月22日 08:47