Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88c32343 authored by Ricardo Garcia's avatar Ricardo Garcia Committed by Android (Google) Code Review
Browse files

Merge "Floating point support for audio post processing components"

parents 2648da1f d7d01344
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ LOCAL_C_INCLUDES := \
	$(call include-path-for, audio-effects) \
	$(call include-path-for, audio-utils)

LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT
LOCAL_CFLAGS += -Wall -Werror

LOCAL_HEADER_LIBRARIES += libhardware_headers
+339 −7
Original line number Diff line number Diff line
@@ -33,6 +33,10 @@

#define MINUS_3_DB_IN_Q19_12 2896 // -3dB = 0.707 * 2^12 = 2896

#ifdef BUILD_FLOAT
#define MINUS_3_DB_IN_FLOAT 0.70710678f // -3dB = 0.70710678f
#endif

// subset of possible audio_channel_mask_t values, and AUDIO_CHANNEL_OUT_* renamed to CHANNEL_MASK_*
typedef enum {
    CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD_BACK,
@@ -82,8 +86,19 @@ static const effect_descriptor_t * const gDescriptors[] = {

// number of effects in this library
const int kNbEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);


#ifdef BUILD_FLOAT
static LVM_FLOAT clamp_float(LVM_FLOAT a) {
    if (a > 1.0f) {
        return 1.0f;
    }
    else if (a < -1.0f) {
        return -1.0f;
    }
    else {
        return a;
    }
}
#endif
/*----------------------------------------------------------------------------
 * Test code
 *--------------------------------------------------------------------------*/
@@ -286,7 +301,7 @@ int32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t
    return -EINVAL;
}


#ifndef BUILD_FLOAT
/*--- Effect Control Interface Implementation ---*/

static int Downmix_Process(effect_handle_t self,
@@ -385,7 +400,108 @@ static int Downmix_Process(effect_handle_t self,

    return 0;
}
#else /*BUILD_FLOAT*/
/*--- Effect Control Interface Implementation ---*/

static int Downmix_Process(effect_handle_t self,
        audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {

    downmix_object_t *pDownmixer;
    LVM_FLOAT *pSrc, *pDst;
    downmix_module_t *pDwmModule = (downmix_module_t *)self;

    if (pDwmModule == NULL) {
        return -EINVAL;
    }

    if (inBuffer == NULL || inBuffer->raw == NULL ||
        outBuffer == NULL || outBuffer->raw == NULL ||
        inBuffer->frameCount != outBuffer->frameCount) {
        return -EINVAL;
    }

    pDownmixer = (downmix_object_t*) &pDwmModule->context;

    if (pDownmixer->state == DOWNMIX_STATE_UNINITIALIZED) {
        ALOGE("Downmix_Process error: trying to use an uninitialized downmixer");
        return -EINVAL;
    } else if (pDownmixer->state == DOWNMIX_STATE_INITIALIZED) {
        ALOGE("Downmix_Process error: trying to use a non-configured downmixer");
        return -ENODATA;
    }

    pSrc = (LVM_FLOAT *) inBuffer->s16;
    pDst = (LVM_FLOAT *) outBuffer->s16;
    size_t numFrames = outBuffer->frameCount;

    const bool accumulate =
            (pDwmModule->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
    const uint32_t downmixInputChannelMask = pDwmModule->config.inputCfg.channels;

    switch(pDownmixer->type) {

      case DOWNMIX_TYPE_STRIP:
          if (accumulate) {
              while (numFrames) {
                  pDst[0] = clamp_float(pDst[0] + pSrc[0]);
                  pDst[1] = clamp_float(pDst[1] + pSrc[1]);
                  pSrc += pDownmixer->input_channel_count;
                  pDst += 2;
                  numFrames--;
              }
          } else {
              while (numFrames) {
                  pDst[0] = pSrc[0];
                  pDst[1] = pSrc[1];
                  pSrc += pDownmixer->input_channel_count;
                  pDst += 2;
                  numFrames--;
              }
          }
          break;

      case DOWNMIX_TYPE_FOLD:
#ifdef DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER
          // bypass the optimized downmix routines for the common formats
          if (!Downmix_foldGeneric(
                  downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
              ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
                    downmixInputChannelMask);
              return -EINVAL;
          }
          break;
#endif
        // optimize for the common formats
        switch((downmix_input_channel_mask_t)downmixInputChannelMask) {
        case CHANNEL_MASK_QUAD_BACK:
        case CHANNEL_MASK_QUAD_SIDE:
            Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate);
            break;
        case CHANNEL_MASK_5POINT1_BACK:
        case CHANNEL_MASK_5POINT1_SIDE:
            Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate);
            break;
        case CHANNEL_MASK_7POINT1:
            Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate);
            break;
        default:
            if (!Downmix_foldGeneric(
                    downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
                ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
                      downmixInputChannelMask);
                return -EINVAL;
            }
            break;
        }
        break;

      default:
        return -EINVAL;
    }

    return 0;
}
#endif

