[comp.sources.misc] v20i048: sndblast - Sound Blaster Unix Driver, Part02/02

brians@eecs.cs.pdx.edu (Brian Smith) (06/08/91)

Submitted-by: Brian Smith <brians@eecs.cs.pdx.edu>
Posting-number: Volume 20, Issue 48
Archive-name: sndblast/part02
Environment: ISC-Unix

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  ./INSTALL ./LICENSE ./Makefile ./Master ./Name ./Node
#   ./README ./Space.c ./System ./apps/Makefile ./apps/get_instr.1
#   ./apps/get_instr.c ./apps/play_cleanup.c ./apps/play_cmf.1
#   ./apps/play_snd.1 ./apps/record_snd.1 ./apps/set_speed.1
#   ./apps/set_speed.c ./apps/snd_norm.1 ./apps/snd_norm.c
#   ./apps/tst_fm_note.c ./apps/tst_fm_open.c ./apps/tst_instr.c
# Wrapped by kent@sparky on Fri Jun  7 22:16:57 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 2 (of 2)."'
if test -f './INSTALL' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./INSTALL'\"
else
  echo shar: Extracting \"'./INSTALL'\" \(1068 characters\)
  sed "s/^X//" >'./INSTALL' <<'END_OF_FILE'
X
X                         Sound Blaster(tm) Driver
X                       (Copyright 1991, Brian Smith)
X
X
XINSTALLING THE DRIVER
X
X1. Run make in the directory with the driver code (sb.c, sb.h, etc...).
X2. su to root, if not already so, and run /etc/insdriver.
X    a. Answer . for query asking for the directory of the driver
X        files.
X    b. Answer sb for the query asking for the driver name.
X    c. Accept the default of /etc/conf for the configuration directory
X        by hitting return.
X    d. Enter any description you like.  Maybe: "Sound Blaster Driver".
X    e. Answer n to the configuration question.
X3. As root still, run /etc/kconfig.
X4. Make sure the driver is configured into the kernel in the
X    configuration menu.
X5. Build a new kernel.
X6. Install the new kernel.  This reboots the machine.
X
X
XINSTALLING THE USER PROGRAMS
X
X1. Edit the Makefile in the apps directory.
X2. Run make.
X3. Run make install.
X4. Manually install the man files however you like.  The *.1 files are
Xnroff source, while the *.doc files are nroff'ed for those of use
Xwithout.
END_OF_FILE
  if test 1068 -ne `wc -c <'./INSTALL'`; then
    echo shar: \"'./INSTALL'\" unpacked with wrong size!
  fi
  # end of './INSTALL'
fi
if test -f './LICENSE' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./LICENSE'\"
else
  echo shar: Extracting \"'./LICENSE'\" \(2117 characters\)
  sed "s/^X//" >'./LICENSE' <<'END_OF_FILE'
X
X                 SoundBlaster(tm) Driver General Public License
X                       (Copyright 1991, Brian Smith)
X
X  Most licenses are restrictive in one way or another, the GNU license
Xas well.  The whole purpose of this excercise was to benefit the computer
Xcommunity as a whole, including those of us unprincipled enough to want
Xto make money on software. :-)
X
X  For my protection, it must be stated at the outset that there is NO
Xstated or implied warranty for the driver nor is there any stated or
Ximplied warranty for any of the associated user programs nor for the
Xdocumentation.  The mistakes are mine, the responsibility is yours (for
Xusing the package).
X
XCOPYING ANDUSE POLICIES
X
X1. You may use this unmodified package on any and all computers which
Xyou wish to install this package.
X
X2. You may copy and distribute verbatim copies of this SoundBlaster driver
Xand associated user software as you recieved them.  Distribute them however
Xyou like, as long as they are distributed with the original copyright
Xand (lack of) warranty messages intact.
X
X3. You may distribute modified copies of this driver in source forms if
Xand only if my copyright and (lack of) is intact in addition to an
Xappended statement of your modification.  I must not be held responsible
Xfor any modifications made by other persons.
X
X4. Any persons or companies or persons who wish to make a commercial
Xdistribution (binaries only) using this package or any portion of this
Xpackage must contact me first.  I will most likely license the person or
Xcompany for little or no charge.  Mostly, I'm a snoop: if you are using
Xmy software let me know. :-)
X
XAs I am not a lawyer, so, there are likely legal holes the size of
Xsmall continents, but please try to keep the spirit of this license.  The
Xintent of this was for betterment of the community.  Any changes should
Xbe sent to me for integration (either e-mail or snail-mail).
X
XCURRENT ADDRESSES
X    e-mail:     brians@cs.pdx.edu
X                ...!uunet!tektronix!pdxgate!eecs!brians
X    US Mail:    Brian Smith
X                18700 SW Cascadia Court
X                Aloha, OR 97007
END_OF_FILE
  if test 2117 -ne `wc -c <'./LICENSE'`; then
    echo shar: \"'./LICENSE'\" unpacked with wrong size!
  fi
  # end of './LICENSE'
fi
if test -f './Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./Makefile'\"
else
  echo shar: Extracting \"'./Makefile'\" \(1110 characters\)
  sed "s/^X//" >'./Makefile' <<'END_OF_FILE'
