Click here to Skip to main content
15,180,707 members
Articles / Desktop Programming / MFC
Posted 15 Sep 2008


57 bookmarked

Play Wave file with DirectSound and display its spectrum in real time

Rate me:
Please Sign up or sign in to vote.
3.44/5 (8 votes)
15 Sep 2008CPOL2 min read
An article to show how to play a Wave file with DirectSound and display its spectrum in real time.



Do you want to play a Wave file with DirectSound and display its spectrum in real time? This article uses the DirectSound Win32 GDI API to achieve this. This article includes two parts: one is playing the Wave file, which is based on the article: Using DirectSound to Play Audio Stream Data; the other is how to display the sound spectrum in real time? This is our main work.


Maintain our circle buffer when playing

In this section, I add some code to maintain a circle buffer with red color displayed, which is based on the article: Using DirectSound to Play Audio Stream Data.

class CMyDirectSound  

    virtual ~CMyDirectSound();

    void SetFormat(WAVEFORMATEX WFE);
    void SetCallback(LPGETAUDIOSAMPLES_PROGRESS Function_Callback, 
                     LPVOID lpData);
    void Play();
    void Pause();
    void Stop();
    DWORD GetSamplesPlayed(DWORD* pCurPlayPos);
    void TimerCallback();
    LPDIRECTSOUNDBUFFER GetSoundBuffer() { return m_lpDSB; }
    WAVEFORMATEX GetWaveFormateEx() { return m_WFE; } // jacky_zz[2008-09-04]
    LPDIRECTSOUNDBUFFER GetDirectSoundBuffer() { return m_lpDSB; } // jacky_zz[2008-09-04]
    LPBYTE GetSampleDataBuffer() { return m_lpSampleDataBuffer; } // jacky_zz[2008-09-04]


    HANDLE m_pHEvent[2];

    //<Audio Buffer>
    LPBYTE m_lpAudioBuf;
    LPVOID m_lpData;
    //</Audio Buffer>

    //<SampleData> jacky_zz[2008-09-04]
    LPBYTE m_lpSampleDataBuffer;
    //</SampleData> jacky_zz[2008-09-04]

    MMRESULT m_timerID;
    DWORD m_dwCircles1;
    DWORD m_dwCircles2;
    int m_iDB;    

    //<Error Information>
    CString m_strLastError;
    //</Error Information>

    DWORD m_dwThreadID;
    HANDLE m_hThread;

The member m_lpSampleDataBuffer is two seconds long, the same as the second buffer, m_lpDSB, in the class CMyDirectSound. The class CMyDirectSound reads the Wave file sound data and fills it into the second buffer, and I add some code here to copy sound data into m_lpSampleDataBuffer.

void CMyDirectSound::Play()

    //Copy Audio Buffer to DirectSoundBuffer
    if (NULL == lpvAudio2)
        memcpy(lpvAudio1, m_lpAudioBuf, dwRetBytes);

        memcpy(m_lpSampleDataBuffer, m_lpAudioBuf, dwRetBytes);
        memcpy(lpvAudio1, m_lpAudioBuf, dwBytesAudio1);
        memcpy(lpvAudio2, m_lpAudioBuf + dwBytesAudio1, dwBytesAudio2);

        memcpy(m_lpSampleDataBuffer, m_lpAudioBuf, 
               dwBytesAudio1 + dwBytesAudio2);