static int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
        void *pCmdData, uint32_t *replySize, void *pReplyData) {
@@ -818,6 +934,7 @@ int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *
 *
 *----------------------------------------------------------------------------
 */
#ifndef BUILD_FLOAT
void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
    // sample at index 0 is FL
    // sample at index 1 is FR
@@ -845,7 +962,35 @@ void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool ac
        }
    }
}

#else
void Downmix_foldFromQuad(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
    // sample at index 0 is FL
    // sample at index 1 is FR
    // sample at index 2 is RL
    // sample at index 3 is RR
    if (accumulate) {
        while (numFrames) {
            // FL + RL
            pDst[0] = clamp_float(pDst[0] + ((pSrc[0] + pSrc[2]) / 2.0f));
            // FR + RR
            pDst[1] = clamp_float(pDst[1] + ((pSrc[1] + pSrc[3]) / 2.0f));
            pSrc += 4;
            pDst += 2;
            numFrames--;
        }
    } else { // same code as above but without adding and clamping pDst[i] to itself
        while (numFrames) {
            // FL + RL
            pDst[0] = clamp_float((pSrc[0] + pSrc[2]) / 2.0f);
            // FR + RR
            pDst[1] = clamp_float((pSrc[1] + pSrc[3]) / 2.0f);
            pSrc += 4;
            pDst += 2;
            numFrames--;
        }
    }
}
#endif

/*----------------------------------------------------------------------------
 * Downmix_foldFrom5Point1()
@@ -864,6 +1009,7 @@ void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool ac
 *
 *----------------------------------------------------------------------------
 */
#ifndef BUILD_FLOAT
void Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
    int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
    // sample at index 0 is FL
@@ -908,7 +1054,52 @@ void Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool
        }
    }
}

#else
void Downmix_foldFrom5Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
    LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
    // sample at index 0 is FL
    // sample at index 1 is FR
    // sample at index 2 is FC
    // sample at index 3 is LFE
    // sample at index 4 is RL
    // sample at index 5 is RR
    // code is mostly duplicated between the two values of accumulate to avoid repeating the test
    // for every sample
    if (accumulate) {
        while (numFrames) {
            // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
            centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
                    + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
            // FL + centerPlusLfeContrib + RL
            lt = pSrc[0] + centerPlusLfeContrib + pSrc[4];
            // FR + centerPlusLfeContrib + RR
            rt = pSrc[1] + centerPlusLfeContrib + pSrc[5];
            // accumulate in destination
            pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
            pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
            pSrc += 6;
            pDst += 2;
            numFrames--;
        }
    } else { // same code as above but without adding and clamping pDst[i] to itself
        while (numFrames) {
            // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
            centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
                    + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
            // FL + centerPlusLfeContrib + RL
            lt = pSrc[0] + centerPlusLfeContrib + pSrc[4];
            // FR + centerPlusLfeContrib + RR
            rt = pSrc[1] + centerPlusLfeContrib + pSrc[5];
            // store in destination
            pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
            pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
            pSrc += 6;
            pDst += 2;
            numFrames--;
        }
    }
}
#endif

/*----------------------------------------------------------------------------
 * Downmix_foldFrom7Point1()
@@ -927,6 +1118,7 @@ void Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool
 *
 *----------------------------------------------------------------------------
 */
#ifndef BUILD_FLOAT
void Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
    int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
    // sample at index 0 is FL
@@ -973,8 +1165,54 @@ void Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool
        }
    }
}


