Click here to Skip to main content
15,886,578 members
Articles / Desktop Programming / Win32

Play Audio Files with DirectSound and Display its Spectrum in Real Time - Part 3

Rate me:
Please Sign up or sign in to vote.
4.93/5 (21 votes)
24 Dec 2008CPOL3 min read 273.7K   17.7K   86  
An article to show how to play audio file with DirectSound and display its spectrum in real time accurately
#include "AudioStream.h"
#pragma warning(disable : 4006)

void WMA_Reader_Init(WMA_SYNC_READER* reader, CStream* pStream, BOOL bDescrete, SHORT iSpeakers)
{
	DWORD dwOutputCount = 0, dwFormatCount = 0;
	DWORD i = 0, j = 0, dwSize = 0;
	IWMOutputMediaProps* pWMOutputMediaProps = NULL;
	WM_MEDIA_TYPE* pOutputMediaType = NULL;
	WM_MEDIA_TYPE* pFormatMediaType = NULL;
	PWAVEFORMATEX pWaveFmtEx = NULL;
	WMT_ATTR_DATATYPE dataType;
	WORD wLen = 0, wAStream = 0;
	ULARGE_INTEGER uliNewPosition;
	BYTE bEnable = FALSE;
	DWORD dwValue = 0;
	BOOL bCond = FALSE;
	HRESULT hr = S_OK;

	CoInitialize(NULL);

	CCriticalSection cs;
	cs.Enter();

	reader->pAudioStream = NULL;
	reader->pNSSBuffer = NULL;
	reader->pStream = NULL;
	reader->pWMHeaderInfo = NULL;
	reader->pWMSyncReader = NULL;

	hr = WMCreateSyncReader(NULL, 0, &reader->pWMSyncReader);
	if(hr != S_OK)
	{
		cs.Leave();
		return;
	}

	reader->pAudioStream = new CAudioStream;
	reader->pAudioStream->SetStream(pStream);
	reader->pStream = static_cast<IStream*>(reader->pAudioStream);
	reader->pStream->AddRef();

	// open stream
	hr = reader->pWMSyncReader->OpenStream(reader->pStream);
	if(hr != S_OK)
	{
		LARGE_INTEGER liMove;
		liMove.LowPart = 30;
		reader->pAudioStream->Seek(liMove, 0, &uliNewPosition);

		hr = reader->pWMSyncReader->OpenStream(reader->pStream);
		if(hr != S_OK)
		{
			reader->pWMSyncReader->Release();
			reader->pWMSyncReader = NULL;

			reader->pStream->Release();
			reader->pAudioStream = NULL;
			reader->pStream = NULL;

			cs.Leave();
			return;
		}
	}

	//get output count
	hr = reader->pWMSyncReader->GetOutputCount(&dwOutputCount);
	if(hr != S_OK)
	{
		reader->pWMSyncReader->Release();
		reader->pWMSyncReader = NULL;

		reader->pStream->Release();
		reader->pAudioStream = NULL;
		reader->pStream = NULL;

		cs.Leave();
		return;
	}

	for(i = 0; i < dwOutputCount; i++)
	{
		hr = reader->pWMSyncReader->GetOutputProps(i, &pWMOutputMediaProps);
		if(hr != S_OK) continue;

		hr = pWMOutputMediaProps->GetMediaType(NULL, &dwSize);
		if(hr != S_OK) continue;

		pOutputMediaType = (WM_MEDIA_TYPE*)malloc(dwSize);
		if(pOutputMediaType == NULL)
		{
			MessageBox(GetActiveWindow(), _TEXT("Out of memory!"), _TEXT("Error"), MB_OK);
			continue;
		}

		hr = pWMOutputMediaProps->GetMediaType(pOutputMediaType, &dwSize);
		if(hr != S_OK)
		{
			free(pOutputMediaType);
			pOutputMediaType = NULL;

			continue;
		}

		if(IsEqualGUID(pOutputMediaType->majortype, WMMEDIATYPE_Audio))
		{
			bEnable = (BYTE)bDescrete;
			reader->pWMSyncReader->SetOutputSetting(i, _TEXT("EnableDiscreteOutput"),
				WMT_TYPE_BOOL, (const BYTE*)&bEnable, 4);

			if(iSpeakers == 0)
			{
				pWaveFmtEx = (PWAVEFORMATEX)pOutputMediaType->pbFormat;
				reader->dwSampleRate = pWaveFmtEx->nSamplesPerSec;
				reader->dwChannels = pWaveFmtEx->nChannels;

				hr = reader->pWMSyncReader->GetOutputFormatCount(i, &dwFormatCount);
				if(hr == S_OK)
				{
					for(j = 0; j < dwFormatCount; j++)
					{
						hr = reader->pWMSyncReader->GetOutputFormat(i, j, &pWMOutputMediaProps);
						if(hr != S_OK) continue;

						hr = pWMOutputMediaProps->GetMediaType(NULL, &dwSize);
						if(hr != S_OK) continue;

						pFormatMediaType = (WM_MEDIA_TYPE*)malloc(dwSize);
						if(pFormatMediaType == NULL)
						{
							MessageBox(GetActiveWindow(), _TEXT("Out of memory!"), _TEXT("Error"), MB_OK);
							continue;
						}

						hr = pWMOutputMediaProps->GetMediaType(pFormatMediaType, &dwSize);
						if(hr != S_OK)
						{
							free(pFormatMediaType);
							pFormatMediaType = NULL;

							continue;
						}

						if(IsEqualGUID(pFormatMediaType->formattype, WMFORMAT_WaveFormatEx))
						{
							pWaveFmtEx = (PWAVEFORMATEX)pFormatMediaType->pbFormat;
							bCond = (pWaveFmtEx->wBitsPerSample >= reader->dwBitsPerSample) &&
								(pWaveFmtEx->nSamplesPerSec == reader->dwSampleRate) &&
								(pWaveFmtEx->nChannels == reader->dwChannels);

							if(bCond)
							{
								reader->bHasAudio = TRUE;
								reader->dwOutput = i;
								reader->dwBitsPerSample = pWaveFmtEx->wBitsPerSample;
								reader->pWMSyncReader->SetOutputProps(i, pWMOutputMediaProps);
							}
						}

						free(pFormatMediaType);
						pFormatMediaType = NULL;
					}
				}
			}
			else
			{
				if(iSpeakers > 2)
				{
					dwValue = iSpeakers;
					reader->pWMSyncReader->SetOutputSetting(i, _TEXT("SpeakerConfig"),
						WMT_TYPE_DWORD, (const BYTE*)&dwValue, 4);
				}

				reader->pWMSyncReader->GetOutputFormatCount(i, &dwFormatCount);
				for(j = 0; j< dwFormatCount; j++)
				{
					reader->pWMSyncReader->GetOutputFormat(i, j, &pWMOutputMediaProps);
					pWMOutputMediaProps->GetMediaType(NULL, &dwSize);

					pFormatMediaType = (WM_MEDIA_TYPE*)malloc(dwSize);
					if(pFormatMediaType == NULL)
					{
						MessageBox(GetActiveWindow(), _TEXT("Out of memory!"), _TEXT("Error"), MB_OK);
						continue;
					}

					pWMOutputMediaProps->GetMediaType(pFormatMediaType, &dwSize);
					if(IsEqualGUID(pFormatMediaType->formattype, WMFORMAT_WaveFormatEx))
					{
						pWaveFmtEx = (PWAVEFORMATEX)pFormatMediaType->pbFormat;
						if(iSpeakers > 0)
							bCond = (pWaveFmtEx->nChannels == iSpeakers);
						else
						{
							bCond = (pWaveFmtEx->wBitsPerSample >= reader->dwBitsPerSample) &&
								(pWaveFmtEx->nSamplesPerSec >= reader->dwSampleRate) &&
								(pWaveFmtEx->nChannels >= reader->dwChannels);
						}

						if(bCond)
						{
							reader->bHasAudio = TRUE;
							reader->dwOutput = i;
							reader->dwChannels = pWaveFmtEx->nChannels;
							reader->dwSampleRate = pWaveFmtEx->nSamplesPerSec;
							reader->dwBitsPerSample = pWaveFmtEx->wBitsPerSample;
							reader->pWMSyncReader->SetOutputProps(i, pWMOutputMediaProps);
						}
					}
				}
			}
		}

		free(pOutputMediaType);
		pOutputMediaType = NULL;

		pWMOutputMediaProps->Release();
		pWMOutputMediaProps = NULL;
	}

	if(reader->bHasAudio)
	{
		reader->pWMSyncReader->GetStreamNumberForOutput(reader->dwOutput, &reader->wStream);
		if(reader->pWMSyncReader->SetReadStreamSamples(reader->wStream, FALSE) == NS_E_PROTECTED_CONTENT)
		{
			reader->bProtected = TRUE;
		}
		else reader->bProtected = FALSE;

		wLen = 8;
		wAStream = 0;

		hr = reader->pWMSyncReader->QueryInterface(IID_IWMHeaderInfo, (void**)&reader->pWMHeaderInfo);
		if(hr == S_OK)
		{
			hr = reader->pWMHeaderInfo->GetAttributeByName(&wAStream, _TEXT("Duration"), &dataType,
				(BYTE*)&reader->liDuration, &wLen);
			if(hr != S_OK) reader->liDuration.LowPart = 0;
		}
	}

	cs.Leave();
}