void CMyDirectSound::TimerCallback()

    //If near the end of the audio data
    if (dwRetSamples < m_WFE.nSamplesPerSec)
        DWORD dwRetBytes = dwRetSamples*m_WFE.nBlockAlign;
        memset(m_lpAudioBuf+dwRetBytes, 0, 
               m_WFE.nAvgBytesPerSec - dwRetBytes);

        memset(m_lpSampleDataBuffer+dwRetBytes, 0, 
               m_WFE.nAvgBytesPerSec*2 - dwRetBytes);

    //Copy AudioBuffer to DirectSoundBuffer
    if (NULL == lpvAudio2)
        memcpy(lpvAudio1, m_lpAudioBuf, dwBytesAudio1);

               m_lpAudioBuf, dwBytesAudio1);
        memcpy(lpvAudio1, m_lpAudioBuf, dwBytesAudio1);
        memcpy(lpvAudio2, m_lpAudioBuf + dwBytesAudio1, dwBytesAudio2);

        memcpy(m_lpSampleDataBuffer+dwOffset, m_lpAudioBuf, 


Calculate values of left and right, then use FFT to calculate it

In this section, I will describe how to calculate the values of left and right, then use FFT to calculate it. I want to say some things before doing it. I referenced a few articles like FFT of waveIn audio signals, Simple Audio Out Oscilloscope and Spectrum Analyzer, and Multimedia PeakMeter control. All of them cast the sound data (in bytes) to a short array with reinterpret_cast or (short*). But this method does not work right in my program, so I used a Java MP3 player which can display the spectrum.

LPBYTE lpAudioBuffer = playmod->pMyDS->GetSampleDataBuffer();
if(lpAudioBuffer == NULL)

float left, right;
for(int i=0;i<FFT_SAMPLE_SIZE;i++) {
    if(dwCurPlayPos > dw2SecondByteSize)
        dwCurPlayPos -= dw2SecondByteSize;

    left = (float)((lpAudioBuffer[dwCurPlayPos+1] << 8) + 
    right = (float)((lpAudioBuffer[dwCurPlayPos+3] << 8) + 
    floatSamples[i] = (left+right)/2;

FFT* fft = (FFT*)playmod->fft;
float* lpFloatFFTData = fft->calculate(floatSamples, FFT_SAMPLE_SIZE);
memcpy(floatMag, lpFloatFFTData, FFT_SAMPLE_SIZE/2);
SendMessage(playmod->hWndMain, WM_PAINT+913, (WPARAM)0, (LPARAM)13);

Use Win32 GDI API to draw the spectrum

void DrawSpectrum(HWND hwnd, float* fftData)
    if(fftData == NULL)

    HDC hdc = GetWindowDC(hwnd);
    SetBkMode(hdc, TRANSPARENT);

    HPEN hpen, hpenOld;
    HBRUSH hbrush, hbrushOld;
    HBRUSH hbrush1, hbrushOld1;
    RECT rect;

    rect.left = 4; = 23;
    rect.right = rect.left+SPECTRUM_WIDTH;
    rect.bottom =;

    // Create a green pen.
    hpen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
    // Create a red brush.
    hbrush = CreateSolidBrush(RGB(0, 0, 0));
    hbrush1 = CreateSolidBrush(RGB(125, 125, 125));

    // Select the new pen and brush, and then draw.
    hpenOld = (HPEN)SelectObject(hdc, hpen);
    hbrushOld = (HBRUSH)SelectObject(hdc, hbrush);
    hbrushOld1 = (HBRUSH)SelectObject(hdc, hbrush1);
    Rectangle(hdc, rect.left,, rect.right, rect.bottom);

    int maxFreq = FFT_SIZE / 2;
    int height = 0;
    int maxHeight = SPECTRUM_HEIGHT;

    float c = 0;
    float floatFrrh = 1.0;
    float floatDecay = (float)SPECTRUM_DECAY;
    float floatSadFrr = (floatFrrh*floatDecay);
    float floatBandWidth = ((float)SPECTRUM_WIDTH/(float)SPECTRUM_BANDS);
    float floatMultiplier = 2.0;

    //CString xx;
    RECT r;
    for(int a=0, band=0; band < SPECTRUM_BANDS; 
            a+=(int)floatMultiplier, band++)
        float wFs = 0;

        // -- Average out nearest bands.
        for (int b = 0; b < floatMultiplier; b++) {
            wFs += fftData[a + b];

        // -- Log filter.
        wFs = (wFs * (float) log((float)(band + 2)));
        //xx.Format(_T(&quot;%1.4f\n&quot;), wFs);
        if (wFs > 1.0f) {
            wFs = 1.0f;

        // -- Compute SA decay...
        if (wFs >= (floatOldMag[a] - floatSadFrr)) {
            floatOldMag[a] = wFs;
        } else {
            floatOldMag[a] -= floatSadFrr;
            if (floatOldMag[a] < 0) {
                floatOldMag[a] = 0;
            wFs = floatOldMag[a];

        r.left = rect.left + (int)c + 1;
        r.right = r.left + (int)(floatBandWidth-1); = SPECTRUM_HEIGHT - (int)(wFs*SPECTRUM_HEIGHT);
        if( <
   = + 2; += 22;
        r.bottom = rect.bottom-2;        

        FillRect(hdc, &r, hbrushOld1);

        int height = HEIGHT(r);
        if(height > intPeaks[band])
            intPeaks[band] = height;
            intPeaksDelay[band] = SPECTRUM_DELAY;
            if (intPeaksDelay[band] < 0) {

            if (intPeaks[band] < 0) {
                intPeaks[band] = 0;
        } -= intPeaks[band];
        if( <
   = + 2; += 22;
        if( >= rect.bottom)
   = rect.bottom - 2;

        r.bottom = + 1;
        FillRect(hdc, &r, hbrushOld1);

        c += floatBandWidth;

    // Do not forget to clean up.
    SelectObject(hdc, hpenOld);
    SelectObject(hdc, hbrushOld);
    SelectObject(hdc, hbrushOld1);
    ReleaseDC(hwnd, hdc);


The position that I get is not exactly a circle buffer

This program is not mature. So, some problems still exist, some of which I am not able to get the right way to resolve. I hope people at CodeProject can help me. One of the issues is that the position that I get is not exactly a circle buffer. I have tried methods like using a thread or a timer. Do you think you could help me resolve it?


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


About the Author

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

Questionabout the spectrum analysis Pin
Zhao Weifeng27-Aug-12 22:55
MemberZhao Weifeng27-Aug-12 22:55 
AnswerRe: about the spectrum analysis Pin
jackyxinli29-Aug-12 16:05
Memberjackyxinli29-Aug-12 16:05 
GeneralDemo File is Infected by Virus Pin
satmosc24-Feb-11 11:16
Membersatmosc24-Feb-11 11:16 
Questionleft and right value ? Pin
liao gang13-Jan-11 22:02
Memberliao gang13-Jan-11 22:02 
AnswerRe: left and right value ? Pin
liao gang16-Jan-11 21:17
Memberliao gang16-Jan-11 21:17 
GeneralRe: left and right value ? Pin
jackyxinli17-Jan-11 16:50
Memberjackyxinli17-Jan-11 16:50 
AnswerRe: left and right value ? Pin
jackyxinli17-Jan-11 16:54
Memberjackyxinli17-Jan-11 16:54 
GeneralError at compilation Pin
catalin7716-Apr-09 10:51
Membercatalin7716-Apr-09 10:51 
GeneralRe: Error at compilation Pin
jackyxinli16-Apr-09 15:10
Memberjackyxinli16-Apr-09 15:10 
GeneralRe: Error at compilation Pin
catalin7720-Apr-09 10:36
Membercatalin7720-Apr-09 10:36 
GeneralRe: Error at compilation Pin
jackyxinli20-Apr-09 22:06
Memberjackyxinli20-Apr-09 22:06 
GeneralMissing Files Pin
Breezium22-Sep-08 4:16
MemberBreezium22-Sep-08 4:16 
GeneralRe: Missing Files Pin
jackyxinli22-Sep-08 15:35
Memberjackyxinli22-Sep-08 15:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.