/* GUS driver. This card rocks for the sound chip emulation. Voices 0,1,2 are as expected. Voice 3 is for noise. We set up one instrument to be the 'tone', one instrument for periodic noise, and one instrument for white noise. Each of these is generated by this program, and played as 'simple' MOD-style instruments. Something to note -- either due to the Ultrasound library or some other reason, we can't play these samples at exactly X Hz. This drops a lot of tones in the lower registers, which is very undesirable, especially for musical programs. So, to get around this, we play samples at 64 octaves higher than they are. This way, we get resolution comparable to the 99/4A. Except for white noise, since its sample is VERY long due to how easy it is to hear repeats, we play it at X Hz rather than create a 4096k sample. ;) */ #ifdef GUS #include #include #include #include #include "16bit.h" #include "emulate.h" #include "sound.h" static int cards; static int card; static void *gus_pcm_handle, *gus_handle; int gusdetect() { if ((cards = gus_cards()) <= 0) return 0; else { log("Using GUS for sound... "); return 1; } } /* Set up the voices. Voices 0,1,2 are tones, so are loaded with a tone patch. */ struct svoice { u8 *sample; gus_wave_t wave; gus_instrument_t instr; gus_layer_t layer; }; static struct svoice tone, noise0, noise1; void voiceinit(struct svoice *v, int usignd, int len, int instr) { memset((void *) v, 0, sizeof(*v)); v->sample = (void *) malloc(len); memset(v->sample, usignd ? 128 : 0, len); v->wave.begin.ptr = v->sample; v->wave.mode = v->instr.mode = v->layer.mode = GUS_INSTR_SIMPLE; v->wave.format = GUS_WAVE_LOOP | usignd; v->instr.info.layer = &v->layer; v->instr.number.instrument = instr; v->layer.wave = &v->wave; v->wave.size = len; v->wave.loop_end = len << 4; } #define HZMUL 64 void maketone() { s8 *ptr; int x; /* voiceinit(&tone,GUS_WAVE_UNSIGNED,64,0); ptr=tone.sample; *ptr++=0; *ptr++=128; *ptr++=128; *ptr++=128; *ptr++=128;*/ voiceinit(&tone, 0, 64, 0); ptr = tone.sample; memset(ptr, -128, 64); *ptr++ = 127; *ptr++ = 127; *ptr++ = 127; *ptr++ = 127; *ptr++ = 127; *ptr++ = 127; *ptr++ = 127; *ptr++ = 127; if (gus_memory_alloc(gus_handle, &tone.instr) < 0) fatal("Couldn't allocate voice #0"); } #define N0MUL 64 void makenoise0() { s8 *ptr; int x; voiceinit(&noise0, 0, 64 * 16, 1); ptr = noise0.sample; for (x = 0; x < 64; x++) *ptr++ = 127; if (gus_memory_alloc(gus_handle, &noise0.instr) < 0) fatal("Couldn't allocate noise #0"); } #define N1MUL 1 void makenoise1() { s8 *ptr; int x, y; unsigned short r0, r1; voiceinit(&noise1, 0, 65536, 2); ptr = noise1.sample; r0 = r1 = 0xffff; while (ptr < noise1.sample + 65536) { *ptr++ = (r0 & 1) ? 127 : -128; r0 = (r0 << 1) | (r0 >> 15); r0 ^= r1; if ((r1 += r0) == 0) r1 = 0xffff; } if (gus_memory_alloc(gus_handle, &noise1.instr) < 0) fatal("Couldn't allocate noise #1"); } void setupvoices() { int x; unsigned short cx, bp; /* No 'gradual fadeins' pleez */ gus_ultraclick_t click; click.volume_ramp = 0; gus_ultraclick_set(gus_handle, &click); maketone(); makenoise0(); makenoise1(); gus_timer_start(gus_handle); } #define BUFFERSIZE (200*25) static u8 *buffer; static int buflen; static int dmasize; static void *gushandle; void setupspeech() { buffer = (void *) malloc(BUFFERSIZE); buflen = 0; if (gus_pcm_cards() < 1) { log("no PCM cards available for speech... "); return; } if (gus_pcm_open (&gus_pcm_handle, -1, -1, GUS_PCM_DIRECTION_PLAYBACK, GUS_PCM_OF_NONBLOCK) < 0) { log("cannot open PCM card for speech... "); return; } /* gus_pcm_select_card(card); gushandle=gus_pcm_get_handle(card);*/ if (gus_pcm_mode_set (gus_pcm_handle, GUS_PCM_DIRECTION_PLAYBACK, GUS_PCM_MODE_U8) < 0 || gus_pcm_rate_set(gus_pcm_handle, GUS_PCM_DIRECTION_PLAYBACK, 8000) < 0) { log("sound driver doesn't support mono/8000 Hz... "); return; } if (gus_pcm_dma_size_set (gus_pcm_handle, GUS_PCM_DIRECTION_PLAYBACK, 16, 9) < 0) { log("DMA setup error... "); return; } dmasize = gus_pcm_dma_size_get(gus_pcm_handle, GUS_PCM_DIRECTION_PLAYBACK, 1); log("dmasize=%d, got GUS for speech... ", dmasize); features |= FE_SPEECH; } int gusattach() { for (card = 0; card < cards; card++) { if (gus_open(&gus_handle, card, 0, 512, 0) == 0) { gus_queue_write_set_size(gus_handle, 512); gus_memory_reset(gus_handle, GUS_DOWNLOAD_MODE_NORMAL); gus_reset(gus_handle, 4, 0); /* gus_select(gus_hacard);*/ setupvoices(); setupspeech(); log("done, card #%d\n", card); return 1; } } log("failed, no GUS cards available\n"); return 0; } int gusdetach() { gus_close(gus_handle); gus_close(gus_pcm_handle); return 1; } void gusspeakeron() { gus_do_voice_start(gus_handle, 0, 0, 0, 16384, 8192); gus_do_voice_start(gus_handle, 1, 0, 0, 16384, 8192); gus_do_voice_start(gus_handle, 2, 0, 0, 16384, 8192); } void gusspeakeroff() { int x; for (x = 0; x < 4; x++) gus_do_voice_control(gus_handle, x, 3); } int getvol(u8 voice) { return (15 - voices[voice].volume) * 512; } void gusvoice(u8 voice) { gus_do_voice_frequency(gus_handle, voice, voices[voice].hertz * HZMUL); gus_do_flush(gus_handle); } void gusvoicevol(u8 voice) { gus_do_voice_volume(gus_handle, voice, getvol(voice)); gus_do_flush(gus_handle); } u8 laststype; void gusnoise() { int inst = (voices[3].stype & 4) != 0; int hz = voices[3].hertz * (inst ? N1MUL : N0MUL); if ((voices[3].stype & 7) != (laststype & 7)) { gus_do_voice_start(gus_handle, 3, inst + 1, hz, getvol(3), 8192); } else gus_do_voice_frequency(gus_handle, 3, hz); gus_do_flush(gus_handle); laststype = voices[3].stype; } void gusnoisevol() { gus_do_voice_volume(gus_handle, 3, getvol(3)); gus_do_flush(gus_handle); } void gustoggle() { gus_do_flush(gus_handle); } void gusspeech(u8 * data, int len) { log("GUS speech: %d bytes\n", len); // fd_set writefds; /* if (buflen>=BUFFERSIZE || len==0) { log("Spit out data... %d bytes\n",buflen); gus_pcm_write(gus_pcm_handle,buffer,buflen); buflen=0; } if (len) { memcpy(buffer+buflen,data,len); buflen+=len; }*/ if (len) if (gus_pcm_write(gus_pcm_handle, data, len) < 0) { log("GUS PCM write error\n"); perror("PCM:"); gus_pcm_sync(gus_pcm_handle, GUS_PCM_DIRECTION_PLAYBACK); } // gus_pcm_write(gus_pcm_handle,data,0); // gus_pcm_sync(gus_pcm_handle,); } static void nullhandler() { } struct sounddevice sound_gus = { gusdetect, gusattach, gusdetach, gusvoice, gusvoicevol, gusnoise, gusnoisevol, gustoggle, gusspeakeron, gusspeakeroff, gusspeech }; #endif