X# 
X#                       Sound Blaster(tm) Driver
X#                     (Copyright 1991, Brian Smith)
X#
X
XSHELL=/bin/sh
XINCLSYS = /usr/include/sys
XLKDRVRDIR = /etc/conf/pack.d/sb
XLKSCONFDIR = /etc/conf/sdevice.d
XLKNCONFDIR = /etc/conf/node.d
XLKICONFDIR = /etc/conf/init.d
XLKKCONFDIR = /etc/conf/kconfig.d
XDRVRNAME = Driver.o
XCONFNAME = sb
X
XCC=cc
XCFLAGS = -O -DINKERNEL
X
XOBJS = Driver.o
X
Xall: Driver.o $(INCLSYS)/sb.h
X
XDriver.o: sb.c $(INCLSYS)/sb.h Makefile
X	$(CC) $(CFLAGS) -c sb.c
X	mv sb.o Driver.o
X
Xinstall: $(LKDRVRDIR) $(LKDRVRDIR)/$(DRVRNAME) $(LKDRVRDIR)/space.c \
X	$(INCLSYS)/sb.h
X
X# OLD install, now done manually
X# install: Driver.o $(INCLSYS)/sb.h Master System Space.c Node
X# 	/etc/insdriver
X# 	/etc/kconfig
X
X$(LKDRVRDIR):
X	-mkdir $(LKDRVRDIR) 2> /dev/null
X	chmod 755 $(LKDRVRDIR)
X
X$(INCLSYS)/sb.h: sb.h
X	@echo /bin/cp sb.h $(INCLSYS)/sb.h
X	/bin/cp sb.h $(INCLSYS)/sb.h
X
X$(LKDRVRDIR)/Driver.o: Driver.o
X	cp Driver.o $(LKDRVRDIR)/$(DRVRNAME)
X	chmod 644 $(LKDRVRDIR)/$(DRVRNAME)
X
X$(LKDRVRDIR)/space.c: Space.c
X	cp Space.c $(LKDRVRDIR)/space.c
X	chmod 644 $(LKDRVRDIR)/space.c
X
Xclean:
X	rm -f Driver.o
END_OF_FILE
  if test 1110 -ne `wc -c <'./Makefile'`; then
    echo shar: \"'./Makefile'\" unpacked with wrong size!
  fi
  # end of './Makefile'
fi
if test -f './Master' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./Master'\"
else
  echo shar: Extracting \"'./Master'\" \(27 characters\)
  sed "s/^X//" >'./Master' <<'END_OF_FILE'
Xsb ocrwiI iHc sb 0 0 1 3 1
END_OF_FILE
  if test 27 -ne `wc -c <'./Master'`; then
    echo shar: \"'./Master'\" unpacked with wrong size!
  fi
  # end of './Master'
fi
if test -f './Name' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./Name'\"
else
  echo shar: Extracting \"'./Name'\" \(20 characters\)
  sed "s/^X//" >'./Name' <<'END_OF_FILE'
XSoundBlaster Driver
END_OF_FILE
  if test 20 -ne `wc -c <'./Name'`; then
    echo shar: \"'./Name'\" unpacked with wrong size!
  fi
  # end of './Name'
fi
if test -f './Node' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./Node'\"
else
  echo shar: Extracting \"'./Node'\" \(48 characters\)
  sed "s/^X//" >'./Node' <<'END_OF_FILE'
Xsb  sbcms  c  0
Xsb  sbfm   c  1
Xsb  sbdsp  c  2
END_OF_FILE
  if test 48 -ne `wc -c <'./Node'`; then
    echo shar: \"'./Node'\" unpacked with wrong size!
  fi
  # end of './Node'
fi
if test -f './README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./README'\"
else
  echo shar: Extracting \"'./README'\" \(3663 characters\)
  sed "s/^X//" >'./README' <<'END_OF_FILE'
X
X                         Sound Blaster(tm) Driver
X                       (Copyright 1991, Brian Smith)
X
X
XREQUIREMENTS
X
XThis driver and the associated user programs require a 386/486 system
Xrunning System V 3.2 Unix.  It has been tested on ISC Unix versions
X2.0.2 through 2.2.1.  I believe it will work correctly on Esix, Intel,
Xand AT&T Unix.  SCO is a mystery to me (as well as many others).  I do
Xnot believe it will work in SysV 4.0 and above, but the modifications
Xshould be fairly minimal.  Remember, though, THERE IS NO WARRANTY.
X 
X
XGENERAL INFORMATION
X
XThis driver is for the Sound Blaster sound card designed by Creative
XLabs, Incorporated.  The Sound Blaster is a sound card for the
XIBM-PC(tm) type I/O bus.  The card is capable of sampling sound from a
Xmicrophone jack from 4KHz to 23KHz (or 24KHz, depending upon which
Xportion of the manual you believe) at 8 raw bits of resolution.  It is
Xalso capable of playing samples at speeds from 4KHz up to 12KHz.  The
Xboard can play raw 8 bit samples, or 2 bit, 2.6 bit, or 4 bit ADPCM
Xpacked samples.  ADCPM is a lossy method of data compression.  The
Xsampling and output may be directly driven by the CPU, or it may be
Xdriven by DMA.  The card is also capable of playing music through an
Xon-board FM synthesizer chip.  The chip may play 9 simultaneous
Xinstruments, or it can play 6 simultaneous voices with 5 additional
Xrhythm instruments.  In addition, the board (but NOT my driver) also
Xsupports the addition of 2 C/MS chips. For more information, read the
Xadvertising blurb, errr...  manual which comes with the Sound Blaster.
X
XThe driver is capable of utilizing only a subset of the capabilities
Xof the Sound Blaster card.  The driver is accessed through three
Xdevice nodes.
X
XThe /dev/sbdsp node accesses the DSP chip which controls sampling and
Xsample playback.  Only 8-bit sound is supported thus far.  The driver
Xutilizes DMA, and therefore is very unobtrusive to the system load.
XThe ls utility is harder upon the system.  Read(2) and write(2) upon
X/dev/sbdsp sample sound and play back sound samples, respectively.
XSeveral ioctl(2)'s control sampling/playback speed, resets, etc... 
XThe play_snd utility demonstrates the use of the /dev/sbdsp node.
X
XThe /dev/sbfm node accesses the FM chips.  The only access to the FM
Xchips are through ioctl(2)'s.  The play_cmf utility demonstrates the
Xuse of the FM chips by (mostly) interpreting and playing CMF files.
XThe various options controlling the voices can be dumped from a CMF
Xfile by the get_instruments utility.  Those familiar with synthesizers
Xcan then learn how to create their own instruments.  I can't provide
Xdirect documentation, as I believe that would be a violation of
XCreative Lab's copyrights.  Those having questions, send me e-mail.  I
Xthink it would be OK to answer questions.
X
XThe /dev/sbcms node accesses absolutely nothing.  I do not have the
XC/MS chips with which to experiment.
X
XThis driver is merely the rough outlines of what it could be.  Support
Xcould be added for oodles of features, like efficiency improvements, and
XADCPM interpretion for the /dev/sbdsp node.  If you wish to add to this
Xdriver, please be my guest (after reading the license file).  When you
Xhave patches, send those to me.  I will then integrate, do rudimentary
Xtesting, and send the patches to Usenet.  That way, there won't be
Xbillions of versions of this driver to contend with.
X
XI am not requiring donations to my, no doubt worthy cause, however,
Xthey are willingly accepted. :-)  They will help me in future
Xprojects, and if there are enough requests (loudness does not count),
XI will continue work on this driver and write more software to use
Xit.
END_OF_FILE
  if test 3663 -ne `wc -c <'./README'`; then
    echo shar: \"'./README'\" unpacked with wrong size!
  fi
  # end of './README'
