Logo Search packages:      
Sourcecode: alsa-driver version File versions  Download package

hpifunc.c

/******************************************************************************

    AudioScience HPI driver
    Copyright (C) 1997-2003  AudioScience Inc. <support@audioscience.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of version 2 of the GNU General Public License as
    published by the Free Software Foundation;

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

Hardware Programming Interface (HPI) functions

(C) Copyright AudioScience Inc. 1996,1997, 1998
*******************************************************************************/

#define HPI_GENERATE_FUNCTIONS 1
#include "hpi.h"

#ifndef HPI_KERNEL_MODE
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>       // for log10 in meter get level
#endif

// local prototypes

#define UNUSED(param) (void)param

void HPI_InitMessage(HPI_MESSAGE * phm, u16 wObject, u16 wFunction);
u32 HPI_IndexesToHandle(const char cObject, const u16 wIndex1,
                  const u16 wIndex2);
void HPI_HandleToIndexes(const u32 dwHandle, u16 * pwIndex1, u16 * pwIndex2);
u32 HPI_IndexesToHandle3(const char cObject, const u16 wIndex1,
                   const u16 wIndex2, const u16 wIndex0);
void HPI_HandleToIndexes3(const u32 dwHandle, u16 * pwIndex1, u16 * pwIndex2,
                    u16 * pwIndex0);

#ifdef HAS_AES18_ON_HOST
void AES18_Message(int wControlType, HPI_MESSAGE * phm, HPI_RESPONSE * phr);
void Aes18_Init(void);
#endif

#define HPI_HANDLETOINDEXES(h,i1,i2) if (h==0) return HPI_ERROR_INVALID_OBJ; else HPI_HandleToIndexes(h,i1,i2)
#define HPI_HANDLETOINDEXES3(h,i1,i2,i0) if (h==0) return HPI_ERROR_INVALID_OBJ; else HPI_HandleToIndexes3(h,i1,i2,i0)

///////////////////////////////////////////////////////////////////////////
/**\defgroup subsys HPI Subsystem
\{
*/
static HPI_HSUBSYS ghSubSys;  // not really used

HPI_HSUBSYS *HPI_SubSysCreate(void)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;

      memset(&ghSubSys, 0, sizeof(HPI_HSUBSYS));
#ifndef HPI_KERNEL_MODE       //----------------- not Win95,WinNT,WDM kernel

      if (HPI_DriverOpen())
#endif

      {
            HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_OPEN);
            HPI_Message(&hm, &hr);

            if (hr.wError == 0)
                  return (&ghSubSys);
#ifndef HPI_KERNEL_MODE       //----------------- not Win95,WinNT,WDM kernel

            else
                  HPI_DriverClose();
#endif

      }
      return (NULL);
}

void HPI_SubSysFree(HPI_HSUBSYS * phSubSys)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;

// tell HPI to shutdown
      HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CLOSE);
      HPI_Message(&hm, &hr);

#ifndef HPI_KERNEL_MODE       // not Win95,WinNT,WDM kernel

      HPI_DriverClose();
#endif
}

u16 HPI_SubSysGetVersion(HPI_HSUBSYS * phSubSys, u32 * pdwVersion)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;

      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_GET_VERSION);
      HPI_Message(&hm, &hr);
      *pdwVersion = hr.u.s.dwVersion;
      return (hr.wError);
}

u16 HPI_SubSysGetInfo(HPI_HSUBSYS * phSubSys,
                  u32 * pdwVersion,
                  u16 * pwNumAdapters, u16 awAdapterList[], u16 wListLength)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_GET_INFO);

      HPI_Message(&hm, &hr);

      *pdwVersion = hr.u.s.dwVersion;
      if (wListLength > HPI_MAX_ADAPTERS)
            memcpy(awAdapterList, &hr.u.s.awAdapterList, HPI_MAX_ADAPTERS);
      else
            memcpy(awAdapterList, &hr.u.s.awAdapterList, wListLength);
      *pwNumAdapters = hr.u.s.wNumAdapters;
      return (hr.wError);
}

u16 HPI_SubSysCreateAdapter(HPI_HSUBSYS * phSubSys,
                      HPI_RESOURCE * pResource, u16 * pwAdapterIndex)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER);
      memcpy(&hm.u.s.Resource, pResource, sizeof(HPI_RESOURCE));

      HPI_Message(&hm, &hr);

      *pwAdapterIndex = hr.u.s.wAdapterIndex;
      return (hr.wError);
}

u16 HPI_SubSysDeleteAdapter(HPI_HSUBSYS * phSubSys, u16 wAdapterIndex)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_DELETE_ADAPTER);
      hm.wAdapterIndex = wAdapterIndex;
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

u16 HPI_SubSysFindAdapters(HPI_HSUBSYS * phSubSys,
                     u16 * pwNumAdapters,
                     u16 awAdapterList[], u16 wListLength)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_FIND_ADAPTERS);

      HPI_Message(&hm, &hr);

      if (wListLength > HPI_MAX_ADAPTERS) {
            memcpy(awAdapterList, &hr.u.s.awAdapterList,
                   HPI_MAX_ADAPTERS * sizeof(u16));
            memset(&awAdapterList[HPI_MAX_ADAPTERS], 0,
                   (wListLength - HPI_MAX_ADAPTERS) * sizeof(u16));
      } else
            memcpy(awAdapterList, &hr.u.s.awAdapterList,
                   wListLength * sizeof(u16));
      *pwNumAdapters = hr.u.s.wNumAdapters;

      return (hr.wError);
}

/// port read/write functions (for use through a VxD or Kernel driver)
00188 u16 HPI_SubSysReadPort8(HPI_HSUBSYS * phSubSys, u16 wAddress, u16 * pwData)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_READ_PORT_8);
      hm.u.s.Resource.r.PortIO.dwAddress = (u32) wAddress;

      HPI_Message(&hm, &hr);

      *pwData = (u16) hr.u.s.dwData;
      return (hr.wError);
}

u16 HPI_SubSysWritePort8(HPI_HSUBSYS * phSubSys, u16 wAddress, u16 wData)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_WRITE_PORT_8);
      hm.u.s.Resource.r.PortIO.dwAddress = (u32) wAddress;
      hm.u.s.Resource.r.PortIO.dwData = (u32) wData;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

///\}
///////////////////////////////////////////////////////////////////////////
/** \defgroup adapter Adapter

@{
*/

u16 HPI_AdapterOpen(HPI_HSUBSYS * phSubSys, u16 wAdapterIndex)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_OPEN);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

      return (hr.wError);

}

u16 HPI_AdapterClose(HPI_HSUBSYS * phSubSys, u16 wAdapterIndex)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_CLOSE);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/*!
Given an object type HPI_OBJ_*, index, and adapter index,
Determine if the object exists, and if so the dsp index of the object.
Implementation is non-trivial only for multi-DSP adapters

/return u16 an error code HPI_ERROR_*
*/
00257 u16 HPI_AdapterFindObject(const HPI_HSUBSYS * phSubSys, u16 wAdapterIndex,    //< Index of adapter to search
                    u16 wObjectType,      //< Type of object HPI_OBJ_*
                    u16 wObjectIndex,     //< Index of object
                    u16 * pDspIndex //< Output the index of the DSP containing the object
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

// contruct the HPI message from the function parameters
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_FIND_OBJECT);
      hm.wAdapterIndex = wAdapterIndex;
      hm.u.a.wAssertId = wObjectIndex;
      hm.u.a.wObjectType = wObjectType;

      HPI_Message(&hm, &hr);  // Find out where the object is
/* HPIs that serve only a single DSP can process this message on the PC, returning
0 in wDspIndex */

      if (hr.wError == 0)
            *pDspIndex = hr.u.a.wAdapterIndex;
      else if (hr.wError == HPI_ERROR_INVALID_FUNC) {
// for backwards compatibility
            *pDspIndex = 0;
            hr.wError = 0;
      }

      return hr.wError;
}

u16 HPI_AdapterSetMode(HPI_HSUBSYS * phSubSys,
                   u16 wAdapterIndex, u32 dwAdapterMode)
{
      return HPI_AdapterSetModeEx(phSubSys, wAdapterIndex, dwAdapterMode,
                            HPI_ADAPTER_MODE_SET);
}

u16 HPI_AdapterSetModeEx(HPI_HSUBSYS * phSubSys,
                   u16 wAdapterIndex, u32 dwAdapterMode, u16 wQueryOrSet)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_SET_MODE);
      hm.wAdapterIndex = wAdapterIndex;
      hm.u.a.dwAdapterMode = dwAdapterMode;
      hm.u.a.wAssertId = wQueryOrSet;
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

u16 HPI_AdapterGetMode(HPI_HSUBSYS * phSubSys,
                   u16 wAdapterIndex, u32 * pdwAdapterMode)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_GET_MODE);
      hm.wAdapterIndex = wAdapterIndex;
      HPI_Message(&hm, &hr);
      if (pdwAdapterMode)
            *pdwAdapterMode = hr.u.a.dwSerialNumber;
      return (hr.wError);
}

u16 HPI_AdapterGetInfo(HPI_HSUBSYS * phSubSys,
                   u16 wAdapterIndex,
                   u16 * pwNumOutStreams, u16 * pwNumInStreams,
//u8   szAdapterName[],
//u16 wStringLen
                   u16 * pwVersion,
                   u32 * pdwSerialNumber, u16 * pwAdapterType)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_GET_INFO);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

      *pwAdapterType = hr.u.a.wAdapterType;
      *pwNumOutStreams = hr.u.a.wNumOStreams;
      *pwNumInStreams = hr.u.a.wNumIStreams;
      *pwVersion = hr.u.a.wVersion;
      *pdwSerialNumber = hr.u.a.dwSerialNumber;
//strncpy( szAdapterName, hr.u.a.szAdapterName, wStringLen );
      return (hr.wError);
}

/*

OR

Gets various attributes of an adapter, such as serial number

u16 HPI_AdapterGetAttribute(
HPI_HSUBSYS *phSubSys,
u16    wAdapterIndex,      // 0..N-1
u16    wAttribute,         // HPI_ATTRIBUTE_SERIALNUMBER
u32    *pdwValue
)
{
}
*/

u16 HPI_AdapterGetAssert(HPI_HSUBSYS * phSubSys,
                   u16 wAdapterIndex,
                   u16 * wAssertPresent,
                   char *pszAssert, u16 * pwLineNumber)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_GET_ASSERT);
      hm.wAdapterIndex = wAdapterIndex;
      HPI_Message(&hm, &hr);

// no assert
      *wAssertPresent = 0;

      if (!hr.wError) {
            *pwLineNumber = (u16) hr.u.a.dwSerialNumber;    // send line number back in the dwSerialNumber field
            if (*pwLineNumber) {
// we have an assert
                  int i;
                  char *Src = (char *)hr.u.a.szAdapterAssert;
                  char *Dst = pszAssert;

                  *wAssertPresent = 1;

// simple version of strncpy (saves linking to a library)
                  for (i = 0; i < STR_SIZE(HPI_STRING_LEN); i++) {
                        char c;
                        c = *Src++;
                        *Dst++ = c;
                        if (c == 0)
                              break;
                  }

            }
      }
      return (hr.wError);
}

/** Extended Get Assert
adds 32 bit 'line number' and dsp index to standard assert

\return u16 error code HPI_ERROR_*
*/
00407 u16 HPI_AdapterGetAssertEx(HPI_HSUBSYS * phSubSys,    ///< HPI subsystem handle
                     u16 wAdapterIndex,   ///<  Adapter to query
                     u16 * wAssertPresent,      ///< OUT* The number of asserts waiting including this one
                     char *pszAssert,     ///< OUT* Assert message, traditionally file name
                     u32 * pdwLineNumber, ///< OUT* Assert number, traditionally line number in file
                     u16 * pwAssertOnDsp  ///< OUT* The index of the DSP that generated the assert
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_GET_ASSERT);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

      *wAssertPresent = 0;

      if (!hr.wError) {
            *pdwLineNumber = hr.u.a.dwSerialNumber;   // send line number back in the dwSerialNumber field
            *wAssertPresent = hr.u.a.wAdapterType;    // count of asserts BEFORE getting this one
            *pwAssertOnDsp = hr.u.a.wAdapterIndex;    // DSP where error occurred

            if (!*wAssertPresent && *pdwLineNumber)
                  *wAssertPresent = 1;    // for backward compatibility. See also hpi4000.c HPI_4000()

            if (*wAssertPresent) {
// we have an assert
                  int i;
                  char *Src = (char *)hr.u.a.szAdapterAssert;
                  char *Dst = pszAssert;

// simple version of strncpy (saves linking to a library)
                  for (i = 0; i < STR_SIZE(HPI_STRING_LEN); i++) {
                        char c;
                        c = *Src++;
                        *Dst++ = c;
                        if (c == 0)
                              break;
                  }

            } else {
                  *pszAssert = 0;
            }
      }
      return (hr.wError);
}

u16 HPI_AdapterTestAssert(HPI_HSUBSYS * phSubSys,
                    u16 wAdapterIndex, u16 wAssertId)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_TEST_ASSERT);
      hm.wAdapterIndex = wAdapterIndex;
      hm.u.a.wAssertId = wAssertId;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_AdapterEnableCapability(HPI_HSUBSYS * phSubSys,
                        u16 wAdapterIndex, u16 wCapability, u32 dwKey)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_ENABLE_CAPABILITY);
      hm.wAdapterIndex = wAdapterIndex;
      hm.u.a.wAssertId = wCapability;
      hm.u.a.dwAdapterMode = dwKey;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_AdapterSelfTest(HPI_HSUBSYS * phSubSys, u16 wAdapterIndex)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_SELFTEST);
      hm.wAdapterIndex = wAdapterIndex;
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

/*! Sets the adapter property specified but the dwProperty field. As of driver version 2.95
the only property supported is HPI_ADAPTER_PROPERTY_ERRATA_1 on an ASI6xxx adapter.

HPI_ADAPTER_PROPERTY_ERRATA_1 supports correcting the CS4224 single sample delay on each Line Out
independently. The sample delay for each stereo line out is bitmapped into dwParamter1, i.e. bit0
applies to Line Out 0 and bit1 applies to Line Out 1 etc. dwParamter2 is unused for this property
and should be set to 0.
\return HPI_ERROR_*
*/
00506 u16 HPI_AdapterSetProperty(HPI_HSUBSYS * phSubSys,    ///< HPI subsystem handle.
                     u16 wAdapterIndex,   ///< Adapter index.
                     u16 wProperty, ///< Adapter property to set. One of HPI_ADAPTER_PROPERTY_*.
                     u16 wParameter1,     ///< Adapter property parameter 1.
                     u16 wParameter2      ///< Adapter property parameter 2.
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_SET_PROPERTY);
      hm.wAdapterIndex = wAdapterIndex;
      hm.u.ax.property_set.wProperty = wProperty;
      hm.u.ax.property_set.wParameter1 = wParameter1;
      hm.u.ax.property_set.wParameter2 = wParameter2;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/*! Gets the adapter property specified but the dwProperty field. As of driver version 2.95
the only property supported is HPI_ADAPTER_PROPERTY_ERRATA_1 on an ASI6xxx adapter.

HPI_ADAPTER_PROPERTY_ERRATA_1 supports correcting the CS4224 single sample delay on each Line Out
independently. The sample delay for each stereo line out is bitmapped into the returned pdwParamter1,
i.e. bit0 applies to Line Out 0 and bit1 applies to Line Out 1 etc. pdwParamter2 is unused for this
property and should be set to 0.
\return HPI_ERROR_*
*/
00536 u16 HPI_AdapterGetProperty(HPI_HSUBSYS * phSubSys,    ///< HPI subsystem handle.
                     u16 wAdapterIndex,   ///< Adapter index.
                     u16 wProperty, ///< Adapter property to set. One of HPI_ADAPTER_PROPERTY_*.
                     u16 * pwParameter1,  ///< Returned adapter property parameter 1.
                     u16 * pwParameter2   ///< Returned adapter property parameter 2.
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ADAPTER, HPI_ADAPTER_GET_PROPERTY);
      hm.wAdapterIndex = wAdapterIndex;
      hm.u.ax.property_set.wProperty = wProperty;

      HPI_Message(&hm, &hr);
      if (!hr.wError) {
            if (pwParameter1)
                  *pwParameter1 = hr.u.ax.property_get.wParameter1;
            if (pwParameter2)
                  *pwParameter2 = hr.u.ax.property_get.wParameter2;
      }

      return (hr.wError);
}

/*! Enumerates adapter properties. To be implemented sometime in the future.

This function allows an application to determine what property a particular adapter supports. Furthermore
the settings for a particular propery can also be established.
\return HPI_ERROR_*
*/
00567 u16 HPI_AdapterEnumerateProperty(HPI_HSUBSYS * phSubSys,    ///< HPI subsystem handle.
                         u16 wAdapterIndex,     ///< Adapter index.
                         u16 wIndex,      ///< Adapter property # to return.
                         u16 wWhatToEnumerate,  ///< Either HPI_ADAPTER_PROPERTY_ENUMERATE_PROPERTIES or HPI_ADAPTER_PROPERTY_ENUMERATE_SETTINGS
                         u16 wPropertyIndex,    ///< Property index.
                         u32 * pdwSetting ///< Returned adapter property, or property setting, depending on wWhatToEnumerate.
    )
{
      return 0;
}

/** @} */

/** \defgroup stream Streams
Perform audio I/O and format conversion
@{
*/
u16 HPI_StreamEstimateBufferSize(HPI_FORMAT * pF,
                         u32 dwHostPollingRateInMilliSeconds,
                         u32 * dwRecommendedBufferSize)
{
// compute bytes per second
      u32 dwBytesPerSecond;
      u32 dwSize;
      u16 wChannels;

      wChannels = pF->wChannels;

      switch (pF->wFormat) {
      case HPI_FORMAT_PCM16_BIGENDIAN:
      case HPI_FORMAT_PCM16_SIGNED:
            dwBytesPerSecond = pF->dwSampleRate * 2L * wChannels;
            break;
      case HPI_FORMAT_PCM24_SIGNED:
            dwBytesPerSecond = pF->dwSampleRate * 3L * wChannels;
            break;
      case HPI_FORMAT_PCM32_SIGNED:
      case HPI_FORMAT_PCM32_FLOAT:
            dwBytesPerSecond = pF->dwSampleRate * 4L * wChannels;
            break;
      case HPI_FORMAT_PCM8_UNSIGNED:
            dwBytesPerSecond = pF->dwSampleRate * 1L * wChannels;
            break;
      case HPI_FORMAT_MPEG_L1:
      case HPI_FORMAT_MPEG_L2:
      case HPI_FORMAT_MPEG_L3:
            dwBytesPerSecond = pF->dwBitRate / 8L;
            break;
      case HPI_FORMAT_DOLBY_AC2:
// Dolby AC-2 is around 256 kBytes/second
            dwBytesPerSecond = 256000L / 8L;
            break;
      default:
            return HPI_ERROR_INVALID_FORMAT;
      }
      dwSize =
          (dwBytesPerSecond * dwHostPollingRateInMilliSeconds * 2) / 1000L;
      *dwRecommendedBufferSize = (dwSize + 4095L) & ~4095L; // round up to nearest 4 K bounday.
      return 0;
}

////////////////////////////////////////////////////////////////////////////
/** \defgroup outstream Ouput Stream

@{
*/
u16 HPI_OutStreamOpen(HPI_HSUBSYS * phSubSys,
                  u16 wAdapterIndex,
                  u16 wOutStreamIndex, HPI_HOSTREAM * phOutStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_OPEN);
      hm.wAdapterIndex = wAdapterIndex;
      hm.u.d.wOStreamIndex = wOutStreamIndex;

      HPI_Message(&hm, &hr);

      if (hr.wError == 0)
            *phOutStream =
                HPI_IndexesToHandle('O', wAdapterIndex, wOutStreamIndex);
      else
            *phOutStream = 0;
      return (hr.wError);
}

u16 HPI_OutStreamClose(HPI_HSUBSYS * phSubSys, HPI_HOSTREAM hOutStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_HOSTBUFFER_FREE);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
      HPI_Message(&hm, &hr);

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_CLOSE);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/**
\deprecated This function has been superseded by HPI_OutStreamGetInfoEx()
*/
00676 u16 HPI_OutStreamGetInfo(HPI_HSUBSYS * phSubSys,
                   HPI_HOSTREAM hOutStream,
                   u16 * pwState,
                   u32 * pdwBufferSize, u32 * pdwDataToPlay)
{
      return (HPI_OutStreamGetInfoEx(phSubSys,
                               hOutStream,
                               pwState,
                               pdwBufferSize, pdwDataToPlay, NULL, NULL)
          );
}

