/*
 *  ofxMidi.cpp
 *  openFrameworks MIDI Addon.
 *
 *  Created by Andy Best
 *	www.andybest.net
 *
 *	+Kyle McDonald
 */

#include "ofxMidi.h"

ofxMidiOut::ofxMidiOut() {
#if defined( TARGET_OSX )
	OSStatus err;
	err = MIDIClientCreate(CFSTR("OpenFrameworks"), NULL, NULL, &_midiClient);
	if (err)
		fprintf(stderr, "Couldn't create client %i", err);
	err = MIDISourceCreate(_midiClient, CFSTR("OpenFrameworks Virtual Port"), &_source);
	if (err) {
		fprintf(stderr, "Couldn't create client %i", err);
		MIDIClientDispose(_midiClient);
	}
#endif
#if defined( TARGET_WIN32 )
	int devs = midiOutGetNumDevs();
	usePort(devs - 1);
#endif
}

ofxMidiOut::ofxMidiOut(int port) {
	usePort(port);
}

void ofxMidiOut::usePort(int port) {
#if defined( TARGET_OSX)
	fprintf(stderr, "Cannot open port %i", port);
#endif
#if defined( TARGET_WIN32 )
	int flag = midiOutOpen(&device, port, 0, 0, CALLBACK_NULL);
	if (flag != MMSYSERR_NOERROR)
		printf("Couldn't open MIDI port %i.\n", port);
#endif
}

// requires a lowercase letter
unsigned char ofxMidiOut::getNoteNumber(char letter, int octave) {
	return (octave + 1) * 12 + ((int) letter) - 99;
}

void ofxMidiOut::sendNoteOn (unsigned char note, unsigned char velocity) {
	sendNoteOn(1, note, velocity);
}

void ofxMidiOut::sendNoteOn (unsigned char channel, unsigned char note, unsigned char velocity) {
	sendMidi(0x90, channel, note, velocity);
}

void ofxMidiOut::sendNoteOff (unsigned char note, unsigned char velocity) {
	sendNoteOff(1, note, velocity);
}

void ofxMidiOut::sendNoteOff (unsigned char channel, unsigned char note, unsigned char velocity) {
	sendMidi(0x80, channel, note, velocity);
}

void ofxMidiOut::sendControlChange (unsigned char channel, unsigned char controlNum, unsigned char controlVal) {
	sendMidi(0xB0, channel, controlNum, controlVal);
}

void ofxMidiOut::sendMidi (unsigned char midiType, unsigned char channel, unsigned char a, unsigned char b) {
#if defined( TARGET_OSX )
	Byte data[3];
	Byte *dataPtr = data;

	data[0] = (Byte)( midiType | (channel - 1));
	data[1] = (Byte) a;
	data[2] = (Byte) b;

	MIDIPacketList pktlist;
	MIDIPacket* packet;
	packet = MIDIPacketListInit(&pktlist);
	packet = MIDIPacketListAdd( &pktlist, sizeof(MIDIPacketList), packet, AudioGetCurrentHostTime(), 3, dataPtr);

	MIDIReceived(_source, &pktlist);
#endif
#if defined( TARGET_WIN32 )
	message.data[0] = midiType | ((channel - 1) << 4);
	message.data[1] = a;
	message.data[2] = b;
	message.data[3] = 0;
	midiOutShortMsg(device, message.word);
#endif
}
