home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 26
/
CD_ASCQ_26_1295.iso
/
vrac
/
gctv101.zip
/
GCTVSAPI.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1995-09-18
|
18KB
|
698 lines
// ------------------------------------------------------------------
// 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;
}
// ------------------------------------------------------------------