Sfront Reference Manual: Part II/3: Audio Drivers
Description: A part of the Sfront reference manual, that is a collection of reference materials. Sfront is a program that translates MP4-SA files into C programs.
Keywords: MP4-SA, SASL, SAOL, MP4, sfront, command line options.

### From The `sfront` Reference Manual by John Lazzaro and John Wawrzynek.

# Part II/3: Audio Drivers

## Sections Introduction. Driver Structure. How audio drivers work. Initialization. Device setup. Passive Audio Output. Receive samples from output_bus. Passive Audio Input. Send samples to input_bus Active Drivers. Support for callback systems. Synchronization. Updating `cputime`. Shutdown. Ending a session. Registration. Linking drivers to sfront. Summary. | ## Audio Driver Functions asys_osetup asys_isetup asys_iosetup asys_preamble asys_putbuf asys_getbuf asys_main asys_orun asys_iorun ksyncinit ksync asys_oshutdown asys_ishutdown asys_ioshutdown

## Introduction In this chapter, we describe how to add support for new audio file formats and audio hardware devices to `sfront`. Adding a new format or device involves writing an audio driver that is included in the C file sfront creates. Users select the new audio driver through the `-ain` and `-aout` command line options. We begin the chapter by discussing the structure of an audio driver. We describe the functions that an audio driver declares to handle initialization, data movement, and synchronization. We also describe how to register a new driver with sfront, so that a command-line invocation results in the inclusion of the audio driver into the `sa.c` file. | ##

## Driver Structure An audio driver is a file containing a set of C functions. This file is embedded into the sfront executable during compilation, and is copied into the C program sfront creates. Look in `sfront/src/lib/asys/` to see examples of audio driver files. The right panel shows the set of functions contained in an audio driver. In this chapter, we describe the semantics for these functions. Not all audio drivers use all of the functions listed on the right hand panel. Several factors determine the subset of functions that are in use: User directives. Users may request that an audio driver to do audio output, audio input, or both. The functions a driver declares depends on this request. A driver uses the symbols `ASYS_HASOUTPUT` and `ASYS_HASINPUT` to determine its role. Callback support. In many cases, a simple method suffices for the transfer of audio samples between the driver and sfront: the driver declares functions to send and receive data, and sfront calls these functions to do I/O. We call these simple drivers passive drivers. However, some operating systems use a callback technique for audio access: an application registers a function with the operating system, that is called whenever new data is needed for input or output. Sfront supports a second audio driver approach (called active drivers) to handle callback interfaces. Synchronization. Audio drivers may define functions that act to keep the SAOL program execution synchronized with audio input and output. These functions also act to update the SAOL standard name `cputime`, which SAOL programs use to avoid output glitches. #### Naming conventions Audio drivers must be careful when defining functions, variables, and pre-processor symbols for its own use, to avoid name-space collisions. Audio drivers may define elements that begin with `asysn_drivername_` and `ASYS_DRIVERNAME_` , where `drivername` is the name of the audio driver file (sans extension) located in `sfront/src/lib/asys/` If `ASYS_KSYNC` exists, elements that begin with `sync_` and `SYNC_` are also permissible. In addition, if `ASYS_HASOUTPUT` exists, elements that begin with `asyso_` or `ASYSO_` are permissible. If `ASYS_HASINPUT` exists, elements that begin with `asysi_` or `ASYSI_` are permissible. If both `ASYS_HASINPUT` and `ASYS_HASOUTPUT` exist, elements that begin with `asysio_` or `ASYSIO_` are permissible. | ## `Audio Driver Functions` `
    (function arguments not shown)

    Initialization

    int asys_osetup();
    int asys_isetup();
    int asys_iosetup();

    Passive Audio Output

    int asys_preamble();
    int asys_putbuf();

    Passive Audio Input

    int asys_getbuf();

    Active Drivers

    /* declared by driver */

    void asys_main();

    /* called by driver */

    int asys_orun();
    int asys_iorun();

    Synchronization

    int ksyncinit();
    int ksync();

    Shutdown

    int asys_oshutdown();
    int asys_ishutdown();
    int asys_ioshutdown();
