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