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