`

## Initialization Users select audio input and output drivers through the `-ain` and `-aout` command line options. Depending on the selection, a particular audio driver may be required to supply audio input, audio output, or both audio input and audio output. An audio driver determines its role in an `sa.c` file by detecting if certain pre-processor symbols have been defined, using the pre-processor utilities `ifdef` or `defined` . Specifically, if both `ASYS_HASINPUT` and `ASYS_HASOUTPUT` symbols are defined, an audio driver should perform audio input and audio output. If only one of these symbols is defined, the audio driver should only perform audio input (`ASYS_HASINPUT` defined) or audio output (`ASYS_HASOUTPUT` defined). #### Initialization functions An audio driver declares an initialization function, which is called at the start of program execution. The exact form of the initialization function depends on the status of `ASYS_HASINPUT` and `ASYS_HASOUTPUT` symbols; see the right panel for details. The initialization function should perform the initial setup needed for the audio file type or the audio hardware. If this setup is successful, the function should return ASYS_DONE, a pre-defined constant. If driver setup failed, the function should return ASYS_ERROR. The arguments passed by the initialization function describe the audio input and output environment; the argument list may include: `srate.` Audio sampling rate of the SAOL orchestra. `ochannels.` The number of output audio channels (equal to the pre-defined constant ASYS_OCHAN). `ichannels.` The number of input audio channels (equal to the pre-defined constant ASYS_ICHAN). `*oname.` The output file name, if applicable, or else NULL. `*iname.` The input file name, if applicable, or else NULL `osample.` Output data representation for a sample, see below. `isample.` Input data representation for a sample, see below. `toption.` Has the value ASYS_RENDER (offline processing), ASYS_PLAYBACK (real-time mode) or ASYS_TIMESYNC (alternative real-time mode). See the synchronization section for details. The pre-defined constant ASYS_TIMEOPTION has the same value as `toption`. The exact argument list depends on the function type. #### Audio data types The audio driver states its data type preference as part of the registration procedure. This preference is coded in the `osample` and `isample` variables, which may take on the pre-defined constant values ASYS_SHORT (for 16-bit signed integers) or ASYS_FLOAT (for 32-bit floats). The pre-defined constant ASYS_OTYPENAME has the same value as `osample`, and the pre-defined constant ASYS_ITYPENAME has the same value as `isample`. The correct C keywords for the input and output datatypes are held in the symbols ASYS_OTYPE and ASYS_ITYPE, and may be used in variable declarations. #### Driver identity symbols In some situations, an audio driver may need to know the presence of other drivers active in the system. The symbols `ASYS_OUTDRIVER_XX`, `ASYS_INDRIVER_YY`, and `CSYS_CDRIVER_ZZ` are defined if an audio output driver, audio input driver, or a control driver is present in the system. The actual strings for `XX`, `YY`, and `ZZ` are the fully-capitalized versions of the driver names (either the full symbol following `-cin`, `-ain`, and `-aout`, or the extension for filename drivers). #### Run-time options An audio driver may define command-line options. Users types these options when executing an `sa.c` program that contains the driver, to dynamically configure driver parameters (for example, setting a maximum file size). The right panel describes audio driver parameters in detail. | ## `Initalization Functions` `
    The audio driver declares
    one of three functions for
    initialization, depending
    on user requests. This
    function will be called
    once, at the start of
    program execution.

    If the user requests only
    output driver service, the
    symbol ASYS_HASOUTPUT is
    defined, and the driver
    should declare:

    int asys_osetup(int srate,
                    int ochannels,
                    int osample,
                    char * oname,
                    int toption)

    If the user requests only
    input driver service, the
    symbol ASYS_HASINPUT is
    defined, and the driver
    should declare:

    int asys_isetup(int srate,
                    int ichannels,
                    int isample,
    	        char * iname,
                    int toption)

    If the user requests both
    input and output driver
    service, both ASYS_HASINPUT
    and ASYS_HASOUTPUT are
    defined, and the driver
    should declare:

    int asys_iosetup(int srate,
                     int ichannels,
                     int ochannels,
    		 int isample,
                     int osample,
    		 char * iname,
                     char * oname,
                     int toption)

    These functions should return
    ASYS_DONE if the driver is
    able to operate, and ASYS_ERROR
    if the initialization failed.

    See left panel for description
    of function parameters.
