/* * Routines for sampling from a Soundblaster-16 sound card. * These routines require the functions in sbio.c derived from * Ethan Brodsky's Soundblaster-16 programming library . * Copyright (C) 1997 Philip VanBaren & Emil Laurentiu * Last modified: Wednesday, 06 August 1997 */ #include "freq.h" #ifdef SC_SB16 #include #include #include #include #include #include "sb.h" #include "sbio.h" #include "extern.h" /* Function prototypes */ int atox16( char *ptr ); void interrupt sb16_callback( void ); void init_sb16( char **environ ); void reset_sb16( void ); void halt_sb16( void ); void cleanup_sb16( void ); void recordblock_sb16( void far * buffer ); void set_mixer_sb16( int mix, int level ); int atox16( char *ptr ) { // Convert ascii hex values to integer int v = 0; while ( ( ( *ptr >= '0' ) && ( *ptr <= '9' ) ) || ( ( ( *ptr | 0x20 ) >= 'a' ) && ( ( *ptr | 0x20 ) <= 'f' ) ) ) { v = v * 16; if ( *ptr <= '9' ) v = v + *ptr - '0'; else v = v + ( *ptr | 0x20 ) - 'a' + 10; ptr++; } return v; } #define is_blaster(var) ((((var)[0]=='B')||((var)[0]=='b')) && \ (((var)[1]=='L')||((var)[1]=='l')) && \ (((var)[2]=='A')||((var)[2]=='a')) && \ (((var)[3]=='S')||((var)[3]=='s')) && \ (((var)[4]=='T')||((var)[4]=='t')) && \ (((var)[5]=='E')||((var)[5]=='e')) && \ (((var)[6]=='R')||((var)[6]=='r'))) /* Turn off stack checking for this routine */ #pragma option -N- void interrupt sb16_callback( ) { extern int poll16port, dma_maskport, dma_stopmask; unsigned int far *s, far * d; int i; /* * Callback function. This function is called every time a buffer has been * filled. It copies the latest data, and sets a flag so the main loop * recognises and processes the buffer. */ d = buffer[record_buffer]; s = dmaptr + (curblock * fftlen); for ( i = 0; i < fftlen; i++ ) *d++ = *s++; flag[record_buffer] = 1; if ( ++record_buffer >= BUFFERS ) record_buffer = 0; curblock = !curblock; /* Toggle active block flag */ /* If we hit the end of the queued buffers, stop recording */ if ( record_buffer == queue_buffer ) { write_dsp( 0xD5 ); /* Stop digitized sound xfer */ outportb( dma_maskport, dma_stopmask ); /* Mask DMA channel */ sb16dmarunning = 0; } /* Acknowledge the interrupt */ inportb( poll16port ); outportb( 0x20, 0x20 ); outportb( 0xA0, 0x20 ); } /* Restore stack checking to the command-line specified state */ #pragma option -N. void init_sb16( char **environ ) { int i; // Scan the environment variables for BLASTER=Axxx Ix Dx for ( i = 0; environ[i] != NULL; i++ ) { if ( is_blaster( environ[i] ) ) { int j; DOUT( "SB16: Found the BLASTER environment variable:" ); DOUT( environ[i] ); for ( j = 8; environ[i][j] != 0; j++ ) { if ( ( environ[i][j] == 'A' ) || ( environ[i][j] == 'a' ) ) { DOUT( "SB16: Axxx found" ); sb_addr = atox16( &environ[i][j + 1] ); } if ( ( environ[i][j] == 'H' ) || ( environ[i][j] == 'h' ) ) { DOUT( "SB16: Hx found" ); sb_dma = atoi( &environ[i][j + 1] ); } if ( ( environ[i][j] == 'I' ) || ( environ[i][j] == 'i' ) ) { DOUT( "SB16: Ix found" ); sb_irq = atoi( &environ[i][j + 1] ); } // Skip to the next parameter while ( ( environ[i][j] != ' ' ) && ( environ[i][j + 1] != 0 ) ) j++; } break; } } #ifdef DEBUG_OUTPUT { char message[100]; sprintf( message, "SB16: Address=0x%03x, DMA=%d, IRQ=%d", sb_addr, sb_dma, sb_irq ); DOUT( message ); } #endif /* Set up the pointers to the recording routines */ reset_soundcard = reset_sb16; halt_soundcard = halt_sb16; cleanup_soundcard = cleanup_sb16; recordblock = recordblock_sb16; set_mixer = set_mixer_sb16; sample_size = 16; mixers = 1; DOUT( "SB16: Initializing the card" ); if ( !init_sb( sb_addr, sb_irq, sb_dma, input, MAX_LEN ) ) { closegraph( ); puts( "Unable to initialize the Soundblaster16 card, aborting..." ); exit( 1 ); } DOUT( "SB16: Reading initial mixer settings" ); mic_level = get_mic_level( ); ext_level = get_line_level( ); int_level = get_cd_level( ); DOUT( "SB16: Set Master volume & FM volume to maximum" ); set_master_level( 0x0f ); set_fm_level( 0x0f ); } void reset_sb16( void ) { int i; /* Round sampling rate to a valid value for the SB card */ i = floor( 1000000.0 / SampleRate + 0.5 ); if ( i < 1 ) i = 1; SampleRate = floor( 1000000.0 / ( double ) i + 0.5 ); /* Reset the buffer pointers */ queue_buffer = 0; // Pointer to next buffer to be queued record_buffer = 0; // Pointer to next buffer to be filled process_buffer = 0; // Pointer to next buffer to be FFTed for ( i = 0; i < BUFFERS; i++ ) flag[i] = 0; /* This function starts the DMA process. */ DOUT( "SB16: Starting the recording process" ); recordblock_sb16( ( char far * ) buffer[queue_buffer] ); } void halt_sb16( void ) { /* * Shut down the DMA system. */ DOUT( "SB16: Stopping the sampling process" ); stopio( ); } void cleanup_sb16( void ) { /* * Shut down the DMA system and remove the interrupt handler. */ DOUT( "SB16: Stopping the sampling process and cleaning up" ); shutdown_sb( ); Sb_FM_Reset( ); } void recordblock_sb16( void far * buffer ) { /* Start transferring data into the DMA buffer */ if ( ++queue_buffer >= BUFFERS ) queue_buffer = 0; /* If the DMA has halted, restart it */ if ( !sb16dmarunning ) startio( ( unsigned int ) SampleRate, fftlen ); } void set_mixer_sb16( int mix, int level ) { /* * Set a mixer level on the PAS16 card */ if ( mix == MIXER_EXT ) { DOUT( "SB16: Setting the line mixer level" ); set_line_level( level ); } else if ( mix == MIXER_INT ) { DOUT( "SB16: Setting the CD mixer level" ); set_cd_level( level ); } else if ( mix == MIXER_MIC ) { DOUT( "SB16: Setting the microphone mixer level" ); set_mic_level( level ); } } #endif