[directmusic] Help! Problem when loading scripts

  • From: <tomas.elf@xxxxxxxxxxxx>
  • To: <directmusic@xxxxxxxxxxxxx>
  • Date: Wed, 16 Feb 2005 18:15:32 +0000

Hi everyone,

I'm Tomas, Directmusic programmer of a small game development group and reader 
of this mailing list for quite some time now. 
I've noticed that there's a lot of smart people around here, so I hope someone 
can help me with a Directmusic problem that I'm having :-).

The background: I must find a way to load Directmusic-objects without using the 
specific file functions in IDirectMusicLoader8 (e.g LoadObjectFromFile, 
SetSearchDirectory etc). The reason for this is that the Directmusic module in 
our system will not have access to any files, but instead will be given a 
pointer to the data that I probably will 
be able to load using IDirectMusicLoader8::GetObject. I'm pretty sure that I've 
managed to load a segment consisting of a number of wavetracks by first using 
IDirectMusicLoader8::SetObject on the wave-files referred to by the script, and 
then loading the Segment like usual.

Now, the problem is: This does not seem to work too well with scripts (or 
containers in general, I suspect). The only way I've managed to load a script 
is by either embedding all references in the script or by placing all referred 
files in the same directory and then pointing IDirectMusicLoader8::
SetSearchDirectory to that directory. But, as I said before, the latter one 
does not meet our requirements (and obviously, the first one is very 
inefficient if I want to use the same file in a lot of scripts). So, I need to 
be able to load scripts by using IDirectMusicLoader8::SetObject or by some 
other solution that lets me give the loader a pointer to the data.

I thought that you could simply use IDirectMusicLoader8::SetObject on 
all the objects that are referred to by the script, and then simply load the 
script, just as with segments. Is this not possible? Here's an excerpt from the 
current, flawed solution:


