home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3456 < prev    next >
Internet Message Format  |  1991-06-06  |  44KB

  1. From: brians@eecs.cs.pdx.edu (Brian Smith)
  2. Newsgroups: alt.sources
  3. Subject: Sound Blaster Unix Driver 2/2
  4. Message-ID: <2822@pdxgate.UUCP>
  5. Date: 6 Jun 91 17:22:05 GMT
  6.  
  7. #! /bin/sh
  8. # This is a shell archive, meaning:
  9. # 1. Remove everything above the #! /bin/sh line.
  10. # 2. Save the resulting text in a file.
  11. # 3. Execute the file with /bin/sh (not csh) to create:
  12. #    apps/Makefile
  13. #    apps/get_instr.1
  14. #    apps/get_instr.c
  15. #    apps/play_cleanup.1
  16. #    apps/play_cleanup.c
  17. #    apps/play_cmf.1
  18. #    apps/play_cmf.c
  19. #    apps/play_snd.1
  20. #    apps/play_snd.c
  21. #    apps/record_snd.1
  22. #    apps/record_snd.c
  23. #    apps/set_speed.1
  24. #    apps/set_speed.c
  25. #    apps/snd_norm.1
  26. #    apps/snd_norm.c
  27. #    apps/tst_fm_note.c
  28. #    apps/tst_fm_open.c
  29. #    apps/tst_instr.c
  30. # This archive created: Thu Jun  6 08:33:44 1991
  31. export PATH; PATH=/bin:/usr/bin:$PATH
  32. if test -f 'apps/Makefile'
  33. then
  34.     echo shar: "will not over-write existing file 'apps/Makefile'"
  35. else
  36. cat << \SHAR_EOF > 'apps/Makefile'
  37. #                 Programs using Sound Blaster(tm) Driver
  38. #                     (Copyright 1991, Brian Smith)
  39. #
  40.  
  41. SHELL=/bin/sh
  42. CC= gcc -fpcc-struct-return
  43. CFLAGS = # -O
  44. LIBS= -lc_s
  45.  
  46. PROGRAMS= play_snd set_speed play_cmf record_snd snd_norm
  47. TESTS= play_cleanup tst_fm_open tst_fm_note get_instr tst_instr
  48.  
  49. all: $(PROGRAMS) $(TESTS)
  50.  
  51. record_snd: record_snd.c /usr/include/sys/sb.h
  52.     $(CC) $(CFLAGS) -o record_snd record_snd.c $(LIBS)
  53.  
  54. play_snd: play_snd.c /usr/include/sys/sb.h
  55.     $(CC) $(CFLAGS) -o play_snd play_snd.c $(LIBS)
  56.  
  57. play_cleanup: play_cleanup.c /usr/include/sys/sb.h
  58.     $(CC) $(CFLAGS) -o play_cleanup play_cleanup.c $(LIBS)
  59.  
  60. get_instr: get_instr.c /usr/include/sys/sb.h
  61.     $(CC) $(CFLAGS) -o get_instr get_instr.c $(LIBS)
  62.  
  63. set_speed: set_speed.c /usr/include/sys/sb.h
  64.     $(CC) $(CFLAGS) -o set_speed set_speed.c $(LIBS)
  65.  
  66. tst_fm_open: tst_fm_open.c /usr/include/sys/sb.h
  67.     $(CC) $(CFLAGS) -o tst_fm_open tst_fm_open.c $(LIBS)
  68.  
  69. tst_fm_note: tst_fm_note.c /usr/include/sys/sb.h
  70.     $(CC) $(CFLAGS) -o tst_fm_note tst_fm_note.c $(LIBS)
  71.  
  72. play_cmf: play_cmf.c /usr/include/sys/sb.h
  73.     $(CC) $(CFLAGS) -o play_cmf play_cmf.c -linet $(LIBS)
  74.  
  75. tst_instr: tst_instr.c /usr/include/sys/sb.h
  76.     $(CC) $(CFLAGS) -o tst_instr tst_instr.c $(LIBS)
  77.  
  78. snd_norm: snd_norm.c
  79.     $(CC) $(CFLAGS) -o snd_norm snd_norm.c $(LIBS)
  80.  
  81. install: $(PROGRAMS)
  82.     for i in $(PROGRAMS); do \
  83.     mcs -d $$i ; \
  84.     strip $$i ; \
  85.     (echo $$i | cpio -pdlmv /usr/local/bin) ; \
  86.     done
  87.  
  88. clean:
  89.     /bin/rm -f $(PROGRAMS) $(TESTS)
  90. SHAR_EOF
  91. fi
  92. if test -f 'apps/get_instr.1'
  93. then
  94.     echo shar: "will not over-write existing file 'apps/get_instr.1'"
  95. else
  96. cat << \SHAR_EOF > 'apps/get_instr.1'
  97. .TH GET_INSTR 1 "3 June 1991"
  98. .UC 4
  99. .SH NAME
  100. get_instr \- decodes and prints instrument info from CMF files
  101. .SH SYNOPSIS
  102. .B get_instr
  103. [
  104. .I file
  105. ]
  106. .PP
  107. The argument must be the CMF file to be examined.
  108. .SH DESCRIPTION
  109. .B get_instr
  110. reads the portion of the CMF file detailing the instruments used, and
  111. then prints out the breakdown of that information.
  112. .SH AUTHOR
  113. .PP
  114. Brian Smith
  115. SHAR_EOF
  116. fi
  117. if test -f 'apps/get_instr.c'
  118. then
  119.     echo shar: "will not over-write existing file 'apps/get_instr.c'"
  120. else
  121. cat << \SHAR_EOF > 'apps/get_instr.c'
  122. /*
  123.  * Copyrighted as an unpublished work.
  124.  * (c) Copyright 1991 Brian Smith
  125.  * All rights reserved.
  126.  *
  127.  * Read the LICENSE file for details on distribution and use.
  128.  *
  129.  */
  130.  
  131. #include <sys/fcntl.h>
  132. #include <sys/unistd.h>
  133. #include <sys/sb.h>
  134. #include <stdio.h>
  135.  
  136. int main(argc, argv)
  137. int argc;
  138. char **argv;
  139. {
  140.     int cmf_fd;
  141.  
  142.     if (argc != 2)
  143.     {
  144.         printf("usage: %s <cmf file>\n", argv[0]);
  145.         exit(-1);
  146.     }
  147.  
  148.     /* open cmf file */
  149.     cmf_fd = open(argv[1], O_RDONLY);
  150.     if (cmf_fd == -1)
  151.     {
  152.         printf("usage: %s <cmf file>\n", argv[0]);
  153.         exit(-1);
  154.     }
  155.  
  156.     /* verify that file is a cmf file */
  157.     if (!verify_cmf(cmf_fd))
  158.     {
  159.         printf("file was not a cmf file\n");
  160.         printf("usage: %s <cmf file>\n", argv[0]);
  161.         exit(-1);
  162.     }
  163.  
  164.     /* print out info on instruments in cmf file */
  165.     print_instruments(cmf_fd);
  166.  
  167.     return(0);
  168. }
  169.  
  170.  
  171. /* check for "CTMF" in first four bytes of file */
  172. int verify_cmf(fd)
  173. int fd;
  174. {
  175.     char idbuf[5];
  176.  
  177.     /* get id */
  178.     lseek(fd, 0, SEEK_SET);
  179.     if (read(fd, idbuf, 4) != 4)
  180.         return(FALSE);
  181.     
  182.     /* compare to standard id */
  183.     idbuf[4] = (char)0;
  184.     if (strcmp(idbuf, "CTMF") != 0)
  185.         return(FALSE);
  186.     
  187.     return(TRUE);
  188. }
  189.  
  190. int print_instruments(fd)
  191. int fd;
  192. {
  193.     int offset;
  194.     int num_instruments;
  195.     int i;
  196.     int j;
  197.     unsigned char tmp_byte;
  198.     unsigned char instrument_buf[16];
  199.  
  200. #define lobyte(X)   (((unsigned char *)&X)[0])
  201. #define hibyte(X)   (((unsigned char *)&X)[1])
  202.  
  203.     /* get offset of instrument block */
  204.     offset = 0;
  205.     lseek(fd, 0x06, SEEK_SET);
  206.     read(fd, &tmp_byte, 1);
  207.     lobyte(offset) = tmp_byte;
  208.     read(fd, &tmp_byte, 1);
  209.     hibyte(offset) = tmp_byte;
  210.  
  211.     /* get number of instruments */
  212.     num_instruments = 0;
  213.     lseek(fd, 0x24, SEEK_SET);
  214.     read(fd, &tmp_byte, 1);
  215.     lobyte(num_instruments) = tmp_byte;
  216.     read(fd, &tmp_byte, 1);
  217.     hibyte(num_instruments) = tmp_byte;
  218.  
  219.     /* read each instrument */
  220.     lseek(fd, offset, SEEK_SET);
  221.     for (i=0; i< num_instruments; i++)
  222.     {
  223.         read(fd, instrument_buf, 16);
  224.         printf("instrument: 0x%02x\n", i);
  225.  
  226.         for (j=0; j<16; j++)
  227.             printf("0x%02x ", (unsigned int)instrument_buf[j]);
  228.         printf("\n");
  229.  
  230.         /* byte 0 */
  231.         printf("\tModulator: 0x%02x\n", (unsigned int)instrument_buf[0]);
  232.  
  233.         /* byte 1 */
  234.         printf("\tCarrier Sound Characteristic\n");
  235.         if (instrument_buf[1] & (1<<7))
  236.             printf("\tPitch Vibrato: On\n");
  237.         else
  238.             printf("\tPitch Vibrato: Off\n");
  239.         if (instrument_buf[1] & (1<<6))
  240.             printf("\tAmplitude Vibrato: On\n");
  241.         else
  242.             printf("\tAmplitude Vibrato: Off\n");
  243.         if (instrument_buf[1] & (1<<5))
  244.             printf("\tSustaining Sound: On\n");
  245.         else
  246.             printf("\tSustaining Sound: Off\n");
  247.         if (instrument_buf[1] & (1<<4))
  248.             printf("\tEnvelope Scaling: On\n");
  249.         else
  250.             printf("\tEnvelope Scaling: Off\n");
  251.         printf("\tFrequency Multiplier: 0x%02x\n", instrument_buf[1] & 0x0F);
  252.  
  253.         /* byte 2 */
  254.         printf("\tModulator Level Scaling: 0x%02x\n", instrument_buf[2] >> 4);
  255.         printf("\tModulator Output Level: 0x%02x\n", instrument_buf[2] & 0x3f);
  256.  
  257.         /* byte 3 */
  258.         printf("\tCarrier Level Scaling: 0x%02x\n", instrument_buf[3] >> 4);
  259.         printf("\tCarrier Output Level: 0x%02x\n", instrument_buf[3] & 0x3f);
  260.  
  261.         /* byte 4 */
  262.         printf("\tModulator Attack Rate 0x%02x\n", instrument_buf[5] >> 4);
  263.         printf("\tModulator Decay Rate 0x%02x\n", instrument_buf[5] & 0xF);
  264.  
  265.         /* byte 5 */
  266.         printf("\tCarrier Attack Rate 0x%02x\n", instrument_buf[5] >> 4);
  267.         printf("\tCarrier Decay Rate 0x%02x\n", instrument_buf[5] & 0xF);
  268.  
  269.         /* byte 6 */
  270.         printf("\tModulator Sustain Level 0x%02x\n", instrument_buf[6] >> 4);
  271.         printf("\tModulator Release Level 0x%02x\n", instrument_buf[6] >> 4);
  272.  
  273.         /* byte 7 */
  274.         printf("\tCarrier Sustain Level 0x%02x\n", instrument_buf[7] >> 4);
  275.         printf("\tCarrier Release Level 0x%02x\n", instrument_buf[7] >> 4);
  276.  
  277.         /* byte 8 */
  278.         printf("\tModulator Wave Select 0x%02x\n", instrument_buf[8] & 0x03);
  279.  
  280.         /* byte 9 */
  281.         printf("\tCarrier Wave Select 0x%02x\n", instrument_buf[9] & 0x03);
  282.  
  283.         /* byte A */
  284.         printf("\tModulator FeedBack 0x%02x\n",
  285.             (instrument_buf[0xA] >> 1) & 0x07);
  286.     }
  287.  
  288.     return(0);
  289. }
  290. SHAR_EOF
  291. fi
  292. if test -f 'apps/play_cleanup.1'
  293. then
  294.     echo shar: "will not over-write existing file 'apps/play_cleanup.1'"
  295. else
  296. cat << \SHAR_EOF > 'apps/play_cleanup.1'
  297. .TH PLAY_CLEANUP 1 "3 June 1991"
  298. .UC 4
  299. .SH NAME
  300. play_cleanup \- Cleans up after a very abnormal exit from play_snd
  301. .SH SYNOPSIS
  302. .B play_cleanup
  303. .PP
  304. No arguments are necessary.
  305. .SH DESCRIPTION
  306. If play_snd exits without destroying the shared memory segment,
  307. further invocations will fail until the segment is destroyed.  This
  308. program destroys that memory segment.  This should not be needed,
  309. because play_snd cleans up after getting eof and SIGINT.  It cannot,
  310. however, catch SIGKILL.
  311. .B play_cleanup
  312. .SH AUTHOR
  313. .PP
  314. Brian Smith
  315. SHAR_EOF
  316. fi
  317. if test -f 'apps/play_cleanup.c'
  318. then
  319.     echo shar: "will not over-write existing file 'apps/play_cleanup.c'"
  320. else
  321. cat << \SHAR_EOF > 'apps/play_cleanup.c'
  322. /*
  323.  * Copyrighted as an unpublished work.
  324.  * (c) Copyright 1991 Brian Smith
  325.  * All rights reserved.
  326.  *
  327.  * Read the LICENSE file for details on distribution and use.
  328.  *
  329.  */
  330.  
  331. #include <sys/types.h>
  332. #include <sys/ipc.h>
  333. #include <sys/shm.h>
  334.  
  335. #define NUMBUFS     2
  336. #define SHM_BUFSIZ  (8*4096)
  337. #define SHM_KEY     1796
  338.  
  339. typedef struct {
  340.     int     not_last_segment[NUMBUFS];
  341.     int     unlocked[NUMBUFS];
  342.     char    buf[NUMBUFS*SHM_BUFSIZ];
  343. }   buf_struct;
  344.  
  345.  
  346. main()
  347. {
  348.     int rc;
  349.     int shmid;
  350.  
  351.     shmid = shmget(SHM_KEY, sizeof(buf_struct), IPC_CREAT | 0644);
  352.     if (shmid == -1)
  353.     {
  354.         perror("creating shared-mem buffer");
  355.         exit(-1);
  356.     }
  357.  
  358.     rc = shmctl(shmid, IPC_RMID, 0);
  359.     if (rc == -1)
  360.         perror("removing segment");
  361.  
  362.     exit(0);
  363. }
  364. SHAR_EOF
  365. fi
  366. if test -f 'apps/play_cmf.1'
  367. then
  368.     echo shar: "will not over-write existing file 'apps/play_cmf.1'"
  369. else
  370. cat << \SHAR_EOF > 'apps/play_cmf.1'
  371. .TH PLAY_CMF 1 "3 June 1991"
  372. .UC 4
  373. .SH NAME
  374. play_cmf \- decodes and plays a CMF music file.
  375. .SH SYNOPSIS
  376. .B play_cmf
  377. [
  378. .I file
  379. ]
  380. .PP
  381. The argument must be the CMF file to be played.
  382. .SH DESCRIPTION
  383. .B play_cmf
  384. Attempts to play a CMF file.
  385. .SH BUGS
  386. Many CMF files attempt to use Control Change events not understood by the
  387. author.  Therefore, the program does not implement whatever these
  388. control changes are supposed to do.
  389. .SH AUTHOR
  390. .PP
  391. Brian Smith
  392. SHAR_EOF
  393. fi
  394. if test -f 'apps/play_cmf.c'
  395. then
  396.     echo shar: "will not over-write existing file 'apps/play_cmf.c'"
  397. else
  398. cat << \SHAR_EOF > 'apps/play_cmf.c'
  399. /*
  400.  * Copyrighted as an unpublished work.
  401.  * (c) Copyright 1991 Brian Smith
  402.  * All rights reserved.
  403.  *
  404.  * Read the LICENSE file for details on distribution and use.
  405.  *
  406.  */
  407.  
  408. #include <sys/fcntl.h>
  409. #include <sys/unistd.h>
  410. #include <sys/sb.h>
  411. #include <sys/time.h>
  412. #include <stdio.h>
  413.  
  414. #define lobyte(X)   (((unsigned char *)&X)[0])
  415. #define hibyte(X)   (((unsigned char *)&X)[1])
  416.  
  417. /* Globals */
  418. int fm_herz;        /* clock ticks per second */
  419. int tempo;          /* clock ticks per quarter note */
  420. int fm_fd;
  421. int note_on[16];
  422. char **instrument_table;
  423. int note_table[12] = {
  424.     343,
  425.     363,
  426.     385,
  427.     408,
  428.     432,
  429.     458,
  430.     485,
  431.     514,
  432.     544,
  433.     577,
  434.     611,
  435.     647
  436.     };
  437.  
  438.  
  439. int main(argc, argv)
  440. int argc;
  441. char **argv;
  442. {
  443.     int cmf_fd;
  444.  
  445.     if (argc != 2)
  446.     {
  447.         printf("usage: %s <cmf file>\n", argv[0]);
  448.         exit(-1);
  449.     }
  450.  
  451.     /* open cmf file */
  452.     cmf_fd = open(argv[1], O_RDONLY);
  453.     if (cmf_fd == -1)
  454.     {
  455.         printf("usage: %s <cmf file>\n", argv[0]);
  456.         exit(-1);
  457.     }
  458.  
  459.     /* verify that file is a cmf file */
  460.     if (!verify_cmf(cmf_fd))
  461.     {
  462.         printf("file was not a cmf file\n");
  463.         printf("usage: %s <cmf file>\n", argv[0]);
  464.         exit(-1);
  465.     }
  466.  
  467.     /* read and set instruments from cmf file */
  468.     get_instruments(cmf_fd);
  469.  
  470.     /* get timing */
  471.     set_timing(cmf_fd);
  472.  
  473.     /* open soundblaster fm chips */
  474.     fm_fd = open("/dev/sbfm", O_WRONLY);
  475.     if (fm_fd == -1)
  476.     {
  477.         perror("opening fm chips");
  478.         exit(-1);
  479.     }
  480.  
  481.     /* play song */
  482.     play_song(cmf_fd);
  483.  
  484.     return(0);
  485. }
  486.  
  487.  
  488. /* check for "CTMF" in first four bytes of file */
  489. int verify_cmf(fd)
  490. int fd;
  491. {
  492.     char idbuf[5];
  493.  
  494.     /* get id */
  495.     lseek(fd, 0, SEEK_SET);
  496.     if (read(fd, idbuf, 4) != 4)
  497.         return(FALSE);
  498.     
  499.     /* compare to standard id */
  500.     idbuf[4] = (char)0;
  501.     if (strcmp(idbuf, "CTMF") != 0)
  502.         return(FALSE);
  503.     
  504.     return(TRUE);
  505. }
  506.  
  507. int get_instruments(fd)
  508. int fd;
  509. {
  510.     int offset;
  511.     int num_instruments;
  512.     int i;
  513.     int rc;
  514.     int fnum, block, note;
  515.     unsigned char tmp_byte;
  516.     sb_fm_character note_character;
  517.  
  518.     /* get offset of instrument block */
  519.     offset = 0;
  520.     lseek(fd, 0x06, SEEK_SET);
  521.     read(fd, &tmp_byte, 1);
  522.     lobyte(offset) = tmp_byte;
  523.     read(fd, &tmp_byte, 1);
  524.     hibyte(offset) = tmp_byte;
  525.  
  526.     /* get number of instruments */
  527.     num_instruments = 0;
  528.     lseek(fd, 0x24, SEEK_SET);
  529.     read(fd, &tmp_byte, 1);
  530.     lobyte(num_instruments) = tmp_byte;
  531.     read(fd, &tmp_byte, 1);
  532.     hibyte(num_instruments) = tmp_byte;
  533.  
  534.     /* allocate space */
  535.     instrument_table = (char **)malloc(sizeof(int *) * num_instruments);
  536.  
  537.     /* read each instrument */
  538.     lseek(fd, offset, SEEK_SET);
  539.     for (i=0; i< num_instruments; i++)
  540.     {
  541.         /* allocate space */
  542.         instrument_table[i] = (char *)malloc(16);
  543.  
  544.         /* set instrument characteristics */
  545.         read(fd, instrument_table[i], 16);
  546.     }
  547.  
  548.     return(0);
  549. }
  550.  
  551.  
  552. /*
  553.  * get and set timing parameters
  554.  */
  555. int set_timing(fd)
  556. int fd;
  557. {
  558.     unsigned char tmp_byte;
  559.  
  560.     /* get tempo */
  561.     tempo = 0;
  562.     lseek(fd, 0x0C, SEEK_SET);
  563.     read(fd, &tmp_byte, 1);
  564.     tempo = (unsigned int)tmp_byte;
  565.     read(fd, &tmp_byte, 1);
  566.     tempo += (unsigned int)tmp_byte << 8;
  567.  
  568.     /* get herz of timing clock */
  569.     fm_herz = 0;
  570.     lseek(fd, 0x0C, SEEK_SET);
  571.     read(fd, &tmp_byte, 1);
  572.     fm_herz = (unsigned int)tmp_byte;
  573.     read(fd, &tmp_byte, 1);
  574.     fm_herz += (unsigned int)tmp_byte << 8;
  575.     
  576.     return(0);
  577. }
  578.  
  579.  
  580. /*
  581.  * seek to the midi stream and handle midi events for the song
  582.  */
  583. int play_song(fd)
  584. int fd;
  585. {
  586.     int offset;
  587.     unsigned char tmp_byte;
  588.     int delta;
  589.  
  590.     /* get offset of music stream */
  591.     lseek(fd, 8, SEEK_SET);
  592.     read(fd, &tmp_byte, 1);
  593.     offset = (unsigned int)tmp_byte;
  594.     read(fd, &tmp_byte, 1);
  595.     offset += (unsigned int)tmp_byte << 8;
  596.     lseek(fd, offset, SEEK_SET);
  597.  
  598.     /* process till EOF */
  599.     while(1)
  600.     {
  601.         /* get delta time */
  602.         delta = ReadVarLen(fd);
  603.         if (delta == -1)
  604.             break;
  605.  
  606.         /* wait delta */
  607.         if (delta > 0)
  608.             high_res_sleep((double)delta/(double)fm_herz);
  609.  
  610.         /* process midi event */
  611.         process_event(fd, delta);
  612.     }
  613.  
  614.  
  615.     return(0);
  616. }
  617.  
  618.  
  619. /*
  620.  * read a variable length scalar in MIDI format
  621.  */
  622. int ReadVarLen(fd)
  623. int fd;
  624. {
  625.     int value;
  626.     unsigned char tmp_byte;
  627.  
  628.     if (read(fd, &tmp_byte, 1) == 0)
  629.         return(-1);
  630.     value = (int)tmp_byte;
  631.     if (tmp_byte & 0x80)
  632.     {
  633.         value &= 0x7F;
  634.         do
  635.         {
  636.             if (read(fd, &tmp_byte, 1) == 0)
  637.                 return(-1);
  638.             value = (value << 7) + (tmp_byte & 0x7F);
  639.         } while (tmp_byte & 0x80);
  640.     }
  641.  
  642.     return(value);
  643. }
  644.  
  645.  
  646. /*
  647.  * process a midi event
  648.  */
  649. int process_event(fd, delta)
  650. int fd;
  651. {
  652.     int rc;
  653.     unsigned char tmp_byte;
  654.     static int status = -1;
  655.     sb_fm_note note;
  656.  
  657.     /* get status byte */
  658.     read(fd, &tmp_byte, 1);
  659.     if (tmp_byte & 0x80)
  660.     {
  661.         status = (unsigned int)tmp_byte;
  662.     }
  663.     else
  664.     {
  665.         /* running status, so back up one */
  666.         if (status == -1)
  667.         {
  668.             printf("ERROR in cmf file. Running status at beginning of file\n");
  669.             exit(-1);
  670.         }
  671.         lseek(fd, -1, SEEK_CUR);
  672.     }
  673.     
  674.     /* switch different events */
  675.     switch (status & 0xF0)
  676.     {
  677.         case 0x80:
  678.             /* turn note off */
  679.             ioctl(fm_fd, FM_IOCTL_NOTE_OFF, status & 0x0F);
  680.             note_on[status&0x0F] = 0;
  681.             /* waste two bytes */
  682.             read(fd, &tmp_byte, 1);
  683.             read(fd, &tmp_byte, 1);
  684.             break;
  685.         case 0x90:
  686.             /* get note */
  687.             read(fd, &tmp_byte, 1);
  688.             /* determine note */
  689.             note_num(note) = status & 0x0F;
  690.             fnum_low(note) = note_table[tmp_byte%12] & 0xFF;
  691.             fnum_low(note) = note_table[tmp_byte%12] & 0xFF;
  692.             keyon_blk_fnum(note) = 0;
  693.             keyon_blk_fnum(note) |= 1<<5;
  694.             keyon_blk_fnum(note) |= ((tmp_byte/12) & 7) << 2;
  695.             keyon_blk_fnum(note) |= (note_table[tmp_byte%12] & 0x3FF) >> 8;
  696.  
  697.             /* turn note on */
  698.             if (note_on[status&0x0F])
  699.                 ioctl(fm_fd, FM_IOCTL_NOTE_OFF, status&0x0F);
  700.             ioctl(fm_fd, FM_IOCTL_NOTE_ON, note);
  701.             note_on[status&0x0F] = 1;
  702.  
  703.             /* waste a bytes */
  704.             read(fd, &tmp_byte, 1);
  705.             break;
  706.         case 0xA0:
  707.             printf("polyphonic key pressure: not handled\n");
  708.             /* waste two bytes */
  709.             read(fd, &tmp_byte, 1);
  710.             read(fd, &tmp_byte, 1);
  711.             break;
  712.         case 0xB0:
  713.             printf("control change: not handled\n");
  714.             /* waste two bytes */
  715.             read(fd, &tmp_byte, 1);
  716.             read(fd, &tmp_byte, 1);
  717.             break;
  718.         case 0xC0:
  719.             /* change the instrument on a channel */
  720.             read(fd, &tmp_byte, 1);
  721.             load_instrument(status&0x0F, tmp_byte & 0x0F);
  722.             break;
  723.         case 0xD0:
  724.             printf("Channel Pressure: not handled\n");
  725.             /* waste a byte */
  726.             read(fd, &tmp_byte, 1);
  727.             break;
  728.         case 0xE0:
  729.             printf("Pitch Wheel Change: not handled\n");
  730.             /* waste two bytes */
  731.             read(fd, &tmp_byte, 1);
  732.             read(fd, &tmp_byte, 1);
  733.             break;
  734.         case 0xF0:
  735.             printf("System Exclusive: not handled\n");
  736.             /* waste two bytes */
  737.             read(fd, &tmp_byte, 1);
  738.             read(fd, &tmp_byte, 1);
  739.             break;
  740.         default:
  741.             printf("internal program error\n");
  742.             /* waste two bytes */
  743.             read(fd, &tmp_byte, 1);
  744.             read(fd, &tmp_byte, 1);
  745.             break;
  746.     }
  747.  
  748.  
  749.     return(0);
  750. }
  751.  
  752.  
  753. /*
  754.  * load an instrument from the instrument table into the SoundBlaster
  755.  */
  756. int load_instrument(channel, instrument)
  757. {
  758.     int rc;
  759.     sb_fm_character note_character;
  760.  
  761.     /* error check! */
  762.     if ((channel <0) || (channel >= 9))
  763.         return;
  764.  
  765.     /* abort instrument if being loaded */
  766.     if (note_on[channel])
  767.         ioctl(fm_fd, FM_IOCTL_NOTE_OFF, channel);
  768.  
  769.     /* set instrument characteristics */
  770.     note_character.voice_num = channel;
  771.     memcpy(note_character.data, instrument_table[instrument], 16);
  772.     rc = ioctl(fm_fd, FM_IOCTL_SET_VOICE, (int)¬e_character);
  773.     if (rc == -1)
  774.     {
  775.         perror("fm chips voice set");
  776.         exit(-1);
  777.     }
  778.  
  779.     return(0);
  780. }
  781.  
  782.  
  783. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  784. Higher-resolution sleep
  785. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  786. int high_res_sleep(seconds)
  787.     double      seconds;
  788. {
  789.     int         fds = 0;
  790.     struct timeval timeout;
  791.  
  792.     timeout.tv_sec = seconds;
  793.     timeout.tv_usec = (seconds - timeout.tv_sec) * 1000000.0;
  794.     select(0, &fds, &fds, &fds, &timeout);
  795. }
  796.  
  797. SHAR_EOF
  798. fi
  799. if test -f 'apps/play_snd.1'
  800. then
  801.     echo shar: "will not over-write existing file 'apps/play_snd.1'"
  802. else
  803. cat << \SHAR_EOF > 'apps/play_snd.1'
  804. .TH PLAY_SND 1 "3 June 1991"
  805. .UC 4
  806. .SH NAME
  807. play_snd \- plays a raw 8-bit sound file
  808. .SH SYNOPSIS
  809. .B play_snd
  810. [
  811. .I file
  812. ]
  813. .PP
  814. The argument must be the sound file to be played.
  815. .SH DESCRIPTION
  816. .B play_snd
  817. Plays raw 8-bit sound files, using shared memory and two processes
  818. to double buffer reads and writes.  Feel free to use SIGINT (usually
  819. control-C) to interrupt the play.  Do NOT, however, use SIGKILL or any
  820. other signal to terminate the program.  This leaves unwanted
  821. left-overs, in the form of a shared memory segment.  Use play_cleanup
  822. if this happens accidentally.
  823.  
  824. Use set_speed to change the playing rate of the samples.
  825. .SH AUTHOR
  826. .PP
  827. Brian Smith
  828. SHAR_EOF
  829. fi
  830. if test -f 'apps/play_snd.c'
  831. then
  832.     echo shar: "will not over-write existing file 'apps/play_snd.c'"
  833. else
  834. cat << \SHAR_EOF > 'apps/play_snd.c'
  835. /*
  836.  * Copyrighted as an unpublished work.
  837.  * (c) Copyright 1991 Brian Smith
  838.  * All rights reserved.
  839.  *
  840.  * Read the LICENSE file for details on distribution and use.
  841.  *
  842.  */
  843.  
  844. #include <sys/fcntl.h>
  845. #include <sys/types.h>
  846. #include <sys/ipc.h>
  847. #include <sys/shm.h>
  848. #include <sys/sb.h>
  849. #include <signal.h>
  850. #include <errno.h>
  851. #include <stdio.h>
  852.  
  853. #define NUMBUFS     4
  854. #define SHM_BUFSIZ  (8*4096)
  855. #define SHM_KEY     1796
  856.  
  857. typedef struct {
  858.     char    buf[NUMBUFS*SHM_BUFSIZ];
  859.     int     write_waiting;
  860.     int     read_waiting;
  861.     int     locked[NUMBUFS];
  862.     int     length[NUMBUFS];
  863. }   buf_struct;
  864.  
  865.  
  866. /* GLOBALS */
  867. int shmid;
  868. buf_struct *buffers;
  869. int sound_fd;
  870.  
  871. void sigusr_handler()
  872. {
  873.     return;
  874. }
  875.  
  876.  
  877. void cleanup()
  878. {
  879.     shmctl(shmid, IPC_RMID, 0);
  880.     exit(0);
  881. }
  882.  
  883. void detach()
  884. {
  885.     shmdt(buffers);
  886.     exit(0);
  887. }
  888.  
  889.  
  890. int main(argc, argv)
  891. int argc;
  892. char **argv;
  893. {
  894.     int infile;
  895.     int child_pid;
  896.     int buf_num;
  897.     int rc;
  898.  
  899.     if (argc != 2)
  900.     {
  901.         printf("usage: %s <sound file>\n", argv[0]);
  902.         printf("\tif <sound file> is \"-\", then %s will play from stdin\n",
  903.             argv[0]);
  904.         exit(-1);
  905.     }
  906.  
  907.     if (strcmp(argv[1], "-") == 0)
  908.         infile = 0;
  909.     else
  910.     {
  911.         infile = open(argv[1], O_RDONLY);
  912.         if (infile == -1)
  913.         {
  914.             perror("opening data file");
  915.             printf("usage: %s <sound file>\n", argv[0]);
  916.             printf("\tif <sound file> is \"-\", then %s will play from stdin\n",
  917.                 argv[0]);
  918.             exit(-1);
  919.         }
  920.     }
  921.  
  922.     /* open device */
  923.     sound_fd = open("/dev/sbdsp", O_WRONLY);
  924.     if (sound_fd == -1)
  925.     {
  926.         perror("opening SoundBlaster device");
  927.         exit(-1);
  928.     }
  929.  
  930.     /* create shared memory segment */
  931.     shmid = shmget(SHM_KEY, sizeof(buf_struct), IPC_CREAT | IPC_EXCL | 0644);
  932.     if (shmid == -1)
  933.     {
  934.         perror("creating shared-mem buffer");
  935.         exit(-1);
  936.     }
  937.  
  938.     /* attach handler for signal */
  939.     sigset(SIGUSR1, sigusr_handler);
  940.     sigset(SIGINT, cleanup);
  941.     sigset(SIGHUP, cleanup);
  942.  
  943.     /* start read process */
  944.     child_pid = fork();
  945.     switch (child_pid)
  946.     {
  947.         case 0:
  948.             start_read(infile);
  949.             exit(0);
  950.         case -1:
  951.             perror("forking reader process");
  952.             cleanup();
  953.     }
  954.  
  955.     /* attach shared memory segment */
  956.     buffers = (buf_struct *)shmat(shmid, 0, 0);
  957.     if (buffers == (buf_struct *)-1)
  958.     {
  959.         perror("attaching shared memory");
  960.         if (buffers->read_waiting)
  961.             kill(child_pid, SIGKILL);
  962.         cleanup();
  963.     }
  964.  
  965.     /* start writing stuff in buffers */
  966.     while(1)
  967.     {
  968.         /* wait until buffer is locked for us, or flush and break on eof */
  969.         if (!buffers->locked[buf_num])
  970.         {
  971.             buffers->write_waiting = 1;
  972.             sigpause(SIGUSR1);
  973.             continue;
  974.         }
  975.  
  976.         /* not waiting now */
  977.         buffers->write_waiting = 0;
  978.  
  979.         /* eof check */
  980.         if (buffers->length[buf_num] <= 0)
  981.             break;
  982.  
  983.         /* write out data in buffer */
  984.         rc = write(sound_fd, buffers->buf + (buf_num*SHM_BUFSIZ),
  985.             buffers->length[buf_num]);
  986.         if (rc != buffers->length[buf_num])
  987.         {
  988.             if ((errno == EINTR) || (errno == 0))
  989.                 continue;
  990.  
  991.             perror("writing to sound blaster");
  992.             kill(child_pid, SIGKILL);
  993.             cleanup();
  994.         }
  995.  
  996.         /* unlock buffer for child's use */
  997.         buffers->locked[buf_num] = 0;
  998.         if (buffers->read_waiting)
  999.             kill(child_pid, SIGUSR1);
  1000.  
  1001.         /* go to next buffer */
  1002.         buf_num++;
  1003.         buf_num %= NUMBUFS;
  1004.     }
  1005.  
  1006.  
  1007.     cleanup();
  1008.     return(0);
  1009. }
  1010.  
  1011. int start_read(infile)
  1012. int infile;
  1013. {
  1014.     buf_struct *buffers;
  1015.     int buf_num = 0;
  1016.  
  1017.     /* attach handler for signal */
  1018.     sigset(SIGUSR1, sigusr_handler);
  1019.     sigset(SIGINT, detach);
  1020.     sigset(SIGHUP, detach);
  1021.  
  1022.     /* attach shared memory */
  1023.     buffers = (buf_struct *)shmat(shmid, 0, 0);
  1024.     if (buffers == (buf_struct *)-1)
  1025.     {
  1026.         perror("attaching shared memory");
  1027.         exit(0);
  1028.     }
  1029.  
  1030.     /* init shared mem stuff */
  1031.     buffers->read_waiting = 0;
  1032.     for (buf_num=0; buf_num < NUMBUFS; buf_num++)
  1033.         buffers->locked[buf_num] = 0;
  1034.  
  1035.     /* start reading into buffers */
  1036.     buf_num = 0;
  1037.     sleep(1);
  1038.     while(1)
  1039.     {
  1040.         /* wait for current buffer to become unlocked */
  1041.         if (buffers->locked[buf_num])
  1042.         {
  1043.             buffers->read_waiting = 1;
  1044.             sigpause(SIGUSR1);
  1045.             continue;
  1046.         }
  1047.  
  1048.         /* not waiting any more */
  1049.         buffers->read_waiting = 0;
  1050.  
  1051.         /* actually read data */
  1052.         buffers->length[buf_num] =
  1053.             read(infile, buffers->buf + (buf_num*SHM_BUFSIZ), SHM_BUFSIZ);
  1054.         if (buffers->length[buf_num] == -1) 
  1055.         {
  1056.             if (errno == EINTR)
  1057.                 continue;
  1058.             else
  1059.             {
  1060.                 perror("reading from input file\n");
  1061.                 detach();
  1062.             }
  1063.         }
  1064.         else if (buffers->length[buf_num] == 0)
  1065.         {
  1066.             buffers->locked[buf_num] = 1;
  1067.  
  1068.             /* wake up parent */
  1069.             if (buffers->write_waiting)
  1070.                 kill(getppid(), SIGUSR1);
  1071.  
  1072.             break;
  1073.         }
  1074.  
  1075.         /* lock buffer for parent's use */
  1076.         buffers->locked[buf_num] = 1;
  1077.                 
  1078.         /* wake up parent */
  1079.         if (buffers->write_waiting)
  1080.             kill(getppid(), SIGUSR1);
  1081.  
  1082.         /* go to next buffer */
  1083.         buf_num++;
  1084.         buf_num %= NUMBUFS;
  1085.     }
  1086.         
  1087.  
  1088.     /* wake up parent */
  1089.     if (buffers->write_waiting)
  1090.         kill(getppid(), SIGUSR1);
  1091.  
  1092.     /* detach shared memory */
  1093.     shmdt(buffers);
  1094.  
  1095.     return(0);
  1096. }
  1097. SHAR_EOF
  1098. fi
  1099. if test -f 'apps/record_snd.1'
  1100. then
  1101.     echo shar: "will not over-write existing file 'apps/record_snd.1'"
  1102. else
  1103. cat << \SHAR_EOF > 'apps/record_snd.1'
  1104. .TH RECORD_SND 1 "3 June 1991"
  1105. .UC 4
  1106. .SH NAME
  1107. record_snd \- records a raw 8-bit sound file
  1108. .SH SYNOPSIS
  1109. .B record_snd
  1110. [
  1111. .I file
  1112. ]
  1113. .PP
  1114. The argument must be the sound file to contain the recording.
  1115. .SH DESCRIPTION
  1116. .B record_snd
  1117. Records raw 8-bit sound files, using shared memory and two processes
  1118. to double buffer reads and writes.  Use SIGINT (usually control-C) to
  1119. stop the recording.  Do NOT, however, use SIGKILL or any other signal
  1120. to terminate the program.  This leaves unwanted left-overs, in the
  1121. form of a shared memory segment.  Use play_cleanup if this happens
  1122. accidentally.
  1123.  
  1124. Use set_speed to change the recording rate of the samples.
  1125. .SH AUTHOR
  1126. .PP
  1127. Brian Smith
  1128. SHAR_EOF
  1129. fi
  1130. if test -f 'apps/record_snd.c'
  1131. then
  1132.     echo shar: "will not over-write existing file 'apps/record_snd.c'"
  1133. else
  1134. cat << \SHAR_EOF > 'apps/record_snd.c'
  1135. /*
  1136.  * Copyrighted as an unpublished work.
  1137.  * (c) Copyright 1991 Brian Smith
  1138.  * All rights reserved.
  1139.  *
  1140.  * Read the LICENSE file for details on distribution and use.
  1141.  *
  1142.  */
  1143.  
  1144. #include <sys/fcntl.h>
  1145. #include <sys/types.h>
  1146. #include <sys/ipc.h>
  1147. #include <sys/shm.h>
  1148. #include <sys/sb.h>
  1149. #include <signal.h>
  1150. #include <errno.h>
  1151. #include <stdio.h>
  1152.  
  1153. #define NUMBUFS     4
  1154. #define SHM_BUFSIZ  (8*4096)
  1155. #define SHM_KEY     1796
  1156.  
  1157. typedef struct {
  1158.     char    buf[NUMBUFS*SHM_BUFSIZ];
  1159.     int     write_waiting;
  1160.     int     read_waiting;
  1161.     int     locked[NUMBUFS];
  1162.     int     length[NUMBUFS];
  1163. }   buf_struct;
  1164.  
  1165.  
  1166. /* GLOBALS */
  1167. int shmid;
  1168. buf_struct *buffers;
  1169.  
  1170. void sigusr_handler()
  1171. {
  1172.     return;
  1173. }
  1174.  
  1175.  
  1176. void cleanup()
  1177. {
  1178.     printf("cleanup\n");
  1179.     shmctl(shmid, IPC_RMID, 0);
  1180.     exit(0);
  1181. }
  1182.  
  1183. void detach()
  1184. {
  1185.     printf("detaching\n");
  1186.     shmdt(buffers);
  1187.     exit(0);
  1188. }
  1189.  
  1190.  
  1191. int main(argc, argv)
  1192. int argc;
  1193. char **argv;
  1194. {
  1195.     int outfile;
  1196.     int sound_fd;
  1197.     int child_pid;
  1198.     int buf_num;
  1199.     int rc;
  1200.  
  1201.     if (argc != 2)
  1202.     {
  1203.         printf("usage: %s <new sound file>\n", argv[0]);
  1204.         printf("\tif <sound file> is \"-\", then %s will record to stdout\n",
  1205.             argv[0]);
  1206.         exit(-1);
  1207.     }
  1208.  
  1209.     if (strcmp(argv[1], "-") == 0)
  1210.         outfile = 1;
  1211.     else
  1212.     {
  1213.         outfile = open(argv[1], O_WRONLY | O_CREAT, 0666);
  1214.         if (outfile == -1)
  1215.         {
  1216.             perror("opening output file");
  1217.             printf("usage: %s <output sound file>\n", argv[0]);
  1218.             printf("\tif <sound file> is \"-\", %s will record to stdout\n",
  1219.                 argv[0]);
  1220.             exit(-1);
  1221.         }
  1222.     }
  1223.  
  1224.     /* open device */
  1225.     sound_fd = open("/dev/sbdsp", O_RDONLY);
  1226.     if (sound_fd == -1)
  1227.     {
  1228.         perror("opening SoundBlaster device");
  1229.         exit(-1);
  1230.     }
  1231.     if (ioctl(sound_fd, DSP_IOCTL_RESET) == -1)
  1232.     {
  1233.         perror("trying to reset DSP");
  1234.         exit(-1);
  1235.     }
  1236.     if (ioctl(sound_fd, DSP_IOCTL_VOICE, 0) == -1)
  1237.     {
  1238.         perror("trying to set voice on");
  1239.         exit(-1);
  1240.     }
  1241.  
  1242.     /* create shared memory segment */
  1243.     shmid = shmget(SHM_KEY, sizeof(buf_struct), IPC_CREAT | IPC_EXCL | 0644);
  1244.     if (shmid == -1)
  1245.     {
  1246.         perror("creating shared-mem buffer");
  1247.         exit(-1);
  1248.     }
  1249.  
  1250.     /* attach handler for signal */
  1251.     sigset(SIGUSR1, sigusr_handler);
  1252.     sigset(SIGINT, cleanup);
  1253.     sigset(SIGHUP, cleanup);
  1254.  
  1255.     /* start read process */
  1256.     child_pid = fork();
  1257.     switch (child_pid)
  1258.     {
  1259.         case 0:
  1260.             start_read(sound_fd);
  1261.             exit(0);
  1262.         case -1:
  1263.             perror("forking read process");
  1264.             cleanup();
  1265.     }
  1266.  
  1267.     /* attach shared memory segment */
  1268.     buffers = (buf_struct *)shmat(shmid, 0, 0);
  1269.     if (buffers == (buf_struct *)-1)
  1270.     {
  1271.         perror("attaching shared memory");
  1272.         if (buffers->read_waiting)
  1273.             kill(child_pid, SIGKILL);
  1274.         cleanup();
  1275.     }
  1276.  
  1277.     /* start writing stuff from buffers */
  1278.     while(1)
  1279.     {
  1280.         /* wait until buffer is locked for us, or flush and break on eof */
  1281.         if (!buffers->locked[buf_num])
  1282.         {
  1283.             buffers->write_waiting = 1;
  1284.             sigpause(SIGUSR1);
  1285.             continue;
  1286.         }
  1287.  
  1288.         /* not waiting now */
  1289.         buffers->write_waiting = 0;
  1290.  
  1291.         /* eof check */
  1292.         if (buffers->length[buf_num] <= 0)
  1293.             break;
  1294.  
  1295.         /* write out data in buffer */
  1296.         rc = write(outfile, buffers->buf + (buf_num*SHM_BUFSIZ),
  1297.             buffers->length[buf_num]);
  1298.         if (rc != buffers->length[buf_num])
  1299.         {
  1300.             if ((errno == EINTR) || (errno == 0))
  1301.                 continue;
  1302.  
  1303.             perror("writing to output file");
  1304.             kill(child_pid, SIGKILL);
  1305.             cleanup();
  1306.         }
  1307.  
  1308.         /* unlock buffer for child's use */
  1309.         buffers->locked[buf_num] = 0;
  1310.         if (buffers->read_waiting)
  1311.             kill(child_pid, SIGUSR1);
  1312.  
  1313.         /* go to next buffer */
  1314.         buf_num++;
  1315.         buf_num %= NUMBUFS;
  1316.     }
  1317.  
  1318.  
  1319.     printf("done\n");
  1320.     cleanup();
  1321.     return(0);
  1322. }
  1323.  
  1324. int start_read(sound_fd)
  1325. int sound_fd;
  1326. {
  1327.     buf_struct *buffers;
  1328.     int buf_num = 0;
  1329.  
  1330.     /* attach handler for signal */
  1331.     sigset(SIGUSR1, sigusr_handler);
  1332.     sigset(SIGINT, detach);
  1333.     sigset(SIGHUP, detach);
  1334.  
  1335.     /* attach shared memory */
  1336.     buffers = (buf_struct *)shmat(shmid, 0, 0);
  1337.     if (buffers == (buf_struct *)-1)
  1338.     {
  1339.         perror("attaching shared memory");
  1340.         exit(0);
  1341.     }
  1342.  
  1343.     for (buf_num=0; buf_num < NUMBUFS; buf_num++)
  1344.         buffers->locked[buf_num] = 0;
  1345.  
  1346.     /* start reading into buffers */
  1347.     buf_num = 0;
  1348.     sleep(1);
  1349.     while(1)
  1350.     {
  1351.         /* wait for current buffer to become unlocked */
  1352.         if (buffers->locked[buf_num])
  1353.         {
  1354.             buffers->read_waiting = 1;
  1355.             sigpause(SIGUSR1);
  1356.             continue;
  1357.         }
  1358.  
  1359.         /* not waiting any more */
  1360.         buffers->read_waiting = 1;
  1361.  
  1362.         /* actually read data */
  1363.         buffers->length[buf_num] =
  1364.             read(sound_fd, buffers->buf + (buf_num*SHM_BUFSIZ), SHM_BUFSIZ);
  1365.         if (buffers->length[buf_num] == -1) 
  1366.         {
  1367.             if (errno == EINTR)
  1368.                 continue;
  1369.             else
  1370.             {
  1371.                 perror("reading from SoundBlaster\n");
  1372.                 detach();
  1373.             }
  1374.         }
  1375.         else if (buffers->length[buf_num] == 0)
  1376.         {
  1377.             buffers->locked[buf_num] = 1;
  1378.  
  1379.             /* wake up parent */
  1380.             if (buffers->write_waiting)
  1381.                 kill(getppid(), SIGUSR1);
  1382.  
  1383.             break;
  1384.         }
  1385.  
  1386.         /* lock buffer for parent's use */
  1387.         buffers->locked[buf_num] = 1;
  1388.                 
  1389.         /* wake up parent */
  1390.         if (buffers->write_waiting)
  1391.             kill(getppid(), SIGUSR1);
  1392.  
  1393.         /* go to next buffer */
  1394.         buf_num++;
  1395.         buf_num %= NUMBUFS;
  1396.     }
  1397.         
  1398.  
  1399.     /* wake up parent */
  1400.     kill(getppid(), SIGUSR1);
  1401.  
  1402.     /* detach shared memory */
  1403.     shmdt(buffers);
  1404.  
  1405.     return(0);
  1406. }
  1407. SHAR_EOF
  1408. fi
  1409. if test -f 'apps/set_speed.1'
  1410. then
  1411.     echo shar: "will not over-write existing file 'apps/set_speed.1'"
  1412. else
  1413. cat << \SHAR_EOF > 'apps/set_speed.1'
  1414. .TH SET_SPEED 1 "3 June 1991"
  1415. .UC 4
  1416. .SH NAME
  1417. set_speed \- changes the speed of recording and playing on Sound
  1418. Blaster
  1419. .SH SYNOPSIS
  1420. .B set_speed
  1421. ]
  1422. .I speed
  1423. ]
  1424. .PP
  1425. The argument must be the speed (in HZ) for sampling or playing.
  1426. .SH DESCRIPTION
  1427. .B set_speed
  1428. Sets the speed of the sampling and playing of the Sound Blaster
  1429. driver.  The speed must be greater than (or equal) to 4000Hz, and less
  1430. than 24000Hz.  Speeds in excess of 13000Hz will be truncated to
  1431. approximately 13000Hz by any recording.
  1432. .SH AUTHOR
  1433. .PP
  1434. Brian Smith
  1435. SHAR_EOF
  1436. fi
  1437. if test -f 'apps/set_speed.c'
  1438. then
  1439.     echo shar: "will not over-write existing file 'apps/set_speed.c'"
  1440. else
  1441. cat << \SHAR_EOF > 'apps/set_speed.c'
  1442. /*
  1443.  * Copyrighted as an unpublished work.
  1444.  * (c) Copyright 1991 Brian Smith
  1445.  * All rights reserved.
  1446.  *
  1447.  * Read the LICENSE file for details on distribution and use.
  1448.  *
  1449.  */
  1450.  
  1451. #include <sys/fcntl.h>
  1452. #include <sys/sb.h>
  1453.  
  1454. int main(argc, argv)
  1455. int argc;
  1456. char **argv;
  1457. {
  1458.     int fd;
  1459.     int speed;
  1460.  
  1461.     if (argc != 2)
  1462.     {
  1463.         printf("usage: %s <speed>\n", argv[0]);
  1464.         exit(-1);
  1465.     }
  1466.     speed = atoi(argv[1]);
  1467.     if ((speed < 4000) || (speed > 24000))
  1468.     {
  1469.         printf("usage: %s <speed>\n", argv[0]);
  1470.         printf("\tspeed must be between 4000 and 24000");
  1471.         exit(-1);
  1472.     }
  1473.  
  1474.     fd = open("/dev/sbdsp", O_RDONLY);
  1475.     if (fd == -1)
  1476.     {
  1477.         perror("opening SoundBlaster");
  1478.         exit(-1);
  1479.     }
  1480.  
  1481.     ioctl(fd, DSP_IOCTL_SPEED, speed);
  1482.  
  1483.     exit(0);
  1484. }
  1485. SHAR_EOF
  1486. fi
  1487. if test -f 'apps/snd_norm.1'
  1488. then
  1489.     echo shar: "will not over-write existing file 'apps/snd_norm.1'"
  1490. else
  1491. cat << \SHAR_EOF > 'apps/snd_norm.1'
  1492. .TH SND_NORM 1 "3 June 1991"
  1493. .UC 4
  1494. .SH NAME
  1495. snd_norm \- normalizes a sound file
  1496. .SH SYNOPSIS
  1497. .B snd_norm
  1498. [
  1499. .I old file
  1500. ]
  1501. [
  1502. .I new file
  1503. ]
  1504. .PP
  1505. The arguments are the input and output of the normalization.
  1506. .SH DESCRIPTION
  1507. .B snd_norm
  1508. The input file is normalized, such that the larget amplitude 127, thus
  1509. obtaining the larget volume from a file (for a given volume setting on
  1510. the actual Sound Blaster).  Usefull for post-processing recordings
  1511. which are barely audible.
  1512. .SH AUTHOR
  1513. .PP
  1514. Brian Smith
  1515. SHAR_EOF
  1516. fi
  1517. if test -f 'apps/snd_norm.c'
  1518. then
  1519.     echo shar: "will not over-write existing file 'apps/snd_norm.c'"
  1520. else
  1521. cat << \SHAR_EOF > 'apps/snd_norm.c'
  1522. /*
  1523.  * Copyrighted as an unpublished work.
  1524.  * (c) Copyright 1991 Brian Smith
  1525.  * All rights reserved.
  1526.  *
  1527.  * Read the LICENSE file for details on distribution and use.
  1528.  *
  1529.  */
  1530.  
  1531. #include <stdio.h>
  1532. #include <sys/fcntl.h>
  1533. #include <sys/unistd.h>
  1534.  
  1535. main(argc, argv)
  1536. int argc;
  1537. char **argv;
  1538. {
  1539.     int fd, new_fd, rc, max_wave;
  1540.     unsigned char tmp_byte;
  1541.     int tmp_int;
  1542.     int i;
  1543.     double augmentation;
  1544.  
  1545.     if (argc != 3)
  1546.     {
  1547.         printf("usage: %s <oldfile> <newfile>\n", argv[0]);
  1548.         exit(-1);
  1549.     }
  1550.  
  1551.     fd = open(argv[1], O_RDONLY);
  1552.     if (fd == -1)
  1553.     {
  1554.         perror("opening oldfile");
  1555.         exit(-1);
  1556.     }
  1557.  
  1558.     new_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
  1559.     if (new_fd == -1)
  1560.     {
  1561.         perror("opening newfile");
  1562.         exit(-1);
  1563.     }
  1564.  
  1565.     printf("normalizing from input file..");
  1566.     fflush(stdout);
  1567.     i = 0;
  1568.     max_wave = 0;
  1569.     while(1)
  1570.     {
  1571.         i++ ; i &= 0x7FFF;
  1572.         if (!i)
  1573.             write(1, ".", 1);
  1574.  
  1575.         rc = read(fd, &tmp_byte, 1);
  1576.         if (rc == 0)
  1577.             break;
  1578.         tmp_int = tmp_byte - 128;
  1579.         if (abs(tmp_int) > max_wave)
  1580.             max_wave = abs(tmp_int);
  1581.     }
  1582.     write(1, "\n", 1);
  1583.  
  1584.     augmentation = (double)0x80 / (double)max_wave;
  1585.     printf("max_wave\t%d\n", max_wave);
  1586.     printf("augmentation\t%f\n", augmentation);
  1587.  
  1588.  
  1589.     /* write out new file */
  1590.     lseek(fd, 0, SEEK_SET);
  1591.     while (1)
  1592.     {
  1593.         rc = read(fd, &tmp_byte, 1);
  1594.         if (rc == 0)
  1595.             break;
  1596.  
  1597.         tmp_int = tmp_byte - 128;
  1598.         tmp_int *= augmentation;
  1599.         tmp_int += 128;
  1600.  
  1601.         tmp_byte = tmp_int;
  1602.  
  1603.         rc = write(new_fd, &tmp_byte, 1);
  1604.         if (rc != 1)
  1605.         {
  1606.             perror("writing to new_fd");
  1607.             exit(-1);
  1608.         }
  1609.     }
  1610.         
  1611.  
  1612.     return(0);
  1613. }
  1614. SHAR_EOF
  1615. fi
  1616. if test -f 'apps/tst_fm_note.c'
  1617. then
  1618.     echo shar: "will not over-write existing file 'apps/tst_fm_note.c'"
  1619. else
  1620. cat << \SHAR_EOF > 'apps/tst_fm_note.c'
  1621. /*
  1622.  * Copyrighted as an unpublished work.
  1623.  * (c) Copyright 1991 Brian Smith
  1624.  * All rights reserved.
  1625.  *
  1626.  * Read the LICENSE file for details on distribution and use.
  1627.  *
  1628.  */
  1629.  
  1630. #include <sys/fcntl.h>
  1631. #include <sys/signal.h>
  1632. #include <sys/sb.h>
  1633. #include <stdio.h>
  1634. #include <memory.h>
  1635.  
  1636. void handler()
  1637. {
  1638.     return;
  1639. }
  1640.  
  1641. int main(argc, argv)
  1642. int argc;
  1643. char **argv;
  1644. {
  1645.     int fd;
  1646.     int rc;
  1647.     int i;
  1648.     int note;
  1649.     int fnum;
  1650.     int block;
  1651.     static unsigned char instrument_buf[16] = {
  1652.         0x11, 0x01, 0x8a, 0x40,
  1653.         0xf1, 0xf1, 0x11, 0xb3,
  1654.         0x00, 0x00, 0x06, 0x00,
  1655.         0x00, 0x00, 0x00, 0x00 
  1656.     };
  1657.     sb_fm_character note_character;
  1658.  
  1659.     sigset(SIGINT, handler);
  1660.  
  1661.     fd = open("/dev/sbfm", O_WRONLY);
  1662.     if (fd == -1)
  1663.     {
  1664.         perror("opening fm device");
  1665.         return(-1);
  1666.     }
  1667.  
  1668.     /* test reset */
  1669.     rc = ioctl(fd, FM_IOCTL_RESET);
  1670.     if (rc == -1)
  1671.     {
  1672.         perror("fm chips reset");
  1673.         exit(-1);
  1674.     }
  1675.  
  1676.     /* test setting an instrument */
  1677.     for (i=0 ; i<9; i++)
  1678.     {
  1679.         /* set instrument characteristics */
  1680.         note_character.voice_num = i;
  1681.         memset(note_character.data, (char)0, 16);
  1682.         memcpy(note_character.data, instrument_buf, 16);
  1683.         rc = ioctl(fd, FM_IOCTL_SET_VOICE, (int)¬e_character);
  1684.         if (rc == -1)
  1685.         {
  1686.             perror("fm chips voice set");
  1687.             exit(-1);
  1688.         }
  1689.  
  1690.         /* set note to play */
  1691.         fnum = 686;
  1692.         block = i;
  1693.         note_num(note) = i;
  1694.         fnum_low(note) = fnum & 0xFF;
  1695.         keyon_blk_fnum(note) = 0;
  1696.         keyon_blk_fnum(note) |= 1<<5;                   /* KEYON bit */
  1697.         keyon_blk_fnum(note) |= (block & 7) << 2;       /* block/octave */
  1698.         keyon_blk_fnum(note) |= (fnum & 0x3FF) >> 8;    /* top 2 bits of fnum */
  1699.  
  1700.         /* test note on/off */
  1701.         rc = ioctl(fd, FM_IOCTL_NOTE_ON, note);
  1702.         if (rc == -1)
  1703.         {
  1704.             perror("fm chips voice on");
  1705.             exit(-1);
  1706.         }
  1707.     }
  1708.  
  1709.     /* wait for ^C */
  1710.     sigpause(SIGINT);
  1711.     close(fd);
  1712.     return(0);
  1713. }
  1714. SHAR_EOF
  1715. fi
  1716. if test -f 'apps/tst_fm_open.c'
  1717. then
  1718.     echo shar: "will not over-write existing file 'apps/tst_fm_open.c'"
  1719. else
  1720. cat << \SHAR_EOF > 'apps/tst_fm_open.c'
  1721. /*
  1722.  * Copyrighted as an unpublished work.
  1723.  * (c) Copyright 1991 Brian Smith
  1724.  * All rights reserved.
  1725.  *
  1726.  * Read the LICENSE file for details on distribution and use.
  1727.  *
  1728.  */
  1729.  
  1730. #include <sys/fcntl.h>
  1731. #include <sys/sb.h>
  1732.  
  1733. int main(argc, argv)
  1734. int argc;
  1735. char **argv;
  1736. {
  1737.     int fd;
  1738.  
  1739.     fd = open("/dev/sbfm", O_WRONLY);
  1740.     if (fd == -1)
  1741.         perror("opening fm device");
  1742.     else
  1743.         close(fd);
  1744.  
  1745.     return(0);
  1746. }
  1747. SHAR_EOF
  1748. fi
  1749. if test -f 'apps/tst_instr.c'
  1750. then
  1751.     echo shar: "will not over-write existing file 'apps/tst_instr.c'"
  1752. else
  1753. cat << \SHAR_EOF > 'apps/tst_instr.c'
  1754. /*
  1755.  * Copyrighted as an unpublished work.
  1756.  * (c) Copyright 1991 Brian Smith
  1757.  * All rights reserved.
  1758.  *
  1759.  * Read the LICENSE file for details on distribution and use.
  1760.  *
  1761.  */
  1762.  
  1763. #include <sys/fcntl.h>
  1764. #include <sys/unistd.h>
  1765. #include <sys/sb.h>
  1766. #include <stdio.h>
  1767.  
  1768. #define lobyte(X)   (((unsigned char *)&X)[0])
  1769. #define hibyte(X)   (((unsigned char *)&X)[1])
  1770.  
  1771. /* Globals */
  1772. int fm_herz;        /* clock ticks per second */
  1773. int tempo;          /* clock ticks per quarter note */
  1774. int fm_fd;
  1775.  
  1776. int main(argc, argv)
  1777. int argc;
  1778. char **argv;
  1779. {
  1780.     int cmf_fd;
  1781.  
  1782.     if (argc != 2)
  1783.     {
  1784.         printf("usage: %s <cmf file>\n", argv[0]);
  1785.         exit(-1);
  1786.     }
  1787.  
  1788.     /* open cmf file */
  1789.     cmf_fd = open(argv[1], O_RDONLY);
  1790.     if (cmf_fd == -1)
  1791.     {
  1792.         printf("usage: %s <cmf file>\n", argv[0]);
  1793.         exit(-1);
  1794.     }
  1795.  
  1796.     /* verify that file is a cmf file */
  1797.     if (!verify_cmf(cmf_fd))
  1798.     {
  1799.         printf("file was not a cmf file\n");
  1800.         printf("usage: %s <cmf file>\n", argv[0]);
  1801.         exit(-1);
  1802.     }
  1803.  
  1804.     /* read and set instruments from cmf file */
  1805.     set_instruments(cmf_fd);
  1806.  
  1807.     /* play song */
  1808.     play_song(cmf_fd);
  1809.  
  1810.     return(0);
  1811. }
  1812.  
  1813.  
  1814. /* check for "CTMF" in first four bytes of file */
  1815. int verify_cmf(fd)
  1816. int fd;
  1817. {
  1818.     char idbuf[5];
  1819.  
  1820.     /* get id */
  1821.     lseek(fd, 0, SEEK_SET);
  1822.     if (read(fd, idbuf, 4) != 4)
  1823.         return(FALSE);
  1824.     
  1825.     /* compare to standard id */
  1826.     idbuf[4] = (char)0;
  1827.     if (strcmp(idbuf, "CTMF") != 0)
  1828.         return(FALSE);
  1829.     
  1830.     return(TRUE);
  1831. }
  1832.  
  1833. int set_instruments(fd)
  1834. int fd;
  1835. {
  1836.     int offset;
  1837.     int num_instruments;
  1838.     int i;
  1839.     int rc;
  1840.     int fnum, block, note;
  1841.     unsigned char tmp_byte;
  1842.     sb_fm_character note_character;
  1843.  
  1844.     /* open soundblaster fm chips */
  1845.     fm_fd = open("/dev/sbfm", O_WRONLY);
  1846.     if (fm_fd == -1)
  1847.     {
  1848.         perror("opening fm chips");
  1849.         exit(-1);
  1850.     }
  1851.  
  1852.     /* get offset of instrument block */
  1853.     offset = 0;
  1854.     lseek(fd, 0x06, SEEK_SET);
  1855.     read(fd, &tmp_byte, 1);
  1856.     lobyte(offset) = tmp_byte;
  1857.     read(fd, &tmp_byte, 1);
  1858.     hibyte(offset) = tmp_byte;
  1859.  
  1860.     /* get number of instruments */
  1861.     num_instruments = 0;
  1862.     lseek(fd, 0x24, SEEK_SET);
  1863.     read(fd, &tmp_byte, 1);
  1864.     lobyte(num_instruments) = tmp_byte;
  1865.     read(fd, &tmp_byte, 1);
  1866.     hibyte(num_instruments) = tmp_byte;
  1867.  
  1868.     if (num_instruments > 9)
  1869.         num_instruments = 9;
  1870.     printf("loading %d instruments\n", num_instruments);
  1871.  
  1872.     /* read each instrument */
  1873.     lseek(fd, offset, SEEK_SET);
  1874.     for (i=0; i< num_instruments; i++)
  1875.     {
  1876.         /* set instrument characteristics */
  1877.         note_character.voice_num = i;
  1878.         read(fd, note_character.data, 16);
  1879.         printf("loading instrument: 0x%02x\n", i);
  1880.         rc = ioctl(fm_fd, FM_IOCTL_SET_VOICE, (int)¬e_character);
  1881.         if (rc == -1)
  1882.         {
  1883.             perror("fm chips voice set");
  1884.             exit(-1);
  1885.         }
  1886.  
  1887.         /* set note to regular C note */
  1888.         fnum = 686;
  1889.         block = 4;
  1890.         note_num(note) = i;
  1891.         fnum_low(note) = fnum & 0xFF;
  1892.         keyon_blk_fnum(note) = 0;
  1893.         keyon_blk_fnum(note) |= 1<<5;                   /* KEYON bit */
  1894.         keyon_blk_fnum(note) |= (block & 7) << 2;       /* block/octave */
  1895.         keyon_blk_fnum(note) |= (fnum & 0x3FF) >> 8;    /* top 2 bits of fnum */
  1896.         ioctl(fm_fd, FM_IOCTL_NOTE_ON, note);
  1897.         sleep(1);
  1898.         ioctl(fm_fd, FM_IOCTL_NOTE_ON, i);
  1899.     }
  1900.  
  1901.     return(0);
  1902. }
  1903.  
  1904.  
  1905. /*
  1906.  * get and set timing parameters
  1907.  */
  1908. void set_timing(fd)
  1909. int fd;
  1910. {
  1911.     unsigned char tmp_byte;
  1912.  
  1913.     /* get tempo */
  1914.     tempo = 0;
  1915.     lseek(fd, 0x0C, SEEK_SET);
  1916.     read(fd, &tmp_byte, 1);
  1917.     tempo = (unsigned int)tmp_byte;
  1918.     read(fd, &tmp_byte, 1);
  1919.     tempo += (unsigned int)tmp_byte << 8;
  1920.  
  1921.     /* get herz of timing clock */
  1922.     fm_herz = 0;
  1923.     lseek(fd, 0x0C, SEEK_SET);
  1924.     read(fd, &tmp_byte, 1);
  1925.     tempo = (unsigned int)fm_herz;
  1926.     read(fd, &tmp_byte, 1);
  1927.     tempo += (unsigned int)fm_herz << 8;
  1928.     
  1929.     return;
  1930. }
  1931.  
  1932.  
  1933. /*
  1934.  * seek to the midi stream and handle midi events for the song
  1935.  */
  1936. int play_song(fd)
  1937. int fd;
  1938. {
  1939.     return(0);
  1940. }
  1941. SHAR_EOF
  1942. fi
  1943. exit 0
  1944. #    End of shell archive
  1945.