fi
if test -f './Space.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./Space.c'\"
else
  echo shar: Extracting \"'./Space.c'\" \(374 characters\)
  sed "s/^X//" >'./Space.c' <<'END_OF_FILE'
X/*
X * Copyrighted as an unpublished work.
X * (c) Copyright 1991 Brian Smith
X * All rights reserved.
X *
X * Read the LICENSE file for details on distribution and use.
X *
X */
X
X#include <sys/types.h>
X#include <sys/iobuf.h>
X#include <config.h>
X
X#include <sys/sb.h>
X
Xushort sb_configured = SB;
Xushort sb_dma_chan = SB_CHAN;
Xushort sb_interrupt = SB_0_VECT;
Xstruct iobuf sbtab[3];
END_OF_FILE
  if test 374 -ne `wc -c <'./Space.c'`; then
    echo shar: \"'./Space.c'\" unpacked with wrong size!
  fi
  # end of './Space.c'
fi
if test -f './System' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./System'\"
else
  echo shar: Extracting \"'./System'\" \(34 characters\)
  sed "s/^X//" >'./System' <<'END_OF_FILE'
Xsb  Y  3  6  3  5  220  22F  0  0
END_OF_FILE
  if test 34 -ne `wc -c <'./System'`; then
    echo shar: \"'./System'\" unpacked with wrong size!
  fi
  # end of './System'
fi
if test -f './apps/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/Makefile'\"
else
  echo shar: Extracting \"'./apps/Makefile'\" \(1472 characters\)
  sed "s/^X//" >'./apps/Makefile' <<'END_OF_FILE'
X# 
X#                 Programs using Sound Blaster(tm) Driver
X#                     (Copyright 1991, Brian Smith)
X#
X
XSHELL=/bin/sh
XCC= gcc -fpcc-struct-return
XCFLAGS = # -O
XLIBS= -lc_s
X
XPROGRAMS= play_snd set_speed play_cmf record_snd snd_norm
XTESTS= play_cleanup tst_fm_open tst_fm_note get_instr tst_instr
X
Xall: $(PROGRAMS) $(TESTS)
X
Xrecord_snd: record_snd.c /usr/include/sys/sb.h
X	$(CC) $(CFLAGS) -o record_snd record_snd.c $(LIBS)
X
Xplay_snd: play_snd.c /usr/include/sys/sb.h
X	$(CC) $(CFLAGS) -o play_snd play_snd.c $(LIBS)
X
Xplay_cleanup: play_cleanup.c /usr/include/sys/sb.h
X	$(CC) $(CFLAGS) -o play_cleanup play_cleanup.c $(LIBS)
X
Xget_instr: get_instr.c /usr/include/sys/sb.h
X	$(CC) $(CFLAGS) -o get_instr get_instr.c $(LIBS)
X
Xset_speed: set_speed.c /usr/include/sys/sb.h
X	$(CC) $(CFLAGS) -o set_speed set_speed.c $(LIBS)
X
Xtst_fm_open: tst_fm_open.c /usr/include/sys/sb.h
X	$(CC) $(CFLAGS) -o tst_fm_open tst_fm_open.c $(LIBS)
X
Xtst_fm_note: tst_fm_note.c /usr/include/sys/sb.h
X	$(CC) $(CFLAGS) -o tst_fm_note tst_fm_note.c $(LIBS)
X
Xplay_cmf: play_cmf.c /usr/include/sys/sb.h
X	$(CC) $(CFLAGS) -o play_cmf play_cmf.c -linet $(LIBS)
X
Xtst_instr: tst_instr.c /usr/include/sys/sb.h
X	$(CC) $(CFLAGS) -o tst_instr tst_instr.c $(LIBS)
X
Xsnd_norm: snd_norm.c
X	$(CC) $(CFLAGS) -o snd_norm snd_norm.c $(LIBS)
X
Xinstall: $(PROGRAMS)
X	for i in $(PROGRAMS); do \
X	mcs -d $$i ; \
X	strip $$i ; \
X	(echo $$i | cpio -pdlmv /usr/local/bin) ; \
X	done
X
Xclean:
X	/bin/rm -f $(PROGRAMS) $(TESTS)
END_OF_FILE
  if test 1472 -ne `wc -c <'./apps/Makefile'`; then
    echo shar: \"'./apps/Makefile'\" unpacked with wrong size!
  fi
  # end of './apps/Makefile'
fi
if test -f './apps/get_instr.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/get_instr.1'\"
else
  echo shar: Extracting \"'./apps/get_instr.1'\" \(377 characters\)
  sed "s/^X//" >'./apps/get_instr.1' <<'END_OF_FILE'
