-
Notifications
You must be signed in to change notification settings - Fork 2
/
emu8kmid.c
428 lines (344 loc) · 12.2 KB
/
emu8kmid.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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/* ______ ___ ___
* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
* \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
* \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
* \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
* \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
* /\____/
* \_/__/
* By Shawn Hargreaves,
* 1 Salisbury Road,
* Market Drayton,
* Shropshire,
* England, TF9 1AJ.
*
* This file written by George Foot.
*
* AWE32/EMU8000 driver for the MIDI player.
*
* See readme.txt for copyright information.
*
* Modified by J. Flynn 3/7/98 to remove floating log calculations
* during interrupt - replaced by precomputed lookup table.
*/
#ifndef DJGPP
#error This file should only be used by the djgpp version of Allegro
#endif
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "allegro.h"
#include "internal.h"
#include "string.h" // GB 2014
#include "emu8k.h"
/* Variables from awedata.c, containing the envelope data from synthgm.sf2 */
extern short int _awe_sf_defaults[];
extern int _awe_sf_num_presets;
extern short int _awe_sf_presets[];
extern short int _awe_sf_splits[];
extern short int _awe_sf_gens[];
extern int _awe_sf_sample_data[];
/* external interface to the AWE32 driver */
static int awe32_detect();
static int awe32_init(int voices);
static void awe32_exit();
static void awe32_key_on(int inst, int note, int bend, int vol, int pan);
static void awe32_key_off(int voice);
static void _awe32_do_note(int inst, int note, int bend, int vol, int pan);
static void awe32_set_volume (int voice, int vol);
static void awe32_set_pitch (int voice, int note, int bend);
static void translate_soundfont_into_something_useful();
static void destroy_useful_version_of_soundfont();
static struct midi_preset_t { /* struct to hold envelope data for each preset */
int num_splits; /* number of splits in this preset */
struct envparms_t **split; /* array of num_splits pointers to envelope data */
} *midi_preset; /* global variable to hold the data */
static struct envparms_t **voice_envelope; /* array of pointers pointing at the envelope playing on each voice */
static int *exclusive_class_info; /* exclusive class information */
static char awe32_desc[256] = "not initialised";
MIDI_DRIVER midi_awe32 = {
"AWE32/EMU8000", /* name */
awe32_desc, /* desc */
32, 0, 32, 32, -1, -1, /* voices, basevoice, max_voices, def_voices, xmin, xmax */
awe32_detect, /* detect */
awe32_init, /* init */
awe32_exit, /* exit */
NULL, /* mixer_volume */
NULL, /* raw_midi */
_dummy_load_patches, /* load_patches */
_dummy_adjust_patches, /* adjust_patches */
awe32_key_on, /* key_on */
awe32_key_off, /* key_off */
awe32_set_volume, /* set_volume */
awe32_set_pitch, /* set_pitch */
_dummy_noop2, /* set_pan */
_dummy_noop2 /* set_vibrato */
};
//jff 3/7/98 added to avoid floating point usage in interrupt
static const unsigned char attentbl[]=
{
255,255,221,199,184,172,162,154,147,141,135,130,125,121,117,113,
110,107,104,101, 98, 95, 93, 91, 88, 86, 84, 82, 80, 78, 76, 75,
73, 71, 70, 68, 67, 65, 64, 62, 61, 60, 59, 57, 56, 55, 54, 53,
51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 39, 38, 37,
36, 35, 34, 34, 33, 32, 31, 31, 30, 29, 28, 28, 27, 26, 25, 25,
24, 23, 23, 22, 22, 21, 20, 20, 19, 18, 18, 17, 17, 16, 16, 15,
14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7,
6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 1, 1, 0, 0, 0,
};
//jff 3/7/98 end addition
/* awe32_key_on:
* Triggers the specified voice. The instrument is specified as a GM
* patch number, pitch as a midi note number, and volume from 0-127.
* The bend parameter is _not_ expressed as a midi pitch bend value.
* It ranges from 0 (no pitch change) to 0xFFF (almost a semitone sharp).
* Drum sounds are indicated by passing an instrument number greater than
* 128, in which case the sound is GM percussion key #(inst-128).
*/
static void awe32_key_on(int inst, int note, int bend, int vol, int pan) {
if (inst > 127) { /* drum sound? */
_awe32_do_note (128,inst-128,bend,vol,pan);
} else { /* regular instrument */
_awe32_do_note (inst,note,bend,vol,pan);
}
}
static END_OF_FUNCTION(awe32_key_on);
/* _awe32_do_note:
* Actually plays the note as described above; the above function just remaps
* the drums.
*/
static void _awe32_do_note(int inst, int note, int bend, int vol, int pan) {
int voice;
int i;
envparms_t *env;
int key,vel;
int atten;
int pan_pos;
/* EMU8000 pan is back-to-front and twice the scale */
pan = 0x100-2*pan;
if (pan>0xff) pan = 0xff;
if (pan<0x00) pan = 0x00;
for (i=0;i<midi_preset[inst].num_splits;i++) {
/* envelope for this split */
env=midi_preset[inst].split[i];
/* should we play this split? */
if ((note>=env->minkey)&&(note<=env->maxkey)&&( vol>=env->minvel)&&( vol<=env->maxvel)) {
/* get a voice (any voice) to play it on */
voice = _midi_allocate_voice (-1,-1);
/* did we get one? */
if (voice>=0) {
/* set the current envelope for this voice */
voice_envelope[voice]=env;
/* set pitch and velocity */
key = note*0x1000+bend;
vel = vol;
/* override key and velocity if envelope says so */
if ((env->key>=0)&&(env->key<=127)) key=env->key*0x1000;
if ((env->vel>=0)&&(env->vel<=127)) vel=env->vel;
/* check key and velocity numbers are within range */
if (key>0x7ffff) key=0x7ffff;
if (key<0) key=0;
if (vel>127) vel=127;
if (vel<0) vel=0;
/* add one-off information to the envelope (these have no side-effects on the other voices using this envelope) */
env->ip=env->ipbase+(env->ipscale*key)/1200;
/* remap MIDI velocity to attenuation */
if (vel)
//jff 3/7/98 was: env->atten + (-20/0.375*log(vel/127.0));
atten = env->atten + attentbl[vel];
else
atten = 0xff;
if (atten<0x00) atten = 0x00;
if (atten>0xff) atten = 0xff;
/* update it in the envelope */
env->ifatn=env->filter+atten;
/* modify pan with envelope's built-in pan */
if (pan<0x80) {
pan_pos = (pan*env->pan)/0x80;
} else {
pan_pos = env->pan + (pan-0x80)*(256-env->pan)/0x80;
}
if (pan_pos<0x00) pan_pos=0x00;
if (pan_pos>0xff) pan_pos=0xff;
/* update pan in the envelope */
env->psst = (pan_pos<<24) + env->loopst;
/* test exclusive class */
exclusive_class_info[voice] = (inst << 8) + env->exc;
if (env->exc) {
int chan;
for (chan = 0; chan < 32; chan++)
if ((chan != voice) && (exclusive_class_info[chan] == exclusive_class_info[voice]))
emu8k_terminatesound (chan);
}
/* start the note playing */
emu8k_startsound(voice,env);
}
}
}
}
static END_OF_FUNCTION(_awe32_do_note);
/* awe32_set_*:
* Modulation routines
*/
static void awe32_set_volume (int voice, int vol) {
int atten;
struct envparms_t *env;
/* get envelope in use on this voice */
env = voice_envelope[voice];
/* allow envelope to override new volume */
if ((env->vel>=0)&&(env->vel<=127)) vol=env->vel;
/* check velocity number is within range */
if (vol>127) vol=127;
if (vol<0) vol=0;
/* remap MIDI velocity to attenuation */
if (vol)
//jff 3/7/98 was: env->atten + (-20/0.375*log(vol/127.0));
atten = env->atten + attentbl[vol];
else
atten = 0xff;
if (atten<0x00) atten = 0x00;
if (atten>0xff) atten = 0xff;
emu8k_modulate_atten(voice,atten);
}
static END_OF_FUNCTION(awe32_set_volume);
static void awe32_set_pitch (int voice, int note, int bend) {
struct envparms_t *env;
int key,ip;
/* get envelope in use on this voice */
env = voice_envelope[voice];
key = note*0x1000+bend;
/* override key if envelope says so */
if ((env->key>=0)&&(env->key<=127)) key=env->key*0x1000;
/* check key number is within range */
if (key>0x7ffff) key=0x7ffff;
if (key<0) key=0;
ip=env->ipbase+(env->ipscale*key)/1200;
emu8k_modulate_ip(voice,ip);
}
static END_OF_FUNCTION (awe32_set_pitch);
/* awe32_key_off:
* Hey, guess what this does :-)
*/
static void awe32_key_off(int voice) {
emu8k_releasesound (voice,voice_envelope[voice]);
}
static END_OF_FUNCTION(awe32_key_off);
/* awe32_detect:
* AWE32/EMU8000 detection routine.
*/
static int awe32_detect() {
if (emu8k_detect()) {
sprintf (awe32_desc,"SB AWE32/compatible on port 0x%04x",_emu8k_baseport);
return TRUE;
} else {
sprintf(allegro_error, "AWE32 not detected");
return FALSE;
}
}
/* awe32_lockmem:
* Locks required memory blocks
*/
static void awe32_lockmem() {
/* Functions */
LOCK_FUNCTION(awe32_key_on);
LOCK_FUNCTION(awe32_key_off);
LOCK_FUNCTION(_awe32_do_note);
LOCK_FUNCTION(awe32_set_volume);
LOCK_FUNCTION(awe32_set_pitch);
/* Data */
/* Most data is locked on allocation */
LOCK_VARIABLE(midi_preset);
LOCK_VARIABLE(voice_envelope);
LOCK_VARIABLE(exclusive_class_info);
LOCK_VARIABLE(midi_awe32);
//jff 3/7/98 added attentbl to avoid floating point in awe32, must be locked
LOCK_VARIABLE(attentbl);
/* Stuff in emu8k.c */
emu8k_lock();
}
/* awe32_init:
* Setup the AWE32/EMU8000 driver.
*/
static int awe32_init(int voices) {
int chan;
emu8k_init();
translate_soundfont_into_something_useful();
voice_envelope = (struct envparms_t **) _lock_malloc (32 * sizeof(struct envparms_t *));
exclusive_class_info = (int *) _lock_malloc (32 * sizeof (int));
awe32_lockmem();
for (chan = 0; chan < 32; chan++) {
voice_envelope[chan] = NULL;
exclusive_class_info[chan] = 0;
}
return 0;
}
/* awe32_exit:
* Cleanup when we are finished.
*/
static void awe32_exit() {
int i;
for (i=0;i<_emu8k_numchannels;i++) emu8k_terminatesound(i);
destroy_useful_version_of_soundfont();
free (voice_envelope);
free (exclusive_class_info);
}
/* translate_soundfont_into_something_useful:
* Like it says, translate the soundfont data into something we can use
* when playing notes.
*/
static void translate_soundfont_into_something_useful() {
int p,s,gen,weirdo;
struct midi_preset_t *thing_to_write=NULL;
generators_t temp_gens;
int global_split=0,global_weirdo=0,num_weirdos;
midi_preset = (struct midi_preset_t *)_lock_malloc(129*sizeof(struct midi_preset_t));
for (p=0;p<_awe_sf_num_presets;p++) {
if (_awe_sf_presets[p*3+1]==0) {
thing_to_write = &midi_preset[_awe_sf_presets[p*3+0]];
} else if (_awe_sf_presets[p*3+1]==128) {
thing_to_write = &midi_preset[128];
} else {
thing_to_write = NULL;
}
if (thing_to_write) {
thing_to_write->num_splits=_awe_sf_presets[p*3+2];
thing_to_write->split=(struct envparms_t **)_lock_malloc(thing_to_write->num_splits*sizeof(struct envparms_t *));
for (s=0;s<thing_to_write->num_splits;s++) {
for (gen=0;gen<SOUNDFONT_NUM_GENERATORS-4;gen++) temp_gens[gen] = _awe_sf_defaults[gen];
num_weirdos = _awe_sf_splits[global_split];
for (weirdo=global_weirdo;weirdo<global_weirdo+num_weirdos;weirdo++) temp_gens[_awe_sf_gens[weirdo*2]] = _awe_sf_gens[weirdo*2+1];
global_weirdo+=num_weirdos;
for (gen=0;gen<4;gen++) temp_gens[gfgen_startAddrs+gen] = _awe_sf_sample_data[global_split*4+gen];
global_split++;
thing_to_write->split[s]=emu8k_createenvelope(temp_gens);
}
} else {
strcpy(allegro_error,"AWE32 driver: had trouble with the embedded data");
}
}
}
/* destroy_useful_version_of_soundfont:
* Destroys the data created by the above function
*/
static void destroy_useful_version_of_soundfont() {
int p,s;
for (p=0;p<129;p++)
if (midi_preset[p].num_splits>0) {
for (s=0;s<midi_preset[p].num_splits;s++) emu8k_destroyenvelope(midi_preset[p].split[s]);
free(midi_preset[p].split);
}
free(midi_preset);
}
/* _lock_malloc:
* Allocates a locked memory block
*/
void *_lock_malloc (size_t size) {
void *ret = malloc (size);
if (!ret) return NULL;
if (_go32_dpmi_lock_data (ret, size)) {
free (ret);
return NULL;
}
return ret;
}