
        AUOPWM Sigma-Delta Audio Driver v1.15
        -------------------------------------
                for VSOS 3.67 or higher
               2026-04-23  VLSI Solution



PWM audio driver converts its input to a sigma-delta encoded mono signal, and
outputs that signal through VS1005's PWM output (pin 88). If the PWM pin
is followed by a proper RC low-pass filter, the PWM output can be used to
implement a high-quality so-called 0.1-channel subwoofer output.

For best results, the accompanying filter should have its -3 dB point at
approximately 200 Hz or lower.



Activating example driver at 16 bits 48 kHz:
# Load Sigma-delta driver
AUOPWM s

Doing the same from the VSOS Shell:
S:>driver +auopwm s






Unloading the beforementioned driver using the VSOS Shell:
S:>driver -auopwm



Opening a Driver:
  // Change name as necessary
  #define LIB_NAME "auxpwmm"

  u_int16 *pwmLib = NULL;
  FILE *pwmFP = NULL;

  pwmLib = LoadLibrary(LIB_NAME);
  if (!pwmLib) {
    printf("Cannot load " LIB_NAME ".DL3 library\n");
    goto finally;
  }
  /* Open */
  pwmFP = (FILE *)RunLoadedFunction(pwmLib, ENTRY_3, 0);
  if (!pwmFP) {
    printf("Cannot open " LIB_NAME ".DL3 audio file\n");
    goto finally;
  }



Closing a driver:
  finally:
  if (pwmFP) {
    /* Close file */
    RunLoadedFunction(pwmLib, ENTRY_4, (s_int16)pwmFP);
    pwmFP = NULL;
  }
  if (pwmLib) {
    DropLibrary(pwmLib);
    pwmLib = NULL;
  }



Fractional sample rate:
  Sample rate is presented as a 32-bit integer. However, particularly
  when streaming, there sometimes is a need to present sample rates
  at greater accuracy. To do this, when setting a sample rate, bits 30:24
  may used presented to present a fractional sample rate in 1/128 Hz
  increments. This is compatible with all VSOS audio drivers: those who
  can't handle fractional sample rates will ignore these bits.

  This driver ignores fractional sample rate information.

  Examples:
  - 44100       Hz is 0x0000ac44.
  - 44100 1/128 Hz is 0x0100ac44.
  - 44100.5     Hz is 0x4000ac44.



Reading Data:
  Character-based reading is NOT supported.

  The only supported read operation is:
  fread(buffer, sizeof(buffer[0]), BUFFER_ELEMENTS, pwmFP);
  where the amount to read must be aligned with whole stereo samples,
  so 2 16-bit words for 16-bit audio, and 4 16-bit words for 32-bit audio!

  For best performance, it is recommended to read at least 16 words at a time.



Writing Data:
  Character-based reading is NOT supported.

  The only supported write operation is:
  fwrite(buffer, sizeof(buffer[0]), BUFFER_ELEMENTS, pwmFP);
  where the amount to write must be aligned with whole stereo samples,
  so 2 16-bit words for 16-bit audio, and 4 16-bit words for 32-bit audio!

  For best performance, it is recommended to write at least 16 words at a time.



IOCTL Controls:
  Restart driver. Normally this needs never be done.
  Example:
    ioctl(pwmFP, IOCTL_RESTART, NULL);

  Get number of bits.
  Example:
    bits = ioctl(pwmFP, IOCTL_AUDIO_GET_BITS, NULL);

  Set number of bits.
  - bits may be 16 or 32
  Example:
    if (ioctl(pwmFP, IOCTL_AUDIO_SET_BITS, (char *)(32))) {
      printf("Couldn't set bits\n");
    }

  Get how many 16-bit words there are free in the output buffer.
  Example:
    iBufFill = ioctl(pwmFP, IOCTL_AUDIO_GET_OUTPUT_BUFFER_FREE, NULL);

  Get output buffer size in 16-bit words.
  Example:
    oBufSize = ioctl(pwmFP, IOCTL_AUDIO_GET_OUTPUT_BUFFER_SIZE, NULL);

  Set output buffer size in 16-bit words.
  Example:
    if (ioctl(pwmFP, IOCTL_AUDIO_SET_OUTPUT_BUFFER_SIZE, (char *)(1024))) {
      printf("Couldn't set output buffer size\n");
    }

  Get sample counter.
  Example:
    s_int32 sampleCounter;
    if (ioctl(pwmFP, IOCTL_AUDIO_GET_SAMPLE_COUNTER, (char *)(&sampleCounter))){
      printf("Couldn't get sample counter\n");
    }

  Get underflow sample counter for the output buffer.
  - Only for drivers with output
  Example:
    s_int32 uFlow;
    if (ioctl(pwmFP, IOCTL_AUDIO_GET_UNDERFLOWS, (char *)(&uFlow))) {
      printf("Couldn't get underflow counter\n");
    }



License:
This code may be used freely in any product containing one or more ICs
by VLSI Solution.


Disclaimer:
Absolutely no guarantee is given for the usability of this code.


Version History:
2026-04-23 HH v1.15 - Improved stability in low-memory conditions.
2023-02-27 HH v1.14 - Buffer size doesn't need to be power of 2 anymore.
2021-03-17 HH v1.01 - Initial public release.
2020-02-18 HH v1.00 - Initial internal release.