DWORD WMA_Reader_GetDuration(WMA_SYNC_READER* reader)
{
	if(reader == NULL) return 0;

	return (DWORD)(reader->liDuration.LowPart/0.1e6);
}

void WMA_Reader_GetTag(WMA_SYNC_READER* reader, WCHAR* pszTagName, WCHAR* pszTagValue, size_t vsize)
{
	WORD wStream = 0, wLen = vsize;
	WMT_ATTR_DATATYPE dataType;// = WMT_TYPE_STRING;
	HRESULT hr;

	hr = reader->pWMHeaderInfo->GetAttributeByName(&wStream, pszTagName, &dataType, (BYTE*)pszTagValue, &wLen);
	if(hr != S_OK) pszTagValue[0] = '\0';
}

WORD WMA_Reader_GetTagLength(WMA_SYNC_READER* reader, WCHAR* pszTagName)
{
	if(reader == NULL) return 0;

	WORD wStream = 0, wLength = 0;
	WMT_ATTR_DATATYPE dataType;
	HRESULT hr;

	hr = reader->pWMHeaderInfo->GetAttributeByName(&wStream, pszTagName, &dataType, NULL, &wLength);
	if(hr != S_OK) wLength = 0;

	return wLength;
}

void WMA_Reader_GetAuthor(WMA_SYNC_READER* reader, WCHAR* pszAuthor)
{
	if(reader == NULL) return;

	WORD wLen = WMA_Reader_GetTagLength(reader, _TEXT("Author"));
	if(wLen == 0) return;


}