` ## `Audio Driver Parameters` `
    An audio driver may parse the
    command line of its sa.c file
    it is contained in, by accessing:

    int asys_argc;
    char ** asys_argv

    An audio driver may define its own
    command-line flags, so that users
    can configure drivers at runtime.
    A driver must use this convention:

      -asys_xxx[_yyy] [p1 p2]

    where:

    xxx   is the driver name
    yyy   is the option name (if needed)
    p#    is a parameter for the
          option. options can have
          zero, one, or more than one
          parameters. a parameter can
          not start with a - (except
          as the sign of a number)
          and may not contain spaces.

    For example, the linux driver
    could define:

      -asys_linux_size p1

    as an option for setting the size
    of the output data, where

      -asys_linux_size 8bit
      -asys_linux_size 16bit

    are the legal parameter values.
`

## Passive Audio Output In this section, we describe the functions `asys_preamble` and `asys_putbuf` (see right panel for function definitions). Passive audio drivers define these functions to handle audio output. A passive audio driver does not always define the audio output functions: in some cases, the user may only wish to perform audio input. Passive audio drivers should define the audio output functions only if the symbol `ASYS_HASOUTPUT` is defined. #### Basic operation The `asys_preamble` function is called once, at the start of audio playback. The audio driver uses this call to allocate a buffer for audio data, whose location and size it returns to the calling program. The first call to `asys_putbuf` returns this buffer to the audio driver, filled with audio sample data. The audio driver outputs the audio data, and returns a memory buffer to be filled with more samples. This cycle repeats until the program ends. #### Starting Silence An audio output driver that controls a soundcard device should output a period of silence to the soundcard during the `asys_preamble` call. The silent period provides an extra margin of time that sfront may use to compute new sound samples without overruning the soundcard. The silent period also sets the latency of the system. The appropriate length to choose for the silence period depends on the application. Interactive applications demand latencies of a few milliseconds; audio playback applications work best with several hundred milliseconds of latency. The pre-defined symbol `ASYS_LATENCYTYPE` indicates the application type, taking on values `ASYS_HIGHLATENCY` (audio streaming) or `ASYS_LOWLATENCY` (real-time interaction). Audio drivers may use the application type to determine an appropriate latency value, or may use the suggested latency value `ASYS_LATENCY`, which is a floating-point constant with units of seconds. If the pre-defined symbol `ASYS_USERLATENCY` is set to 1, the value of `ASYS_LATENCY` is a user suggestion; if `ASYS_USERLATENCY` is set to 0, the value is a system default value. #### Buffer Management Passive audio output drivers set the nominal buffer size of an audio output operation, by choosing the return value of `*osize` in the `asys_preamble` and `asys_putbuf` functions. In a real-time system, the buffer size should be set to be a small integral fraction of the starting silence period. For example, if a silent period of 3 ms is chosen, a good choice for the buffer size is the amount of storage needed to hold 0.75 ms of audio. This approach maximizes the efficiency of sfront execution, while minimizing the risk that a single late buffer can overrun the system. #### Compute-Ahead Issues If an `sa.c` program is set up as a real-time system, the penalty for computing audio buffers too slowly is obvious: if the interval between `asys_putbuf` calls is too long, the audio buffer may underrun, producing clicks and glitches. However, computing audio buffers too quickly also brings problems. For interactive applications, computing ahead too quickly increases the latency between user action and sound output. For streaming applications, computing too far ahead results in too much memory usage to hold the future audio. To avoid these problems, real-time audio drivers should take steps to limit the compute-ahead of the program. One way to limit the compute-ahead is to allocate a fixed number of buffers during the `asys_preamble` call, whose combined audio time equals the starting silence period. Buffers from this pool are passed to `asys_putbuf` to be filled, then passed to the soundcard to be played, which returns them once the audio plays out. If no free buffers are available to return to `asys_putbuf`, the audio driver sleeps until the soundcard returns a buffer. This scheme limits the compute-ahead of the program, without the use of explicit timekeeping; it works best with soundcard interfaces such as OSS which maintain fixed buffer pools internally. An alternative way to limit the compute-ahead is to explicitly keep track of elapsed time inside the audio driver, using operating system time functions. Audio drivers that use this approach may find it easiest to perform compute-ahead monitoring in the `ksync` function, described in a later section of this chapter. | ## `asys_preamble` `
    int asys_preamble(
        ASYS_OTYPE * asys_obuf[]
        int * osize
        )

    Called once, at the start of
    audio playback. When called,
    *asys_obuf will be set to NULL,
    and *osize will be set to 0.

    On return, *asys_obuf must
    point to an array of ASYS_OTYPE,
    and *osize must be set to the
    number of elements in the array
    to be filled with audio. The
    *osize value must be evenly
    divisible by the number of
    audio output channels, and
    must not be zero.

    Return value should be ASYS_DONE
    if preamble succeeded, ASYS_ERROR
    to terminate the calling program.
