tjw@unix.cis.pitt.edu (TJ Wood WA3VQJ) (08/25/90)
I've updated the code that I wrote for the Soundblaster. This new code will work with the Microsoft C "huge" memory model. The applications "PLAY.C" and "RECORD.C" turn your PC into a tape (CD?) recorder by using the Soundblaster's A/D D/A converters. To compile/assemble these routines, I used MSC 5.0 and MSA 4.0. You'll also need CT-VOICE.DRV (which is part of the VOXKIT) and you'll need to copy one of the ".VOC" files to EXIT.VOC (I used TV4.VOC which comes with the VOXKIT). Be sure to compile this code with the /AH switch to get the huge memory model. The general syntax for using these routines is: "RECORD fn.ext", where fn.ext is the name of the file you wish to record into. PLAY works the same way. The RECORD program prompts for a scan rate (5000 to 13000 Hz). If you try this code, please drop me a line via e-mail. Maybe we can share some ideas about the board. I've sent for the programmer's tool kit, and I hope to figure out how to use the other "voices" of the board. Anyway here's the code: SB.ASM: PGROUP GROUP INTERFACE INTERFACE SEGMENT BYTE PUBLIC 'DATA' ASSUME CS:INTERFACE PUBLIC _sb_driver _SB_DRIVER PROC FAR db 2500 dup (0) _SB_DRIVER ENDP PUBLIC _SB_STATUS_WORD _SB_STATUS_WORD PROC FAR dw 0 _SB_STATUS_WORD ENDP PUBLIC _SB3 ;Init Sound Board _SB3 PROC FAR mov bx,3 ;Init Function code mov cx,0 jmp cx ;Go to top of segment (where the driver starts) _SB3 ENDP PUBLIC _SB4 ;Speaker off(0)/on(1) Sound Board Interface _SB4 PROC FAR push bp ;save the original base pointer mov bp,sp ;store the beginning of the stack in bp ;push (in order) any additional registers here mov bx,4 mov ax,[bp+6] ;Function code pop bp ;restore the base pointer mov cx,0 jmp cx ;Go to top of segment (where the driver starts) _SB4 ENDP PUBLIC _SB5 ;Set status word address Sound Board Interface _SB5 PROC FAR push bp ;save the base pointer mov bp,sp ;store the beginning of the stack in bp push di ;save for later push si mov bx,5 ;function code 5 mov di,[bp+6] ;offset address of status word into reg di mov es,[bp+8] ;Segment address mov si,0 ;set si to point to the start of the driver push cs ;set up for a far return call si ;call the driver with a pseudo "far" call pop si ;restore the value of the si register pop di ;restore the value of the di register pop bp ;restore the base pointer ret ;"Clem Clone! Back to the shadows again! (Appologies to The Firesign Theatre) _SB5 ENDP PUBLIC _SB6 ;Output voice - Sound Board Interface _SB6 PROC FAR push bp ;save the base pointer mov bp,sp ;store the beginning of the stack in bp push di push si mov bx,6 ;function code 6 mov di,[bp+6] ;offset address of sound buffer into reg di mov es,[bp+8] ;Segment address mov si,0 ;set si to point to the start of the driver push cs ;set up for a far return call si ;call the driver with a pseudo "far" call pop si ;restore the value of the si register pop di ;restore the value of the di register pop bp ;restore the base pointer ret ;"Clem Clone! Back to the shadows again! (Appologies to The Firesign Theatre) _SB6 ENDP PUBLIC _SB7 ;Input voice Sound Board Interface _SB7 PROC FAR push bp ;save the original base pointer mov bp,sp ;store the beginning of the stack in bp push di ;push (in order) any additional registers here push si mov bx,7 mov di,[bp+6] ;offset address of sound buffer into reg di mov es,[bp+8] ;Segment address mov ax,[bp+10] ;Sampling rate mov cx,[bp+12] ;ditto mov dx,[bp+14] ;Size of buffer mov si,0 ;set si to point to the start of the driver push cs ;set up for a far return call si ;call the driver with a pseudo "far" call pop si ;restore the value of the si register pop di ;restore the value of the di register pop bp ;restore the base pointer ret ;"Clem Clone! Back to the shadows again! (Appologies to The Firesign Theatre) _SB7 ENDP PUBLIC _SB8 ;Stop Voice Process Sound Board Interface _SB8 PROC FAR mov bx,8 mov ax,0 jmp ax ;Go to top of segment (where the driver starts) _SB8 ENDP PUBLIC _SB9 ;Uninstall Driver - Sound Board Interface _SB9 PROC FAR mov bx,9 mov ax,0 jmp ax ;Go to top of segment (where the driver starts) _SB9 ENDP PUBLIC _SB10 ;Sound Board Interface _SB10 PROC FAR mov bx,10 mov ax,0 jmp ax ;Go to top of segment (where the driver starts) _SB10 ENDP PUBLIC _SB11 ;Sound Board Interface _SB11 PROC FAR mov bx,11 mov ax,0 jmp ax ;Go to top of segment (where the driver starts) _SB11 ENDP PUBLIC _SB12 ;Sound Board Interface _SB12 PROC FAR push bp ;save the original base pointer mov bp,sp ;store the beginning of the stack in bp ;push (in order) any additional registers here mov bx,12 mov ax,[bp+6] ;load Parameter into ax pop bp ;restore the base pointer mov cx,0 jmp cx ;Go to top of segment (where the driver starts) _SB12 ENDP INTERFACE ENDS END -------------------------------CUT HERE---------------------------------- PLAY.C #include <stdio.h> extern char far SB_DRIVER; unsigned long int array_size = 50000; char huge array1[50000]; char huge array2[50000]; extern unsigned int far SB_STATUS_WORD; extern int far SB3(); extern int far SB4(); extern int far SB5(); extern int far SB6(); extern int far SB7(); extern int far SB8(); extern int far SB9(); extern int far SB10(); extern int far SB11(); extern int far SB12(); unsigned int c; unsigned long int count; unsigned int SB_DRIVER_SIZE; unsigned long int start_seg_addr; char far *ptr; unsigned char SB_DRIVER_CODE[3000]; main(argc,argv) int argc; char *argv[]; { FILE *fp; unsigned long int i; unsigned int j; unsigned short int k; unsigned int digi_rate; int LOAD_DRIVER(); int now_at_end=0; int now_playing=0; if (argc != 2){ printf("Usage: Play fn.ext\n"); exit(1); } if ( (fp = fopen(argv[1],"rb") ) == NULL) { /* Open input file */ printf("PLAY: error opening %s , file not found\n",argv[1]); exit(2); } printf("Press any key to EXIT\n\n"); k = LOAD_DRIVER(); /* Read the VOXKIT driver into memory */ k = SB3(); /* Init */ if( k != 0){ printf("Init FAILS %d\n",k); } k = SB5(&SB_STATUS_WORD); /* Assign the status word */ if( k != 0){ printf("Set status word FAILS %d\n",k); } k = SB4(1); /* Speaker On */ if( k != 0){ printf("Speaker on FAILS %d\n",k); } while(now_at_end == 0){ SAVE_DRIVER(); printf("loading buffer 1\r"); RESTORE_DRIVER(); for(i=0; i < array_size; i++){ c = fgetc(fp); if(c != EOF){ array1[i] = c; } else { if(i == 0){ now_at_end = 1; break; } else { now_at_end = 2; for (j = i; j < array_size; j++){ array1[j] = 0; } } break; } } if(now_playing == 1){ SB_WAIT(); /* Wait for sb to finish playing array2 */ if(kbhit() != 0){ /* If any key is pressed, exit */ k = getche(); break; } } k = SB6(array1); if( k != 0){ printf("Voice out FAILS %d\n",k); } now_playing = 1; /* raise the flag */ if (now_at_end != 0){ break; } SAVE_DRIVER(); printf("loading buffer 2\r"); RESTORE_DRIVER(); for(i=0; i < array_size; i++){ c = fgetc(fp); if(c != EOF){ array2[i] = c; } else { if(i == 0){ now_at_end = 1; break; } else { now_at_end = 2; for (j = i; j < array_size; j++){ array2[j] = 0; } } break; } } SB_WAIT(); /* Wait for sb to finish playing array1 */ if(kbhit() != 0){ /* If any key is pressed, exit */ k = getche(); break; } if(now_at_end != 0){ break; } k = SB6(array2); if( k != 0){ printf("Voice out array2 FAILS %d\n",k); } } fclose(fp); k = SB4(0); if( k != 0){ printf("Speaker on FAILS %d\n",k); } } int SB_WAIT() /* Waits until sound board is done */ { /* Returns the number of loops we made */ unsigned int j; do { /* Loop until sound board is done */ j = SB_STATUS_WORD; } while(j != 0); } int LOAD_DRIVER() /* Load driver from disk file */ { FILE *fp; ptr = &SB_DRIVER; start_seg_addr = ptr; start_seg_addr = start_seg_addr & 0xFFFF0000; ptr = start_seg_addr; if( (fp = fopen("CT-VOICE.DRV","rb")) == NULL){ return(1); } SB_DRIVER_SIZE = 0; while ( (c = fgetc(fp)) != EOF){ *(ptr+SB_DRIVER_SIZE) = c; SB_DRIVER_SIZE++; } fclose(fp); return(0); } int SAVE_DRIVER() /* Save current state of driver from memory */ { int i; ptr = start_seg_addr; for (i=0; i < SB_DRIVER_SIZE; i++){ SB_DRIVER_CODE[i] = *(ptr+i); } } int RESTORE_DRIVER() /* Restore driver back into memory */ { int i; ptr = start_seg_addr; for (i=0; i < SB_DRIVER_SIZE; i++){ *(ptr+i) = SB_DRIVER_CODE[i]; } } ----------------------------CUT HERE--------------------------- RECORD.C #include <stdio.h> extern char far SB_DRIVER; unsigned long int array_size = 50000; char huge array1[50000]; char huge array2[50000]; extern unsigned int far SB_STATUS_WORD; extern int far SB3(); extern int far SB4(); extern int far SB5(); extern int far SB6(); extern int far SB7(); extern int far SB8(); extern int far SB9(); extern int far SB10(); extern int far SB11(); extern int far SB12(); unsigned int c; unsigned long int count; unsigned int SB_DRIVER_SIZE; unsigned long int start_seg_addr; char far *ptr; unsigned char SB_DRIVER_CODE[3000]; main(argc,argv) int argc; char *argv[]; { FILE *fp; unsigned long int i; unsigned int j; unsigned short int k; unsigned int digi_rate; int LOAD_DRIVER(); if (argc != 2){ printf("Usage: RECORD fn.ext\n"); exit(1); } if ( (fp = fopen(argv[1],"wb") ) == NULL) { /* Open output file */ printf("RECORD: error opening %s\n",argv[1]); exit(2); } printf("Rate to Scan? (5000 to 13000) >"); scanf("%d",&digi_rate); printf("\n\n"); k = LOAD_DRIVER(); k = SB3(); if( k != 0){ printf("Init FAILS %d\n",k); } k = SB5(&SB_STATUS_WORD); if( k != 0){ printf("Set status word FAILS %d\n",k); } k = SB4(0); if( k != 0){ printf("Speaker off FAILS %d\n",k); } SAVE_DRIVER(); printf("Press any key to BEGIN Recording..."); while (kbhit() == 0); k = getche(); printf("\rPress any key to STOP Recording... "); RESTORE_DRIVER(); k = SB7(array1,digi_rate,array_size); if( k != 0){ printf("Voice in FAILS %d\n",k); } while (1 == 1){ SB_WAIT(); if(kbhit() != 0){ k = getche(); break; } k = SB7(array2,digi_rate,array_size); for(i=0; i < array_size; i++){ /* Write first buffer to file */ fputc(array1[i],fp); } SB_WAIT(); k = SB7(array1,digi_rate,array_size); if( k != 0){ printf("Voice in FAILS %d\n",k); } for(i=0; i < array_size; i++){ /* Write second buffer to file */ fputc(array2[i],fp); } } for(i=0; i < array_size; i++){ /* Write first buffer to file */ fputc(array1[i],fp); } fclose(fp); k = SB4(1); if( k != 0){ printf("Speaker on FAILS %d\n",k); } SAVE_DRIVER(); printf("\rYour recording is complete... "); RESTORE_DRIVER(); k = EXIT_VOICE(); k = SB6(array1); SB_WAIT(); if( k != 0){ printf("Voice out FAILS %d\n",k); } k = SB4(0); if( k != 0){ printf("Speaker off FAILS %d\n",k); } } int EXIT_VOICE() { FILE *fp; unsigned long int i; if( (fp = fopen("EXIT.VOC","rb")) == NULL){ return(1); } for(i=0; i < 0x1a; i++){ /*Strip off the header */ c = fgetc(fp); } i=0; while ( (c = fgetc(fp)) != EOF){ array1[i] = c; i++; } fclose(fp); return(0); } int SB_WAIT() /* Waits until sound board is done */ { /* Returns the number of loops we made */ unsigned int j; do { /* Loop until sound board is done */ j = SB_STATUS_WORD; } while(j != 0); } int LOAD_DRIVER() /* Load driver from disk file */ { FILE *fp; ptr = &SB_DRIVER; start_seg_addr = ptr; start_seg_addr = start_seg_addr & 0xFFFF0000; ptr = start_seg_addr; if( (fp = fopen("CT-VOICE.DRV","rb")) == NULL){ return(1); } SB_DRIVER_SIZE = 0; while ( (c = fgetc(fp)) != EOF){ *(ptr+SB_DRIVER_SIZE) = c; SB_DRIVER_SIZE++; } fclose(fp); return(0); } int SAVE_DRIVER() /* Save current state of driver from memory */ { int i; ptr = start_seg_addr; for (i=0; i < SB_DRIVER_SIZE; i++){ SB_DRIVER_CODE[i] = *(ptr+i); } } int RESTORE_DRIVER() /* Restore driver back into memory */ { int i; ptr = start_seg_addr; for (i=0; i < SB_DRIVER_SIZE; i++){ *(ptr+i) = SB_DRIVER_CODE[i]; } } ---------------------CUT HERE------------------------ -- INTERNET: tjw@unix.cis.pitt.edu BITNET: TJW@PITTVMS CC-NET: 33802::tjw UUCP: {decwrl!decvax!idis, allegra, bellcore}!pitt!unix.cis.pitt.edu!tjw And if dreams could come true, I'd still be there with you, On the banks of cold waters at the close of the day. - Craig Johnson
tjw@unix.cis.pitt.edu (TJ Wood WA3VQJ) (08/29/90)
In article <31643@unix.cis.pitt.edu> tjw@unix.cis.pitt.edu I wrote: >I've updated the code that I wrote for the Soundblaster. This new code >will work with the Microsoft C "huge" memory model. >The applications "PLAY.C" and "RECORD.C" turn your PC into a tape (CD?) >recorder by using the Soundblaster's A/D D/A converters. I just received my "developer's kit" today. In it was another "User Reference Manual" and new floppy disks for version 1.5 of the Soundboard software. Also included are two new (to me) programs: SBTALKER and DR SBAITSO. These were not included in my original package. This leads me to believe that I bought an "old" package (just how old, I'm not really sure). I notice all of the information that I used to construct my macro assembly interface to CT-VOICE.DRV is not contained in the new user reference manual. If you've been unable to make heads-nor-tails of my code, please accept my appology! I assumed that everyone had the same manual with the same appendix. I'll post a description of the routines and their use in the near future. The appendix that I used is included in the developer's kit. Also there's a "tip" that explains why my original polling loop would go into an infinite loop: the compiler is playing optimization tricks on me and assigning a register instead of the memory location I wanted! (I'm not crazy after all) ;-) I'm also concerned that perhaps I have old hardware. The new flyer I have on the SOUNDBLASTER says that the DAC can sample at 23KHz. The old VOXKIT program that I have limits sampling to 13KHz. If I run my RECORD program at > 13KHz all it does is "speed up" the playback. Perhaps this is a function of the CT-VOICE.DRV that came with my original package. Has anyone tried their VOXKIT at 23KHz? I'm going to install the "new" software and see what happens. The developer's kit looks interesting. I'll post a "review" of sorts in the future. Terry -- INTERNET: tjw@unix.cis.pitt.edu BITNET: TJW@PITTVMS CC-NET: 33802::tjw UUCP: {decwrl!decvax!idis, allegra, bellcore}!pitt!unix.cis.pitt.edu!tjw And if dreams could come true, I'd still be there with you, On the banks of cold waters at the close of the day. - Craig Johnson