]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/allg_snd/sound/drv/emu8kmid.c
This commit was generated by cvs2svn to compensate for changes in r2,
[btb/d2x.git] / arch / dos / allg_snd / sound / drv / emu8kmid.c
1 /*         ______   ___    ___ 
2  *        /\  _  \ /\_ \  /\_ \ 
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *      By Shawn Hargreaves,
11  *      1 Salisbury Road,
12  *      Market Drayton,
13  *      Shropshire,
14  *      England, TF9 1AJ.
15  *
16  *      This file written by George Foot.
17  *
18  *      AWE32/EMU8000 driver for the MIDI player.
19  *
20  *      See readme.txt for copyright information.
21  */
22
23
24 #ifndef DJGPP
25 #error This file should only be used by the djgpp version of Allegro
26 #endif
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <math.h>
31
32 #include "allegro.h"
33 #include "internal.h"
34
35 #include "emu8k.h"
36
37 /* Variables from awedata.c, containing the envelope data from synthgm.sf2 */
38 extern short int _awe_sf_defaults[];
39 extern       int _awe_sf_num_presets;
40 extern short int _awe_sf_presets[];
41 extern short int _awe_sf_splits[];
42 extern short int _awe_sf_gens[];
43 extern       int _awe_sf_sample_data[];
44
45 /* external interface to the AWE32 driver */
46 static int  awe32_detect();
47 static int  awe32_init(int voices);
48 static void awe32_exit();
49 static void awe32_key_on(int inst, int note, int bend, int vol, int pan);
50 static void awe32_key_off(int voice);
51 static void _awe32_do_note(int inst, int note, int bend, int vol, int pan);
52 static void awe32_set_volume (int voice, int vol);
53 static void awe32_set_pitch (int voice, int note, int bend);
54 static void translate_soundfont_into_something_useful();
55 static void destroy_useful_version_of_soundfont();
56
57 static struct midi_preset_t {   /* struct to hold envelope data for each preset */
58  int num_splits;                /* number of splits in this preset */
59  struct envparms_t **split;     /* array of num_splits pointers to envelope data */
60 } *midi_preset;                 /* global variable to hold the data */
61
62 static struct envparms_t **voice_envelope;      /* array of pointers pointing at the envelope playing on each voice */
63 static int *exclusive_class_info;               /* exclusive class information */
64
65 static char awe32_desc[256] = "not initialised";
66
67 MIDI_DRIVER midi_awe32 = {
68    "AWE32/EMU8000",             /* name */
69    awe32_desc,                  /* desc */
70    32, 0, 32, 32, -1, -1,       /* voices, basevoice, max_voices, def_voices, xmin, xmax */
71    awe32_detect,                /* detect */
72    awe32_init,                  /* init */
73    awe32_exit,                  /* exit */
74    NULL,                        /* mixer_volume */
75    NULL,                        /* raw_midi */
76    _dummy_load_patches,         /* load_patches */
77    _dummy_adjust_patches,       /* adjust_patches */
78    awe32_key_on,                /* key_on */
79    awe32_key_off,               /* key_off */
80    awe32_set_volume,            /* set_volume */
81    awe32_set_pitch,             /* set_pitch */
82    _dummy_noop2,                /* set_pan */
83    _dummy_noop2                 /* set_vibrato */
84 };
85
86
87
88 /* awe32_key_on:
89  *  Triggers the specified voice. The instrument is specified as a GM
90  *  patch number, pitch as a midi note number, and volume from 0-127.
91  *  The bend parameter is _not_ expressed as a midi pitch bend value.
92  *  It ranges from 0 (no pitch change) to 0xFFF (almost a semitone sharp).
93  *  Drum sounds are indicated by passing an instrument number greater than
94  *  128, in which case the sound is GM percussion key #(inst-128).
95  */
96 static void awe32_key_on(int inst, int note, int bend, int vol, int pan) {
97  if (inst > 127) {                              /* drum sound? */
98   _awe32_do_note (128,inst-128,bend,vol,pan);
99  } else {                                       /* regular instrument */
100   _awe32_do_note (inst,note,bend,vol,pan);
101  }
102 }
103 static END_OF_FUNCTION(awe32_key_on);
104
105
106
107 /* _awe32_do_note:
108  *  Actually plays the note as described above; the above function just remaps
109  *  the drums.
110  */
111 static void _awe32_do_note(int inst, int note, int bend, int vol, int pan) {
112  int voice;
113  int i;
114  envparms_t *env;
115  int key,vel;
116  int atten;
117  int pan_pos;
118
119  /* EMU8000 pan is back-to-front and twice the scale */
120  pan = 0x100-2*pan;
121  if (pan>0xff) pan = 0xff;
122  if (pan<0x00) pan = 0x00;
123
124  for (i=0;i<midi_preset[inst].num_splits;i++) {
125   /* envelope for this split */
126   env=midi_preset[inst].split[i];
127
128   /* should we play this split? */
129   if ((note>=env->minkey)&&(note<=env->maxkey)&&( vol>=env->minvel)&&( vol<=env->maxvel)) {
130
131    /* get a voice (any voice) to play it on */
132    voice = _midi_allocate_voice (-1,-1);
133
134    /* did we get one? */
135    if (voice>=0) {
136
137     /* set the current envelope for this voice */
138     voice_envelope[voice]=env;
139
140     /* set pitch and velocity */
141     key = note*0x1000+bend;
142     vel = vol;
143
144     /* override key and velocity if envelope says so */
145     if ((env->key>=0)&&(env->key<=127)) key=env->key*0x1000;
146     if ((env->vel>=0)&&(env->vel<=127)) vel=env->vel;
147
148     /* check key and velocity numbers are within range */
149     if (key>0x7ffff) key=0x7ffff;
150     if (key<0) key=0;
151     if (vel>127) vel=127;
152     if (vel<0) vel=0;
153
154     /* add one-off information to the envelope (these have no side-effects on the other voices using this envelope) */
155     env->ip=env->ipbase+(env->ipscale*key)/1200;
156
157     /* remap MIDI velocity to attenuation */
158     if (vel)
159      atten = env->atten + (-20/0.375*log(vel/127.0));
160     else
161      atten = 0xff;
162     if (atten<0x00) atten = 0x00;
163     if (atten>0xff) atten = 0xff;
164
165     /* update it in the envelope */
166     env->ifatn=env->filter+atten;
167
168     /* modify pan with envelope's built-in pan */
169     if (pan<0x80) {
170      pan_pos = (pan*env->pan)/0x80;
171     } else {
172      pan_pos = env->pan + (pan-0x80)*(256-env->pan)/0x80;
173     }
174     if (pan_pos<0x00) pan_pos=0x00;
175     if (pan_pos>0xff) pan_pos=0xff;
176
177     /* update pan in the envelope */
178     env->psst = (pan_pos<<24) + env->loopst;
179
180     /* test exclusive class */
181     exclusive_class_info[voice] = (inst << 8) + env->exc;
182
183     if (env->exc) {
184      int chan;
185      for (chan = 0; chan < 32; chan++)
186       if ((chan != voice) && (exclusive_class_info[chan] == exclusive_class_info[voice]))
187        emu8k_terminatesound (chan);
188     }
189
190     /* start the note playing */
191     emu8k_startsound(voice,env);
192
193    }
194   }
195  }
196 }
197 static END_OF_FUNCTION(_awe32_do_note);
198
199
200
201 /* awe32_set_*:
202  *  Modulation routines
203  */
204 static void awe32_set_volume (int voice, int vol) {
205  int atten;
206  struct envparms_t *env;
207
208  /* get envelope in use on this voice */
209  env = voice_envelope[voice];
210
211  /* allow envelope to override new volume */
212  if ((env->vel>=0)&&(env->vel<=127)) vol=env->vel;
213
214  /* check velocity number is within range */
215  if (vol>127) vol=127;
216  if (vol<0) vol=0;
217
218  /* remap MIDI velocity to attenuation */
219  if (vol)
220   atten = env->atten + (-20/0.375*log(vol/127.0));
221  else
222   atten = 0xff;
223  if (atten<0x00) atten = 0x00;
224  if (atten>0xff) atten = 0xff;
225
226  emu8k_modulate_atten(voice,atten);
227 }
228 static END_OF_FUNCTION(awe32_set_volume);
229
230
231
232 static void awe32_set_pitch (int voice, int note, int bend) {
233  struct envparms_t *env;
234  int key,ip;
235
236  /* get envelope in use on this voice */
237  env = voice_envelope[voice];
238
239  key = note*0x1000+bend;
240
241  /* override key if envelope says so */
242  if ((env->key>=0)&&(env->key<=127)) key=env->key*0x1000;
243
244  /* check key number is within range */
245  if (key>0x7ffff) key=0x7ffff;
246  if (key<0) key=0;
247
248  ip=env->ipbase+(env->ipscale*key)/1200;
249
250  emu8k_modulate_ip(voice,ip);
251 }
252 static END_OF_FUNCTION (awe32_set_pitch);
253
254
255
256 /* awe32_key_off:
257  *  Hey, guess what this does :-)
258  */
259 static void awe32_key_off(int voice) {
260  emu8k_releasesound (voice,voice_envelope[voice]);
261 }
262 static END_OF_FUNCTION(awe32_key_off);
263
264
265
266 /* awe32_detect:
267  *  AWE32/EMU8000 detection routine.
268  */
269 static int awe32_detect() {
270  if (emu8k_detect()) {
271   sprintf (awe32_desc,"SB AWE32/compatible on port 0x%04x",_emu8k_baseport);
272   return TRUE;
273  } else {
274   sprintf(allegro_error, "AWE32 not detected");
275   return FALSE;
276  }
277 }
278
279
280
281 /* awe32_lockmem:
282  *  Locks required memory blocks
283  */
284 static void awe32_lockmem() {
285
286 /* Functions */
287  LOCK_FUNCTION(awe32_key_on);
288  LOCK_FUNCTION(awe32_key_off);
289  LOCK_FUNCTION(_awe32_do_note);
290  LOCK_FUNCTION(awe32_set_volume);
291  LOCK_FUNCTION(awe32_set_pitch);
292
293 /* Data */
294  /* Most data is locked on allocation */
295  LOCK_VARIABLE(midi_preset);
296  LOCK_VARIABLE(voice_envelope);
297  LOCK_VARIABLE(exclusive_class_info);
298  LOCK_VARIABLE(midi_awe32);
299
300 /* Stuff in emu8k.c */
301  emu8k_lock();
302
303 }
304
305
306
307 /* awe32_init:
308  *  Setup the AWE32/EMU8000 driver.
309  */
310 static int awe32_init(int voices) {
311  int chan;
312
313  emu8k_init();
314  translate_soundfont_into_something_useful();
315  voice_envelope = (struct envparms_t **) _lock_malloc (32 * sizeof(struct envparms_t *));
316  exclusive_class_info = (int *) _lock_malloc (32 * sizeof (int));
317  awe32_lockmem();
318
319  for (chan = 0; chan < 32; chan++) {
320   voice_envelope[chan] = NULL;
321   exclusive_class_info[chan] = 0;
322  }
323
324  return 0;
325 }
326
327
328
329 /* awe32_exit:
330  *  Cleanup when we are finished.
331  */
332 static void awe32_exit() {
333  int i;
334  for (i=0;i<_emu8k_numchannels;i++) emu8k_terminatesound(i);
335  destroy_useful_version_of_soundfont();
336  free (voice_envelope);
337  free (exclusive_class_info);
338 }
339
340
341
342 /* translate_soundfont_into_something_useful:
343  *  Like it says, translate the soundfont data into something we can use
344  *  when playing notes.
345  */
346 static void translate_soundfont_into_something_useful() {
347  int p,s,gen,weirdo;
348  struct midi_preset_t *thing_to_write=NULL;
349  generators_t temp_gens;
350  int global_split=0,global_weirdo=0,num_weirdos;
351
352  midi_preset = (struct midi_preset_t *)_lock_malloc(129*sizeof(struct midi_preset_t));
353  for (p=0;p<_awe_sf_num_presets;p++) {
354   if (_awe_sf_presets[p*3+1]==0) {
355    thing_to_write = &midi_preset[_awe_sf_presets[p*3+0]];
356   } else if (_awe_sf_presets[p*3+1]==128) {
357    thing_to_write = &midi_preset[128];
358   } else {
359    thing_to_write = NULL;
360   }
361   if (thing_to_write) {
362    thing_to_write->num_splits=_awe_sf_presets[p*3+2];
363    thing_to_write->split=(struct envparms_t **)_lock_malloc(thing_to_write->num_splits*sizeof(struct envparms_t *));
364    for (s=0;s<thing_to_write->num_splits;s++) {
365     for (gen=0;gen<SOUNDFONT_NUM_GENERATORS-4;gen++) temp_gens[gen] = _awe_sf_defaults[gen];
366     num_weirdos = _awe_sf_splits[global_split];
367     for (weirdo=global_weirdo;weirdo<global_weirdo+num_weirdos;weirdo++) temp_gens[_awe_sf_gens[weirdo*2]] = _awe_sf_gens[weirdo*2+1];
368     global_weirdo+=num_weirdos;
369     for (gen=0;gen<4;gen++) temp_gens[gfgen_startAddrs+gen] = _awe_sf_sample_data[global_split*4+gen];
370     global_split++;
371     thing_to_write->split[s]=emu8k_createenvelope(temp_gens);
372    }
373   } else {
374    strcpy(allegro_error,"AWE32 driver: had trouble with the embedded data");
375   }
376  }
377 }
378
379
380
381 /* destroy_useful_version_of_soundfont:
382  *  Destroys the data created by the above function
383  */
384 static void destroy_useful_version_of_soundfont() {
385  int p,s;
386  for (p=0;p<129;p++)
387   if (midi_preset[p].num_splits>0) {
388    for (s=0;s<midi_preset[p].num_splits;s++) emu8k_destroyenvelope(midi_preset[p].split[s]);
389    free(midi_preset[p].split);
390   }
391  free(midi_preset);
392 }
393
394
395
396 /* _lock_malloc:
397  *  Allocates a locked memory block
398  */
399 void *_lock_malloc (size_t size) {
400  void *ret = malloc (size);
401  if (!ret) return NULL;
402  if (_go32_dpmi_lock_data (ret, size)) {
403   free (ret);
404   return NULL;
405  }
406  return ret;
407 }
408