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

PlayMML.cpp
// マルチバイト文字セット
 
#pragma comment(lib, "winmm")
 
#include <Windows.h>
#include <map>
 
using namespace std;
 
typedef multimap<DWORD, DWORD> SEQ;
 
// status
#define NOTE_OFF	0x8
#define NOTE_ON		0x9
#define PROGRAM_CHANGE	0xc
 
// program
#define ACOUSTIC_PIANO	0x00
#define ACCORDION	0x15
 
#define MAKESMSG(st,ch,d1,d2) ((st)<<4|(ch)|(d1)<<8|(d2)<<16)
 
// 関数プロトタイプ宣言
void ParseMML(LPCTSTR mml);
void Command(TCHAR newCmd);
void SeqInsert(DWORD ticks, DWORD smsg);
 
const int noteList[] = {9, 11, 0, 2, 4, 5, 7};
 
// 外部変数
SEQ seq;
DWORD ticks;
TCHAR cmd = ' ';
int ch;
int note;
int tempo = 120;
int len = 4;
int octave = 4;
int velocity = 0x60;
int value = 0;
int dot = 0;
 
//==============================================================================
int main()
{
//	LPCTSTR mml = "ccggaag2ffeeddc2";
	LPCTSTR mml = "r1r1 cdefedcr efgagfer crcrcrcr l8ccddeefferdrl4cr";
//	LPCTSTR mml = "o5co4b8.a16g.f8edc.g8a.a8b.b8o5c2.";
 
	ch = 0;
	ticks = 0;
	SeqInsert(ticks, MAKESMSG(PROGRAM_CHANGE, ch, ACOUSTIC_PIANO, 0));
	velocity = 0x70;
	ParseMML(mml + 5);
 
	ch = 1;
	ticks = 0;
	SeqInsert(ticks, MAKESMSG(PROGRAM_CHANGE, ch, ACCORDION, 0));
	velocity = 0x60;
	ParseMML(mml);
 
	// play
	HMIDIOUT hmo;
	midiOutOpen(&hmo, MIDI_MAPPER, NULL, 0, CALLBACK_NULL);
 
	DWORD start = timeGetTime();
	for (SEQ::iterator it = seq.begin(); it != seq.end(); it++) {
		while (timeGetTime() - start < (*it).first) Sleep(1);
		midiOutShortMsg(hmo, (*it).second);
	}
 
	midiOutReset(hmo);
	midiOutClose(hmo);
	return 0;
}
 
void ParseMML(LPCTSTR mml)
{
	for (LPCTSTR p = mml; *p; p++) {
		switch (*p) {
		case ' ':
			break;
		case '.':
			dot++;
			break;
		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			value = value * 10 + (*p - '0');
			break;
		case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
			Command('n');
			note = (octave + 1) * 12 + noteList[*p - 'a'];
			break;
		case 'l': case 'o': case 'r': case 't':
			Command(*p);
			break;
		}
	}
	Command(' ');
}
 
void Command(TCHAR newCmd)
{
	DWORD wait = 240000 / (tempo * (value ? value : len));
	if (dot) wait += wait / 2;
 
	switch (cmd) {
	case 'l':
		len = value;
		break;
	case 'n':
		SeqInsert(ticks, MAKESMSG(NOTE_ON, ch, note, velocity));
		ticks += wait;
		SeqInsert(ticks - 1, MAKESMSG(NOTE_OFF, ch, note, 0));
		break;
	case 'o':
		octave = value;
		break;
	case 'r':
		ticks += wait;
		break;
	case 't':
		tempo = value;
		break;
	}
 
	cmd = newCmd;
	value = 0;
	dot = 0;
}
 
void SeqInsert(DWORD ticks, DWORD smsg)
{
	seq.insert(SEQ::value_type(ticks, smsg));
}
 
最終更新:2013年01月24日 20:42