[comp.sys.ibm.pc.misc] Soundblaster drivers

fasciano@IRO.UMontreal.CA (Massimo Fasciano) (10/08/90)

Hi everybody,

 a while ago, somebody posted some sources in ASM/C that showed
 how to access the sound driver (CT-VOICE.DRV) used to record/playback
 digitized sounds on the Soundblaster. I erased them by mistake...
 Could somebody send them to me?

 If you don't have these sources, but have a copy of the old SB manual,
 (it contains a description of the 12(?) functions of the driver)
 could you summarize the functions for me?

		     Thanks in advance

--

Massimo Fasciano (fasciano@iro.umontreal.ca)

tjw@unix.cis.pitt.edu (TJ Wood WA3VQJ) (10/13/90)

In article <1990Oct7.215640.24241@IRO.UMontreal.CA> fasciano@IRO.UMontreal.CA (Massimo Fasciano) writes:

>Hi everybody,

> a while ago, somebody posted some sources in ASM/C that showed
> how to access the sound driver (CT-VOICE.DRV) used to record/playback
> digitized sounds on the Soundblaster. I erased them by mistake...
> Could somebody send them to me?

I'll plead guilty! :-)  I did it!

When I get a chance, this weekend, I'll send you my routines.  If
anybody else wants them, send me e-mail.  I'm trying to get caught up
with everything here at work, so I'm somewhat behind on my mail, though!

I've not had much time to play with the sound blaster card lately.

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 

tjw@unix.cis.pitt.edu (Terry J. Wood) (10/15/90)

Well, since my mailbox has been flooded for requests for this code, I conclude
that sound blaster sales must be quite brisk!  So, I'm going to post my
sound blaster interface routines (SB1.ASM) that work with the CT-VOICE.DRV
file.

Also enclosed please find 2 demo programs: RECORD1.C and PLAY1.C which
demonstrate how to call the SB1.ASM routines.

RECORD1.C records sounds to a file.  PLAY1.C plays those sounds.  They do
NOT work with ".VOC" files since ".VOC" files have headers in them that
I've not bother to write.  RECORD1.C will play a ".VOC" file when it's done
recording and you should copy TV4.VOC (that comes with the VOXKIT) to
EXIT.VOC.  You can examine the routine "EXIT_VOICE" to see how to strip off
headers of ".VOC" files before playing them, if you're interesting in doing
that.

PLAY1.C and RECORD1.C are not really all that well written.  I was more
interested in getting the SB1.ASM files to work.  One of the problems that I
faced is that the CT-VOICE.DRV file must be loaded at the beginning of a
memory segment.  I used the crude method of using the huge memory model and
allocating a 64K byte vector array for use with the CT-VOICE.DRV file. 

While this guarantees that the code is loaded at the beginning of a segment,
it's really wastefull.  The driver is less than 3K bytes long!  If I was
really interested in the application program, I would use the rest of the
60 some K vector array for playing/recording sounds.  Or I might learn more
about the assembler and figure out how to allocate memory correctly! :-)

I guess I should point out that I usually program VMS systems and I avoid
using assembly like I avoid the plague.  Try as I might, I couldn't find
a way to load the proper registers from "C" and I broke down and purchased
a macro assembler for this project.  (How red my face is now :-)

RECORD.C and PLAY.C are similar programs to what now comes with the sound
blaster.  When I bought my sound blaster, no such programs existed.  Great
minds think alike, I guess.  These programs will gobble up your hard disk's
free space if you record more than several minutes of sound, btw!  They
don't check for write errors, so don't be suprised if you use it all up
while recording!

If you want to play files generated with RECORD1.C with the sound blaster
provided programs, use VOC-HDR.EXE to add headers to the files.

One thing that my RECORD1.C will do that the sound blaster counter part will
not do, is let you listen in to the recording.  If you invoke RECORD1 program
with "RECORD DEMO.SNG 12000 1" (which means record to DEMO.SNG at 12KHz and
TURN THE SPEAKER ON), you'll hear what you're recording.  Don't panic that
you'll also hear squeaks and squacks, the recording will probably come out
OK.  The manual says to turn off the speaker during recording, but as burger
king sez: "Sometimes you gotta break the rules".  Becareful not to blow your
speakers/ears out, though.  I've come close!

