summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/imagedev/midiin.h
blob: d557a47b7c412ee3fd673ae0e9ed8b80748cbeba (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// license:BSD-3-Clause
// copyright-holders:R. Belmont,Aaron Giles
/*********************************************************************

    midiin.h

    MIDI In image device

*********************************************************************/

#ifndef MAME_IMAGEDEV_MIDIIN_H
#define MAME_IMAGEDEV_MIDIIN_H

#pragma once

#include "diserial.h"

#include "interface/midiport.h"

#include <memory>
#include <string>
#include <system_error>
#include <utility>


/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

class midiin_device :    public device_t,
						public device_image_interface,
						public device_serial_interface
{
public:
	// construction/destruction
	midiin_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
	~midiin_device();

	auto input_callback() { return m_input_cb.bind(); }

	// device_image_interface implementation
	virtual std::pair<std::error_condition, std::string> call_load() override;
	virtual void call_unload() override;

	// image device
	virtual bool is_readable()  const noexcept override { return true; }
	virtual bool is_writeable() const noexcept override { return false; }
	virtual bool is_creatable() const noexcept override { return false; }
	virtual bool is_reset_on_load() const noexcept override { return false; }
	virtual const char *file_extensions() const noexcept override { return "mid,syx"; }
	virtual bool core_opens_image_file() const noexcept override { return false; }
	virtual const char *image_type_name() const noexcept override { return "midiin"; }
	virtual const char *image_brief_type_name() const noexcept override { return "min"; }

protected:
	// device_t implementation
	virtual ioport_constructor device_input_ports() const override;
	virtual void device_start() override;
	virtual void device_reset() override;

	// device_serial_interface implementation
	virtual void tra_complete() override;    // Tx completed sending byte
	virtual void tra_callback() override;    // Tx send bit

	TIMER_CALLBACK_MEMBER(midi_update);

private:
	static const int XMIT_RING_SIZE = (8192*4*4);

	void xmit_char(uint8_t data);

	std::unique_ptr<osd::midi_input_port> m_midi;
	required_ioport m_config;
	emu_timer *m_timer;
	devcb_write_line        m_input_cb;
	uint8_t m_xmitring[XMIT_RING_SIZE];
	int m_xmit_read, m_xmit_write;
	bool m_tx_busy;

	// internal helper class for parsing
	class midi_parser
	{
	public:
		// minimal error class
		class error
		{
		public:
			error(char const *description) : m_description(description) { }
			char const *description() const { return m_description; }
		private:
			char const *m_description;
		};

		// construction
		midi_parser(util::random_read &stream, u32 length, u32 offset);

		// end of buffer?
		bool eob() const { return (m_offset >= m_length); }

		// create a subset
		midi_parser subset(u32 length);

		// change position within buffer
		midi_parser &rewind(u32 count);
		midi_parser &reset() { return rewind(m_offset); }

		// read data of various sizes and endiannesses
		u8 byte();
		u16 word_be();
		u32 triple_be();
		u32 dword_be();
		u32 dword_le();

		// special variable reader for MIDI
		u32 variable();

	private:
		// internal helper
		void check_bounds(u32 length);

		// internal state
		util::random_read &m_stream;
		u32 m_length;
		u32 m_offset;
	};

	// internal helper class reperesenting an event at a given
	// time containing MIDI data
	class midi_event
	{
	public:
		// constructor
		midi_event(u32 tick) :
			m_tick(tick) { }

		// simple getters
		u32 tick() const { return m_tick; }
		attotime const &time() const { return m_time; }
		std::vector<u8> const &data() const { return m_data; }

		// simple setters
		void set_time(attotime const &time) { m_time = time; }

		// append data to the buffer
		midi_event &append(u8 byte) { m_data.push_back(byte); return *this; }

	private:
		// internal state
		u32 m_tick;
		attotime m_time;
		std::vector<u8> m_data;
	};

	// internal helper class representing a MIDI sequence
	class midi_sequence
	{
	public:
		// constructor
		midi_sequence() : m_iterator(m_list.begin()) { }

		// clear the sequence
		void clear() { m_list.clear(); }

		// parse a new sequence
		std::error_condition parse(util::random_read &stream, u32 length);

		// rewind to the start of time
		void rewind(attotime const &basetime);
		midi_event *current_event() const { return (m_iterator == m_list.end()) ? nullptr : &(*m_iterator); }
		midi_event *advance_event() { ++m_iterator; return current_event(); }
		attotime const &duration() { return m_list.back().time(); }

	private:
		// internal helpers
		midi_event &event_at(u32 tick);
		u32 parse_track_data(midi_parser &buffer, u32 start_tick);
		void parse_midi_data(midi_parser &buffer);
		void parse_sysex_data(midi_parser &buffer);

		// internal state
		std::list<midi_event> m_list;
		std::list<midi_event>::iterator m_iterator;
	};

	midi_sequence m_sequence;
	attotime m_sequence_start;
};

// device type definition
DECLARE_DEVICE_TYPE(MIDIIN, midiin_device)

// device iterator
typedef device_type_enumerator<midiin_device> midiin_device_enumerator;

#endif // MAME_IMAGEDEV_MIDIIN_H