X.TH GET_INSTR 1 "3 June 1991"
X.UC 4
X.SH NAME
Xget_instr \- decodes and prints instrument info from CMF files
X.SH SYNOPSIS
X.B get_instr
X[
X.I file
X]
X.PP
XThe argument must be the CMF file to be examined.
X.SH DESCRIPTION
X.B get_instr
Xreads the portion of the CMF file detailing the instruments used, and
Xthen prints out the breakdown of that information.
X.SH AUTHOR
X.PP
XBrian Smith
END_OF_FILE
  if test 377 -ne `wc -c <'./apps/get_instr.1'`; then
    echo shar: \"'./apps/get_instr.1'\" unpacked with wrong size!
  fi
  # end of './apps/get_instr.1'
fi
if test -f './apps/get_instr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/get_instr.c'\"
else
  echo shar: Extracting \"'./apps/get_instr.c'\" \(4479 characters\)
  sed "s/^X//" >'./apps/get_instr.c' <<'END_OF_FILE'
X/*
X * Copyrighted as an unpublished work.
X * (c) Copyright 1991 Brian Smith
X * All rights reserved.
X *
X * Read the LICENSE file for details on distribution and use.
X *
X */
X
X#include <sys/fcntl.h>
X#include <sys/unistd.h>
X#include <sys/sb.h>
X#include <stdio.h>
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int cmf_fd;
X
X    if (argc != 2)
X    {
X        printf("usage: %s <cmf file>\n", argv[0]);
X        exit(-1);
X    }
X
X    /* open cmf file */
X    cmf_fd = open(argv[1], O_RDONLY);
X    if (cmf_fd == -1)
X    {
X        printf("usage: %s <cmf file>\n", argv[0]);
X        exit(-1);
X    }
X
X    /* verify that file is a cmf file */
X    if (!verify_cmf(cmf_fd))
X    {
X        printf("file was not a cmf file\n");
X        printf("usage: %s <cmf file>\n", argv[0]);
X        exit(-1);
X    }
X
X    /* print out info on instruments in cmf file */
X    print_instruments(cmf_fd);
X
X    return(0);
X}
X
X
X/* check for "CTMF" in first four bytes of file */
Xint verify_cmf(fd)
Xint fd;
X{
X    char idbuf[5];
X
X    /* get id */
X    lseek(fd, 0, SEEK_SET);
X    if (read(fd, idbuf, 4) != 4)
X        return(FALSE);
X    
X    /* compare to standard id */
X    idbuf[4] = (char)0;
X    if (strcmp(idbuf, "CTMF") != 0)
X        return(FALSE);
X    
X    return(TRUE);
X}
X
Xint print_instruments(fd)
Xint fd;
X{
X    int offset;
X    int num_instruments;
X    int i;
X    int j;
X    unsigned char tmp_byte;
X    unsigned char instrument_buf[16];
X
X#define lobyte(X)   (((unsigned char *)&X)[0])
X#define hibyte(X)   (((unsigned char *)&X)[1])
X
X    /* get offset of instrument block */
X    offset = 0;
X    lseek(fd, 0x06, SEEK_SET);
X    read(fd, &tmp_byte, 1);
X    lobyte(offset) = tmp_byte;
X    read(fd, &tmp_byte, 1);
X    hibyte(offset) = tmp_byte;
X
X    /* get number of instruments */
X    num_instruments = 0;
X    lseek(fd, 0x24, SEEK_SET);
X    read(fd, &tmp_byte, 1);
X    lobyte(num_instruments) = tmp_byte;
X    read(fd, &tmp_byte, 1);
X    hibyte(num_instruments) = tmp_byte;
X
X    /* read each instrument */
X    lseek(fd, offset, SEEK_SET);
X    for (i=0; i< num_instruments; i++)
X    {
X        read(fd, instrument_buf, 16);
X        printf("instrument: 0x%02x\n", i);
X
X        for (j=0; j<16; j++)
X            printf("0x%02x ", (unsigned int)instrument_buf[j]);
X        printf("\n");
X
X        /* byte 0 */
X        printf("\tModulator: 0x%02x\n", (unsigned int)instrument_buf[0]);
X
X        /* byte 1 */
X        printf("\tCarrier Sound Characteristic\n");
X        if (instrument_buf[1] & (1<<7))
X            printf("\tPitch Vibrato: On\n");
X        else
X            printf("\tPitch Vibrato: Off\n");
X        if (instrument_buf[1] & (1<<6))
X            printf("\tAmplitude Vibrato: On\n");
X        else
X            printf("\tAmplitude Vibrato: Off\n");
X        if (instrument_buf[1] & (1<<5))
X            printf("\tSustaining Sound: On\n");
X        else
X            printf("\tSustaining Sound: Off\n");
X        if (instrument_buf[1] & (1<<4))
X            printf("\tEnvelope Scaling: On\n");
X        else
X            printf("\tEnvelope Scaling: Off\n");
X        printf("\tFrequency Multiplier: 0x%02x\n", instrument_buf[1] & 0x0F);
X
X        /* byte 2 */
X        printf("\tModulator Level Scaling: 0x%02x\n", instrument_buf[2] >> 4);
X        printf("\tModulator Output Level: 0x%02x\n", instrument_buf[2] & 0x3f);
X
X        /* byte 3 */
X        printf("\tCarrier Level Scaling: 0x%02x\n", instrument_buf[3] >> 4);
X        printf("\tCarrier Output Level: 0x%02x\n", instrument_buf[3] & 0x3f);
X
X        /* byte 4 */
X        printf("\tModulator Attack Rate 0x%02x\n", instrument_buf[5] >> 4);
X        printf("\tModulator Decay Rate 0x%02x\n", instrument_buf[5] & 0xF);
X
X        /* byte 5 */
X        printf("\tCarrier Attack Rate 0x%02x\n", instrument_buf[5] >> 4);
X        printf("\tCarrier Decay Rate 0x%02x\n", instrument_buf[5] & 0xF);
X
X        /* byte 6 */
X        printf("\tModulator Sustain Level 0x%02x\n", instrument_buf[6] >> 4);
X        printf("\tModulator Release Level 0x%02x\n", instrument_buf[6] >> 4);
X
X        /* byte 7 */
X        printf("\tCarrier Sustain Level 0x%02x\n", instrument_buf[7] >> 4);
X        printf("\tCarrier Release Level 0x%02x\n", instrument_buf[7] >> 4);
X
X        /* byte 8 */
X        printf("\tModulator Wave Select 0x%02x\n", instrument_buf[8] & 0x03);
X
X        /* byte 9 */
X        printf("\tCarrier Wave Select 0x%02x\n", instrument_buf[9] & 0x03);
X
X        /* byte A */
X        printf("\tModulator FeedBack 0x%02x\n",
X            (instrument_buf[0xA] >> 1) & 0x07);
X    }
X
X    return(0);
X}
END_OF_FILE
  if test 4479 -ne `wc -c <'./apps/get_instr.c'`; then
    echo shar: \"'./apps/get_instr.c'\" unpacked with wrong size!
  fi
  # end of './apps/get_instr.c'