` ## `asys_putbuf` `
    int asys_putbuf(
        ASYS_OTYPE * asys_obuf[]
        int * osize
        )

    asys_obuf points to an array
    of audio samples to send to
    the audio output. It is
    guaranteed to be filled on
    channel-contiguous boundaries.

    asys_obuf points to the buffer
    returned by asys_putbuf() on
    the previous call, or for the
    first call to asys_putbuf(),
    the buffer returned by
    sys_preamble().

    In most cases, *osize will be
    identical to the requested
    *osize from the last call.
    In some cases (such as the
    end of the orchestra) it may
    be smaller (but never greater).

    On return, *asys_obuf must point
    to an array of ASYS_OTYPEs, and
    *osize must be set to the number
    of elements in the array to be
    filled with audio. The *osize
    value must be divisible by the
    number of audio output channels,
    and must not be zero.

    Return value should be ASYS_DONE
    if preamble succeeded, ASYS_ERROR
    to terminate the calling program.
` ## `ASYS_TIMEOPTION` `
    The pre-defined constant
    ASYS_TIMEOPTION codes the
    temporal mode of the
    program. It may reflect
    the presence of the
    -render, -playback,
    or -timesync option on the
    sfront command line; if
    these flags do not appear
    on the command line, sfront
    chooses a default value.

    The -render option requests
    off-line file processing:
    ASYS_TIMEOPTION has the
    value ASYS_RENDER.

    The -playback and -timesync
    options requests real-time
    processing: ASYS_TIMEOPTION
    takes on the value
    ASYS_PLAYBACK or ASYS_TIMESYNC
    in this case.

    If an audio output driver
    that interfaces to a soundcard
    finds that -render is in
    effect, it is probably a user
    error: the program may ignore
    the request, or may force an
    exit via an ASYS_ERROR return
    during initialization.
`

## Passive Audio Input Passive audio input drivers route audio input data from a sound file or audio device into the `input_bus` of a SAOL program. The function `asys_getbuf` embodies the passive audio input driver. See the right panel for a complete description of this function. An audio driver should only define the `asys_getbuf` function if the `ASYS_HASINPUT` symbol is defined, indicating the driver was selected via the `-ain` sfront command-line argument. #### Buffer management As described on the right panel, the calling program does not request a specific number of audio samples, and does not provide a buffer to fill. Instead, the audio input driver is free to create an input buffering scheme that works well with the underlying file format or hardware device. #### Compute-Ahead Issues If an audio input driver supports a real-time input device, the `asys_getbuf` may be called before new input samples are ready. In this case, the audio input driver should not return control to the calling program until the new samples are ready. If possible, the driver should block while waiting for new data, so that other processes may run on the machine. Note that by holding control in the fashion, the audio input driver acts to prevent the SAOL program from computing ahead too far. As a result, real-time passive audio drivers usually do not need to provide explicit compute-ahead protection if both `ASYS_HASINPUT` and `ASYS_HASOUTPUT` are defined. | ## `asys_getbuf` `
    int asys_getbuf(
        ASYS_ITYPE * asys_ibuf[],
        int * isize
        );

    The function asys_getbuf is
    called when the sa.c program
    needs new input_bus samples
    in order to continue SAOL
    processing.

    On the first call to asys_getbuf,
    *asys_ibuf will be set to NULL
    and *isize will be set to 0. Upon
    return, *asys_ibuf should point
    to a buffer of *isize audio
    samples, filled with data from
    the input device. ASYS_ITYPE is
    is the sample type indicated by
    isample during initialization.

    On subsequent calls to asys_getbuf,
    *asys_ibuf and *isize hold the
    values provided in the previous
    call. Upon return, *asys_ibuf
    should point to a buffer of fresh
    audio samples, of size *isize.

    The contents of the buffer that
    asys_getbuf should not be changed
    by the audio driver until the next
    call to asys_getbuf.

    An *isize return value of 0
    indicates EOF.

    asys_getbuf() should return
    ASYS_DONE if it was possible
    to process the request,
    including the EOF case.

    ASYS_ERROR should be returned
    for non-EOF error conditions
    (filesystem error, etc).