/** Get information about attributes and state of output stream
*/

00691 u16 HPI_OutStreamGetInfoEx(HPI_HSUBSYS * phSubSys,
                     HPI_HOSTREAM hOutStream,
                     u16 * pwState,
                     u32 * pdwBufferSize,
                     u32 * pdwDataToPlay,
                     u32 * pdwSamplesPlayed, u32 * pdwAuxiliaryDataToPlay)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_GET_INFO);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);

      HPI_Message(&hm, &hr);

// only send back data if valid pointers supplied!!
      if (pwState)
            *pwState = hr.u.d.wState;
      if (pdwBufferSize)
            *pdwBufferSize = hr.u.d.dwBufferSize;
      if (pdwDataToPlay)
            *pdwDataToPlay = hr.u.d.dwDataAvailable;
      if (pdwSamplesPlayed)
            *pdwSamplesPlayed = hr.u.d.dwSamplesTransfered;
      if (pdwAuxiliaryDataToPlay)
            *pdwAuxiliaryDataToPlay = hr.u.d.dwAuxilaryDataAvailable;
      return (hr.wError);
}

u16 HPI_OutStreamWrite(HPI_HSUBSYS * phSubSys,
                   HPI_HOSTREAM hOutStream, HPI_DATA * pData)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_WRITE);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
      memcpy(&hm.u.d.u.Data, pData, sizeof(HPI_DATA));

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_OutStreamStart(HPI_HSUBSYS * phSubSys, HPI_HOSTREAM hOutStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_START);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_OutStreamStop(HPI_HSUBSYS * phSubSys, HPI_HOSTREAM hOutStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_STOP);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_OutStreamSinegen(HPI_HSUBSYS * phSubSys, HPI_HOSTREAM hOutStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_SINEGEN);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_OutStreamReset(HPI_HSUBSYS * phSubSys, HPI_HOSTREAM hOutStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_RESET);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_OutStreamQueryFormat(HPI_HSUBSYS * phSubSys,
                       HPI_HOSTREAM hOutStream, HPI_FORMAT * pFormat)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_QUERY_FORMAT);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
      memcpy(&hm.u.d.u.Data.Format, pFormat, sizeof(HPI_FORMAT));

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

// SGT feb-26-99
u16 HPI_OutStreamSetVelocity(HPI_HSUBSYS * phSubSys,
                       HPI_HOSTREAM hOutStream, short nVelocity)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_SET_VELOCITY);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
      hm.u.d.u.wVelocity = nVelocity;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_OutStreamSetPunchInOut(HPI_HSUBSYS * phSubSys,
                         HPI_HOSTREAM hOutStream,
                         u32 dwPunchInSample, u32 dwPunchOutSample)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_SET_PUNCHINOUT);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);

      hm.u.d.u.Pio.dwPunchInSample = dwPunchInSample;
      hm.u.d.u.Pio.dwPunchOutSample = dwPunchOutSample;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_OutStreamAncillaryReset(HPI_HSUBSYS * phSubSys,
                        HPI_HOSTREAM hOutStream, u16 wMode)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_ANC_RESET);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
#ifdef HPI_64BIT
      hm.u.d.u.Data.Format.wChannels = wMode;
#else
      hm.u.d.u.Data.Format.wMode = wMode;
#endif
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

u16 HPI_OutStreamAncillaryGetInfo(HPI_HSUBSYS * phSubSys,
                          HPI_HOSTREAM hOutStream,
                          u32 * pdwFramesAvailable)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_ANC_GET_INFO);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
      HPI_Message(&hm, &hr);
      if (hr.wError == 0) {
            if (pdwFramesAvailable)
                  *pdwFramesAvailable =
                      hr.u.d.dwDataAvailable / sizeof(HPI_ANC_FRAME);
      }
      return (hr.wError);
}

u16 HPI_OutStreamAncillaryRead(HPI_HSUBSYS * phSubSys,
                         HPI_HOSTREAM hOutStream,
                         HPI_ANC_FRAME * pAncFrameBuffer,
                         u32 dwAncFrameBufferSizeInBytes,
                         u32 dwNumberOfAncillaryFramesToRead)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_ANC_READ);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
      hm.u.d.u.Data.dwpbData = (PTR_AS_NUMBER) pAncFrameBuffer;
      hm.u.d.u.Data.dwDataSize =
          dwNumberOfAncillaryFramesToRead * sizeof(HPI_ANC_FRAME);
      if (hm.u.d.u.Data.dwDataSize <= dwAncFrameBufferSizeInBytes)
            HPI_Message(&hm, &hr);
      else
            hr.wError = HPI_ERROR_INVALID_DATA_TRANSFER;
      return (hr.wError);
}

u16 HPI_OutStreamSetTimeScale(HPI_HSUBSYS * phSubSys,
                        HPI_HOSTREAM hOutStream, u32 dwTimeScale)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_SET_TIMESCALE);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);

      hm.u.d.u.dwTimeScale = dwTimeScale;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_OutStreamHostBufferAllocate(HPI_HSUBSYS * phSubSys,
                            HPI_HOSTREAM hOutStream, u32 dwSizeInBytes)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_HOSTBUFFER_ALLOC);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
      hm.u.d.u.Data.dwDataSize = dwSizeInBytes;
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

u16 HPI_OutStreamHostBufferFree(HPI_HSUBSYS * phSubSys, HPI_HOSTREAM hOutStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_OSTREAM, HPI_OSTREAM_HOSTBUFFER_FREE);
      HPI_HANDLETOINDEXES(hOutStream, &hm.wAdapterIndex,
                      &hm.u.d.wOStreamIndex);
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

        /** @} */// outstream
///////////////////////////////////////////////////////////////////////////
/** \defgroup instream Input Stream

@{
*/
u16 HPI_InStreamOpen(HPI_HSUBSYS * phSubSys,
                 u16 wAdapterIndex,
                 u16 wInStreamIndex, HPI_HISTREAM * phInStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      u16 wDspIndex;
      UNUSED(phSubSys);

// only need to make this call for objects that can be distributed
      hr.wError = HPI_AdapterFindObject(phSubSys, wAdapterIndex,
                                HPI_OBJ_ISTREAM, wInStreamIndex,
                                &wDspIndex);

      if (hr.wError == 0) {
            HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_OPEN);
            hm.wDspIndex = wDspIndex;     // overloaded member
            hm.wAdapterIndex = wAdapterIndex;
            hm.u.d.wIStreamIndex = wInStreamIndex;

            HPI_Message(&hm, &hr);

// construct a global (to the audio subsystem) handle from the adapter,DSP
// and stream index
            if (hr.wError == 0)
                  *phInStream =
                      HPI_IndexesToHandle3('I', wAdapterIndex,
                                     wInStreamIndex, wDspIndex);
            else
                  *phInStream = 0;
      } else {
            *phInStream = 0;
      }
      return (hr.wError);
}

u16 HPI_InStreamClose(HPI_HSUBSYS * phSubSys, HPI_HISTREAM hInStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_HOSTBUFFER_FREE);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
      HPI_Message(&hm, &hr);

      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_CLOSE);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_InStreamQueryFormat(HPI_HSUBSYS * phSubSys,
                      HPI_HISTREAM hInStream, HPI_FORMAT * pFormat)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

// contruct the HPI message from the function parameters
      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_QUERY_FORMAT);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
      memcpy(&hm.u.d.u.Data.Format, pFormat, sizeof(HPI_FORMAT));

      HPI_Message(&hm, &hr);  // send the message to all the HPIs

      return (hr.wError);
}

u16 HPI_InStreamSetFormat(HPI_HSUBSYS * phSubSys,
                    HPI_HISTREAM hInStream, HPI_FORMAT * pFormat)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

// contruct the HPI message from the function parameters
      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_SET_FORMAT);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
      memcpy(&hm.u.d.u.Data.Format, pFormat, sizeof(HPI_FORMAT));

      HPI_Message(&hm, &hr);  // send the message to all the HPIs

      return (hr.wError);
}

u16 HPI_InStreamRead(HPI_HSUBSYS * phSubSys,
                 HPI_HISTREAM hInStream, HPI_DATA * pData)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

// contruct the HPI message from the function parameters
      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_READ);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
      memcpy(&hm.u.d.u.Data, pData, sizeof(HPI_DATA));

      HPI_Message(&hm, &hr);  // send the message to all the HPIs

// get the return parameters from the HPI response
      memcpy(pData, &hm.u.d.u.Data, sizeof(HPI_DATA));
      return (hr.wError);
}

u16 HPI_InStreamStart(HPI_HSUBSYS * phSubSys, HPI_HISTREAM hInStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

// contruct the HPI message from the function parameters
      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_START);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);

      HPI_Message(&hm, &hr);  // send the message to all the HPIs

      return (hr.wError);
}

u16 HPI_InStreamStop(HPI_HSUBSYS * phSubSys, HPI_HISTREAM hInStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

// contruct the HPI message from the function parameters
      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_STOP);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);

      HPI_Message(&hm, &hr);  // send the message to all the HPIs

      return (hr.wError);
}

u16 HPI_InStreamReset(HPI_HSUBSYS * phSubSys, HPI_HISTREAM hInStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

// contruct the HPI message from the function parameters
      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_RESET);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);

      HPI_Message(&hm, &hr);  // send the message to all the HPIs

      return (hr.wError);
}

/**
\deprecated This function has been superseded by HPI_InStreamGetInfoEx()
*/
01120 u16 HPI_InStreamGetInfo(HPI_HSUBSYS * phSubSys,
                  HPI_HOSTREAM hOutStream,
                  u16 * pwState,
                  u32 * pdwBufferSize, u32 * pdwDataRecorded)
{
      return (HPI_InStreamGetInfoEx(phSubSys,
                              hOutStream,
                              pwState,
                              pdwBufferSize,
                              pdwDataRecorded, NULL, NULL)
          );
}

u16 HPI_InStreamGetInfoEx(HPI_HSUBSYS * phSubSys,
                    HPI_HISTREAM hInStream,
                    u16 * pwState,
                    u32 * pdwBufferSize,
                    u32 * pdwDataRecorded,
                    u32 * pdwSamplesRecorded,
                    u32 * pdwAuxilaryDataRecorded)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_GET_INFO);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);

      HPI_Message(&hm, &hr);

// only send back data if valid pointers supplied!!
      if (pwState)
            *pwState = hr.u.d.wState;
      if (pdwBufferSize)
            *pdwBufferSize = hr.u.d.dwBufferSize;
      if (pdwDataRecorded)
            *pdwDataRecorded = hr.u.d.dwDataAvailable;
      if (pdwSamplesRecorded)
            *pdwSamplesRecorded = hr.u.d.dwSamplesTransfered;
      if (pdwAuxilaryDataRecorded)
            *pdwAuxilaryDataRecorded = hr.u.d.dwAuxilaryDataAvailable;
      return (hr.wError);
}

u16 HPI_InStreamAncillaryReset(HPI_HSUBSYS * phSubSys, HPI_HISTREAM hInStream, u16 wBytesPerFrame, u16 wMode,     // = HPI_MPEG_ANC_XXX
                         u16 wAlignment, u16 wIdleBit)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_ANC_RESET);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
/*
* Format structure packing
* dwAttributes = wBytesPerFrame
* wFormat = wMode
* wMode = wIdleBit
*/
      hm.u.d.u.Data.Format.dwAttributes = wBytesPerFrame;
      hm.u.d.u.Data.Format.wFormat = (wMode << 8) | (wAlignment & 0xff);
#ifdef HPI_64BIT
      hm.u.d.u.Data.Format.wChannels = wIdleBit;
#else
      hm.u.d.u.Data.Format.wMode = wIdleBit;
#endif
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

u16 HPI_InStreamAncillaryGetInfo(HPI_HSUBSYS * phSubSys,
                         HPI_HISTREAM hInStream, u32 * pdwFrameSpace)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_ANC_GET_INFO);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
      HPI_Message(&hm, &hr);
      if (pdwFrameSpace)
            *pdwFrameSpace =
                (hr.u.d.dwBufferSize -
                 hr.u.d.dwDataAvailable) / sizeof(HPI_ANC_FRAME);
      return (hr.wError);
}

u16 HPI_InStreamAncillaryWrite(HPI_HSUBSYS * phSubSys,
                         HPI_HISTREAM hInStream,
                         HPI_ANC_FRAME * pAncFrameBuffer,
                         u32 dwAncFrameBufferSizeInBytes,
                         u32 dwNumberOfAncillaryFramesToWrite)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_ANC_WRITE);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
      hm.u.d.u.Data.dwpbData = (PTR_AS_NUMBER) pAncFrameBuffer;
      hm.u.d.u.Data.dwDataSize =
          dwNumberOfAncillaryFramesToWrite * sizeof(HPI_ANC_FRAME);
      if (hm.u.d.u.Data.dwDataSize <= dwAncFrameBufferSizeInBytes)
            HPI_Message(&hm, &hr);
      else
            hr.wError = HPI_ERROR_INVALID_DATA_TRANSFER;
      return (hr.wError);
}

u16 HPI_InStreamHostBufferAllocate(HPI_HSUBSYS * phSubSys,
                           HPI_HISTREAM hInStream, u32 dwSizeInBytes)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_HOSTBUFFER_ALLOC);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
      hm.u.d.u.Data.dwDataSize = dwSizeInBytes;
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

u16 HPI_InStreamHostBufferFree(HPI_HSUBSYS * phSubSys, HPI_HISTREAM hInStream)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_ISTREAM, HPI_ISTREAM_HOSTBUFFER_FREE);
      HPI_HANDLETOINDEXES3(hInStream, &hm.wAdapterIndex,
                       &hm.u.d.wIStreamIndex, &hm.wDspIndex);
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

        /** @} */// Instream
        /** @} */// Streams

///////////////////////////////////////////////////////////////////////////
/** \defgroup mixer Mixer and Controls

@{
*/

u16 HPI_MixerOpen(HPI_HSUBSYS * phSubSys,
              u16 wAdapterIndex, HPI_HMIXER * phMixerHandle)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_MIXER, HPI_MIXER_OPEN);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

      if (hr.wError == 0)
            *phMixerHandle = HPI_IndexesToHandle('M', wAdapterIndex, 0);
      else
            *phMixerHandle = 0;
      return (hr.wError);
}

u16 HPI_MixerClose(HPI_HSUBSYS * phSubSys, HPI_HMIXER hMixerHandle)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_MIXER, HPI_MIXER_CLOSE);
      HPI_HANDLETOINDEXES(hMixerHandle, &hm.wAdapterIndex, NULL);
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

u16 HPI_MixerGetControl(HPI_HSUBSYS * phSubSys, HPI_HMIXER hMixerHandle, u16 wSrcNodeType, u16 wSrcNodeTypeIndex, u16 wDstNodeType, u16 wDstNodeTypeIndex, u16 wControlType,  // HPI_CONTROL_METER, _VOLUME etc
                  HPI_HCONTROL * phControlHandle)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_MIXER, HPI_MIXER_GET_CONTROL);
      HPI_HANDLETOINDEXES(hMixerHandle, &hm.wAdapterIndex, NULL);
      hm.u.m.wNodeType1 = wSrcNodeType;
      hm.u.m.wNodeIndex1 = wSrcNodeTypeIndex;
      hm.u.m.wNodeType2 = wDstNodeType;
      hm.u.m.wNodeIndex2 = wDstNodeTypeIndex;
      hm.u.m.wControlType = wControlType;

      HPI_Message(&hm, &hr);

// each control in an adapter/mixer has a unique index.
      if (hr.wError == 0)
            *phControlHandle =
                HPI_IndexesToHandle('C', hm.wAdapterIndex,
                              hr.u.m.wControlIndex);
      else
            *phControlHandle = 0;
      return (hr.wError);
}

/** Get the location and type of a mixer control by index.
To enumerate all the mixer controls of an adapter, iterate wControlIndex
from 0 until the function returns HPI_ERROR_INVALID_OBJ_INDEX

A control may exist between two nodes, or on a single node in which case
either source or destination node type is zero.

\return HPI_ERROR_*
\retval HPI_ERROR_INVALID_OBJ_INDEX when wControlIndex > number of mixer controls
*/
01332 u16 HPI_MixerGetControlByIndex(HPI_HSUBSYS * phSubSys,      ///<  HPI subsystem handle
                         HPI_HMIXER hMixerHandle,     ///<  Mixer Handle
                         u16 wControlIndex,     ///<  Control Index to query
                         u16 * pwSrcNodeType,   ///< [out] Source node type
                         u16 * pwSrcNodeIndex,  ///< [out] Source ndoe index
                         u16 * pwDstNodeType,   ///< [out] Destination node type
                         u16 * pwDstNodeIndex,  ///< [out] Destination node index
                         u16 * pwControlType,   ///< [out] Control Type
                         HPI_HCONTROL * phControlHandle     ///< [out] Control handle
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_MIXER, HPI_MIXER_GET_CONTROL_BY_INDEX);
      HPI_HANDLETOINDEXES(hMixerHandle, &hm.wAdapterIndex, NULL);
      hm.u.m.wControlIndex = wControlIndex;
      HPI_Message(&hm, &hr);

      if (pwSrcNodeType) {    /* return all or none of info fields */
            *pwSrcNodeType = hr.u.m.wSrcNodeType + HPI_SOURCENODE_BASE;
            *pwSrcNodeIndex = hr.u.m.wSrcNodeIndex;
            *pwDstNodeType = hr.u.m.wDstNodeType + HPI_DESTNODE_BASE;
            *pwDstNodeIndex = hr.u.m.wDstNodeIndex;
            *pwControlType = hr.u.m.wControlIndex;    /* Actually Type */
      }
// each control in an adapter/mixer has a unique index.
      if (phControlHandle) {
            if (hr.wError == 0)
                  *phControlHandle =
                      HPI_IndexesToHandle('C', hm.wAdapterIndex,
                                    wControlIndex);
            else
                  *phControlHandle = 0;
      }
      return (hr.wError);
}

/////////////////////////////////////////////////////////////////////////
// MIXER CONTROLS
/** General function for setting common control parameters
Still need specific code to set analog values
*/
01375 u16 HPI_ControlParamSet(const HPI_HSUBSYS * phSubSys,
                  const HPI_HCONTROL hControlHandle,
                  const u16 wAttrib,
                  const u32 dwParam1, const u32 dwParam2)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = wAttrib;
      hm.u.c.dwParam1 = dwParam1;
      hm.u.c.dwParam2 = dwParam2;
      HPI_Message(&hm, &hr);
      return (hr.wError);
}
static u16 HPI_ControlExParamSet(const HPI_HSUBSYS * phSubSys,
                         const HPI_HCONTROL hControlHandle,
                         const u16 wAttrib,
                         const u32 dwParam1, const u32 dwParam2)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = wAttrib;
      hm.u.cx.u.generic.dwParam1 = dwParam1;
      hm.u.cx.u.generic.dwParam2 = dwParam2;
      HPI_Message(&hm, &hr);
      return (hr.wError);
}

/** General function for getting up to 2 u32 return values
*/
01410 u16 HPI_ControlParamGet(const HPI_HSUBSYS * phSubSys,
                  const HPI_HCONTROL hControlHandle,
                  const u16 wAttrib,
                  u32 dwParam1,
                  u32 dwParam2, u32 * pdwParam1, u32 * pdwParam2)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = wAttrib;
      hm.u.c.dwParam1 = dwParam1;
      hm.u.c.dwParam2 = dwParam2;
      HPI_Message(&hm, &hr);
      if (pdwParam1)
            *pdwParam1 = hr.u.c.dwParam1;
      if (pdwParam2)
            *pdwParam2 = hr.u.c.dwParam2;

      return (hr.wError);
}
static u16 HPI_ControlExParamGet(const HPI_HSUBSYS * phSubSys,
                         const HPI_HCONTROL hControlHandle,
                         const u16 wAttrib,
                         u32 dwParam1,
                         u32 dwParam2, u32 * pdwParam1, u32 * pdwParam2)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = wAttrib;
      hm.u.cx.u.generic.dwParam1 = dwParam1;
      hm.u.cx.u.generic.dwParam2 = dwParam2;
      HPI_Message(&hm, &hr);
      if (pdwParam1)
            *pdwParam1 = hr.u.cx.u.generic.dwParam1;
      if (pdwParam2)
            *pdwParam2 = hr.u.cx.u.generic.dwParam2;

      return (hr.wError);
}