int main() 

        First run SetObject on all files that the script refers to.
        The LoaderSetObject simply runs SetObject on the file passed 
        to it. 

        hr = LoaderSetObject(g_pLoader, CLSID_DirectMusicAudioPathConfig, 
                L"Audiopath_AllCh", L"C:\\Documents and Settings\\Tomas\\My 

        hr = LoaderSetObject(g_pLoader, CLSID_DirectSoundWave, L"Riff_Bass-01", 
                L"C:\\Documents and Settings\\Tomas\\My 

        ... *snip* LoaderSetObject of all other referred files is omitted from 
        code listing... 

        WCHAR wcharFilename[] = L"C:\\Runtimefiles\\TestScript1.spt";
        WCHAR wcharRoutine[] = L"PlaySegment";

        // ... Then load & play the script. 
        hr = PlayScript(g_pLoader, g_pPerformance, pScript, wcharFilename, 


} //End main

        Lets the loader know where all referred files can be found 
        when loading a script.
        pLoader: The Directmusic loader
        guidClass: The class id of the object to give to SetObject.
        wcharObjName: The internal name of the object to set [optional]
        wcharFilepath: The path+filename to the object that is going to be set.
HRESULT LoaderSetObject(IDirectMusicLoader8* &pLoader, GUID guidClass, 
                        WCHAR* wcharObjName, WCHAR* wcharFilepath)
        DMUS_OBJECTDESC objDesc;
        HRESULT hr;

        objDesc.dwSize = sizeof(objDesc);
        objDesc.guidClass = guidClass;
        wcscpy(objDesc.wszFileName, wcharFilepath);
        objDesc.dwValidData = DMUS_OBJ_FULLPATH | DMUS_OBJ_CLASS;

        if (wcharObjName)
                wcsncpy(objDesc.wszName, wcharObjName, sizeof(objDesc.wszName) -
                objDesc.wszName[sizeof(objDesc.wszName) - 1] = 0;
                objDesc.dwValidData |= DMUS_OBJ_NAME;
        hr = pLoader->SetObject(&objDesc);
        return hr;

        Loads and plays the script.
        pLoader & pPerformance: Obvious ;-)
        pScript: Return variable of the script object loaded by PlayScript
        wcharFilename: The path+filename of the script to load & play.
        wcharRoutinge: The name of the script routine to play.  
HRESULT PlayScript(IDirectMusicLoader8* &pLoader, 
                        IDirectMusicPerformance8* &pPerformance, 
                        IDirectMusicScript8* &pScript, 
                        WCHAR* wcharFilename, 
                        WCHAR* wcharRoutine)
        HRESULT hr;
        DMUS_OBJECTDESC objDesc;

        if (!pLoader || !pPerformance)
                return E_INVALIDARG;

        objDesc.dwSize = sizeof(DMUS_OBJECTDESC);
        objDesc.guidClass = CLSID_DirectMusicScript;
        wcscpy(objDesc.wszFileName, wcharFilename);
        objDesc.dwValidData = DMUS_OBJ_FULLPATH | DMUS_OBJ_CLASS;
        hr = pLoader->GetObject(&objDesc, IID_IDirectMusicScript, (LPVOID *) 
        if (FAILED (hr = pScript->Init(pPerformance, &errInfo))) 
                return E_FAIL;
        hr = pScript->CallRoutine(wcharRoutine, &errInfo);

        MessageBox(NULL, "Script", "Playing", MB_OK);
        pPerformance->Stop(NULL, NULL, 0, 0);

        return S_OK;

        } //End try

                DEBUG ("PlayScript Exception!\n");
                return S_FALSE;

} //End PlayScript


You may wonder why I load files in this code example when I told you that I 
would not use files. That's because I thought that it would be 
easy to just replace the file references with memory references later on, since 
I use SetObject.

Now, what happens is that when reaching the row... 

"hr = pLoader->GetObject(&objDesc, IID_IDirectMusicScript, (LPVOID *) 

... in the PlayScript-method above, I get the following debug printout from 
direct-x in my output window in Visual Studio and the &pScript is still 


DMLOADER: Warning: The file Riff_Bass-01.wav couldn't be opened: No such file 
or directory
. Try another path.
DMLOADER: Warning: The file Riff_Chords-01.wav couldn't be opened: No such file 
or directory
. Try another path.
DMLOADER: Warning: The file Riff_Drums-01.wav couldn't be opened: No such file 
or directory
. Try another path.
DMLOADER: Warning: The file Audiopath_AllCh.aud couldn't be opened: No such 
file or directory
. Try another path.
DMLOADER: Warning: The file Segment1.sgt couldn't be opened: No such file or 
. Try another path.
DMLOADER: Warning: The file Riff_Bass-01.wav couldn't be opened: No such file 
or directory
. Try another path.
DMLOADER: Load failure. While attempting to load the object
DMLOADER:    [file C:\Documents and Settings\Tomas\My 
Documents\DMUSProducer\Test1\Runtimefiles\TestScript1.spt, name TestScript1, 
type Microsoft.DirectMusicScript.1, guid {CAFFF46E-F3D6-4AA1-BE06-
DMLOADER: the following referenced objects could not be loaded:
DMLOADER:    [file Riff_Bass-01.wav, name Riff_Bass-01, type Microsoft.
DirectMusicSegment.1, guid {F7B4BDBE-4695-4320-9A9E-C4CF4785B8C0}]


Basically, none of files that the script refers to can be loaded. The files 
cannot be found it seems, since they are found if I were to point out their 
directory using IDirectMusicLoader8::SetSearchDirectory (but since I won't be 
able to rely on files later on, that's a no-no).
I don't understand why the loader cannot find the files. If I point out them 
using the SetObject, the loader should be able to load them when loading the 
script, right?

FYI, in Producer, the script is set to load all references and download all 
segments when it's loaded.

I would be very grateful if somebody out there with some experience could help 
me with this problem. It makes no sense to me :-(.

Best regards,
Tomas Elf

Other related posts: