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

📄 streamoutput.cpp

📁 NXP LPC3000系列 wince BSP包
💻 CPP
📖 第 1 页 / 共 2 页
字号:
}

// Get next WAVE buffer
PBYTE StreamOutput::stGetNextBuffer(void)
{

    LPWAVEHDR lpOldHdr;
    LPWAVEHDR lpNewHdr;
    LPSTR pNewBuf = NULL;

    // Get a pointer to the current buffer which is now done being processed
    lpOldHdr = m_lpWaveHdrCurrent;

	if (!lpOldHdr)
    {
        return NULL;
    }

    // Are we in a loop
    // Note: a loopcount of 1 means we're not really in a loop
    if (m_dwLoopCount > 1)
    {
        // We're in a loop!
        if (lpOldHdr->dwFlags & WHDR_ENDLOOP)
        {
           // In loop, last buffer
            // If dwLoopCount was set to INFINITE, loop forever
            // (Note: this is not explicitly in the wave driver API spec)
            if (m_dwLoopCount != INFINITE)
            {
                m_dwLoopCount--;                    // decrement loop count
            }
           lpNewHdr = m_lpWaveHdrHead;           // go back to start of loop
        }
        else
        {
           // In loop, intermediate buffer
           lpNewHdr = lpOldHdr->lpNext;          // just go to next buffer in loop block
        }

        lpOldHdr = NULL;
    }
    else
    {
        // Not in a loop; return old buffer and get new buffer
        lpNewHdr = lpOldHdr->lpNext;

        m_lpWaveHdrHead = lpNewHdr;           // reset list head
        if (!lpNewHdr)
        {
            m_lpWaveHdrTail = NULL;             // no new buffer, reset tail to NULL
        }
        else if (lpNewHdr->dwFlags & WHDR_BEGINLOOP)    // if new buffer is start of a loop block
        {
            m_dwLoopCount = lpNewHdr->dwLoops;  // save # of loops
        }
    }

    m_lpWaveHdrCurrent = lpNewHdr;              // save current buffer pointer

    if (lpNewHdr)
    {
        m_lpCurrData    = (PBYTE)lpNewHdr->lpData;  // reinitialize data pointer
        m_lpCurrDataEnd = m_lpCurrData + lpNewHdr->dwBufferLength;
    }
    else
    {
        m_lpCurrData  = NULL;
        m_lpCurrDataEnd = NULL;
    }

    // Return the old buffer
    // This may cause the stream to be destroyed, so make sure that any calls to this function
    // are within an AddRef/Release block
    if (lpOldHdr)
    {
        stReturnBuffer(lpOldHdr);
    }

    return m_lpCurrData;
}

// Return a buffer to the ACM
void StreamOutput::stReturnBuffer(LPWAVEHDR lpWaveHdr)
{
	lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
	lpWaveHdr->dwFlags |= WHDR_DONE;
	stDoCallbackReturnBuffer(lpWaveHdr);
}

// Break a playback loop
DWORD StreamOutput::stBreakLoop(void)
{
    if (m_dwLoopCount > 0)
    {
        m_dwLoopCount = 0;

        LPWAVEHDR lpHdr;
        while (m_lpWaveHdrHead != m_lpWaveHdrCurrent)
        {
            lpHdr = m_lpWaveHdrHead;
            m_lpWaveHdrHead = lpHdr->lpNext;
            if (m_lpWaveHdrHead == NULL)
            {
                m_lpWaveHdrHead = NULL;
            }

			stReturnBuffer(lpHdr);
        }
    }

    return MMSYSERR_NOERROR;
}

// Return current byte playback count
DWORD StreamOutput::stGetByteCount(void)
{
	return m_dwByteCount;
}

// Get data position
DWORD StreamOutput::stGetPos(PMMTIME pmmt)
{
    switch (pmmt->wType)
    {

    case TIME_SAMPLES:
        pmmt->u.sample = (m_dwByteCount * 8) /
                         (m_WaveFormat.nChannels * m_WaveFormat.wBitsPerSample);
        break;

    case TIME_MS:
        if (m_WaveFormat.nAvgBytesPerSec != 0)
        {
            pmmt->u.ms = (m_dwByteCount * 1000) / m_WaveFormat.nAvgBytesPerSec;
            break;
        }
        // If we don't know avg bytes per sec, fall through to TIME_BYTES

    default:
        // Anything else, return TIME_BYTES instead.
        pmmt->wType = TIME_BYTES;

        // Fall through to TIME_BYTES
    case TIME_BYTES:
        pmmt->u.cb = m_dwByteCount;
    }

    return MMSYSERR_NOERROR;
}

// Stop DMA
DWORD StreamOutput::stStop(void)
{
    m_bRunning = FALSE;
    return MMSYSERR_NOERROR;
}

// Start DMA
DWORD StreamOutput::stStart(void)
{
    if (m_lpCurrData)
    {
		m_bRunning = TRUE;
        SetEvent(m_stEventDma);
    }

    return MMSYSERR_NOERROR;
}

