Laggin' with DirectSound and timers

So there's two problems:

First: I can load waves from resource perfectly into a ds buffer, but when I try to play it, it stops before playing.

Here's my Sound class and engine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// Setup:

#ifndef PENTTI_H
#define PENTTI_H

#include "mmio.h"
#include <dsound.h>

// Typedefs:

typedef unsigned char byte;

// Pentti engine:

class Pentti
{
public:
	bool init(HWND window);
	LPDIRECTSOUND ds;

private:
};

bool Pentti::init(HWND window)
{
	if ( DirectSoundCreate(NULL, &ds, NULL) != DS_OK )
		return 1;

	if ( ds->SetCooperativeLevel(window, DSSCL_NORMAL) != DS_OK )
		return 1;

	return 0;
};

Pentti pentti;

// Sound class:

class Sound
{
public:
	Sound() { wave = NULL; };
	Sound(UINT id) { create(id); };
	~Sound();
	bool create(UINT id, bool doLoad = 1);
	bool restore() { return create(0, 0) | ( buffer->Restore() == DD_OK )? 0 : 1; };

	bool play(bool loop = 0);
	bool stop();

	//bool isPlaying();

	//bool setPan();
	//bool setFrequency();
	//bool setVolume();

private:
	BOOL    GetFormat(WAVEFORMATEX& wfFormat) const;
    DWORD   GetDataLen() const;
    DWORD   GetData(BYTE*& pWaveData, DWORD dwMaxToCopy) const;
	BOOL    IsValid() const { return (m_pImageData ? TRUE : FALSE); };

	byte* m_pImageData;
    DWORD m_dwImageLen;

	LPDIRECTSOUNDBUFFER buffer;
	byte *wave;
	unsigned long waveSize;
};

typedef Sound* LPSound;

bool Sound::create(UINT id, bool doLoad)
{
	if (doLoad)
	{
		m_pImageData = (byte*)LockResource(LoadResource(NULL, FindResource(NULL, MAKEINTRESOURCE(id), L"WAVE")));
		m_dwImageLen = SizeofResource(NULL, FindResource(NULL, MAKEINTRESOURCE(id), L"WAVE"));
	}

	unsigned long dataLength = GetDataLen();
	WAVEFORMATEX format;
	GetFormat(format);

	DSBUFFERDESC bufferDesc;
	ZeroMemory(&bufferDesc, sizeof(bufferDesc));

	bufferDesc.dwSize		 = sizeof(bufferDesc);
	bufferDesc.dwFlags		 = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC;
	bufferDesc.dwBufferBytes = dataLength;
	bufferDesc.lpwfxFormat	 = &format;

	HRESULT x;
	if (x = pentti.ds->CreateSoundBuffer(&bufferDesc, &buffer, NULL) != DS_OK )
		return 1;

	byte *bufferData;

	if ( buffer->Lock(0, dataLength, (void**)&bufferData, &dataLength, NULL, 0, 0) != DS_OK )
		return 1;

	dataLength = GetData(bufferData, dataLength);

	if ( buffer->Unlock(bufferData, dataLength, NULL, 0) != DS_OK )
		return 1;

	return 0;
}

Sound::~Sound()
{
	if (wave)
		FreeResource(GlobalHandle(wave));
}

bool Sound::play(bool loop)
{
	DWORD status;
	buffer->GetStatus(&status);

	if ( status & DSBSTATUS_BUFFERLOST )
		restore();

	if ( buffer->Play(0, 0, loop? DSBPLAY_LOOPING : 0) != DS_OK )
		return 1;

	return 0;
}

bool Sound::stop()
{
	DWORD status;
	buffer->GetStatus(&status);

	if ( ( status & DSBSTATUS_LOOPING ) || ( status & DSBSTATUS_PLAYING ) )
		buffer->Stop();

	return 0;
}

BOOL Sound::GetFormat(WAVEFORMATEX& wfFormat) const
{
    // Check validity
    if (!IsValid())
        return FALSE;

    // Setup and open the MMINFO structure
    CMMMemoryIOInfo mmioInfo((HPSTR)m_pImageData, m_dwImageLen);
    CMMIO           mmio(mmioInfo);

    // Find the WAVE chunk
    CMMTypeChunk mmckParent('W','A','V','E');
    mmio.Descend(mmckParent, MMIO_FINDRIFF);

    // Find and read the format subchunk
    CMMIdChunk mmckSubchunk('f','m','t',' ');
    mmio.Descend(mmckSubchunk, mmckParent, MMIO_FINDCHUNK);
    mmio.Read((HPSTR)&wfFormat, sizeof(WAVEFORMATEX));
    mmio.Ascend(mmckSubchunk);

    return TRUE;
}