#if 1
#define HPI_ControlParam1Get(s,h,a,p1) HPI_ControlParamGet(s,h,a,0,0,p1,NULL)
#define HPI_ControlParam2Get(s,h,a,p1,p2) HPI_ControlParamGet(s,h,a,0,0,p1,p2)
#define HPI_ControlExParam1Get(s,h,a,p1) HPI_ControlExParamGet(s,h,a,0,0,p1,NULL)
#define HPI_ControlExParam2Get(s,h,a,p1,p2) HPI_ControlExParamGet(s,h,a,0,0,p1,p2)
#else
u16 HPI_ControlParam2Get(const HPI_HSUBSYS * phSubSys,
                   const HPI_HCONTROL hControlHandle,
                   const u16 wAttrib, u32 * pdwParam1, u32 * pdwParam2)
{
      return HPI_ControlParamGet(phSubSys, hControlHandle, wAttrib, 0, 0,
                           pdwParam1, pdwParam2);
}

u16 HPI_ControlParam1Get(const HPI_HSUBSYS * phSubSys,
                   const HPI_HCONTROL hControlHandle,
                   const u16 wAttrib, u32 * pdwParam1)
{
      return HPI_ControlParamGet(phSubSys, hControlHandle, wAttrib, 0, 0,
                           pdwParam1, 0L);
}
#endif

/** Get the possible settings of an attribute of a mixer control given its index.

This is done without disturbing the current setting of the control.
Do this by iterating dwIndex from 0 until the function returns HPI_ERROR_INVALID_OBJ_INDEX.

For example, to determine which bands are supported by a particular tuner, do the following:
\code
for (dwIndex=0; dwIndex<10; dwIndex++) {
wErr= HPI_ControlQuery(phSS,hC, HPI_TUNER_BAND, dwIndex, 0 , AvailableBands[dwIndex]);
if (wErr !=0) break;
}
numBands=dwIndex;
\endcode

For attributes that have a range, 3 values will be returned for indices 0 to 2: minimum, maximum and step.
The supplementary parameter dwParam is used where the possible settings for one attribute depend on the setting of another attribute, e.g. a tuners frequency range depends on which band is selected.
For example, to determine the frequency range of the AM band, do the following:

\code
wErr= HPI_ControlQuery(phSS,hC, HPI_TUNER_FREQ, 0, HPI_TUNER_BAND_AM , pdwMinFreq);
wErr= HPI_ControlQuery(phSS,hC, HPI_TUNER_FREQ, 1, HPI_TUNER_BAND_AM , pdwMaxFreq);
wErr= HPI_ControlQuery(phSS,hC, HPI_TUNER_FREQ, 2, HPI_TUNER_BAND_AM , pdwFreqStep);
\endcode

<table>
<caption>Supported attributes</caption>
<tr><td>Associated set function</td>         <td>wAttrib           </td>              <td>dwParam</td>            <td>*dwSetting</td></tr>
<tr><td>HPI_Tuner_SetBand()</td>             <td>HPI_TUNER_BAND</td>              <td>0</td>                  <td>HPI_TUNER_BAND_*</td></tr>
<tr><td>HPI_Tuner_SetFrequency()</td>        <td>HPI_TUNER_FREQ</td>              <td>HPI_TUNER_BAND_*</td>   <td>Range in kHz</td></tr>
<tr><td>HPI_Tuner_SetGain()</td>             <td>HPI_TUNER_GAIN</td>              <td>0</td>                  <td>Range in milliBels</td></tr>
<tr><td>HPI_SampleClock_SetSource()</td>     <td>HPI_SAMPLECLOCK_SOURCE</td>      <td>0</td>                  <td>HPI_SAMPLECLOCK_SOURCE_*</td></tr>
<tr><td>HPI_SampleClock_SetSourceIndex()</td><td>HPI_SAMPLECLOCK_SOURCE_INDEX</td><td>HPI_SAMPLECLOCK_SOURCE_*</td><td>a source index</td></tr>
<tr><td>HPI_SampleClock_SetSampleRate() </td><td>HPI_SAMPLECLOCK_SAMPLERATE</td>  <td>0</td>                  <td> List or range of frequencies in Hz</td></tr>
</table>
*/
01513 u16 HPI_ControlQuery(const HPI_HSUBSYS * phSubSys, const HPI_HCONTROL hControlHandle, const u16 wAttrib,    ///< A control attribute
                 const u32 dwIndex, ///< Index for possible attribute values
                 const u32 dwParam, ///< Supplementary parameter
                 u32 * pdwSetting   ///< [out] One of N possible settings for the control attribute, specified by dwIndex=0..N-1(and possibly depending on the value of the supplementary parameter)
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_INFO);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);

      hm.u.c.wAttribute = wAttrib;
      hm.u.c.dwParam1 = dwIndex;
      hm.u.c.dwParam2 = dwParam;

      HPI_Message(&hm, &hr);
      if (pdwSetting)
            *pdwSetting = hr.u.c.dwParam1;

      return (hr.wError);
}

/////////////////////////////////////////////////////////////////////////
/** \defgroup aesrx AES/EBU Digital audio receiver controls
\{
*/

/** set whether to input from the professional AES/EBU input
or the consumer S/PDIF input
*/
01544 u16 HPI_AESEBU_Receiver_SetSource(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wSource    //  HPI_AESEBU_SOURCE_AESEBU
//  HPI_AESEBU_SOURCE_SPDIF
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle, HPI_AESEBU_SOURCE,
                           wSource, 0);
}

u16 HPI_AESEBU_Receiver_GetSource(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 * pwSource //  HPI_AESEBU_SOURCE_AESEBU
//  HPI_AESEBU_SOURCE_SPDIF
    )
{
      u16 wErr;
      u32 dwParam;

      wErr =
          HPI_ControlParam1Get(phSubSys, hControlHandle, HPI_AESEBU_SOURCE,
                         &dwParam);
      if (!wErr && pwSource)
            *pwSource = (u16) dwParam;

      return wErr;
}

/// get the sample rate of the current AES/EBU input
01569 u16 HPI_AESEBU_Receiver_GetSampleRate(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u32 * pdwSampleRate    //0, 32000,44100 or 48000 returned
    )
{
      return HPI_ControlParam1Get(phSubSys, hControlHandle,
                            HPI_AESEBU_SAMPLERATE, pdwSampleRate);
}

/// get a byte of user data from the AES/EBU stream
01577 u16 HPI_AESEBU_Receiver_GetUserData(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wIndex,  // ranges from 0..3
                            u16 * pwData  // returned user data
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_AESEBU_USERDATA;
      hm.u.c.dwParam1 = wIndex;

      HPI_Message(&hm, &hr);

      if (pwData)
            *pwData = (u16) hr.u.c.dwParam2;
      return (hr.wError);
}

///get a byte of channel status from the AES/EBU stream
01598 u16 HPI_AESEBU_Receiver_GetChannelStatus(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wIndex,   // ranges from 0..23
                               u16 * pwData     // returned channel status data
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_AESEBU_CHANNELSTATUS;
      hm.u.c.dwParam1 = wIndex;

      HPI_Message(&hm, &hr);

      if (pwData)
            *pwData = (u16) hr.u.c.dwParam2;
      return (hr.wError);
}

/** get error status from the AES/EBU stream

*pwErrorData:    bit0: 1 when PLL is not locked
bit1: 1 when signal quality is poor
bit2: 1 when there is a parity error
bit3: 1 when there is a bi-phase coding violation
bit4: 1 whne the validity bit is high
*/

01627 u16 HPI_AESEBU_Receiver_GetErrorStatus(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 * pwErrorData     ///< returned error data
    )
{
      u32 dwErrorData = 0;
      u16 wError = 0;

      wError =
          HPI_ControlParam1Get(phSubSys, hControlHandle,
                         HPI_AESEBU_ERRORSTATUS, &dwErrorData);
      if (pwErrorData)
            *pwErrorData = (u16) dwErrorData;
      return (wError);
}

/*\}*/
///////////////////////////////////////////////////////////
/**\defgroup aestx AES/EBU Digital audio transmitter control
\{
*/
/** set the AES/EBU transmitters sample rate
this is only valid if the source is the analog mixer
if the source is an outstream, then the samplerate will
be that of the outstream.
*/
01651 u16 HPI_AESEBU_Transmitter_SetSampleRate(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u32 dwSampleRate    //32000,44100 or 48000
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_AESEBU_SAMPLERATE, dwSampleRate, 0);
}

u16 HPI_AESEBU_Transmitter_SetUserData(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wIndex,     // ranges from 0..3
                               u16 wData  // user data to set
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_AESEBU_USERDATA, wIndex, wData);
}

/// set a byte of channel status in the AES/EBU stream
01667 u16 HPI_AESEBU_Transmitter_SetChannelStatus(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wIndex,      // ranges from 0..23
                                  u16 wData     // channel status data to write
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_AESEBU_CHANNELSTATUS, wIndex, wData);
}

/** get a byte of channel status in the AES/EBU stream
\warning Currently disabled pending debug of DSP code
*/
01678 u16 HPI_AESEBU_Transmitter_GetChannelStatus(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wIndex,      // ranges from 0..23
                                  u16 * pwData  // channel status data to write
    )
{
#if 0
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_AESEBU_CHANNELSTATUS;
      hm.u.c.dwParam1 = wIndex;

      HPI_Message(&hm, &hr);

      if (!hr.wError && pwData)
            *pwData = (u16) hr.u.c.dwParam2;

      return hr.wError;
#else
      return HPI_ERROR_INVALID_OPERATION;
#endif
}

/** sets the AES3 Transmitter clock source to be say the adapter or external sync
*/
01705 u16 HPI_AESEBU_Transmitter_SetClockSource(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wClockSource   /* SYNC, ADAPTER */
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_AESEBU_CLOCKSOURCE, wClockSource, 0);
}

u16 HPI_AESEBU_Transmitter_GetClockSource(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 * pwClockSource      /* SYNC, ADAPTER */
    )
{
      u16 wErr;
      u32 dwParam;

      wErr =
          HPI_ControlParam1Get(phSubSys, hControlHandle,
                         HPI_AESEBU_CLOCKSOURCE, &dwParam);
      if (!wErr && pwClockSource)
            *pwClockSource = (u16) dwParam;

      return wErr;
}

u16 HPI_AESEBU_Transmitter_SetFormat(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wOutputFormat /* HPI_AESEBU_SOURCE_AESEBU, _SPDIF */
    )
{
// we use the HPI_AESEBU_SOURCE attribute, because thats used on the receiver side - _FORMAT would be a better descriptor
      return HPI_ControlParamSet(phSubSys, hControlHandle, HPI_AESEBU_SOURCE,
                           wOutputFormat, 0);
}

u16 HPI_AESEBU_Transmitter_GetFormat(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 * pwOutputFormat    /* HPI_AESEBU_SOURCE_AESEBU, _SPDIF */
    )
{
      u16 wErr;
      u32 dwParam;

// we use the HPI_AESEBU_SOURCE attribute, because thats used on the receiver side - _FORMAT would be a better descriptor
      wErr =
          HPI_ControlParam1Get(phSubSys, hControlHandle, HPI_AESEBU_SOURCE,
                         &dwParam);
      if (!wErr && pwOutputFormat)
            *pwOutputFormat = (u16) dwParam;

      return wErr;
}

/*\}*/
/////////////////////////////////////////////////////////////////////////
/**\defgroup bitstream Bitstream control
Control synchronous bitstream I/O
\{
*/
u16 HPI_Bitstream_SetClockEdge(HPI_HSUBSYS * phSubSys,
                         HPI_HCONTROL hControlHandle, u16 wEdgeType)
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_BITSTREAM_CLOCK_EDGE, wEdgeType, 0);
}

u16 HPI_Bitstream_SetDataPolarity(HPI_HSUBSYS * phSubSys,
                          HPI_HCONTROL hControlHandle, u16 wPolarity)
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_BITSTREAM_DATA_POLARITY, wPolarity, 0);
}

u16 HPI_Bitstream_GetActivity(HPI_HSUBSYS * phSubSys,
                        HPI_HCONTROL hControlHandle,
                        u16 * pwClkActivity, u16 * pwDataActivity)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_BITSTREAM_ACTIVITY;
      HPI_Message(&hm, &hr);
      if (pwClkActivity)
            *pwClkActivity = (u16) hr.u.c.dwParam1;
      if (pwDataActivity)
            *pwDataActivity = (u16) hr.u.c.dwParam2;
      return (hr.wError);
}

///\}

/////////////////////////////////////////////////////////////////////////
/**\defgroup channelmode Channel Mode control
\{
*/
u16 HPI_ChannelModeSet(HPI_HSUBSYS * phSubSys,
                   HPI_HCONTROL hControlHandle, u16 wMode)
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_MULTIPLEXER_SOURCE, wMode, 0);
}

u16 HPI_ChannelModeGet(HPI_HSUBSYS * phSubSys,
                   HPI_HCONTROL hControlHandle, u16 * wMode)
{
      u32 dwMode = 0;
      u16 wError =
          HPI_ControlParam1Get(phSubSys, hControlHandle,
                         HPI_MULTIPLEXER_SOURCE, &dwMode);
      if (wMode)
            *wMode = (u16) dwMode;
      return (wError);
}

/**\}*/
////////////////////////////////////////////////////////////////////////////////
/**\defgroup cobranet Cobranet control
A cobranet adapter has one cobranet control for each cobranet interface (usually only one).
The cobranet control is located on (HPI_SOURCENODE_COBRANET,0,HPI_DESTNODE_COBRANET,0)
The cobranet control allows reading and writing of the cobranet HMI variables
(See Cirrus cobranet documentation for details)

@{
*/

/** Write to an HMI variable.
\return 0=success or HPI_ERROR_*
\retval HPI_ERROR_INVALID_CONTROL if type is not cobranet
\retval HPI_ERROR_INVALID_OPERATION if HMI variable is not writeable
\retval HPI_ERROR_INVALID_DATASIZE if requested size is greater than the HMI variable size
*/

01833 u16 HPI_Cobranet_HmiWrite(HPI_HSUBSYS * phSubSys,     ///<Subsystem handle
                    HPI_HCONTROL hControlHandle,      ///<Handle of a cobranet control
                    u32 dwHmiAddress,     /// dwHmiAddress HMI address
                    u32 dwByteCount,      ///<Number of bytes to send to the control
                    u8 * pbData     ///<pointer to data to send
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);

      hm.u.cx.u.cobranet_data.dwByteCount = dwByteCount;
      hm.u.cx.u.cobranet_data.dwHmiAddress = dwHmiAddress;

      if (dwByteCount <= 8) {
            memcpy(hm.u.cx.u.cobranet_data.dwData, pbData, dwByteCount);
            hm.u.cx.wAttribute = HPI_COBRANET_SET;
      } else {
            hm.u.cx.u.cobranet_bigdata.dwpbData = (u32) pbData;
            hm.u.cx.wAttribute = HPI_COBRANET_SET_DATA;
      }

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/** Read from an HMI variable.
\return 0==success or HPI_ERROR_*
\retval HPI_ERROR_INVALID_CONTROL if type is not cobranet

The amount of data returned will be the minimum of the input dwMaxByteCount and the actual
size of the variable reported by the HMI
*/

01870 u16 HPI_Cobranet_HmiRead(HPI_HSUBSYS * phSubSys,      ///< Subsystem handle
                   HPI_HCONTROL hControlHandle, ///< Handle of a cobranet control
                   u32 dwHmiAddress,      ///<HMI address
                   u32 dwMaxByteCount,    ///<maximum number of bytes to return (<= buffer size of pbData)
                   u32 * pdwByteCount,    ///<[out]actual number of bytes returned
                   u8 * pbData      ///<[out] data read from HMI variable
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);

      hm.u.cx.u.cobranet_data.dwByteCount = dwMaxByteCount;
      hm.u.cx.u.cobranet_data.dwHmiAddress = dwHmiAddress;

      if (dwMaxByteCount <= 8) {
            hm.u.cx.wAttribute = HPI_COBRANET_GET;
      } else {
            hm.u.cx.u.cobranet_bigdata.dwpbData = (u32) pbData;
            hm.u.cx.wAttribute = HPI_COBRANET_GET_DATA;
      }

      HPI_Message(&hm, &hr);
      if (!hr.wError && pbData) {

            *pdwByteCount = hr.u.cx.u.cobranet_data.dwByteCount;

            if (*pdwByteCount < dwMaxByteCount)
                  dwMaxByteCount = *pdwByteCount;

            if (hm.u.cx.wAttribute == HPI_COBRANET_GET) {
                  memcpy(pbData, hr.u.cx.u.cobranet_data.dwData,
                         dwMaxByteCount);
            } else {
/* data was already copied in hpi */
            }

      }
      return (hr.wError);
}

/** Get the status of the last cobranet operation
*/
01915 u16 HPI_Cobranet_HmiGetStatus(HPI_HSUBSYS * phSubSys, ///< Subsystem handle
                        HPI_HCONTROL hControlHandle,  ///< Handle of a cobranet control
                        u32 * pdwStatus,  ///<[out]the raw status word from the HMI
                        u32 * pdwReadableSize,  ///<[out] the reported readable size from the last variable access
                        u32 * pdwWriteableSize  ///<[out] the reported writeable size from the last variable access
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);

      hm.u.cx.wAttribute = HPI_COBRANET_GET_STATUS;

      HPI_Message(&hm, &hr);
      if (!hr.wError) {
            if (pdwStatus)
                  *pdwStatus = hr.u.cx.u.cobranet_status.dwStatus;
            if (pdwReadableSize)
                  *pdwReadableSize =
                      hr.u.cx.u.cobranet_status.dwReadableSize;
            if (pdwWriteableSize)
                  *pdwWriteableSize =
                      hr.u.cx.u.cobranet_status.dwWriteableSize;
      }
      return (hr.wError);
}

/** Set the CobraNet mode.
\return 0==success or HPI_ERROR_*
\retval HPI_ERROR_INVALID_CONTROL if type is not cobranet

Allows the user to set the mode of CobraNet operation. This changes the way that a ASI6416 and ASI2416
work together. A reload of the DSP code is required for the new setting to take effect. In Windows
this requires a reboot of the computer. In Linux this requires that driver be unloaded and reloaded.
*/
01952 u16 HPI_Cobranet_SetMode(HPI_HSUBSYS * phSubSys,      ///< Subsystem handle
                   HPI_HCONTROL hControlHandle, ///< Handle of a CobraNet control
                   u32 dwMode,      ///< Mode should be one of HPI_COBRANET_MODE_NETWORK, HPI_COBRANET_MODE_TETHERED
                   u32 dwSetOrQuery ///< Use HPI_COBRANET_MODE_QUERY to query or HPI_COBRANET_MODE_SET to set
    )
{
      return HPI_ControlExParamSet(phSubSys, hControlHandle,
                             HPI_COBRANET_MODE, dwMode, dwSetOrQuery);
}

/** Get the CobraNet mode.
\return 0==success or HPI_ERROR_*
\retval HPI_ERROR_INVALID_CONTROL if type is not cobranet

Allows the user to get the mode of CobraNet operation. This changes the way that a ASI6416 and ASI2416
work together.
*/
01969 u16 HPI_Cobranet_GetMode(HPI_HSUBSYS * phSubSys,      ///< Subsystem handle
                   HPI_HCONTROL hControlHandle, ///< Handle of a CobraNet control
                   u32 * pdwMode    ///< Returns HPI_COBRANET_MODE_NETWORK or HPI_COBRANET_MODE_TETHERED
    )
{
      u16 nError = 0;
      u32 dwMode = 0;
      nError =
          HPI_ControlExParam1Get(phSubSys, hControlHandle, HPI_COBRANET_MODE,
                           &dwMode);
      if (pdwMode)
            *pdwMode = (u16) dwMode;
      return (nError);
}

/** Get the CobraNet node's IP address.
\return 0==success or HPI_ERROR_*
\retval HPI_ERROR_INVALID_CONTROL if type is not cobranet

Allows the user to get the IP address of the CobraNet node.
*/
01990 u16 HPI_Cobranet_GetIPaddress(HPI_HSUBSYS * phSubSys, ///< Subsystem handle
                        HPI_HCONTROL hControlHandle,  ///< Handle of a cobranet control
                        u32 * pdwIPaddress      ///< OUT: the IP address
    )
{
      u32 dwByteCount;
      u32 dwIP;
      u16 wError;
      wError = HPI_Cobranet_HmiRead(phSubSys, hControlHandle,
                              HPI_COBRANET_HMI_cobraIpMonCurrentIP,
                              4, &dwByteCount, (u8 *) & dwIP);
// byte swap the IP address
      *pdwIPaddress =
          ((dwIP & 0xff000000) >> 8) |
          ((dwIP & 0x00ff0000) << 8) |
          ((dwIP & 0x0000ff00) >> 8) | ((dwIP & 0x000000ff) << 8);

      return wError;

}

/** Get the CobraNet node's MAC address.
\return 0==success or HPI_ERROR_*
\retval HPI_ERROR_INVALID_CONTROL if type is not cobranet

Allows the user to get the MAC address of the CobraNet node.
*/
02017 u16 HPI_Cobranet_GetMACaddress(HPI_HSUBSYS * phSubSys,      ///< Subsystem handle
                         HPI_HCONTROL hControlHandle, ///< Handle of a cobranet control
                         u32 * pdwMAC_MSBs,     ///< OUT: the first 4 bytes of the MAC address.
                         u32 * pdwMAC_LSBs      ///< OUT: the last 2 bytes of the MAC address returned in the upper 2 bytes.
    )
{
      u32 dwByteCount;
      u16 wError;
      u32 dwMAC;
      wError = HPI_Cobranet_HmiRead(phSubSys, hControlHandle,
                              HPI_COBRANET_HMI_cobraIfPhyAddress,
                              4, &dwByteCount, (u8 *) & dwMAC);
      *pdwMAC_MSBs =
          ((dwMAC & 0xff000000) >> 8) |
          ((dwMAC & 0x00ff0000) << 8) |
          ((dwMAC & 0x0000ff00) >> 8) | ((dwMAC & 0x000000ff) << 8);
      wError += HPI_Cobranet_HmiRead(phSubSys, hControlHandle,
                               HPI_COBRANET_HMI_cobraIfPhyAddress + 1,
                               4, &dwByteCount, (u8 *) & dwMAC);
      *pdwMAC_LSBs =
          ((dwMAC & 0xff000000) >> 8) |
          ((dwMAC & 0x00ff0000) << 8) |
          ((dwMAC & 0x0000ff00) >> 8) | ((dwMAC & 0x000000ff) << 8);
      return wError;

}

        /** @} */// group cobranet
/////////////////////////////////////////////////////////////////////////////////
/**\defgroup compand  Compressor Expander control
\{
The compander multiplies its input signal by a factor that is dependent on the
amplitude of that signal.
*/
/*! Set up a compressor expander
\return HPI_ERROR_*
*/
02054 u16 HPI_Compander_Set(HPI_HSUBSYS * phSubSys,   //!<HPI subsystem handle
                  HPI_HCONTROL hControlHandle,  //!<Equalizer control handle
                  u16 wAttack,      //!<attack time in milliseconds
                  u16 wDecay, //!<decay time in milliseconds
                  short wRatio100,  //!<gain ratio * 100
                  short nThreshold0_01dB, //!<threshold in 100ths of a dB
                  short nMakeupGain0_01dB //!<makeup gain in 100ths of a dB
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);

      hm.u.c.dwParam1 = wAttack + ((u32) wRatio100 << 16);
      hm.u.c.dwParam2 = (wDecay & 0xFFFFL);
      hm.u.c.anLogValue[0] = nThreshold0_01dB;
      hm.u.c.anLogValue[1] = nMakeupGain0_01dB;
      hm.u.c.wAttribute = 0;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/*! Get the settings of a compressor expander
\return HPI_ERROR_*
*/
02083 u16 HPI_Compander_Get(HPI_HSUBSYS * phSubSys,   //!<HPI subsystem handle
                  HPI_HCONTROL hControlHandle,  //!<Equalizer control handle
                  u16 * pwAttack,   //!<[out] attack time in milliseconds
                  u16 * pwDecay,    //!<[out] decay time in milliseconds
                  short *pwRatio100,      //!<[out] gain ratio * 100
                  short *pnThreshold0_01dB,     //!<[out] threshold in 100ths of a dB
                  short *pnMakeupGain0_01dB     //!<[out] makeup gain in 100ths of a dB
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = 0;

      HPI_Message(&hm, &hr);

      if (pwAttack)
            *pwAttack = (short)(hr.u.c.dwParam1 & 0xFFFF);
      if (pwDecay)
            *pwDecay = (short)(hr.u.c.dwParam2 & 0xFFFF);
      if (pwRatio100)
            *pwRatio100 = (short)(hr.u.c.dwParam1 >> 16);

      if (pnThreshold0_01dB)
            *pnThreshold0_01dB = hr.u.c.anLogValue[0];
      if (pnMakeupGain0_01dB)
            *pnMakeupGain0_01dB = hr.u.c.anLogValue[1];

      return (hr.wError);
}

///\}
/////////////////////////////////////////////////////////////////////////
/** \defgroup level Level Control
The level control sets the gain of the line (analog) inputs and outputs
The level is in units of 0.01dBu (0dBu = 0.775 VRMS)
\{
*/

u16 HPI_LevelSetGain(HPI_HSUBSYS * phSubSys,
                 HPI_HCONTROL hControlHandle,
                 short anGain0_01dB[HPI_MAX_CHANNELS]
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      memcpy(hm.u.c.anLogValue, anGain0_01dB,
             sizeof(short) * HPI_MAX_CHANNELS);
      hm.u.c.wAttribute = HPI_LEVEL_GAIN;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_LevelGetGain(HPI_HSUBSYS * phSubSys,
                 HPI_HCONTROL hControlHandle,
                 short anGain0_01dB[HPI_MAX_CHANNELS]
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_LEVEL_GAIN;

      HPI_Message(&hm, &hr);

      memcpy(anGain0_01dB, hr.u.c.anLogValue,
             sizeof(short) * HPI_MAX_CHANNELS);
      return (hr.wError);
}

///\}
/////////////////////////////////////////////////////////////////////////
/** \defgroup meter  Meter Control
The meter control returns information about the level of the audio signal
at the position of the control.

Depending on the adapter, Peak and RMS readings are available.
On some adapters meter ballistics may be set (on older adapters the meter gives an instantaneous reading)

Readings are in units of 0.01dB

\todo Implement linear to log conversion in fixed point math so that it can be included with kernel code.

@{
*/

/** Get the meter peak reading
*/
02181 u16 HPI_MeterGetPeak(HPI_HSUBSYS * phSubSys,    ///< HPI subsystem handle
                 HPI_HCONTROL hControlHandle,   ///< meter control handle
                 short anPeakdB[HPI_MAX_CHANNELS]     ///< [out] meter peaks
    )
{
#ifndef HPI_KERNEL_MODE
      short nLinear = 0;
#endif
      short i = 0;

      HPI_MESSAGE hm;
      HPI_RESPONSE hr;

      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_METER_PEAK;

      HPI_Message(&hm, &hr);

      if (!hr.wError) {
// Method to return meter values from DSP
// If return value is -ve (-1 to -32767) then treat as Log(peak)
// range of log values will be -1 to -20000 (-0.01 to -200.00 dB)
// 0 will never be returned for log (-1 = -0.01dB is max)

#ifndef HPI_KERNEL_MODE
/// \bug Kernel mode cant do floating point log.  +ve linear value is returned instead.

// convert 0..32767 level to 0.01dB (20log10), 0 is -100.00dB
            for (i = 0; i < HPI_MAX_CHANNELS; i++) {
                  nLinear = hr.u.c.anLogValue[i];
// don't have to touch the LogValue when it is -ve since it is already a log value
                  if (nLinear >= 0) {
                        if (nLinear == 0)
                              hr.u.c.anLogValue[i] =
                                  HPI_METER_MINIMUM;
                        else
                              hr.u.c.anLogValue[i] = (short)((float)(20 * log10((float)nLinear / 32767.0)) * 100.0);    // units are 0.01dB
                  }
            }
#endif

            memcpy(anPeakdB, hr.u.c.anLogValue,
                   sizeof(short) * HPI_MAX_CHANNELS);
      } else
            for (i = 0; i < HPI_MAX_CHANNELS; i++)
                  anPeakdB[i] = HPI_METER_MINIMUM;
      return (hr.wError);
}

/** Get the meter RMS reading in 100ths of a dB
*/
02234 u16 HPI_MeterGetRms(HPI_HSUBSYS * phSubSys,
                HPI_HCONTROL hControlHandle, short anRmsdB[HPI_MAX_CHANNELS]
    )
{
#ifndef HPI_KERNEL_MODE
      short nLinear = 0;
#endif
      short i = 0;

      HPI_MESSAGE hm;
      HPI_RESPONSE hr;

      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_METER_RMS;

      HPI_Message(&hm, &hr);

      if (!hr.wError) {
#ifndef HPI_KERNEL_MODE
/// \bug Kernel mode cant do floating point log.  +ve linear value is returned instead.
// convert 0..32767 level to 0.01dB (20log10), 0 is -100.00dB
            for (i = 0; i < HPI_MAX_CHANNELS; i++) {
                  nLinear = hr.u.c.anLogValue[i];
// don't have to touch the LogValue when it is -ve since it is already a log value
                  if (nLinear >= 0) {
                        if (nLinear == 0)
                              hr.u.c.anLogValue[i] =
                                  HPI_METER_MINIMUM;
                        else
                              hr.u.c.anLogValue[i] = (short)((float)(20 * log10((float)nLinear / 32767.0)) * 100.0);    // units are 0.01dB
                  }
            }
#endif
            memcpy(anRmsdB, hr.u.c.anLogValue,
                   sizeof(short) * HPI_MAX_CHANNELS);
      } else
            for (i = 0; i < HPI_MAX_CHANNELS; i++)
                  anRmsdB[i] = HPI_METER_MINIMUM;     // return -100dB in case function is not supported.

      return (hr.wError);
}

/** Set the ballistics of the RMS part of a meter.

The attack and decay values represent the time constants of the equivalent single pole low pass filter used to create the ballistics.
With a time constant of T, if the meter is stable at full scale and the input is suddenly removed, the meter will decay.

Setting nAttack to 0 gives the meter instantaneous rise time.
Setting nDecay to a value smaller than a few times your  meter polling interval is not advised.
The meter will appear to read something approaching the instantaneous value at the time of polling
rather than the maximum peak since the previous reading.
*/
02288 u16 HPI_MeterSetRmsBallistics(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, unsigned short nAttack,  ///< Attack timeconstant in milliseconds
                        unsigned short nDecay   ///< Decay timeconstant in milliseconds
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_METER_RMS_BALLISTICS, nAttack, nDecay);
}

/** Get the ballistics settings of the RMS part of a meter.
*/
02298 u16 HPI_MeterGetRmsBallistics(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, unsigned short *pnAttack,      ///< Attack timeconstant in milliseconds
                        unsigned short *pnDecay ///< Decay timeconstant in milliseconds
    )
{
      u32 dwAttack;
      u32 dwDecay;
      u16 nError;

      nError =
          HPI_ControlParam2Get(phSubSys, hControlHandle,
                         HPI_METER_RMS_BALLISTICS, &dwAttack, &dwDecay);

      if (pnAttack)
            *pnAttack = (unsigned short)dwAttack;
      if (pnDecay)
            *pnDecay = (unsigned short)dwDecay;

      return nError;
}

/** Set the ballistics of the Peak part of a meter.
*/
02320 u16 HPI_MeterSetPeakBallistics(HPI_HSUBSYS * phSubSys,
                         HPI_HCONTROL hControlHandle,
                         unsigned short nAttack, unsigned short nDecay)
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_METER_PEAK_BALLISTICS, nAttack, nDecay);
}

/** Get the ballistics settings of the Peak part of a meter.
*/
02330 u16 HPI_MeterGetPeakBallistics(HPI_HSUBSYS * phSubSys,
                         HPI_HCONTROL hControlHandle,
                         unsigned short *pnAttack,
                         unsigned short *pnDecay)
{
      u32 dwAttack;
      u32 dwDecay;
      u16 nError;

      nError =
          HPI_ControlParam2Get(phSubSys, hControlHandle,
                         HPI_METER_PEAK_BALLISTICS, &dwAttack,
                         &dwDecay);

      if (pnAttack)
            *pnAttack = (short)dwAttack;
      if (pnDecay)
            *pnDecay = (short)dwDecay;

      return nError;
}

/** @} */

/* future function to convert linear to log using integers

long lLogC[16] = {
5184138,
-95824768,
-196833680,
-297842592,
-398851488,
-499860384,
-600869312,
-701878208,
-802887104,
-903896000,
-1004904896,
-1105913856,
-1206922752,
-1307931648,
-1408940544,
30};
double __fastcall TFLogDemo::LinearToLogQuadApproxInt(short nPeak)
{
short   nBeforeFirstBit;
short   nR;
short nSample;
long    lAcc;

nBeforeFirstBit = 0;
nSample=nPeak;
while(!(nSample&0x8000) )
{
nSample <<= 1;
nBeforeFirstBit++;
}
nSample &= ~0x8000;
nR = nBeforeFirstBit;
lAcc = (long)nSample * -1047L;  // Q15 * Q9 = Q24
lAcc = lAcc + 135336768L;
lAcc = lAcc >> 15;              // Q24 > Q9
lAcc = lAcc * (long)nSample;    // Q9 * Q15 = Q24
lAcc = lAcc + lLogC[nR];        // lAcc has result in Q24
// lAcc = (lAcc>>8)*100;        // result is 100ths of dB in Q16 format
// dB100 = (short)(lAcc>>16L);
return (double)lAcc / pow(2.0,24.0);
}
*/
/////////////////////////////////////////////////////////////////////////////////
/**\defgroup mic Microphone control
\{
*/
u16 HPI_Microphone_SetPhantomPower(HPI_HSUBSYS * phSubSys,
                           HPI_HCONTROL hControlHandle, u16 wOnOff)
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_MICROPHONE_PHANTOM_POWER, (u32) wOnOff,
                           0);
}

u16 HPI_Microphone_GetPhantomPower(HPI_HSUBSYS * phSubSys,
                           HPI_HCONTROL hControlHandle, u16 * pwOnOff)
{
      u16 nError = 0;
      u32 dwOnOff = 0;
      nError =
          HPI_ControlParam1Get(phSubSys, hControlHandle,
                         HPI_MICROPHONE_PHANTOM_POWER, &dwOnOff);
      if (pwOnOff)
            *pwOnOff = (u16) dwOnOff;
      return (nError);
}

///\}
/////////////////////////////////////////////////////////////////////////
/** \defgroup mux Multiplexer control
This control allows one of many sources to be connected to a destination
Typically used on the instream (record) side to select a record input
or on the linein to select analog or digital input.
\{
*/

u16 HPI_Multiplexer_SetSource(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wSourceNodeType,     // any source node
                        u16 wSourceNodeIndex    // any source node
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_MULTIPLEXER_SOURCE, wSourceNodeType,
                           wSourceNodeIndex);
}

u16 HPI_Multiplexer_GetSource(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 * wSourceNodeType,   /* any source node */
                        u16 * wSourceNodeIndex  /* any source node  */
    )
{
      u32 dwNode, dwIndex;
      u16 wError =
          HPI_ControlParam2Get(phSubSys, hControlHandle,
                         HPI_MULTIPLEXER_SOURCE, &dwNode, &dwIndex);
      if (wSourceNodeType)
            *wSourceNodeType = (u16) dwNode;
      if (wSourceNodeIndex)
            *wSourceNodeIndex = (u16) dwIndex;
      return wError;
}

u16 HPI_Multiplexer_QuerySource(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wIndex, u16 * wSourceNodeType, /* any source node */
                        u16 * wSourceNodeIndex  /* any source node  */
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_MULTIPLEXER_QUERYSOURCE;
      hm.u.c.dwParam1 = wIndex;

      HPI_Message(&hm, &hr);

      if (wSourceNodeType)
            *wSourceNodeType = (u16) hr.u.c.dwParam1;
      if (wSourceNodeIndex)
            *wSourceNodeIndex = (u16) hr.u.c.dwParam2;
      return (hr.wError);
}

/**\}*/
/////////////////////////////////////////////////////////////////////////
/** \defgroup onoff On/off switch control
This control allows make/break connections to be supported.
\{
*/

u16 HPI_OnOffSwitch_SetState(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wState    /* 1=on, 0=off */
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_ONOFFSWITCH_STATE, wState, 0);
}

u16 HPI_OnOffSwitch_GetState(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 * wState  /* 1=on, 0=off */
    )
{
      u32 dwState = 0;
      u16 wError =
          HPI_ControlParam1Get(phSubSys, hControlHandle,
                         HPI_ONOFFSWITCH_STATE, &dwState);
      if (wState)
            *wState = (u16) dwState;
      return (wError);
}

/**\}*/
/////////////////////////////////////////////////////////////////////////////////
/**\addtogroup parmeq  Parametric Equalizer control
\{
*/

/*!
Find out the number of available bands of a parametric equalizer,
and whether it is enabled or not

\return HPI_ERROR_*
*/
02517 u16 HPI_ParametricEQ_GetInfo(HPI_HSUBSYS * phSubSys,  //!<  HPI subsystem handle
                       HPI_HCONTROL hControlHandle,   //!<  Equalizer control handle
                       u16 * pwNumberOfBands,   //!< [out] number of bands available
                       u16 * pwOnOff      //!< [out] enabled status
    )
{
      u32 dwNOB = 0;
      u32 dwOO = 0;
      u16 nError = 0;

      nError =
          HPI_ControlParam2Get(phSubSys, hControlHandle,
                         HPI_EQUALIZER_NUM_FILTERS, &dwOO, &dwNOB);
      if (pwNumberOfBands)
            *pwNumberOfBands = (u16) dwNOB;
      if (pwOnOff)
            *pwOnOff = (u16) dwOO;
      return nError;
}

/*!
Turn a parametric equalizer on or off

\return HPI_ERROR_*
*/
02542 u16 HPI_ParametricEQ_SetState(HPI_HSUBSYS * phSubSys, //!<  HPI subsystem handle
                        HPI_HCONTROL hControlHandle,  //!<  Equalizer control handle
                        u16 wOnOff  //!<  1=on, 0=off
    )
{
      return HPI_ControlParamSet(phSubSys,
                           hControlHandle,
                           HPI_EQUALIZER_NUM_FILTERS, wOnOff, 0);
}

/*! Set up one of the filters in a parametric equalizer
\return HPI_ERROR_*
*/
02555 u16 HPI_ParametricEQ_SetBand(HPI_HSUBSYS * phSubSys,  //!<  HPI subsystem handle
                       HPI_HCONTROL hControlHandle,   //!<  Equalizer control handle
                       u16 wIndex,  //!<  index of band to set
                       u16 nType,   //!<  band type, One of the \ref eq_filter_types
                       u32 dwFrequencyHz, //!<  band frequency
                       short nQ100, //!<  filter Q * 100
                       short nGain0_01dB  //!<  filter gain in 100ths of a dB
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);

      hm.u.c.dwParam1 = dwFrequencyHz;
      hm.u.c.dwParam2 = (wIndex & 0xFFFFL) + ((u32) nType << 16);
      hm.u.c.anLogValue[0] = nGain0_01dB;
      hm.u.c.anLogValue[1] = nQ100;
      hm.u.c.wAttribute = HPI_EQUALIZER_FILTER;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/*! Get the settings of one of the filters in a parametric equalizer
\return HPI_ERROR_*
*/
02584 u16 HPI_ParametricEQ_GetBand(HPI_HSUBSYS * phSubSys,  //!<  HPI subsystem handle
                       HPI_HCONTROL hControlHandle,   //!<  Equalizer control handle
                       u16 wIndex,  //!<  index of band to Get
                       u16 * pnType,      //!< [out] band type
                       u32 * pdwFrequencyHz,    //!< [out] band frequency
                       short *pnQ100,     //!< [out] filter Q * 100
                       short *pnGain0_01dB      //!< [out] filter gain in 100ths of a dB
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_EQUALIZER_FILTER;
      hm.u.c.dwParam2 = wIndex;

      HPI_Message(&hm, &hr);

      if (pdwFrequencyHz)
            *pdwFrequencyHz = hr.u.c.dwParam1;
      if (pnType)
            *pnType = (u16) (hr.u.c.dwParam2 >> 16);
      if (pnQ100)
            *pnQ100 = hr.u.c.anLogValue[1];
      if (pnGain0_01dB)
            *pnGain0_01dB = hr.u.c.anLogValue[0];

      return (hr.wError);
}

