/////////////////////////////////////////////////////////////////////////////
// File:        midi_types.h
// Author:      Cesar Mauri Loba (cesar at crea-si dot com)
// Copyright:   (C) 2011 Cesar Mauri Loba - CREA Software Systems
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////
#ifndef MIDI_TYPES
#define MIDI_TYPES

#include "spcore/basetypeimpl.h"

namespace mod_midi {

/**
	MIDI message type
*/
class CTypeMIDIMessageContents : public spcore::CTypeAny {
public:
	static inline const char* getTypeName() { return "midi_message"; }

	enum EMIDIKeys {
		MIDI_NOTE_ON= 0x9,
		MIDI_NOTE_OFF= 0x8,
		MIDI_PROGRAM_CHANGE= 0xC
	};

	virtual void SetStatus (unsigned char status) {
		m_message= (m_message & 0x00FFFF00) | status;
	}

	virtual void SetStatus (unsigned char key, unsigned char channel) {
		assert (!(key & 0xF0));
		assert (!(channel & 0xF0));
		CTypeMIDIMessageContents::SetStatus ((key << 4) | channel);
	}

	virtual void SetData1 (unsigned char data1) {
		m_message= (m_message & 0x00FF00FF) | (data1 << 8);
	}

	virtual void SetData2 (unsigned char data2) {
		m_message= (m_message & 0x0000FFFF) | (data2 << 16);
	}

	virtual unsigned char GetStatus () const {
		return (m_message & 0xFF);
	}

	virtual unsigned char GetKey () const {
		return (CTypeMIDIMessageContents::GetStatus() >> 4);
	}

	virtual unsigned char GetChannel () const {
		return (CTypeMIDIMessageContents::GetStatus() & 0xF);
	}

	virtual unsigned char GetData1 () const {
		return ((m_message >> 8) & 0xFF);
	}

	virtual unsigned char GetData2 () const {
		return ((m_message >> 16) & 0xFF);
	}

	virtual void SetNoteOn (unsigned char channel, unsigned char note, unsigned char velocity) {
		assert (!(note & 0x80));
		assert (!(velocity & 0x80));
		CTypeMIDIMessageContents::SetStatus (MIDI_NOTE_ON, channel);
		CTypeMIDIMessageContents::SetData1 (note);
		CTypeMIDIMessageContents::SetData2 (velocity);
	}

	virtual void SetNoteOff (unsigned char channel, unsigned char note, unsigned char velocity) {
		assert (!(note & 0x80));
		assert (!(velocity & 0x80));
		CTypeMIDIMessageContents::SetStatus (MIDI_NOTE_OFF, channel);
		CTypeMIDIMessageContents::SetData1 (note);
		CTypeMIDIMessageContents::SetData2 (velocity);
	}

	virtual void SetProgramChange (unsigned char channel, unsigned char instrument) {
		assert (!(instrument & 0x80));
		CTypeMIDIMessageContents::SetStatus (MIDI_PROGRAM_CHANGE, channel);
		CTypeMIDIMessageContents::SetData1 (instrument);
		CTypeMIDIMessageContents::SetData2 (0);
	}

	virtual unsigned int GetBuffer() const { return m_message; }

protected:
	CTypeMIDIMessageContents(int id)
	: spcore::CTypeAny(id)
	, m_message(0)
	{}

private:
	// The three bytes of the MIDI message are stored packed
	// in a single 32bit unsigned int
	unsigned int m_message; //, m_timestamp;
};

typedef spcore::SimpleType<CTypeMIDIMessageContents> CTypeMIDIMessage;
};

#endif
