home *** CD-ROM | disk | FTP | other *** search
-
- // ------------------------------------------------------------------
- // GCTVSAPI 1.01 - Goldware Sound API for CT-VOICE.DRV.
- // Released to Public Domain by Odinn Sorensen.
- // ------------------------------------------------------------------
- // This source was written to compile cleanly with Borland C++ 3.1.
- // Compile with BCC -O1 -d -K -k- -ml -N- -v-.
- // Compile with -DDEBUG for lots of diagnostics.
- // ------------------------------------------------------------------
- // See GOLDSAPI.DOC for a specification of the Goldware Sound API.
- // ------------------------------------------------------------------
- // v1.00: Initial release.
- // v1.01: Now returns errorlevel from program.
- // ------------------------------------------------------------------
- // Acknowledgements:
- // * Gody Keijzer 2:283/7.17 helped with the errorlevel stuff.
- // ------------------------------------------------------------------
-
-
- // ------------------------------------------------------------------
-
- #include <io.h>
- #include <dos.h>
- #include <fcntl.h>
- #include <share.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <string.h>
- #include <process.h>
- #ifdef DEBUG
- #include <stdio.h>
- #endif
-
-
- // ------------------------------------------------------------------
- // Some typedefs
-
- typedef unsigned char byte;
- typedef unsigned short word;
- typedef unsigned int uint;
-
-
- // ------------------------------------------------------------------
- // Some defines
-
- #define TRUE 1
- #define FALSE 0
- #define NOT !
- #define NUL '\0'
- #define NW(x) (x=x)
-
-
- // ------------------------------------------------------------------
- // Goldware Sound API version
-
- #define GSAPI_VERSION 0x0100
-
-
- // ------------------------------------------------------------------
- // Goldware Sound API function numbers
-
- #define GSAPI_INSTALL_CHECK 0x00
- #define GSAPI_OPEN_API 0x10
- #define GSAPI_CLOSE_API 0x11
- #define GSAPI_OPEN_AND_LOAD_FILE 0x12
- #define GSAPI_CLOSE_FILE 0x13
- #define GSAPI_PLAY 0x14
- #define GSAPI_STOP 0x15
- #define GSAPI_PAUSE 0x16
- #define GSAPI_RESUME 0x17
- #define GSAPI_BREAK_LOOP 0x18
- #define GSAPI_SPEAKER_ON_OFF 0x19
-
-
- // ------------------------------------------------------------------
- // Goldware Sound API data structure
-
- struct gsapidata {
- word driver_version;
- word dsp_version;
- word io_port;
- byte irq_number;
- byte dma_channel;
- word sample_rate;
- volatile word status;
- word buffer_segment;
- word buffer_offset;
- long buffer_length;
- char parameters[80];
- };
-
-
- // ------------------------------------------------------------------
- // The AMIS signature string
-
- struct amis_signature {
- char manufacturer[8];
- char product_name[8];
- char product_description[64];
- };
-
-
- // ------------------------------------------------------------------
- // The .VOC file header structure
-
- struct voc_header {
- char filetype[20];
- word dataoffset;
- word vocversion;
- word vocid;
- };
-
-
- // ------------------------------------------------------------------
- // A type for casting the argument to _dos_setvect()
-
- typedef void interrupt (*interrupt_handler)(...);
-
-
- // ------------------------------------------------------------------
- // A pointer to the next INT 2Dh handler
-
- static void interrupt (*old_handler)(...);
-
-
- // ------------------------------------------------------------------
- // The AMIS signature string and multiplex number
-
- static amis_signature signature;
- static uint mpx;
-
-
- // ------------------------------------------------------------------
- // Goldware Sound API data structure and state variables
-
- static gsapidata data;
- static int unique_key = 0;
- static int api_okay = FALSE;
- static int api_open = FALSE;
- static int file_open = FALSE;
- static int errorlevel = 0;
-
-
- // ------------------------------------------------------------------
- // CT-VOICE driver pointers and return status
-
- static void far (*driver)(void) = NULL;
- static char* driver_buffer = NULL;
- static word ctv_status = 0;
-
-
- // ------------------------------------------------------------------
-
- int ctv_init() {
-
- memset(&data, 0, sizeof(gsapidata));
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: init\n");
- #endif
- char file[80];
- *file = NUL;
- char* sound = getenv("SOUND");
- if(sound) {
- #ifdef DEBUG
- fprintf(stderr, "ctv: SOUND=%s\n", sound);
- #endif
- strcpy(file, sound);
- if(file[strlen(file)-1] != '\\')
- strcat(file, "\\");
- strcat(file, "DRV\\");
- }
- strcat(file, "CT-VOICE.DRV");
- #ifdef DEBUG
- fprintf(stderr, "ctv: driver at %s\n", file);
- #endif
- int fh = sopen(file, O_RDONLY|O_BINARY, SH_DENYNO);
- if(fh != -1) {
- uint driver_size = (uint)filelength(fh);
- driver_buffer = (char*)malloc(driver_size+32);
- if(driver_buffer) {
- driver = (void(far*)())MK_FP(FP_SEG(driver_buffer)+1, 0x0000);
- read(fh, (void*)driver, driver_size);
- #ifdef DEBUG
- fprintf(stderr, "ctv: getting driver version\n");
- #endif
- _AX = 0;
- _BX = 0;
- (*driver)();
- ctv_status = _AX;
- data.driver_version = ctv_status;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- #ifdef DEBUG
- fprintf(stderr, "ctv: found driver version %u.%02u\n", ctv_status>>8, ctv_status&0xFF);
- #endif
- char* blaster = getenv("BLASTER");
- if(blaster) {
- #ifdef DEBUG
- fprintf(stderr, "ctv: BLASTER=%s\n", blaster);
- #endif
- while(*blaster) {
- if(toupper(*blaster) == 'A') {
- word p = (word)atoi(blaster+1);
- data.io_port = p;
- #ifdef DEBUG
- fprintf(stderr, "ctv: setting i/o port to %u\n", p);
- #endif
- if(driver) {
- _AX = p;
- _BX = 1;
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- }
- }
- else if(toupper(*blaster) == 'I') {
- word i = (word)atoi(blaster+1);
- data.irq_number = i;
- #ifdef DEBUG
- fprintf(stderr, "ctv: setting interrupt to %u\n", i);
- #endif
- if(driver) {
- _AX = i;
- _BX = 2;
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- }
- }
- else if(toupper(*blaster) == 'D') {
- word d = (word)atoi(blaster+1);
- data.dma_channel = d;
- }
- blaster++;
- }
- }
- }
- close(fh);
- #ifdef DEBUG
- fprintf(stderr, "ctv: driver init\n");
- #endif
- ctv_status = 0xFFFF;
- if(driver) {
- _BX = 3;
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- }
- switch(ctv_status) {
- case 0:
- #ifdef DEBUG
- fprintf(stderr, "ctv: no errors in driver init\n");
- #endif
- break;
- case 1:
- #ifdef DEBUG
- fprintf(stderr, "ctv: voice card failure in driver init\n");
- #endif
- break;
- case 2:
- #ifdef DEBUG
- fprintf(stderr, "ctv: i/o read/write failure in driver init\n");
- #endif
- break;
- case 3:
- #ifdef DEBUG
- fprintf(stderr, "ctv: dma interrupt failure in driver init\n");
- #endif
- break;
- default:
- #ifdef DEBUG
- fprintf(stderr, "ctv: unknown error %u in driver init\n", ctv_status);
- #endif
- ;
- }
- if(ctv_status != 0)
- driver = NULL;
- #ifdef DEBUG
- fprintf(stderr, "ctv: setting voice status word address\n");
- #endif
- if(driver) {
- _BX = 5;
- _ES = FP_SEG(&data.status);
- _DI = FP_OFF(&data.status);
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- return TRUE; // driver is ready and waiting for commands
- }
- }
- if(driver_buffer) {
- free(driver_buffer);
- driver_buffer = NULL;
- }
- return FALSE; // Error during init
- }
-
-
- // ------------------------------------------------------------------
-
- void ctv_reset() {
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: reset\n");
- #endif
- _BX = 9;
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- free(driver_buffer);
- driver_buffer = NULL;
- driver = NULL;
- }
-
-
- // ------------------------------------------------------------------
-
- word ctv_open_and_load() {
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: requested to load \"%s\"\n", data.parameters);
- #endif
- #define GSND_BLOCK_SIZE 65000L
- int fh = sopen(data.parameters, O_RDONLY|O_BINARY, SH_DENYNO);
- if(fh != -1) {
- long length = data.buffer_length;
- char huge* ptr = (char huge*)MK_FP(data.buffer_segment, data.buffer_offset);
- while(length > 0) {
- uint chunk_length = (uint)(length > GSND_BLOCK_SIZE ? GSND_BLOCK_SIZE : length);
- if(read(fh, (void*)ptr, chunk_length) != chunk_length) {
- int errno_tmp = errno;
- close(fh);
- errno = errno_tmp;
- return 0xFFFF; // DOS error
- }
- length -= GSND_BLOCK_SIZE;
- ptr += GSND_BLOCK_SIZE;
- }
- #ifdef DEBUG
- fprintf(stderr, "ctv: \"%s\" loaded at %04X:%04X\n", data.parameters, data.buffer_segment, data.buffer_offset);
- #endif
- if(close(fh) == -1)
- return 0xFFFF;
- // Sample rate is not supported yet
- data.sample_rate = 0;
- return 0x0000; // Success
- }
- return 0xFFFF; // DOS error
- }
-
-
- // ------------------------------------------------------------------
-
- void ctv_close() {
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: close\n");
- #endif
- // Nothing else to do in this implementation
- }
-
-
- // ------------------------------------------------------------------
-
- void ctv_stop() {
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: stop\n");
- #endif
- _BX = 8;
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- }
-
-
- // ------------------------------------------------------------------
-
- void ctv_play(word sample_rate) {
-
- // Sample rate is not supported yet
- NW(sample_rate);
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: play buffer at %04X:%04X\n", data.buffer_segment, data.buffer_offset);
- #endif
- char* vocbuf = (char*)MK_FP(data.buffer_segment, data.buffer_offset);
- void* vocptr = vocbuf + ((voc_header*)vocbuf)->dataoffset;
- if(data.status)
- ctv_stop();
- _BX = 6;
- _ES = FP_SEG(vocptr);
- _DI = FP_OFF(vocptr);
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- }
-
-
- // ------------------------------------------------------------------
-
- void ctv_pause() {
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: pause\n");
- #endif
- _BX = 10;
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- }
-
-
- // ------------------------------------------------------------------
-
- void ctv_resume() {
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: continue\n");
- #endif
- _BX = 11;
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- }
-
-
- // ------------------------------------------------------------------
-
- void ctv_break_loop(word method) {
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: break loop\n");
- #endif
- _AX = method;
- _BX = 12;
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- }
-
-
- // ------------------------------------------------------------------
-
- void ctv_speaker(word onoff) {
-
- #ifdef DEBUG
- fprintf(stderr, "ctv: speaker %s\n", onoff ? "on" : "off");
- #endif
- _AX = onoff;
- _BX = 4;
- (*driver)();
- ctv_status = _AX;
- #ifdef DEBUG
- fprintf(stderr, "ctv: status = %04X\n", ctv_status);
- #endif
- }
-
-
- // ------------------------------------------------------------------
-
- void interrupt gsapi_handler(uint, uint di, uint, uint, uint, uint dx, uint cx, uint bx, uint ax) {
-
- NW(di); NW(dx); NW(cx);
-
- if((ax >> 8) == mpx) {
- switch(ax & 0xFF) {
- case GSAPI_INSTALL_CHECK:
- ax = 0xFF;
- cx = GSAPI_VERSION;
- dx = FP_SEG(&signature);
- di = FP_OFF(&signature);
- #ifdef DEBUG
- fprintf(stderr, "gapi_handler: installation check using signature at %04X:%04X\n", dx, di);
- #endif
- return;
- case GSAPI_OPEN_API:
- if(api_okay) {
- if(NOT api_open) {
- api_open = ++unique_key;
- bx = api_open;
- cx = sizeof(gsapidata);
- dx = FP_SEG(&data);
- di = FP_OFF(&data);
- #ifdef DEBUG
- fprintf(stderr, "gsapi_handler: api opened using data at %04X:%04X, length %u\n", dx, di, cx);
- #endif
- ax = 0x0000; // Success
- return;
- }
- ax = 0x0001; // Already open
- return;
- }
- ax = 0xFFFF; // Cannot open
- return;
- case GSAPI_CLOSE_API:
- if(api_open) {
- if(bx == api_open) {
- if(data.status)
- ctv_stop();
- if(file_open) {
- ctv_close();
- file_open = FALSE;
- }
- api_open = FALSE;
- ax = 0x0000; // Success
- return;
- }
- ax = 0xFFFF; // Not correct key
- return;
- }
- ax = 0x0001; // Not open
- return;
- case GSAPI_OPEN_AND_LOAD_FILE:
- if(NOT file_open) {
- if(data.buffer_length == 0) {
- #ifdef DEBUG
- fprintf(stderr, "ctv: opening \"%s\"\n", data.parameters);
- #endif
- find_t fb;
- if(_dos_findfirst(data.parameters, 0, &fb)) {
- bx = errno;
- ax = 0xFFFF; // DOS error
- return;
- }
- data.buffer_length = fb.size;
- #ifdef DEBUG
- fprintf(stderr, "ctv: need %li bytes for \"%s\"\n", data.buffer_length, data.parameters);
- #endif
- ax = 0x0002; // Need memory
- return;
- }
- ax = ctv_open_and_load();
- if(ax == 0xFFFF) // DOS error
- bx = errno;
- else
- file_open = TRUE;
- return;
- }
- ax = 0x0001; // File already open
- return;
- case GSAPI_CLOSE_FILE:
- if(file_open) {
- ctv_close();
- file_open = FALSE;
- data.buffer_length = 0;
- ax = 0x0000; // Success
- return;
- }
- ax = 0x0001; // Not open
- return;
- case GSAPI_PLAY:
- if(file_open) {
- //if(data.status)
- // ctv_stop();
- ctv_play(bx);
- ax = 0x0000; // Success
- return;
- }
- ax = 0x0001; // No sound
- return;
- case GSAPI_STOP:
- if(file_open) {
- ctv_stop();
- ax = 0x0000; // Success
- return;
- }
- ax = 0x0001; // No sound
- return;
- case GSAPI_PAUSE:
- if(file_open) {
- ctv_pause();
- ax = 0x0000; // Success
- return;
- }
- ax = 0x0001; // No sound
- return;
- case GSAPI_RESUME:
- if(file_open) {
- ctv_resume();
- ax = 0x0000; // Success
- return;
- }
- ax = 0x0001; // No sound
- return;
- case GSAPI_BREAK_LOOP:
- if(file_open) {
- ctv_break_loop(bx);
- ax = 0x0000; // Success
- return;
- }
- ax = 0x0001; // No sound
- return;
- case GSAPI_SPEAKER_ON_OFF:
- ctv_speaker(bx);
- return;
- default:
- #ifdef DEBUG
- fprintf(stderr, "gsapi_handler: received function %u\n", ax & 0xFF);
- #endif
- ax = 0; // Return "not implemented" for all other functions
- return;
- }
- }
- _chain_intr(old_handler);
- }
-
-
- // ------------------------------------------------------------------
-
- void gsapi_handler_install(char** argv) {
-
- api_okay = ctv_init();
-
- if(api_okay) {
-
- // Fill in the AMI signature
- memcpy(signature.manufacturer, "Goldware", 8);
- memcpy(signature.product_name, "GoldSAPI", 8);
- strcpy(signature.product_description, "The Goldware Sound API by Odinn Sorensen, " __DATE__);
-
- // Find a free multiplex number
- REGPACK regs;
- for(mpx=0; mpx<256; mpx++) {
- regs.r_ax = mpx << 8;
- intr(0x2D, ®s);
- if((regs.r_ax & 0xFF) == 0)
- break;
- }
-
- if(mpx < 256) {
-
- // Link in the handler
- old_handler = _dos_getvect(0x2D);
- _dos_setvect(0x2D, (interrupt_handler)gsapi_handler);
-
- #ifdef DEBUG
- fprintf(stderr, "gsapi_handler_install: using mpx %u\n", mpx);
- #endif
-
- errorlevel = spawnv(P_WAIT,*(argv+1),argv+1);
-
- _dos_setvect(0x2D, old_handler);
- }
-
- ctv_reset();
- }
- }
-
-
- // ------------------------------------------------------------------
-
- int main(int argc, char** argv) {
-
- if(argc > 1) {
- gsapi_handler_install(argv);
- #ifdef DEBUG
- fprintf(stderr, "%s returned errorlevel %u\n", argv[1], errorlevel);
- #endif
- }
- else {
- char* syntax = "GCTVSAPI <prog> [parms]$";
- REGPACK regs;
- regs.r_ax = 0x0900;
- regs.r_ds = FP_SEG(syntax);
- regs.r_dx = FP_OFF(syntax);
- intr(0x21, ®s);
- }
-
- return errorlevel;
- }
-
-
- // ------------------------------------------------------------------
-
-