Closing down DirectMusic is a matter of clearing the loader cache, stopping the performance, releasing all the objects that have been created, and finally dereferencing COM (remember, every call to CoInitialize must have a matching call to CoUninitialize).
The following function performs the necessary cleanup in Donuts.cpp:
void CleanUpDMusic()
{
if (gpLoader)
{
gpLoader->ClearCache(GUID_DirectMusicAllTypes);
gpLoader->Release();
}
if (gpComposer)
{
gpComposer->Release();
}
if (gpIntroTemplate)
{
gpIntroTemplate->Release();
}
if (gpGameTemplate)
{
gpGameTemplate->Release();
}
for (short n = 0; n < NUM_STYLES; n++)
{
if (gapShieldBand[n])
{
gapShieldBand[n]->Unload(gpPerformance);
gapShieldBand[n]->Release();
}
if (gapDefaultBand[n])
{
gapDefaultBand[n]->Unload(gpPerformance);
gapDefaultBand[n]->Release();
}
if (gapShieldSegment[n])
{
gapShieldSegment[n]->Release();
}
if (gapDefaultSegment[n])
{
gapDefaultSegment[n]->Release();
}
if (gapStyle[n])
{
gapStyle[n]->Release();
}
for (short m = 0; m < NUM_CHORDMAP; m++)
{
if (gapChordMap[n][m])
{
gapChordMap[n][m]->Release();
}
}
for (m = 0; m < NUM_MOTIFS; m++)
{
if (gapMotif[n][m])
{
gapMotif[n][m]->Release();
}
}
}
if (gpPerformance)
{
gpPerformance->Stop( NULL, NULL, 0, 0 );
gpPerformance->CloseDown();
gpPerformance->Release();
}
for (n = 0; n < NUM_SEGMENTS; n++)
{
if (gapSegment[n])
{
gapSegment[n]->Release();
}
}
if (gpDirectMusic)
{
gpDirectMusic->Release();
}
CoUninitialize();
}