void WMA_Reader_Uninit(WMA_SYNC_READER* reader)
{
	if(reader == NULL) return;

	CCriticalSection cs;
	cs.Enter();

	if(reader->pNSSBuffer != NULL)
		reader->pNSSBuffer->Release();

	if(reader->pStream != NULL)
		reader->pStream->Release();

	if(reader->pWMHeaderInfo != NULL)
		reader->pWMHeaderInfo->Release();

	if(reader->pWMSyncReader != NULL)
	{
		reader->pWMSyncReader->Close();
		reader->pWMSyncReader->Release();
	}

	reader->pAudioStream = NULL;
	reader->pNSSBuffer = NULL;
	reader->pStream = NULL;
	reader->pWMHeaderInfo = NULL;
	reader->pWMSyncReader = NULL;

	CoUninitialize();
	cs.Leave();
}

DWORD WMA_Reader_GetBitrate(WMA_SYNC_READER* reader)
{
	WORD len, stream;
	WMT_ATTR_DATATYPE dataType;

	len = 4;
	stream = 0;
	DWORD ret;

	if(reader->pWMHeaderInfo->GetAttributeByName(&stream, _TEXT("Bitrate"), &dataType, (BYTE*)&ret, &len) != S_OK)
		return 0;

	return ret;
}

DWORD WMA_Reader_GetFormatCount(WMA_SYNC_READER* reader, BOOL Descrete)
{
	BYTE Enable = (BYTE)Descrete;
	DWORD dwCount = 0;
	reader->pWMSyncReader->SetOutputSetting(reader->dwOutput, _TEXT("EnableDiscreteOutput"),
		WMT_TYPE_BOOL, &Enable, 4);
	reader->pWMSyncReader->GetOutputFormatCount(reader->dwOutput, &dwCount);

	return dwCount;
}

void WMA_Reader_GetFormat(WMA_SYNC_READER* reader, BOOL Descrete, INT index, WMAFormatSpec* pFormatSpec)
{
	IWMOutputMediaProps* pOutputMediaProps;
	WM_MEDIA_TYPE* pFormatMediaType;
	PWAVEFORMATEX pFormatEx;
	BYTE Enable = (BYTE)Descrete;
	DWORD dwSize = 0;

	reader->pWMSyncReader->SetOutputSetting(reader->dwOutput, _TEXT("EnableDiscreteOutput"),
		WMT_TYPE_BOOL, &Enable, 4);
	reader->pWMSyncReader->GetOutputFormat(reader->dwOutput, index, &pOutputMediaProps);

	pOutputMediaProps->GetMediaType(NULL, &dwSize);
	pFormatMediaType = (WM_MEDIA_TYPE*)malloc(dwSize);
	pOutputMediaProps->GetMediaType(pFormatMediaType, &dwSize);

	if(IsEqualGUID(pFormatMediaType->formattype, WMFORMAT_WaveFormatEx))
	{
		pFormatEx = (PWAVEFORMATEX)pFormatMediaType->pbFormat;
		pFormatSpec->BitsPerSample = pFormatEx->wBitsPerSample;
		pFormatSpec->Channels = pFormatEx->nChannels;
		pFormatSpec->SampleRate = pFormatEx->nSamplesPerSec;
	}
	else
	{
		pFormatSpec->BitsPerSample = 0;
		pFormatSpec->Channels = 0;
		pFormatSpec->SampleRate = 0;
	}

	free(pFormatMediaType);
	pOutputMediaProps->Release();
	pOutputMediaProps = NULL;
}