fi
if test -f './apps/play_cleanup.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/play_cleanup.c'\"
else
  echo shar: Extracting \"'./apps/play_cleanup.c'\" \(767 characters\)
  sed "s/^X//" >'./apps/play_cleanup.c' <<'END_OF_FILE'
X/*
X * Copyrighted as an unpublished work.
X * (c) Copyright 1991 Brian Smith
X * All rights reserved.
X *
X * Read the LICENSE file for details on distribution and use.
X *
X */
X
X#include <sys/types.h>
X#include <sys/ipc.h>
X#include <sys/shm.h>
X
X#define NUMBUFS     2
X#define SHM_BUFSIZ  (8*4096)
X#define SHM_KEY     1796
X
Xtypedef struct {
X    int     not_last_segment[NUMBUFS];
X    int     unlocked[NUMBUFS];
X    char    buf[NUMBUFS*SHM_BUFSIZ];
X}   buf_struct;
X
X
Xmain()
X{
X    int rc;
X    int shmid;
X
X    shmid = shmget(SHM_KEY, sizeof(buf_struct), IPC_CREAT | 0644);
X    if (shmid == -1)
X    {
X        perror("creating shared-mem buffer");
X        exit(-1);
X    }
X
X    rc = shmctl(shmid, IPC_RMID, 0);
X    if (rc == -1)
X        perror("removing segment");
X
X    exit(0);
X}
END_OF_FILE
  if test 767 -ne `wc -c <'./apps/play_cleanup.c'`; then
    echo shar: \"'./apps/play_cleanup.c'\" unpacked with wrong size!
  fi
  # end of './apps/play_cleanup.c'
fi
if test -f './apps/play_cmf.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/play_cmf.1'\"
else
  echo shar: Extracting \"'./apps/play_cmf.1'\" \(450 characters\)
  sed "s/^X//" >'./apps/play_cmf.1' <<'END_OF_FILE'
X.TH PLAY_CMF 1 "3 June 1991"
X.UC 4
X.SH NAME
Xplay_cmf \- decodes and plays a CMF music file.
X.SH SYNOPSIS
X.B play_cmf
X[
X.I file
X]
X.PP
XThe argument must be the CMF file to be played.
X.SH DESCRIPTION
X.B play_cmf
XAttempts to play a CMF file.
X.SH BUGS
XMany CMF files attempt to use Control Change events not understood by the
Xauthor.  Therefore, the program does not implement whatever these
Xcontrol changes are supposed to do.
X.SH AUTHOR
X.PP
XBrian Smith
END_OF_FILE
  if test 450 -ne `wc -c <'./apps/play_cmf.1'`; then
    echo shar: \"'./apps/play_cmf.1'\" unpacked with wrong size!
  fi
  # end of './apps/play_cmf.1'
fi
if test -f './apps/play_snd.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/play_snd.1'\"
else
  echo shar: Extracting \"'./apps/play_snd.1'\" \(657 characters\)
  sed "s/^X//" >'./apps/play_snd.1' <<'END_OF_FILE'
X.TH PLAY_SND 1 "3 June 1991"
X.UC 4
X.SH NAME
Xplay_snd \- plays a raw 8-bit sound file
X.SH SYNOPSIS
X.B play_snd
X[
X.I file
X]
X.PP
XThe argument must be the sound file to be played.
X.SH DESCRIPTION
X.B play_snd
XPlays raw 8-bit sound files, using shared memory and two processes
Xto double buffer reads and writes.  Feel free to use SIGINT (usually
Xcontrol-C) to interrupt the play.  Do NOT, however, use SIGKILL or any
Xother signal to terminate the program.  This leaves unwanted
Xleft-overs, in the form of a shared memory segment.  Use play_cleanup
Xif this happens accidentally.
X
XUse set_speed to change the playing rate of the samples.
X.SH AUTHOR
X.PP
XBrian Smith
END_OF_FILE
  if test 657 -ne `wc -c <'./apps/play_snd.1'`; then
    echo shar: \"'./apps/play_snd.1'\" unpacked with wrong size!
  fi
  # end of './apps/play_snd.1'
fi
if test -f './apps/record_snd.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/record_snd.1'\"
else
  echo shar: Extracting \"'./apps/record_snd.1'\" \(670 characters\)
  sed "s/^X//" >'./apps/record_snd.1' <<'END_OF_FILE'
