開発環境 |
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