`

## Active Drivers The passive audio driver concept is not a good match for a soundcard interface that uses callback semantics, such as MacOS X coreaudio. In a callback architecture, applications supply a callback function to the soundcard interface as part of the initialization process. The soundcard interface invokes the callback function whenever an audio data transfer is needed. To support callback semantics, sfront provides an active driver interface as an alternative to normal passive drivers. An audio driver identifies itself as passive or active as part of the registration procedure. Users specify active drivers using the same `-ain` and `-aout` command line options as passive drivers use. An active driver may be selected for input while a passive driver is selected for output, or vice versa; in addition, the same active driver type may be specified as the input and the output driver. However, two different different active drivers may not be selected for use at the same. #### `asys_main` Active output drivers declare the single function `asys_main`, shown on the right panel. This function is called after the SAOL program is initialized, and after all `asys_setup` functions are called. Once `asys_main` is called, it is the responsibility of the active audio driver to control SAOL program execution; the driver exercises this control by calling a service function to compute audio samples. The audio driver exits the `asys_main` function once the SAOL program completes execution. We first discuss active audio drivers that interact with SAOL programs that do not use the `input_bus`. In this case, the symbol `ASYS_ACTIVE_O` is defined, and the service function `asys_orun` is provided to compute new audio samples. See the right panel for a full description of `asys_orun`. To support a callback system, an active audio driver would define a callback function for the soundcard interface to call. This callback function would in turn call `asys_orun` to generate the required number of audio samples on demand. In this approach, the `asys_main` function would go to sleep once the callback function was installed. The callback function would awaken the `asys_main` function once the SAOL program ended, so that the `asys_main` function could return control to the calling program. The callback function becomes aware of the end of the SAOL program by checking the return value of the `asys_orun` function, which returns `ASYS_EXIT` once the program ends. | ## `asys_main` `
    void asys_main(void)

    This function is called
    after SAOL program
    initialization is complete,
    and after all asys_setup
    functions are called.

    When asys_main returns,
    asys_shutdown functions
    are called, and the program
    exits.
` ## `asys_orun` `
    int asys_orun(
        ASYS_OTYPE obuf[],
        int * osize)

    asys_orun is a service
    function, provided for use
    by the active audio driver
    if the SAOL program does
    not use the input_bus. This
    function exists if the
    symbol ASYS_ACTIVE_O exists.

    asys_orun takes the sample
    buffer pointer obuf as an
    argument, writes at most
    the next *osize channel-
    interleaved sample values
    into the buffer, and returns.

    The *osize value received by
    asys_orun must correspond to
    an integral number of audio
    sample periods. The return
    value of *osize is the actual
    number of ASYS_OTYPE
    samples written into obuf.

    If the SAOL program is still
    running, asys_orun returns
    ASYS_DONE; if the SAOL program
    has finished, asys_orun returns
    ASYS_EXIT.
