porting the demo to miniglut
[dosdemo] / libs / mikmod / drivers / drv_ultra.c
1 /*      MikMod sound library
2         (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
3         complete list.
4
5         This library is free software; you can redistribute it and/or modify
6         it under the terms of the GNU Library General Public License as
7         published by the Free Software Foundation; either version 2 of
8         the License, or (at your option) any later version.
9
10         This program is distributed in the hope that it will be useful,
11         but WITHOUT ANY WARRANTY; without even the implied warranty of
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13         GNU Library General Public License for more details.
14
15         You should have received a copy of the GNU Library General Public
16         License along with this library; if not, write to the Free Software
17         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18         02111-1307, USA.
19 */
20
21 /*==============================================================================
22
23   $Id$
24
25   Driver for Gravis Ultrasound cards using libGUS.
26   A subset of libGUS is provided for DOS/DJGPP and OS/2
27
28 ==============================================================================*/
29
30 /*
31
32         Written by Andy Lo A Foe <andy@alsa-project.org>
33
34         Updated to work with later versions of both the ultrasound driver and
35         libmikmod by C. Ray C. <crayc@pyro.net>
36
37         Major fixes by Andrew Zabolotny <bit@eltech.ru>
38         + Ported to OS/2 and DOS.
39         + Eight-bit samples are not converted to 16-bit anymore.
40         + Samples are no longer kept in normal memory.
41         + Removed sample 'unclick' logic... libGUS does unclick internally.
42
43 */
44
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #include "mikmod_internals.h"
50
51 #ifdef DRV_ULTRA
52
53 #ifdef HAVE_UNISTD_H
54 #include <unistd.h>
55 #endif
56 #ifdef HAVE_MEMORY_H
57 #include <memory.h>
58 #endif
59
60 #ifdef MIKMOD_DYNAMIC
61 #include <dlfcn.h>
62 #endif
63 #include <errno.h>
64 #include <stdlib.h>
65 #include <string.h>
66
67 #include <libgus.h>
68
69 #if !defined(GUS_INSTR_SIMPLE) || !defined(GUS_WAVE_BIDIR)
70 #error libgus version is too old
71 #endif
72 /* just in case */
73 #ifndef LIBGUS_VERSION_MAJOR
74 #define LIBGUS_VERSION_MAJOR 0x0003
75 #endif
76
77 /* DOS/DJGPP and OS/2 libGUS'es have gus_get_voice_status() */
78 #if defined(__EMX__) || defined(__DJGPP__)
79 #define HAVE_VOICE_STATUS
80 #else
81 #include <time.h>
82 #endif
83
84
85 #ifdef MIKMOD_DYNAMIC
86 /* runtime link with libgus */
87 static int (*_libgus_cards) (void);
88
89 #if LIBGUS_VERSION_MAJOR < 0x0004
90 static int (*_libgus_close) (int);
91 static int (*_libgus_do_flush) (void);
92 static void (*_libgus_do_tempo) (unsigned int);
93 static void (*_libgus_do_voice_frequency) (unsigned char, unsigned int);
94 static void (*_libgus_do_voice_pan) (unsigned char, unsigned short);
95 static void (*_libgus_do_voice_start) (unsigned char, unsigned int,
96                                         unsigned int, unsigned short,
97                                         unsigned short);
98 static void (*_libgus_do_voice_start_position) (unsigned char, unsigned int,
99                                                 unsigned int, unsigned short,
100                                                 unsigned short, unsigned int);
101 static void (*_libgus_do_voice_stop) (unsigned char, unsigned char);
102 static void (*_libgus_do_voice_volume) (unsigned char, unsigned short);
103 static void (*_libgus_do_wait) (unsigned int);
104 static int (*_libgus_get_handle) (void);
105 static int (*_libgus_info) (gus_info_t *, int);
106 static int (*_libgus_memory_alloc) (gus_instrument_t *);
107 static int (*_libgus_memory_free) (gus_instrument_t *);
108 static int (*_libgus_memory_free_size) (void);
109 static int (*_libgus_memory_pack) (void);
110 static int (*_libgus_open) (int, size_t, int);
111 static int (*_libgus_queue_flush) (void);
112 static int (*_libgus_queue_read_set_size) (int);
113 static int (*_libgus_queue_write_set_size) (int);
114 static int (*_libgus_reset) (int, unsigned int);
115 static int (*_libgus_select) (int);
116 static int (*_libgus_timer_start) (void);
117 static int (*_libgus_timer_stop) (void);
118 static int (*_libgus_timer_tempo) (int);
119 #else
120 static int (*_libgus_close) (void*);
121 static int (*_libgus_do_flush) (void*);
122 static void (*_libgus_do_tempo) (void*, unsigned int);
123 static void (*_libgus_do_voice_frequency) (void*, unsigned char, unsigned int);
124 static void (*_libgus_do_voice_pan) (void*, unsigned char,unsigned short);
125 static void (*_libgus_do_voice_start) (void*, unsigned char, unsigned int,
126                                         unsigned int, unsigned short,
127                                         unsigned short);
128 static void (*_libgus_do_voice_start_position) (void*, unsigned char, unsigned int,
129                                                 unsigned int,unsigned short,
130                                                 unsigned short, unsigned int);
131 static void (*_libgus_do_voice_stop) (void*, unsigned char, unsigned char);
132 static void (*_libgus_do_voice_volume) (void*, unsigned char, unsigned short);
133 static void (*_libgus_do_wait) (void*, unsigned int);
134 static int (*_libgus_get_file_descriptor) (void*);
135 static int (*_libgus_info) (void*, gus_info_t*, int);
136 static int (*_libgus_memory_alloc) (void*, gus_instrument_t*);
137 static int (*_libgus_memory_free) (void*, gus_instrument_t*);
138 static int (*_libgus_memory_free_size) (void*);
139 static int (*_libgus_memory_pack) (void*);
140 static int (*_libgus_open) (void**, int, int, size_t, int);
141 static int (*_libgus_queue_flush) (void*);
142 static int (*_libgus_queue_read_set_size) (void*, int);
143 static int (*_libgus_queue_write_set_size) (void*, int);
144 static int (*_libgus_reset) (void*, int, unsigned int);
145 static int (*_libgus_timer_start)(void*);
146 static int (*_libgus_timer_stop) (void*);
147 static int (*_libgus_timer_tempo) (void*, int);
148 #endif
149 #ifndef HAVE_RTLD_GLOBAL
150 #define RTLD_GLOBAL (0)
151 #endif
152 static void *libgus = NULL;
153
154 #else
155 /* compile-time link with libgus */
156 #define _libgus_cards                           gus_cards
157 #define _libgus_close                           gus_close
158 #define _libgus_do_flush                        gus_do_flush
159 #define _libgus_do_tempo                        gus_do_tempo
160 #define _libgus_do_voice_frequency              gus_do_voice_frequency
161 #define _libgus_do_voice_pan                    gus_do_voice_pan
162 #define _libgus_do_voice_start                  gus_do_voice_start
163 #define _libgus_do_voice_start_position         gus_do_voice_start_position
164 #define _libgus_do_voice_stop                   gus_do_voice_stop
165 #define _libgus_do_voice_volume                 gus_do_voice_volume
166 #define _libgus_do_wait                         gus_do_wait
167 #if LIBGUS_VERSION_MAJOR < 0x0004
168 #define _libgus_get_handle                      gus_get_handle
169 #else
170 #define _libgus_get_file_descriptor             gus_get_file_descriptor
171 #endif
172 #define _libgus_info                            gus_info
173 #define _libgus_memory_alloc                    gus_memory_alloc
174 #define _libgus_memory_free                     gus_memory_free
175 #define _libgus_memory_free_size                gus_memory_free_size
176 #define _libgus_memory_pack                     gus_memory_pack
177 #define _libgus_open                            gus_open
178 #define _libgus_queue_flush                     gus_queue_flush
179 #define _libgus_queue_read_set_size             gus_queue_read_set_size
180 #define _libgus_queue_write_set_size            gus_queue_write_set_size
181 #define _libgus_reset                           gus_reset
182 #if LIBGUS_VERSION_MAJOR < 0x0004
183 #define _libgus_select                          gus_select
184 #endif
185 #define _libgus_timer_start                     gus_timer_start
186 #define _libgus_timer_stop                      gus_timer_stop
187 #define _libgus_timer_tempo                     gus_timer_tempo
188 #endif
189
190 #define libgus_cards                            _libgus_cards   /* same between v3 and v4 */
191 #define libgus_open                             _libgus_open    /* different between v3 and v4: must use #ifdef */
192 #define libgus_close                            _libgus_close   /* different between v3 and v4: must use #ifdef */
193 /* the following can be handled easily by macros: v4 only adds them the handle as the first param */
194 #if LIBGUS_VERSION_MAJOR < 0x0004
195 #define libgus_get_handle                       _libgus_get_handle /* only in v3 */
196 #define libgus_do_flush                         _libgus_do_flush
197 #define libgus_do_tempo                         _libgus_do_tempo
198 #define libgus_do_voice_frequency               _libgus_do_voice_frequency
199 #define libgus_do_voice_pan                     _libgus_do_voice_pan
200 #define libgus_do_voice_start                   _libgus_do_voice_start
201 #define libgus_do_voice_start_position          _libgus_do_voice_start_position
202 #define libgus_do_voice_stop                    _libgus_do_voice_stop
203 #define libgus_do_voice_volume                  _libgus_do_voice_volume
204 #define libgus_do_wait                          _libgus_do_wait
205 #define libgus_info                             _libgus_info
206 #define libgus_memory_alloc                     _libgus_memory_alloc
207 #define libgus_memory_free                      _libgus_memory_free
208 #define libgus_memory_free_size                 _libgus_memory_free_size
209 #define libgus_memory_pack                      _libgus_memory_pack
210 #define libgus_queue_flush                      _libgus_queue_flush
211 #define libgus_queue_read_set_size              _libgus_queue_read_set_size
212 #define libgus_queue_write_set_size             _libgus_queue_write_set_size
213 #define libgus_reset                            _libgus_reset
214 #define libgus_select                           _libgus_select
215 #define libgus_timer_start                      _libgus_timer_start
216 #define libgus_timer_stop                       _libgus_timer_stop
217 #define libgus_timer_tempo                      _libgus_timer_tempo
218 #else
219 #define libgus_get_file_descriptor              _libgus_get_file_descriptor /* only in v4 */
220 #define libgus_do_flush()                       _libgus_do_flush(ultra_h)
221 #define libgus_do_tempo(t)                      _libgus_do_tempo(ultra_h,t)
222 #define libgus_do_voice_frequency(a,b)          _libgus_do_voice_frequency(ultra_h,a,b)
223 #define libgus_do_voice_pan(a,b)                _libgus_do_voice_pan(ultra_h,a,b)
224 #define libgus_do_voice_start(a,b,c,d,e)        _libgus_do_voice_start(ultra_h,a,b,c,d,e)
225 #define libgus_do_voice_start_position(a,b,c,d,e,f) _libgus_do_voice_start_position(ultra_h,a,b,c,d,e,f)
226 #define libgus_do_voice_stop(a,b)               _libgus_do_voice_stop(ultra_h,a,b)
227 #define libgus_do_voice_volume(a,b)             _libgus_do_voice_volume(ultra_h,a,b)
228 #define libgus_do_wait(a)                       _libgus_do_wait(ultra_h,a)
229 #define libgus_info(a,b)                        _libgus_info(ultra_h,a,b)
230 #define libgus_memory_alloc(a)                  _libgus_memory_alloc(ultra_h,a)
231 #define libgus_memory_free(a)                   _libgus_memory_free(ultra_h,a)
232 #define libgus_memory_free_size()               _libgus_memory_free_size(ultra_h)
233 #define libgus_memory_pack()                    _libgus_memory_pack(ultra_h)
234 #define libgus_queue_flush()                    _libgus_queue_flush(ultra_h)
235 #define libgus_queue_read_set_size(a)           _libgus_queue_read_set_size(ultra_h,a)
236 #define libgus_queue_write_set_size(a)          _libgus_queue_write_set_size(ultra_h,a)
237 #define libgus_reset(a,b)                       _libgus_reset(ultra_h,a,b)
238 #define libgus_timer_start()                    _libgus_timer_start(ultra_h)
239 #define libgus_timer_stop()                     _libgus_timer_stop(ultra_h)
240 #define libgus_timer_tempo(a)                   _libgus_timer_tempo(ultra_h,a)
241 #endif
242
243 #define GUS_SAMPLES                     256     /* Max. GUS samples loadable */
244 #define GUS_CHANNELS                    32      /* Max. GUS channels available */
245 #define SIZE_OF_SEQBUF          (8 * 1024)      /* Size of the sequence buffer */
246 #define ULTRA_PAN_MIDDLE        (16383 >> 1)    /* Middle balance position */
247
248 #define CH_FREQ 1
249 #define CH_VOL  2
250 #define CH_PAN  4
251
252 /*      This structure holds the current state of a GUS voice channel. */
253 typedef struct GUS_VOICE {
254         UBYTE kick;
255         UBYTE active;
256         UWORD flags;
257         SWORD handle;
258         ULONG start;
259         ULONG size;
260         ULONG reppos;
261         ULONG repend;
262         ULONG frq;
263         int vol;
264         int decvol;
265         int pan;
266
267         int changes;
268 #ifndef HAVE_VOICE_STATUS
269         time_t started;
270 #endif
271 } GUS_VOICE;
272
273 /* Global declarations follow */
274
275 static SAMPLE *samples[GUS_SAMPLES];    /* sample handles */
276 static GUS_VOICE voices[GUS_CHANNELS];  /* channel status */
277
278 static int ultra_dev = 0;       /* GUS index, if more than one card */
279 #if LIBGUS_VERSION_MAJOR < 0x0004
280 static int ultra_card = -1;     /* returned by gus_open(ultra_dev,,) - must be same as ultra_dev */
281 #else
282 static void* ultra_h = NULL;    /* GUS handle */
283 #endif
284 static int ultra_fd = -1;       /* GUS file descriptor */
285
286
287 #ifdef MIKMOD_DYNAMIC
288 static int Ultra_Link(void)
289 {
290         if (libgus)
291                 return 0;
292
293         /* load libgus.so */
294 #if LIBGUS_VERSION_MAJOR < 0x0004
295         libgus = dlopen("libgus.so.3", RTLD_LAZY | RTLD_GLOBAL);
296 #else
297         libgus = dlopen("libgus.so.4", RTLD_LAZY | RTLD_GLOBAL);
298 #endif
299         if (!libgus) /* then this won't succeed either, but whatever.. */
300                 libgus = dlopen("libgus.so", RTLD_LAZY | RTLD_GLOBAL);
301         if (!libgus)
302                 return 1;
303
304         /* resolve function references */
305 #define IMPORT_SYMBOL(x,ret,params) \
306         if (!(_lib##x = (ret (*)params) dlsym(libgus, #x))) return 1
307
308         IMPORT_SYMBOL(gus_cards, int, (void));
309 #if LIBGUS_VERSION_MAJOR < 0x0004
310         IMPORT_SYMBOL(gus_close, int, (int));
311         IMPORT_SYMBOL(gus_do_flush, int, (void));
312         IMPORT_SYMBOL(gus_do_tempo, void, (unsigned int));
313         IMPORT_SYMBOL(gus_do_voice_frequency, void, (unsigned char, unsigned int));
314         IMPORT_SYMBOL(gus_do_voice_pan, void, (unsigned char, unsigned short));
315         IMPORT_SYMBOL(gus_do_voice_start, void, (unsigned char, unsigned int, unsigned int, unsigned short, unsigned short));
316         IMPORT_SYMBOL(gus_do_voice_start_position, void, (unsigned char, unsigned int, unsigned int, unsigned short, unsigned short, unsigned int));
317         IMPORT_SYMBOL(gus_do_voice_stop, void, (unsigned char, unsigned char));
318         IMPORT_SYMBOL(gus_do_voice_volume, void, (unsigned char, unsigned short));
319         IMPORT_SYMBOL(gus_do_wait, void, (unsigned int));
320         IMPORT_SYMBOL(gus_get_handle, int, (void));
321         IMPORT_SYMBOL(gus_info, int, (gus_info_t *, int));
322         IMPORT_SYMBOL(gus_memory_alloc, int, (gus_instrument_t *));
323         IMPORT_SYMBOL(gus_memory_free, int, (gus_instrument_t *));
324         IMPORT_SYMBOL(gus_memory_free_size, int, (void));
325         IMPORT_SYMBOL(gus_memory_pack, int, (void));
326         IMPORT_SYMBOL(gus_open, int, (int, size_t, int));
327         IMPORT_SYMBOL(gus_queue_flush, int, (void));
328         IMPORT_SYMBOL(gus_queue_read_set_size, int, (int));
329         IMPORT_SYMBOL(gus_queue_write_set_size, int, (int));
330         IMPORT_SYMBOL(gus_reset, int, (int, unsigned int));
331         IMPORT_SYMBOL(gus_select, int, (int));
332         IMPORT_SYMBOL(gus_timer_start, int, (void));
333         IMPORT_SYMBOL(gus_timer_stop, int, (void));
334         IMPORT_SYMBOL(gus_timer_tempo, int, (int));
335 #else
336         IMPORT_SYMBOL(gus_close, int, (void*));
337         IMPORT_SYMBOL(gus_do_flush, int, (void*));
338         IMPORT_SYMBOL(gus_do_tempo, void, (void*, unsigned int));
339         IMPORT_SYMBOL(gus_do_voice_frequency, void, (void*, unsigned char, unsigned int));
340         IMPORT_SYMBOL(gus_do_voice_pan, void, (void*, unsigned char, unsigned short));
341         IMPORT_SYMBOL(gus_do_voice_start, void, (void*, unsigned char, unsigned int, unsigned int, unsigned short, unsigned short));
342         IMPORT_SYMBOL(gus_do_voice_start_position, void, (void*, unsigned char, unsigned int, unsigned int, unsigned short, unsigned short, unsigned int));
343         IMPORT_SYMBOL(gus_do_voice_stop, void, (void*, unsigned char, unsigned char));
344         IMPORT_SYMBOL(gus_do_voice_volume, void, (void*, unsigned char, unsigned short));
345         IMPORT_SYMBOL(gus_do_wait, void, (void*, unsigned int));
346         IMPORT_SYMBOL(gus_get_file_descriptor, int, (void*));
347         IMPORT_SYMBOL(gus_info, int, (void*, gus_info_t *, int));
348         IMPORT_SYMBOL(gus_memory_alloc, int, (void*, gus_instrument_t *));
349         IMPORT_SYMBOL(gus_memory_free, int, (void*, gus_instrument_t *));
350         IMPORT_SYMBOL(gus_memory_free_size, int, (void*));
351         IMPORT_SYMBOL(gus_memory_pack, int, (void*));
352         IMPORT_SYMBOL(gus_open, int, (void**, int, int, size_t, int));
353         IMPORT_SYMBOL(gus_queue_flush, int, (void*));
354         IMPORT_SYMBOL(gus_queue_read_set_size, int, (void*, int));
355         IMPORT_SYMBOL(gus_queue_write_set_size, int, (void*, int));
356         IMPORT_SYMBOL(gus_reset, int, (void*, int, unsigned int));
357         IMPORT_SYMBOL(gus_timer_start, int, (void*));
358         IMPORT_SYMBOL(gus_timer_stop, int, (void*));
359         IMPORT_SYMBOL(gus_timer_tempo, int, (void*, int));
360 #endif
361 #undef IMPORT_SYMBOL
362
363         return 0;
364 }
365
366 static void Ultra_Unlink(void)
367 {
368         _libgus_cards = NULL;
369         _libgus_close = NULL;
370         _libgus_do_flush = NULL;
371         _libgus_do_tempo = NULL;
372         _libgus_do_voice_frequency = NULL;
373         _libgus_do_voice_pan = NULL;
374         _libgus_do_voice_start = NULL;
375         _libgus_do_voice_start_position = NULL;
376         _libgus_do_voice_stop = NULL;
377         _libgus_do_voice_volume = NULL;
378         _libgus_do_wait = NULL;
379 #if LIBGUS_VERSION_MAJOR < 0x0004
380         _libgus_get_handle = NULL;
381 #else
382         _libgus_get_file_descriptor = NULL;
383 #endif
384         _libgus_info = NULL;
385         _libgus_memory_alloc = NULL;
386         _libgus_memory_free = NULL;
387         _libgus_memory_free_size = NULL;
388         _libgus_memory_pack = NULL;
389         _libgus_open = NULL;
390         _libgus_queue_flush = NULL;
391         _libgus_queue_read_set_size = NULL;
392         _libgus_queue_write_set_size = NULL;
393         _libgus_reset = NULL;
394 #if LIBGUS_VERSION_MAJOR < 0x0004
395         _libgus_select = NULL;
396 #endif
397         _libgus_timer_start = NULL;
398         _libgus_timer_stop = NULL;
399         _libgus_timer_tempo = NULL;
400
401         if (libgus) {
402                 dlclose(libgus);
403                 libgus = NULL;
404         }
405 }
406 #endif
407
408 static void Ultra_CommandLine(const CHAR *cmdline)
409 {
410         CHAR *ptr = MD_GetAtom("card", cmdline, 0);
411
412         if (ptr) {
413                 int buf = atoi(ptr);
414
415                 if (buf >= 0 && buf <= 8)
416                         ultra_dev = buf;
417                 MikMod_free(ptr);
418         }
419 #ifdef __DJGPP__
420         ptr = MD_GetAtom("dma", cmdline, 0);
421         if (ptr) {
422                 gus_dma_usage (atoi(ptr));
423                 MikMod_free(ptr);
424         }
425 #endif
426 }
427
428 /* Checks for the presence of GUS cards */
429 static BOOL Ultra_IsThere(void)
430 {
431         BOOL retval;
432
433 #ifdef MIKMOD_DYNAMIC
434         if (Ultra_Link())
435                 return 0;
436 #endif
437         retval = libgus_cards()? 1 : 0;
438 #ifdef MIKMOD_DYNAMIC
439         Ultra_Unlink();
440 #endif
441         return retval;
442 }
443
444 /* Load a new sample directly into GUS DRAM and return a handle */
445 static SWORD Ultra_SampleLoad(struct SAMPLOAD *sload, int type)
446 {
447         int handle;
448         SAMPLE *s = sload->sample;
449         gus_instrument_t instrument;
450         gus_layer_t layer;
451         gus_wave_t wave;
452         unsigned char *buffer;
453         unsigned int length, loopstart, loopend;
454
455         /* Find empty slot to put sample in */
456         for (handle = 0; handle < GUS_SAMPLES; handle++)
457                 if (!samples[handle])
458                         break;
459
460         if (handle == GUS_SAMPLES) {
461                 _mm_errno = MMERR_OUT_OF_HANDLES;
462                 return -1;
463         }
464
465         /* Fill an gus_instrument_t structure and feed it to libgus. We can
466            download 8 and 16 bit, both signed and unsigned samples into GUS, so
467            don't bother much about formats here. */
468
469         /* convert position/length data from samples to bytes */
470         length = s->length;
471         loopstart = s->loopstart;
472         loopend = s->loopend ? s->loopend : length;
473         /* sanity checks */
474         if (loopend > length)
475                 loopend = length;
476         if (loopstart > loopend)
477                 loopstart = loopend;
478         if (s->flags & SF_16BITS) {
479                 length <<= 1;
480                 loopstart <<= 1;
481                 loopend <<= 1;
482         }
483
484         /* Load sample into normal memory */
485         if (!(buffer = (unsigned char *) MikMod_malloc(length))) {
486                 _mm_errno = MMERR_SAMPLE_TOO_BIG;
487                 return -1;
488         }
489
490         if (SL_Load(buffer, sload, s->length)) {
491                 MikMod_free(buffer);
492                 return -1;
493         }
494
495         samples[handle] = s;
496
497         memset(&wave, 0, sizeof(wave));
498         memset(&layer, 0, sizeof(layer));
499         memset(&instrument, 0, sizeof(instrument));
500
501         wave.format =
502                 ((s->flags & SF_SIGNED) ? 0 : GUS_WAVE_INVERT) |
503                 ((s->flags & SF_16BITS) ? GUS_WAVE_16BIT : 0) |
504                 ((s->flags & SF_DELTA ) ? GUS_WAVE_DELTA : 0) |
505                 ((s->flags & SF_LOOP  ) ? GUS_WAVE_LOOP  : 0) |
506                 ((s->flags & SF_BIDI  ) ? GUS_WAVE_BIDIR : 0);
507         wave.begin.ptr = buffer;
508         wave.loop_start = loopstart << 4;
509         wave.loop_end = loopend << 4;
510         wave.size = length;
511
512         layer.wave = &wave;
513
514         instrument.mode = layer.mode = wave.mode = GUS_INSTR_SIMPLE;
515         instrument.number.instrument = handle;
516         instrument.info.layer = &layer;
517
518         /* Download the sample to GUS RAM */
519         if (libgus_memory_alloc(&instrument)) {
520                 MikMod_free(buffer);
521                 _mm_errno = MMERR_SAMPLE_TOO_BIG;
522                 return -1;
523         }
524
525         MikMod_free(buffer);
526         return handle;
527 }
528
529 /* Discards a sample from the GUS memory and mark handle as free */
530 static void Ultra_SampleUnload(SWORD handle)
531 {
532         gus_instrument_t instrument;
533
534         if (handle >= GUS_SAMPLES || handle < 0 || !samples[handle])
535                 return;
536
537         memset(&instrument, 0, sizeof(instrument));
538         instrument.mode = GUS_INSTR_SIMPLE;
539         instrument.number.instrument = handle;
540         libgus_memory_free(&instrument);
541         samples[handle] = NULL;
542 }
543
544 /* Reports available sample space */
545 static ULONG Ultra_SampleSpace(int type)
546 {
547         libgus_memory_pack();
548         return (libgus_memory_free_size());
549 }
550
551 /* Reports the size of a sample */
552 static ULONG Ultra_SampleLength(int type, SAMPLE *s)
553 {
554         if (!s)
555                 return 0;
556
557         if (s->flags & SF_16BITS)
558                 return ((s->length << 1) + 31) & ~31;
559         else
560                 return ( s->length       + 15) & ~15;
561 }
562
563 /* Initializes the driver */
564 static int Ultra_Init_internal(void)
565 {
566         gus_info_t info;
567
568 #if LIBGUS_VERSION_MAJOR < 0x0004
569         if ((ultra_card = libgus_open(ultra_dev, SIZE_OF_SEQBUF, 0)) < 0) {
570                 _mm_errno = (errno == ENOMEM)? MMERR_OUT_OF_MEMORY : MMERR_INVALID_DEVICE;
571                 return 1;
572         }
573         libgus_select(ultra_card);
574         ultra_fd = libgus_get_handle();
575 #else
576         if (libgus_open(&ultra_h, ultra_dev, 0, SIZE_OF_SEQBUF, GUS_OPEN_FLAG_NONE) < 0) {
577                 _mm_errno = (errno == ENOMEM)? MMERR_OUT_OF_MEMORY : MMERR_INVALID_DEVICE;
578                 return 1;
579         }
580         ultra_fd = libgus_get_file_descriptor(ultra_h);
581 #endif
582
583         /* We support only 16-bit stereo with 44K mixing frequency. On UltraSound
584            Classic mixing frequency depends on number of channels, on Interwave it
585            is always 44KHz. */
586         md_mode |= DMODE_16BITS | DMODE_STEREO;
587         md_mixfreq = info.mixing_freq;
588
589         libgus_info(&info, 0);
590 #ifdef MIKMOD_DEBUG
591         switch (info.version) {
592           case 0x24:
593                 fputs("GUS 2.4", stderr);
594                 break;
595           case 0x35:
596                 fputs("GUS 3.7 (flipped)", stderr);
597                 break;
598           case 0x37:
599                 fputs("GUS 3.7", stderr);
600                 break;
601           case 0x90:
602                 fputs("GUS ACE", stderr);
603                 break;
604           case 0xa0:
605                 fputs("GUS MAX 10", stderr);
606                 break;
607           case 0xa1:
608                 fputs("GUS MAX 11", stderr);
609                 break;
610           case 0x100:
611                 fputs("Interwave/GUS PnP", stderr);
612                 break;
613           default:
614                 fprintf(stderr, "Unknown GUS type %x", info.version);
615                 break;
616         }
617         fprintf(stderr, " with %dKb RAM on board\n", info.memory_size >> 10);
618 #endif
619
620         /* Zero the voice states and sample handles */
621         memset (&voices, 0, sizeof (voices));
622         memset (&samples, 0, sizeof (samples));
623
624         return 0;
625 }
626
627 static int Ultra_Init(void)
628 {
629 #ifdef MIKMOD_DYNAMIC
630         if (Ultra_Link()) {
631                 _mm_errno = MMERR_DYNAMIC_LINKING;
632                 return 1;
633         }
634 #endif
635         return Ultra_Init_internal();
636 }
637
638 /* Closes the driver */
639 static void Ultra_Exit_internal(void)
640 {
641 #if LIBGUS_VERSION_MAJOR < 0x0004
642         if (ultra_card >= 0) {
643                 ultra_card = -1;
644                 libgus_close(ultra_dev);
645         }
646 #else
647         if (ultra_h) {
648                 libgus_close(ultra_h);
649                 ultra_h = NULL;
650         }
651 #endif
652         ultra_fd = -1;
653 }
654
655 static void Ultra_Exit(void)
656 {
657         Ultra_Exit_internal();
658 #ifdef MIKMOD_DYNAMIC
659         Ultra_Unlink();
660 #endif
661 }
662
663 /* Poor man's reset function */
664 static int Ultra_Reset(void)
665 {
666         Ultra_Exit_internal();
667         return Ultra_Init_internal();
668 }
669
670 static int Ultra_SetNumVoices(void)
671 {
672         return 0;
673 }
674
675 /* Module player tick function */
676 static void UltraPlayer(void)
677 {
678         int channel, panning;
679         struct GUS_VOICE *voice;
680         static BOOL ultra_pause = 1;    /* paused status */
681
682         md_player();
683
684         if (ultra_pause != Player_Paused())
685                 if ((ultra_pause = Player_Paused()))
686                         for (channel = 0, voice = voices; channel < md_numchn;
687                              channel++, voice++) {
688                                 libgus_do_voice_volume (channel, 0);
689                                 voices->changes |= (CH_VOL | CH_FREQ | CH_PAN);
690                         }
691
692         if (ultra_pause)
693                 return;
694
695         for (channel = 0, voice = voices; channel < md_numchn; channel++, voice++) {
696                 panning = (voice->pan == PAN_SURROUND) ?
697                                ULTRA_PAN_MIDDLE : (voice->pan << 6);
698
699                 if (voice->kick) {
700                         voice->kick = 0;
701                         voice->decvol = voice->vol;
702                         if (voice->start > 0)
703                                 libgus_do_voice_start_position(channel, voice->handle,
704                                       voice->frq, voice->vol << 6, panning, voice->start << 4);
705                         else
706                                 libgus_do_voice_start(channel, voice->handle, voice->frq,
707                                                          voice->vol << 6, voice->pan << 6);
708                 } else {
709                         if (voice->changes & CH_FREQ)
710                                 libgus_do_voice_frequency(channel, voice->frq);
711                         if (voice->changes & CH_VOL)
712                                 libgus_do_voice_volume(channel, voice->vol << 6);
713                         if (voice->changes & CH_PAN)
714                                 libgus_do_voice_pan(channel, panning);
715                         if (voice->decvol)
716                                 voice->decvol -= 4;
717                 }
718                 voice->changes = 0;
719         }
720 }
721
722 /* Play sound */
723 #if defined(__DJGPP__) || defined(__EMX__)
724 static void Ultra_Callback(void)
725 {
726         UltraPlayer();
727         libgus_do_flush();
728 }
729
730 static void Ultra_Update(void)
731 {
732         static UWORD ultra_bpm = 0;             /* current GUS tempo */
733
734         /* All real work is done during GF1 timer 1 interrupt */
735         if (ultra_bpm != md_bpm) {
736                 libgus_do_tempo((md_bpm * 50) / 125);
737                 ultra_bpm = md_bpm;
738         }
739 }
740
741 #else
742 static void Ultra_Update(void)
743 {
744         fd_set write_fds;
745         int need_write;
746         static UWORD ultra_bpm = 0;     /* current GUS tempo */
747
748         if (ultra_bpm != md_bpm) {
749                 libgus_do_tempo((md_bpm * 50) / 125);
750                 ultra_bpm = md_bpm;
751         }
752
753         UltraPlayer();
754
755         do {
756                 need_write = libgus_do_flush();
757
758                 FD_ZERO(&write_fds);
759                 do {
760                         FD_SET(ultra_fd, &write_fds);
761
762                         select(ultra_fd + 1, NULL, &write_fds, NULL, NULL);
763                 } while (!FD_ISSET(ultra_fd, &write_fds));
764         } while(need_write > 0);
765
766         /* Wait so that all voice commands gets executed */
767         libgus_do_wait (1);
768 }
769
770 #endif
771
772 /* Start playback */
773 static int Ultra_PlayStart(void)
774 {
775         int t;
776         gus_info_t info;
777
778         for (t = 0; t < md_numchn; t++) {
779                 voices[t].flags = 0;
780                 voices[t].handle = 0;
781                 voices[t].size = 0;
782                 voices[t].start = 0;
783                 voices[t].reppos = 0;
784                 voices[t].repend = 0;
785                 voices[t].changes = 0;
786                 voices[t].kick = 0;
787                 voices[t].frq = 10000;
788                 voices[t].vol = 0;
789                 voices[t].pan = ULTRA_PAN_MIDDLE;
790                 voices[t].active = 0;
791         }
792
793 #if LIBGUS_VERSION_MAJOR < 0x0004
794         libgus_select(ultra_card);
795 #endif
796         if (libgus_reset(md_numchn, 0) < 0) {
797                 _mm_errno = MMERR_GUS_RESET;
798                 return 1;
799         }
800
801         /* Query mixing frequency */
802         libgus_info(&info, 0);
803         md_mixfreq = info.mixing_freq;
804
805         libgus_queue_write_set_size(1024);
806         libgus_queue_read_set_size(128);
807
808         if (libgus_timer_start() < 0) {
809                 _mm_errno = MMERR_GUS_TIMER;
810                 return 1;
811         }
812
813 #if defined(__DJGPP__) || defined(__EMX__)
814         gus_timer_callback(Ultra_Callback);
815 #endif
816
817         libgus_timer_tempo(50);
818
819         for (t = 0; t < md_numchn; t++) {
820                 libgus_do_voice_pan(t, ULTRA_PAN_MIDDLE);
821                 libgus_do_voice_volume(t, 0 << 8);
822         }
823
824         libgus_do_flush();
825
826         return 0;
827 }
828
829 /* Stop playback */
830 static void Ultra_PlayStop(void)
831 {
832         int voice;
833
834         libgus_queue_flush();
835         libgus_timer_stop();
836         libgus_queue_write_set_size(0);
837         libgus_queue_read_set_size(0);
838         for(voice = 0; voice < md_numchn; voice++)
839                 libgus_do_voice_stop(voice, 0);
840
841 #if defined(__DJGPP__) || defined(__EMX__)
842         gus_timer_callback(NULL);
843 #endif
844
845         libgus_do_flush();
846 }
847
848 /* Set the volume for the given voice */
849 static void Ultra_VoiceSetVolume(UBYTE voice, UWORD vol)
850 {
851         if (voice < md_numchn)
852                 if (vol != voices[voice].vol) {
853                         voices[voice].decvol =
854                         voices[voice].vol = vol;
855                         voices[voice].changes |= CH_VOL;
856                 }
857 }
858
859 /* Returns the volume of the given voice */
860 static UWORD Ultra_VoiceGetVolume(UBYTE voice)
861 {
862         return (voice < md_numchn) ? voices[voice].vol : 0;
863 }
864
865 /* Set the pitch for the given voice */
866 static void Ultra_VoiceSetFrequency(UBYTE voice, ULONG frq)
867 {
868         if (voice < md_numchn)
869                 if (frq != voices[voice].frq) {
870                         voices[voice].frq = frq;
871                         voices[voice].changes |= CH_FREQ;
872                 }
873 }
874
875 /* Returns the frequency of the given voice */
876 static ULONG Ultra_VoiceGetFrequency(UBYTE voice)
877 {
878         return (voice < md_numchn) ? voices[voice].frq : 0;
879 }
880
881 /* Set the panning position for the given voice */
882 static void Ultra_VoiceSetPanning(UBYTE voice, ULONG pan)
883 {
884         if (voice < md_numchn)
885                 if (pan != voices[voice].pan) {
886                         voices[voice].pan = pan;
887                         voices[voice].changes |= CH_PAN;
888                 }
889 }
890
891 /* Returns the panning of the given voice */
892 static ULONG Ultra_VoiceGetPanning(UBYTE voice)
893 {
894         return (voice < md_numchn) ? voices[voice].pan : 0;
895 }
896
897 /* Start a new sample on a voice */
898 static void Ultra_VoicePlay(UBYTE voice, SWORD handle, ULONG start,
899                                                         ULONG size, ULONG reppos, ULONG repend,
900                                                         UWORD flags)
901 {
902         if ((voice >= md_numchn) || (start >= size))
903                 return;
904
905         if (flags & SF_LOOP)
906                 if (repend > size)
907                         repend = size;
908
909         voices[voice].flags = flags;
910         voices[voice].handle = handle;
911         voices[voice].start = start;
912         voices[voice].size = size;
913         voices[voice].reppos = reppos;
914         voices[voice].repend = repend;
915         voices[voice].kick = 1;
916         voices[voice].active = 1;
917 #ifndef HAVE_VOICE_STATUS
918         voices[voice].started = time(NULL);
919 #endif
920 }
921
922 /* Stops a voice */
923 static void Ultra_VoiceStop(UBYTE voice)
924 {
925         if (voice < md_numchn)
926                 voices[voice].active = 0;
927 }
928
929 /* Returns whether a voice is stopped */
930 static BOOL Ultra_VoiceStopped(UBYTE voice)
931 {
932         if (voice >= md_numchn)
933                 return 1;
934
935 #ifdef HAVE_VOICE_STATUS
936         if (voices[voice].active)
937                 return gus_get_voice_status(voice) ? 0 : 1;
938         else
939                 return 1;
940 #else
941         if (voices[voice].active) {
942                 /* is sample looping ? */
943                 if (voices[voice].flags & (SF_LOOP | SF_BIDI))
944                         return 0;
945                 else
946                   if (time(NULL) - voices[voice].started >=
947                           ((voices[voice].size - voices[voice].start + md_mixfreq -1)
948                           / md_mixfreq)) {
949                         voices[voice].active = 0;
950                         return 1;
951                 }
952                 return 0;
953         } else
954                 return 1;
955 #endif
956 }
957
958 /* Returns current voice position */
959 static SLONG Ultra_VoiceGetPosition(UBYTE voice)
960 {
961         /* NOTE This information can not be determined. */
962         return -1;
963 }
964
965 /* Returns voice real volume */
966 static ULONG Ultra_VoiceRealVolume(UBYTE voice)
967 {
968         int retval = 0;
969         if (!Ultra_VoiceStopped (voice)) {
970                 /* NOTE This information can not be accurately determined. */
971                 retval = (voices [voice].decvol) << 8;
972                 if (retval > 0xffff) retval = 0xffff;
973         }
974         return retval;
975 }
976
977 MDRIVER drv_ultra = {
978         NULL,
979         "Gravis Ultrasound native mode",
980         "Gravis Ultrasound native mode driver v1.2",
981         0, (GUS_CHANNELS)-1,
982         "ultra",
983 #ifdef __DJGPP__
984         "dma:b:1:Use DMA for transferring samples into GUS DRAM\n"
985 #endif
986         "card:r:0,8,0:Soundcard number\n",
987
988         Ultra_CommandLine,
989         Ultra_IsThere,
990         Ultra_SampleLoad,
991         Ultra_SampleUnload,
992         Ultra_SampleSpace,
993         Ultra_SampleLength,
994         Ultra_Init,
995         Ultra_Exit,
996         Ultra_Reset,
997         Ultra_SetNumVoices,
998         Ultra_PlayStart,
999         Ultra_PlayStop,
1000         Ultra_Update,
1001         NULL,
1002         Ultra_VoiceSetVolume,
1003         Ultra_VoiceGetVolume,
1004         Ultra_VoiceSetFrequency,
1005         Ultra_VoiceGetFrequency,
1006         Ultra_VoiceSetPanning,
1007         Ultra_VoiceGetPanning,
1008         Ultra_VoicePlay,
1009         Ultra_VoiceStop,
1010         Ultra_VoiceStopped,
1011         Ultra_VoiceGetPosition,
1012         Ultra_VoiceRealVolume
1013 };
1014 #else
1015
1016 MISSING(drv_ultra);
1017
1018 #endif /* DRV_ULTRA */
1019
1020 /* ex:set ts=8: */