⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wavepdd.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
📖 第 1 页 / 共 2 页
字号:
            pwh = pwh->lpNext;
            if (pwh == NULL)
                break;
            pm16 = (SAMPLE_16_MONO *)(pwh->lpData + pwh->dwBytesRecorded);
        }

        sample = ((LONG)pm16->sample*Volume) >> 22;
        pbuf[a] = (UINT16)(sample + AUDIO_SILENCE_PLAY);
        pm16++;
        pwh->dwBytesRecorded += 2;
    }

    // fill rest space
    while (a < nSamples) {
        pbuf[a++] = AUDIO_SILENCE_PLAY;
    }
}

static void
AudOut_FillBufferS16(PWAVEHDR pwh, ULONG page, ULONG nSamples)
{
    ULONG           a;
    LONG            sample;
    SAMPLE_16_STEREO    *ps16;
    volatile UINT16     *pbuf;

    if (pwh == NULL) {
        return;
    }

    pbuf = (volatile UINT16 *)dma_page[WAPI_OUT][page];
    ps16 = (SAMPLE_16_STEREO *)(pwh->lpData + pwh->dwBytesRecorded);

    for (a=0; a<nSamples; a++) {
        if (pwh->dwBytesRecorded >= pwh->dwBufferLength) {
            pwh = pwh->lpNext;
            if (pwh == NULL)
                break;
            ps16 = (SAMPLE_16_STEREO *)(pwh->lpData + pwh->dwBytesRecorded);
        }

        sample = ((LONG)ps16->sample_left + (LONG)ps16->sample_right) >> 1;
        sample = (sample*Volume) >> 22;
        pbuf[a] = (UINT16)(sample + AUDIO_SILENCE_PLAY);
        ps16++;
        pwh->dwBytesRecorded += 4;
    }

    // fill rest space
    while (a < nSamples) {
        pbuf[a++] = AUDIO_SILENCE_PLAY;
    }
}

static void
AudOut_Start(PWAVEHDR pwh)
{
    (*FillBuf)(pwh, 0, AUDIO_DMA_PAGE_SIZE/2);
    (*FillBuf)(pwh, 1, AUDIO_DMA_PAGE_SIZE/2);

    v_fMoreData[WAPI_OUT] = TRUE;        // we expect to have more data coming...
    v_nNextPage[WAPI_OUT] = 0;

    // setup output DMA address
    REG32(pVRC4173+AIUOBALREG) = physDMAbase[WAPI_OUT];
    REG32(pVRC4173+AIUOALREG) = physDMAbase[WAPI_OUT];

    // enable output DMA
    InterlockedAndOr16((volatile UINT16 *)(pVRC4173+DMA73MSKREG), 0xFFFF, DMAMSKAOUT);

    // enable AIU Tclock
    AIU_ClockEnable(WAPI_OUT);

    // set output sampling rate
    switch (SampleRate[WAPI_OUT]) {
    case 8000:
        REG16(pVRC4173+AIUSCNVRREG) = CNVR_8K;
        break;
    case 11025:
        REG16(pVRC4173+AIUSCNVRREG) = CNVR_11K;
        break;
    case 22050:
        REG16(pVRC4173+AIUSCNVRREG) = CNVR_22K;
        break;
    case 44100:
        REG16(pVRC4173+AIUSCNVRREG) = CNVR_44K;
        break;
    default:
        RETAILMSG(1, (TEXT("AudOut_Start: bad sampling rate\r\n")));
    }

    // D/A Vref power on
    REG16(pVRC4173+AIUSCNTREG) = DAENAIU;   // SSTOPEN=0, DAENAIU=1
    RtcWait(1);             // wait Vref stable (5us)

    // clear output interrupts
    REG16(pVRC4173+AIUINTREG) = AIUINTSIDLE | AIUINTS | AIUINTSEND;

    // activate AIU output
    InterlockedAndOr16((volatile UINT16 *)(pVRC4173+AIUSEQREG), 0xFFFF, AIUSEN);
}

// prepare next output DMA buffer
static void
AudOut_Continue(PWAVEHDR pwh)
{
    // fill DMA buffer
    (*FillBuf)(pwh, v_nNextPage[WAPI_OUT], AUDIO_DMA_PAGE_SIZE/2);

    // flip page
    v_nNextPage[WAPI_OUT] ^= 1;
}

// stop output at next DMA buffer boundary
static void
AudOut_EndOfData(void)
{
    v_fMoreData[WAPI_OUT] = FALSE;

    // SSTOPEN=1
    REG16(pVRC4173+AIUSCNTREG) = SSTOPEN | DAENAIU;
}