Note that I'm using V5.0 of Microsoft C and V.5.1 of Microsoft Macro Assembler 
to compile/assemble these routines.

These routines are in the public domain.  They are offered to you free of
charge, with no warranty of course!  No warranty whatsoever!  They are yours
to do with as you see fit and you assume all responsibility for their use.
(I'm not a lawyer, nor do I play one on TV, but I wish I did).

If you make a million dollars (or more) off of these routines, please send me
10% :-).  Seriously, if you do make something neat from them, send me a copy
of the source code so I can play with it too.  Games are always welcome. 

(Anybody got a Star Trek program in "C"?  I've recorded some great Star Trek
sound effects and I'd love to add them to one of those old Star Trek Games.
If anyone out there wants to exchange recordings, I'd be game for that too!)

Oh, yes one last thing:  I've bought the developer's kit.  If you're going
to do some serious programming with the board, you'll probably want to get
a copy for yourself.  It's about $100 from creative labs.

It provides an interface for almost everything the board will do.  If you're
a "haquer" like myself, it will provide you with hours of entertainment. 


So, here they are!  Enjoy:

SB1.ASM
----------------------------------------------------------------------
PGROUP  GROUP   INTERFACE
.MODEL HUGE
;    INTERFACE SEGMENT   BYTE PUBLIC 'PROG'
    INTERFACE SEGMENT   BYTE PUBLIC 'DATA'

    ASSUME  CS:INTERFACE


    PUBLIC _SB0          ;Get Version number  Returns: AH - Major  AL - Minor
_SB0 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,0        ;Init Function code

    call    dword ptr [bp+6]    ;call the driver

    pop     bp

    ret

_SB0 ENDP

    PUBLIC _SB1          ;Set Base I/O Address
_SB1 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,3        ;Init Function code
    mov     ax,[bp+6]   ;Set AX to be the base address (210x - 260x)

    call    dword ptr [bp+8]    ;call the driver

    pop     bp

    ret

_SB1 ENDP

    PUBLIC _SB2          ;Set Interrupt number
_SB2 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,3        ;Init Function code
    mov     ax,[bp+6]   ;Set AX to be the interrupt number for the DMA (2,3,5 or 7)

    call    dword ptr [bp+8]    ;call the driver

    pop     bp

    ret

_SB2 ENDP


    PUBLIC _SB3         ;Init Sound Blaster
_SB3 PROC    FAR
                        ;Returns: 0 - OK!;                  1 - Voice Card Fails
                        ;         2 - I/O read/write fails; 3 -Interrupt for DMA Fails

    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,3        ;Init Function code

    call    dword ptr [bp+6]    ;call the driver

    pop     bp

    ret

_SB3 ENDP

    PUBLIC _SB4          ;Speaker off(0)/on(1) 
_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

    call    dword ptr [bp+8]    ;call the driver

    pop     bp

    ret


_SB4 ENDP

    PUBLIC _SB5          ;Set status word address 
_SB5 PROC    FAR


    push    bp          ;save the base pointer
    mov     bp,sp       ;store the beginning of the stack in bp

    push    di

    mov     bx,5        ;function code 5

    mov     di,[bp+6]   ;offset address of status word into reg di
    mov     es,[bp+8]   ;Segment address

    call    dword ptr [bp+10]    ;call the driver

    pop     di          ;restore the value of the di register
    pop     bp          ;restore the base pointer
    ret                 


_SB5 ENDP

    PUBLIC _SB6          ;Output voice
_SB6 PROC    FAR

    push    bp          ;save the base pointer
    mov     bp,sp       ;store the beginning of the stack in bp

    push    di

    mov     bx,6        ;function code 6

    mov     di,[bp+6]   ;offset address of sound buffer into reg di
    mov     es,[bp+8]   ;Segment address

    call    dword ptr [bp+10]    ;call the driver

    pop     di          ;restore the value of the di register
    pop     bp          ;restore the base pointer
    ret                 

_SB6 ENDP


    PUBLIC _SB7          ;Input voice 
_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

    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


    call    dword ptr [bp+16]    ;call the driver


    pop     di          ;restore the value of the di register 
    pop     bp          ;restore the base pointer
    ret                 

_SB7 ENDP




    PUBLIC _SB8          ;Stop Voice Process 
_SB8 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,8        ;Init Function code

    call    dword ptr [bp+6]    ;call the driver

    pop     bp

    ret

_SB8 ENDP

    PUBLIC _SB9          ;Uninstall Driver
_SB9 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,9        ;Init Function code

    call    dword ptr [bp+6]    ;call the driver

    pop     bp

    ret

_SB9 ENDP

    PUBLIC _SB10        ;Pause Output Voice
_SB10 PROC    FAR       ;Returns: 0 - OK!;  1- Voice output not in progress

    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,10        ;Init Function code

    call    dword ptr [bp+6]    ;call the driver

    pop     bp

    ret

_SB10 ENDP

    PUBLIC _SB11        ;Continue Output Voice
_SB11 PROC    FAR
                        ;Returns: 0 - OK!;  1- No Voice to continue

    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,11        ;Init Function code

    call    dword ptr [bp+6]    ;call the driver

    pop     bp

    ret

_SB11 ENDP

    PUBLIC _SB12          ;Break-out Looping Voice
_SB12 PROC    FAR
                          ;Returns: 0 - OK!;  1- No voice in loop

    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

    call    dword ptr [bp+8]    ;call the driver

    pop     bp

    ret

_SB12 ENDP

    INTERFACE ENDS

    END

----------------------------------------------------------------------
RECORD1.C
----------------------------------------------------------------------
#include <stdio.h>

char huge SB_DRIVER[65536];
unsigned int far SB_STATUS_WORD;

unsigned long int array_size = 65536;
char huge array1[65536];
char huge array2[65536];

extern  int far SB0();      /* Get version of driver                        */
extern  int far SB1();      /* Set Base I/O Address                         */
extern  int far SB2();      /* Set Interrupt number (2,3,5, or 7)           */
extern  int far SB3();      /* Init Driver                                  */
extern  int far SB4();      /* Turn speaker off (0) or (1) On               */
extern  int far SB5();      /* Tell Driver the address of the Status Word   */
extern  int far SB6();      /* Play voice                                   */
extern  int far SB7();      /* Record Voice                                 */
extern  int far SB8();      /* Stop Voice Process                           */
extern  int far SB9();      /* Uninstall Driver (clean up, etc)             */
extern  int far SB10();     /* Pause playing voice                          */
extern  int far SB11();     /* Continue playing voice                       */
extern  int far SB12();     /* Break-out looping voice                      */

unsigned int c;
unsigned long int count;
unsigned int SB_DRIVER_SIZE;
unsigned long int start_seg_addr;
char far *ptr;


main(argc,argv)
int argc;
char *argv[];
{

    FILE *fp;

    unsigned long  int i;
    unsigned int j;
    unsigned short int k;
    unsigned int digi_rate;
    unsigned int speaker_setting;

    unsigned int version;

    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);
    }

    if (argc >= 3){
        sscanf(argv[2],"%d",&digi_rate);
    }
    else {
        printf("Rate to Scan? (4000 to 12000) >");
        scanf("%d",&digi_rate);
        printf("\n\n");
    }

    if (argc >= 4){
        sscanf(argv[3],"%d",&speaker_setting);
    }
    else {
        speaker_setting = 0;
    }

    k = LOAD_DRIVER();

    version = SB0(SB_DRIVER);
    printf("CT-DRIVER version is %d.%d\n\n",(version & 0xFF00) >> 8,version & 0x00FF);


    k = SB3(SB_DRIVER);
    if( k != 0){
        printf("Init FAILS %d\n",k);
    }

    k = SB5(&SB_STATUS_WORD,SB_DRIVER);
    if( k != 0){
        printf("Set status word FAILS %d\n",k);
    }

    k = SB4(speaker_setting,SB_DRIVER);
    if( k != 0){
        printf("Speaker control FAILS %d\n",k);
    }

    printf("Press any key to BEGIN Recording...");

    while (kbhit() == 0);
    k = getche();

    printf("\rPress any key to STOP Recording... ");

    k = SB7(array1,digi_rate,array_size,SB_DRIVER);

    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,SB_DRIVER);

        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,SB_DRIVER);

        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,SB_DRIVER);
    if( k != 0){
        printf("Speaker on FAILS %d\n",k);
    }


    printf("\rYour recording is complete...      ");

    k = EXIT_VOICE();    

    k = SB6(array1,SB_DRIVER);

    SB_WAIT();

    if( k != 0){
        printf("Voice out FAILS %d\n",k);
    }

    k = SB4(0,SB_DRIVER);
    if( k != 0){
        printf("Speaker off FAILS %d\n",k);
    }

    k = SB9(SB_DRIVER);
    if( k != 0){
        printf("Uninstall driver 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;

    if( (fp = fopen("CT-VOICE.DRV","rb")) == NULL){
        return(1);
    }

        
    SB_DRIVER_SIZE = 0;

    while ( (c = fgetc(fp)) != EOF){

        SB_DRIVER[SB_DRIVER_SIZE] = c;

        SB_DRIVER_SIZE++;
    }

    fclose(fp);

    return(0);
}
----------------------------------------------------------------------
PLAY1.C
----------------------------------------------------------------------
#include <stdio.h>

char huge SB_DRIVER[65536];
unsigned int far SB_STATUS_WORD;

unsigned long int array_size = 65536;
char huge array1[65536];
char huge array2[65536];

extern  int far SB0();      /* Get version of driver                        */
extern  int far SB1();      /* Set Base I/O Address                         */
extern  int far SB2();      /* Set Interrupt number (2,3,5, or 7)           */
extern  int far SB3();      /* Init Driver                                  */
extern  int far SB4();      /* Turn speaker off (0) or (1) On               */
extern  int far SB5();      /* Tell Driver the address of the Status Word   */
extern  int far SB6();      /* Play voice                                   */
extern  int far SB7();      /* Record Voice                                 */
extern  int far SB8();      /* Stop Voice Process                           */
extern  int far SB9();      /* Uninstall Driver (clean up, etc)             */
extern  int far SB10();     /* Pause playing voice                          */
extern  int far SB11();     /* Continue playing voice                       */
extern  int far SB12();     /* Break-out looping voice                      */

unsigned int c;
unsigned long int count;
unsigned int SB_DRIVER_SIZE;
unsigned long int start_seg_addr;
char far *ptr;


main(argc,argv)
int argc;
char *argv[];
{
    FILE *fp;

    unsigned long  int i;
    unsigned int j;
    unsigned short int k;
    unsigned int digi_rate;
    unsigned int version;

    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 */

    version = SB0(SB_DRIVER);     /* Get version number of driver */
    printf("CT-DRIVER version is %d.%d\n\n",(version & 0xFF00) >> 8,version & 0x00FF);

    k = SB3(SB_DRIVER);              /* Init */
    if( k != 0){
        printf("Init FAILS %d\n",k);
    }

    k = SB5(&SB_STATUS_WORD,SB_DRIVER);   /* Assign the status word */
    if( k != 0){
        printf("Set status word FAILS %d\n",k);
    }


    k = SB4(1,SB_DRIVER);             /* Speaker On */
    if( k != 0){
        printf("Speaker on FAILS %d\n",k);
    }


    while(now_at_end == 0){

        printf("loading buffer 1\r");

        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){

            printf("                \r");

            SB_WAIT();  /* Wait for sb to finish playing array2 */

            if(kbhit() != 0){   /* If any key is pressed, exit */
                k = getche();
                break;
            }

        }

        k = SB6(array1,SB_DRIVER);

        if( k != 0){
            printf("Voice out FAILS %d\n",k);
        }

        now_playing = 1;    /* raise the flag */

        if (now_at_end != 0){
            break;
        }


        printf("loading buffer 2\r");

        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;
            }
        }

        printf("                \r");


        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,SB_DRIVER);

        if( k != 0){
            printf("Voice out array2 FAILS %d\n",k);
        }

    }

    fclose(fp);

    k = SB4(0,SB_DRIVER);
    if( k != 0){
        printf("Speaker off FAILS %d\n",k);
    }


    k = SB9(SB_DRIVER);
    if( k != 0){
        printf("Uninstall driver FAILS %d\n",k);
    }


}

int SB_WAIT()  /* Waits until sound board is done */
{ 
    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;

    if( (fp = fopen("CT-VOICE.DRV","rb")) == NULL){
        return(1);
    }

        
    SB_DRIVER_SIZE = 0;

    while ( (c = fgetc(fp)) != EOF){

        SB_DRIVER[SB_DRIVER_SIZE] = c;

        SB_DRIVER_SIZE++;
    }

    fclose(fp);

    return(0);
}
-- 
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