/** Retrieve the calculated filter coefficients (scaled by 1000 into integers)
*/
02617 u16 HPI_ParametricEQ_GetCoeffs(HPI_HSUBSYS * phSubSys,      //!<  HPI subsystem handle
                         HPI_HCONTROL hControlHandle, //!<  Equalizer control handle
                         u16 wIndex,      //!<  index of band to Get
                         short coeffs[5]  //!< [out] filter coefficients * 1000 a1,a2,b0,b1,b2 (a0==0)
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_EQUALIZER_COEFFICIENTS;
      hm.u.c.dwParam2 = wIndex;

      HPI_Message(&hm, &hr);

      coeffs[0] = (short)hr.u.c.anLogValue[0];
      coeffs[1] = (short)hr.u.c.anLogValue[1];
      coeffs[2] = (short)hr.u.c.dwParam1;
      coeffs[3] = (short)(hr.u.c.dwParam1 >> 16);
      coeffs[4] = (short)hr.u.c.dwParam2;

      return (hr.wError);
}

///\}
/////////////////////////////////////////////////////////////////////////////////
/**\defgroup sampleclock SampleClock control
\{
*/
u16 HPI_SampleClock_SetSource(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wSource  // HPI_SAMPLECLOCK_SOURCE_ADAPTER, _AESEBU etc
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_SAMPLECLOCK_SOURCE, wSource, 0);
}

u16 HPI_SampleClock_SetSourceIndex(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wSourceIndex    // index of the source to use
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_SAMPLECLOCK_SOURCE_INDEX, wSourceIndex,
                           0);
}

u16 HPI_SampleClock_GetSource(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 * pwSource     // HPI_SAMPLECLOCK_SOURCE_ADAPTER, _AESEBU etc
    )
{
      u16 wError = 0;
      u32 dwSource = 0;
      wError =
          HPI_ControlParam1Get(phSubSys, hControlHandle,
                         HPI_SAMPLECLOCK_SOURCE, &dwSource);
      if (!wError)
            if (pwSource)
                  *pwSource = (u16) dwSource;
      return (wError);
}

u16 HPI_SampleClock_GetSourceIndex(HPI_HSUBSYS * phSubSys,
                           HPI_HCONTROL hControlHandle,
                           u16 * pwSourceIndex)
{
      u16 wError = 0;
      u32 dwSourceIndex = 0;
      wError =
          HPI_ControlParam1Get(phSubSys, hControlHandle,
                         HPI_SAMPLECLOCK_SOURCE_INDEX, &dwSourceIndex);
      if (!wError)
            if (pwSourceIndex)
                  *pwSourceIndex = (u16) dwSourceIndex;
      return (wError);
}

u16 HPI_SampleClock_SetSampleRate(HPI_HSUBSYS * phSubSys,
                          HPI_HCONTROL hControlHandle, u32 dwSampleRate)
{
      return HPI_ControlParamSet(phSubSys, hControlHandle,
                           HPI_SAMPLECLOCK_SAMPLERATE, dwSampleRate, 0);
}

u16 HPI_SampleClock_GetSampleRate(HPI_HSUBSYS * phSubSys,
                          HPI_HCONTROL hControlHandle,
                          u32 * pdwSampleRate)
{
      u16 wError = 0;
      u32 dwSampleRate = 0;
      wError =
          HPI_ControlParam1Get(phSubSys, hControlHandle,
                         HPI_SAMPLECLOCK_SAMPLERATE, &dwSampleRate);
      if (!wError)
            if (pdwSampleRate)
                  *pdwSampleRate = dwSampleRate;
      return (wError);
}

///\}

/////////////////////////////////////////////////////////////////////////////////
/**\defgroup tonedetector Tone Detector control
\{
The tone detector monitors its inputs for the presence of any of a number of tones.

Currently 25Hz and 35Hz tones can be detected independently on left and right channels.
The result of the detection is reflected in the controls state, and optionally by sending an
async event with the new sate.
*/

u16 HPI_ToneDetector_GetFrequency(HPI_HSUBSYS * phSubSys,
                          HPI_HCONTROL hControl,
                          u32 nIndex, u32 * dwFrequency)
{
      return HPI_ControlParamGet(phSubSys, hControl,
                           HPI_TONEDETECTOR_FREQUENCY, nIndex, 0,
                           dwFrequency, NULL);
}

///\}

///////////////////////////////////////////////////////////////////////////////
/** \defgroup tuner Tuner Controls

The tuner control sets the band and frequency of a tuner, and measures the RF level
\{
*/

/** Select the tuner band.

Not all tuners support all bands. (Currently either AM+FM or TV+FM).

Note that with the exception of HPI_TUNER_BAND_AUX,
the tuner frequency must subsequently be set using HPI_Tuner_SetFrequency().
\return 0 or HPI_ERROR_*
\retval HPI_ERROR_INVALID_CONTROL_VALUE if tuner does not support the requested band

\sa HPI_ControlQuery() for details on determining the bands supported by a particular tuner.
*/
02754 u16 HPI_Tuner_SetBand(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wBand
                   /**< one of the \ref tuner_bands */
    )
{
      return HPI_ControlParamSet(phSubSys, hControlHandle, HPI_TUNER_BAND,
                           wBand, 0);
}

/** Set the RF gain of the tuner front end.
*/
02764 u16 HPI_Tuner_SetGain(HPI_HSUBSYS * phSubSys,
                  HPI_HCONTROL hControlHandle, short nGain)
{
      return HPI_ControlParamSet(phSubSys, hControlHandle, HPI_TUNER_GAIN,
                           nGain, 0);
}

u16 HPI_Tuner_SetFrequency(HPI_HSUBSYS * phSubSys,
                     HPI_HCONTROL hControlHandle, u32 wFreqInkHz)
{
      return HPI_ControlParamSet(phSubSys, hControlHandle, HPI_TUNER_FREQ,
                           wFreqInkHz, 0);
}

u16 HPI_Tuner_GetBand(HPI_HSUBSYS * phSubSys,
                  HPI_HCONTROL hControlHandle, u16 * pwBand)
{
      u32 dwBand = 0;
      u16 nError = 0;

      nError =
          HPI_ControlParam1Get(phSubSys, hControlHandle, HPI_TUNER_BAND,
                         &dwBand);
      if (pwBand)
            *pwBand = (u16) dwBand;
      return nError;
}

u16 HPI_Tuner_GetGain(HPI_HSUBSYS * phSubSys,
                  HPI_HCONTROL hControlHandle, short *pnGain)
{
      u32 dwGain = 0;
      u16 nError = 0;

      nError =
          HPI_ControlParam1Get(phSubSys, hControlHandle, HPI_TUNER_GAIN,
                         &dwGain);
      if (pnGain)
            *pnGain = (u16) dwGain;
      return nError;
}

u16 HPI_Tuner_GetFrequency(HPI_HSUBSYS * phSubSys,
                     HPI_HCONTROL hControlHandle, u32 * pwFreqInkHz)
{
      return HPI_ControlParam1Get(phSubSys, hControlHandle, HPI_TUNER_FREQ,
                            pwFreqInkHz);
}

u16 HPI_Tuner_GetRFLevel(HPI_HSUBSYS * phSubSys,
                   HPI_HCONTROL hControlHandle, short *pwLevel)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_TUNER_LEVEL;
      hm.u.c.dwParam1 = HPI_TUNER_LEVEL_AVERAGE;
      HPI_Message(&hm, &hr);
      if (pwLevel)
            *pwLevel = (short)hr.u.c.dwParam1;
      return (hr.wError);
}

u16 HPI_Tuner_GetRawRFLevel(HPI_HSUBSYS * phSubSys,
                      HPI_HCONTROL hControlHandle, short *pwLevel)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_TUNER_LEVEL;
      hm.u.c.dwParam1 = HPI_TUNER_LEVEL_RAW;
      HPI_Message(&hm, &hr);
      if (pwLevel)
            *pwLevel = (short)hr.u.c.dwParam1;
      return (hr.wError);
}

/**
\deprecated This function has been superceded by HPI_Tuner_GetStatus()
*/
02848 u16 HPI_Tuner_GetVideoStatus(HPI_HSUBSYS * phSubSys,
                       HPI_HCONTROL hControlHandle, u16 * pwStatus)
{
      u32 dwStatus = 0;
      u16 nError = 0;

      nError =
          HPI_ControlParam1Get(phSubSys, hControlHandle,
                         HPI_TUNER_VIDEO_STATUS, &dwStatus);
      if (pwStatus)
            *pwStatus = (u16) dwStatus;
      return nError;
}

u16 HPI_Tuner_GetStatus(HPI_HSUBSYS * phSubSys,
                  HPI_HCONTROL hControlHandle,
                  u16 * pwStatusMask, u16 * pwStatus)
{
      u32 dwStatus = 0;
      u16 nError = 0;

// wStatusmask is in high 16bit word, wStatus is in low 16bit word
      nError =
          HPI_ControlParam1Get(phSubSys, hControlHandle, HPI_TUNER_STATUS,
                         &dwStatus);
      if (pwStatus) {
            if (!nError) {
                  *pwStatusMask = (u16) (dwStatus >> 16);
                  *pwStatus = (u16) (dwStatus & 0xFFFF);
            } else {
                  *pwStatusMask = 0;
                  *pwStatus = 0;
            }
      }
      return nError;
}

u16 HPI_Tuner_SetMode(HPI_HSUBSYS * phSubSys,
                  HPI_HCONTROL hControlHandle, u32 nMode, u32 nValue)
{
      return HPI_ControlParamSet(phSubSys, hControlHandle, HPI_TUNER_MODE,
                           nMode, nValue);
}

u16 HPI_Tuner_GetMode(HPI_HSUBSYS * phSubSys,
                  HPI_HCONTROL hControlHandle, u32 nMode, u32 * pnValue)
{
      return HPI_ControlParamGet(phSubSys, hControlHandle, HPI_TUNER_MODE,
                           nMode, 0, pnValue, NULL);
}

/**\}*/
/////////////////////////////////////////////////////////////////////////
/** \defgroup volume Volume Control
\{
*/
u16 HPI_VolumeSetGain(HPI_HSUBSYS * phSubSys,
                  HPI_HCONTROL hControlHandle,
                  short anLogGain[HPI_MAX_CHANNELS]
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      memcpy(hm.u.c.anLogValue, anLogGain, sizeof(short) * HPI_MAX_CHANNELS);
      hm.u.c.wAttribute = HPI_VOLUME_GAIN;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_VolumeGetGain(HPI_HSUBSYS * phSubSys,
                  HPI_HCONTROL hControlHandle,
                  short anLogGain[HPI_MAX_CHANNELS]
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_VOLUME_GAIN;

      HPI_Message(&hm, &hr);

      memcpy(anLogGain, hr.u.c.anLogValue, sizeof(short) * HPI_MAX_CHANNELS);
      return (hr.wError);
}

u16 HPI_VolumeQueryRange(HPI_HSUBSYS * phSubSys,
                   HPI_HCONTROL hControlHandle,
                   short *nMinGain_01dB,
                   short *nMaxGain_01dB, short *nStepGain_01dB)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_VOLUME_RANGE;

      HPI_Message(&hm, &hr);
      if (hr.wError) {
            hr.u.c.anLogValue[0] = hr.u.c.anLogValue[1] = 0;
            hr.u.c.dwParam1 = (u32) 0;
      }
      if (nMinGain_01dB)
            *nMinGain_01dB = hr.u.c.anLogValue[0];
      if (nMaxGain_01dB)
            *nMaxGain_01dB = hr.u.c.anLogValue[1];
      if (nStepGain_01dB)
            *nStepGain_01dB = (short)hr.u.c.dwParam1;
      return (hr.wError);
}

/* starts an automatic ramp of the volume control from the current gain setting to
the specified setting over the specified duration (in milliseconds )
The profile can be either log or linear
*/

u16 HPI_VolumeAutoFadeProfile(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, short anStopGain0_01dB[HPI_MAX_CHANNELS], u32 dwDurationMs, u16 wProfile /* HPI_VOLUME_AUTOFADE_??? */
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      memcpy(hm.u.c.anLogValue, anStopGain0_01dB,
             sizeof(short) * HPI_MAX_CHANNELS);

      if (wProfile < HPI_VOLUME_AUTOFADE)
            wProfile = HPI_VOLUME_AUTOFADE;

      hm.u.c.wAttribute = wProfile;
      hm.u.c.dwParam1 = dwDurationMs;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_VolumeAutoFade(HPI_HSUBSYS * phSubSys,
                   HPI_HCONTROL hControlHandle,
                   short anStopGain0_01dB[HPI_MAX_CHANNELS],
                   u32 dwDurationMs)
{
      return HPI_VolumeAutoFadeProfile(phSubSys,
                               hControlHandle,
                               anStopGain0_01dB,
                               dwDurationMs, HPI_VOLUME_AUTOFADE);
}

/** \} */
/////////////////////////////////////////////////////////////////////////
/**  \defgroup Vox Vox control
VOX controls are always situated on a destination node of type HPI_DESTNODE_ISTREAM.
The VOX control specifies the signal level required for recording to begin.
Until the signal exceeds the VOX level no samples are recorded to the record stream.
After the VOX level has been exceeded, recording continues until the stream is stopped or reset.

A trigger level of -100 dB indicates that recording begins with any level audio signal.
A single threshold level is used for both left and right channels.
If either channel exceeds the threshold, recording will proceed.

@{
*/

/**
Sets the threshold of a VOX control.  Note the threshold is in units of 0.01dB.
The threshold will typically range between 0 and -100dB.
On startup the VOX control is set to -100 dB.
*/

03026 u16 HPI_VoxSetThreshold(HPI_HSUBSYS * phSubSys, ///< Subsystem handle
                  HPI_HCONTROL hControlHandle,  ///< Handle of a vox control
                  short anGain0_01dB      ///<  Trigger level in 100ths of a dB
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_VOX_THRESHOLD;

#ifndef HPI_KERNEL_MODE
/// \bug Requires floating point operations, not usable in kernel mode. Kernel mode uses raw linear value instead.

// convert db range 0..-100 dB , 0.01dB (20log10) to 0..32767 (-96 dB = 0 )
      {
/*
fDB = 20 * log10( fLinear/32767 )

fLinear = 10^(fDB/20) * 32767

Want to avoid using pow() routine, because math libraries in the past
have not handled it well.

Re-arrange to us log()/exp() (natural log) routines.

Re-write 10^(fDB/20) using natural logs.

fLinear = exp( log(10.0) * fDB/20.0 ) * 32767.0;

*/
            float fDB = (float)anGain0_01dB / 100.0f; // units are 0.01dB
            float fLinear = 0.0;
            fLinear = (float)(exp(log(10.0) * fDB / 20.0) * 32767.0);
            hm.u.c.anLogValue[0] = (short)(fLinear);  // only use the first index (LEFT)
      }
#else

      hm.u.c.anLogValue[0] = anGain0_01dB;      // only use the first index (LEFT)
#endif

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/** Get the current threshold setting of a vox control
*/
03076 u16 HPI_VoxGetThreshold(HPI_HSUBSYS * phSubSys, ///< Subsystem handle
                  HPI_HCONTROL hControlHandle,  ///< Handle of a vox contrl
                  short *anGain0_01dB     ///<  [out] Trigger level in 100ths of a dB
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.c.wControlIndex);
      hm.u.c.wAttribute = HPI_VOX_THRESHOLD;

      HPI_Message(&hm, &hr);

#ifndef HPI_KERNEL_MODE
/// \bug Requires floating point operations, not usable in kernel mode

// convert db range 0..-100 dB , 0.01dB (20log10) to 0..32767 (-96 dB = 0 )
      {
/*
fDB = 20 * log10( fLinear/32767 )

fLinear = 10^(fDB/20) * 32767

Want to avoid using pow() routine, because math libraries in the past
have not handled it well.

Re-arrange to us log()/exp() (natural log) routines.

Re-write 10^(fDB/20) using natural logs.

fLinear = exp( log(10.0) * fDB/20.0 ) * 32767.0;

*/
            float fDB, fLinear;

            if (hr.u.c.anLogValue[0] == 0) {
                  fDB = -100.0;
            } else {
                  fLinear = (float)hr.u.c.anLogValue[0];
                  fDB =
                      (float)(log(fLinear / 32767.0) * 20.0 / log(10.0));
            }

            *anGain0_01dB = (short)(fDB * 100.0);     // only use the first index (LEFT)
      }
#else

      *anGain0_01dB = hr.u.c.anLogValue[0];     // only use the first index (LEFT)
#endif

      return (hr.wError);
}

/** @}*/
        /** @} */// group mixer
////////////////////////////////////////////////////////////////////////////
/**\defgroup clock Clock
Realtime clock
\note Not currently implemented anywhere???
Only one clock per adapter
\{
*/
/// open the clock and get a handle
03141 u16 HPI_ClockOpen(HPI_HSUBSYS * phSubSys,
              u16 wAdapterIndex, HPI_HCLOCK * phClock)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CLOCK, HPI_CLOCK_OPEN);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

#ifdef TRY_NEW_HANDLE_STRUCT
      if (hr.wError == 0) {
            phClock->adapterIndex = wAdapterIndex;
            phClock->dspIndex = 0;
            phClock->objIndex = 0;
            phClock->valid = 1;
      } else
            phClock->valid = 0;
#else
      if (hr.wError == 0)
            *phClock = HPI_IndexesToHandle('T', wAdapterIndex, 0);      // only 1 clock obj per adapter
      else
            *phClock = 0;
#endif

      return (hr.wError);
}

/// set the time of the DSP clock object.
03171 u16 HPI_ClockSetTime(HPI_HSUBSYS * phSubSys,
                 HPI_HCLOCK hClock,
                 u16 wHour, u16 wMinute, u16 wSecond, u16 wMilliSeconds)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CLOCK, HPI_CLOCK_SET_TIME);
#ifdef TRY_NEW_HANDLE_STRUCT
      if (!hClock.valid)
            return HPI_ERROR_OBJ_NOT_OPEN;
      hm.wAdapterIndex = hClock.adapterIndex;
#else
      HPI_HANDLETOINDEXES(hClock, &hm.wAdapterIndex, NULL);
#endif
      hm.u.t.wMilliSeconds = wMilliSeconds;
      hm.u.t.wSeconds = wSecond;
      hm.u.t.wMinutes = wMinute;
      hm.u.t.wHours = wHour;
      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/// set the time of the DSP clock object.
03196 u16 HPI_ClockGetTime(HPI_HSUBSYS * phSubSys,
                 HPI_HCLOCK hClock,
                 u16 * pwHour,
                 u16 * pwMinute, u16 * pwSecond, u16 * pwMilliSecond)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CLOCK, HPI_CLOCK_GET_TIME);
#ifdef TRY_NEW_HANDLE_STRUCT
      if (!hClock.valid)
            return HPI_ERROR_OBJ_NOT_OPEN;
      hm.wAdapterIndex = hClock.adapterIndex;
#else
      HPI_HANDLETOINDEXES(hClock, &hm.wAdapterIndex, NULL);
#endif
      HPI_Message(&hm, &hr);
      if (pwMilliSecond)
            *pwMilliSecond = hr.u.t.wMilliSeconds;
      if (pwSecond)
            *pwSecond = hr.u.t.wSeconds;
      if (pwMinute)
            *pwMinute = hr.u.t.wMinutes;
      if (pwHour)
            *pwHour = hr.u.t.wHours;

      return (hr.wError);
}

///\}
////////////////////////////////////////////////////////////////////////////
/**\defgroup gpio Digital I/O
The digital I/O object on an adapter reperesents a number of input bits
that may be individually sensed and a number of digital output bits that
may be individually set.

There is at most one gpio object per adapter.
\{
*/

u16 HPI_GpioOpen(HPI_HSUBSYS * phSubSys,
             u16 wAdapterIndex,
             HPI_HGPIO * phGpio,
             u16 * pwNumberInputBits, u16 * pwNumberOutputBits)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_GPIO, HPI_GPIO_OPEN);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

      if (hr.wError == 0) {
            *phGpio = HPI_IndexesToHandle('L', wAdapterIndex, 0); // only 1 digital i/o obj per adapter
            if (pwNumberInputBits)
                  *pwNumberInputBits = hr.u.l.wNumberInputBits;
            if (pwNumberOutputBits)
                  *pwNumberOutputBits = hr.u.l.wNumberOutputBits;
      } else
            *phGpio = 0;
      return (hr.wError);
}