#else
void Downmix_foldFrom7Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
    LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
    // sample at index 0 is FL
    // sample at index 1 is FR
    // sample at index 2 is FC
    // sample at index 3 is LFE
    // sample at index 4 is RL
    // sample at index 5 is RR
    // sample at index 6 is SL
    // sample at index 7 is SR
    // code is mostly duplicated between the two values of accumulate to avoid repeating the test
    // for every sample
    if (accumulate) {
        while (numFrames) {
            // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
            centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
                    + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
            // FL + centerPlusLfeContrib + SL + RL
            lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4];
            // FR + centerPlusLfeContrib + SR + RR
            rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5];
            //accumulate in destination
            pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
            pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
            pSrc += 8;
            pDst += 2;
            numFrames--;
        }
    } else { // same code as above but without adding and clamping pDst[i] to itself
        while (numFrames) {
            // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
            centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
                    + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
            // FL + centerPlusLfeContrib + SL + RL
            lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4];
            // FR + centerPlusLfeContrib + SR + RR
            rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5];
            // store in destination
            pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
            pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
            pSrc += 8;
            pDst += 2;
            numFrames--;
        }
    }
}
#endif
/*----------------------------------------------------------------------------
 * Downmix_foldGeneric()
 *----------------------------------------------------------------------------
@@ -1001,6 +1239,7 @@ void Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool
 *
 *----------------------------------------------------------------------------
 */
#ifndef BUILD_FLOAT
bool Downmix_foldGeneric(
        uint32_t mask, int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {

@@ -1092,3 +1331,96 @@ bool Downmix_foldGeneric(
    }
    return true;
}
#else
bool Downmix_foldGeneric(
        uint32_t mask, LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {

    if (!Downmix_validChannelMask(mask)) {
        return false;
    }

    const bool hasSides = (mask & kSides) != 0;
    const bool hasBacks = (mask & kBacks) != 0;

    const int numChan = audio_channel_count_from_out_mask(mask);
    const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
    const bool hasLFE =
            ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
    const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER);
    // compute at what index each channel is: samples will be in the following order:
    //   FL FR FC LFE BL BR BC SL SR
    // when a channel is not present, its index is set to the same as the index of the preceding
    // channel
    const int indexFC  = hasFC    ? 2            : 1;        // front center
    const int indexLFE = hasLFE   ? indexFC + 1  : indexFC;  // low frequency
    const int indexBL  = hasBacks ? indexLFE + 1 : indexLFE; // back left
    const int indexBR  = hasBacks ? indexBL + 1  : indexBL;  // back right
    const int indexBC  = hasBC    ? indexBR + 1  : indexBR;  // back center
    const int indexSL  = hasSides ? indexBC + 1  : indexBC;  // side left
    const int indexSR  = hasSides ? indexSL + 1  : indexSL;  // side right

    LVM_FLOAT lt, rt, centersLfeContrib;
    // code is mostly duplicated between the two values of accumulate to avoid repeating the test
    // for every sample
    if (accumulate) {
        while (numFrames) {
            // compute contribution of FC, BC and LFE
            centersLfeContrib = 0;
            if (hasFC)  { centersLfeContrib += pSrc[indexFC]; }
            if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
            if (hasBC)  { centersLfeContrib += pSrc[indexBC]; }
            centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
            // always has FL/FR
            lt = pSrc[0];
            rt = pSrc[1];
            // mix in sides and backs
            if (hasSides) {
                lt += pSrc[indexSL];
                rt += pSrc[indexSR];
            }
            if (hasBacks) {
                lt += pSrc[indexBL];
                rt += pSrc[indexBR];
            }
            lt += centersLfeContrib;
            rt += centersLfeContrib;
            // accumulate in destination
            pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
            pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
            pSrc += numChan;
            pDst += 2;
            numFrames--;
        }
    } else {
        while (numFrames) {
            // compute contribution of FC, BC and LFE
            centersLfeContrib = 0;
            if (hasFC)  { centersLfeContrib += pSrc[indexFC]; }
            if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
            if (hasBC)  { centersLfeContrib += pSrc[indexBC]; }
            centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
            // always has FL/FR
            lt = pSrc[0];
            rt = pSrc[1];
            // mix in sides and backs
            if (hasSides) {
                lt += pSrc[indexSL];
                rt += pSrc[indexSR];
            }
            if (hasBacks) {
                lt += pSrc[indexBL];
                rt += pSrc[indexBR];
            }
            lt += centersLfeContrib;
            rt += centersLfeContrib;
            // store in destination
            pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
            pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
            pSrc += numChan;
            pDst += 2;
            numFrames--;
        }
    }
    return true;
}
#endif
 No newline at end of file
+11 −2
Original line number Diff line number Diff line
@@ -27,7 +27,9 @@
*/

#define DOWNMIX_OUTPUT_CHANNELS AUDIO_CHANNEL_OUT_STEREO

#ifdef BUILD_FLOAT
#define LVM_FLOAT float
#endif
typedef enum {
    DOWNMIX_STATE_UNINITIALIZED,
    DOWNMIX_STATE_INITIALIZED,
@@ -95,11 +97,18 @@ int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bo
int Downmix_Reset(downmix_object_t *pDownmixer, bool init);
int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue);
int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue);