// Reset stream
DWORD StreamOutput::stReset(void)
{
    // Stop stream for now.
    stStop();

    m_lpWaveHdrCurrent  = NULL;
    m_lpCurrData        = NULL;
    m_lpCurrDataEnd     = NULL;
    m_dwByteCount       = 0;
    m_dwLoopCount       = 0;

	m_buffsUsed = 0;

    LPWAVEHDR lpHdr;
    while (m_lpWaveHdrHead)
    {
        lpHdr = m_lpWaveHdrHead;
        m_lpWaveHdrHead = lpHdr->lpNext;
        if (m_lpWaveHdrHead == NULL)
        {
            m_lpWaveHdrTail = NULL;
        }
        stReturnBuffer(lpHdr);
    }

	dmaListReset(m_stdmaCtl);

    return MMSYSERR_NOERROR;
}

// Output control thread
void StreamOutput::InterruptThread(void)
{
	DWORD bytes, evid, queueroom;
	PBYTE pCurData;
	int nextfillidx;

    RETAILMSG(1, (TEXT("OutputStreamContext::InterruptThread started!!!!\r\n")));

	// TBD thread priority
	SetThreadPriority(m_stThread, THREAD_PRIORITY_HIGHEST); // TBD

	pCurData = NULL;
	nextfillidx = 0;
	ResetEvent(m_stEventDma);
	while (m_stThreadStop == 0)
	{
		// Wait for event
		evid = WaitForSingleObject(m_stEventDma, INFINITE);
		if (evid != WAIT_OBJECT_0)
		{
		    RETAILMSG(1, (TEXT("OutputStreamContext::InterruptThread event failure!!!!\r\n")));
			m_stThreadStop = 1;
		}
		if (m_stThreadStop == 0)
		{
			// Pop any previously completed buffers
			bytes = dmaCleanUp(m_stdmaCtl);
			while (bytes > 0)
			{
				m_dwByteCount += bytes;
				bytes = dmaCleanUp(m_stdmaCtl);
				m_buffsUsed--;
			}

			// Data fill DMA loop
			queueroom = 1;
			while ((queueroom == 1) && (m_buffsUsed < 2))
			{
				// Is there more data to play
				if (pCurData == NULL)
				{
					pCurData = stGetNextBuffer();
				}

				// Pop any previously completed buffers
				bytes = dmaCleanUp(m_stdmaCtl);
				while (bytes > 0)
				{
					m_dwByteCount += bytes;
					bytes = dmaCleanUp(m_stdmaCtl);
					m_buffsUsed--;
				}

				// Compute number of bytes to transfer
				bytes = (DWORD) (m_lpCurrDataEnd - pCurData);
				if (bytes > 2048)
				{
					bytes = 2048;
				}

				// Copy data to DMA buffer
			    memcpy(m_buffVirt [nextfillidx], pCurData, bytes);

				// Submit buffer to hardware
				if (dmaListEntry(m_stdmaCtl, (DWORD) m_buffPhy [nextfillidx],
					(I2S1_BASE + 8), bytes) == 0)
				{
					// Hardware cannot accept more yet
					queueroom = 0;
				}
				else
				{
					// Toggle buffer space
					nextfillidx = 1 - nextfillidx;
					m_buffsUsed++;

					pCurData += bytes;
					if (pCurData >= m_lpCurrDataEnd)
					{
						pCurData = NULL;
					}
				}
			}
		}

		if (dmaIsOn(m_stdmaCtl) == 0)
		{
			// Stalled, will need DMA restart later
			m_bRunning = FALSE;
		}

		// Re-enable DMA interrupts
		InterruptDone(m_stsysIntrDMA);
	}

	// Thread is exited
	m_stThreadDone = 1;
}

//********************************************************************
// Misc functions
//********************************************************************

// Returns supported status of a stream open
DWORD StreamOutput::stIsSupportedFormat(LPWAVEFORMATEX pWaveFormat)
{
	DWORD supported = 1;

	// Check supported audio formats
	if (pWaveFormat->wFormatTag != WAVE_FORMAT_PCM)
	{
		supported = 0;
	}

	// Check supported channels
	if ((pWaveFormat->nChannels != 1) && (pWaveFormat->nChannels != 2))
	{
		supported = 0;
	}

	// Check supported sample sizes
	if ((pWaveFormat->wBitsPerSample != 8) &&
		(pWaveFormat->wBitsPerSample != 16))
	{
		supported = 0;
	}

	return supported;
}

// Open, close, and buffer return callback function
void StreamOutput::stDoDriverCallback(UINT msg,
									  DWORD dwParam1,
									  DWORD dwParam2)
{
	m_pfnCallback(m_hWave, msg, m_dwInstance, dwParam1, dwParam2);
}

// Buffer return callback function
void StreamOutput::stDoCallbackReturnBuffer(LPWAVEHDR lpHdr)
{
	stDoDriverCallback(WOM_DONE, (DWORD)lpHdr, 0);
}

// Stream open callback function
void StreamOutput::stDoCallbackStreamOpened(void)
{
	stDoDriverCallback(WOM_OPEN, 0, 0);
}

// Stream close callback function
void StreamOutput::stDoCallbackStreamClosed(void)
{
	stDoDriverCallback(WOM_CLOSE, 0, 0);
}

⌨️ 快捷键说明

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