`

#### SAOL programs that use `input_bus` If the SAOL program uses the `input_bus`, sfront provides the `asys_iorun` service function for active drivers to use (see right panel for details). This function accepts two audio buffers: an input array to route to `input_bus`, and an output array to hold generated `output_bus` samples. An active audio driver senses the presence of the `asys_iorun` function by testing to see if the symbol `ASYS_ACTIVE_IO` is defined. If `ASYS_ACTIVE_IO` is defined, `ASYS_ACTIVE_O` is not defined, and `asys_orun` is not available. If an active audio driver is expected to provide audio input and audio output from its device, the symbols `ASYS_HASINPUT` and `ASYS_HASOUTPUT` are defined. In this case, the driver simply passes the audio input to `asys_iorun` as it becomes available, and routes audio output to its device each time `asys_iorun` returns. However, if `ASYS_HASINPUT` or `ASYS_HASOUTPUT` is not defined, the user has specified a passive driver for input or output. In this case, the active driver calls the passive driver functions, in keeping with the semantics of the audio passive driver interface. For example, if `ASYS_HASINPUT` is not defined, the active audio driver calls the `asys_getbuf` function, and passes the buffer returned by this function to `asys_iorun`. If `ASYS_HASOUTPUT` is not defined, the active audio driver calls `asys_preamble` to initialize the passive audio output driver, and then uses `asys_putbuf` to process the audio buffers returned by `asys_iorun`. Basic information about the passive driver, such as channel size and sample data format, may be discovered by examining pre-defined constants such as `ASYS_OCHAN` and `ASYS_OTYPE`. See the initialization section for a description of these constants. | ## `asys_iorun` `
    int asys_iorun(
        ASYS_ITYPE ibuf[],
        int * isize,
        ASYS_OTYPE obuf[],
        int * osize)

    asys_iorun is a service
    function, provided for use
    by the active audio driver
    if the SAOL program uses
    the input_bus. This
    function exists if the
    symbol ASYS_ACTIVE_IO exists.

    asys_iorun takes two
    audio sample buffers as
    input.

    The buffer pointer
    ibuf supplies audio input
    data to route to the SAOL
    input_bus. it contains
    *isize samples, which must
    correspond to an integral
    number of sample periods.

    asys_iorun also takes
    the sample buffer pointer
    obuf as an argument. it
    writes, at most, the next
    *osize channel-interleaved
    sample values into the
    buffer, and returns.

    asys_iorun handles any
    combination of *isize and
    *osize buffers well --
    it computes new audio
    samples until ibuf is
    exhausted, obus is fill,
    or the SAOL program ends.

    If the SAOL program is still
    running, asys_iorun returns
    ASYS_DONE; if the SAOL program
    has finished, asys_iorun returns
    ASYS_EXIT.
`

## Synchronization SAOL programs may read the k-rate standard name `cputime`, to sense the real-time performance of the program. This floating-point variables has a range of 0.0 to 1.0, and codes CPU utilization as in percentage terms. A `cputime` value of 1.0 indicates the edge of real-time performance: any additional load may cause a buffer overrun. Audio drivers can take responsibility for estimating the `cputime` value seen by the SAOL program. A driver requests this task as part of the registration procedure; if this request is granted, the audio driver finds the symbol `ASYS_KSYNC` defined. See the right panel for details about the selection algorithm sfront uses for `cputime` duties. If `ASYS_KSYNC` is defined, the audio driver defines the `ksync` and `ksyncinit` functions (see right panel for details). The `ksync` function is called once per execution cycle, after all audio samples have been computed. The return value of `ksync` is the new estimate of `cputime`. The `ksyncinit` function is called once, right before SAOL program execution begins. #### Computing `cputime` To compute `cputime`, audio drivers estimate the real time used to compute the audio samples, and normalize by the total amount of audio generated during the cycle. The predefined floating-point constant `KTIME` indicates the length of audio generated each execution cycle, in units of seconds. #### Compute-ahead issues Audio drivers may need to actively limit the length of audio compute-ahead during program execution (we discuss compute-ahead issues in detail in an earlier section of this chapter). The `ksync` function is a convenient place to limit compute-head time. To limit compute-ahead, the audio driver compares the elapsed real time with the computer audio time during each `ksync` invocation, and sleeps (or less preferably, spins) if the compute-ahead time exceeds the desired latency of the system. A user may explicitly request this type of active compute-head limit, by using the `-timesync` sfront command-line option. If this option is selected, the constant `ASYS_TIMEOPTION` has the value `ASYS_TIMESYNC`. | ## Selection Algorithm `
    Sfront allocates cputime
    calculation chores using
    the following algorithm.

    If offline render mode is
    in effect (ASYS_TIMEOPTION
    set to ASYS_RENDER), the
    cputime is always set to
    0, and no audio driver
    is assigned cputime duties.

    Elsewise, the audio
    output driver has first
    priority for cputime
    calculation, the audio
    input driver has second
    priority, and a default
    UNIX-only algorithm for
    cputime calculation is
    used if neither audio
    driver requests cputime
    duties.
` ## `ksyncinit` `
    void ksyncinit(void)

    This function is called at
    the start of SAOL program
    execution.

    Audio drivers may use this
    call to initialize global
    state variables. Audio
    driver state variables and
    functions related to
    synchronization should use
    names that begin with sync_
