home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / sound / sid.sit / HearHere.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-01-09  |  40.1 KB  |  1,448 lines  |  [TEXT/KAHL]

  1. /* *************** HearHere.c -- The HearHere Toolbox ****************** */
  2. /*                                                                       */
  3. /*                          Copyright (C) 1990                           */
  4. /*                              The SID Trio                             */
  5. /*                          All Rights Reserved                          */
  6. /*                                                                       */
  7. /*                                                                       */
  8. /* ********************************************************************* */
  9.  
  10.  
  11. #include <SoundDvr.h>
  12. #include "HearHere.h"            /* external symbolic definitions */
  13.  
  14.  
  15.  
  16. /* ********************************************************************* */
  17. /*                                                                       */
  18. /*                      Internal Symbolic Definitions                    */
  19. /*                                                                       */
  20. /* ********************************************************************* */
  21.  
  22. #define MODEM_PORT_CTL 2            /* Offsets to SCC registers */
  23. #define MODEM_PORT_DATA 6            /* ... */
  24. #define PRITER_PORT_CTL 0            /* ... */
  25. #define PRINTER_PORT_DATA 4            /* ... */
  26.  
  27.  
  28.  
  29. /*****
  30.  *  AppleTalk definitions for serial ports
  31.  *    Note: these are not used but are given as a reference
  32.  *
  33.  */
  34. #define SPConfig (*(char *) 0x1fb)    /* use types for serial ports */
  35. #define PortAUse (*(char *) 0x290)    /* current use of modem port */
  36. #define PortBUse (*(char *) 0x291)    /* current use of printer port */
  37. #define useFree 0x80                  /* port is unused */
  38. #define useATalk 1                    /* configured for AppleTalk */
  39. #define useAsync 2                    /* configured for the serial driver */
  40.  
  41.  
  42.  
  43. /*****
  44.  *  SCC Definitions
  45.  *    Only the registers and bits which are used by HearHere are
  46.  *    defined below.  For a full description of all of the registers
  47.  *    and all of the bit definitions, refer to the Zilog Z8530 
  48.  *    SCC Serial Communications Controller data sheet.
  49.  *
  50.  */
  51.  
  52. #define ReadBase (*(char **) 0x1d8)        /* SCC base read address */
  53. #define WriteBase (*(char **) 0x1dc)    /* SCC base write address */
  54.  
  55.                         /* Read Register 0: transmit/receive buffer
  56.                          * status and external status */
  57. #define RR0        0x00
  58. #define        RXCAVAIL    0x01
  59.  
  60.  
  61.                         /* Write Register 0: CRC initialize, initialization
  62.                          * commands for the various modes, reg pointers */
  63. #define WR0        0x00
  64.  
  65.                         /* Write Register 1: transmit/receive interrupt
  66.                          * and data transfer mode definition */
  67. #define WR1        0x01
  68. #define        EXTINT        0x01
  69.  
  70.                         /* Write Register 3: receive parameters and
  71.                          * control */
  72. #define WR3        0x03
  73. #define        RXENABLE    0x01
  74. #define        RX8BITS        0xc0
  75.     
  76.                         /* Write Register 4: transmit/receive miscellaneous
  77.                          * parameters and modes */
  78. #define WR4        0x04
  79. #define        STOP2        0x0c
  80. #define        X1CLOCK        0x00
  81. #define     X16CLOCK    0x40
  82.  
  83.                         /* Write Register 5: transmit parameters and
  84.                          * control */
  85. #define WR5        0x05
  86. #define     RTS            0x02
  87. #define     TXENABLE    0x08
  88. #define        SBREAK        0x10
  89. #define        TX8BITS        0x60
  90.  
  91.                         /* Write Register 9: master interrupt control 
  92.                          * and reset */
  93. #define WR9        0x09
  94. #define        NV            0x02
  95. #define        MIE            0x08
  96.  
  97.                         /* Write Register 11: clock mode control */
  98. #define WR11    0x0b
  99. #define        TCLOCKBR    0x10
  100. #define        RCLOCKTR    0x20
  101.  
  102.                         /* Write Register 14: miscellaneous control bits */
  103. #define WR14    0x0e
  104. #define        BRENABLE    0x01
  105.  
  106.                         /* Write Register 15: external/status interrupt
  107.                          * control */
  108. #define WR15    0x0f
  109. #define     DCDINT        0x08
  110.  
  111.  
  112.  
  113. /*****
  114.  *  Miscellaneuos definitions
  115.  *
  116.  */
  117. #define MAX_ATTEMPTS 1000        /* maximum attempts waiting for valid */
  118.                                 /* ...audio data before returning FALSE */
  119. #define MAX_FRONTWINDOW 2500    /* maximum size of a front window */
  120.  
  121.  
  122.  
  123. /*****
  124.  *  Global declarations...
  125.  *
  126.  */
  127. int HHLastError;            /* last error from HearHere */
  128. int HHRate;                    /* sampling rate code */
  129. int HHStartThresh;            /* front window starting threshold */
  130. int HHFrontLength;            /* samples in the front window */
  131. int HHMaxWait;                /* max sample wait in front, in 1000's */
  132. int HHQuietThresh;            /* rear window quiet threshold */
  133. int HHRearLength;            /* number of quiet samps in the rear window */
  134. int HHPort;                    /* which port is being accessed */
  135. char *HHCtrlRead;            /* SCC read address for ctrl value */
  136. char *HHCtrlWrite;            /* SCC write address for ctrl value */
  137. char *HHDataRead;            /* SCC read address for data value */
  138. Boolean HHStatus = FALSE;    /* TRUE after INIT, FALSE otherwise */
  139. long SRSave;                /* status register after interrupts disabled */
  140.  
  141.  
  142.  
  143. /*****
  144.  *  The data that the various Mac recording devices sends is received
  145.  *  in the wrong order from standard serial communications.  SoundData
  146.  *  is simply a table which will transform the reversed data input into
  147.  *  the proper 0-255 level that applications and the Mac toolbox expect.
  148.  *
  149.  */
  150.  
  151. unsigned char SoundData[] = {
  152.     0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
  153.     0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
  154.     0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
  155.     0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
  156.     0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
  157.     0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
  158.     0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
  159.     0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
  160.     0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
  161.     0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
  162.     0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
  163.     0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
  164.     0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
  165.     0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
  166.     0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
  167.     0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
  168.     0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
  169.     0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
  170.     0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
  171.     0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
  172.     0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
  173.     0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
  174.     0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
  175.     0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
  176.     0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
  177.     0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
  178.     0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
  179.     0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
  180.     0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
  181.     0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
  182.     0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
  183.     0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
  184. };
  185.  
  186.  
  187.  
  188.  
  189. /* ********************************************************************* */
  190. /*                                                                       */
  191. /*                         *** The Toolbox ***                           */
  192. /*                                                                       */
  193. /* ********************************************************************* */
  194.  
  195.  
  196.  
  197. /*****
  198.  *  HHInit -- Initializes the SCC for the audio device
  199.  *    Parameter:  port - MODEM_PORT or PRINTER_PORT
  200.  *    Returns:    TRUE - valid port
  201.  *                FALSE - invalid port or port assigned to AppleTalk or
  202.  *                    the port is in use - check HHError() for reason
  203.  *    Notes:      This routine turns on the green light of the
  204.  *                Impulse sound digitizer
  205.  *
  206.  */
  207. Boolean HHInit(port)
  208. int port;
  209. {    
  210.     register unsigned char *ctrl,*data;
  211.     register int attempts;
  212.     int i;
  213.     long currentTicks;
  214.     char c;
  215.     
  216.     HHStatus = FALSE;
  217.     
  218.     if (port == MODEM_PORT) {
  219.         HHCtrlRead = ReadBase + 2;
  220.         HHCtrlWrite = WriteBase + 2;
  221.         HHDataRead = ReadBase + 6;
  222.     }
  223.     else
  224.         if (port == PRINTER_PORT) {
  225.             HHCtrlRead = ReadBase + 0;
  226.             HHCtrlWrite = WriteBase + 0;
  227.             HHDataRead = ReadBase + 4;
  228.         }
  229.         else {
  230.             HHLastError = INVALID_PORT;
  231.             return FALSE;
  232.         }
  233.     
  234.     HHPort = port;                /* save the port being accessed */
  235.  
  236.             /*****
  237.              *  Set up the SCC for the audio device
  238.              *
  239.              */
  240.     SCCSet(WR9,NV);
  241.     SCCSet(WR1,EXTINT);            /* external interrupt is for mouse... */
  242.     SCCSet(WR3,(RXENABLE | RX8BITS));
  243.     SCCSet(WR4,(STOP2 | X1CLOCK));
  244.     SCCSet(WR5,(RTS | TXENABLE | SBREAK | TX8BITS));
  245.     SCCSet(WR11,(TCLOCKBR | RCLOCKTR));
  246.     SCCSet(WR14,BRENABLE);
  247.     SCCSet(WR15,DCDINT);        /* CD interrupt for mouse... */
  248.     SCCSet(WR9,(NV | MIE));        /* initialize master interrupt and NV */
  249.  
  250.             /*****
  251.              *  Check to make sure that the audio device is
  252.              *  really out there...
  253.              *
  254.              */
  255.     Delay(1L,¤tTicks);                /* delay for 1/60 second */
  256.     ctrl = (unsigned char *) HHCtrlRead;
  257.     data = (unsigned char *) HHDataRead;
  258.     for (i = 0; i < 5; i++) {
  259.         attempts = 0;
  260.         while ((*ctrl & 0x01) == 0)
  261.             if (++attempts > MAX_ATTEMPTS) {
  262.                 HHLastError = NOT_RESPONDING;
  263.                 return FALSE;
  264.             }
  265.         attempts = attempts;
  266.         c = *data;
  267.     }
  268.              
  269.             /*****
  270.              *  Set default internal conditions
  271.              *
  272.              */
  273.     HHLastError = 0;
  274.     HHRate = 1;                /* default to 22K samples/sec */
  275.     HHStartThresh = 0;        /* no threshold needed */
  276.     HHFrontLength = 0;        /* no front window length */
  277.     HHMaxWait = 0;            /* no timeout possible... */
  278.     HHQuietThresh = 0;        /* samples are never quiet */
  279.     HHRearLength = 0;        /* no rear window length */
  280.     
  281.     HHStatus = TRUE;
  282.     return TRUE;
  283. }
  284.  
  285.  
  286.  
  287. /*****
  288.  *  SCCSet -- Sets an SCC register with a value
  289.  *    Parameters:  reg - the SCC register
  290.  *                 value - the value to set
  291.  *
  292.  */
  293. SCCSet(reg,value)
  294. char reg,value;
  295. {
  296.     *HHCtrlWrite = reg;            /* set SCC register */
  297.     *HHCtrlWrite = value;        /* put the value into the reg */
  298.     
  299.     reg = reg;                    /* add some delay... */
  300.     reg = reg;
  301. }
  302.  
  303.  
  304.  
  305. /*****
  306.  *  HHSample -- Return the current level of the audio device
  307.  *    Parameter:  level - returned value
  308.  *    Returns:    TRUE - value returned
  309.  *                FALSE - check HHError() for error code
  310.  *
  311.  */
  312. Boolean HHSample(level)
  313. int *level;
  314. {
  315.     register unsigned char *data,*ctrl;
  316.     register int attempts;
  317.  
  318.     if (!HHStatus) {
  319.         HHLastError = UNKNOWN_STATE;
  320.         return FALSE;
  321.     }
  322.     
  323.     ctrl = (unsigned char *) HHCtrlRead;
  324.     data = (unsigned char *) HHDataRead;
  325.  
  326.     attempts = 0;
  327.  
  328.     while ((*ctrl & 0x01) == 0)
  329.         if (++attempts > MAX_ATTEMPTS) {
  330.             HHLastError = NOT_RESPONDING;
  331.             return FALSE;
  332.         }
  333.         
  334.     *level = SoundData[*data] & 0xff;
  335.     return TRUE;    
  336. }
  337.  
  338.  
  339.  
  340. /*****
  341.  *  HHSampleRate -- Sets the sampling rate used in HHRecord
  342.  *    Parameter:  rate - sampling rate coefficient where:
  343.  *                     Sample rate = 22000 / rate
  344.  *
  345.  *                     rate    sampling
  346.  *                       1       22254 samples/sec
  347.  *                       2       11127 samples/sec
  348.  *                       3        7418 samples/sec
  349.  *                       4        5564 samples/sec
  350.  *
  351.  *    Returns:    TRUE - rate set
  352.  *                FALSE - check HHError() for error code
  353.  *    Note:       Each sample uses one byte of memory...
  354.  *
  355.  */
  356. Boolean HHSampleRate(rate)
  357. int rate;
  358. {
  359.     if (!HHStatus) {
  360.         HHLastError = UNKNOWN_STATE;
  361.         return FALSE;
  362.     }
  363.     
  364.     if (rate <= 0 || rate > 4) {
  365.         HHLastError = INVALID_RATE;
  366.         return FALSE;
  367.     }
  368.     
  369.     HHRate = rate;
  370.     return TRUE;
  371. }
  372.  
  373.  
  374.  
  375. /*****
  376.  *  HHFrontWindow -- Sets the recording front window parameters
  377.  *    Parameters:  startThresh - threshold of a valid sound
  378.  *                 frontLength - num of samples to save before sound starts
  379.  *                 maxWait - maximum number of samples to wait (in 1000's)
  380.  *    Returns:     TRUE - front window set
  381.  *                 FALSE - check HHError() for error code
  382.  *    Note:        Setting maxWait to -1 will force an indefinite wait
  383.  *                 in a record until a sound is made satisfying the
  384.  *                 threshold conditions.
  385.  *
  386.  */
  387. Boolean HHFrontWindow(startThresh,frontLength,maxWait)
  388. int startThresh,frontLength,maxWait;
  389. {
  390.     if (!HHStatus) {
  391.         HHLastError = UNKNOWN_STATE;
  392.         return FALSE;
  393.     }
  394.     
  395.     if ((startThresh < 0) || (frontLength < 0) || (maxWait < -1)) {
  396.         HHLastError = INVALID_FRONT;
  397.         return FALSE;
  398.     }
  399.     
  400.     if (frontLength > MAX_FRONTWINDOW) {
  401.         HHLastError = INVALID_FRONT;
  402.         return FALSE;
  403.     }
  404.     
  405.     HHStartThresh = startThresh;
  406.     HHFrontLength = frontLength;
  407.     HHMaxWait = maxWait;
  408.     return TRUE;
  409. }
  410.  
  411.  
  412.  
  413. /*****
  414.  *  HHRearWindow -- Sets the recording rear window parameters
  415.  *    Parameters:  quietThresh - threshold of "quiet"
  416.  *                 rearLength - num of quiet samps needed to end recording
  417.  *    Returns:     TRUE - rear window set
  418.  *                 FALSE - check HHError() for error code
  419.  *    Note:        Setting rearLength to zero causes a recording to
  420.  *                 never end because of quietness.
  421.  *
  422.  */
  423. Boolean HHRearWindow(quietThresh,rearLength)
  424. int quietThresh,rearLength;
  425. {
  426.     if (!HHStatus) {
  427.         HHLastError = UNKNOWN_STATE;
  428.         return FALSE;
  429.     }
  430.     
  431.     if ((quietThresh < 0) || (rearLength < 0)) {
  432.         HHLastError = INVALID_REAR;
  433.         return FALSE;
  434.     }
  435.     
  436.     HHQuietThresh = quietThresh;
  437.     HHRearLength = rearLength;
  438.     return TRUE;
  439. }
  440.  
  441.  
  442. /*****
  443.  *  HHRecord -- Record data from the audio device based on HH settings
  444.  *    Parameters:  buffer - address of where to put the data
  445.  *                 bufLen - the maximum number of samples to record
  446.  *                   diskUse - 0 for RAM recording, otherwise it is the refNum
  447.  *                       of a previously opened hard disk file
  448.  *                 mouseFlag - TRUE: mouse movement *WILL* stop recording
  449.  *                             FALSE: movement will not stop recording
  450.  *                 recordLen - the actual number of samples recorded
  451.  *                     positive value: recording ended via rear window
  452.  *                     negative value: recording ended because of mouse
  453.  *                                 -1: recording filled buffer completely
  454.  *    Returns:     TRUE - recording done, check recordLen for more info
  455.  *                 FALSE - check HHError() for error code
  456.  *    Note:        Based on the sample rate, this routine just calls
  457.  *                 one of the two recording routines.  This is needed
  458.  *                 because at the highest sampling rate, excess code
  459.  *                 needs to be removed to guarantee high quality 
  460.  *                 recording on all Macintoshes.
  461.  *                 
  462.  */
  463. Boolean HHRecord(buffer,bufLen,diskUse,mouseFlag,recordLen)
  464. unsigned char *buffer;
  465. long bufLen;
  466. int diskUse;
  467. Boolean mouseFlag;
  468. long *recordLen;
  469. {
  470.     if (HHRate == 1)
  471.         return HHRecHigh(buffer,bufLen,diskUse,mouseFlag,recordLen);
  472.     else
  473.         return HHRecLow(buffer,bufLen,diskUse,mouseFlag,recordLen);
  474. }
  475.  
  476.  
  477.  
  478. /*****
  479.  *  HHRecHigh -- Record data from the audio device at high rate
  480.  *    Note:           This routine is an internal process routine for HHRecord.
  481.  *                   It handles recording when the data rate is at the 22K rate
  482.  *                   because it leaves out some data checks to make the processing
  483.  *                   faster, especially when it is run on a MacPlus or SE.
  484.  *
  485.  *                   If disk recording is requested, this routine just calls another
  486.  *                   routine which handles high data rate recording to disk.
  487.  *                 
  488.  */
  489. Boolean HHRecHigh(buffer,bufLen,diskUse,mouseFlag,recordLen)
  490. unsigned char *buffer;
  491. long bufLen;
  492. int diskUse;
  493. Boolean mouseFlag;
  494. long *recordLen;
  495. {
  496.     register unsigned char *data,*ctrl;
  497.     register unsigned char *bufInsert;
  498.     register unsigned char upperLimit,lowerLimit,level;
  499.     register int attempts,vInt;
  500.     register long vLong;
  501.     unsigned char quietUpper,quietLower;
  502.     unsigned char frontWindow[MAX_FRONTWINDOW];
  503.     unsigned char *bufEnd;
  504.     int *intPtr,prevFlag,constant;
  505.     Boolean filled;                /* TRUE when frontWindow gets filled */
  506.     Boolean interrupt;            /* TRUE when interrupt occured */
  507.     int i;
  508.  
  509.  
  510.     if (!HHStatus) {
  511.         HHLastError = UNKNOWN_STATE;
  512.         return FALSE;
  513.     }
  514.     
  515.             /*****
  516.              *  Handle recording to disk in a completely separate way.
  517.              *  This allows some developers the option of leaving out
  518.              *  this module completely if it is not appropriate for
  519.              *  their application.
  520.              *
  521.              */
  522.     if (diskUse != 0)
  523.         return HHRecToDiskHigh(buffer,bufLen,diskUse,mouseFlag,recordLen);
  524.  
  525.             /*****
  526.              *  Set up as required variables
  527.              *
  528.              */
  529.     ctrl = (unsigned char *) HHCtrlRead;
  530.     data = (unsigned char *) HHDataRead;
  531.     bufInsert = frontWindow;
  532.     upperLimit = 128 + HHStartThresh;
  533.     lowerLimit = 128 - HHStartThresh;
  534.     quietUpper = 128 + HHQuietThresh;
  535.     quietLower = 128 - HHQuietThresh;
  536.     vLong = HHMaxWait * 1000L;
  537.     filled = FALSE;
  538.     interrupt = FALSE;
  539.     
  540.     if (mouseFlag)
  541.         intPtr = (int *) 0x828;            /* interrupt flag */
  542.     else
  543.         intPtr = &constant;                    /* never changes... */
  544.     prevFlag = *intPtr;
  545.  
  546.     
  547.             /*****
  548.              *  Wait for the front window
  549.              *
  550.              */
  551.     while (vLong-- > 0) {
  552.  
  553.         attempts = 0;
  554.             
  555.         while ((*ctrl & 0x01) == 0) {            /* still alive? */
  556.             if (*intPtr != prevFlag) {            /* interrupt? */
  557.                 *recordLen = 0;
  558.                 HHLastError = INTERRUPT;
  559.                 return FALSE;
  560.             }
  561.                 
  562.             if (++attempts > MAX_ATTEMPTS) {
  563.                 HHLastError = NOT_RESPONDING;    /* no, error... */
  564.                 return FALSE;
  565.             }
  566.         }
  567.                 
  568.         level = SoundData[*data];                /* get current level */
  569.         
  570.         *bufInsert++ = level;                        /* save it away */
  571.         
  572.         if (bufInsert == &frontWindow[MAX_FRONTWINDOW]) {
  573.             bufInsert = frontWindow;
  574.             filled = TRUE;                /* circle around the buffer... */
  575.         }
  576.         
  577.         if (level < lowerLimit || level > upperLimit)
  578.             break;
  579.     }
  580.     
  581.     if (vLong <= 0L) {
  582.         HHLastError = TIMEOUT;
  583.         return FALSE;
  584.     }
  585.     
  586.     
  587.             /*****
  588.              *  Front window is satisfied.  Now read the remaining
  589.              *  sound data until the front window or mouse condition
  590.              *  is met...
  591.              *
  592.              */
  593.     
  594.     vLong = (long) bufInsert;    /* save last location of front window */
  595.     bufInsert = buffer + HHFrontLength;    /* leave room for front window */
  596.     upperLimit = quietUpper;    /* get new limits... */
  597.     lowerLimit = quietLower;    /* ... */
  598.     vInt = 0;                    /* count of number of "quiet" samples */
  599.     bufEnd = buffer + bufLen;    /* last buffer location */
  600.     
  601.     if (HHRearLength != 0) {
  602.     
  603.                     /*****
  604.                      *  There IS a rear window
  605.                      *
  606.                      */
  607.         while (vInt < HHRearLength) {
  608.         
  609.             if (*intPtr != prevFlag) {        /* interrupt? */
  610.                 interrupt = TRUE;
  611.                 goto EscapeLoop;
  612.             }
  613.                     
  614.             attempts = 0;
  615.             
  616.             while ((*ctrl & 0x01) == 0) {        /* still alive? */
  617.                 if (++attempts > MAX_ATTEMPTS) {
  618.                     HHLastError = NOT_RESPONDING; /* no, error... */
  619.                     return FALSE;
  620.                 }
  621.             }
  622.                 
  623.             level = SoundData[*data];            /* get current level */
  624.             
  625.             if (level > lowerLimit && level < upperLimit)
  626.                 vInt++;
  627.             else
  628.                 vInt = 0;
  629.         
  630.             *bufInsert++ = level;                    /* save it away */
  631.             
  632.             if (bufInsert == bufEnd)                /* at end of buffer? */
  633.                 break;                                /* yes, stop here */
  634.         }
  635.         
  636.     }
  637.         
  638.     else {
  639.                     /*****
  640.                      *  There is not a rear window
  641.                      *
  642.                      */
  643.         while (bufInsert != bufEnd) {
  644.         
  645.             if (*intPtr != prevFlag) {        /* interrupt? */
  646.                 interrupt = TRUE;
  647.                 goto EscapeLoop;
  648.             }
  649.         
  650.             attempts = 0;
  651.             
  652.             while ((*ctrl & 0x01) == 0)    {            /* still alive? */
  653.                 if (++attempts > MAX_ATTEMPTS) {
  654.                     HHLastError = NOT_RESPONDING;    /* no, error... */
  655.                     return FALSE;
  656.                 }
  657.             }
  658.                 
  659.             level = SoundData[*data];            /* get current level */
  660.             
  661.             *bufInsert++ = level;                /* save it away */
  662.             
  663.         }
  664.         
  665.     }
  666.  
  667. EscapeLoop:    
  668.     if (bufInsert == bufEnd)
  669.         *recordLen = -1;
  670.     else
  671.         *recordLen = (long) bufInsert - (long) buffer;
  672.         
  673.     
  674.             /*****
  675.              *  Put the front window into the data buffer
  676.              *
  677.              */
  678.     bufInsert = (unsigned char *) vLong;    /* last byte of front */
  679.     data = buffer + HHFrontLength;            /* last loc in buffer */
  680.     
  681.     while (data > buffer) {
  682.         if (bufInsert == frontWindow)
  683.             if (filled)
  684.                 bufInsert = &frontWindow[MAX_FRONTWINDOW];
  685.             else {
  686.                 *--data = 128;                /* fill with quiet */
  687.                 continue;
  688.             }
  689.             
  690.         *--data = *--bufInsert;                /* put in next from front */
  691.     }
  692.     
  693.     if (interrupt) {
  694.         HHLastError = INTERRUPT;
  695.         return FALSE;
  696.     }
  697.     
  698.     return TRUE;
  699. }
  700.  
  701.  
  702.  
  703. /*****
  704.  *  HHRecLow -- Record data from the audio device at lower sampling rates
  705.  *    Note:           This routine is an internal process routine for HHRecord.
  706.  *                   It handles recording when the data rate is less than the
  707.  *                   22K rate.
  708.  *
  709.  *                   If disk recording is requested, this routine just calls another
  710.  *                   routine which handles low data rate recording to disk.
  711.  *                 
  712.  */
  713. Boolean HHRecLow(buffer,bufLen,diskUse,mouseFlag,recordLen)
  714. unsigned char *buffer;
  715. long bufLen;
  716. int diskUse;
  717. Boolean mouseFlag;
  718. long *recordLen;
  719. {
  720.     register unsigned char *data,*ctrl;
  721.     register unsigned char *bufInsert;
  722.     register unsigned char upperLimit,lowerLimit,level;
  723.     register int attempts,vInt;
  724.     long vLong;
  725.     unsigned char quietUpper,quietLower;
  726.     unsigned char frontWindow[MAX_FRONTWINDOW];
  727.     unsigned char *bufEnd;
  728.     int *intPtr,prevFlag,constant;
  729.     Boolean filled;                /* TRUE when frontWindow gets filled */
  730.     Boolean interrupt;            /* TRUE when interrupt occured */
  731.     int i;
  732.  
  733.  
  734.     if (!HHStatus) {
  735.         HHLastError = UNKNOWN_STATE;
  736.         return FALSE;
  737.     }
  738.  
  739.             /*****
  740.              *  Handle recording to disk in a completely separate way.
  741.              *  This allows some developers the option of leaving out
  742.              *  this module completely if it is not appropriate for
  743.              *  their application.
  744.              *
  745.              */
  746.     if (diskUse != 0)
  747.         return HHRecToDiskLow(buffer,bufLen,diskUse,mouseFlag,recordLen);
  748.         
  749.             /*****
  750.              *  Set up as required variables
  751.              *
  752.              */
  753.     ctrl = (unsigned char *) HHCtrlRead;
  754.     data = (unsigned char *) HHDataRead;
  755.     bufInsert = frontWindow;
  756.     upperLimit = 128 + HHStartThresh;
  757.     lowerLimit = 128 - HHStartThresh;
  758.     quietUpper = 128 + HHQuietThresh;
  759.     quietLower = 128 - HHQuietThresh;
  760.     vLong = HHMaxWait * 1000L;
  761.     filled = FALSE;
  762.     interrupt = FALSE;
  763.     
  764.     if (mouseFlag)
  765.         intPtr = (int *) 0x828;            /* interrupt flag */
  766.     else
  767.         intPtr = &constant;                    /* never changes... */
  768.     prevFlag = *intPtr;
  769.  
  770.     
  771.             /*****
  772.              *  Wait for the front window
  773.              *
  774.              */
  775.     while (vLong-- > 0) {
  776.  
  777.         for (vInt = 0; vInt < HHRate; vInt++) {        /* handle samp rate */
  778.         
  779.             attempts = 0;
  780.             
  781.             while ((*ctrl & 0x01) == 0) {            /* still alive? */
  782.                 if (*intPtr != prevFlag) {            /* interrupt? */
  783.                     *recordLen = 0;
  784.                     HHLastError = INTERRUPT;
  785.                     return FALSE;
  786.                 }
  787.                 
  788.                 if (++attempts > MAX_ATTEMPTS) {
  789.                     HHLastError = NOT_RESPONDING;    /* no, error... */
  790.                     return FALSE;
  791.                 }
  792.             }
  793.                 
  794.             level = SoundData[*data];                /* get current level */
  795.         }
  796.         
  797.         *bufInsert++ = level;                        /* save it away */
  798.         
  799.         if (bufInsert == &frontWindow[MAX_FRONTWINDOW]) {
  800.             bufInsert = frontWindow;
  801.             filled = TRUE;                /* circle around the buffer... */
  802.         }
  803.         
  804.         if (level < lowerLimit || level > upperLimit)
  805.             break;
  806.     }
  807.     
  808.     if (vLong <= 0L) {
  809.         HHLastError = TIMEOUT;
  810.         return FALSE;
  811.     }
  812.     
  813.             /*****
  814.              *  Front window is satisfied.  Now read the remaining
  815.              *  sound data until the front window or mouse condition
  816.              *  is met...
  817.              *
  818.              */
  819.     
  820.     vLong = (long) bufInsert;    /* save last location of front window */
  821.     bufInsert = buffer + HHFrontLength;    /* leave room for front window */
  822.     upperLimit = quietUpper;    /* get new limits... */
  823.     lowerLimit = quietLower;    /* ... */
  824.     vInt = 0;                    /* count of number of "quiet" samples */
  825.     bufEnd = buffer + bufLen;    /* last buffer location */
  826.     
  827.     if (HHRearLength != 0) {
  828.     
  829.                     /*****
  830.                      *  There IS a rear window
  831.                      *
  832.                      */
  833.         while (vInt < HHRearLength) {
  834.         
  835.             if (*intPtr != prevFlag) {        /* interrupt? */
  836.                 interrupt = TRUE;
  837.                 goto EscapeLoop;
  838.             }
  839.                     
  840.              for (i = 0; i < HHRate; i++) {
  841.                 attempts = 0;
  842.             
  843.                 while ((*ctrl & 0x01) == 0) {        /* still alive? */
  844.                     if (++attempts > MAX_ATTEMPTS) {
  845.                         HHLastError = NOT_RESPONDING; /* no, error... */
  846.                         return FALSE;
  847.                     }
  848.                 }
  849.                 
  850.                 level = SoundData[*data];            /* get current level */
  851.             }
  852.             
  853.             if (level > lowerLimit && level < upperLimit)
  854.                 vInt++;
  855.             else
  856.                 vInt = 0;
  857.         
  858.             *bufInsert++ = level;                    /* save it away */
  859.             
  860.             if (bufInsert == bufEnd)                /* at end of buffer? */
  861.                 break;                                /* yes, stop here */
  862.         }
  863.         
  864.     }
  865.         
  866.     else {
  867.                     /*****
  868.                      *  There is not a rear window
  869.                      *
  870.                      */
  871.         while (bufInsert != bufEnd) {
  872.         
  873.             if (*intPtr != prevFlag) {        /* interrupt? */
  874.                 interrupt = TRUE;
  875.                 goto EscapeLoop;
  876.             }
  877.         
  878.             for (i = 0; i < HHRate; i++) {
  879.                 attempts = 0;
  880.             
  881.                 while ((*ctrl & 0x01) == 0)    {        /* still alive? */
  882.                     if (++attempts > MAX_ATTEMPTS) {
  883.                         HHLastError = NOT_RESPONDING; /* no, error... */
  884.                         return FALSE;
  885.                     }
  886.                 }
  887.                 
  888.                 level = SoundData[*data];            /* get current level */
  889.             }
  890.             
  891.             *bufInsert++ = level;                    /* save it away */
  892.             
  893.         }
  894.         
  895.     }
  896.  
  897. EscapeLoop:    
  898.     if (bufInsert == bufEnd)
  899.         *recordLen = -1;
  900.     else
  901.         *recordLen = (long) bufInsert - (long) buffer;
  902.         
  903.     
  904.             /*****
  905.              *  Put the front window into the data buffer
  906.              *
  907.              */
  908.     bufInsert = (unsigned char *) vLong;    /* last byte of front */
  909.     data = buffer + HHFrontLength;            /* last loc in buffer */
  910.     
  911.     while (data > buffer) {
  912.         if (bufInsert == frontWindow)
  913.             if (filled)
  914.                 bufInsert = &frontWindow[MAX_FRONTWINDOW];
  915.             else {
  916.                 *--data = 128;                /* fill with quiet */
  917.                 continue;
  918.             }
  919.             
  920.         *--data = *--bufInsert;                /* put in next from front */
  921.     }
  922.     
  923.     if (interrupt) {
  924.         HHLastError = INTERRUPT;
  925.         return FALSE;
  926.     }
  927.     
  928.     return TRUE;
  929. }
  930.  
  931.  
  932.  
  933. /*****
  934.  *  HHRecToDiskHigh -- Record data from the audio device directly to disk
  935.  *                 at 22 KHz sampling rate.  This routine is needed
  936.  *                 because at this rate, code must be taken out in order
  937.  *                 to record properly on 8 MHz Macs (SE's and Plus's).
  938.  *    Note:           This routine is an internal process routine for HHRecord.
  939.  *                   It handles the recording of sound input directly to disk
  940.  *                   by double-buffering the data to writing to disk with
  941.  *                   asynchronous I/O's
  942.  *                 
  943.  */
  944. Boolean HHRecToDiskHigh(buffer,bufLen,diskUse,mouseFlag,recordLen)
  945. unsigned char *buffer;
  946. long bufLen;
  947. int diskUse;
  948. Boolean mouseFlag;
  949. long *recordLen;
  950. {
  951.     register unsigned char *data,*ctrl;
  952.     register unsigned char *bufInsert;
  953.     register unsigned char upperLimit,lowerLimit,level;
  954.     register int attempts,vInt;
  955.     long vLong;
  956.     unsigned char quietUpper,quietLower;
  957.     unsigned char frontWindow[MAX_FRONTWINDOW];
  958.     unsigned char *bufEnd;
  959.     unsigned char *altBuffer;
  960.     int whichBuffer;
  961.     int *intPtr,prevFlag,constant;
  962.     Boolean filled;                /* TRUE when frontWindow gets filled */
  963.     Boolean interrupt;            /* TRUE when interrupt occured */
  964.     int i;
  965.     IOParam iop;
  966.     OSErr err;
  967.  
  968.     altBuffer = (unsigned char *) buffer + (bufLen >> 1);
  969.     bufLen >>= 1;
  970.     
  971.     whichBuffer = 1;
  972.     *recordLen = 0;
  973.     bufLen--;
  974.     
  975.     iop.ioCompletion = 0L;
  976.     iop.ioRefNum = diskUse;
  977.     iop.ioVersNum = 0;
  978.     iop.ioPermssn = fsWrPerm;
  979.     iop.ioMisc = 0L;
  980.     iop.ioPosMode = 0;
  981.     iop.ioPosOffset = 0L;
  982.     iop.ioResult = 0;
  983.  
  984.             /*****
  985.              *  Set up as required variables
  986.              *
  987.              */
  988.     ctrl = (unsigned char *) HHCtrlRead;
  989.     data = (unsigned char *) HHDataRead;
  990.     bufInsert = frontWindow;
  991.     upperLimit = 128 + HHStartThresh;
  992.     lowerLimit = 128 - HHStartThresh;
  993.     quietUpper = 128 + HHQuietThresh;
  994.     quietLower = 128 - HHQuietThresh;
  995.     vLong = HHMaxWait * 1000L;
  996.     filled = FALSE;
  997.     interrupt = FALSE;
  998.     
  999.     if (mouseFlag)
  1000.         intPtr = (int *) 0x828;            /* interrupt flag */
  1001.     else
  1002.         intPtr = &constant;                    /* never changes... */
  1003.     prevFlag = *intPtr;
  1004.  
  1005.     while (1) {
  1006.  
  1007.         attempts = 0;
  1008.             
  1009.         while ((*ctrl & 0x01) == 0) {            /* still alive? */
  1010.             if (*intPtr != prevFlag) {            /* interrupt? */
  1011.                 *recordLen = 0;
  1012.                 HHLastError = INTERRUPT;
  1013.                 return FALSE;
  1014.             }
  1015.                 
  1016.             if (++attempts > MAX_ATTEMPTS) {
  1017.                 HHLastError = NOT_RESPONDING;    /* no, error... */
  1018.                 return FALSE;
  1019.             }
  1020.         }
  1021.                 
  1022.         level = SoundData[*data];                /* get current level */
  1023.         
  1024.         if (level < lowerLimit || level > upperLimit)
  1025.             break;
  1026.     }
  1027.  
  1028.  
  1029.  
  1030.     bufInsert = (unsigned char *) buffer;
  1031.     upperLimit = quietUpper;    /* get new limits... */
  1032.     if (HHRearLength == 0)
  1033.         upperLimit = 0;            /* no rear window */
  1034.     lowerLimit = quietLower;    /* ... */
  1035.     vInt = 0;                    /* count of number of "quiet" samples */
  1036.     bufEnd = (unsigned char *) (buffer + bufLen);    /* last buffer location */
  1037.     
  1038.     
  1039.     while (vInt <= HHRearLength) {
  1040.         
  1041.         if (*intPtr != prevFlag) {        /* interrupt? */
  1042.             interrupt = TRUE;
  1043.             goto EscapeLoop;
  1044.         }
  1045.                     
  1046.         attempts = 0;
  1047.             
  1048.         while ((*ctrl & 0x01) == 0) {        /* still alive? */
  1049.             if (++attempts > MAX_ATTEMPTS) {
  1050.                 HHLastError = NOT_RESPONDING; /* no, error... */
  1051.                 return FALSE;
  1052.             }
  1053.         }
  1054.                 
  1055.         level = SoundData[*data];            /* get current level */
  1056.             
  1057.         if (level > lowerLimit && level < upperLimit)
  1058.             vInt++;
  1059.         else
  1060.             vInt = 0;
  1061.         
  1062.         *bufInsert++ = level;                    /* save it away */
  1063.             
  1064.         if (bufInsert == bufEnd) {
  1065.             if (whichBuffer == 1) {
  1066.                 iop.ioBuffer = (Ptr) buffer;
  1067.                 bufInsert = (unsigned char *) altBuffer;
  1068.                 bufEnd = (unsigned char *) (altBuffer + bufLen);
  1069.                 whichBuffer = 2;
  1070.             }
  1071.             else {
  1072.                 iop.ioBuffer = (Ptr) altBuffer;
  1073.                 bufInsert = (unsigned char *) buffer;
  1074.                 bufEnd = (unsigned char *) (buffer + bufLen);
  1075.                 whichBuffer = 1;
  1076.             }
  1077.             iop.ioReqCount = bufLen;
  1078.             err = PBWrite(&iop,TRUE);
  1079.             if (err != noErr) {
  1080.                 HHLastError = DISKFAIL;
  1081.                 return FALSE;
  1082.             }
  1083.             (*recordLen) += bufLen;
  1084.         }
  1085.             
  1086.     }
  1087.     
  1088. EscapeLoop:    
  1089.     
  1090.     while (iop.ioResult > 0)
  1091.         ;
  1092.     
  1093.     while (bufInsert < bufEnd)
  1094.         *bufInsert++ = 128;            /* fill out buffer with silence */
  1095.         
  1096.     if (whichBuffer == 1) {
  1097.         iop.ioBuffer = (Ptr) buffer;
  1098.     }
  1099.     else {
  1100.         iop.ioBuffer = (Ptr) altBuffer;
  1101.     }
  1102.     iop.ioReqCount = bufLen;
  1103.     err = PBWrite(&iop,FALSE);
  1104.     if (err != noErr) {
  1105.         HHLastError = DISKFAIL;
  1106.         return FALSE;
  1107.     }
  1108.     
  1109.     (*recordLen) += bufLen;
  1110.         
  1111.  
  1112.     if (interrupt) {
  1113.         HHLastError = INTERRUPT;
  1114.         return FALSE;
  1115.     }
  1116.     
  1117.     return TRUE;
  1118. }
  1119.  
  1120.  
  1121.  
  1122. /*****
  1123.  *  HHRecToDiskLow -- Record data from the audio device directly to disk
  1124.  *                 at lower than 22 KHz sampling rate.
  1125.  *    Note:           This routine is an internal process routine for HHRecord.
  1126.  *                   It handles the recording of sound input directly to disk
  1127.  *                   by double-buffering the data to writing to disk with
  1128.  *                   asynchronous I/O's
  1129.  *                 
  1130.  */
  1131. Boolean HHRecToDiskLow(buffer,bufLen,diskUse,mouseFlag,recordLen)
  1132. unsigned char *buffer;
  1133. long bufLen;
  1134. int diskUse;
  1135. Boolean mouseFlag;
  1136. long *recordLen;
  1137. {
  1138.     register unsigned char *data,*ctrl;
  1139.     register unsigned char *bufInsert;
  1140.     register unsigned char upperLimit,lowerLimit,level;
  1141.     register int attempts,vInt;
  1142.     long vLong;
  1143.     unsigned char quietUpper,quietLower;
  1144.     unsigned char frontWindow[MAX_FRONTWINDOW];
  1145.     unsigned char *bufEnd;
  1146.     unsigned char *altBuffer;
  1147.     int whichBuffer;
  1148.     int *intPtr,prevFlag,constant;
  1149.     Boolean filled;                /* TRUE when frontWindow gets filled */
  1150.     Boolean interrupt;            /* TRUE when interrupt occured */
  1151.     int i;
  1152.     IOParam iop;
  1153.     OSErr err;
  1154.  
  1155.     altBuffer = (unsigned char *) buffer + (bufLen >> 1);
  1156.     bufLen >>= 1;
  1157.     
  1158.     whichBuffer = 1;
  1159.     *recordLen = 0;
  1160.     bufLen--;
  1161.     
  1162.     iop.ioCompletion = 0L;
  1163.     iop.ioRefNum = diskUse;
  1164.     iop.ioVersNum = 0;
  1165.     iop.ioPermssn = fsWrPerm;
  1166.     iop.ioMisc = 0L;
  1167.     iop.ioPosMode = 0;
  1168.     iop.ioPosOffset = 0L;
  1169.     iop.ioResult = 0;
  1170.  
  1171.             /*****
  1172.              *  Set up as required variables
  1173.              *
  1174.              */
  1175.     ctrl = (unsigned char *) HHCtrlRead;
  1176.     data = (unsigned char *) HHDataRead;
  1177.     bufInsert = frontWindow;
  1178.     upperLimit = 128 + HHStartThresh;
  1179.     lowerLimit = 128 - HHStartThresh;
  1180.     quietUpper = 128 + HHQuietThresh;
  1181.     quietLower = 128 - HHQuietThresh;
  1182.     vLong = HHMaxWait * 1000L;
  1183.     filled = FALSE;
  1184.     interrupt = FALSE;
  1185.     
  1186.     if (mouseFlag)
  1187.         intPtr = (int *) 0x828;            /* interrupt flag */
  1188.     else
  1189.         intPtr = &constant;                    /* never changes... */
  1190.     prevFlag = *intPtr;
  1191.  
  1192.     while (1) {
  1193.  
  1194.         attempts = 0;
  1195.             
  1196.         while ((*ctrl & 0x01) == 0) {            /* still alive? */
  1197.             if (*intPtr != prevFlag) {            /* interrupt? */
  1198.                 *recordLen = 0;
  1199.                 HHLastError = INTERRUPT;
  1200.                 return FALSE;
  1201.             }
  1202.                 
  1203.             if (++attempts > MAX_ATTEMPTS) {
  1204.                 HHLastError = NOT_RESPONDING;    /* no, error... */
  1205.                 return FALSE;
  1206.             }
  1207.         }
  1208.                 
  1209.         level = SoundData[*data];                /* get current level */
  1210.         
  1211.         if (level < lowerLimit || level > upperLimit)
  1212.             break;
  1213.     }
  1214.  
  1215.     bufInsert = (unsigned char *) buffer;
  1216.     upperLimit = quietUpper;    /* get new limits... */
  1217.     if (HHRearLength == 0)
  1218.         upperLimit = 0;            /* no rear window */
  1219.     lowerLimit = quietLower;    /* ... */
  1220.     vInt = 0;                    /* count of number of "quiet" samples */
  1221.     bufEnd = (unsigned char *) (buffer + bufLen);    /* last buffer location */
  1222.     
  1223.     
  1224.     while (vInt <= HHRearLength) {
  1225.         
  1226.         if (*intPtr != prevFlag) {        /* interrupt? */
  1227.             interrupt = TRUE;
  1228.             goto EscapeLoop;
  1229.         }
  1230.                     
  1231.          for (i = 0; i < HHRate; i++) {
  1232.             attempts = 0;
  1233.             
  1234.             while ((*ctrl & 0x01) == 0) {        /* still alive? */
  1235.                 if (++attempts > MAX_ATTEMPTS) {
  1236.                     HHLastError = NOT_RESPONDING; /* no, error... */
  1237.                     return FALSE;
  1238.                 }
  1239.             }
  1240.                 
  1241.             level = SoundData[*data];            /* get current level */
  1242.         }
  1243.             
  1244.         if (level > lowerLimit && level < upperLimit)
  1245.             vInt++;
  1246.         else
  1247.             vInt = 0;
  1248.         
  1249.         *bufInsert++ = level;                    /* save it away */
  1250.             
  1251.         if (bufInsert == bufEnd) {
  1252.             if (whichBuffer == 1) {
  1253.                 iop.ioBuffer = (Ptr) buffer;
  1254.                 bufInsert = (unsigned char *) altBuffer;
  1255.                 bufEnd = (unsigned char *) (altBuffer + bufLen);
  1256.                 whichBuffer = 2;
  1257.             }
  1258.             else {
  1259.                 iop.ioBuffer = (Ptr) altBuffer;
  1260.                 bufInsert = (unsigned char *) buffer;
  1261.                 bufEnd = (unsigned char *) (buffer + bufLen);
  1262.                 whichBuffer = 1;
  1263.             }
  1264.             iop.ioReqCount = bufLen;
  1265.             err = PBWrite(&iop,TRUE);
  1266.             if (err != noErr) {
  1267.                 HHLastError = DISKFAIL;
  1268.                 return FALSE;
  1269.             }
  1270.             (*recordLen) += bufLen;
  1271.         }
  1272.             
  1273.     }
  1274.     
  1275. EscapeLoop:    
  1276.  
  1277.     while (iop.ioResult > 0)
  1278.         ;
  1279.  
  1280.     while (bufInsert < bufEnd)
  1281.         *bufInsert++ = 128;            /* fill out buffer with silence */
  1282.         
  1283.     if (whichBuffer == 1) {
  1284.         iop.ioBuffer = (Ptr) buffer;
  1285.     }
  1286.     else {
  1287.         iop.ioBuffer = (Ptr) altBuffer;
  1288.     }
  1289.     iop.ioReqCount = bufLen;
  1290.     err = PBWrite(&iop,FALSE);
  1291.     if (err != noErr) {
  1292.         HHLastError = DISKFAIL;
  1293.         return FALSE;
  1294.     }
  1295.     
  1296.     (*recordLen) += bufLen;
  1297.         
  1298.  
  1299.     if (interrupt) {
  1300.         HHLastError = INTERRUPT;
  1301.         return FALSE;
  1302.     }
  1303.     
  1304.     return TRUE;
  1305. }
  1306.  
  1307.  
  1308.  
  1309. /*****
  1310.  *  HHDiskPlay -- Outputs previously recorded sound from a disk file
  1311.  *    Parameters:  refNum - the refNum of an open file
  1312.  *                 buffer - a buffer to use for inputting data from the disk
  1313.  *                 bufLen - the length of the buffer
  1314.  *    Returns:     TRUE - successful play
  1315.  *                 FALSE - check HHError() for error code
  1316.  *
  1317.  */
  1318. Boolean HHDiskPlay(refNum,buffer,bufLen)
  1319. int refNum;
  1320. unsigned char *buffer;
  1321. long bufLen;
  1322. {
  1323.     int whichBuffer;
  1324.     long len,ioCount;
  1325.     long ticks;
  1326.     FFSynthPtr b1,b2,b;
  1327.     OSErr err;
  1328.  
  1329.     StopSound();
  1330.     b1 = (FFSynthPtr) buffer;
  1331.     b2 = (FFSynthPtr) ((char *) buffer + (bufLen >> 1));
  1332.     b1->mode = ffMode;
  1333.     b1->count = FixRatio(1,HHRate);
  1334.     b2->mode = ffMode;
  1335.     b2->count = FixRatio(1,HHRate);
  1336.     whichBuffer = 1;
  1337.     len = (bufLen >> 1) - 10;
  1338.     
  1339.     SetSoundVol(7);
  1340.     
  1341.     ioCount = len;
  1342.     err = FSRead(refNum,&ioCount,b1->waveBytes);
  1343.     if (ioCount == 0L) {
  1344.         HHLastError = DISKFAIL;
  1345.         return FALSE;
  1346.     }
  1347.     
  1348.     StartSound(b1,ioCount,0L);
  1349.     Delay(60,&ticks);            /* don't know why I need this...but I do... */
  1350.     
  1351.     while (err == noErr) {
  1352.         whichBuffer = 3 - whichBuffer;
  1353.         if (whichBuffer == 1) {
  1354.             b = b1;
  1355.         }
  1356.         else {
  1357.             b = b2;
  1358.         }
  1359.         
  1360.         ioCount = len;
  1361.         err = FSRead(refNum,&ioCount,b->waveBytes);
  1362.  
  1363.         if (err == noErr) {
  1364.             while (SoundDone() == FALSE)
  1365.                 ;
  1366.             StartSound(b,ioCount,0L);
  1367.         }
  1368.     }
  1369.  
  1370.     while (SoundDone() == FALSE)
  1371.         ;
  1372.     
  1373.     return TRUE;
  1374. }
  1375.  
  1376.  
  1377.  
  1378.  
  1379. /*****
  1380.  *  HHDisableInts -- Disables all interrupts on the Macintosh
  1381.  *      (Included as part of the toolbox to show how to disable interrupts)
  1382.  *
  1383.  */
  1384. void HHDisableInts()
  1385. {
  1386.     asm {
  1387.         move sr,SRSave
  1388.         ori #0x700,sr
  1389.     }
  1390. }
  1391.  
  1392.  
  1393.  
  1394. /*****
  1395.  *  HHEnableInts -- Re-enables all interrupts on the Macintosh
  1396.  *      (Included as part of the toolbox to show how to enable interrupts)
  1397.  *
  1398.  */
  1399. void HHEnableInts()
  1400. {
  1401.     asm {
  1402.         move SRSave,sr                /* enable interrupts */
  1403.     }
  1404. }
  1405.  
  1406.  
  1407.  
  1408. /*****
  1409.  *  HHEnd -- Closes communications with the audio device
  1410.  *    Note:    If HHLastError is set to -1 then HHEnd will be
  1411.  *             allowed to be processed when HHInit wasn't called.
  1412.  *             This allows the resetting of the use flags for
  1413.  *             a developer who knows what they are doing...
  1414.  *
  1415.  */
  1416. Boolean HHEnd()
  1417. {
  1418.     if (!HHStatus && (HHLastError != -1)) {
  1419.         HHLastError = UNKNOWN_STATE;
  1420.         return FALSE;
  1421.     }
  1422.     
  1423.     SCCSet(WR5,0);                        /* turn off recording reference */
  1424.     
  1425.     HHStatus = FALSE;                    /* no longer init'd */
  1426. }
  1427.  
  1428.  
  1429.  
  1430. /*****
  1431.  *  HHError -- Return the last error generated in HearHere
  1432.  *
  1433.  */
  1434. int HHError()
  1435. {
  1436.     return HHLastError;
  1437. }
  1438.  
  1439.  
  1440.  
  1441.  
  1442.  
  1443. /* ********************************************************************* */
  1444. /*                                                                       */
  1445. /*                          End of HearHere.c                            */
  1446. /*                                                                       */
  1447. /* ********************************************************************* */
  1448.