// stop output immediately
static void
AudOut_Stop(void)
{
    v_fMoreData[WAPI_OUT] = FALSE;
    AudOut_Standby();
}

// power down AIU output
static void
AudOut_Standby(void)
{
    // disable AIU output
    InterlockedAndOr16((volatile UINT16 *)(pVRC4173+AIUSEQREG), ~AIUSEN, 0);

    // clear output interrupts
    REG16(pVRC4173+AIUINTREG) = AIUINTSIDLE | AIUINTS | AIUINTSEND;

    // D/A Vref power off
    REG16(pVRC4173+AIUSCNTREG) = 0; // SSTOPEN=0, DAENAIU=0

    // disable output DMA
    InterlockedAndOr16((volatile UINT16 *)(pVRC4173+DMA73MSKREG), ~DMAMSKAOUT, 0);

    AIU_ClockDisable(WAPI_OUT);
}

//
// Wavedev DDSI functions

// ---------------------------------------------------------------------------
//
// @doc     WPDD_EXT
//
// @func    AUDIO_STATE | PDD_AudioGetInterruptType |
//          Determines the cause of the SYSINTR_AUDIO interrupt. The PDD
//          should report the status of the playback or record circuitry.
//          The interrupt should occur as a result of the audio DMA passing
//          a buffer boundary.  See the <t AUDIO_STATE> return codes for the
//          possible states that an interrupt can represent.
//
// @rdesc   Returns one of the <t AUDIO_STATE> values.
//
// ---------------------------------------------------------------------------
AUDIO_STATE
PDD_AudioGetInterruptType(VOID)
{
    UINT16      intr;
    AUDIO_STATE stat;

    stat = AUDIO_STATE_IGNORE;

    intr = REG16(pVRC4173+AIUINTREG);

    // input interrupts
    if (intr & AIUINTM) {
        stat |= AUDIO_STATE_IN_RECORDING;
        REG16(pVRC4173+AIUINTREG) = AIUINTM;
    } else if (intr & (AIUINTMIDLE | AIUINTMEND)) {
        stat |= AUDIO_STATE_IN_OVERFLOW;
        REG16(pVRC4173+AIUINTREG) = AIUINTMIDLE | AIUINTMEND;
    }

    // output interrupts
    if (intr & AIUINTS) {
        if (v_fMoreData[WAPI_OUT]) {
            stat |= AUDIO_STATE_OUT_PLAYING;
        } else {
            // stop AIU output
            InterlockedAndOr16((volatile UINT16 *)(pVRC4173+AIUSEQREG), ~AIUSEN, 0);
            stat |= AUDIO_STATE_OUT_STOPPED;
        }
        REG16(pVRC4173+AIUINTREG) = AIUINTS;
    } else if (intr & (AIUINTSIDLE | AIUINTSEND)) {
        stat |= AUDIO_STATE_OUT_UNDERFLOW;
        REG16(pVRC4173+AIUINTREG) = AIUINTSIDLE | AIUINTSEND;
    }

    return stat;
}

//------------------------------------------------------------------------------
//
//  @doc    WPDD_EXT
//
//  @func   DWORD | PDD_AudioMessage | This function sends messages to the 
//          Audio PDD. Custom functions can be accessed via this routine.
//          This function is a pass through of both the <f waveOutMessage> and
//          <f waveInMessage> functions.
//
//  @parm   UINT | uMsg  | The message to send.
//
//  @parm   DWORD | dwParam1 | Parameter 1.
//
//  @parm   DWORD | dwParam2 | Parameter 2.
//
//  @rdesc  Dependent on uMsg.
//
//------------------------------------------------------------------------------
DWORD
PDD_AudioMessage(UINT uMsg, DWORD dwParam1, DWORD dwParam2)
{
    return MMSYSERR_NOTSUPPORTED;
}


