#
# vim:sw=4 ts=8:et sta:ft=unknown:textwidth=78
#

Note: This draft represent what will go into manual pages, and hopefully
      handbook.

Summary:

 +--------------------------------------------+
 | 1) Volume Per Channel (VPC)                |
 | 2) New, High Quality Sample Rate Converter |
 | 3) Parametric Software Equalizer           |
 | 4) Transparent / Adaptive Virtual Channel  |
 | 5) Bitperfect                              |
 | 6) Exclusive Access                        |
 | 7) Multichannel 'Matrix' Processing        |
 | 8) NULL Driver                             |
 | 9) Others..                                |
 +--------------------------------------------+



1) Volume Per Channel (VPC)
   ------------------------

    Default: enabled

    Provides: Independent, individual volume control for each
              application/channel/streams without touching master
              "pcm" volume.

    Related ioctls():
        SNDCTL_DSP_GETPLAYVOL, SNDCTL_DSP_SETPLAYVOL,
        SNDCTL_DSP_GETRECVOL, SNDCTL_DSP_SETRECVOL,
        SOUND_MIXER_PCM (compat mode)

    Hints/systcls:

        hint.pcm.X.vpc (default=undefined, enabled)
            0=disable, 1=enable
            Notes: The only place to enable/disable vpc.
                   Enabling/Disabling requires driver reload.

        hw.snd.vpc_reset (default=0)
            1=reset all channels back to 0 dB
            Notes: This switch provides central control to 'restore' all
                   channels volume back to 0dB.

        hw.snd.vpc_0db (default=45)
            default 0 dB relative level
            Notes: Default value for pcm volume. Increasing it will give
                   more room for attenuation control, while decreasing it
                   will give more room for amplification at the cost of
                   possible sound clipping.

        hw.snd.vpc_autoreset (default=1, enabled)
            0=disable, 1=enable
            Notes: By default, channel volume will be reset to 0db
                   relative after the channel is closed which means that any
                   changes will be lost and not preserved. Setting this to '0'
                   will preserve the volume at the cost of possible confusion
                   for other applications trying to re-open the same
                   device (see hw.snd.vpc_reset for possible 'panic' switch to
                   fix the volumes).

        hw.snd.vpc_mixer_bypass (default=1, enabled)
            0=disable, 1=enable
            Notes: The recommended way to use the  VPC feature is
                   to teach/change applications using the proper ioctl():
                       SNDCTL_DSP_GETPLAYVOL, SNDCTL_DSP_SETPLAYVOL,
                       SNDCTL_DSP_GETRECVOL, SNDCTL_DSP_SETRECVOL.
                   However, these ioctls() are rather new and not quite
                   popular yet. By enabling 'mixer bypass' mode, existing
                   applications (mplayer, xmms, etc) can use their own
                   existing mixer logic to control their own opened channel
                   volume.

    OSSv4 Compatibility:
        Mostly, but we did it a 'better' way, like providing a special
        bypass mode for legacy applications.

