#include #include "ultramid.h" /* The first half of this file contains the interface functions to */ /* UltraMID, and the second half contains the file i/o, wav i/o, and */ /* user interface */ #pragma inline #define MK_LONG (long)((void _seg *)(_DX) + (void near *)(_AX)) void (far *um_hook)(void) = 0L; short volume = 4095; short pan = 7; short voice; unsigned short frequency; int still_playing; int user_request_stop = 0; #define NBUFFS 10 int play_index; /* pointer to buffer which is being played */ int dma_index; /* pointer to buffer which is being xferred */ int fill_index; /* pinter to buffer which should be filled next */ #define BS_EMPTY 0 #define BS_FILLED 1 #define BS_XFERRED 2 #define BS_PLAYING 3 unsigned char buff_status[NBUFFS]; unsigned long buff_len[NBUFFS]; #define BSIZE 4096U #define GF1BSIZE 8192L unsigned char buffs[NBUFFS][BSIZE]; unsigned char stbuff[GF1BSIZE/4]; #pragma warn -par int far um_callback(int reason, int voice, unsigned char far * far*buf, unsigned long far *size, unsigned short far *rate) { /* this function is called from an interrupt */ /* restore our DS register */ asm push ds asm mov ax, cs asm mov ds, ax switch (reason) { case UM_STOP_SOUND: still_playing = 0; break; case UM_MORE_DATA: if (buff_status[dma_index] == BS_FILLED) { *buf = buffs[dma_index]; *size = buff_len[dma_index]; *rate = frequency; buff_status[dma_index] = BS_XFERRED; dma_index = (dma_index + 1) % NBUFFS; asm pop ds return(1); /* return 1 when there is more data */ /* return 0 when done playing */ } break; case UM_VOICE_DONE: buff_status[play_index] = BS_EMPTY; play_index = (play_index + 1) % NBUFFS; if (buff_status[play_index] == BS_XFERRED) { buff_status[play_index] = BS_PLAYING; } break; } asm pop ds return(0); } #pragma warn .par int um_start_digital(struct um_sound_struct *umss) { _ES = FP_SEG(umss); _DI = FP_OFF(umss); _AX = TSR_START_DIGITAL; (*um_hook)(); return(_AX); } void um_stop_digital(int voice) { _CX = voice; _AX = TSR_STOP_DIGITAL; (*um_hook)(); } void um_restart_digital(int voice) { _CX = voice; _AX = TSR_RESTART_DIGITAL; (*um_hook)(); } void um_pause_digital(int voice) { _CX = voice; _AX = TSR_PAUSE_DIGITAL; (*um_hook)(); } void um_set_pan(int voice, int pan) { _CX = voice; _BX = pan; _AX = TSR_SET_PAN; (*um_hook)(); } void um_set_volume(int voice, int volume) { _CX = voice; _BX = volume; _AX = TSR_SET_VOLUME; (*um_hook)(); } long um_allocate_memory(long mem) { asm mov dx, word ptr mem; asm mov bx, word ptr mem+2; _AX = TSR_ALLOCATE_MEMORY; (*um_hook)(); mem = MK_LONG; return(mem); } void um_free_memory(long mem) { asm mov bx, word ptr mem+2; asm mov dx, word ptr mem; _AX = TSR_FREE_MEMORY; (*um_hook)(); } struct um_sound_struct umss; /**********************************************************************/ /* file i/o functions, console functions, and other library funcs */ /**********************************************************************/ #define CARRY_FLAG 1 void interrupt (*getvect(int int_number))() { _AX = 0x3500; _AL = (char)int_number; geninterrupt(0x21); return(MK_FP(_ES, _BX)); } int my_strncmp(char far *str1, char far *str2, int len) { asm mov dx, ds asm cld asm les di, str2 asm mov si, di asm mov ax, len asm mov cx, ax asm jcxz done asm mov bx, ax asm xor al, al asm repne scasb asm sub bx, cx asm mov cx, bx asm mov di, si asm lds si, str1 asm repe cmpsb asm mov al, [si-1] asm mov bl, es:[di-1] asm xor ah, ah asm mov bh, ah asm sub ax, bx done: asm mov ds, dx return(_AX); } void myputs(char *s) { while (*s) { _BH = 0; _AL = *s; _AH = 0x0e; geninterrupt(0x10); s++; } } mygetch(void) { _AX = 0x0700; geninterrupt(0x21); _AH = 0x0; return(_AL); } my_open(char *name) { int save_ax, hold_ds; hold_ds = FP_SEG( name ); _DX = FP_OFF( name ); _AH = 0x3d; /* open file */ _AL = 0x0; /* read only */ asm push ds; _DS = hold_ds; geninterrupt(0x21); asm pop ds; save_ax = _AX; if( _FLAGS & CARRY_FLAG ) { return( -1 ); } return(save_ax); } void my_close(int handle) { _BX = handle; _AH = 0x3e; geninterrupt(0x21); } my_read(int handle, unsigned char *buff, unsigned long lsize) { int hold_ds; unsigned int size; unsigned short seg, offset; unsigned long addr; while (lsize > 0) { size = (lsize > 32768U) ? 32768U : lsize; lsize -= size; hold_ds = FP_SEG(buff); _DX = FP_OFF(buff); _BX = handle; _CX = size; _AH = 0x3f; /* read file */ asm push ds; _DS = hold_ds; geninterrupt(0x21); asm pop ds; if (_FLAGS & CARRY_FLAG) { return(0); } buff += size; } return(1); } /**********************************************************************/ /* Application Functions */ /**********************************************************************/ struct riff_header { char RIFF[4]; unsigned long file_size; char WAVE[4]; char fmt[4]; unsigned long format_size; } riff_header; struct format_header { unsigned int wFormatTag; unsigned int nChannels; unsigned long nSamplesPerSec; unsigned long nAvgBytesPerSec; unsigned int nBlockAlign; unsigned int nBitsPerSample; } format_header; struct data_header { unsigned char DATA[4]; unsigned long size; } data_header; #define MIN(a,b) ((a) < (b) ? (a) : (b)) int far *head_keys = (int far *)0x0040001aL; int far *tail_keys = (int far *)0x0040001cL; #define fast_kbhit() (*head_keys != *tail_keys) void check_buffers(int fp, unsigned long *length) { unsigned long size; static int paused=0; int c; if (fast_kbhit()) { if ((c=mygetch()) == 27) { user_request_stop = 1; um_stop_digital(voice); return; } else if (c == 'P' || c == 'p') { if (paused) { um_restart_digital(voice); } else { um_pause_digital(voice); } paused ^= 1; } else if (c == '>') { if (pan > 0) { um_set_pan(voice, --pan); } } else if (c == '<') { if (pan < 15) { um_set_pan(voice, ++pan); } } else if (c == ',') { volume -= 50; if (volume < 0) volume = 0; um_set_volume(voice, volume); } else if (c == '.') { volume += 50; if (volume > 4095) volume = 4095; um_set_volume(voice, volume); } } while (buff_status[fill_index] == BS_EMPTY) { /* check to see if there is any more data to read */ if (*length == 0) break; /* if no more data in file - return */ /* fill next buffer */ size = MIN(BSIZE, *length); my_read(fp, buffs[fill_index], size); *length -= size; buff_len[fill_index] = size; buff_status[fill_index] = BS_FILLED; fill_index = (fill_index + 1) % NBUFFS; } } void play(char *filename, unsigned long gf1mem) { int fp; int i; unsigned long length; unsigned short type=0; fp = my_open(filename); if (fp == -1) { myputs("Can't open file "); myputs(filename); myputs(" for playback"); return; } my_read(fp, (unsigned char *)&riff_header, sizeof(riff_header)); if (my_strncmp(riff_header.RIFF, "RIFF", 4) == 0 && my_strncmp(riff_header.WAVE, "WAVE", 4) == 0 && my_strncmp(riff_header.fmt, "fmt ", 4) == 0) { /* read header */ if (my_read(fp, (unsigned char *)&format_header, riff_header.format_size) != 1) { myputs("File "); myputs(filename); myputs(" isn't a .WAV format file"); my_close(fp); return; } if (format_header.wFormatTag != 1) { myputs("This player can't play "); myputs(filename); my_close(fp); return; } if (format_header.nChannels != 1) { type |= UM_STEREO; } if (format_header.nBitsPerSample == 8) { type |= UM_8BIT; type |= UM_INVERT_MSB; } else if (format_header.nBitsPerSample != 16) { myputs("Can't play "); myputs(filename); myputs(". Must be 8 or 16 bits"); my_close(fp); return; } frequency = format_header.nSamplesPerSec; my_read(fp, (unsigned char *)&data_header, sizeof(data_header)); if (my_strncmp(data_header.DATA, "data", 4)) { myputs("This player can't play "); myputs(filename); myputs(". Can't find data"); my_close(fp); return; } length = data_header.size; user_request_stop = 0; umss.stereo_mem = stbuff; umss.gf1mem = gf1mem; umss.pan = pan; umss.volume = volume; umss.sample_rate = frequency; umss.priority = 0; umss.data_type = type; umss.callback = um_callback; for (i=0; i < NBUFFS; i++) buff_status[i] = BS_EMPTY; fill_index = 0; play_index = 0; dma_index = 0; while (user_request_stop == 0 && length != 0) { check_buffers(fp,&length); buff_status[play_index] = BS_PLAYING; umss.sound_data = buffs[play_index]; umss.sound_len = buff_len[play_index]; dma_index = (dma_index + 1) % NBUFFS; still_playing = 1; voice = um_start_digital(&umss); if (voice == -1) break; while (still_playing) { check_buffers(fp,&length); } } } my_close(fp); } int main(void) { unsigned long mem; int ret, i; int vector; char far *stamp; char filename[80], *cp; char far *command; unsigned char far *command_len; command_len = MK_FP(_psp, 0x80); command = MK_FP(_psp,0x82); if (*command_len <= 1) return(0); command[*command_len-1] = '\0'; cp = filename; while ((*cp++ = *command++) != 0) ; for (vector=0x78; vector <= 0x7f; vector++) { um_hook = (void (far *)())getvect(vector); stamp = (char far *)MK_FP(FP_SEG(um_hook), 0x103); if (my_strncmp(stamp, "ULTRAMID", 8) == 0) break; } if (vector > 0x7f) { myputs("Couldn't find UltraMID\r\n"); return(3); } mem = um_allocate_memory(0x2000L); if (mem == 0L) { myputs("UltraSound card - out of memory"); } else { play(filename, mem); um_free_memory(mem); } return(0); }