-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patha_mpu401.c
301 lines (218 loc) · 7.24 KB
/
a_mpu401.c
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
Copyright (C) 2023 Frenkel Smeijers
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**********************************************************************
module: MPU401.C
author: James R. Dose
date: January 1, 1994
Low level routines to support sending of MIDI data to MPU401
compatible MIDI interfaces.
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#include <conio.h>
#include <dos.h>
#include "id_heads.h"
#include "a_mpu401.h"
#define MPU_NotFound -1
#define MPU_UARTFailed -2
#define MPU_ReadyToWrite 0x40
#define MPU_ReadyToRead 0x80
#define MPU_CmdEnterUART 0x3f
#define MPU_CmdReset 0xff
#define MPU_CmdAcknowledge 0xfe
#define MIDI_NOTE_OFF 0x80
#define MIDI_NOTE_ON 0x90
#define MIDI_POLY_AFTER_TCH 0xA0
#define MIDI_CONTROL_CHANGE 0xB0
#define MIDI_PROGRAM_CHANGE 0xC0
#define MIDI_AFTER_TOUCH 0xD0
#define MIDI_PITCH_BEND 0xE0
#define MPU_DefaultAddress 0x330
static int32_t MPU_BaseAddr = MPU_DefaultAddress;
#define MPU_Delay 0x5000;
/*---------------------------------------------------------------------
Function: MPU_SendMidi
Sends a byte of MIDI data to the music device.
---------------------------------------------------------------------*/
static void MPU_SendMidi(int32_t data)
{
int32_t port = MPU_BaseAddr + 1;
uint32_t count = MPU_Delay;
while (count > 0)
{
// check if status port says we're ready for write
if (!(inp(port) & MPU_ReadyToWrite))
break;
count--;
}
port--;
// Send the midi data
outp(port, data);
}
/*---------------------------------------------------------------------
Function: MPU_NoteOff
Sends a full MIDI note off event out to the music device.
---------------------------------------------------------------------*/
void MPU_NoteOff(int32_t channel, int32_t key, int32_t velocity)
{
MPU_SendMidi(MIDI_NOTE_OFF | channel);
MPU_SendMidi(key);
MPU_SendMidi(velocity);
}
/*---------------------------------------------------------------------
Function: MPU_NoteOn
Sends a full MIDI note on event out to the music device.
---------------------------------------------------------------------*/
void MPU_NoteOn(int32_t channel, int32_t key, int32_t velocity)
{
MPU_SendMidi(MIDI_NOTE_ON | channel);
MPU_SendMidi(key);
MPU_SendMidi(velocity);
}
/*---------------------------------------------------------------------
Function: MPU_PolyAftertouch
Sends a full MIDI polyphonic aftertouch event out to the music device.
---------------------------------------------------------------------*/
void MPU_PolyAftertouch(int32_t channel, int32_t key, int32_t pressure)
{
MPU_SendMidi(MIDI_POLY_AFTER_TCH | channel);
MPU_SendMidi(key);
MPU_SendMidi(pressure);
}
/*---------------------------------------------------------------------
Function: MPU_ControlChange
Sends a full MIDI control change event out to the music device.
---------------------------------------------------------------------*/
void MPU_ControlChange(int32_t channel, int32_t number, int32_t value)
{
MPU_SendMidi(MIDI_CONTROL_CHANGE | channel);
MPU_SendMidi(number);
MPU_SendMidi(value);
}
/*---------------------------------------------------------------------
Function: MPU_ProgramChange
Sends a full MIDI program change event out to the music device.
---------------------------------------------------------------------*/
void MPU_ProgramChange(int32_t channel, int32_t program)
{
MPU_SendMidi(MIDI_PROGRAM_CHANGE | channel);
MPU_SendMidi(program);
}
/*---------------------------------------------------------------------
Function: MPU_ChannelAftertouch
Sends a full MIDI channel aftertouch event out to the music device.
---------------------------------------------------------------------*/
void MPU_ChannelAftertouch(int32_t channel, int32_t pressure)
{
MPU_SendMidi(MIDI_AFTER_TOUCH | channel);
MPU_SendMidi(pressure);
}
/*---------------------------------------------------------------------
Function: MPU_PitchBend
Sends a full MIDI pitch bend event out to the music device.
---------------------------------------------------------------------*/
void MPU_PitchBend(int32_t channel, int32_t lsb, int32_t msb)
{
MPU_SendMidi(MIDI_PITCH_BEND | channel);
MPU_SendMidi(lsb);
MPU_SendMidi(msb);
}
/*---------------------------------------------------------------------
Function: MPU_SendCommand
Sends a command to the MPU401 card.
---------------------------------------------------------------------*/
static void MPU_SendCommand(int32_t data)
{
int32_t port = MPU_BaseAddr + 1;
uint32_t count = 0xffff;
while (count > 0)
{
// check if status port says we're ready for write
if (!(inp(port) & MPU_ReadyToWrite))
break;
count--;
}
outp(port, data);
}
/*---------------------------------------------------------------------
Function: MPU_Reset
Resets the MPU401 card.
---------------------------------------------------------------------*/
int32_t MPU_Reset(void)
{
int32_t port = MPU_BaseAddr + 1;
uint32_t count = 0xffff;
// Output "Reset" command via Command port
MPU_SendCommand(MPU_CmdReset);
// Wait for status port to be ready for read
while (count > 0)
{
if (!(inp(port) & MPU_ReadyToRead))
{
port--;
// Check for a successful reset
if (inp(port) == MPU_CmdAcknowledge)
return MPU_Ok;
port++;
}
count--;
}
// Failed to reset : MPU-401 not detected
return MPU_NotFound;
}
/*---------------------------------------------------------------------
Function: MPU_EnterUART
Sets the MPU401 card to operate in UART mode.
---------------------------------------------------------------------*/
static int32_t MPU_EnterUART(void)
{
int32_t port = MPU_BaseAddr + 1;
uint32_t count = 0xffff;
// Output "Enter UART" command via Command port
MPU_SendCommand(MPU_CmdEnterUART);
// Wait for status port to be ready for read
while (count > 0)
{
if (!(inp(port) & MPU_ReadyToRead))
{
port--;
// Check for a successful reset
if (inp(port) == MPU_CmdAcknowledge)
return MPU_Ok;
port++;
}
count--;
}
// Failed to reset : MPU-401 not detected
return MPU_UARTFailed;
}
/*---------------------------------------------------------------------
Function: MPU_Init
Detects and initializes the MPU401 card.
---------------------------------------------------------------------*/
int32_t MPU_Init(int32_t addr)
{
int32_t status;
int32_t count = 4;
MPU_BaseAddr = addr;
while (count > 0)
{
status = MPU_Reset();
if (status == MPU_Ok)
return MPU_EnterUART();
count--;
}
return status;
}