2) New, High Quality Sample Rate Converter
   ---------------------------------------
   (Codename: feeder_rate, zresampler, z, The Z zsrc, whatever)

    (sample-rate-converte abbreviated as 'src')
    (SINC = Sine Cardinal)

    Default: Compile time enabled, runtime disabled

    Provides: High quality, production quality, scalable, tunable
              sample-rate-converter (and fast too).

    Comparisons: http://people.freebsd.org/~ariff/z_comparison/
                 (require browser with javascript for interactive comparison).

    Hints/sysctls:

        hw.snd.feeder_rate_quality (default=1, Linear Interpolation)
            (0 - 4)
            Notes: 0 = Zero Order Hold (ZOH), fastest, poorest quality. The
                       first ever src was created resembling this form by
                       Cameron Grant <cg@FreeBSD.org>
                   1 = Linear Interpolation, fast, quality subject to personal
                       preferences or usage but technically the quality is
                       poor due to lack of anti-aliasing filter. First
                       materialized by Orion Hodson <orion@FreeBSD.org>, but
                       limited to 16bit samples and 48KHz at most. Later
                       rewritten by Ariff Abdullah <ariff@FreeBSD.org> to
                       support other than 16bit and a wider frequency range.
                  >= 2 Bandlimited SINC Interpolator, technically based on
                       Julius O'Smith's Digital Audio Resampling -
                       http://ccrma.stanford.edu/~jos/resample/ .
                       This implementation takes us one step further by
                       implementing Polyphase banking to boost the conversion
                       speed (at the cost of memory usage) with multiple
                       high-quality polynomial interpolators
                       (Olli Niemitalo
                         http://www.student.oulu.fi/~oniemita/dsp/deip.pdf)
                       to raise the bar of conversion accuracy. It is 100%
                       fixed point, 64bit accumulator with 32bit coefficients
                       and high precision sample buffering.
                       Default quality value is mapped sequentially as:
                       2 = 100dB stopband, 8 taps, 85% bandwidth
                       3 = 100dB stopband, 36 taps, 90% bandwidth
                       4 = 100dB stopband, 164 taps, 97% bandwidth

        hw.snd.feeder_rate_polyphase_max (default=183040)
            Notes: Applicable for SINC interpolator.
                   SINC interpolator works in 2 modes:
                   1) Ordinary coefficients calculation during conversion,
                      slower, but highly economical in terms of memory
                      consumption.
                   2) High Speed Polyphase Banking (default), fast, but
                      require amounts of memory to store all coefficients for
                      all possible phases before the conversion process.
                      Conversion quality is also higher than #1 due to the
                      usage of complex polynomial interpolators which results
                      in better coefficients.
                   This will set the maximum polyphases entries allowable
                   during the process of building resampling filters.  Setting
                   this to 0 will disable polyphase resampling and revert to
                   ordinary SINC #1.

        hw.snd.feeder_rate_presets (strings, read-only)
            Notes: Show the compiled in FEEDER_RATE_PRESETS (note below).

    FEEDER_RATE_PRESETS
        The default rate presets are "100:8:0.85 100:36:0.90 100:164:0.97",
        which is a compile time tunable by defining FEEDER_RATE_PRESETS in
        /etc/make.conf. In its simplest form, defining
            FEEDER_RATE_PRESETS="8 16 32 64 128"
        will create a resampler that will be filtered through 8, 16, 32, 64 or
        128 taps filter.
      Acceptable form:
      * "8 16 ..." simplest form, define taps per-filter.
      * "100:32 ..." stopband-attenuation:taps.
      * "100:32:0.95 .." stopband-attenuation:taps:rolloff/bandwidth.
        Caution: defining too many presets, or a preset with large taps will
        bloat the kernel!

    OSSv4 Compatibility:
        Not relevant. The infrastructure of this src is far, far better
        than 4front OSS.

3) Parametric Software Equalizer  (feeder_eq)
   -----------------------------

    Default: disabled

    Provides: Compile time, Parametric Equalizer through 'bass' and 'treble'
              controls.

              This feature gives 'tone' controls for any pcm streams, either
              for ear-candy or frequency compensation due to variability of
              hardware/speakers/headsets/phones quality or frequency response.

    Hints/systcls:

        hint.pcm.X.eq (default=undefined, disabled)
            0=disable, 1=enable
            Notes: The only place to enable/disable eq.
                   Enabling/Disabling requires driver reload. Enabling will
                   make 'bass' and 'treble' controls appear in mixer
                   applications.

        dev.pcm.X.eq (default=1, enabled)
            0=disable, 1=enable, 2=bypass
            Notes: Once the EQ is enabled, use this sysctl to switch its
                   modes:
                   0=disable - Soft disable the adjustment of the EQ value.
                               Everything is 0dB but the streams will still go
                               through the filter for possible eq_preamp
                               adjustments.
                   1=enable - Enable EQ adjustements.
                   2=bypass - Entirely bypass the EQ filter (as in disabling
                              it). This is different than '0' since this
                              value will be a 'hard' disable, and totally
                              bypass even the eq_preamp processing.

        dev.pcm.X.eq_preamp (default=+0.0dB)
            (-min dB <-> +max dB, depending on presets)
            Notes: feeder_eq is a passive filter, which means that the gain
                   and attenuation are illusions from the listener
                   perspective. Enabling EQ with a -9dB <-> +9dB range means
                   that first the entire stream will be attenuated to -9dB
                   (minus +max dB) and further gain is a process relative to
                   that 0dB point. This will somehow create a lower volume
                   from the listeners perspective. To accomodate that, this
                   sysctl is present to give a slight 'compensation' for such
                   a situation, at the cost of possible sound clipping if
                   applied excessively.

        hw.snd.feeder_eq_exact_rate (default=0, disable)
            Notes: Technically only certain rates are allowable for proper and
                   precise processing (see below, on 'Supported Rates').  This
                   switch will toggle the rigidness of such requirements and
                   even allow sloppy processing for unsupported rates, which
                   is why the default setting is '0' (allow sloppy).

        hw.snd.feeder_eq_presets (strings, read-only)
            Notes: Show the compiled in FEEDER_EQ_PRESETS (note below).

    FEEDER_EQ_PRESETS
        The default rate presets is

 "PEQ:16000,0.2500,62,0.2500:-9,9,1.0:44100,48000,88200,96000,176400,192000"

        which is a compile time tunable by defining FEEDER_EQ_PRESETS in
        /etc/make.conf. The 4 main fields (separated by double colons) and
        subfields separated by commas:

        1) EQ Type:
            PEQ   - Peaking EQ          -or-
            SHELF - Shelving EQ
           Default: 'PEQ'

        2) Tone Parameters:
            Divided by 4 subfields:
                Treble Corner Frequency (in Hz),
                Treble Q (peaking EQ) or S (Shelving) parameter,
                Bass Corner Frequency (in Hz),
                Bass Q (peaking EQ) or S (Shelving) parameter
           Default: '16000,0.2500,62,0.2500'

        3) Gain Range/Step:
            Divided by 3 subfields:
                Minimum attenuation (dB),
                Maximum gain (dB),
                Step level for attenuation/gain
            Default: '-9,9,1.0'

        4) Supported Rates:
            Define as many supported rates as possible, separated by commas.
           Default: '44100,48000,88200,96000,176400,192000'
           Caution: defining too many rates may bloat the kernel!
           This setting will dictate what rate is suitable for processing if
           hw.snd.feeder_eq_exact=1 and reject all other rates that was not
           part of this list.

        Further readings on EQ type, Q or S:

        "Cookbook formulae for audio EQ biquad filter coefficients"
        by Robert Bristow-Johnson  <rbj@audioimagination.com>
        - http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt

    OSSv4 Compatibility:
        Not relevant. The infrastructure of this eq is far, far better
        than 4front OSS.