/// read a particular bit from an adapters digital input port
03261 u16 HPI_GpioReadBit(HPI_HSUBSYS * phSubSys,
                HPI_HGPIO hGpio, u16 wBitIndex, u16 * pwBitData)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_GPIO, HPI_GPIO_READ_BIT);
      HPI_HANDLETOINDEXES(hGpio, &hm.wAdapterIndex, NULL);  // only one dig i/o obj per adapter
      hm.u.l.wBitIndex = wBitIndex;

      HPI_Message(&hm, &hr);

      *pwBitData = hr.u.l.wBitData;
      return (hr.wError);
}

/// read all bits from an adapters digital input port (upto 16)
03278 u16 HPI_GpioReadAllBits(HPI_HSUBSYS * phSubSys,
                  HPI_HGPIO hGpio, u16 * pwBitData)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_GPIO, HPI_GPIO_READ_ALL);
      HPI_HANDLETOINDEXES(hGpio, &hm.wAdapterIndex, NULL);  // only one dig i/o obj per adapter

      HPI_Message(&hm, &hr);

      *pwBitData = hr.u.l.wBitData;
      return (hr.wError);
}

/// write a particular bit to an adapters digital output port
03294 u16 HPI_GpioWriteBit(HPI_HSUBSYS * phSubSys,
                 HPI_HGPIO hGpio, u16 wBitIndex, u16 wBitData)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_GPIO, HPI_GPIO_WRITE_BIT);
      HPI_HANDLETOINDEXES(hGpio, &hm.wAdapterIndex, NULL);  // only one dig i/o obj per adapter
      hm.u.l.wBitIndex = wBitIndex;
      hm.u.l.wBitData = wBitData;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

///\}

////////////////////////////////////////////////////////////////////////////
/**\defgroup async Asynchronous Event Handling Functions
The asynchronous event module is designed to report events that occur on an adapter to an
\em interested application.

An Async object can be used to reciev notifications for both GPIO and other signal detection events.
A typical coding sequence would look something like:

\code

// The below code represents the bits that would go in an application.

...
// application startup section
HPI_AsyncEventOpen(pSS,0,&hAsync);
CreateThread(ThreadAsync);
...

...
// application shutdown
HPI_AsyncEventOpen(pSS,hAsync);
...

#define MAX_EVENTS 10
void ThreadAsync()
{
int ExitSignalled=0;
u16 wError;
tHPIAsyncEvent e[MAX_EVENTS]

while(!ExitSignalled)
{
wError = u16 HPI_AsyncEventWait( pSS, hAsync,
MAX_EVENTS,
&e[0],
&wEvents);

if(wError==HPI_ASYNC_TERMINATE_WAIT)
ExitSignalled=1;
else
{
if(!wError)
for(i=0;i<wEvents;i++)
CallCodeToProcessEvent(e[i]);
}

}
}

\endcode

\{
*/

/** Open an ASync object.
Opens a GPIO object and returns a handle to the same.
\return 0==success or HPI_ERROR_*
*/
03370 u16 HPI_AsyncEventOpen(HPI_HSUBSYS * phSubSys,  ///< Subsystem handle.
                   u16 wAdapterIndex,     ///< The adapter index to open the Async object.
                   HPI_HASYNC * phAsync   ///< Returned handle of an ASync object.
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ASYNCEVENT, HPI_ASYNCEVENT_OPEN);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

      if (hr.wError == 0) {
            *phAsync = HPI_IndexesToHandle('E', wAdapterIndex, 0);      // only 1 nv-memory obj per adapter
      } else
            *phAsync = 0;
      return (hr.wError);

}

/** Closes an ASync object.
\return 0==success or HPI_ERROR_*
*/
03394 u16 HPI_AsyncEventClose(HPI_HSUBSYS * phSubSys, ///< Subsystem handle.
                  HPI_HASYNC hAsync ///< Handle of the Async object to close.
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ASYNCEVENT, HPI_ASYNCEVENT_OPEN);
      HPI_HANDLETOINDEXES(hAsync, &hm.wAdapterIndex, NULL);

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/** Waits for a asynchronous events.
This call waits for any async event. The calling thread is suspended until an ASync event
is detected. After the async event is detected the call completes and returns information
about the event(s) that occured.
\return 0==success or HPI_ERROR_*
*/
03415 u16 HPI_AsyncEventWait(HPI_HSUBSYS * phSubSys,  ///< Subsystem handle.
                   HPI_HASYNC hAsync,     ///< Handle of an Async object.
                   u16 wMaximumEvents,    ///< Maximum number of events matches size of array passed in pEvents.
                   HPI_ASYNC_EVENT * pEvents,   ///< Events are returned here.
                   u16 * pwNumberReturned ///< Number events returned.
    )
{
      return (0);
}

/** Returns the number of asynchronous events waiting.
\return 0==success or HPI_ERROR_*
*/
03428 u16 HPI_AsyncEventGetCount(HPI_HSUBSYS * phSubSys,    ///< Subsystem handle.
                     HPI_HASYNC hAsync,   ///< Handle of an Async object.
                     u16 * pwCount  /// Returned number of events waiting.
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ASYNCEVENT, HPI_ASYNCEVENT_GETCOUNT);
      HPI_HANDLETOINDEXES(hAsync, &hm.wAdapterIndex, NULL);

      HPI_Message(&hm, &hr);

      if (hr.wError == 0)
            if (pwCount)
                  *pwCount = hr.u.as.u.count.wCount;

      return (hr.wError);
}

/** Returns single or many asynchronous events.
This call will read any waiting events from the asynchronous event queue and return a description of the event. It is
non-blocking.
\return 0==success or HPI_ERROR_*
*/
03453 u16 HPI_AsyncEventGet(HPI_HSUBSYS * phSubSys,   ///< Subsystem handle.
                  HPI_HASYNC hAsync,      ///< Handle of an Async object.
                  u16 wMaximumEvents,     ///< Maximum number of events matches size of array passed in pEvents.
                  HPI_ASYNC_EVENT * pEvents,    ///< Events are returned here.
                  u16 * pwNumberReturned  ///< Number events returned.
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_ASYNCEVENT, HPI_ASYNCEVENT_GET);
      HPI_HANDLETOINDEXES(hAsync, &hm.wAdapterIndex, NULL);

      HPI_Message(&hm, &hr);
      if (!hr.wError) {
            memcpy(pEvents, &hr.u.as.u.event, sizeof(HPI_ASYNC_EVENT));
            *pwNumberReturned = 1;
      }

      return (hr.wError);
}

///\}

////////////////////////////////////////////////////////////////////////////
/** \defgroup nvmem Nonvolatile memory

Some adapters contain non-volatile memory containing a number of bytes
The number of data words is adapter dependant and can be obtained
from the *pwSizeInBytes parameter returned from the Open function

There can be at most one nvmemory object per adapter.

@{
*/
u16 HPI_NvMemoryOpen(HPI_HSUBSYS * phSubSys,
                 u16 wAdapterIndex,
                 HPI_HNVMEMORY * phNvMemory, u16 * pwSizeInBytes)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_NVMEMORY, HPI_NVMEMORY_OPEN);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

      if (hr.wError == 0) {
            *phNvMemory = HPI_IndexesToHandle('N', wAdapterIndex, 0);   // only 1 nv-memory obj per adapter
            if (pwSizeInBytes)
                  *pwSizeInBytes = hr.u.n.wSizeInBytes;
      } else
            *phNvMemory = 0;
      return (hr.wError);
}

u16 HPI_NvMemoryReadByte(HPI_HSUBSYS * phSubSys,
                   HPI_HNVMEMORY hNvMemory, u16 wIndex, u16 * pwData)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_NVMEMORY, HPI_NVMEMORY_READ_BYTE);
      HPI_HANDLETOINDEXES(hNvMemory, &hm.wAdapterIndex, NULL);    // only one NvMem obj per adapter
      hm.u.n.wIndex = wIndex;

      HPI_Message(&hm, &hr);

      *pwData = hr.u.n.wData;
      return (hr.wError);
}

u16 HPI_NvMemoryWriteByte(HPI_HSUBSYS * phSubSys,
                    HPI_HNVMEMORY hNvMemory, u16 wIndex, u16 wData)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_NVMEMORY, HPI_NVMEMORY_WRITE_BYTE);
      HPI_HANDLETOINDEXES(hNvMemory, &hm.wAdapterIndex, NULL);    // only one NvMem obj per adapter
      hm.u.n.wIndex = wIndex;
      hm.u.n.wData = wData;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/** @}  */
////////////////////////////////////////////////////////////////////////////
/** \defgroup profile Profile
The Profile object supports profiling of the DSP code.
It should be used as a development tool for measuring DSP code operation.
Comments in AXPROF.H describe the DSP side of the profiling operation
@{
*/
/** open all the profiles on a particular adapter.

If the adapter does not have profiling enabled, the function will return an error.

The complete profile set of all profiles can be thought of as any array of execution timings/profiles.
Each indexed profile corresponds to the execution of a particular segment of DSP code.

Note that HPI_ProfileStartAll() must be called after HPI_ProfileOpenAll() to start the profiling operation on the DSP.
*/
03558 u16 HPI_ProfileOpenAll(HPI_HSUBSYS * phSubSys,  ///<[in] HPI subsystem handle
                   u16 wAdapterIndex,     ///<[in] adapter index
                   u16 wProfileIndex,     ///< corresponds to DSP index
                   HPI_HPROFILE * phProfile,    ///<[out] profile handle
                   u16 * pwMaxProfiles    ///<[out] maximum number of profile bins supported
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_PROFILE, HPI_PROFILE_OPEN_ALL);
      hm.wAdapterIndex = wAdapterIndex;
      hm.wDspIndex = wProfileIndex;
      HPI_Message(&hm, &hr);

      *pwMaxProfiles = hr.u.p.u.o.wMaxProfiles;
      if (hr.wError == 0)
            *phProfile =
                HPI_IndexesToHandle('P', wAdapterIndex, wProfileIndex);
      else
            *phProfile = 0;
      return (hr.wError);
}

u16 HPI_ProfileGet(HPI_HSUBSYS * phSubSys,
               HPI_HPROFILE hProfile,
               u16 wIndex,
               u16 * pwSeconds,
               u32 * pdwMicroSeconds,
               u32 * pdwCallCount,
               u32 * pdwMaxMicroSeconds, u32 * pdwMinMicroSeconds)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_PROFILE, HPI_PROFILE_GET);
      HPI_HANDLETOINDEXES(hProfile, &hm.wAdapterIndex, &hm.wDspIndex);
      hm.u.p.wIndex = wIndex;
      HPI_Message(&hm, &hr);
      if (pwSeconds)
            *pwSeconds = hr.u.p.u.t.wSeconds;
      if (pdwMicroSeconds)
            *pdwMicroSeconds = hr.u.p.u.t.dwMicroSeconds;
      if (pdwCallCount)
            *pdwCallCount = hr.u.p.u.t.dwCallCount;
      if (pdwMaxMicroSeconds)
            *pdwMaxMicroSeconds = hr.u.p.u.t.dwMaxMicroSeconds;
      if (pdwMinMicroSeconds)
            *pdwMinMicroSeconds = hr.u.p.u.t.dwMinMicroSeconds;
      return (hr.wError);
}

/**
\deprecated this function is no longer supported. Please use HPI_ProfileGetUtilization() instead.
*/
03613 u16 HPI_ProfileGetIdleCount(HPI_HSUBSYS * phSubSys,
                      HPI_HPROFILE hProfile,
                      u16 wIndex, u32 * pdwIdleCycles, u32 * pdwCount)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_PROFILE, HPI_PROFILE_GET_IDLECOUNT);
      HPI_HANDLETOINDEXES(hProfile, &hm.wAdapterIndex, &hm.wDspIndex);
      hm.u.p.wIndex = wIndex;
      HPI_Message(&hm, &hr);
      if (hr.wError) {
            if (pdwIdleCycles)
                  *pdwIdleCycles = 0;
            if (pdwCount)
                  *pdwCount = 0;
      } else {
            if (pdwIdleCycles)
                  *pdwIdleCycles = hr.u.p.u.t.dwMicroSeconds;
            if (pdwCount)
                  *pdwCount = hr.u.p.u.t.dwCallCount;
      }
      return (hr.wError);
}

/** Get the DSP utilization in 1/100 of a percent
*/
03640 u16 HPI_ProfileGetUtilization(HPI_HSUBSYS * phSubSys, ///<[in] HPI subsystem handle
                        HPI_HPROFILE hProfile,  ///<[in] handle of profile object
                        u32 * pdwUtilization    ///<[out] DSP utilization in 100ths of a percent
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_PROFILE, HPI_PROFILE_GET_UTILIZATION);
      HPI_HANDLETOINDEXES(hProfile, &hm.wAdapterIndex, &hm.wDspIndex);
      HPI_Message(&hm, &hr);
      if (hr.wError) {
            if (pdwUtilization)
                  *pdwUtilization = 0;
      } else {
            if (pdwUtilization)
                  *pdwUtilization = hr.u.p.u.t.dwCallCount;
      }
      return (hr.wError);
}

u16 HPI_ProfileGetName(HPI_HSUBSYS * phSubSys,
                   HPI_HPROFILE hProfile,
                   u16 wIndex, char *szName, u16 nNameLength)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_PROFILE, HPI_PROFILE_GET_NAME);
      HPI_HANDLETOINDEXES(hProfile, &hm.wAdapterIndex, &hm.wDspIndex);
      hm.u.p.wIndex = wIndex;
      HPI_Message(&hm, &hr);
      if (hr.wError) {
            if (szName)
                  strcpy(szName, "??");
      } else {
            if (szName)
                  memcpy(szName, (char *)hr.u.p.u.n.szName, nNameLength);
      }
      return (hr.wError);
}

u16 HPI_ProfileStartAll(HPI_HSUBSYS * phSubSys, HPI_HPROFILE hProfile)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_PROFILE, HPI_PROFILE_START_ALL);
      HPI_HANDLETOINDEXES(hProfile, &hm.wAdapterIndex, &hm.wDspIndex);
      HPI_Message(&hm, &hr);

      return (hr.wError);
}

u16 HPI_ProfileStopAll(HPI_HSUBSYS * phSubSys, HPI_HPROFILE hProfile)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_PROFILE, HPI_PROFILE_STOP_ALL);
      HPI_HANDLETOINDEXES(hProfile, &hm.wAdapterIndex, &hm.wDspIndex);
      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/** @} */
////////////////////////////////////////////////////////////////////////////
/**\defgroup watchdog  Watchdog timer
Only one watch-dog per adapter.
\note Not implemented on any adapters as of 2005-06-01
\{
*/
/// Open a watch dog object and return a handle
03714 u16 HPI_WatchdogOpen(HPI_HSUBSYS * phSubSys,
                 u16 wAdapterIndex, HPI_HWATCHDOG * phWatchdog)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_WATCHDOG, HPI_WATCHDOG_OPEN);
      hm.wAdapterIndex = wAdapterIndex;

      HPI_Message(&hm, &hr);

      if (hr.wError == 0)
            *phWatchdog = HPI_IndexesToHandle('W', wAdapterIndex, 0);   // only 1 watchdog obj per adapter
      else
            *phWatchdog = 0;
      return (hr.wError);
}

/** set the time of the watch dog object.
Time=0 will disable the watchdog
*/
03735 u16 HPI_WatchdogSetTime(HPI_HSUBSYS * phSubSys,
                  HPI_HWATCHDOG hWatchdog, u32 dwTimeMillisec)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_WATCHDOG, HPI_WATCHDOG_SET_TIME);
      HPI_HANDLETOINDEXES(hWatchdog, &hm.wAdapterIndex, NULL);    // only one watchdog obj per adapter
      hm.u.w.dwTimeMs = dwTimeMillisec;

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

/// reset watchdog timer
03751 u16 HPI_WatchdogPing(HPI_HSUBSYS * phSubSys, HPI_HWATCHDOG hWatchdog)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_WATCHDOG, HPI_WATCHDOG_PING);
      HPI_HANDLETOINDEXES(hWatchdog, &hm.wAdapterIndex, NULL);    // only one watchdog obj per adapter

      HPI_Message(&hm, &hr);

      return (hr.wError);
}

///\}

/////////////////////////////////////////////////////////////////////////////////
/**\defgroup aes18 AES18 data transfer over AES/EBU link
Currently only relevant to ASI4601 adapters.
\{
*/

#ifdef HAS_AES18_ON_HOST

//****** test vars for dummy code
u8 awTest[200];
u16 wLength;
//**********

/* !!! Test only !!! */
void HPI_Aes18Init(void)
{
      Aes18_Init();
}

#endif

u16 HPI_AES18BGSetConfiguration(HPI_HSUBSYS * phSubSys,
                        HPI_HCONTROL hControlHandle,
                        u16 wBlocksPerSec[HPI_AES18_MAX_CHANNELS],
                        u16 wPriorityEnableMask[HPI_AES18_MAX_CHANNELS],
                        u16 wOperatingMode[HPI_AES18_MAX_CHANNELS],
                        u16 wChannelMode)
{
      u16 i;
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_CONTROLX_MSG_AES18BG *pAes18BGSetConfiguration = &hm.u.cx.u.aes18bg;

      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = HPI_AES18_CONFIG;

// Input bounds check
      for (i = 0; i < HPI_AES18_MAX_CHANNELS; i++) {
            switch (wBlocksPerSec[i]) {
            case 2:     // these are all ok
            case 5:
            case 24:
            case 25:
            case 33:
            case 100:
                  break;
            default:
                  return (HPI_ERROR_AES18BG_BLOCKSPERSEC);
            }

            if (wPriorityEnableMask[i] > HPI_AES18_MAX_PRIORITYMASK)
                  return (HPI_ERROR_AES18BG_PRIORITYMASK);
            switch (wOperatingMode[i]) {
            case HPI_AES18_MODE_MASTER:
            case HPI_AES18_MODE_SLAVE:
                  break;
            default:
                  return (HPI_ERROR_AES18BG_MODE);
            }
            switch (wChannelMode) {
            case HPI_AES18_CHANNEL_MODE_JOINT:
            case HPI_AES18_CHANNEL_MODE_INDEPENDENT:
                  break;
            default:
                  return (HPI_ERROR_AES18BG_CHANNEL_MODE);
            }
      }

      for (i = 0; i < HPI_AES18_MAX_CHANNELS; i++) {
            pAes18BGSetConfiguration->wBlocksPerSec[i] = wBlocksPerSec[i];
            pAes18BGSetConfiguration->wPriorityMask[i] =
                wPriorityEnableMask[i];
            pAes18BGSetConfiguration->wOperatingMode[i] = wOperatingMode[i];
      }
      pAes18BGSetConfiguration->wChannelMode = wChannelMode;

#ifndef HAS_AES18_ON_HOST

      HPI_Message(&hm, &hr);
#else

      AES18_Message(HPI_CONTROL_AES18_BLOCKGENERATOR, &hm, &hr);
#endif

      return (hr.wError);
}

u16 HPI_AES18RxSetAddress(HPI_HSUBSYS * phSubSys,
                    HPI_HCONTROL hControlHandle,
                    u16 awDecoderAddress[HPI_AES18_MAX_CHANNELS]
    )
{
      u16 i;
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_CONTROLX_MSG_AES18RX_ADDRESS *pAes18RxSetAddress =
          &hm.u.cx.u.aes18rx_address;

      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = HPI_AES18_ADDRESS;

// Check input bounds
/* HPI_AES18_MAX_ADDRESS = 0x10000, so following check is not required
for (i=0;i<HPI_AES18_MAX_CHANNELS;i++)
{
if(awDecoderAddress[i] >= HPI_AES18_MAX_ADDRESS)
return(HPI_ERROR_AES18_INVALID_ADDRESS);
}
*/

      for (i = 0; i < HPI_AES18_MAX_CHANNELS; i++) {
            pAes18RxSetAddress->wAddress[i] = awDecoderAddress[i];
      }
#ifndef HAS_AES18_ON_HOST
      HPI_Message(&hm, &hr);
#else

      AES18_Message(HPI_CONTROL_AES18_RECEIVER, &hm, &hr);
#endif

      return (hr.wError);
}

/* Receiver */

