Cómo: crear un XAPO

La API de XAPO proporciona la interfaz IXAPO y la clase CXAPOBase para crear nuevos tipos de XAPO. La interfaz IXAPO contiene todos los métodos que deben implementarse para crear un nuevo XAPO. La clase CXAPOBase proporciona una implementación básica de la interfaz IXAPO . CXAPOBase implementa todos los métodos de interfaz IXAPO excepto el método IXAPO::P rocess , que es único para cada XAPO.

Para crear un nuevo XAPO estático

  1. Derive una nueva clase XAPO de la clase base CXAPOBase .

    Nota

    Los XAPOs implementan la interfaz IUnknown . Las interfaces IXAPO e IXAPOParameters incluyen los tres métodos IUnknown : QueryInterface, AddRef y Release. CXAPOBase proporciona implementaciones de los tres métodos IUnknown . Una nueva instancia de CXAPOBase tendrá un recuento de referencias de 1. Se destruirá cuando su recuento de referencias se convierta en 0. Para permitir que XAudio2 destruya una instancia de un XAPO cuando ya no sea necesario, llame a IUnknown::Release en el XAPO después de agregarla a una cadena de efectos XAudio2. Vea Cómo: Usar un XAPO en XAudio2 para obtener más información sobre el uso de un XAPO con XAudio2.

     

  2. Invalide la implementación de la clase CXAPOBase del método IXAPO::LockForProcess .

    La invalidación de LockForProcess permite almacenar información sobre el formato de los datos de audio para su uso en IXAPO::P rocess.

  3. Implemente el método IXAPO::P rocess .

    XAudio2 llama al método IXAPO::P rocess cada vez que un XAPO necesita procesar datos de audio. El proceso contiene la mayor parte del código para un XAPO.

Implementación del método Process

El método IXAPO::P rocess acepta búferes de flujo para los datos de audio de entrada y salida. Un XAPO típico esperará un búfer de flujo de entrada y un búfer de flujo de salida. Debe basar el procesamiento de datos del búfer de flujo de entrada en el formato especificado en la función LockForProcess y las marcas pasadas a la función Process con el búfer de flujo de entrada. Copie los datos procesados del búfer de flujo de entrada en el búfer de flujo de salida. Establezca el parámetro BufferFlags del búfer de flujo de salida como XAPO_BUFFER_VALID o XAPO_BUFFER_SILENT.

En el ejemplo siguiente se muestra una implementación de LockForProcess y Process que simplemente copia datos de un búfer de entrada en un búfer de salida. Sin embargo, no hay ningún procesamiento si el búfer de entrada está marcado con XAPO_BUFFER_SILENT.

STDMETHOD(LockForProcess) (UINT32 InputLockedParameterCount,
          const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS* pInputLockedParameters,
          UINT32 OutputLockedParameterCount,
          const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS* pOutputLockedParameters)
{
    assert(!IsLocked());
    assert(InputLockedParameterCount == 1);
    assert(OutputLockedParameterCount == 1);
    assert(pInputLockedParameters != NULL);
    assert(pOutputLockedParameters != NULL);
    assert(pInputLockedParameters[0].pFormat != NULL);
    assert(pOutputLockedParameters[0].pFormat != NULL);


    m_uChannels = pInputLockedParameters[0].pFormat->nChannels;
    m_uBytesPerSample = (pInputLockedParameters[0].pFormat->wBitsPerSample >> 3);

    return CXAPOBase::LockForProcess(
        InputLockedParameterCount,
        pInputLockedParameters,
        OutputLockedParameterCount,
        pOutputLockedParameters);
}
STDMETHOD_(void, Process)(UINT32 InputProcessParameterCount,
           const XAPO_PROCESS_BUFFER_PARAMETERS* pInputProcessParameters,
           UINT32 OutputProcessParameterCount,
           XAPO_PROCESS_BUFFER_PARAMETERS* pOutputProcessParameters,
           BOOL IsEnabled)
{
    assert(IsLocked());
    assert(InputProcessParameterCount == 1);
    assert(OutputProcessParameterCount == 1);
    assert(NULL != pInputProcessParameters);
    assert(NULL != pOutputProcessParameters);


    XAPO_BUFFER_FLAGS inFlags = pInputProcessParameters[0].BufferFlags;
    XAPO_BUFFER_FLAGS outFlags = pOutputProcessParameters[0].BufferFlags;

    // assert buffer flags are legitimate
    assert(inFlags == XAPO_BUFFER_VALID || inFlags == XAPO_BUFFER_SILENT);
    assert(outFlags == XAPO_BUFFER_VALID || outFlags == XAPO_BUFFER_SILENT);

    // check input APO_BUFFER_FLAGS
    switch (inFlags)
    {
    case XAPO_BUFFER_VALID:
        {
            void* pvSrc = pInputProcessParameters[0].pBuffer;
            assert(pvSrc != NULL);

            void* pvDst = pOutputProcessParameters[0].pBuffer;
            assert(pvDst != NULL);

            memcpy(pvDst,pvSrc,pInputProcessParameters[0].ValidFrameCount * m_uChannels * m_uBytesPerSample);
            break;
        }

    case XAPO_BUFFER_SILENT:
        {
            // All that needs to be done for this case is setting the
            // output buffer flag to XAPO_BUFFER_SILENT which is done below.
            break;
        }

    }

    // set destination valid frame count, and buffer flags
    pOutputProcessParameters[0].ValidFrameCount = pInputProcessParameters[0].ValidFrameCount; // set destination frame count same as source
    pOutputProcessParameters[0].BufferFlags     = pInputProcessParameters[0].BufferFlags;     // set destination buffer flags same as source

}

Al escribir un método Process , es importante tener en cuenta que los datos de audio XAudio2 se intercalan. Esto significa que los datos de cada canal son adyacentes para un número de muestra determinado. Por ejemplo, si hay una onda de 4 canales reproduciendo en una voz de origen XAudio2, los datos de audio son una muestra del canal 0, una muestra del canal 1, una muestra del canal 2, una muestra del canal 3 y, a continuación, la siguiente muestra de canales 0, 1, 2, 3, etc.

Efectos de audio

Información general sobre XAPO