#ifdef BUILD_FLOAT
void Downmix_foldFromQuad(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
void Downmix_foldFrom5Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
void Downmix_foldFrom7Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
bool Downmix_foldGeneric(
        uint32_t mask, LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
#else
void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate);
void Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate);
void Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate);
bool Downmix_foldGeneric(
        uint32_t mask, int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate);
#endif

#endif /*ANDROID_EFFECTDOWNMIX_H_*/
+9 −2
Original line number Diff line number Diff line
@@ -72,19 +72,25 @@ LOCAL_SRC_FILES:= \
    Common/src/From2iToMono_16.c \
    Common/src/Copy_16.c \
    Common/src/MonoTo2I_16.c \
    Common/src/MonoTo2I_32.c \
    Common/src/LoadConst_16.c \
    Common/src/LoadConst_32.c \
    Common/src/dB_to_Lin32.c \
    Common/src/Shift_Sat_v16xv16.c \
    Common/src/Shift_Sat_v32xv32.c \
    Common/src/Abs_32.c \
    Common/src/Int32RShiftToInt16_Sat_32x16.c \
    Common/src/From2iToMono_32.c \
    Common/src/mult3s_16x16.c \
    Common/src/Mult3s_32x16.c \
    Common/src/NonLinComp_D16.c \
    Common/src/DelayMix_16x16.c \
    Common/src/MSTo2i_Sat_16x16.c \
    Common/src/From2iToMS_16x16.c \
    Common/src/Mac3s_Sat_16x16.c \
    Common/src/Mac3s_Sat_32x16.c \
    Common/src/Add2_Sat_16x16.c \
    Common/src/Add2_Sat_32x32.c \
    Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c \
    Common/src/LVC_MixSoft_1St_D16C31_SAT.c \
    Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c \
@@ -120,7 +126,7 @@ LOCAL_C_INCLUDES += \
    $(LOCAL_PATH)/StereoWidening/src \
    $(LOCAL_PATH)/StereoWidening/lib

LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
LOCAL_CFLAGS += -Wall -Werror

include $(BUILD_STATIC_LIBRARY)
@@ -179,6 +185,7 @@ LOCAL_C_INCLUDES += \
    $(LOCAL_PATH)/Common/lib \
    $(LOCAL_PATH)/Common/src

LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
LOCAL_CFLAGS += -Wall -Werror

include $(BUILD_STATIC_LIBRARY)
+15 −2
Original line number Diff line number Diff line
@@ -198,6 +198,10 @@ typedef enum
#define LVDBE_CAP_FS_32000               64
#define LVDBE_CAP_FS_44100               128
#define LVDBE_CAP_FS_48000               256
#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
#define LVDBE_CAP_FS_96000               512
#define LVDBE_CAP_FS_192000              1024
#endif

typedef enum
{
@@ -210,6 +214,10 @@ typedef enum
    LVDBE_FS_32000 = 6,
    LVDBE_FS_44100 = 7,
    LVDBE_FS_48000 = 8,
#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
    LVDBE_FS_96000 = 9,
    LVDBE_FS_192000 = 10,
#endif
    LVDBE_FS_MAX   = LVM_MAXINT_32
} LVDBE_Fs_en;

@@ -450,12 +458,17 @@ LVDBE_ReturnStatus_en LVDBE_Control(LVDBE_Handle_t hInstance,
/* NOTES:                                                                               */
/*                                                                                      */
/****************************************************************************************/

#ifdef BUILD_FLOAT
LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t          hInstance,
                                       const LVM_FLOAT      *pInData,
                                       LVM_FLOAT            *pOutData,
                                       LVM_UINT16           NumSamples);
#else
LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t          hInstance,
                                       const LVM_INT16      *pInData,
                                       LVM_INT16            *pOutData,
                                       LVM_UINT16           NumSamples);

#endif

#ifdef __cplusplus
}
Loading