u16 HPI_AES18RxGetInternalBufferState(HPI_HSUBSYS * phSubSys,
                              HPI_HCONTROL hControlHandle,
                              u16 awFrameError[HPI_AES18_MAX_CHANNELS],
                              u16
                              awMessageWaiting[HPI_AES18_MAX_CHANNELS]
                              [HPI_AES18_MAX_PRIORITIES],
                              u16
                              awInternalBufferOverFlow
                              [HPI_AES18_MAX_CHANNELS]
                              [HPI_AES18_MAX_PRIORITIES],
                              u16
                              awMissedMessage[HPI_AES18_MAX_CHANNELS]
                              [HPI_AES18_MAX_PRIORITIES]
    )
{
      u16 wChannelCount, wPriorityCount, wBitShift;
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_CONTROLX_RES_AES18RX_BUFFER_STATE *pAes18RxGetIBState =
          &hr.u.cx.u.aes18rx_internal_buffer_state;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = HPI_AES18_INTERNAL_BUFFER_STATE;

#ifndef HAS_AES18_ON_HOST

      HPI_Message(&hm, &hr);
#else

      AES18_Message(HPI_CONTROL_AES18_RECEIVER, &hm, &hr);
#endif

/* Unpack the status bits from the response */
      if (awFrameError) {
            for (wChannelCount = 0; wChannelCount < HPI_AES18_MAX_CHANNELS;
                 wChannelCount++) {
                  awFrameError[wChannelCount] =
                      (pAes18RxGetIBState->
                       awFrameErrorPacked >> wChannelCount) & 1;
            }
      }

/* NOTE!!! Also need to check awInternalBufferOverFlow and awMissedMessage */
      wBitShift = 0;
      if (awMessageWaiting) {
            for (wChannelCount = 0; wChannelCount < HPI_AES18_MAX_CHANNELS;
                 wChannelCount++) {
                  for (wPriorityCount = 0;
                       wPriorityCount < HPI_AES18_MAX_PRIORITIES;
                       wPriorityCount++) {
                        awMessageWaiting[wChannelCount][wPriorityCount]
                            =
                            (pAes18RxGetIBState->
                             awMessageWaitingPacked >> wBitShift) & 1;

                        awInternalBufferOverFlow[wChannelCount]
                            [wPriorityCount] =
                            (pAes18RxGetIBState->
                             awInternalBufferOverFlowPacked >>
                             wBitShift) & 1;

                        awMissedMessage[wChannelCount][wPriorityCount] =
                            (pAes18RxGetIBState->
                             awMissedMessagePacked >> (wBitShift++)) &
                            1;
                  }
            }
      }

      return (hr.wError);

}

u16 HPI_AES18RxGetInternalBufferSize(HPI_HSUBSYS * phSubSys,
                             HPI_HCONTROL hControlHandle,
                             u16
                             awBytesPerBuffer[HPI_AES18_MAX_PRIORITIES]
    )
{
      u16 wPriorityCount;
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_CONTROLX_RES_AES18RX_BUFFER_SIZE *pAes18RxGetIBSize =
          &hr.u.cx.u.aes18rx_internal_buffer_size;

      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = HPI_AES18_INTERNAL_BUFFER_SIZE;

#ifndef HAS_AES18_ON_HOST

      HPI_Message(&hm, &hr);
#else

      AES18_Message(HPI_CONTROL_AES18_RECEIVER, &hm, &hr);
#endif

      if (awBytesPerBuffer) {
            for (wPriorityCount = 0;
                 wPriorityCount < HPI_AES18_MAX_PRIORITIES;
                 wPriorityCount++) {
                  awBytesPerBuffer[wPriorityCount] =
                      pAes18RxGetIBSize->awBytesPerBuffer[wPriorityCount];
            }
      }
      return (hr.wError);
}

u16 HPI_AES18RxGetMessage(HPI_HSUBSYS * phSubSys, HPI_HCONTROL hControlHandle, u16 wChannel, u16 wPriority, u16 wQueueSize,   // In bytes
                    u8 * pbMessage, u16 * pwMessageLength   // in bytes
    )
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_CONTROLX_RES_AES18RX_GET_MESSAGE *pAes18ResRxGetMessage =
          &hr.u.cx.u.aes18rx_get_message;
      HPI_CONTROLX_MSG_AES18RX_GET_MESSAGE *pAes18MsgRxGetMessage =
          &hm.u.cx.u.aes18rx_get_message;

      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = HPI_AES18_MESSAGE;

// Input bounds check
      if (wChannel >= HPI_AES18_MAX_CHANNELS)
            return (HPI_ERROR_INVALID_CHANNELS);

      if (wPriority > HPI_AES18_MAX_PRIORITIES)
            return (HPI_ERROR_AES18_INVALID_PRIORITY);

      pAes18MsgRxGetMessage->wChannel = wChannel;
      pAes18MsgRxGetMessage->wPriority = wPriority;
      pAes18MsgRxGetMessage->wQueueSize = wQueueSize;
      pAes18MsgRxGetMessage->dwpbMessage = (PTR32) pbMessage;

#ifndef HAS_AES18_ON_HOST

      HPI_Message(&hm, &hr);
#else

      AES18_Message(HPI_CONTROL_AES18_RECEIVER, &hm, &hr);
#endif

      *pwMessageLength = pAes18ResRxGetMessage->wReturnedMessageSize;
      return (hr.wError);
}

// Transmitter

u16 HPI_AES18TxSendMessage(HPI_HSUBSYS * phSubSys,
                     HPI_HCONTROL hControlHandle,
                     u16 wChannel,
                     u8 * pbMessage,
                     u16 wMessageLength,
                     u16 wDestinationAddress,
                     u16 wPriorityIndex, u16 wRepetitionIndex)
{
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_CONTROLX_MSG_AES18TX_SEND_MESSAGE *pAes18SendMsg =
          &hm.u.cx.u.aes18tx_send_message;

      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_SET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = HPI_AES18_MESSAGE;

// Input bounds check

      if (wChannel >= HPI_AES18_MAX_CHANNELS)
            return (HPI_ERROR_INVALID_CHANNELS);

      if (wPriorityIndex > HPI_AES18_MAX_PRIORITIES)
            return (HPI_ERROR_AES18_INVALID_PRIORITY);

/* HPI_AES18_MAX_ADDRESS = 0x10000, so following test is not required
if(wDestinationAddress > HPI_AES18_MAX_ADDRESS)
return(HPI_ERROR_AES18_INVALID_ADDRESS);
*/

      if (wRepetitionIndex > HPI_AES18_MAX_REPETITION)
            return (HPI_ERROR_AES18_INVALID_REPETITION);

      pAes18SendMsg->wChannel = wChannel;
      pAes18SendMsg->dwpbMessage = (PTR_AS_NUMBER) pbMessage;
      pAes18SendMsg->wMessageLength = wMessageLength;
      pAes18SendMsg->wDestinationAddress = wDestinationAddress;
      pAes18SendMsg->wPriorityIndex = wPriorityIndex;
      pAes18SendMsg->wRepetitionIndex = wRepetitionIndex;

#ifndef HAS_AES18_ON_HOST
      HPI_Message(&hm, &hr);
#else

      AES18_Message(HPI_CONTROL_AES18_TRANSMITTER, &hm, &hr);
#endif

      return (hr.wError);
}

u16 HPI_AES18TxGetInternalBufferState(HPI_HSUBSYS * phSubSys,
                              HPI_HCONTROL hControlHandle,
                              u16
                              awInternalBufferBusy
                              [HPI_AES18_MAX_CHANNELS]
                              [HPI_AES18_MAX_PRIORITIES]
    )
{
      u16 wChannelCount, wPriorityCount, wBitShift, wPackedBits;
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_CONTROLX_RES_AES18TX_BUFFER_STATE *pAes18TxGetIBState =
          &hr.u.cx.u.aes18tx_internal_buffer_state;
      UNUSED(phSubSys);

      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = HPI_AES18_INTERNAL_BUFFER_STATE;

      wBitShift = 0;

#ifndef HAS_AES18_ON_HOST

      HPI_Message(&hm, &hr);
#else

      AES18_Message(HPI_CONTROL_AES18_TRANSMITTER, &hm, &hr);
#endif

      wPackedBits = pAes18TxGetIBState->wInternalBufferBusyPacked;

/* Unpack the status bits from the response */
      if (awInternalBufferBusy) {
            for (wChannelCount = 0; wChannelCount < HPI_AES18_MAX_CHANNELS;
                 wChannelCount++) {
                  for (wPriorityCount = 0;
                       wPriorityCount < HPI_AES18_MAX_PRIORITIES;
                       wPriorityCount++) {
                        awInternalBufferBusy[wChannelCount]
                            [wPriorityCount] =
                            (wPackedBits >> (wBitShift++)) & 1;
                  }
            }
      }
      return (hr.wError);

};

u16 HPI_AES18TxGetInternalBufferSize(HPI_HSUBSYS * phSubSys,
                             HPI_HCONTROL hControlHandle,
                             u16
                             awBytesPerBuffer[HPI_AES18_MAX_PRIORITIES]
    )
{
      u16 wPriorityCount;
      HPI_MESSAGE hm;
      HPI_RESPONSE hr;
      HPI_CONTROLX_RES_AES18TX_BUFFER_SIZE *pAes18TxGetIBSize =
          &hr.u.cx.u.aes18tx_internal_buffer_size;
      UNUSED(phSubSys);
      HPI_InitMessage(&hm, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE);
      HPI_HANDLETOINDEXES(hControlHandle, &hm.wAdapterIndex,
                      &hm.u.cx.wControlIndex);
      hm.u.cx.wAttribute = HPI_AES18_INTERNAL_BUFFER_SIZE;

#ifndef HAS_AES18_ON_HOST
      HPI_Message(&hm, &hr);
#else
      AES18_Message(HPI_CONTROL_AES18_TRANSMITTER, &hm, &hr);
#endif

      if (awBytesPerBuffer) {
            for (wPriorityCount = 0;
                 wPriorityCount < HPI_AES18_MAX_PRIORITIES;
                 wPriorityCount++) {
                  awBytesPerBuffer[wPriorityCount] =
                      pAes18TxGetIBSize->awBytesPerBuffer[wPriorityCount];
            }
      }
      return (hr.wError);
}

#ifdef HAS_AES18_ON_HOST
/* prototype the functions in aes18.c */
int Aes18BgCtrl_Set(int nIndex, HPI_CONTROL_MSG * pCm, HPI_CONTROL_RES * pCr);
int Aes18RxCtrl_Set(int nIndex, HPI_CONTROL_MSG * pCm, HPI_CONTROL_RES * pCr);
int Aes18RxCtrl_Get(int nIndex, HPI_CONTROL_MSG * pCm, HPI_CONTROL_RES * pCr);
int Aes18TxCtrl_Set(int nIndex, HPI_CONTROL_MSG * pCm, HPI_CONTROL_RES * pCr);
int Aes18TxCtrl_Get(int nIndex, HPI_CONTROL_MSG * pCm, HPI_CONTROL_RES * pCr);

// Copied from ax4\axctrl.c DSP code.
// this function takes the control type as a parameter because when running
// on the pc, we dont get a correct control index

void AES18_Message(int wControlType, HPI_MESSAGE * pHm, HPI_RESPONSE * pHr)
{
      HPI_CONTROL_MSG *pCm = &pHm->u.c;
      HPI_CONTROL_RES *pCr = &pHr->u.c;
      int nIndex = 0;

      pHr->wError = HPI_ERROR_INVALID_CONTROL;
//  if( pCm->wControlIndex > nNumControls )
//      return;

      switch (pHm->wFunction) {
      case HPI_CONTROL_GET_STATE:
            switch (wControlType) {
            case HPI_CONTROL_AES18_TRANSMITTER:
                  Aes18TxCtrl_Get(nIndex, pCm, pCr);
                  break;
            case HPI_CONTROL_AES18_RECEIVER:
                  Aes18RxCtrl_Get(nIndex, pCm, pCr);
                  break;
            case HPI_CONTROL_AES18_BLOCKGENERATOR:
                  break;
            }
            break;
      case HPI_CONTROL_SET_STATE:
            switch (wControlType) {
            case HPI_CONTROL_AES18_TRANSMITTER:
                  Aes18TxCtrl_Set(nIndex, pCm, pCr);
                  break;
            case HPI_CONTROL_AES18_RECEIVER:
                  Aes18RxCtrl_Set(nIndex, pCm, pCr);
                  break;
            case HPI_CONTROL_AES18_BLOCKGENERATOR:
                  Aes18BgCtrl_Set(nIndex, pCm, pCr);
                  break;
            }
            break;
      default:
            return;
      }

}
#endif                        /* HAS_AES18_ON_HOST */
///\}
/////////////////////////////////////////////////////////////////////////
/** \defgroup utility Utility Functions
@{
*/

#if 0
/// global to store specifc errors for use by HPI_GetLastErrorDetail
u32 gadwHpiSpecificError[4] = { 0, 0, 0, 0 };

/// Get HW specific errors
void HPI_GetLastErrorDetail(u16 wError, char *pszErrorText,
                      u32 ** padwSpecificError)
{
/* Need to get this via HPI message interface */
      *padwSpecificError = &gadwHpiSpecificError[0];  // send back pointer to array of errors
      HPI_GetErrorText(wError, pszErrorText);
}
#endif

/**
*/

void HPI_GetErrorText(u16 wError, char *pszErrorText)
{
      strcpy(pszErrorText, " ");

      sprintf(pszErrorText, "#%3d - ", wError);

      switch (wError) {
      case 0:
            strcat(pszErrorText, "No Error");
            break;
      case HPI_ERROR_INVALID_TYPE:  //100 // message type does not exist
            strcat(pszErrorText, "Invalid message type");
            break;
      case HPI_ERROR_INVALID_OBJ:   //101 // object type does not exist
            strcat(pszErrorText, "Invalid object type");
            break;
      case HPI_ERROR_INVALID_FUNC:  //102 // function does not exist
            strcat(pszErrorText, "Invalid function");
            break;
      case HPI_ERROR_INVALID_OBJ_INDEX:   //103 // the specified object (adapter/Stream) does not exist
            strcat(pszErrorText,
                   "Invalid object (adapter/stream/mixer/control) index");
            break;
      case HPI_ERROR_OBJ_NOT_OPEN:  //104
            strcat(pszErrorText, "Object not open");
            break;
      case HPI_ERROR_OBJ_ALREADY_OPEN:    //105
            strcat(pszErrorText, "Object already in use (opened)");
            break;
      case HPI_ERROR_INVALID_RESOURCE:    //106 // PCI, ISA resource not valid
            strcat(pszErrorText, "Invalid bus/port resource");
            break;
      case HPI_ERROR_SUBSYSFINDADAPTERS_GETINFO:      //107
            strcat(pszErrorText,
                   "GetInfo call from SubSysFindAdapters failed");
            break;
      case HPI_ERROR_INVALID_RESPONSE:    // 108
            strcat(pszErrorText, "Response structure not updated");
            break;
      case HPI_ERROR_PROCESSING_MESSAGE:  // 109
            strcat(pszErrorText, "wSize field of response was not updated");
            break;
      case HPI_ERROR_NETWORK_TIMEOUT:     //110
            strcat(pszErrorText, "Network timeout waiting for response");
            break;
      case HPI_ERROR_INVALID_HANDLE:      //111
            strcat(pszErrorText, "Invalid HPI handle (uninitialised?)");
            break;
      case HPI_ERROR_UNIMPLEMENTED: //1112
            strcat(pszErrorText, "Functionality not yet implemented");
            break;

      case HPI_ERROR_TOO_MANY_ADAPTERS:   //200
            strcat(pszErrorText, "Too many adapters");
            break;
      case HPI_ERROR_BAD_ADAPTER:   //201
            strcat(pszErrorText, "Bad adapter");
            break;
      case HPI_ERROR_BAD_ADAPTER_NUMBER:  //202    // adapter number out of range or not set properly
            strcat(pszErrorText, "Invalid adapter index");
            break;
      case HPI_DUPLICATE_ADAPTER_NUMBER:  //203    // 2 adapters with the same adapter number
            strcat(pszErrorText, "Duplicate adapter index");
            break;
      case HPI_ERROR_DSP_BOOTLOAD:  //204
            strcat(pszErrorText, "DSP failed bootload");
            break;
      case HPI_ERROR_DSP_SELFTEST:  //205
            strcat(pszErrorText, "DSP failed selftest");
            break;
      case HPI_ERROR_DSP_FILE_NOT_FOUND:  //206
            strcat(pszErrorText, "Failed to find/open DSP code file");
            break;
      case HPI_ERROR_DSP_HARDWARE:  //207
            strcat(pszErrorText, "internal DSP hardware error");
            break;
      case HPI_ERROR_DOS_MEMORY_ALLOC:    //208
            strcat(pszErrorText, "could not allocate memory in DOS");
            break;
      case HPI_ERROR_PLD_LOAD:      //209
            strcat(pszErrorText, "PLD could not be configured");
            break;
      case HPI_ERROR_DSP_FILE_FORMAT:     //210
            strcat(pszErrorText,
                   "Invalid DSP code file format (corrupt file?)");
            break;

      case HPI_ERROR_DSP_FILE_ACCESS_DENIED:    //211
            strcat(pszErrorText, "Found but could not open DSP code file");
            break;
      case HPI_ERROR_DSP_FILE_NO_HEADER:  //212
            strcat(pszErrorText,
                   "First DSP code section header not found in DSP file");
            break;
      case HPI_ERROR_DSP_FILE_READ_ERROR: //213
            strcat(pszErrorText,
                   "File read operation on DSP code file failed");
            break;
      case HPI_ERROR_DSP_SECTION_NOT_FOUND:     //214
            strcat(pszErrorText, "DSP code for adapter family not found");
            break;
      case HPI_ERROR_DSP_FILE_OTHER_ERROR:      //215
            strcat(pszErrorText,
                   "Other OS specific error opening DSP file");
            break;
      case HPI_ERROR_DSP_FILE_SHARING_VIOLATION:      //216
            strcat(pszErrorText, "Sharing violation opening DSP code file");
            break;

      case HPI_ERROR_BAD_CHECKSUM:  //221
            strcat(pszErrorText,
                   "Flash - could not determine a valid checksum");
            break;
      case HPI_ERROR_BAD_SEQUENCE:  //222
            strcat(pszErrorText,
                   "Flash - bad packet sequence number during flash programming");
            break;
      case HPI_ERROR_FLASH_ERASE:   //223
            strcat(pszErrorText, "Flash - erase failed");
            break;
      case HPI_ERROR_FLASH_PROGRAM: //224
            strcat(pszErrorText, "Flash - programming failed");
            break;
      case HPI_ERROR_FLASH_VERIFY:  //225
            strcat(pszErrorText, "Flash - verification failed");
            break;
      case HPI_ERROR_FLASH_TYPE:    //226
            strcat(pszErrorText, "Flash - wrong type of flash on hardware");
            break;
      case HPI_ERROR_FLASH_START:   //227
            strcat(pszErrorText,
                   "Flash - command to start programming sequence failed");
            break;

      case HPI_ERROR_INVALID_STREAM:      //300
            strcat(pszErrorText, "Invalid stream");
            break;
      case HPI_ERROR_INVALID_FORMAT:      //301
            strcat(pszErrorText, "Invalid Format");
            break;
      case HPI_ERROR_INVALID_SAMPLERATE:  //  302
            strcat(pszErrorText, "Invalid format sample rate");
            break;
      case HPI_ERROR_INVALID_CHANNELS:    //  303
            strcat(pszErrorText, "Invalid format number of channels");
            break;
      case HPI_ERROR_INVALID_BITRATE:     //  304
            strcat(pszErrorText, "Invalid format bitrate");
            break;
      case HPI_ERROR_INVALID_DATASIZE:    // 305
            strcat(pszErrorText,
                   "Invalid datasize used for stream read/write");
            break;
      case HPI_ERROR_BUFFER_FULL:   // 306
            strcat(pszErrorText,
                   "Stream buffer is full during stream write");
            break;
      case HPI_ERROR_BUFFER_EMPTY:  // 307
            strcat(pszErrorText,
                   "stream buffer is empty during stream read");
            break;
      case HPI_ERROR_INVALID_DATA_TRANSFER:     // 308
            strcat(pszErrorText,
                   "invalid datasize used for stream read/write");
            break;
      case HPI_ERROR_INVALID_OPERATION:   // 310
            strcat(pszErrorText,
                   "Invalid operation - object can't do requested operation in its current state");
            break;
      case HPI_ERROR_INCOMPATIBLE_SAMPLERATE:   // 311
            strcat(pszErrorText, "Cannot change to requested samplerate");
            break;
      case HPI_ERROR_BAD_ADAPTER_MODE:    // 312
            strcat(pszErrorText, "Invalid adapter mode");
            break;

      case HPI_ERROR_INVALID_NODE:  //400
            strcat(pszErrorText, "Invalid mixer node");
            break;
      case HPI_ERROR_INVALID_CONTROL:     //401
            strcat(pszErrorText, "Invalid mixer control");
            break;
      case HPI_ERROR_INVALID_CONTROL_VALUE:     // 402
            strcat(pszErrorText, "Invalid mixer control value");
            break;
      case HPI_ERROR_INVALID_CONTROL_ATTRIBUTE: // 403
            strcat(pszErrorText, "Invalid mixer control attribute");
            break;
      case HPI_ERROR_CONTROL_DISABLED:    // 404
            strcat(pszErrorText, "Mixer control disabled");
            break;

      case HPI_ERROR_NVMEM_BUSY:    // 450
            strcat(pszErrorText, "Non-volatile memory is busy");
            break;

      case HPI_ERROR_AES18BG_BLOCKSPERSEC:      //  500
      case HPI_ERROR_AES18BG_PRIORITYMASK:      //  501
      case HPI_ERROR_AES18BG_MODE:  //          502
      case HPI_ERROR_AES18_INVALID_PRIORITY:    //    503
      case HPI_ERROR_AES18_INVALID_ADDRESS:     // 504
      case HPI_ERROR_AES18_INVALID_REPETITION:  //  505
      case HPI_ERROR_AES18BG_CHANNEL_MODE:      //      506
      case HPI_ERROR_AES18_INVALID_CHANNEL:     //  507
            strcat(pszErrorText, "an AES18 error");
            break;

      default:
            strcat(pszErrorText, "Unknown Error");
      }
}

