]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/allg_snd/sound/digmid.c
This commit was generated by cvs2svn to compensate for changes in r2,
[btb/d2x.git] / arch / dos / allg_snd / sound / digmid.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  *      Digitized sample driver for the MIDI player.
17  *
18  *      Based on code by Tom Novelli.
19  *
20  *      See readme.txt for copyright information.
21  */
22
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <string.h>
28 #include <dos.h>
29 #include <limits.h>
30 #include <math.h>
31 #include <dir.h>
32
33 #include "allegro.h"
34 #include "internal.h"
35
36
37 /* external interface to the Digmid driver */
38 static int digmid_detect();
39 static int digmid_init(int voices);
40 static void digmid_exit();
41 static int digmid_load_patches(char *patches, char *drums);
42 static void digmid_key_on(int inst, int note, int bend, int vol, int pan);
43 static void digmid_key_off(int voice);
44 static void digmid_set_volume(int voice, int vol);
45 static void digmid_set_pitch(int voice, int note, int bend);
46
47
48 MIDI_DRIVER midi_digmid =
49 {
50    "DIGMID",
51    "Software wavetable synth",
52    0, 0, -1, 24, -1, -1,
53    digmid_detect,
54    digmid_init,
55    digmid_exit,
56    NULL,
57    NULL,
58    digmid_load_patches,
59    _dummy_adjust_patches,
60    digmid_key_on,
61    digmid_key_off,
62    digmid_set_volume,
63    digmid_set_pitch,
64    _dummy_noop2,
65    _dummy_noop2
66 };
67
68
69 #define MAX_LAYERS   64
70
71
72 typedef struct PATCH_EXTRA          /* additional data for a Gravis PATCH */
73 {
74    int low_note; 
75    int high_note;
76    int base_note;
77    int play_mode; 
78    int decay_time;
79    int release_time;
80    int sustain_level;
81    int scale_freq;
82    int scale_factor; 
83    int pan;
84 } PATCH_EXTRA;
85
86
87 typedef struct PATCH                /* Gravis PATCH structure */
88 {
89    int samples;                     /* number of samples in this instrument */
90    SAMPLE *sample[MAX_LAYERS];      /* the waveform data */
91    PATCH_EXTRA *extra[MAX_LAYERS];  /* additional waveform information */
92    int master_vol;                  /* overall volume level */
93 } PATCH;
94
95
96 /* our instruments */
97 static PATCH *patch[256];
98
99
100 /* frequency table (generated by digmid_init) */
101 static float ftbl[130]; 
102
103
104 /* stored information about active voices */
105 typedef struct DIGMID_VOICE
106 {
107    SAMPLE *s;
108    PATCH_EXTRA *e;
109    int inst;
110    int vol;
111 } DIGMID_VOICE;
112
113
114 static DIGMID_VOICE digmid_voice[MIDI_VOICES];
115
116
117
118 /* destroy_patch:
119  *  Frees a PATCH struct and all samples it contains.
120  */
121 static void destroy_patch(PATCH *pat)
122 {
123    int i;
124
125    if (pat) {
126       for (i=0; i < pat->samples; i++) {
127          destroy_sample(pat->sample[i]);
128
129          _unlock_dpmi_data(pat->extra[i], sizeof(PATCH_EXTRA));
130          free(pat->extra[i]);
131       }
132
133       _unlock_dpmi_data(pat, sizeof(PATCH));
134       free(pat);
135    }
136 }
137
138
139
140 /* load_patch:
141  *  Reads a GUS format patch file from disk.
142  */
143 static PATCH *load_patch(PACKFILE *f, int drum)
144 {
145    int trashtmp;
146    PATCH *p = NULL;
147    char buf[256];
148    char mode;
149    int env_rate[6];
150    int env_offset[6];
151    int i, j;
152    int diff;
153    int odd_len;
154
155    pack_fread(buf, 22, f);                         /* ID tag */
156    if (memcmp(buf, "GF1PATCH110\0", 12) || memcmp(buf+12, "ID#000002\0", 10))
157       goto getout;
158
159    p = malloc(sizeof(PATCH));
160    if (!p) {
161       errno = ENOMEM;
162       goto getout;
163    }
164
165    pack_fread(buf, 65, f);                         /* description */
166    p->master_vol = pack_igetw(f);                  /* volume */
167
168    pack_fread(buf, 109, f);                        /* skip */
169
170    p->samples = pack_getc(f);                      /* number of samples */
171    pack_fread(buf, 40, f);                         /* skip */
172
173    if (p->samples > MAX_LAYERS)
174       p->samples = MAX_LAYERS;
175
176    for (i=0; i<p->samples; i++) {                  /* for each sample... */
177       p->sample[i] = malloc(sizeof(SAMPLE));
178       if (!p->sample[i]) {
179          p->samples = i;
180          destroy_patch(p);
181          p = NULL;
182          goto getout;
183       }
184
185       p->extra[i] = malloc(sizeof(PATCH_EXTRA));
186       if (!p->extra[i])  {
187          free(p->sample[i]);
188          p->samples = i;
189          destroy_patch(p);
190          p = NULL;
191          goto getout;
192       }
193
194       pack_fread(buf, 8, f);                       /* layer name */
195
196       p->sample[i]->len = pack_igetl(f);           /* sample length */
197       p->sample[i]->loop_start = pack_igetl(f);    /* loop start */
198       p->sample[i]->loop_end = pack_igetl(f);      /* loop end */
199       p->sample[i]->freq = pack_igetw(f);          /* sample frequency */
200
201       p->extra[i]->low_note = pack_igetl(f);       /* key min */
202       p->extra[i]->high_note = pack_igetl(f);      /* key max */
203       p->extra[i]->base_note = pack_igetl(f);      /* base key */
204       trashtmp=pack_igetw(f);                               /* skip finetune */
205
206       p->extra[i]->pan = pack_getc(f) * 255/15;    /* pan position */
207
208       for (j=0; j<6; j++)                          /* envelope rate */
209          env_rate[j] = pack_getc(f);
210
211       for (j=0; j<6; j++)                          /* envelope value */
212          env_offset[j] = pack_getc(f);
213
214       pack_fread(buf, 6, f);                       /* skip trem and vib */
215
216       mode = pack_getc(f);                         /* sample flags */
217
218       p->sample[i]->bits = (mode & 1) ? 16 : 8;    /* how many bits? */
219
220       p->extra[i]->play_mode = 0;                  /* sort out loop flags */
221
222       if (mode & 4)
223          p->extra[i]->play_mode |= PLAYMODE_LOOP;
224
225       if (mode & 8) 
226          p->extra[i]->play_mode |= (PLAYMODE_BIDIR | PLAYMODE_LOOP);
227
228       if (mode & 16) 
229          p->extra[i]->play_mode |= (PLAYMODE_BACKWARD | PLAYMODE_LOOP);
230
231       /* convert envelope rates (GUS uses a 2.6 floating point format) */
232       for (j=0; j<6; j++) {
233          static int vexp[4] = { 1, 8, 64, 512 };
234          int e = (env_rate[j] >> 6);
235          int m = (env_rate[j] & 0x3F);
236          env_rate[j] = ((65536 * vexp[e] / ((m) ? m : 1)) >> 12);
237       }
238
239       if ((mode & 32) && (!drum)) {
240          /* sustained volume envelope */
241          p->extra[i]->sustain_level = env_offset[2];
242          p->extra[i]->decay_time = 0;
243
244          diff = env_offset[0];
245          p->extra[i]->decay_time += env_rate[0] * diff / 256;
246
247          diff = ABS(env_offset[1] - env_offset[0]);
248          p->extra[i]->decay_time += env_rate[1] * diff / 256;
249
250          diff = ABS(env_offset[2] - env_offset[1]);
251          p->extra[i]->decay_time += env_rate[2] * diff / 256;
252
253          j = 3;
254       }
255       else {
256          /* one-shot volume envelope */
257          p->extra[i]->decay_time = 0;
258          p->extra[i]->sustain_level = 0;
259
260          for (j=0; j<6; j++) {
261             diff = ABS(env_offset[j] - ((j) ? env_offset[j-1] : 0));
262             p->extra[i]->decay_time += env_rate[j] * diff / 256;
263             if (env_offset[j] < 16) {
264                j++;
265                break;
266             }
267          }
268       }
269
270       /* measure release time */
271       p->extra[i]->release_time = 0;
272
273       while (j < 6) {
274          diff = ABS(env_offset[j] - env_offset[j-1]);
275          p->extra[i]->release_time += env_rate[j] * diff / 256;
276          if (env_offset[j] < 16)
277             break;
278          j++;
279       }
280
281       /* clamp very large/small sustain levels to zero or maximum */
282       if (p->extra[i]->sustain_level < 16)
283          p->extra[i]->sustain_level = 0;
284       else if (p->extra[i]->sustain_level > 192)
285          p->extra[i]->sustain_level = 255;
286
287       if (p->extra[i]->release_time < 10)
288          p->extra[i]->release_time = 0;
289
290       if ((p->extra[i]->sustain_level == 0) && 
291           (p->extra[i]->decay_time == 0)) {
292          p->extra[i]->sustain_level = 255;
293          p->extra[i]->play_mode &= ~PLAYMODE_LOOP;
294       }
295
296       p->extra[i]->scale_freq = pack_igetw(f);     /* scale values */
297       p->extra[i]->scale_factor = pack_igetw(f);
298
299       pack_fread(buf, 36, f);                      /* skip reserved */
300
301       if (p->sample[i]->bits == 16) {              /* adjust 16 bit loops */
302          odd_len = (p->sample[i]->len & 1);
303          p->sample[i]->len /= 2;
304          p->sample[i]->loop_start /= 2;
305          p->sample[i]->loop_end /= 2;
306       }
307       else
308          odd_len = FALSE;
309
310       p->sample[i]->priority = 255;                /* set some defaults */
311       p->sample[i]->param = -1;
312
313       p->sample[i]->data = malloc(p->sample[i]->len);
314       if (!p->sample[i]->data) {
315          free(p->sample[i]);
316          free(p->extra[i]);
317          p->samples = i;
318          destroy_patch(p);
319          p = NULL;
320          goto getout;
321       }
322
323       if (p->sample[i]->bits == 8) {
324          /* read 8 bit sample data */
325          pack_fread(p->sample[i]->data, p->sample[i]->len, f);
326          if (!(mode & 2)) {
327             /* signed data - convert to unsigned */
328             for (j=0; j<(int)p->sample[i]->len; j++)
329                ((unsigned char *)p->sample[i]->data)[j] ^= 0x80;
330          }
331       }
332       else {
333          /* reduce 16 bits to 8 bit waveform */
334          for (j=0; j < (int)p->sample[i]->len; j++) {
335             ((unsigned char *)p->sample[i]->data)[j] = pack_igetw(f) >> 8;
336          }
337          if (!(mode & 2)) {
338             /* signed data - convert to unsigned */
339             for (j=0; j<(int)p->sample[i]->len; j++)
340                ((unsigned char *)p->sample[i]->data)[j] ^= 0x80;
341          }
342          p->sample[i]->bits = 8;
343          if (odd_len)
344             pack_getc(f);
345       }
346    }
347
348    getout:
349
350    /* lock the data into physical memory */
351    if (p) {
352       _go32_dpmi_lock_data(p, sizeof(PATCH));
353
354       for (i=0; i<p->samples; i++) {
355          lock_sample(p->sample[i]);
356          _go32_dpmi_lock_data(p->extra[i], sizeof(PATCH_EXTRA));
357       }
358    }
359
360    return p;
361 }
362
363
364
365 /* try_patch_location:
366  *  Looks for a GUS patch set in the specified location, storing the dir
367  *  and config file name if found.
368  */
369 static int try_patch_location(char *where, char *dir, char *file)
370 {
371    /* could it be a direct .cfg file reference? */
372    if (stricmp(get_extension(where), "cfg") == 0) {
373       if (!file_exists(where, FA_RDONLY | FA_ARCH, NULL))
374          return FALSE;
375       strcpy(dir, where);
376       *get_filename(dir) = 0;
377       strcpy(file, get_filename(where));
378       return TRUE;
379    }
380
381    /* could it be a direct .dat file reference? */
382    if (stricmp(get_extension(where), "dat") == 0) {
383       strcpy(dir, where);
384       strcat(dir, "#default_cfg");
385       if (!file_exists(dir, FA_RDONLY | FA_ARCH, NULL))
386          return FALSE;
387       strcpy(dir, where);
388       strcat(dir, "#");
389       strcpy(file, "default_cfg");
390       return TRUE;
391    }
392
393    /* could it be a directory containing default.cfg? */
394    strcpy(dir, where);
395    put_backslash(dir);
396    strcat(dir, "default.cfg");
397    if (file_exists(dir, FA_RDONLY | FA_ARCH, NULL)) {
398       strcpy(dir, where);
399       put_backslash(dir);
400       strcpy(file, "default.cfg");
401       return TRUE;
402    }
403
404    /* could it be a directory containing patches.dat? */
405    strcpy(dir, where);
406    put_backslash(dir);
407    strcat(dir, "patches.dat#default_cfg");
408    if (file_exists(dir, FA_RDONLY | FA_ARCH, NULL)) {
409       strcpy(dir, where);
410       put_backslash(dir);
411       strcat(dir, "patches.dat#");
412       strcpy(file, "default_cfg");
413       return TRUE;
414    }
415
416    /* could it be the root directory of midi/default.cfg? */
417    strcpy(dir, where);
418    put_backslash(dir);
419    strcat(dir, "midi/default.cfg");
420    if (file_exists(dir, FA_RDONLY | FA_ARCH, NULL)) {
421       strcpy(dir, where);
422       put_backslash(dir);
423       strcat(dir, "midi/");
424       strcpy(file, "default.cfg");
425       return TRUE;
426    }
427
428    return FALSE;
429 }
430
431
432
433 /* _digmid_find_patches:
434  *  Tries to locate the GUS patch set directory and index file (default.cfg).
435  */
436 int _digmid_find_patches(char *dir, char *file)
437 {
438    char *name = get_config_string("sound", "patches", NULL);
439    char path[256], *s;
440
441    /* look where the config file says */
442    if ((name) && (*name))
443       return try_patch_location(name, dir, file);
444
445    /* look in the same directory as the program */
446    strcpy(path, __crt0_argv[0]);
447    *get_filename(path) = 0;
448    put_backslash(path);
449    if (try_patch_location(path, dir, file))
450       return TRUE;
451
452    /* try the ALLEGRO environment variable */
453    s = getenv("ALLEGRO");
454    if (s) {
455       strcpy(path, s);
456       put_backslash(path);
457       if (try_patch_location(path, dir, file))
458          return TRUE;
459    }
460
461    /* try the ULTRASND environment variable */
462    s = getenv("ULTRASND");
463    if (s) {
464       strcpy(path, s);
465       put_backslash(path);
466       if (try_patch_location(path, dir, file))
467          return TRUE;
468    }
469
470    return FALSE;
471 }
472
473
474
475 /* parse_string:
476  *  Splits a string into component parts, storing them in the argv pointers.
477  *  Returns the number of components.
478  */
479 static int parse_string(char *buf, char *argv[])
480 {
481    int c = 0;
482
483    while ((*buf) && (c<16)) {
484       while ((*buf == ' ') || (*buf == '\t') || (*buf == '='))
485          buf++;
486
487       if (*buf == '#')
488          return c;
489
490       if (*buf)
491          argv[c++] = buf;
492
493       while ((*buf) && (*buf != ' ') && (*buf != '\t') && (*buf != '='))
494          buf++;
495
496       if (*buf) {
497          *buf = 0;
498          buf++;
499       }
500    }
501
502    return c;
503 }
504
505
506
507 /* digmid_load_patches:
508  *  Reads the patches that are required by a particular song.
509  */
510 static int digmid_load_patches(char *patches, char *drums)
511 {
512    PACKFILE *f;
513    char dir[256], file[256], buf[256], filename[256];
514    char todo[256][16];
515    char *argv[16];
516    int argc;
517    int patchnum, flag_num;
518    int drum_mode = FALSE;
519    int override_mode = FALSE;
520    int drum_start = 0;
521 #if 0
522    int type, size;
523 #endif
524    int i, j;
525
526    if (!_digmid_find_patches(dir, file))
527       return -1;
528
529    for (i=0; i<256; i++)
530       todo[i][0] = 0;
531
532    strcpy(buf, dir);
533    strcat(buf, file);
534    f = pack_fopen(buf, F_READ);
535    if (!f)
536       return -1;
537
538    while (pack_fgets(buf, 255, f) != 0) {
539       argc = parse_string(buf, argv);
540
541       if (argc > 0) {
542          /* is first word all digits? */
543          flag_num = TRUE;
544          for (i=0; i<(int)strlen(argv[0]); i++) {
545             if ((!isdigit(argv[0][i])) && (argv[0][i] != '-')) {
546                flag_num = FALSE;
547                break;
548             }
549          }
550
551          if ((flag_num) && (argc >= 2)) {
552             if (stricmp(argv[1], "begin_multipatch") == 0) {
553                /* start the block of percussion instruments */
554                drum_start = atoi(argv[0])-1;
555                drum_mode = TRUE;
556             }
557             else if (stricmp(argv[1], "override_patch") == 0) {
558                /* ignore patch overrides */
559                override_mode = TRUE;
560             }
561             else if (!override_mode) {
562                /* must be a patch number */
563                patchnum = atoi(argv[0]);
564
565                if (!drum_mode)
566                   patchnum--;
567
568                if ((patchnum >= 0) && (patchnum < 128) &&
569                    (((drum_mode) && (drums[patchnum])) ||
570                     ((!drum_mode) && (patches[patchnum])))) {
571
572                   if (drum_mode)
573                      patchnum += drum_start;
574
575                   if (!patch[patchnum]) {
576                      /* need to load this sample */
577                      strncpy(todo[patchnum], argv[1], 15);
578                      todo[patchnum][15] = 0;
579                   }
580                }
581             }
582          }
583          else {
584             /* handle other keywords */
585             if (stricmp(argv[0], "end_multipatch") == 0) {
586                drum_mode = FALSE;
587                override_mode = FALSE;
588             }
589          }
590       }
591    }
592
593    pack_fclose(f);
594
595 #if 0
596    if ((dir[0]) && (dir[strlen(dir)-1] == '#')) {
597       /* read from a datafile */
598       dir[strlen(dir)-1] = 0;
599       f = pack_fopen(dir, F_READ_PACKED);
600       if (!f)
601          return -1;
602
603       type = pack_mgetl(f);
604       if (type != DAT_MAGIC) {
605          pack_fclose(f);
606          return -1;
607       }
608
609       pack_mgetl(f);
610
611       filename[0] = 0;
612
613       /* scan through the file */
614       while (!pack_feof(f)) {
615          type = pack_mgetl(f);
616
617          if (type == DAT_PROPERTY) {
618             type = pack_mgetl(f);
619             size = pack_mgetl(f);
620             if (type == DAT_ID('N','A','M','E')) {
621                /* store name property */
622                pack_fread(filename, size, f);
623                filename[size] = 0;
624             }
625             else {
626                /* skip other properties */
627                pack_fseek(f, size);
628             }
629          }
630          else if (type == DAT_PATCH) {
631             /* do we want this patch? */
632             for (i=0; i<256; i++)
633                if ((todo[i][0]) && (stricmp(filename, todo[i]) == 0))
634                   break;
635
636             if (i < 256) {
637                /* load this patch */
638                f = pack_fopen_chunk(f, FALSE);
639                patch[i] = load_patch(f, (i >= 128));
640                f = pack_fclose_chunk(f);
641                for (j=i+1; j<256; j++) {
642                   /* share multiple copies of the instrument */
643                   if (stricmp(todo[i], todo[j]) == 0) {
644                      patch[j] = patch[i];
645                      todo[j][0] = 0;
646                   }
647                }
648                todo[i][0] = 0;
649             }
650             else {
651                /* skip unwanted patch */
652                size = pack_mgetl(f);
653                pack_fseek(f, size+4);
654             }
655          }
656          else {
657             /* skip unwanted object */
658             size = pack_mgetl(f);
659             pack_fseek(f, size+4);
660          }
661       }
662    }
663    else
664 #endif
665    {
666       /* read from regular disk files */
667       for (i=0; i<256; i++) {
668          if (todo[i][0]) {
669             strcpy(filename, dir);
670             strcat(filename, todo[i]);
671             if (*get_extension(filename) == 0)
672                strcat(filename, ".pat");
673             f = pack_fopen(filename, F_READ);
674             if (f) {
675                patch[i] = load_patch(f, (i >= 128));
676                pack_fclose(f);
677                 }
678             errno = 0;
679             for (j=i+1; j<256; j++) {
680                /* share multiple copies of the instrument */
681                if (stricmp(todo[i], todo[j]) == 0) {
682                   patch[j] = patch[i];
683                   todo[j][0] = 0;
684                }
685             }
686          }
687       }
688    }
689
690    return 0;
691 }
692
693
694
695 /* digmid_freq:
696  *  Helper for converting note numbers to sample frequencies.
697  */ 
698 static inline int digmid_freq(int inst, SAMPLE *s, PATCH_EXTRA *e, int note, int bend)
699 {
700    float freq, f1, f2;
701    float sfreq = s->freq;
702    float base_note = e->base_note;
703
704    if (inst > 127) { 
705       /* drums use a fixed frequency */
706       freq = ftbl[inst-128] * sfreq / base_note;
707    }
708    else {
709       /* calculate frequency */
710       f1 = ftbl[note] * sfreq / base_note;
711       f2 = ftbl[note+1] * sfreq / base_note;
712
713       /* quick pitch bend method - ~.035% error - acceptable? */
714       freq = ((f1*(float)(4096-bend)) + (f2*(float)bend)) / 4096.0;
715    }
716
717    /* frequency scaling */
718    if (e->scale_factor != 1024) {
719       f1 = sfreq * e->scale_freq / 60;
720       freq -= f1;
721       freq = (freq * e->scale_factor) / 1024;
722       freq += f1;
723    }
724
725    /* lower by an octave if we are going to overflow */
726    while (freq >= (1<<19)-1)
727       freq /= 2;
728
729    return (int)(freq+0.5);
730 }
731
732
733
734 /* digmid_trigger:
735  *  Helper for activating a specific sample layer.
736  */
737 static inline void digmid_trigger(int inst, int snum, int note, int bend, int vol, int pan)
738 {
739    int freq, voice;
740    DIGMID_VOICE *info;
741    PATCH_EXTRA *e;
742    SAMPLE *s;
743
744    voice = _midi_allocate_voice(-1, -1);
745    if (voice < 0)
746       return;
747
748    s = patch[inst]->sample[snum];
749    e = patch[inst]->extra[snum];
750
751    freq = digmid_freq(inst, s, e, note, bend);
752
753    if (inst > 127)
754       pan = e->pan;
755
756    /* store note information for later use */
757    info = &digmid_voice[voice - midi_digmid.basevoice];
758    info->s = s;
759    info->e = e;
760    info->inst = inst;
761    info->vol = vol;
762
763    /* play the note */
764    reallocate_voice(voice, s);
765    voice_set_playmode(voice, e->play_mode);
766    voice_set_volume(voice, vol);
767    voice_set_frequency(voice, freq);
768    voice_set_pan(voice, pan);
769
770    if (e->sustain_level < 255)
771       voice_ramp_volume(voice, e->decay_time, e->sustain_level*vol/255);
772
773    voice_start(voice);
774 }
775
776
777
778 /* digmid_key_on:
779  *  Triggers the specified voice. The instrument is specified as a GM
780  *  patch number, pitch as a midi note number, and volume from 0-127.
781  *  The bend parameter is _not_ expressed as a midi pitch bend value.
782  *  It ranges from 0 (no pitch change) to 0xFFF (almost a semitone sharp).
783  *  Drum sounds are indicated by passing an instrument number greater than
784  *  128, in which case the sound is GM percussion key #(inst-128).
785  */
786 static void digmid_key_on(int inst, int note, int bend, int vol, int pan)
787 {
788    PATCH_EXTRA *e;
789    float freq;
790    int best, best_diff;
791    int diff;
792    int i, c;
793
794    /* quit if instrument is not available */
795    if ((!patch[inst]) || (patch[inst]->samples < 1))
796       return;
797
798    /* adjust volume and pan ranges */
799    vol *= 2;
800    pan *= 2;
801
802    if (patch[inst]->samples == 1) {
803       /* only one sample to choose from */
804       digmid_trigger(inst, 0, note, bend, vol, pan);
805    }
806    else {
807       /* find the sample(s) with best frequency range */
808       best = -1;
809       best_diff = INT_MAX;
810       c = 0;
811
812       for (i=0; i<patch[inst]->samples; i++) {
813          freq = ftbl[note];
814          e = patch[inst]->extra[i];
815
816          if ((freq >= e->low_note) && (freq <= e->high_note)) {
817             digmid_trigger(inst, i, note, bend, vol, pan);
818             c++;
819             if (c > 4)
820                break;
821          }
822          else {
823             diff = MIN(ABS(freq - e->low_note), ABS(freq - e->high_note));
824             if (diff < best_diff) {
825                best_diff = diff;
826                best = i;
827             }
828          }
829       }
830
831       if ((c <= 0) && (best >= 0))
832          digmid_trigger(inst, best, note, bend, vol, pan);
833    }
834 }
835
836 static END_OF_FUNCTION(digmid_key_on);
837
838
839
840 /* digmid_key_off:
841  *  Hey, guess what this does :-)
842  */
843 static void digmid_key_off(int voice)
844 {
845    DIGMID_VOICE *info = &digmid_voice[voice - midi_digmid.basevoice];
846
847    if (info->inst > 127) 
848       return;
849
850    if (info->e->release_time > 0)
851       voice_ramp_volume(voice, info->e->release_time, 0);
852    else
853       voice_stop(voice);
854 }
855
856 static END_OF_FUNCTION(digmid_key_off);
857
858
859
860 /* digmid_set_volume:
861  *  Sets the volume of the specified voice (vol range 0-127).
862  */
863 static void digmid_set_volume(int voice, int vol)
864 {
865    DIGMID_VOICE *info = &digmid_voice[voice - midi_digmid.basevoice];
866    int v;
867
868    if (info->inst > 127) 
869       return;
870
871    vol *= 2;
872
873    if (info->e->sustain_level < 255) {
874       /* adjust for volume ramping */
875       int current = voice_get_volume(voice);
876       int target = info->e->sustain_level*info->vol/255;
877       int start = info->vol;
878
879       if (ABS(current - target) < 8) {
880          /* ramp has finished */
881          voice_set_volume(voice, vol*info->e->sustain_level/255);
882       }
883       else {
884          /* in the middle of a ramp */
885          int mu;
886
887          if (start > target)
888             mu = MID(0, (current-target) * 256 / (start-target), 256);
889          else
890             mu = 0;
891
892          v = mu+info->e->sustain_level*(256-mu)/256;
893          v = MID(0, vol*v/255, 255);
894
895          voice_set_volume(voice, v);
896          voice_ramp_volume(voice, info->e->decay_time*mu/256, info->e->sustain_level*vol/255);
897       }
898    }
899    else {
900       /* no ramp */
901       voice_set_volume(voice, vol);
902    }
903
904    info->vol = vol;
905 }
906
907 static END_OF_FUNCTION(digmid_set_volume);
908
909
910
911 /* digmid_set_pitch:
912  *  Sets the pitch of the specified voice.
913  */
914 static void digmid_set_pitch(int voice, int note, int bend)
915 {
916    DIGMID_VOICE *info = &digmid_voice[voice - midi_digmid.basevoice];
917    int freq;
918
919    if (info->inst > 127)
920       return;
921
922    freq = digmid_freq(info->inst, info->s, info->e, note, bend);
923
924    voice_set_frequency(voice, freq);
925 }
926
927 static END_OF_FUNCTION(digmid_set_pitch);
928
929
930
931 /* digmid_detect:
932  *  Have we got a sensible looking patch set?
933  */
934 static int digmid_detect()
935 {
936    char dir[256], file[256];
937
938    if (!_digmid_find_patches(dir, file)) {
939       strcpy(allegro_error, "DIGMID patch set not found");
940       return FALSE;
941    }
942
943    return TRUE;
944 }
945
946
947
948 /* digmid_init:
949  *  Setup the digmid driver.
950  */
951 static int digmid_init(int voices)
952 {
953    int i;
954
955    for (i=0; i<256; i++)
956       patch[i] = NULL;
957
958    midi_digmid.voices = voices;
959
960    /* create frequency table */
961    ftbl[129] = 14080000;         /* A10 = 14080.000 hz */
962    for (i=128; i>=0; i--)
963       ftbl[i] = ftbl[i+1] / pow(2.0, 1.0/12.0);
964
965    LOCK_VARIABLE(midi_digmid);
966    LOCK_VARIABLE(patch);
967    LOCK_VARIABLE(ftbl);
968    LOCK_VARIABLE(digmid_voice);
969    LOCK_FUNCTION(digmid_key_on);
970    LOCK_FUNCTION(digmid_key_off);
971    LOCK_FUNCTION(digmid_set_volume);
972    LOCK_FUNCTION(digmid_set_pitch);
973
974    return 0;
975 }
976
977
978
979 /* digmid_exit:
980  *  Cleanup when we are finished.
981  */
982 static void digmid_exit()
983 {
984    int i, j;
985
986    for (i=0; i<256; i++) {
987       if (patch[i]) {
988          for (j=i+1; j<256; j++) {
989             if (patch[j] == patch[i])
990                patch[j] = NULL;
991          }
992          destroy_patch(patch[i]);
993          patch[i] = NULL;
994       }
995    }
996 }
997
998