1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /*
24  * IRIX dmedia support by Rainer Canavan <scumm@canavan.de>
25  *    some code liberated from seq.cpp and coremidi.cpp
26  */
27 
28 // Disable symbol overrides so that we can use system headers.
29 #define FORBIDDEN_SYMBOL_ALLOW_ALL
30 
31 #include "common/scummsys.h"
32 
33 #if defined(IRIX)
34 
35 #include "common/config-manager.h"
36 #include "common/error.h"
37 #include "common/textconsole.h"
38 #include "common/util.h"
39 #include "audio/musicplugin.h"
40 #include "audio/mpu401.h"
41 
42 #include <dmedia/midi.h>
43 #include <sys/types.h>
44 #include <bstring.h>
45 #include <unistd.h>
46 
47 ////////////////////////////////////////
48 //
49 // IRIX dmedia midi driver
50 //
51 ////////////////////////////////////////
52 
53 #define SEQ_MIDIPUTC 5
54 
55 class MidiDriver_DMEDIA : public MidiDriver_MPU401 {
56 public:
57 	MidiDriver_DMEDIA();
58 	int open();
isOpen() const59 	bool isOpen() const { return _isOpen; }
60 	void close();
61 	void send(uint32 b);
62 	void sysEx(const byte *msg, uint16 length);
63 
64 private:
65 	bool _isOpen;
66 	int _deviceNum;
67 	char *_midiportName;
68 	MDport _midiPort;
69 	int _fd;
70 };
71 
MidiDriver_DMEDIA()72 MidiDriver_DMEDIA::MidiDriver_DMEDIA() {
73 	_isOpen = false;
74 	_deviceNum = 0;
75 	_midiportName = NULL;
76 }
77 
open()78 int MidiDriver_DMEDIA::open() {
79 	int numinterfaces;
80 	int i;
81 	const char *var;
82 	char *portName;
83 
84 	if (_isOpen)
85 		return MERR_ALREADY_OPEN;
86 	_isOpen = true;
87 
88 	numinterfaces = mdInit();
89 	if (numinterfaces <= 0) {
90 		fprintf(stderr, "No MIDI interfaces configured.\n");
91 		perror("Cannot initialize libmd for sound output");
92 		return -1;
93 	}
94 
95 	if (getenv("RESIDUALVM_MIDIPORT")) {
96 		_deviceNum = atoi(getenv("RESIDUALVM_MIDIPORT"));
97 		_midiportName = mdGetName(_deviceNum);
98 	} else {
99 		var = ConfMan.get("dmedia_port").c_str();
100 		if (strlen(var) > 0) {
101 			for (i = 0; i < numinterfaces; i++) {
102 				portName = mdGetName(i);
103 				if (strcmp(var, portName) == 0) {
104 					_deviceNum = i;
105 					_midiportName = portName;
106 				}
107 			}
108 
109 		}
110 	}
111 
112 	_midiPort = mdOpenOutPort(_midiportName);
113 	if (!_midiPort) {
114 		warning("Failed to open MIDI interface %s", _midiportName);
115 		return -1;
116 	}
117 
118 	_fd = mdGetFd(_midiPort);
119 	if (!_fd) {
120 		warning("Failed to aquire filehandle for MIDI port %s", _midiportName);
121 		mdClosePort(_midiPort);
122 		return -1;
123 	}
124 
125 	mdSetStampMode(_midiPort, MD_NOSTAMP);  /* don't use Timestamps */
126 
127 	return 0;
128 }
129 
close()130 void MidiDriver_DMEDIA::close() {
131 	mdClosePort(_midiPort);
132 	_isOpen = false;
133 	_deviceNum = 0;
134 	_midiportName = NULL;
135 }
136 
send(uint32 b)137 void MidiDriver_DMEDIA::send(uint32 b) {
138 	MDevent event;
139 	byte status_byte = (b & 0x000000FF);
140 	byte first_byte = (b & 0x0000FF00) >> 8;
141 	byte second_byte = (b & 0x00FF0000) >> 16;
142 
143 
144 	event.sysexmsg = NULL;
145 	event.msg[0] = status_byte;
146 	event.msg[1] = first_byte;
147 	event.msg[2] = second_byte;
148 
149 	switch (status_byte & 0xF0) {
150 	case 0x80:      // Note Off
151 	case 0x90:      // Note On
152 	case 0xA0:      // Polyphonic Aftertouch
153 	case 0xB0:      // Controller Change
154 	case 0xE0:      // Pitch Bending
155 		event.msglen = 3;
156 		break;
157 	case 0xC0:      // Programm Change
158 	case 0xD0:      // Monophonic Aftertouch
159 		event.msglen = 2;
160 		break;
161 	default:
162 		warning("DMediaMIDI driver encountered unsupported status byte: 0x%02x", status_byte);
163 		event.msglen = 3;
164 		break;
165 	}
166 	if (mdSend(_midiPort, &event, 1) != 1) {
167 		warning("failed sending MIDI event (dump follows...)");
168 		warning("MIDI Event (len=%u):", event.msglen);
169 		for (int i = 0; i < event.msglen; i++) warning("%02x ", (int)event.msg[i]);
170 	}
171 }
172 
sysEx(const byte * msg,uint16 length)173 void MidiDriver_DMEDIA::sysEx (const byte *msg, uint16 length) {
174 	MDevent event;
175 	char buf [1024];
176 
177 	assert(length + 2 <= 256);
178 
179 	memcpy(buf, msg, length);
180 	buf[length] = MD_EOX;
181 	event.sysexmsg = buf;
182 	event.msglen = length;
183 	event.msg[0] = MD_SYSEX;
184 	event.msg[1] = 0;
185 	event.msg[2] = 0;
186 
187 	if (mdSend(_midiPort, &event, 1) != 1) {
188 		fprintf(stderr, "failed sending MIDI SYSEX event (dump follows...)\n");
189 		for (int i = 0; i < event.msglen; i++) warning("%02x ", (int)event.msg[i]);
190 	}
191 }
192 
193 
194 // Plugin interface
195 
196 class DMediaMusicPlugin : public MusicPluginObject {
197 public:
getName() const198 	const char *getName() const {
199 		return "DMedia";
200 	}
201 
getId() const202 	const char *getId() const {
203 		return "dmedia";
204 	}
205 
206 	MusicDevices getDevices() const;
207 	Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
208 };
209 
getDevices() const210 MusicDevices DMediaMusicPlugin::getDevices() const {
211 	int numinterfaces;
212 	int i;
213 	char *portName;
214 	MusicDevices devices;
215 
216 	// TODO: Return a different music type depending on the configuration
217 
218 	numinterfaces = mdInit();
219 	if (numinterfaces <= 0) {
220 		fprintf(stderr, "No MIDI interfaces configured.\n");
221 	}
222 
223 	for (i=0; i<numinterfaces; i++) {
224 		portName = mdGetName(0);
225 		fprintf(stderr, "device %i %s\n", i, portName);
226 		devices.push_back(MusicDevice(this, portName, MT_GM));
227 	}
228 
229 	return devices;
230 }
231 
createInstance(MidiDriver ** mididriver,MidiDriver::DeviceHandle) const232 Common::Error DMediaMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
233 	*mididriver = new MidiDriver_DMEDIA();
234 
235 	return Common::kNoError;
236 }
237 
238 //#if PLUGIN_ENABLED_DYNAMIC(DMEDIA)
239 	//REGISTER_PLUGIN_DYNAMIC(DMEDIA, PLUGIN_TYPE_MUSIC, DMediaMusicPlugin);
240 //#else
241 	REGISTER_PLUGIN_STATIC(DMEDIA, PLUGIN_TYPE_MUSIC, DMediaMusicPlugin);
242 //#endif
243 
244 #endif
245