/** Initialize an audio format structure, given various defining parameters

*/
04483 u16 HPI_FormatCreate(HPI_FORMAT * pFormat,      ///< [out] Format structure to be initialized
                 u16 wChannels,     ///< From 1 to 8
                 u16 wFormat, ///< One of the \ref formats
                 u32 dwSampleRate,  ///< Hz. Samplerate must be between 8000 and 200000
                 u32 dwBitRate,     ///< bits per second, must be supplied for MPEG formats, it is calculated for PCM formats
                 u32 dwAttributes   ///< format dependent attributes.  E.g. \ref mpegmodes
    )
{
      u16 wError = 0;

// can be mono or stereo
      if (wChannels < 1)
            wChannels = 1;
      if (wChannels > 8)
            wChannels = 8;

      pFormat->wChannels = wChannels;

// make sure we have a valid audio format
      switch (wFormat) {
      case HPI_FORMAT_PCM16_SIGNED:
      case HPI_FORMAT_PCM24_SIGNED:
      case HPI_FORMAT_PCM32_SIGNED:
      case HPI_FORMAT_PCM32_FLOAT:
      case HPI_FORMAT_PCM16_BIGENDIAN:
      case HPI_FORMAT_PCM8_UNSIGNED:
      case HPI_FORMAT_MPEG_L1:
      case HPI_FORMAT_MPEG_L2:
      case HPI_FORMAT_MPEG_L3:
      case HPI_FORMAT_DOLBY_AC2:
      case HPI_FORMAT_AA_TAGIT1_HITS:
      case HPI_FORMAT_AA_TAGIT1_INSERTS:
      case HPI_FORMAT_RAW_BITSTREAM:
      case HPI_FORMAT_AA_TAGIT1_HITS_EX1:
      case HPI_FORMAT_OEM1:
      case HPI_FORMAT_OEM2:
            break;
      default:
            wError = HPI_ERROR_INVALID_FORMAT;
            return (wError);
      }
      pFormat->wFormat = wFormat;

//sample rate can be between 8kHz and 200kHz
      if (dwSampleRate < 8000L) {
            wError = HPI_ERROR_INCOMPATIBLE_SAMPLERATE;
            dwSampleRate = 8000L;
      }
      if (dwSampleRate > 200000L) {
            wError = HPI_ERROR_INCOMPATIBLE_SAMPLERATE;
            dwSampleRate = 200000L;
      }
      pFormat->dwSampleRate = dwSampleRate;

// for some formats (MPEG) we accept a bitrate
// for some (PCM) we calculate the bit rate
      switch (wFormat) {
      case HPI_FORMAT_MPEG_L1:
      case HPI_FORMAT_MPEG_L2:
      case HPI_FORMAT_MPEG_L3:
            pFormat->dwBitRate = dwBitRate;     // should validate!!!!!!!
            break;
      case HPI_FORMAT_PCM16_SIGNED:
      case HPI_FORMAT_PCM16_BIGENDIAN:
            pFormat->dwBitRate = (u32) wChannels *dwSampleRate * 2;
            break;
      case HPI_FORMAT_PCM32_SIGNED:
      case HPI_FORMAT_PCM32_FLOAT:
            pFormat->dwBitRate = (u32) wChannels *dwSampleRate * 4;
            break;
      case HPI_FORMAT_PCM8_UNSIGNED:
            pFormat->dwBitRate = (u32) wChannels *dwSampleRate;
            break;
      default:
            pFormat->dwBitRate = 0;
      }

// Set the dwAttributes field.
// The attributes are format dependent.
      switch (wFormat) {
      case HPI_FORMAT_MPEG_L2:
            if ((wChannels == 1) && (dwAttributes != HPI_MPEG_MODE_DEFAULT)) {
                  dwAttributes = HPI_MPEG_MODE_DEFAULT;     // correct the error anyway !
                  wError = HPI_ERROR_INVALID_FORMAT;
            } else if (dwAttributes > HPI_MPEG_MODE_DUALCHANNEL) {
                  dwAttributes = HPI_MPEG_MODE_DEFAULT;     // correct the error anyway !
                  wError = HPI_ERROR_INVALID_FORMAT;
            }
            pFormat->dwAttributes = dwAttributes;
            break;
      default:
            pFormat->dwAttributes = dwAttributes;
      }

      return (wError);
}

#if defined ( HPI_OS_WIN16 ) || defined ( HPI_OS_WIN32_USER ) || defined ( INCLUDE_WINDOWS_ON_LINUX )
static unsigned char PcmSubformatGUID[16] =
    { 1, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xAA, 0, 0x38, 0x9B, 0x71 };

u16 HPI_WaveFormatToHpiFormat(const PWAVEFORMATEX lpFormatEx,
                        HPI_FORMAT * pHpiFormat)
{
      u16 wError = 0;

      switch (lpFormatEx->wFormatTag) {
#if defined ( WAVE_FORMAT_EXTENSIBLE ) && defined ( _WAVEFORMATEXTENSIBLE_ )
      case WAVE_FORMAT_EXTENSIBLE:
// Make sure the subformat is PCM
            if (memcmp
                (&((PWAVEFORMATEXTENSIBLE) lpFormatEx)->SubFormat,
                 PcmSubformatGUID, 16) != 0) {
                  wError = HPI_ERROR_INVALID_FORMAT;
                  break;
            }
// else fallthrough
#endif
      case WAVE_FORMAT_PCM:
//DBGPRINTF0(DEBUG_MASK_WOD_CUSTOM,TEXT("PCM"));
            if (lpFormatEx->wBitsPerSample == 16)
                  pHpiFormat->wFormat = HPI_FORMAT_PCM16_SIGNED;
            else if (lpFormatEx->wBitsPerSample == 8)
                  pHpiFormat->wFormat = HPI_FORMAT_PCM8_UNSIGNED;
            else if (lpFormatEx->wBitsPerSample == 24)
                  pHpiFormat->wFormat = HPI_FORMAT_PCM24_SIGNED;
            else if (lpFormatEx->wBitsPerSample == 32)
                  pHpiFormat->wFormat = HPI_FORMAT_PCM32_SIGNED;
            else {
                  pHpiFormat->wFormat = 0;
                  wError = HPI_ERROR_INVALID_FORMAT;
            }
            break;
      case WAVE_FORMAT_IEEE_FLOAT:
            if (lpFormatEx->wBitsPerSample == 32)
                  pHpiFormat->wFormat = HPI_FORMAT_PCM32_FLOAT;
            else {
                  pHpiFormat->wFormat = 0;
                  wError = HPI_ERROR_INVALID_FORMAT;
            }
            break;

      case WAVE_FORMAT_DOLBY_AC2:
//DBGPRINTF0(DEBUG_MASK_WOD_CUSTOM,TEXT("AC2"));
            pHpiFormat->wFormat = HPI_FORMAT_DOLBY_AC2;
            break;

      case WAVE_FORMAT_MPEG:
            switch (((MPEG1WAVEFORMAT *) lpFormatEx)->fwHeadLayer) {
            case ACM_MPEG_LAYER1:
                  pHpiFormat->wFormat = HPI_FORMAT_MPEG_L1;
                  break;
            case ACM_MPEG_LAYER2:
                  pHpiFormat->wFormat = HPI_FORMAT_MPEG_L2;
                  break;
            case ACM_MPEG_LAYER3:
                  pHpiFormat->wFormat = HPI_FORMAT_MPEG_L3;
                  break;
            default:
                  pHpiFormat->wFormat = HPI_FORMAT_MPEG_L2;
                  break;      // really should be error
            }
            pHpiFormat->dwBitRate =
                ((MPEG1WAVEFORMAT *) lpFormatEx)->dwHeadBitrate;
            if (pHpiFormat->dwBitRate == 0)
                  pHpiFormat->dwBitRate = 256000L;    // must have a default
            pHpiFormat->wMode = 0;  //((MPEG1WAVEFORMAT*)lpFormatEx)->fwHeadMode;
            break;
      case WAVE_FORMAT_MPEGLAYER3:
            pHpiFormat->wFormat = HPI_FORMAT_MPEG_L3;
            pHpiFormat->dwBitRate =
                ((MPEGLAYER3WAVEFORMAT *) lpFormatEx)->wfx.nAvgBytesPerSec *
                8;
            if (pHpiFormat->dwBitRate == 0)
                  pHpiFormat->dwBitRate = 256000L;    // must have a default
            pHpiFormat->wMode = 0;  //((MPEG1WAVEFORMAT*)lpFormatEx)->fwHeadMode;
            break;

      default:
            wError = HPI_ERROR_INVALID_FORMAT;
      }
      pHpiFormat->wChannels = lpFormatEx->nChannels;
      pHpiFormat->dwSampleRate = lpFormatEx->nSamplesPerSec;
      pHpiFormat->wMode = 0;
      pHpiFormat->dwAttributes = 0;

      return (wError);
}

u16 HPI_HpiFormatToWaveFormat(const HPI_FORMAT * pHpiFormat,
                        PWAVEFORMATEX lpFormatEx)
{
      u16 wError = 0;

      lpFormatEx->cbSize = 0;

      lpFormatEx->nChannels = pHpiFormat->wChannels;
      lpFormatEx->nSamplesPerSec = pHpiFormat->dwSampleRate;

      switch (pHpiFormat->wFormat) {
      case HPI_FORMAT_PCM8_UNSIGNED:
            lpFormatEx->nAvgBytesPerSec =
                pHpiFormat->wChannels * pHpiFormat->dwSampleRate;
            lpFormatEx->nBlockAlign = pHpiFormat->wChannels;
            lpFormatEx->wBitsPerSample = 8;
            lpFormatEx->wFormatTag = WAVE_FORMAT_PCM;
            break;
      case HPI_FORMAT_PCM16_SIGNED:
            lpFormatEx->nAvgBytesPerSec =
                2 * pHpiFormat->wChannels * pHpiFormat->dwSampleRate;
            lpFormatEx->nBlockAlign = 2 * pHpiFormat->wChannels;
            lpFormatEx->wBitsPerSample = 16;
            lpFormatEx->wFormatTag = WAVE_FORMAT_PCM;
            break;
      case HPI_FORMAT_PCM24_SIGNED:
            lpFormatEx->nAvgBytesPerSec =
                3 * pHpiFormat->wChannels * pHpiFormat->dwSampleRate;
            lpFormatEx->nBlockAlign = 3 * pHpiFormat->wChannels;
            lpFormatEx->wBitsPerSample = 24;
            lpFormatEx->wFormatTag = WAVE_FORMAT_PCM;
            break;

      case HPI_FORMAT_PCM32_SIGNED:
            lpFormatEx->nAvgBytesPerSec =
                4 * pHpiFormat->wChannels * pHpiFormat->dwSampleRate;
            lpFormatEx->nBlockAlign = 4 * pHpiFormat->wChannels;
            lpFormatEx->wBitsPerSample = 32;
            lpFormatEx->wFormatTag = WAVE_FORMAT_PCM;
            break;

      case HPI_FORMAT_PCM32_FLOAT:
            lpFormatEx->nAvgBytesPerSec =
                4 * pHpiFormat->wChannels * pHpiFormat->dwSampleRate;
            lpFormatEx->nBlockAlign = 4 * pHpiFormat->wChannels;
            lpFormatEx->wBitsPerSample = 32;
            lpFormatEx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
            break;

      case HPI_FORMAT_AA_TAGIT1_HITS:
            lpFormatEx->nAvgBytesPerSec =
                2 * pHpiFormat->wChannels * pHpiFormat->dwSampleRate;
            lpFormatEx->nBlockAlign = 2 * pHpiFormat->wChannels;
            lpFormatEx->wBitsPerSample = 16;
            lpFormatEx->wFormatTag = WAVE_FORMAT_DEVELOPMENT;
            break;

//this is setup as MPEG layer 2
      case HPI_FORMAT_MPEG_L2:
      case HPI_FORMAT_MPEG_L3:
            lpFormatEx->wFormatTag = WAVE_FORMAT_MPEG;
            lpFormatEx->wBitsPerSample = 0;
// this is for 44.1kHz, stereo, 256kbs
            lpFormatEx->nBlockAlign
                =
                (unsigned short)((144 * pHpiFormat->dwBitRate) /
                             pHpiFormat->dwSampleRate);
            lpFormatEx->nAvgBytesPerSec = pHpiFormat->dwBitRate / 8;
            lpFormatEx->cbSize = 22;
            if (pHpiFormat->wFormat == HPI_FORMAT_MPEG_L2)
                  ((MPEG1WAVEFORMAT *) lpFormatEx)->fwHeadLayer =
                      ACM_MPEG_LAYER2;
            else
                  ((MPEG1WAVEFORMAT *) lpFormatEx)->fwHeadLayer =
                      ACM_MPEG_LAYER3;
//this makes the desired rather than actual
            ((MPEG1WAVEFORMAT *) lpFormatEx)->dwHeadBitrate =
                pHpiFormat->dwBitRate;
            if (pHpiFormat->wChannels == 2)
                  ((MPEG1WAVEFORMAT *) lpFormatEx)->fwHeadMode =
                      ACM_MPEG_JOINTSTEREO;
            else
                  ((MPEG1WAVEFORMAT *) lpFormatEx)->fwHeadMode =
                      ACM_MPEG_SINGLECHANNEL;

            ((MPEG1WAVEFORMAT *) lpFormatEx)->fwHeadModeExt = 0;  //0x000F;   //??
            ((MPEG1WAVEFORMAT *) lpFormatEx)->wHeadEmphasis = 0;
            ((MPEG1WAVEFORMAT *) lpFormatEx)->fwHeadFlags = 0;    //ACM_MPEG_ID_MPEG1;
            ((MPEG1WAVEFORMAT *) lpFormatEx)->dwPTSLow = 0;
            ((MPEG1WAVEFORMAT *) lpFormatEx)->dwPTSHigh = 0;
            break;

      default:
            wError = HPI_ERROR_INVALID_FORMAT;
      }

      return (wError);
}

#endif                        /* defined(HPI_OS_WIN16) || defined(HPI_OS_WIN32_USER) */

/// Initialize a HPI_DATA structure
04774 u16 HPI_DataCreate(HPI_DATA * pData,      ///<[inout] Structure to be initialised
               HPI_FORMAT * pFormat,      ///<[in] format of the data
               u8 * pbData,   ///<[in] pointer to data buffer
               u32 dwDataSize ///<[in] amount of data in buffer
    )
{
      memcpy(&pData->Format, pFormat, sizeof(HPI_FORMAT));
      pData->dwpbData = (PTR_AS_NUMBER) pbData;
      pData->dwDataSize = dwDataSize;
      return (0);
}

/// The actual message size for each object type
04787 static u16 aMsgSize[HPI_OBJ_MAXINDEX + 1] = HPI_MESSAGE_SIZE_BY_OBJECT;
/// The actual response size for each object type
04789 static u16 aResSize[HPI_OBJ_MAXINDEX + 1] = HPI_RESPONSE_SIZE_BY_OBJECT;

/// initialize the HPI message structure
void HPI_InitMessage(HPI_MESSAGE * phm, u16 wObject, u16 wFunction)
{
      memset(phm, 0, sizeof(HPI_MESSAGE));
      if ((wObject > 0) && (wObject <= HPI_OBJ_MAXINDEX)) {
            phm->wType = HPI_TYPE_MESSAGE;
            phm->wSize = aMsgSize[wObject];
            phm->wObject = wObject;
            phm->wFunction = wFunction;
            phm->wDspIndex = 0;
// Expect adapter index to be set by caller
      } else {
            phm->wType = 0;
            phm->wSize = 0;
      }
}

/// initialize the HPI response structure
04809 void HPI_InitResponse(HPI_RESPONSE * phr, u16 wObject, u16 wFunction,
                  u16 wError)
{
      memset(phr, 0, sizeof(HPI_RESPONSE));
      phr->wType = HPI_TYPE_RESPONSE;
      phr->wSize = aResSize[wObject];
      phr->wObject = wObject;
      phr->wFunction = wFunction;
      phr->wError = wError;
      phr->wSpecificError = 0;
}

        /** @} */// group utility
////////////////////////////////////////////////////////////////////////
// local functions

/** make a handle to an object from the indexes that reference it
\sa HPI_HandleToIndexes()
*/
u32 HPI_IndexesToHandle(const char cObject,     ///< a character representing the type of object
                  const u16 wIndex1,      ///< The Adapter index
                  const u16 wIndex2 ///< The stream or control index, if used
    )
{
      u32 dwHandle = 0;
      dwHandle =
          (((u32) cObject) << 24) | ((u32) (wIndex1 & 0xFFF) << 12) |
          ((u32) (wIndex2 & 0xFFF));
      return (dwHandle);
}

/** turn a handle back into indexes
/sa HPI_IndexesToHandle()
*/
void HPI_HandleToIndexes(const u32 dwHandle, u16 * pwIndex1, u16 * pwIndex2)
{
      if (pwIndex1)
            *pwIndex1 = (u16) ((dwHandle >> 12) & 0xFFF);
      if (pwIndex2)
            *pwIndex2 = (u16) (dwHandle & 0xFFF);
}

/**
Encode 3 indices and an object type into a 32 bit handle.

\return Object handle
\sa HPI_HandleToIndexes3()
*/
u32 HPI_IndexesToHandle3(const char cObject,    ///< a character representing the type of object
                   const u16 wAdapterIndex,     ///< The Adapter index
                   const u16 wObjectIndex,      ///< The stream or control index, if used
                   const u16 wDspIndex    ///< The index of the DSP which implements the object
    )
{
      u32 dwHandle = 0;
      dwHandle = (((u32) cObject) << 24) |
          ((u32) (wDspIndex & 0xFF) << 16) |
          ((u32) (wAdapterIndex & 0xFF) << 8) | ((u32) (wObjectIndex & 0xFF));
      return (dwHandle);
}

/**
Extract up to 3 indices from an object handle, if non-NULL pointers are supplied

/sa HPI_IndexesToHandle3(), HPI_IndexesToHandle()
*/

void HPI_HandleToIndexes3(const u32 dwHandle,   ///< The handle to decode
                    u16 * pwAdapterIndex, ///< Where to store the Adapter index
                    u16 * pwObjectIndex,  ///< Where to store the stream or control index, if used
                    u16 * pwDspIndex      ///< Where to store the index of the DSP which implements the object
    )
{
      if (pwDspIndex)
            *pwDspIndex = (u16) ((dwHandle >> 16) & 0xFF);
      if (pwAdapterIndex)
            *pwAdapterIndex = (u16) ((dwHandle >> 8) & 0xFF);
      if (pwObjectIndex)
            *pwObjectIndex = (u16) (dwHandle & 0xFF);
}

///////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index