1 /***************************************************************************
2 * S3m/Mod player by Daniel Marks (dmarks@ais.net)
3 * GUS support by David Jeske (jeske@uiuc.edu)
4 *
5 * (C) 1994,1995 By Daniel Marks and David Jeske
6 *
7 * While we retain the copyright to this code, this source code is FREE.
8 * You may use it in any way you wish, in any product you wish. You may
9 * NOT steal the copyright for this code from us.
10 *
11 * We respectfully ask that you email one of us, if possible, if you
12 * produce something significant with this code, or if you have any bug
13 * fixes to contribute. We also request that you give credit where
14 * credit is due if you include part of this code in a program of your own.
15 *
16 * Email: s3mod@uiuc.edu
17 * jeske@uiuc.edu
18 *
19 * See the associated README file for Thanks
20 ***************************************************************************
21 *
22 * gus.c - Support for the Gravis Ultrasound card using the Voxware(C)
23 * drivers.
24 */
25
26 #ifdef GUS
27
28 #include <sys/soundcard.h>
29 #include <machine/ultrasound.h>
30 #include <unistd.h>
31 #include "gus.h"
32 #include "mod.h"
33 #include "play.h"
34 #include <sys/types.h>
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include "tables.h"
38 #include "main.h"
39
40 /* /dev/sequencer information:
41 *
42 * /dev/sequencer was a mystery to me when I began this project
43 * so I will attempt to explain what I have learned about it so far.
44 *
45 * First, you must define a sequencer buffer (SEQ_DEFINEBUF(XXXX))
46 * for your sequencer commands.
47 *
48 * the sequencer commands can be found in "soundcard.h", with some
49 * GUS specific commands being found in "ultrasound.h".
50 * When you want to do stuff with /dev/sequencer, you need to have a
51 * time synchronization so that things happen at the right time.
52 * Convinently, /dev/sequencer provides this as well.
53 * the "sync_time" function, along with "this_time" and "next_time"
54 * sync this program up with /dev/sequencer. You setup your "this_time"
55 * to be now, and then set your next_time into the future and then
56 * sync_time() and it'll wait until time catches up.
57 *
58 * You can see how this is applied if you look in "play_mod_gus" in
59 * play.c. the look where "beattrack" and "update_notes" are called
60 * uses this synchronication. There is no call to "sync_time()" here
61 * because it should be as close as possible to the actual sequencer
62 * commands. There are calls to sync_time() in both update_notes and
63 * prepare_notes.
64 */
65
66
67 SEQ_DEFINEBUF(2048);
68
69 int sample_ok[MAX_SAMPLES];
70
71 extern int gus_dev;
72 int seqfd;
73
74 int ticks_per_division;
75 double tick_duration;
76 double this_time,next_time;
77 double clock_rate;
78
79
80 unsigned int gus_total_mem=0;
81
82 /* GUS SETUP VARS
83 * this is sort of a hack, not all things should have these
84 * variables set this way. (i.e. other mod file formats need a
85 * different clock rate) but I'll get to it later
86 */
87
gus_setup_vars()88 void gus_setup_vars()
89 {
90 clock_rate = 50.0; /* for mods */
91
92 tick_duration = 100.0 / clock_rate;
93 }
94
95 /* GUS GET DEVICE
96 * this checks for /dev/sequencer, and then checks to make sure there
97 * is a GUS in there somewhere. If not, then it returns (0) telling
98 * the init routines in "play.c" that there is no GUS available and it
99 * should look for something else.
100 * If it finds a GUS it clears out the RAM on the GUS, and then finds
101 * out how much total free memory is available on it.
102 */
103
get_gus_device(void)104 int get_gus_device(void)
105 {
106 uint32 i,n;
107
108 struct synth_info info;
109
110 if ((seqfd = open ("/dev/sequencer", O_WRONLY, 0)) == -1)
111 {
112 /* perror ("/dev/sequencer");*/
113 seqfd = -1;
114 return (0);
115 }
116
117 printf("seqfd: %d\n",seqfd);
118
119 if (ioctl (seqfd, SNDCTL_SEQ_NRSYNTHS, &n) == -1)
120 {
121 /* perror ("/dev/sequencer"); */
122 return (0);
123 }
124
125 for (i = 0; i < n; i++)
126 {
127 info.device = i;
128
129 if (ioctl (seqfd, SNDCTL_SYNTH_INFO, &info) == -1)
130 {
131 /* perror ("/dev/sequencer"); */
132 return (0);
133 }
134
135 if (info.synth_type == SYNTH_TYPE_SAMPLE
136 && info.synth_subtype == SAMPLE_TYPE_GUS)
137 gus_dev = i;
138 }
139
140 if (gus_dev == -1)
141 {
142 /* fprintf (stderr, "Gravis Ultrasound not detected\n"); */
143 return (0);
144 }
145
146 /*
147 if ((mixerfd = open ("/dev/mixer", O_RDWR, 0)) == -1)
148 printf ("Mixer not available.\n");
149 */
150
151
152 ioctl (seqfd, SNDCTL_SEQ_SYNC, 0);
153 ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev);
154
155
156 gus_total_mem = gus_mem_free(gus_dev);
157
158 return (1);
159 }
160
161 /* GUS MEM FREE
162 * this checks to see how much memory is available on the
163 * GUS which is on /dev/sequencer
164 */
165
gus_mem_free(int dev)166 int gus_mem_free (int dev)
167 {
168 int temp = dev;
169 int temp2 = seqfd;
170
171 #ifdef DEBUG
172 printf("Seqfd = %d\n",seqfd);
173 #endif
174
175 if (ioctl (temp2, SNDCTL_SYNTH_MEMAVL, &temp)==-1)
176 { printf("ioctl error: int gus_mem_free(int dev) seqfd,dev = %d,%d\n",
177 temp2,dev);
178 exit(1);
179 }
180 return (temp);
181 }
182
183 unsigned char dump_enabled=1;
184
185 /* SEQBUF DUMP
186 * borrowed from gmod (see README for thanks)
187 * this dumps all the current
188 * sequencer information to /dev/sequencer
189 */
190
seqbuf_dump()191 void seqbuf_dump ()
192 {
193 int result;
194
195 while (_seqbufptr && dump_enabled)
196 {
197 if ((result = write (seqfd, _seqbuf, _seqbufptr)) == -1)
198 {
199 perror ("write /dev/sequencer");
200 exit (ERR_SEQUENCER);
201 }
202 else if (result != _seqbufptr)
203 {
204 _seqbufptr -= result;
205 memmove (_seqbuf, &(_seqbuf[result]), _seqbufptr);
206 }
207 else
208 _seqbufptr = 0;
209 }
210 }
211
212 /* GUS PATCH LOAD
213 * this loads a patch onto the GUS.
214 * if the patch will not load, then it sets "sample_ok[sample_num]"
215 * to 0. This makes it so the GUS sound support wont try and play
216 * that instrument later.
217 * For some reason, if too many patches fail to load, I think the
218 * kernel drivers get confused.
219 */
220
gus_patch_load(struct patch_info * patch,int sample_num)221 void gus_patch_load (struct patch_info *patch, int sample_num)
222 {
223 int bytes_read;
224 int len = patch->len;
225 unsigned short loop_flags = patch->mode;
226 int loop_start = patch->loop_start;
227 int loop_end = patch->loop_end;
228 int mem_avail;
229
230 /* try to remove loop clicking */
231
232 if ((loop_flags & WAVE_LOOPING) && (loop_end >= 2) &&
233 !(loop_flags & WAVE_16_BITS))
234 {
235 patch->data[loop_end] = patch->data[loop_start];
236
237 if (loop_flags & WAVE_UNSIGNED)
238 patch->data[loop_end - 1] =
239 ((unsigned char) (patch->data[loop_end - 2]) +
240 (unsigned char) (patch->data[loop_end])) / 2;
241 else
242 patch->data[loop_end - 1] =
243 ((signed char) (patch->data[loop_end - 2]) +
244 (signed char) (patch->data[loop_end])) / 2;
245 }
246
247 mem_avail = gus_mem_free (gus_dev); /* XXX */
248
249
250 if (sample_num > MAX_SAMPLES)
251 {
252 printf("*** ERROR: Sample Num:%d is greater than MAX_SAMPLES\n",
253 sample_num);
254 }
255 else
256 if (mem_avail < len)
257 {
258 printf ("*** Skipping patch - %d needed, %d available ***\n",
259 len, mem_avail);
260 /* set sample to be OFF */
261 sample_ok[sample_num]=0;
262 }
263 else
264 {
265 SEQ_WRPATCH (patch, sizeof (*patch) + len);
266 /* set sample to be ON */
267 sample_ok[sample_num] = 1;
268 }
269
270 }
271
272 /* SYNC TIME
273 * borrowed from gmod (See README for thanks)
274 * this is part of the timing mechanism for talking to /dev/sequencer
275 * see the top of this file for a more complete description
276 */
277
sync_time(void)278 void sync_time(void)
279 {
280 if(next_time > this_time)
281 {
282 SEQ_WAIT_TIME ((long) next_time);
283 this_time = next_time;
284 }
285
286 }
287
288 /* STOP ALL VOICES
289 * this stops all the voices which are currently playing on the
290 * GUS.
291 */
292
stop_all_voices(void)293 void stop_all_voices(void)
294 {
295 int j;
296 GUS_NUMVOICES(gus_dev,32);
297
298 for(j=0;j<32;j++)
299 {
300 GUS_VOICEOFF(gus_dev,j);
301 GUS_RAMPOFF(gus_dev,j);
302 }
303
304 SEQ_DUMPBUF();
305
306 }
307
308 /* SET PANNING
309 * borrowed from gmod (see README for thanks)
310 * this functions generates a /dev/sequencer panning value from a number
311 * between -127 to 127. It sends that command to the GUS
312 */
313
set_panning(int channel,signed char panning,unsigned char hw_flag)314 void set_panning (int channel, signed char panning, unsigned char hw_flag)
315 {
316 int pan_val;
317
318 pan_val = panning * 2;
319 if (pan_val > 127)
320 pan_val = 127;
321 else if (pan_val < -127)
322 pan_val = -127;
323 sync_time ();
324 SEQ_PANNING (gus_dev, channel, (signed char) pan_val);
325 if (hw_flag == PAN_HARDWARE)
326 {
327 pan_val = (pan_val + 16) / 32 + 7;
328 GUS_VOICEBALA (gus_dev, channel, pan_val);
329 }
330
331 }
332
333 /* GUS SET SPEED
334 * borrowed from gmod (see README for thanks)
335 * this makes speed changes based on the set speed commands
336 * in MOD and S3M files. if the number is equal to or below
337 * the threshold then it is a "tempo" change, if not, then it's a
338 * "bpm" change. The threshold for MODs is 32, while the
339 * threshold for S3Ms is 48.
340 */
341
gus_set_speed(int parm)342 void gus_set_speed(int parm)
343 {
344 if (!parm)
345 parm = 1;
346
347 if (parm < (mod.s3m ? 49 : 33))
348 ticks_per_division = parm;
349 else
350 tick_duration = (250.0 / parm);
351
352 }
353
354 /* PERIOD TO NOTE
355 * written by the authors of gmod (see README for thanks)
356 * this routine takes a period for a note and turns it into a midi note/bend
357 * pair. You can see how this note/bend pair is used to generate a
358 * "start note"/"pitchbend" pair of commands in the "prepare_notes" and
359 * "update_notes" command.
360 * this uses a period table which is in "tables.h"
361 */
362
period_to_note(int period,int * note,int * pitchbend)363 void period_to_note (int period, int *note, int *pitchbend)
364 {
365 int low = 0, middle = 0, high = NUM_PERIODS - 1;
366 int diff, diff_high, diff_low;
367
368 *pitchbend = 0;
369
370 if (period > period_table[0])
371 period = period_table[0];
372 else if (period < period_table[NUM_PERIODS - 1])
373 period = period_table[NUM_PERIODS - 1];
374
375 while (high >= low)
376 {
377 middle = (high + low) / 2;
378 if (period == period_table[middle])
379 break;
380 else if (period < period_table[middle])
381 low = middle + 1;
382 else
383 high = middle - 1;
384 }
385
386 if (period != period_table[middle])
387 {
388 diff_high = abs (period - period_table[high]);
389 diff_low = abs (period - period_table[low]);
390
391 if (diff_low < diff_high)
392 middle = low;
393 else
394 middle = high;
395
396 if (period < period_table[middle])
397 diff = period_table[middle] - period_table[middle + 1];
398 else
399 diff = period_table[middle - 1] - period_table[middle];
400
401 *pitchbend = (period_table[middle] - period) * 100 / diff;
402 }
403
404 *note = middle + NOTE_BASE;
405 }
406
407 /* PREPARE NOTES
408 * this sets up the notes which will be played during the next row for one
409 * track. If you are all familiar with mods, (or want to be) you should
410 * know that mods can only change the "note" on the beginning of a
411 * row. During that "row", however long it lasts according to the song
412 * tempo, every 1/50 of a second, the effects are updated. When you have
413 * a DSP playing the song, then the computer mixes a new "sample buf"
414 * every 1/50 of a second. On the gus, all you have to do is adjust the
415 * notes every 1/50 of a second. The routine called "update_notes" does
416 * this
417 */
418
prepare_notes(int channel,track_info_ptr old_track,track_info_ptr track)419 void prepare_notes(int channel,track_info_ptr old_track,track_info_ptr track)
420 {
421 int note=0,vol=0,samp,bend=0;
422 int pitchbender=0,old_note;
423
424 samp = track->samp;
425
426
427 if (!sample_ok[samp])
428 return;
429
430 period_to_note(old_track->playing_period,&old_note,&bend);
431 period_to_note(track->playing_period,¬e,&bend);
432 track->note = note;
433 vol = track->playing_volume;
434
435 /* if the patch is not loaded yet, then load it */
436
437 if ((track->note_hit) || (old_track->samp != track->samp))
438 {
439 if (sample_ok[track->samp])
440 {
441 sync_time();
442 SEQ_SET_PATCH(gus_dev,channel,track->samp);
443 }
444 }
445
446 sync_time();
447 if (sample_ok[samp])
448 {
449
450 if (channel & 1)
451 track->panning = -127;
452 else
453 track->panning = 127;
454
455 if (old_track->panning != track->panning)
456 set_panning(channel,track->panning, PAN_HARDWARE);
457
458
459 if (track->note_hit)
460 {
461 pitchbender = (note * 100 + bend) - (note * 100);
462 sync_time();
463 SEQ_START_NOTE(gus_dev,channel,note,vol);
464
465 SEQ_PITCHBEND(gus_dev,channel,pitchbender + 1);
466 }
467 else
468 {
469 /* check the volume and set it if necessary */
470
471 if ((vol != old_track->playing_volume) && sample_ok[track->samp])
472 {
473 sync_time();
474 SEQ_START_NOTE(gus_dev,channel,255,vol);
475 }
476
477 pitchbender = (note * 100 + bend) - (old_note * 100);
478
479 sync_time();
480 SEQ_PITCHBEND(gus_dev,channel,pitchbender + 1);
481 }
482
483 }
484 else
485 GUS_VOICEOFF(gus_dev,channel);
486
487 if (!track->playing_volume)
488 GUS_VOICEOFF(gus_dev,channel);
489
490 track->note_hit = 0;
491 }
492
493 /* UPDATE NOTES
494 * this routine updates the current characteristics of the notes which
495 * are playing on the GUS. Instead of mixing a "sample buffer" and sending
496 * it to the DSP every 1/50 of a second (like a /dev/dsp player does)
497 * the GUS just needs to have it's voice information updated every 1/50
498 * of a second and it does all the rest of the work for us.
499 */
500
update_notes(int channel,register track_info_ptr track)501 void update_notes(int channel,register track_info_ptr track)
502 {
503 int16 t;
504 int note,bend;
505 int old_note,old_bend;
506 int vol = track->playing_volume;
507 int retrig=0,pitchbender=0;
508
509 if (!sample_ok[track->samp])
510 return;
511
512 period_to_note(track->start_period,&old_note,&old_bend);
513
514 period_to_note(track->playing_period,¬e,&bend);
515
516 sync_time();
517
518 /* set the volume */
519 SEQ_START_NOTE(gus_dev,channel,255,vol);
520
521 /* retrigger if necessary */
522 if (track->note_hit)
523 {
524 SEQ_START_NOTE(gus_dev,channel,note,vol);
525 track->note_hit = 0;
526 }
527
528 pitchbender = (note * 100 + bend) - (old_note * 100);
529
530 SEQ_PITCHBEND(gus_dev,channel,pitchbender + 1);
531
532 }
533
534
play_mod_gus(int loud)535 void play_mod_gus(int loud)
536 {
537
538 int16 i;
539 int extra_ticks, tick;
540 track_info_ptr track;
541 track_info_ptr old_track;
542 uint8 *c;
543 uint16 *d;
544
545
546 gus_setup_vars();
547
548 startplaying(loud);
549
550 stop_all_voices();
551
552 SEQ_START_TIMER();
553
554 if (mod.tracks < 14)
555 {
556 GUS_NUMVOICES (gus_dev, 14);
557 }
558 else
559 {
560 GUS_NUMVOICES (gus_dev, mod.tracks);
561 }
562
563
564 for(i=0;i<mod.tracks;i++)
565 {
566 SEQ_BENDER_RANGE(gus_dev,i,8191);
567 SEQ_EXPRESSION(gus_dev,i,options.main_volume);
568 SEQ_MAIN_VOLUME(gus_dev,i,100);
569 SEQ_PANNING (gus_dev,i,0);
570 SEQ_PITCHBEND(gus_dev,i,0);
571 }
572
573
574 next_time = 0.0;
575 gus_set_speed(mod.tempo);
576 gus_set_speed(mod.bpm);
577
578 this_time = 0.0;
579 next_time += tick_duration;
580 sync_time();
581
582 mod_done = 0;
583
584 while (!mod_done)
585 {
586 /* save the old track info for "prepare_notes" */
587
588 memcpy(old_tracks,tracks,sizeof(*tracks) * MAX_TRACKS);
589
590 updatetracks();
591
592 track = tracks;
593 old_track = old_tracks;
594 this_time = 0.0; /* reset the time */
595
596 /* now setup the voices for the current row */
597
598 for (i=0;i<mod.tracks;i++)
599 {
600 prepare_notes(i,old_track++,track++);
601 }
602
603 /* now that the voices are setup, we need to "modulate" them
604 as necessary for the different effects */
605
606 extra_ticks = 0; /* check this out */
607
608 tempo_wait = tempo;
609
610 for(tick = 0; tick < ticks_per_division + extra_ticks;tick++)
611 {
612 track = tracks;
613
614 for(i=0;i<mod.tracks;i++)
615 {
616 beattrack(track);
617 update_notes(i,track);
618 track++;
619 }
620 tempo_wait--;
621 next_time += tick_duration;
622 }
623
624 }
625
626 }
627
628 #endif /* GUS */
629