X.TH RECORD_SND 1 "3 June 1991"
X.UC 4
X.SH NAME
Xrecord_snd \- records a raw 8-bit sound file
X.SH SYNOPSIS
X.B record_snd
X[
X.I file
X]
X.PP
XThe argument must be the sound file to contain the recording.
X.SH DESCRIPTION
X.B record_snd
XRecords raw 8-bit sound files, using shared memory and two processes
Xto double buffer reads and writes.  Use SIGINT (usually control-C) to
Xstop the recording.  Do NOT, however, use SIGKILL or any other signal
Xto terminate the program.  This leaves unwanted left-overs, in the
Xform of a shared memory segment.  Use play_cleanup if this happens
Xaccidentally.
X
XUse set_speed to change the recording rate of the samples.
X.SH AUTHOR
X.PP
XBrian Smith
END_OF_FILE
  if test 670 -ne `wc -c <'./apps/record_snd.1'`; then
    echo shar: \"'./apps/record_snd.1'\" unpacked with wrong size!
  fi
  # end of './apps/record_snd.1'
fi
if test -f './apps/set_speed.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/set_speed.1'\"
else
  echo shar: Extracting \"'./apps/set_speed.1'\" \(520 characters\)
  sed "s/^X//" >'./apps/set_speed.1' <<'END_OF_FILE'
X.TH SET_SPEED 1 "3 June 1991"
X.UC 4
X.SH NAME
Xset_speed \- changes the speed of recording and playing on Sound
XBlaster
X.SH SYNOPSIS
X.B set_speed
X]
X.I speed
X]
X.PP
XThe argument must be the speed (in HZ) for sampling or playing.
X.SH DESCRIPTION
X.B set_speed
XSets the speed of the sampling and playing of the Sound Blaster
Xdriver.  The speed must be greater than (or equal) to 4000Hz, and less
Xthan 24000Hz.  Speeds in excess of 13000Hz will be truncated to
Xapproximately 13000Hz by any recording.
X.SH AUTHOR
X.PP
XBrian Smith
END_OF_FILE
  if test 520 -ne `wc -c <'./apps/set_speed.1'`; then
    echo shar: \"'./apps/set_speed.1'\" unpacked with wrong size!
  fi
  # end of './apps/set_speed.1'
fi
if test -f './apps/set_speed.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/set_speed.c'\"
else
  echo shar: Extracting \"'./apps/set_speed.c'\" \(778 characters\)
  sed "s/^X//" >'./apps/set_speed.c' <<'END_OF_FILE'
X/*
X * Copyrighted as an unpublished work.
X * (c) Copyright 1991 Brian Smith
X * All rights reserved.
X *
X * Read the LICENSE file for details on distribution and use.
X *
X */
X
X#include <sys/fcntl.h>
X#include <sys/sb.h>
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int fd;
X    int speed;
X
X    if (argc != 2)
X    {
X        printf("usage: %s <speed>\n", argv[0]);
X        exit(-1);
X    }
X    speed = atoi(argv[1]);
X    if ((speed < 4000) || (speed > 24000))
X    {
X        printf("usage: %s <speed>\n", argv[0]);
X        printf("\tspeed must be between 4000 and 24000");
X        exit(-1);
X    }
X
X    fd = open("/dev/sbdsp", O_RDONLY);
X    if (fd == -1)
X    {
X        perror("opening SoundBlaster");
X        exit(-1);
X    }
X
X    ioctl(fd, DSP_IOCTL_SPEED, speed);
X
X    exit(0);
X}
END_OF_FILE
  if test 778 -ne `wc -c <'./apps/set_speed.c'`; then
    echo shar: \"'./apps/set_speed.c'\" unpacked with wrong size!
  fi
  # end of './apps/set_speed.c'
fi
if test -f './apps/snd_norm.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/snd_norm.1'\"
else
  echo shar: Extracting \"'./apps/snd_norm.1'\" \(492 characters\)
  sed "s/^X//" >'./apps/snd_norm.1' <<'END_OF_FILE'
X.TH SND_NORM 1 "3 June 1991"
X.UC 4
X.SH NAME
Xsnd_norm \- normalizes a sound file
X.SH SYNOPSIS
X.B snd_norm
X[
X.I old file
X]
X[
X.I new file
X]
X.PP
XThe arguments are the input and output of the normalization.
X.SH DESCRIPTION
X.B snd_norm
XThe input file is normalized, such that the larget amplitude 127, thus
Xobtaining the larget volume from a file (for a given volume setting on
Xthe actual Sound Blaster).  Usefull for post-processing recordings
Xwhich are barely audible.
X.SH AUTHOR
X.PP
XBrian Smith
END_OF_FILE
  if test 492 -ne `wc -c <'./apps/snd_norm.1'`; then
    echo shar: \"'./apps/snd_norm.1'\" unpacked with wrong size!
  fi
  # end of './apps/snd_norm.1'
fi
if test -f './apps/snd_norm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/snd_norm.c'\"
else
  echo shar: Extracting \"'./apps/snd_norm.c'\" \(1777 characters\)
  sed "s/^X//" >'./apps/snd_norm.c' <<'END_OF_FILE'
