Click here to Skip to main content
12,691,453 members (29,660 online)
Click here to Skip to main content
Add your own
alternative version


55 bookmarked

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

, 15 Sep 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
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?

You may also be interested in...

Comments and Discussions

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
jacky_zz17-Jan-11 16:50
memberjacky_zz17-Jan-11 16:50 
AnswerRe: left and right value ? Pin
jacky_zz17-Jan-11 16:54
memberjacky_zz17-Jan-11 16:54 

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.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170117.1 | Last Updated 16 Sep 2008
Article Copyright 2008 by jackyxinli
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid