// license:BSD-3-Clause
// copyright-holders:Carl
#include "emu.h"
#include "machine/midikbd.h"

DEFINE_DEVICE_TYPE(MIDI_KBD, midi_keyboard_device, "midi_kbd", "Generic MIDI Keyboard")

midi_keyboard_device::midi_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, MIDI_KBD, tag, owner, clock),
	device_serial_interface(mconfig, *this),
	m_out_tx_func(*this),
	m_keyboard(*this, "KEYBOARD")
{
}

void midi_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	if(!id)
	{
		const int keyboard_notes[24] =
		{
			0x3c,   // C1
			0x3d,   // C1#
			0x3e,   // D1
			0x3f,   // D1#
			0x40,   // E1
			0x41,   // F1
			0x42,   // F1#
			0x43,   // G1
			0x44,   // G1#
			0x45,   // A1
			0x46,   // A1#
			0x47,   // B1
			0x48,   // C2
			0x49,   // C2#
			0x4a,   // D2
			0x4b,   // D2#
			0x4c,   // E2
			0x4d,   // F2
			0x4e,   // F2#
			0x4f,   // G2
			0x50,   // G2#
			0x51,   // A2
			0x52,   // A2#
			0x53,   // B2
		};

		int i;

		uint32_t kbstate = m_keyboard->read();
		if(kbstate != m_keyboard_state)
		{
			for (i=0; i < 24; i++)
			{
				int kbnote = keyboard_notes[i];

				if ((m_keyboard_state & (1 << i)) != 0 && (kbstate & (1 << i)) == 0)
				{
					// key was on, now off -> send Note Off message
					push_tx(0x80);
					push_tx(kbnote);
					push_tx(0x7f);
				}
				else if ((m_keyboard_state & (1 << i)) == 0 && (kbstate & (1 << i)) != 0)
				{
					// key was off, now on -> send Note On message
					push_tx(0x90);
					push_tx(kbnote);
					push_tx(0x7f);
				}
			}
		}
		else
			// no messages, send Active Sense message instead
			push_tx(0xfe);

		m_keyboard_state = kbstate;
		if(is_transmit_register_empty())
			tra_complete();
	}
}

void midi_keyboard_device::device_start()
{
	set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); //8N1?
	set_tra_rate(clock());
	m_out_tx_func.resolve_safe();
	m_head = m_tail = 0;
	m_keyboard_timer = timer_alloc();
	m_keyboard_timer->adjust(attotime::from_msec(10), 0, attotime::from_msec(10));
}

void midi_keyboard_device::tra_callback()
{
	m_out_tx_func(transmit_register_get_data_bit());
}

void midi_keyboard_device::tra_complete()
{
	if(m_head != m_tail)
	{
		transmit_register_setup(m_buffer[m_tail]);
		++m_tail %= 16;
	}
}

INPUT_PORTS_START(midi_keyboard)
	PORT_START("KEYBOARD")
	PORT_BIT( 0x000001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 C1") PORT_CODE(KEYCODE_Q)
	PORT_BIT( 0x000002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 C1#") PORT_CODE(KEYCODE_W)
	PORT_BIT( 0x000004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 D1") PORT_CODE(KEYCODE_E)
	PORT_BIT( 0x000008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 D1#") PORT_CODE(KEYCODE_R)
	PORT_BIT( 0x000010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 E1") PORT_CODE(KEYCODE_T)
	PORT_BIT( 0x000020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 F1") PORT_CODE(KEYCODE_Y)
	PORT_BIT( 0x000040, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 F1#") PORT_CODE(KEYCODE_U)
	PORT_BIT( 0x000080, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 G1") PORT_CODE(KEYCODE_I)
	PORT_BIT( 0x000100, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 G1#") PORT_CODE(KEYCODE_O)
	PORT_BIT( 0x000200, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 A1") PORT_CODE(KEYCODE_A)
	PORT_BIT( 0x000400, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 A1#") PORT_CODE(KEYCODE_S)
	PORT_BIT( 0x000800, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 B1") PORT_CODE(KEYCODE_D)
	PORT_BIT( 0x001000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 C2") PORT_CODE(KEYCODE_F)
	PORT_BIT( 0x002000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 C2#") PORT_CODE(KEYCODE_G)
	PORT_BIT( 0x004000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 D2") PORT_CODE(KEYCODE_H)
	PORT_BIT( 0x008000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 D2#") PORT_CODE(KEYCODE_J)
	PORT_BIT( 0x010000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 E2") PORT_CODE(KEYCODE_K)
	PORT_BIT( 0x020000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 F2") PORT_CODE(KEYCODE_L)
	PORT_BIT( 0x040000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 F2#") PORT_CODE(KEYCODE_Z)
	PORT_BIT( 0x080000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 G2") PORT_CODE(KEYCODE_X)
	PORT_BIT( 0x100000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 G2#") PORT_CODE(KEYCODE_C)
	PORT_BIT( 0x200000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 A2") PORT_CODE(KEYCODE_V)
	PORT_BIT( 0x400000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 A2#") PORT_CODE(KEYCODE_B)
	PORT_BIT( 0x800000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 B2") PORT_CODE(KEYCODE_N)
INPUT_PORTS_END

ioport_constructor midi_keyboard_device::device_input_ports() const
{
	return INPUT_PORTS_NAME(midi_keyboard);
}