X/*
X * Copyrighted as an unpublished work.
X * (c) Copyright 1991 Brian Smith
X * All rights reserved.
X *
X * Read the LICENSE file for details on distribution and use.
X *
X */
X
X#include <stdio.h>
X#include <sys/fcntl.h>
X#include <sys/unistd.h>
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int fd, new_fd, rc, max_wave;
X    unsigned char tmp_byte;
X    int tmp_int;
X    int i;
X    double augmentation;
X
X    if (argc != 3)
X    {
X        printf("usage: %s <oldfile> <newfile>\n", argv[0]);
X        exit(-1);
X    }
X
X    fd = open(argv[1], O_RDONLY);
X    if (fd == -1)
X    {
X        perror("opening oldfile");
X        exit(-1);
X    }
X
X    new_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
X    if (new_fd == -1)
X    {
X        perror("opening newfile");
X        exit(-1);
X    }
X
X    printf("normalizing from input file..");
X    fflush(stdout);
X    i = 0;
X    max_wave = 0;
X    while(1)
X    {
X        i++ ; i &= 0x7FFF;
X        if (!i)
X            write(1, ".", 1);
X
X        rc = read(fd, &tmp_byte, 1);
X        if (rc == 0)
X            break;
X        tmp_int = tmp_byte - 128;
X        if (abs(tmp_int) > max_wave)
X            max_wave = abs(tmp_int);
X    }
X    write(1, "\n", 1);
X
X    augmentation = (double)0x80 / (double)max_wave;
X    printf("max_wave\t%d\n", max_wave);
X    printf("augmentation\t%f\n", augmentation);
X
X
X    /* write out new file */
X    lseek(fd, 0, SEEK_SET);
X    while (1)
X    {
X        rc = read(fd, &tmp_byte, 1);
X        if (rc == 0)
X            break;
X
X        tmp_int = tmp_byte - 128;
X        tmp_int *= augmentation;
X        tmp_int += 128;
X
X        tmp_byte = tmp_int;
X
X        rc = write(new_fd, &tmp_byte, 1);
X        if (rc != 1)
X        {
X            perror("writing to new_fd");
X            exit(-1);
X        }
X    }
X        
X
X    return(0);
X}
END_OF_FILE
  if test 1777 -ne `wc -c <'./apps/snd_norm.c'`; then
    echo shar: \"'./apps/snd_norm.c'\" unpacked with wrong size!
  fi
  # end of './apps/snd_norm.c'
fi
if test -f './apps/tst_fm_note.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/tst_fm_note.c'\"
else
  echo shar: Extracting \"'./apps/tst_fm_note.c'\" \(2049 characters\)
  sed "s/^X//" >'./apps/tst_fm_note.c' <<'END_OF_FILE'
X/*
X * Copyrighted as an unpublished work.
X * (c) Copyright 1991 Brian Smith
X * All rights reserved.
X *
X * Read the LICENSE file for details on distribution and use.
X *
X */
X
X#include <sys/fcntl.h>
X#include <sys/signal.h>
X#include <sys/sb.h>
X#include <stdio.h>
X#include <memory.h>
X
Xvoid handler()
X{
X    return;
X}
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int fd;
X    int rc;
X    int i;
X    int note;
X    int fnum;
X    int block;
X    static unsigned char instrument_buf[16] = {
X        0x11, 0x01, 0x8a, 0x40,
X        0xf1, 0xf1, 0x11, 0xb3,
X        0x00, 0x00, 0x06, 0x00,
X        0x00, 0x00, 0x00, 0x00 
X    };
X    sb_fm_character note_character;
X
X    sigset(SIGINT, handler);
X
X    fd = open("/dev/sbfm", O_WRONLY);
X    if (fd == -1)
X    {
X        perror("opening fm device");
X        return(-1);
X    }
X
X    /* test reset */
X    rc = ioctl(fd, FM_IOCTL_RESET);
X    if (rc == -1)
X    {
X        perror("fm chips reset");
X        exit(-1);
X    }
X
X    /* test setting an instrument */
X    for (i=0 ; i<9; i++)
X    {
X        /* set instrument characteristics */
X        note_character.voice_num = i;
X        memset(note_character.data, (char)0, 16);
X        memcpy(note_character.data, instrument_buf, 16);
X        rc = ioctl(fd, FM_IOCTL_SET_VOICE, (int)&note_character);
X        if (rc == -1)
X        {
X            perror("fm chips voice set");
X            exit(-1);
X        }
X
X        /* set note to play */
X        fnum = 686;
X        block = i;
X        note_num(note) = i;
X        fnum_low(note) = fnum & 0xFF;
X        keyon_blk_fnum(note) = 0;
X        keyon_blk_fnum(note) |= 1<<5;                   /* KEYON bit */
X        keyon_blk_fnum(note) |= (block & 7) << 2;       /* block/octave */
X        keyon_blk_fnum(note) |= (fnum & 0x3FF) >> 8;    /* top 2 bits of fnum */
X
X        /* test note on/off */
X        rc = ioctl(fd, FM_IOCTL_NOTE_ON, note);
X        if (rc == -1)
X        {
X            perror("fm chips voice on");
X            exit(-1);
X        }
X    }
X
X    /* wait for ^C */
X    sigpause(SIGINT);
X    close(fd);
X    return(0);
X}
END_OF_FILE
  if test 2049 -ne `wc -c <'./apps/tst_fm_note.c'`; then
    echo shar: \"'./apps/tst_fm_note.c'\" unpacked with wrong size!
  fi
  # end of './apps/tst_fm_note.c'
fi
if test -f './apps/tst_fm_open.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/tst_fm_open.c'\"
else
  echo shar: Extracting \"'./apps/tst_fm_open.c'\" \(415 characters\)
  sed "s/^X//" >'./apps/tst_fm_open.c' <<'END_OF_FILE'
X/*
X * Copyrighted as an unpublished work.
X * (c) Copyright 1991 Brian Smith
X * All rights reserved.
X *
X * Read the LICENSE file for details on distribution and use.
X *
X */
X
X#include <sys/fcntl.h>
X#include <sys/sb.h>
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int fd;
X
X    fd = open("/dev/sbfm", O_WRONLY);
X    if (fd == -1)
X        perror("opening fm device");
X    else
X        close(fd);
X
X    return(0);
X}
END_OF_FILE
  if test 415 -ne `wc -c <'./apps/tst_fm_open.c'`; then
    echo shar: \"'./apps/tst_fm_open.c'\" unpacked with wrong size!
  fi
  # end of './apps/tst_fm_open.c'
fi
if test -f './apps/tst_instr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./apps/tst_instr.c'\"
else
  echo shar: Extracting \"'./apps/tst_instr.c'\" \(4064 characters\)
  sed "s/^X//" >'./apps/tst_instr.c' <<'END_OF_FILE'