// ---------------------------------------------------------------------------
//
// @doc     WPDD_EXT
//
// @func    BOOL | PDD_AudioInitialize | Initializes 
//          the audio device for operation.  PDD_AudioInitialize performs 
//          any one time initialization. This may include allocating memory 
//          for device registers and any DMA buffer pages, etc. 
//
// @rdesc   TRUE if successful; otherwise, FALSE.
//
// ---------------------------------------------------------------------------
BOOL
PDD_AudioInitialize(DWORD dwIndex)
{
    if (!MapVR4122intio()) {
        ERRMSG("PDD_AudioInitialize: VR4122 internal I/O map failed");
        return FALSE;
    }

    if (!Find4173()) {
        ERRMSG("PDD_AudioInitialize: VRC4173 not found");
        FreeVR4122intio();
        return FALSE;
    }

    // get DMA buffer physical address
    // HAL sets initial values to registers at VRC4173init()
    physDMAbase[WAPI_IN ] = REG32(pVRC4173+AIUIBALREG) & ~(AUDIO_DMA_PAGE_SIZE-1);
    physDMAbase[WAPI_OUT] = REG32(pVRC4173+AIUOBALREG) & ~(AUDIO_DMA_PAGE_SIZE-1);
    RETAILMSG(1, (TEXT("in=%X, out=%X\r\n"), physDMAbase[WAPI_IN], physDMAbase[WAPI_OUT]));
    //
    // Map both DMA pages into the local address space
    //
    dma_page[WAPI_IN][0] = VirtualAlloc(0, AUDIO_DMA_PAGE_SIZE * 2,
                    MEM_RESERVE, PAGE_NOACCESS);
    if (!dma_page[WAPI_IN][0]) {
        ERRMSG("PDD_AudioInitialize: DMA input buffer allocation failed");
        return FALSE;
    }

    if (!VirtualCopy((PVOID) dma_page[WAPI_IN][0],
            (PVOID)(physDMAbase[WAPI_IN]>>8),
            AUDIO_DMA_PAGE_SIZE * 2,
            PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL)) {
        ERRMSG("PDD_AudioInitialize: DMA input buffer VirtualCopy failed");
        return FALSE;
    }

    dma_page[WAPI_OUT][0] = VirtualAlloc(0, AUDIO_DMA_PAGE_SIZE * 2,
                    MEM_RESERVE, PAGE_NOACCESS);
    if (!dma_page[WAPI_OUT][0]) {
        ERRMSG("PDD_AudioInitialize: DMA output buffer allocation failed");
        return FALSE;
    }

    if (!VirtualCopy((PVOID) dma_page[WAPI_OUT][0],
            (PVOID)(physDMAbase[WAPI_OUT]>>8),
            AUDIO_DMA_PAGE_SIZE * 2,
            PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL)) {
        ERRMSG("PDD_AudioInitialize: DMA output buffer VirtualCopy failed");
        return FALSE;
    }

    dma_page[WAPI_IN ][1] = dma_page[WAPI_IN ][0] + AUDIO_DMA_PAGE_SIZE;
    dma_page[WAPI_OUT][1] = dma_page[WAPI_OUT][0] + AUDIO_DMA_PAGE_SIZE;

    InPowerHandler = FALSE;

    // initialize DMA address
    REG32(pVRC4173+AIUIBALREG) = physDMAbase[WAPI_IN];
    REG32(pVRC4173+AIUOBALREG) = physDMAbase[WAPI_OUT];
    REG32(pVRC4173+AIUIALREG) = physDMAbase[WAPI_IN];
    REG32(pVRC4173+AIUOALREG) = physDMAbase[WAPI_OUT];

    // enable AIU Tclock
    AIU_ClockEnable(WAPI_IN);
    AIU_ClockEnable(WAPI_OUT);

    //reset AIU
    REG16(pVRC4173+AIUSEQREG) = AIURST;
    RtcWait(1);
    REG16(pVRC4173+AIUSEQREG) = 0;
    RtcWait(1);

    // force AIU into powerdown state
    AudIn_Standby();
    AudOut_Standby();

    v_nVolume   = 0xFFFFFFFF;
    Volume      = 0x0000FFFF;
    v_nNextPage[WAPI_IN ] = 0;
    v_nNextPage[WAPI_OUT] = 0;
    v_fMoreData[WAPI_IN ] = FALSE;
    v_fMoreData[WAPI_OUT] = FALSE;

    initialized = TRUE;

    return TRUE;
}

// ---------------------------------------------------------------------------
//
// @doc     WPDD_EXT
//
// @func    VOID | PDD_AudioDeinitialize |
//          Powers down and disconnects the audio device. This function is
//          called if the audio driver gets unloaded from the OS or if the 
//          driver loading process fails.
//
// @rdesc   None.
//
// ---------------------------------------------------------------------------
VOID
PDD_AudioDeinitialize(VOID)
{
    //
    // The driver is being unloaded. Deinitialize. Free up memory, etc.
    //
    if (!initialized)
        return;

    // put input/output AIU into powerdown state
    AudIn_Standby();
    AudOut_Standby();

    FreeVR4122intio();
    Free4173();

    VirtualFree((void *)dma_page[WAPI_IN][0], 0, MEM_RELEASE);
    VirtualFree((void *)dma_page[WAPI_OUT][0], 0, MEM_RELEASE);

    initialized = FALSE;
}

