My Debugging and Audio Loop Code

Hi all,

I'm really enjoying this series, very educational and entertaining.

I just wanted to throw a couple of ideas I've added to the base code so far.

Debug messages

I use a simple macro for my debug messages, so it appears more clearly in my debug output. The other benefit is I can #if it out of the release build and also switch between platforms by defining it in the platform code. Nothing amazingly novel, but I like it :)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#if WIN32_DEBUG
#define DFAIL(msg) OutputDebugStringA("[-] "msg"\n")
#define DSUCCESS(msg) OutputDebugStringA("[+] "msg"\n")
#elif LINUX_DEBUG
....
#endif
....
  XInputLib = LoadLibraryA("xinput9_1_0.dll");
  if (XInputLib){
    DFAIL("No XInput, using stubs");
....


Sound Buffer

I tweaked the audio loop so it used pointers to do the counting, rather than a separate index.
It also switches between regions with in the same loop.

I'm sure this will be fixed by Casey further down the line but I thought it'd be nice to share.

 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
....

void Win32FillSoundBuffer(win32_direct_sound * so, DWORD ByteToLock, DWORD BytesToWrite){
	VOID * Region1;
	VOID * Region2;
	DWORD Region1Size;
	DWORD Region2Size;
	if (SUCCEEDED(GlobalSecondaryBuffer->Lock(ByteToLock, BytesToWrite,
		&Region1, &Region1Size,
		&Region2, &Region2Size,
		0 //flags
		))){

		int16_t *SampleOut = (int16_t *)Region1;
		int16_t *Region1End = (int16_t*)((int8_t*)Region1 + Region1Size);
		int16_t *Region2End = (int16_t*)((int8_t*)Region2 + Region2Size);

		while (SampleOut != Region2End){
			real32 SinV = sinf(so->t_sin);
			int16_t v = (uint16_t)(SinV * 1000);
			*SampleOut++ = v; //Left Channel
			*SampleOut++ = v; //Right Channel
			
			so->t_sin += 2.0f*Pi32*1.0f / (real32)so->WavePeriod;
			++so->RunningSampleIndex;
			if (SampleOut == Region1End){
				SampleOut = (int16_t *)Region2;
			}
		}
		GlobalSecondaryBuffer->Unlock(Region1, Region1Size, Region2, Region2Size);
	}
	else{
		DFAIL("GlobalSecondaryBuffer->Lock");
	}
}

.....

		                DWORD playCursor;
				DWORD writeCursor;
				if (SUCCEEDED(GlobalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))){
					DWORD ByteToLock = (so.RunningSampleIndex * so.BytesPerSample) % so.SecondaryBufferSize;
					DWORD TargetCursor = (playCursor + (so.LatencySampleCount*so.BytesPerSample)) % so.SecondaryBufferSize;
					DWORD BytesToWrite;
					if (ByteToLock > TargetCursor){
						BytesToWrite = (so.SecondaryBufferSize - ByteToLock);
						BytesToWrite += TargetCursor;
					}
					else{
						BytesToWrite = TargetCursor - ByteToLock;
					}
					Win32FillSoundBuffer(&so, ByteToLock, BytesToWrite);
				}

Edited by rtcfirefly on
Hi,

Having nice debug facilities is always nice.

I'm pretty sure that code will be much slower than Casey's original code with the two loops combined. Every turn around the loop there will be 2 branches (the while and the if) where only one is needed per turn around the loop if they are separated. Since only one of the regions is accessed at one time inside the loop, I don't quite see the benefit of combining them into a single loop. What were your thoughts about fusing the loops like you did?

/Johan
I think it just bugged me that there was repeating code.
You are right about the efficiency.
I have to admit I hadn't even considered that (never had to worry about it before :blush: )

Maybe I could do something like this (although it's pretty ugly):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
	while (1){
			....;
			if (SampleOut == *currentRegionEnd){
				if (currentRegionEnd == &Region2End){
					break;
				}
				else{
					SampleOut = Region2;
					currentRegionEnd = &Region2End;

				}
			
			}
		}


I'll go back and think about it.

Thanks for the input :)

Edited by rtcfirefly on
You have to bump into these scenarios many many times before these kind of details becomes visible to you :)

If the repetition of code is bothering (it kind of is to me too) one way to get rid of it is pulling the code out into its own function.

An advantage to pulling out the code into a function is, besides removing duplicated code, that you get the chance to give it a good descriptive name which adds to the readability of the code.

/Johan
You can do without any if statements in loop like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
SampleOut = Region1;
RegionSize = Region1Size;
for (int i=0; i<2; i++)
{
    // use SampleOut and RegionSizse
    ...
    
    SampleOut = Region2;
    RegionSize = Region2Size;
}