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 * Raw output support by Michael Pearce
25 * Alsa support by Nicolas Noble <nicolas@nobis-crew.org> copied from
26 * both the QuickTime support and (vkeybd http://www.alsa-project.org/~iwai/alsa.html)
27 */
28
29 // Disable symbol overrides so that we can use system headers.
30 #define FORBIDDEN_SYMBOL_ALLOW_ALL
31
32 #include "common/scummsys.h"
33
34 #if defined(USE_SEQ_MIDI)
35
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 <fcntl.h>
43 #include <unistd.h>
44 #include <errno.h>
45
46 ////////////////////////////////////////
47 //
48 // Unix dev/sequencer driver
49 //
50 ////////////////////////////////////////
51
52 #define SEQ_MIDIPUTC 5
53
54 class MidiDriver_SEQ : public MidiDriver_MPU401 {
55 public:
56 MidiDriver_SEQ();
57 int open();
isOpen() const58 bool isOpen() const { return _isOpen; }
59 void close();
60 void send(uint32 b);
61 void sysEx(const byte *msg, uint16 length);
62
63 private:
64 bool _isOpen;
65 int device, _device_num;
66 };
67
MidiDriver_SEQ()68 MidiDriver_SEQ::MidiDriver_SEQ() {
69 _isOpen = false;
70 device = 0;
71 _device_num = 0;
72 }
73
open()74 int MidiDriver_SEQ::open() {
75 char *device_name;
76 char dev_seq[] = "/dev/sequencer";
77
78 if (_isOpen)
79 return MERR_ALREADY_OPEN;
80 _isOpen = true;
81 device = 0;
82
83 device_name = getenv("RESIDUALVM_MIDI");
84
85 if (device_name == NULL) {
86 warning("RESIDUALVM_MIDI environment variable not set, using /dev/sequencer");
87 device_name = dev_seq;
88 }
89
90 device = ::open((device_name), O_RDWR, 0);
91
92 if (device < 0) {
93 warning("Cannot open rawmidi device %s - using /dev/null (no music will be heard)",
94 device_name);
95 device = (::open(("/dev/null"), O_RDWR, 0));
96 if (device < 0)
97 error("Cannot open /dev/null to dump midi output");
98 }
99
100 if (getenv("RESIDUALVM_MIDIPORT"))
101 _device_num = atoi(getenv("RESIDUALVM_MIDIPORT"));
102 return 0;
103 }
104
close()105 void MidiDriver_SEQ::close() {
106 MidiDriver_MPU401::close();
107 ::close(device);
108 _isOpen = false;
109 }
110
send(uint32 b)111 void MidiDriver_SEQ::send(uint32 b) {
112 unsigned char buf[256];
113 int position = 0;
114
115 switch (b & 0xF0) {
116 case 0x80:
117 case 0x90:
118 case 0xA0:
119 case 0xB0:
120 case 0xE0:
121 buf[position++] = SEQ_MIDIPUTC;
122 buf[position++] = (unsigned char)b;
123 buf[position++] = _device_num;
124 buf[position++] = 0;
125 buf[position++] = SEQ_MIDIPUTC;
126 buf[position++] = (unsigned char)((b >> 8) & 0x7F);
127 buf[position++] = _device_num;
128 buf[position++] = 0;
129 buf[position++] = SEQ_MIDIPUTC;
130 buf[position++] = (unsigned char)((b >> 16) & 0x7F);
131 buf[position++] = _device_num;
132 buf[position++] = 0;
133 break;
134 case 0xC0:
135 case 0xD0:
136 buf[position++] = SEQ_MIDIPUTC;
137 buf[position++] = (unsigned char)b;
138 buf[position++] = _device_num;
139 buf[position++] = 0;
140 buf[position++] = SEQ_MIDIPUTC;
141 buf[position++] = (unsigned char)((b >> 8) & 0x7F);
142 buf[position++] = _device_num;
143 buf[position++] = 0;
144 break;
145 default:
146 warning("MidiDriver_SEQ::send: unknown: %08x", (int)b);
147 break;
148 }
149 if (write(device, buf, position) == -1)
150 warning("MidiDriver_SEQ::send: write failed (%s)", strerror(errno));
151 }
152
sysEx(const byte * msg,uint16 length)153 void MidiDriver_SEQ::sysEx(const byte *msg, uint16 length) {
154 unsigned char buf [266*4];
155 int position = 0;
156 const byte *chr = msg;
157
158 assert(length + 2 <= 266);
159
160 buf[position++] = SEQ_MIDIPUTC;
161 buf[position++] = 0xF0;
162 buf[position++] = _device_num;
163 buf[position++] = 0;
164 for (; length; --length, ++chr) {
165 buf[position++] = SEQ_MIDIPUTC;
166 buf[position++] = (unsigned char) *chr & 0x7F;
167 buf[position++] = _device_num;
168 buf[position++] = 0;
169 }
170 buf[position++] = SEQ_MIDIPUTC;
171 buf[position++] = 0xF7;
172 buf[position++] = _device_num;
173 buf[position++] = 0;
174
175 if (write(device, buf, position) == -1)
176 warning("MidiDriver_SEQ::send: write failed (%s)", strerror(errno));
177 }
178
179
180 // Plugin interface
181
182 class SeqMusicPlugin : public MusicPluginObject {
183 public:
getName() const184 const char *getName() const {
185 return "SEQ";
186 }
187
getId() const188 const char *getId() const {
189 return "seq";
190 }
191
192 MusicDevices getDevices() const;
193 Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
194 };
195
getDevices() const196 MusicDevices SeqMusicPlugin::getDevices() const {
197 MusicDevices devices;
198 // TODO: Return a different music type depending on the configuration
199 // TODO: List the available devices
200 devices.push_back(MusicDevice(this, "", MT_GM));
201 return devices;
202 }
203
createInstance(MidiDriver ** mididriver,MidiDriver::DeviceHandle) const204 Common::Error SeqMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
205 *mididriver = new MidiDriver_SEQ();
206
207 return Common::kNoError;
208 }
209
210 //#if PLUGIN_ENABLED_DYNAMIC(SEQ)
211 //REGISTER_PLUGIN_DYNAMIC(SEQ, PLUGIN_TYPE_MUSIC, SeqMusicPlugin);
212 //#else
213 REGISTER_PLUGIN_STATIC(SEQ, PLUGIN_TYPE_MUSIC, SeqMusicPlugin);
214 //#endif
215
216 #endif
217