// ---------------------------------------------------------------------------
//
// @doc     WPDD_EXT
//
// @func    VOID | PDD_AudioPowerHandler | 
//          Powers up or down the PDD.
//
// @parm    BOOL | power_down | If the value of power_down is TRUE, the audio 
//          device is shut down. If FALSE, then this is a power_up request.
//
// @rdesc   None.
//
// ---------------------------------------------------------------------------
VOID
PDD_AudioPowerHandler(BOOL power_down)
{
    InPowerHandler = TRUE;

    if (power_down) {
        // power down request
        AudIn_Standby();
        AudOut_Standby();
    } else {
        // power up request
    }

    InPowerHandler = FALSE;
}

// ---------------------------------------------------------------------------
//
//  @doc    WPDD_EXT
//
//  @func   MMRESULT | PDD_WaveProc | This function sends messages to the 
//          Audio PDD.  It is used to implement all of the waveOut and waveIn
//          functions at the PDD level.
//
//  @parm   WAPI_INOUT | apidir  | The direction of the API requested. 
//          See the <t WAPI_INOUT> definition.
//
//  @parm   DWORD | dwCode  | The function to execute.
//
//  @parm   DWORD | dwParam1 | Parameter 1 of the function.
//
//  @parm   DWORD | dwParam2 | Parameter 2 of the function.
//
//  @rdesc  MMRESULT dependent on dwCode. If dwCode and apidir indicate a 
//          function that is not supported, the PDD_WaveProc should return
//          MMSYSERR_NOTSUPPORTED.
//
// ---------------------------------------------------------------------------
MMRESULT
PDD_WaveProc(WAPI_INOUT apidir, DWORD dwCode, DWORD dwParam1, DWORD dwParam2)
{
    MMRESULT mmRet = MMSYSERR_NOERROR;

    if (apidir == WAPI_IN) {
        // wave input function
        switch (dwCode) {
        case WPDM_START:
            AudIn_Start((PWAVEHDR)dwParam1);
            break;

        case WPDM_CONTINUE:
            AudIn_Continue((PWAVEHDR)dwParam1);
            break;

        case WPDM_STANDBY:
            AudIn_Standby();
            break;

        case WPDM_OPEN:
            mmRet = Aud_Open(apidir, (LPWAVEFORMATEX)dwParam1, (BOOL)dwParam2);
            break;

        case WPDM_CLOSE:
            mmRet = Aud_Close(apidir);
            break;

        case WPDM_GETDEVCAPS:
            mmRet = Aud_GetDevCaps(apidir, (PVOID)dwParam1, (UINT)dwParam2);
            break;

        case WPDM_STOP:
            AudIn_Stop((PWAVEHDR)dwParam1);
            break;

        default:
            mmRet = MMSYSERR_NOTSUPPORTED;
        }
    } else {
        // wave output fuction
        switch (dwCode) {
        case WPDM_SETVOLUME:
            v_nVolume = (ULONG)dwParam1;
            Volume = v_nVolume & 0x0000FFFF;    // use low 16 bit
            break;

        case WPDM_GETVOLUME:
            *((PULONG)dwParam1) = v_nVolume;
            break;

        case WPDM_START:
            AudOut_Start((PWAVEHDR)dwParam1);
            break;

        case WPDM_ENDOFDATA:
            AudOut_EndOfData();
            break;

        case WPDM_CONTINUE:
            AudOut_Continue((PWAVEHDR)dwParam1);
            break;

        case WPDM_RESTART:
            AudOut_Start((PWAVEHDR)dwParam1);
            break;

        case WPDM_PAUSE:
            AudOut_EndOfData();
            break;

        case WPDM_STANDBY:
            AudOut_Standby();
            break;

        case WPDM_OPEN:
            mmRet = Aud_Open(apidir, (LPWAVEFORMATEX)dwParam1, (BOOL)dwParam2);
            break;

        case WPDM_CLOSE:
            mmRet = Aud_Close(apidir);
            break;

        case WPDM_GETDEVCAPS:
            mmRet = Aud_GetDevCaps(apidir, (PVOID)dwParam1, (UINT)dwParam2);
            break;

        case WPDM_STOP:
            AudOut_Stop();
            break;

        default:
            mmRet = MMSYSERR_NOTSUPPORTED;
        }
    }

    return mmRet;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -