--- a
+++ b/newmidi.cpp
@@ -0,0 +1,214 @@
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <iostream>
+using namespace std;
+#include <windows.h>
+#include "newmidi.h"
+#include "util.h"
+#include "winutil.h"
+#include "error.h"
+
+#pragma comment(lib, "winmm")
+#pragma warning(disable: 4311 4312)
+
+#define SHORT_MESSAGE(channel, note, vol)	(((channel) & 0x0f) | 0x90) | \
+											(((note) & 0xff) << 8) | \
+											(((vol) & 0x7f) << 16)
+#define SET_INSTRUMENT(instr)				(0xc0 | (((instr) & 0xff) << 8) | (0 << 16))
+
+struct midi_callback_info {
+	midi *pmidi;
+	midi_note note;
+};
+
+static char instruments[MIDI_INSTRUMENTS][MIDI_MAX_INSTRUMENT_NAME] = MIDI_INSTRUMENT_NAMES;
+
+void CALLBACK midi_callback(UINT timer_id, UINT msg, DWORD user_data, DWORD dw1, DWORD dw2);
+
+midi_note volume_byte(double v)
+{
+	return round(v*127.0);
+}
+
+unsigned short volume_word(double v)
+{
+	return round(v*65535.0);
+}
+
+void check_note(midi_note note)
+{
+	if(note < 0 || note >= 128)
+		throw(error("midi", "illegal note %d", int(note)));
+}
+
+void check_volume(double volume)
+{
+	if(volume < 0 || volume > 1)
+		throw(error("midi", "illegal volume %g", volume));
+}
+
+void check_instrument(unsigned char inst)
+{
+	if(inst < 0 || inst >= 128)
+		throw(error("midi", "illegal instrument %d", int(inst)));
+}
+
+void check_channel(unsigned char channel)
+{
+	if(channel < 0 || channel >= MIDI_CHANNELS)
+		throw(error("midi", "illegal channel %d", int(channel)));
+}
+
+midi::midi(unsigned int device)
+{
+	if(device >= midiOutGetNumDevs())
+		throw(error("midi", "device %d does not exist", int(device)));
+	if(midiOutOpen(&_handle, device, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR)
+		throw(error("midi", "could not open midi device"));
+	_channel = 0;
+	_instrument = MIDI_DEFAULT_INSTRUMENT;
+	for(int i = 0; i < MIDI_CHANNELS; i++) _playing[i].clear();
+	_beeping = false;
+	_t = 0;
+}
+
+midi::~midi()
+{
+	midiOutClose(_handle);
+}
+
+void midi::play(midi_note note, double volume)
+{
+	check_note(note);
+	unsigned char vol;
+	if(volume == MIDI_DEFAULT_VOLUME)
+		vol = MIDI_DEFAULT_VELOCITY;
+	else {
+		check_volume(volume);
+		vol = volume_byte(volume);
+	}
+	DWORD msg = SHORT_MESSAGE(_channel, note, vol);
+	midiOutShortMsg(_handle, msg);
+	_playing[_channel].push_back(note);
+}
+
+void midi::stop(midi_note note)
+{
+	check_note(note);
+	DWORD msg = SHORT_MESSAGE(_channel, note, 0);
+	midiOutShortMsg(_handle, msg);
+	vector<midi_note>::iterator new_end = remove(_playing[_channel].begin(), _playing[_channel].end(), note);
+	_playing[_channel].erase(new_end, _playing[_channel].end());
+}
+
+void midi::stop()
+{
+	for(vector<midi_note>::iterator it = _playing[_channel].begin(); it != _playing[_channel].end(); it++) {
+		DWORD msg = SHORT_MESSAGE(_channel, *it, 0);
+		midiOutShortMsg(_handle, msg);
+	}
+	_playing[_channel].clear();
+}
+
+void midi::stop_all()
+{
+	for(int i = 0; i < MIDI_CHANNELS; i++) {
+		for(vector<midi_note>::iterator it = _playing[i].begin(); it != _playing[i].end(); it++) {
+			DWORD msg = SHORT_MESSAGE(i, *it, 0);
+			midiOutShortMsg(_handle, msg);
+		}
+		_playing[i].clear();
+	}
+}
+
+void midi::auto_play(double dur, midi_note note, double volume)
+{
+	play(note, volume);
+	midi_callback_info *p = new midi_callback_info;
+	p->pmidi = this;
+	p->note = note;
+	DWORD user_data = (DWORD) p;
+	set_event(dur, midi_callback, user_data);
+}
+
+void CALLBACK midi_callback(UINT timer_id, UINT msg, DWORD user_data, DWORD dw1, DWORD dw2)
+{
+	midi_callback_info *p = (midi_callback_info *) user_data;
+	p->pmidi->stop(p->note);
+	delete p;
+}
+
+void midi::beep(midi_note note, double dur)
+{
+	play(note);
+	_beep_begin = _t;
+	_beep_end = _beep_begin + dur;
+	_beeping = true;
+}
+
+void midi::beep_check()
+{
+	if(_beeping && _t > _beep_end) beep_stop();
+}
+
+void midi::beep_stop()
+{
+	stop();
+	_beeping = false;
+}
+
+void midi::volume(double v)
+{
+	check_volume(v);
+	volume(v, v);
+}
+
+void midi::volume(double v_left, double v_right)
+{
+	check_volume(v_left);
+	check_volume(v_right);
+	DWORD l = volume_word(v_left), r = volume_word(v_right);
+	midiOutSetVolume(_handle, (r << 16) | l);
+}
+
+void midi::instrument(int inst)
+{
+	check_instrument(inst);
+	midiOutShortMsg(_handle, SET_INSTRUMENT(inst));
+	_instrument = inst;
+}
+
+bool midi::instrument(string inst)
+{
+	for(int i = 0; i < MIDI_INSTRUMENTS; i++) {
+		string name(instruments[i]);
+		if(name.find(inst) != string::npos) {
+			instrument(i);
+			return true;
+		}
+	}
+	return false;
+}
+
+string midi::instrument()
+{
+	return instrument_name(_instrument);
+}
+
+string midi::instrument_name(int inst)
+{
+	check_instrument(inst);
+	return string(instruments[inst]);
+}
+
+void midi::channel(unsigned char channel)
+{
+	check_channel(channel);
+	_channel = channel;
+}
+
+unsigned char midi::channel()
+{
+	return _channel;
+}