` ## `ksync` `
    float ksync(void)

    This function is called at
    the end of the audio
    output creation phase of
    each execution cycle.

    The return value for this
    function is the cputime
    value presented to the
    SAOL program during the
    next execution cycle. It
    should be a number in
    the range [0.0, 1.0]
`

## Shutdown An audio driver declares a shutdown function, which is called at the end of SAOL program execution. Audio drivers use the shutdown function to cleanly close audio files and hardware devices. The name of the shutdown function depends on the status of `ASYS_HASOUTPUT` and `ASYS_HASINPUT`, as described on the right panel. | ## `Shutdown Functions` `
    The audio driver declares
    one of three functions for
    shutdown, depending on its
    role as an input driver,
    output driver, or input and
    output driver.

    If the user requests only
    output driver service, the
    symbol ASYS_HASOUTPUT is
    defined, and the driver
    should declare:

    void asys_oshutdown(void)

    If the user requests only
    input driver service, the
    symbol ASYS_HASINPUT is
    defined, and the driver
    should declare:

    void asys_ishutdown(void)

    If the user requests both
    input and output driver
    service, both ASYS_HASINPUT
    and ASYS_HASOUTPUT are
    defined, and the driver
    should declare:

    void asys_ioshutdown(void)

    These functions should do
    an orderly shutdown of the
    audio hardware or file
    processing operations.
`

## Registration The right panel shows how to register your audio driver with the `sfront` sources. Registration is necessary in order for sfront to add your control driver flag to the permissible arguments to the `-ain` and `-aout` command line options. | ## Step 1: Create Libraries `
    [1] Place your audio driver foo
    in sfront/src/lib/asys/mydriver.c

    [2] cd sfront/src/lib

    [3] Edit Makefile, and add
    name of your control driver
    to the ASYS list.

    [4] Type "make". This will
    create:

    sfront/src/asyslib.c
    sfront/src/asyslib.h

    which includes an embedded
    version of your driver. Search
    in the files for your driver
    name to verify.

    [5] Whenever you change your
    driver code in sfront/src/lib/asys
    you will need to remake the
    asyslib.c file.
` ## Step 2: Edit `sfront/src/audio.c` `
    In sfront/src/audio.c, make
    these additions, to add driver
    "mydriver".

    [1] Add the constant definition

    #define ADRIVER_MYDRIVER

    top the top of the file. Give it
    the current numerical value of
    ADRIVER_END, and then increase
    the value of ADRIVER_END by 1.

    [2] Add a printf line to the
    function

    void printaudiohelp(void)

    that describes the mydriver
    flags. This will be printed out
    when "sfront -help" is invoked.

    [3] Add if statements to the
    aoutfilecheck and ainfilecheck
    functions, to register the
    driver. If the driver is an
    active driver, add the lines

    aoutflow = ACTIVE_FLOW;

    to the aoutfilecheck addition
    and add

    ainflow = ACTIVE_FLOW;

    to the ainfilecheck addition.
    Also in ainfilecheck, set
    ainlatency to indicate
    interactive input (like a
    microphone):

    ainlatency = LOW_LATENCY_DRIVER;

    or streaming input (like a
    fileread):

    ainlatency = HIGH_LATENCY_DRIVER;

    [4] Add an entry for your driver
    to:

      makeaudiotypeout
      makeaudiotypein
      makeaoutsync
      makeainsync
      makeaouttimedefault
      makeaintimedefault
      makeainparams

    if needed.

    [5] Add your driver to:

    void makeaudiodriver(int num)

      case DRIVER_MYDRIVER:
        makemydriver();
        break;

    This call actually does the code
    insertion into the sa.c file: it
    calls the function created in
    asyslib.c from your driver file,
    which is named makemydriver.
` ## Step 3: Compile `sfront` `
    Type "make" in sfront/src to
    compile sfront with your driver.

    During driver development, you
    should edit your original driver
    source in

    sfront/src/lib/asys/mydriver.c

    then to test first:

    cd sfront/src/lib/
    make

    and then:

    cd sfront/src
    make
`

## Summary For now, this is the end of the sfront reference manual. Soon, I hope to add new chapters describing `sfront` and `sa.c` internals. Return to Table of Contents. | ##

Copyright 1999 John Lazzaro and John Wawrzynek.