WAVE.C
上传用户:sunrenlu
上传日期:2022-06-13
资源大小:1419k
文件大小:8k
源码类别:

操作系统开发

开发平台:

DOS

  1. /*
  2.  * wave - crudely play Windows WAV files while preemptive multithreading
  3.  *      - if -sb option given, outputs directly through soundblaster card
  4.  *      - demonstrates hooking the timer tick
  5.  *      - demonstrates messaging between ISR and a thread
  6.  *
  7.  * Copyright (c) 1999 Erick Engelke
  8.  *
  9.  * This is a very crude program which reads Windows WAV files and
  10.  * attempts to convert them to 1-BIT speaker output, or 8-BIT SoundBlaster.
  11.  *
  12.  * NOTE: only 8 bit WAV files supported.
  13.  */
  14. #include <stdio.h>
  15. #include <mem.h>
  16. #include <process.h>
  17. #include <ctype.h>
  18. #include <conio.h>
  19. #include <dos.h>
  20. #include <rtos.h>
  21. #include <string.h>
  22. /*------------------ structure of a WAV file ------------------------*/
  23. typedef struct {
  24.     BYTE  wav_riff[4];       // "RIFF"
  25.     DWORD wav_chunksize;
  26.     BYTE  wav_wave[4];       // "WAVE"
  27. } wav_hdr;
  28. typedef struct {
  29.     char    bID[4];
  30.     DWORD   dwSize;
  31. } chunk_str;
  32. typedef struct {
  33.     WORD    wFormatTag;     // 1 = WAVE_FORMAT_PCM
  34.     WORD    wChannels;      // 1 = mono
  35.     DWORD   dwSamplesPerSec;    // sampling rate
  36.     DWORD   dwAvgBYTEsPerSec;   // for buffer estimation
  37.     WORD    wBlockAlign;        // data block size
  38. } fmt_str;
  39. /*--------------------- global variables ----------------------------*/
  40. WORD soundskip;
  41. WORD soundposn;
  42. BYTE *sounddata;
  43. WORD soundlength;
  44. BYTE soundthreshhold = 120;
  45. /*--------------------- global functions ----------------------------*/
  46. void settimer( void (*x)() )
  47. {
  48.     disable();
  49.     k_user_int8 = x;
  50.     enable();
  51. }
  52. /*------------------ Sound Blaster Functions --------------------------*/
  53. int use_sb = 0;
  54. WORD sb_base = 0;
  55. /*
  56.  * Offsets relative to base I/O address.
  57.  */
  58. #define SB_DSP_RESET 0x06
  59. #define SB_DSP_READ_DATA 0x0A
  60. #define SB_DSP_WRITE_DATA 0x0C
  61. #define SB_DSP_WRITE_STATUS 0x0C
  62. #define SB_DSP_DATA_AVAIL 0x0E
  63. /* DSP Commands */
  64. #define SB_DIRECT_8_BIT_DAC 0x10
  65. #define SB_SPEAKER_ON 0xD1
  66. #define SB_SPEAKER_OFF 0xD3
  67. #define SB_DSP_ID 0xE0
  68. #define SB_DSP_VER 0xE1
  69. void sb_writedac(BYTE x)
  70. {
  71.     while(inportb(sb_base + SB_DSP_WRITE_STATUS) & 0x80);
  72.     outportb(sb_base + SB_DSP_WRITE_DATA, x);
  73. }
  74. void sb_init( void )
  75. {
  76.     WORD port;
  77.     WORD count, count2;
  78.     for ( port = 0x210 ; port <= 0x260 ; port += 0x10 ) {
  79.         count = 10;
  80.         while ( count != 0 ) {
  81.             outportb( port + 0x6, 1 );        /* reset SB */
  82.             for ( count2 = 0 ; count2 < 100 ; ++count2 );
  83.             outportb( port + 0x6, 0 );
  84.             for ( count2 = 50 ;
  85.                   (count2 !=0 ) && ( inportb( port + 0xe ) < 128 ) ;
  86.                   count2-- );
  87.             if ( ( count2 == 0 ) || ( inportb( port + 0xa ) != 0xaa )) {
  88.                 count--;
  89.                 if ( count != 0 ) continue;
  90.                 else break;
  91.             } else {
  92.                 sb_base = port;
  93.                 cprintf("Sound Blaster found found at port 0x%xrn", port );
  94.                 /* enable speaker */
  95.                 sb_writedac( SB_SPEAKER_ON );
  96.                 return;
  97.             }
  98.         }
  99.     }
  100. }
  101. void sb_code( BYTE value )
  102. {
  103.     sb_writedac( 0x10 );
  104.     sb_writedac( value );
  105. }
  106. /*------------------ support functions ------------------------------*/
  107. int read_wav_hdr( FILE *f, wav_hdr *wav )
  108. {
  109.     if ( fread( wav, sizeof( wav_hdr ), 1 , f ) < 1 ) {
  110.         cputs( "unable to read the headerrn");
  111.         return( 0 );
  112.     }
  113.     /* see if RIFF format */
  114.     if ( memcmp( wav->wav_riff , "RIFF", 4 ) != 0 ) {
  115.         cputs( "not RIFF formatrn");
  116.         return( 0 );
  117.     }
  118.     /* see if WAVE subformat */
  119.     if ( memcmp( wav->wav_wave, "WAVE", 4 ) != 0 ) {
  120.         cputs( "not WAVE subformatrn");
  121.         return( 0 );
  122.     }
  123.     return( 1 );
  124. }
  125. int read_chunk( FILE *f, chunk_str *ch )
  126. {
  127.     if ( fread( ch, sizeof( chunk_str), 1 , f ) < 1 ) {
  128.         cputs( "unable to read a chunkrn");
  129.         return( 0 );
  130.     }
  131.     return( 1 );
  132. }
  133. int read_fmt( FILE *f, fmt_str *fmt )
  134. {
  135.     if ( fread( fmt, sizeof( fmt_str), 1 , f ) < 1 ) {
  136.         cputs( "unable to read the fmt headerrn");
  137.         return( 0 );
  138.     }
  139.     if ( fmt->wFormatTag != 1 ) {
  140.         cputs( "not WAVE_FORMAT_PCM rn");
  141.         return( 0 );
  142.     }
  143.     return( 1 );
  144. }
  145. void interrupt_time_player( void )
  146. {
  147.     static int inside = 0;
  148.     BYTE prevval, b;
  149.     if ( inside == 0 ) {
  150.         inside = 1;
  151.         if ( soundposn < soundlength ) {
  152.             b = sounddata[ soundposn ];
  153.             if ( use_sb ) sb_code( b );
  154.             else {
  155.                 prevval = inportb( 0x61 );
  156.                 b = (prevval & 0xFC) | (( b > soundthreshhold) ? 2 : 0) ;
  157.                 if ( b != prevval )
  158.                     outportb( 0x61, b );
  159.             }
  160.             soundposn += soundskip;
  161.             if ( soundposn >= soundlength )
  162.             ksendmessage( kmainthread, 0, 0 );
  163.         }
  164.         inside = 0;
  165.     }
  166. }
  167. void audio_play( WORD channels, DWORD rate, BYTE *data, WORD length )
  168. {
  169.     int value;
  170.     DWORD tempdata;
  171.     soundposn = 0;
  172.     soundlength = length;
  173.     sounddata = data;
  174.     if ( rate > 10000 ) rate = 10000;   /* we are only accurate to 0.1 kHz */
  175.     soundskip = channels;
  176.     rt_timerfreq( rate );
  177.     /* invoke the player */
  178.     settimer( interrupt_time_player );
  179.     /* wait until it's done */
  180.     kreadmessage( &value, &tempdata );
  181.     /* remove the player */
  182.     settimer( NULL );
  183. }
  184. play( char *fname )
  185. {
  186.     FILE *f;
  187.     wav_hdr wav;
  188.     chunk_str chunk;
  189.     fmt_str fmt;
  190.     DWORD posn;
  191.     BYTE *data;
  192.     int samples_per_data;
  193.     if ( (f = fopen( fname, "rb")) == NULL ) {
  194.         cprintf( "unable to open WAV file %s", fname);
  195.         return;
  196.     }
  197.     if ( ! read_wav_hdr( f, &wav )) return;
  198.     do {
  199.         if ( ! read_chunk( f, &chunk ))
  200.             break;
  201.         posn = ftell( f );
  202.         if ( !memcmp(chunk.bID,"fmt ", 4 ))
  203.             if ( ! read_fmt( f, &fmt ))
  204.                 break;
  205.         if ( !memcmp(chunk.bID,"data", 4 )) {
  206.             data = kcalloc( 1, chunk.dwSize );
  207.             if ( data != NULL ) {
  208.                 fread( data, chunk.dwSize, 1 , f );
  209.         samples_per_data = fmt.wChannels * fmt.wBlockAlign;
  210.     cprintf("%u channels, %u align n",
  211.         fmt.wChannels, fmt.wBlockAlign);
  212.                 audio_play( samples_per_data , fmt.dwSamplesPerSec,
  213.                         data, chunk.dwSize );
  214.                 kfree( data );
  215.             }
  216.             break;
  217.         }
  218.         fseek( f, posn + chunk.dwSize , SEEK_SET);
  219.     } while ( 1 );
  220.     fclose( f );
  221.     return;
  222. }
  223. /*
  224.  * consolethread - just dumps stuff to console for visual effect
  225.  */
  226. void consolethread( DWORD data )
  227. {
  228.     int i = 0;
  229.     if ( data == 1 )
  230.         kwindow( 1, 1, 40, 15 );
  231.     else
  232.         kwindow( 40, 1, 80, 15 );
  233.     /* infinite loop */
  234.     do {
  235.         cprintf(" %u", i++ );
  236.     } while ( 1 );
  237. }
  238. int main( int argc, char **argv )
  239. {
  240.     int i;
  241.     kpreemptive = 1;
  242.     kdebug = 1;
  243.     rt_init( 100 );
  244.     clrscr();
  245.     kwindow( 1, 15, 80, 25 );
  246.     sb_init();
  247.     if ( argc < 2 ) {
  248.         cputs("WAVE [-sb] wavefile1.WAV ... rn");
  249.         cputs(" -sb means use SoundBlasterrn");
  250.         return;
  251.     }
  252.     /* create a few threads for visual threading effect */
  253.     rt_newthread( consolethread, 1, 4096, 0, "console thread #1" );
  254.     rt_newthread( consolethread, 2, 4096, 0, "console thread #2" );
  255.     for ( i = 1 ; i < argc ; ++i ) {
  256.         if ( !stricmp( argv[i], "-sb")) {
  257.             if (sb_base == 0 ) rt_halt("no SoundBlaster card, cannot use -sb option");
  258.             use_sb = 1;
  259.             cputs("Using SoundBlasterrn");
  260.             continue;
  261.         } else {
  262.             cprintf("playing : %s ...", argv[i] );
  263.             play( argv[i] );
  264.             cputs("donenr");
  265.         }
  266.         rt_sleep( 1000 );
  267.     }
  268.     return( 0 );
  269. }