X/*
X * Copyrighted as an unpublished work.
X * (c) Copyright 1991 Brian Smith
X * All rights reserved.
X *
X * Read the LICENSE file for details on distribution and use.
X *
X */
X
X#include <sys/fcntl.h>
X#include <sys/unistd.h>
X#include <sys/sb.h>
X#include <stdio.h>
X
X#define lobyte(X)   (((unsigned char *)&X)[0])
X#define hibyte(X)   (((unsigned char *)&X)[1])
X
X/* Globals */
Xint fm_herz;        /* clock ticks per second */
Xint tempo;          /* clock ticks per quarter note */
Xint fm_fd;
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int cmf_fd;
X
X    if (argc != 2)
X    {
X        printf("usage: %s <cmf file>\n", argv[0]);
X        exit(-1);
X    }
X
X    /* open cmf file */
X    cmf_fd = open(argv[1], O_RDONLY);
X    if (cmf_fd == -1)
X    {
X        printf("usage: %s <cmf file>\n", argv[0]);
X        exit(-1);
X    }
X
X    /* verify that file is a cmf file */
X    if (!verify_cmf(cmf_fd))
X    {
X        printf("file was not a cmf file\n");
X        printf("usage: %s <cmf file>\n", argv[0]);
X        exit(-1);
X    }
X
X    /* read and set instruments from cmf file */
X    set_instruments(cmf_fd);
X
X    /* play song */
X    play_song(cmf_fd);
X
X    return(0);
X}
X
X
X/* check for "CTMF" in first four bytes of file */
Xint verify_cmf(fd)
Xint fd;
X{
X    char idbuf[5];
X
X    /* get id */
X    lseek(fd, 0, SEEK_SET);
X    if (read(fd, idbuf, 4) != 4)
X        return(FALSE);
X    
X    /* compare to standard id */
X    idbuf[4] = (char)0;
X    if (strcmp(idbuf, "CTMF") != 0)
X        return(FALSE);
X    
X    return(TRUE);
X}
X
Xint set_instruments(fd)
Xint fd;
X{
X    int offset;
X    int num_instruments;
X    int i;
X    int rc;
X    int fnum, block, note;
X    unsigned char tmp_byte;
X    sb_fm_character note_character;
X
X    /* open soundblaster fm chips */
X    fm_fd = open("/dev/sbfm", O_WRONLY);
X    if (fm_fd == -1)
X    {
X        perror("opening fm chips");
X        exit(-1);
X    }
X
X    /* get offset of instrument block */
X    offset = 0;
X    lseek(fd, 0x06, SEEK_SET);
X    read(fd, &tmp_byte, 1);
X    lobyte(offset) = tmp_byte;
X    read(fd, &tmp_byte, 1);
X    hibyte(offset) = tmp_byte;
X
X    /* get number of instruments */
X    num_instruments = 0;
X    lseek(fd, 0x24, SEEK_SET);
X    read(fd, &tmp_byte, 1);
X    lobyte(num_instruments) = tmp_byte;
X    read(fd, &tmp_byte, 1);
X    hibyte(num_instruments) = tmp_byte;
X
X    if (num_instruments > 9)
X        num_instruments = 9;
X    printf("loading %d instruments\n", num_instruments);
X
X    /* read each instrument */
X    lseek(fd, offset, SEEK_SET);
X    for (i=0; i< num_instruments; i++)
X    {
X        /* set instrument characteristics */
X        note_character.voice_num = i;
X        read(fd, note_character.data, 16);
X        printf("loading instrument: 0x%02x\n", i);
X        rc = ioctl(fm_fd, FM_IOCTL_SET_VOICE, (int)&note_character);
X        if (rc == -1)
X        {
X            perror("fm chips voice set");
X            exit(-1);
X        }
X
X        /* set note to regular C note */
X        fnum = 686;
X        block = 4;
X        note_num(note) = i;
X        fnum_low(note) = fnum & 0xFF;
X        keyon_blk_fnum(note) = 0;
X        keyon_blk_fnum(note) |= 1<<5;                   /* KEYON bit */
X        keyon_blk_fnum(note) |= (block & 7) << 2;       /* block/octave */
X        keyon_blk_fnum(note) |= (fnum & 0x3FF) >> 8;    /* top 2 bits of fnum */
X        ioctl(fm_fd, FM_IOCTL_NOTE_ON, note);
X        sleep(1);
X        ioctl(fm_fd, FM_IOCTL_NOTE_ON, i);
X    }
X
X    return(0);
X}
X
X
X/*
X * get and set timing parameters
X */
Xvoid set_timing(fd)
Xint fd;
X{
X    unsigned char tmp_byte;
X
X    /* get tempo */
X    tempo = 0;
X    lseek(fd, 0x0C, SEEK_SET);
X    read(fd, &tmp_byte, 1);
X    tempo = (unsigned int)tmp_byte;
X    read(fd, &tmp_byte, 1);
X    tempo += (unsigned int)tmp_byte << 8;
X
X    /* get herz of timing clock */
X    fm_herz = 0;
X    lseek(fd, 0x0C, SEEK_SET);
X    read(fd, &tmp_byte, 1);
X    tempo = (unsigned int)fm_herz;
X    read(fd, &tmp_byte, 1);
X    tempo += (unsigned int)fm_herz << 8;
X    
X    return;
X}
X
X
X/*
X * seek to the midi stream and handle midi events for the song
X */
Xint play_song(fd)
Xint fd;
X{
X    return(0);
X}
END_OF_FILE
  if test 4064 -ne `wc -c <'./apps/tst_instr.c'`; then
    echo shar: \"'./apps/tst_instr.c'\" unpacked with wrong size!
  fi
  # end of './apps/tst_instr.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.