Day 008 - Writing a Square Wave to DirectSound / Visual Studio Debugger Crashing

Hi all

Absolutely lovin' working through the series, however I seem to have hit a point early on that's blocking me from going much further :( I'm wondering if anyone can offer me some advice?

I have the following function (win32WriteAudioBuffer), which I call (just once) to fill the audio buffer. (For the purposes of keeping the debugging simple, I don't call this within the game loop at the moment)

The buffer gets filled and the square wave audio loop plays perfectly, no cutting or anything. However, when I run the code, the Visual Studio debugger crashes probably 70% of the time. If I comment out the win32WriteAudioBuffer function, the Debugger never seems to crash. So there must be something buggy about my code, I just can't seem to figure out what!

I've verified that the 192,000 byte buffer gets filled from the first to the last byte - and never writes more than I expect it to, so I dont think it's that. However when I view the details of C:\Users\jon\AppData\Local\CrashDumps\devenv.exe.dmp, I get the following information:

1
2
3
4
5
6
7
8
9
Dump Summary
------------
Dump File:	devenv.exe.15424.dmp : C:\Users\jon\AppData\Local\CrashDumps\devenv.exe.15424.dmp
Last Write Time:	29/04/2020 21:35:30
Process Name:	devenv.exe : C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.exe
Process Architecture:	x86
Exception Code:	0xC0000005
Exception Information:	The thread tried to read from or write to a virtual address for which it does not have the appropriate access.
Heap Information:	Not Present


So it looks like i'm writing to/reading from something I shouldn't somewhere?

  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
internal_func void win32InitDirectSound(HWND window)
{
    audioBuffer.bufferSuccessfulyCreated = FALSE;

    // Load the library
    HMODULE libHandle = LoadLibrary("dsound.dll");

    if (!libHandle) {
        OutputDebugString("Could not load DirectSound DLL (dsound.dll)");
        return;
    }

    // Create the struct    
    audioBuffer.noOfChannels = 2;
    audioBuffer.bitsPerSample = 16;
    audioBuffer.samplesPerSecond = 48000;
    audioBuffer.bytesPerSample = ((audioBuffer.bitsPerSample * audioBuffer.noOfChannels) / BITS_PER_BYTE);
    audioBuffer.secondsWorthOfAudio = 1;
    audioBuffer.bufferSizeInBytes = ((audioBuffer.bytesPerSample * audioBuffer.samplesPerSecond) * audioBuffer.secondsWorthOfAudio);

    uint8_t blockAlignment = audioBuffer.bytesPerSample;

    // Result variable for the various function call return checks.
    HRESULT res;

    DirectSoundCreateDT *DirectSoundCreateAddr = (DirectSoundCreateDT*)GetProcAddress(libHandle, "DirectSoundCreate");

    if (!DirectSoundCreateAddr) {
        OutputDebugString("DirectSoundCreate not in dsound.dll. Malformed DLL?");
        return;
    }

    DirectSoundCreateDT *DirectSoundCreate = DirectSoundCreateAddr;

    LPDIRECTSOUND directSound;

    res = DirectSoundCreate(NULL, &directSound, NULL);

    if (FAILED(res)){
        OutputDebugString("Could not create direct sound object");
        return;
    }

    res = directSound->SetCooperativeLevel(window, DSSCL_PRIORITY);

    if (FAILED(res)){
        OutputDebugString("Could not set cooperative level on direct sound object");
        return;
    }

    // Primary buffer.
    DSBUFFERDESC primarySoundBufferDesc;
    ZeroMemory(&primarySoundBufferDesc, sizeof(DSBUFFERDESC));

    primarySoundBufferDesc.dwSize            = sizeof(primarySoundBufferDesc);
    primarySoundBufferDesc.dwFlags           = DSBCAPS_PRIMARYBUFFER;
    primarySoundBufferDesc.dwBufferBytes     = 0;
    primarySoundBufferDesc.lpwfxFormat       = NULL;
    primarySoundBufferDesc.guid3DAlgorithm   = GUID_NULL;

    LPDIRECTSOUNDBUFFER primarySoundBuffer;

    res = directSound->CreateSoundBuffer(&primarySoundBufferDesc, &primarySoundBuffer, NULL);

    if (FAILED(res)){
        OutputDebugString(LOG_LEVEL_ERROR, "Could not create primary buffer");
        return;
    }

    // Set the format
    WAVEFORMATEX waveFormat = {};

    waveFormat.wFormatTag          = WAVE_FORMAT_PCM;
    waveFormat.nChannels           = audioBuffer.noOfChannels;
    waveFormat.nSamplesPerSec      = audioBuffer.samplesPerSecond;
    waveFormat.nAvgBytesPerSec     = (audioBuffer.samplesPerSecond * blockAlignment);
    waveFormat.nBlockAlign         = blockAlignment;
    waveFormat.wBitsPerSample      = audioBuffer.bitsPerSample;
    waveFormat.cbSize              = 0;

    res = primarySoundBuffer->SetFormat(&waveFormat);

    if (FAILED(res)){
        OutputDebugString("Could not set sound format on primary buffer");
        return;
    }

    // Secondary buffer.
    DSBUFFERDESC secondarySoundBufferDesc;
    ZeroMemory(&secondarySoundBufferDesc, sizeof(DSBUFFERDESC));

    secondarySoundBufferDesc.dwSize              = sizeof(secondarySoundBufferDesc);
    secondarySoundBufferDesc.dwFlags             = 0;
    secondarySoundBufferDesc.dwBufferBytes       = audioBuffer.bufferSizeInBytes;
    secondarySoundBufferDesc.lpwfxFormat         = &waveFormat;
    secondarySoundBufferDesc.guid3DAlgorithm     = GUID_NULL;

    res = directSound->CreateSoundBuffer(&secondarySoundBufferDesc, &audioBuffer.buffer, NULL);

    if (FAILED(res)){
        OutputDebugString("Could not create secondary buffer");
        return;
    }

}


internal_func void win32WriteAudioBuffer(DWORD lockOffsetInBytes, DWORD lockSizeInBytes)
{
    HRESULT res;

    void *chunkOnePtr;
    DWORD chunkOneBytes;

    void *chunkTwoPtr;
    DWORD chunkTwoBytes;

    res = audioBuffer.buffer->Lock(lockOffsetInBytes,
                                    lockSizeInBytes,
                                    &chunkOnePtr,
                                    &chunkOneBytes,
                                    &chunkTwoPtr,
                                    &chunkTwoBytes,
                                    0);

    if (SUCCEEDED(res)) {

        uint64_t chunkSamples = (chunkOneBytes / audioBuffer.bytesPerSample);

        uint16_t *audioSample = (uint16_t*)chunkOnePtr;

        int16_t waveSize = 4000;
        uint16_t cyclesPerSecond = 375;

        uint64_t cycleIndex = 0;
        int16_t audioSampleValue = -waveSize;

        for (size_t i = 0; i < chunkSamples; i++) {

            if (0 == (cycleIndex % cyclesPerSecond)) {
                if (audioSampleValue == waveSize) {
                    audioSampleValue = -waveSize;
                } else {
                    audioSampleValue = waveSize;
                }
            }

            // Left
            *audioSample = audioSampleValue;
            audioSample++;

            // Right
            *audioSample = audioSampleValue;
            audioSample++;

            cycleIndex++;
        }

        uint64_t chunkTwoSamples = (chunkTwoBytes / audioBuffer.bytesPerSample);

        uint16_t *audioTwoSample = (uint16_t*)chunkTwoPtr;

        for (size_t i = 0; i < chunkTwoSamples; i++) {

            if (0 == (cycleIndex % cyclesPerSecond)) {
                if (audioSampleValue == waveSize) {
                    audioSampleValue = -waveSize;
                } else {
                    audioSampleValue = waveSize;
                }
            }

            // Left
            *audioTwoSample = audioSampleValue;
            audioTwoSample++;

            // Right
            *audioTwoSample = audioSampleValue;
            audioTwoSample++;

            cycleIndex++;
        }

        res = audioBuffer.buffer->Unlock(chunkOnePtr, chunkOneBytes, chunkTwoPtr, chunkTwoBytes);

        if (FAILED(res)) {
            OutputDebugString("Could not unlock sound buffer\n");
        }

    } else {
        OutputDebugString("Could not lock secondary sound buffer\n");
    }

}

internal_func int CALLBACK WinMain(HINSTANCE instance,
                                    HINSTANCE prevInstance, 
                                    LPSTR commandLine, 
                                    int showCode)
{
    // window set up...
    //...

    win32InitDirectSound(window);
    win32WriteAudioBuffer(0, audioBuffer.bufferSizeInBytes); // 0, 192000
    audioBuffer.buffer->Play(0, 0, DSBPLAY_LOOPING);

    // game loop...
    //...
}


Any help would be much appreciated

Jon

Edited by Jon on
The debugger should never crash, regardless of bugs or problems with your code. The point of debugger is catch your application crashes and show where it happens. Obviously it cannot do that if debugger crashes itself.

If VS crashes the issue is elsewhere. It could be that debugger has a bug, it's possible, but with low probability - as it works for most of people.
Do you have any Visual Studio extensions installed? Any strange background utilities you run? Antivirus? Do you have latest Windows updates installed? Visual Studio up to date?
Thanks @mmozeiko, I have upgraded my OS and shall test again.