/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2009.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: sgx/src/sgx/audio/midiin.cpp

*/

#include "sgx/core/core.hpp"
#include "sgx/audio/midi.hpp"

#include "domains/midi/midiutil.hpp"
#include "domains/midi/midinotes.hpp"

using std::memset;

/**
Typical invocation:

  	sgxMidiIn *pHandle = new sgxMidiIn();
	sgxMidiInDevice *pMidiIn = sgxMidiSystem::openMidiIn(pHandle, NULL);
*/
sgxMidiIn::sgxMidiIn() {
	m_pHandler = NULL;
	m_bRunning = FALSE;
	m_pDevice = NULL;

	memset(parameterStatus, '\0', sizeof(parameterStatus));
	memset(currentProgram, '\0', sizeof(currentProgram));
	memset(currentPressure, '\0', sizeof(currentPressure));
	memset(pitchWheel, '\0', sizeof(pitchWheel));
	
	resetNotes();
}

void sgxMidiIn::flush() {
	if (m_pDevice) {
		m_pDevice->flush();
	}
}

void sgxMidiIn::close() {
	if (m_pDevice) {
		m_pDevice->close();
	}
	m_pDevice = NULL;
	m_bRunning = FALSE;
}

tBOOL sgxMidiIn::isNoteOn(tUINT32 channel, tUINT32 note) {

	return noteStatus[channel*128 + note] ? TRUE : FALSE;
}

int sgxMidiIn::getProgram(tUINT32 channel) {
	return currentProgram[channel];
}

int sgxMidiIn::getPressure(tUINT32 channel) {
	return currentPressure[channel];
}

int sgxMidiIn::getPitchWheel(tUINT32 channel) {
	return pitchWheel[channel];
}

void sgxMidiIn::start() {
	m_bRunning = TRUE;
}

void sgxMidiIn::stop() {
	m_bRunning = FALSE;
}

void sgxMidiIn::resetNotes() {
	memset(noteStatus, '\0', sizeof(noteStatus));
}

int *sgxMidiIn::getNoteStatus() {
	return noteStatus;
}

sgxMidiInprocess *sgxMidiIn::setprocessHandler(sgxMidiInprocess *m_pHandler) {
	sgxMidiInprocess *last = m_pHandler;
	this->m_pHandler = m_pHandler;
	return last;
}

tBOOL sgxMidiIn::open(sgxMidiInDevice *pDevice) {
	m_pDevice = pDevice;
	return TRUE;
}

void sgxMidiIn::midiClockprocess() {
	if (!m_bRunning) {
		return;
	}

	if (m_pHandler) {
		if (m_pHandler->clock()) {
			return;
		}
	}
}

void sgxMidiIn::midiEventprocess(tUINT32 msg, tUINT32 channel, tUINT32 note, tUINT32 volume) {
	if (!m_bRunning) {
		return;
	}

	if (m_pHandler) {
		if (m_pHandler->event(msg, channel, note, volume)) {
			return;
		}
	}
	//
	switch(msg) {
		case msgNoteOff:
			noteStatus[channel*128 + note] = FALSE;
			break;
		case msgNoteOn:
			noteStatus[channel*128 + note] = TRUE;
			break;
		case msgNoteKeyPressure:
			break;
		case msgSetParameter:
			parameterStatus[note] = volume;
			break;
		case msgSetProgram:
			currentProgram[channel] = note;
			break;
		case msgChangePressure:
			currentPressure[channel] = note;
			break;
		case msgSetPitchWheel:
			pitchWheel[channel] = (note<<7) | volume;
			break;
	}
}

void	sgxMidiIn::midiSysexprocess(tBYTE *pData, tUINT32 dataSize)
{
	if (!m_bRunning) {
		return;
	}

	if (m_pHandler) {
		if (m_pHandler->sysex(pData, dataSize)) {
			return;
		}
	}
}