BOOL WMA_Reader_GetIsVBR(WMA_SYNC_READER* reader)
{
	WORD len, stream;
	WMT_ATTR_DATATYPE dataType;

	len = 4;
	stream = 0;
	BYTE ret;
	if(reader->pWMHeaderInfo->GetAttributeByName(&stream, _TEXT(""), &dataType, &ret, &len) != S_OK)
		return FALSE;

	return TRUE;
}

void WMA_Reader_Free(WMA_SYNC_READER* reader)
{
	reader->pWMSyncReader->Close();
	if(reader->pNSSBuffer != NULL)
		reader->pNSSBuffer->Release();

	if(reader->pWMHeaderInfo != NULL)
		reader->pWMHeaderInfo->Release();

	if(reader->pStream != NULL)
		reader->pStream->Release();

	reader->pWMSyncReader->Release();
	reader->pWMSyncReader = NULL;

	reader->pWMHeaderInfo = NULL;
	reader->pNSSBuffer = NULL;
	reader->pStream = NULL;
	reader->pAudioStream = NULL;
}

void WMA_Reader_GetData(WMA_SYNC_READER* reader, void** buffer, DWORD* bytes)
{
	BYTE* pBuf;
	DWORD len;
	DWORD copylen;
	ULARGE_INTEGER time, duration;
	DWORD flags;
	DWORD Output;
	WORD w;
	HRESULT hr;

	while(TRUE)
	{
		if(reader->pNSSBuffer != NULL)
		{
			reader->pNSSBuffer->GetBufferAndLength((BYTE**)&pBuf, &len);
			if(reader->dwOffset < len)
			{
				if(*bytes < (len - reader->dwOffset))
					copylen = *bytes;
				else
					copylen = len - reader->dwOffset;

				*buffer = pBuf + reader->dwOffset;
				*bytes = copylen;
				reader->dwOffset += copylen;
				return;
			}

			reader->pNSSBuffer->Release();
			reader->pNSSBuffer = NULL;
			reader->dwOffset = 0;
		}

		hr = reader->pWMSyncReader->GetNextSample(reader->wStream, &reader->pNSSBuffer, &time.QuadPart,
			&duration.QuadPart, &flags, &Output, &w);
		if(hr != S_OK)
		{
			*buffer = NULL;
			*bytes = 0;
			return;
		}
	}
}

void WMA_Reader_GetAudioPropties(WMA_SYNC_READER* reader, WORD* channels, WORD* bitspersamples, DWORD* sampledate)
{
	*channels = (WORD)reader->dwChannels;
	*bitspersamples = (WORD)reader->dwBitsPerSample;
	*sampledate = reader->dwSampleRate;
}

void WMA_Reader_Seek(WMA_SYNC_READER* reader, DWORD offset)
{
	reader->pWMSyncReader->SetRange((QWORD)(offset*0.1E6), 0);
}

void WMA_Reader_SetFormat(WMA_SYNC_READER* reader, BOOL Descrete, DWORD FormatIndex)
{
	IWMOutputMediaProps* pOutputMediaProps = NULL;
	WM_MEDIA_TYPE* pFormatMediaType = NULL;
	PWAVEFORMATEX pFormatEx = NULL;
	BYTE Enable = 0;
	DWORD size = 0;

	Enable = (BYTE)Descrete;

	reader->pWMSyncReader->SetOutputSetting(reader->dwOutput, _TEXT("EnableDiscreteOutput"),
		WMT_TYPE_BOOL, &Enable, 4);
	reader->pWMSyncReader->GetOutputFormat(reader->dwOutput, FormatIndex, &pOutputMediaProps);

	pOutputMediaProps->GetMediaType(NULL, &size);
	pFormatMediaType = (WM_MEDIA_TYPE*)malloc(size);
	pOutputMediaProps->GetMediaType(pFormatMediaType, &size);

	if(IsEqualGUID(pFormatMediaType->formattype, WMFORMAT_WaveFormatEx))
	{
		pFormatEx = (PWAVEFORMATEX)pFormatMediaType->pbFormat;
		reader->dwChannels = pFormatEx->nChannels;
		reader->dwBitsPerSample = pFormatEx->wBitsPerSample;
		reader->dwSampleRate = pFormatEx->nSamplesPerSec;
	}

	reader->pWMSyncReader->SetOutputProps(reader->dwOutput, pOutputMediaProps);
	free(pFormatMediaType);

	pOutputMediaProps->Release();
	pOutputMediaProps = NULL;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer none
China China
To be, or not to be, this is question. That's are all depend on your decision. What do you think?

Comments and Discussions