DWORD Sound::GetDataLen() const
{
    // Check validity
    if (!IsValid())
        return (DWORD)0;

    // Setup and open the MMINFO structure
    CMMMemoryIOInfo mmioInfo((HPSTR)m_pImageData, m_dwImageLen);
    CMMIO           mmio(mmioInfo);

    // Find the WAVE chunk
    CMMTypeChunk mmckParent('W','A','V','E');
    mmio.Descend(mmckParent, MMIO_FINDRIFF);

    // Find and get the size of the data subchunk
    CMMIdChunk mmckSubchunk('d','a','t','a');
    mmio.Descend(mmckSubchunk, mmckParent, MMIO_FINDCHUNK);
    return mmckSubchunk.cksize;
}

DWORD Sound::GetData(BYTE*& pWaveData, DWORD dwMaxLen) const
{
    // Check validity
    if (!IsValid())
        return (DWORD)0;

    // Setup and open the MMINFO structure
    CMMMemoryIOInfo mmioInfo((HPSTR)m_pImageData, m_dwImageLen);
    CMMIO           mmio(mmioInfo);

    // Find the WAVE chunk
    CMMTypeChunk mmckParent('W','A','V','E');
    mmio.Descend(mmckParent, MMIO_FINDRIFF);

    // Find and get the size of the data subchunk
    CMMIdChunk mmckSubchunk('d','a','t','a');
    mmio.Descend(mmckSubchunk, mmckParent, MMIO_FINDCHUNK);
    DWORD dwLenToCopy = mmckSubchunk.cksize;

    // Allocate memory if the passed in pWaveData was NULL
    if (pWaveData == NULL)
        pWaveData = (BYTE*)GlobalLock(GlobalAlloc(GMEM_MOVEABLE,
            dwLenToCopy));
    else
        // If we didn't allocate our own memory, honor dwMaxLen
        if (dwMaxLen < dwLenToCopy)
            dwLenToCopy = dwMaxLen;
    if (pWaveData)
        // Read waveform data into the buffer
        mmio.Read((HPSTR)pWaveData, dwLenToCopy);

    return dwLenToCopy;
}

#endif 


And don't ask about the "Pentti" -name, It's just a Finnish name that's shorter than "soundEngine".

Second one: My timer is lagging a bit. Here's it's code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Setup:

#ifndef TIMER_H
#define TIMER_H

#include <mmsystem.h>

class Timer
{
public:
	Timer();

	bool timeForFrame();

	long long getCurrentFrame() { return currentFrame; };

	int getFrame(long long startFrame, int totalFrames, int framesPerFrame = 1);
	long long getFramesSince(long long startFrame, int framesPerFrame = 1);

private:
	long long updateTime();

	bool perfCounter;

	bool passedLastTime;
	long long lastTime;

	long long currentTime;
	double timeScale;

	long long currentFrame;
	double framerate;
};

Timer time;

Timer::Timer()
{
	framerate = 16.7;

	currentFrame = 0;
	currentTime = 0;

	long long pcFrequency;

	if ( QueryPerformanceFrequency((LARGE_INTEGER*) &pcFrequency) )
	{
		perfCounter = true;
		timeScale = 1000 / (double)pcFrequency;
	}
	else
	{
		perfCounter = false;
		timeScale = 1;
	}

	passedLastTime = true;
}

long long Timer::updateTime()
{
	if (perfCounter)
		QueryPerformanceCounter((LARGE_INTEGER*) &currentTime);

	else
		currentTime = timeGetTime();

	return currentTime = (long long)( (double)currentTime * timeScale );
}

bool Timer::timeForFrame()
{
	if ( passedLastTime )
		lastTime = currentTime;

	if ( lastTime + framerate <= updateTime() )
	{
		passedLastTime = true;
		currentFrame++;

		return true;
	}

	passedLastTime = false;
	return false;
}

int Timer::getFrame(long long startFrame, int totalFrames, int framesPerFrame)
{
	return (int)( ( currentFrame - startFrame + currentFrame ) % currentFrame ) / framesPerFrame;
}

long long Timer::getFramesSince(long long startFrame, int framesPerFrame)
{
	return ( currentFrame - startFrame ) / framesPerFrame;
}

#endif 


And here's how I call Timer::timeForFrame() in winMain():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Forward declarations to functions that must be defined in main.cpp:

void init();
void frame();
void cleanup();

void (*doInit)    () = init;
void (*doFrame)   () = frame;
void (*doCleanup) () = cleanup;

...

while (!quit)
{
	if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	else
	{
		////////////////////////
		// So here I call it: //
		////////////////////////

		if (time.timeForFrame())
			doFrame();
	}
}


I'm using MS Visual C++ 2008 Express edition and Windows Vista



P.S. And in that mmio.h are some classes I took from the source CD of DirectX Trainer. It basically just handles the wave files 'easier'.

P.P.S. These codes are pretty much the same as in DirectX Trainer, but I've just put them in to classes, so I dunno what could be wrong...


Thanks for any answers or suggestions,
Otto
Topic archived. No new replies allowed.