4) Transparent / Adaptive Virtual Channel
   --------------------------------------

    Default: Enabled for hardware channel which support digital format (ac3),
             disabled for others.

    Provides: Transparent digital passthrough and adaptive/dynamic format/rate
              channel mixing.

              With this feature, disabling vchans are no longer needed in
              order to make digital format pass through.  It also makes vchans
              more dynamic by choosing a better format/rate among all the
              concurrent streams, which means that
              dev.pcm.X.[rec|play].vchan[format|rate] becomes sort of
              optional.

    Hints/sysctls:

        dev.pcm.X.[play|rec].vchanmode (default=depends...)
            'fixed' or '0':
                The good old mode. Channel mixing is done using fixed
                format/rate. Digital passthrough or other advanced operations
                will not work in this mode (consider it as a 'legacy' mode).
                For hardware channels that doesn't support digital formats, this
                is the default mode.

            'passthrough' or '1':
                Channel mixing is done using fixed format/rate, but advanced
                operations such as digital passthrough or 'Exclusive Access'
                (#6 down below) will start working. All channels should
                produce sound as usual until there is a request for a digital
                format playback, which in this case will 'mute' other channels
                and let the latest incoming digital format pass through
                undisturbed. Multiple / concurrent digital streams are
                supported, but the LATEST stream will take precedence and
                mute all other streams.

            'adaptive' or '2':
                Advanced mode. Works like much like'passthrough' mode, but is
                a bit smarter, especially for multiple pcm channels with
                different format/rate. Whenever a new channel is about to start,
                it will scan the entire list of virtual channels and decide which
                format/rate is the best (mostly, the higher/bigger). This will
                ensure that the quality of mixing depends on the best of all
                channels. The (bad) side effect of this mode is that the
                hardware DMA needs to be restarted and might cause annoying
                pops/clicks, but for a long running playback, this issue
                might be acceptable. Any changes for current format/rate can
                be seen through the output of sysctl
                dev.pcm.[play|rev].vchan[format|rate].

    OSSv4 Compatibility:
        4front OSS incapable of doing this magic.

5) Bitperfect
   ----------

    Default: disabled

    Provides: Pristine, pure pcm stream directly to your 'hardware'. In this
              mode the channel will avoid/skip all kinds of dsp processing
              (channel matrixing, rate converter, eq, etc)

    Related ioctls():
        SNDCTL_DSP_COOKMODE (0=enable bitperfect, 1=disable bitperfect)
        Notes: The 'soft' way of enabling/disabling bitperfect mode,
               per-application.

    Hints/sysctls:
        dev.pcm.X.bitperfect (default=0)
            (0=disable, 1=enable)
            Notes: This sysctl provides the 'hard' way of enabling bitperfect.

    Caveats/Notes:
        * 'hardware' in this sense is kind of relative. If vchans are enabled,
          the bitperfectness will consider default vchan format/rate as the
          definitive format/rate target. The true, recommended way to enable
          pure bitperfect is to disable vchans and use dev.pcm.X.bitperfect
          -or- SNDCTL_DSP_COOKEDMODE instead.
        * Enabling bitperfect either way (sysctl or ioctl()) will cause funny
          results in vchan+'adaptive' mode.

    OSSv4 Compatibility:
        SNDCTL_DSP_COOKEDMODE is mostly compatible, except that it will handle
        complex situation with vchans enabled 'better' compared to 4front OSS.

6) Exclusive Access
   ----------------

    Default: Disabled, applicable only together with vchans with vchanmode
             'passthrough' and above.

    Provides: This feature provides the same effect of vchan 'passthrough'
              mode (muting all other streams/channels), but works with any type
              of pcm stream as long as the application uses open() with
              O_EXCL mode. Consider it as a some sort of 'urgent' notification
              for applications that requires it, maybe or maybe not.

    How:
        open("/dev/dsp", O_<insert your typical open mode> | O_EXCL);

    OSSv4 Compatibility:
        This feature is mostly compatible with OSSv4, except that 4front OSS
        prevents all other applications from running (stalled/halted, other
        unknown grave effects) if any sound device being accessed in a such
        way.  FreeBSD does this smartly on top of the Transparent / Adaptive
        Virtual Channel.

7) Multichannel 'Matrix' Processing
   --------------------------------

    Default: Enabled

    Provides: The core component for multi channel matrixing, seamless
              any-to-any channel conversion and routing.
              This matrix processor supports processing up to 18 channels
              interleaved, but currently limits itself to just 8 channels
              (known as 7.1) as a maximum (intentionally). It can handle
              reduction, expansion or re-routing channels depending on
              internally defined complex matrix mapping. It provides a base
              interface for related multichannel ioctls. It also works with or
              without vchans.

              Notes: Implementation on specific hardware drivers not yet
                     completed, but trivial. Example of possible matrix usages
                     is currently implemented in snd_uaudio(4) to handle
                     quirky swapped channels.

    Related ioctls():
        SNDCTL_DSP_GET_CHNORDER:
            get channel interleaving order.
        SNDCTL_DSP_SET_CHNORDER:
            set channel interleaving order.
        SNDCTL_DSP_GETCHANNELMASK (kind of 'obsolete', but who cares?)
            vlc uses this to detect possible multichannel capability.

    Hints/sysctls:
        hw.snd.report_soft_matrix (default=1, enabled)
            Notes: This will allow seamless channel matrixing regardless of
                   supported hardware or not, which means that you can play
                   multichannel streams (mplayer -channel 6/8) even with
                   simple stereo soundcard.
        dev.pcm.X.[play|rec].vchanformat: (default=s16le:2.0)
            Notes: These sysctls have been extended to allow the following
                   notions:
                   1.0 = mono
                   2.0 = stereo
                   2.1 = 3 channels (left, right, LFE)
                   3.0 = 3 channels (left, right, rear center)
                   4.0 = 4 channels (Quadraphonic: front/rear left and right)
                   4.1 = 5 channels (4.0 + LFE)
                   5.0 = 5 channels (4.0 + center)
                   5.1 = 6 channels (4.0 + center + LFE)
                   6.0 = 6 channels (4.0 + front/rear center)
                   6.1 = 7 channels (6.0 + LFE)
                   7.1 = 8 channels (4.0 + center + LFE + side left and right)

    OSSv4 Compatibility:
        Good enough, though 4front claims that their implementation of
        CHNORDER is sort of incomplete and subject to more butchering.


8) NULL Driver XXX (underway)
    Default: Not enabled, but buildable on i386 and amd64 as part of modules
             compilation.

    Provides: Loopback driver.


9) Others.. XXX
    * most feeder_* stuffs are compilable in userland. Let's not speculate
      whether we should go all out for it (save that for FreeBSD 12.0-RELEASE)
    * kobj signature fixups  Andriy Gapon <avg@freebsd.org>
    * pull out channel mixing logic out of vchan.c and create its own
      feeder_mixer
    * various refactoring here and there.
    * opt_snd.h for possible compile time configuration:
      (mostly for debugging purposes)
        SND_DEBUG
        SND_DIAGNOSTIC
        SND_FEEDER_MULTIFORMAT
        SND_FEEDER_FULL_MULTIFORMAT
        SND_FEEDER_RATE_HP
        SND_PCM_64
        SND_OLDSTEREO