Files
Client/Library/dxx8/samples/Multimedia/Demos/DMBoids/music.cpp
LGram16 e067522598 Initial commit: ROW Client source code
Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 16:24:34 +09:00

1116 lines
27 KiB
C++

//-----------------------------------------------------------------------------
// File: Music.cpp
//
// Desc:
//
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#define STRICT
#include <windows.h>
#include <tchar.h>
#include <oleauto.h>
#include <stdio.h>
#include "DXUtil.h"
#include "music.h"
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
BoidMusic::BoidMusic()
{
m_dwBeatsSinceLastMotif = 0;
m_pSegment = NULL;
m_pPort = NULL;
m_pDMusic = NULL;
m_fCollapsed = FALSE;
m_dwIndex = 0;
m_pBand = NULL;
m_pStyle = NULL;
m_pChordMap = NULL;
long x;
for (x = 0; x < 6; x++)
{
m_pTemplateSegments[x] = NULL;
m_pPrimarySegments[x] = NULL;
m_pMotifSegments[x] = NULL;
}
m_pPrimarySegments[1] = NULL;
m_pTransitionSegment = NULL;
m_pComposer = NULL;
m_pLoader = NULL;
m_pPerformance = NULL;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
BoidMusic::~BoidMusic()
{
long x;
if (m_pSegment)
{
m_pSegment->Release();
}
if (m_pBand)
{
if(m_pPerformance)
{
m_pBand->Unload(m_pPerformance);
}
m_pBand->Release();
}
if (m_pGraph)
{
m_pGraph->Release();
}
if (m_pPort)
{
m_pPort->Release();
}
if (m_pDMusic)
{
m_pDMusic->Release();
}
for (x = 0; x< 6; x++)
{
if (m_pTemplateSegments[x])
{
m_pTemplateSegments[x]->Release();
}
if (m_pPrimarySegments[x])
{
m_pPrimarySegments[x]->Release();
}
if (m_pMotifSegments[x])
{
m_pMotifSegments[x]->Release();
}
}
if (m_pStyle)
{
m_pStyle->Release();
}
if (m_pChordMap)
{
m_pChordMap->Release();
}
if (m_pTransitionSegment)
{
m_pTransitionSegment->Release();
}
if (m_pComposer)
{
m_pComposer->Release();
}
if (m_pLoader)
{
m_pLoader->Release();
}
if (m_pPerformance)
{
m_pPerformance->Release();
}
if( m_hNotify )
{
CloseHandle( m_hNotify );
}
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
BOOL BoidMusic::LoadStyle()
{
if (m_pStyle) m_pStyle->Release();
DMUS_OBJECTDESC ObjectDescript;
ObjectDescript.guidClass = CLSID_DirectMusicStyle;
wcscpy(ObjectDescript.wszFileName, L"Boids2.sty");
ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME ;
ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
if (SUCCEEDED(m_pLoader->GetObject(&ObjectDescript, IID_IDirectMusicStyle, (void**)&m_pStyle)))
{
BSTR bstr = SysAllocString(L"Default");
m_pStyle->GetBand(bstr, &m_pBand) ;
SysFreeString(bstr);
return TRUE;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name:
// Desc: This loads a precomposed segment.
//-----------------------------------------------------------------------------
BOOL BoidMusic::LoadSegment()
{
if (m_pSegment) m_pSegment->Release();
DMUS_OBJECTDESC ObjectDescript;
ObjectDescript.guidClass = CLSID_DirectMusicSegment;
wcscpy(ObjectDescript.wszFileName, L"BoidsD.sgt");
ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME ;
ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
if (SUCCEEDED(m_pLoader->GetObject(&ObjectDescript, IID_IDirectMusicSegment, (void**)&m_pSegment)))
{
return TRUE;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name:
// Desc: Load the dls set that the band needs, but just leave it in the cache.
// Then, it will be referenced and loaded by the bands in the styles and
// segments.
//-----------------------------------------------------------------------------
HRESULT BoidMusic::LoadDLS()
{
DMUS_OBJECTDESC dmod;
dmod.dwSize = sizeof(DMUS_OBJECTDESC);
dmod.guidClass = CLSID_DirectMusicCollection;
dmod.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME ;
wcscpy(dmod.wszFileName, L"Boids.dls");
IDirectMusicCollection* pCollect = NULL;
if( FAILED( m_pLoader->GetObject( &dmod, IID_IDirectMusicCollection,
(VOID**)&pCollect ) ) )
return E_FAIL;
pCollect->Release();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc: Load the Boids chord map.
//-----------------------------------------------------------------------------
BOOL BoidMusic::LoadChordMap()
{
if (m_pChordMap) m_pChordMap->Release();
DMUS_OBJECTDESC ObjectDescript;
ObjectDescript.guidClass = CLSID_DirectMusicChordMap;
wcscpy(ObjectDescript.wszFileName, L"Boids.cdm");
ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
if (SUCCEEDED(m_pLoader->GetObject(&ObjectDescript, IID_IDirectMusicChordMap, (void**)&m_pChordMap)))
{
return TRUE;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name:
// Desc: Load a template and place it in the m_pTemplateSegments[] array.
//-----------------------------------------------------------------------------
BOOL BoidMusic::LoadTemplate(DWORD dwIndex, WCHAR * pwzName)
{
if (m_pTemplateSegments[dwIndex]) m_pTemplateSegments[dwIndex]->Release();
HRESULT hr;
DMUS_OBJECTDESC ObjectDescript;
ObjectDescript.guidClass = CLSID_DirectMusicSegment;
wcscpy(ObjectDescript.wszFileName, pwzName);
ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
if (SUCCEEDED( hr = m_pLoader->GetObject(&ObjectDescript, IID_IDirectMusicSegment, (void**)&m_pTemplateSegments[dwIndex])))
{
return TRUE;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name:
// Desc: Use the composer to compose a style segment from a previously loaded
// template segment, the boids chord map and style. Place the
// segment in the m_pPrimarySegments[] array.
//-----------------------------------------------------------------------------
void BoidMusic::ComposeSegment(DWORD dwIndex)
{
if (m_pComposer && m_pStyle && m_pChordMap && m_pTemplateSegments[dwIndex])
{
if (m_pPrimarySegments[dwIndex])
{
m_pPrimarySegments[dwIndex]->Release();
m_pPrimarySegments[dwIndex] = NULL;
}
m_pComposer->ComposeSegmentFromTemplate(
m_pStyle,
m_pTemplateSegments[dwIndex],
1,
m_pChordMap,
&m_pPrimarySegments[dwIndex]);
if (m_pPrimarySegments[dwIndex])
{
m_pPrimarySegments[dwIndex]->SetRepeats(100);
}
}
}
//-----------------------------------------------------------------------------
// Name:
// Desc: Pull the named motif segment from the boids style.
// Note that we currently use the OLE BSTR string approach.
// This will probably change in the next beta.
//-----------------------------------------------------------------------------
BOOL BoidMusic::GetMotif(DWORD dwIndex, WCHAR * pszName)
{
if (m_pStyle)
{
if (SUCCEEDED(m_pStyle->GetMotif(pszName, &m_pMotifSegments[dwIndex])))
{
return TRUE;
}
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name:
// Desc: Check for a notify event. Since we are only waiting for
// notification of beats, we increment out beat counter. The beat counter
// is used by the boids app to manage the number of motifs allowed at any
// point in time. This keeps things from getting too overcrowded.
// Alternatively, the notifications could be used to synchronize graphic
// events.
//-----------------------------------------------------------------------------
void BoidMusic::HandleNotifies()
{
DMUS_NOTIFICATION_PMSG* pMsg;
if( m_hNotify && m_pPerformance)
{
WaitForSingleObject(m_hNotify, 2);
while( S_OK == m_pPerformance->GetNotificationPMsg(&pMsg))
{
m_pPerformance->FreePMsg((DMUS_PMSG*)pMsg);
m_dwBeatsSinceLastMotif++;
}
}
}
//-----------------------------------------------------------------------------
// Name:
// Desc: This is called by the app, once it gets its main window up.
// Activate the synth and start the music playing.
//-----------------------------------------------------------------------------
void BoidMusic::StartMusic()
{
if (m_pDMusic)
{
m_pDMusic->Activate(TRUE);
}
if (m_pPrimarySegments[0])
{
m_pPerformance->PlaySegment(
m_pPrimarySegments[0], 0, 0, NULL);
m_dwIndex = 0;
}
}
//-----------------------------------------------------------------------------
// Name:
// Desc: This is called from the graphics loop. As we get closer to the center
// of the flock of birds, increase the number of echoes for the echo tool,
// and also increase the duration scalings (makes the note durations
// longer.)
//-----------------------------------------------------------------------------
void BoidMusic::SetDistance(double fDistance)
{
double fTemp = fDistance - 10.0;
fTemp = 70.0 - fTemp;
if (fTemp < 0.0) fTemp = 0.0;
m_Tool.m_dwEcho = (DWORD)(fTemp / 15.0);
m_Tool.m_dwStartRatio = (DWORD)(75 + fTemp);
m_Tool.m_dwRatio = m_Tool.m_dwStartRatio;
}
//-----------------------------------------------------------------------------
// Name:
// Desc: Whenever the flock is about to hit a sphere, this is called. It
// chooses the next segment to go to and plays the planet motif leading
// into the next segment. Notice how it takes the start time of the
// planet motif, adds one, and uses that to start the segment, but on a
// beat boundary. This tricks the segment to start one beat later than
// the motif, creating a smooth musical transition.
//-----------------------------------------------------------------------------
void BoidMusic::Transition()
{
if (!m_fCollapsed && (m_dwBeatsSinceLastMotif > 2))
{
static DWORD dwChoice[8] = { 0, 2, 1, 3, 0, 4, 1, 5 };
m_dwIndex++;
if (m_dwIndex > 8) m_dwIndex = 2;
if (m_dwIndex > 0)
{
if (m_pMotifSegments[0] && m_pPrimarySegments[dwChoice[m_dwIndex-1]])
{
IDirectMusicSegmentState *pState = NULL;
m_pPerformance->PlaySegment(
m_pMotifSegments[0], (DMUS_SEGF_SECONDARY | DMUS_SEGF_BEAT ), 0, &pState);
if (pState)
{
MUSIC_TIME mtTime;
pState->GetStartTime(&mtTime);
pState->Release();
mtTime++;
m_pPerformance->PlaySegment(
m_pPrimarySegments[dwChoice[m_dwIndex-1]], DMUS_SEGF_BEAT , mtTime, NULL);
}
}
}
}
}
//-----------------------------------------------------------------------------
// Name:
// Desc: When the migration force is turned off, the birds start to migrate
// away. So, this starts the migration theme. Note that it plays once,
// and then one of the regular segments is queued to pick up after it.
//-----------------------------------------------------------------------------
void BoidMusic::Migrate()
{
if (m_pSegment)
{
m_pPerformance->PlaySegment(
m_pSegment, DMUS_SEGF_BEAT , 0, NULL);
}
if (m_pPrimarySegments[2])
{
m_pPerformance->PlaySegment(
m_pPrimarySegments[2], DMUS_SEGF_QUEUE , 0, NULL);
}
}
//-----------------------------------------------------------------------------
// Name:
// Desc: When the 's' key or space bar is hit, the birds collapse together. Set
// the collapsed flag indicating the new state. Trigger two motifs to
// play. The first simply plays the collapse motif. The second plays a
// cycling motif until the user lifts up, calling the Expand() function.
//-----------------------------------------------------------------------------
void BoidMusic::Collapse()
{
m_fCollapsed = TRUE;
if (m_dwBeatsSinceLastMotif)
{
if (m_pMotifSegments[5])
{
m_pPerformance->PlaySegment(
m_pMotifSegments[5], (DMUS_SEGF_SECONDARY | DMUS_SEGF_GRID), 0, NULL);
}
if (m_pMotifSegments[3])
{
m_pMotifSegments[3]->SetRepeats(20);
m_pPerformance->PlaySegment(
m_pMotifSegments[3], (DMUS_SEGF_SECONDARY | DMUS_SEGF_MEASURE), 0, NULL);
}
m_dwBeatsSinceLastMotif = 0;
}
}
//-----------------------------------------------------------------------------
// Name:
// Desc: When the user releases the 's' key or space bar, the birds can move
// apart again. Notice that the repeating motif is turned off by calling
// stop on it.
//-----------------------------------------------------------------------------
void BoidMusic::Expand()
{
m_fCollapsed = FALSE;
if (m_dwBeatsSinceLastMotif)
{
if (m_pMotifSegments[4])
{
m_pPerformance->PlaySegment(
m_pMotifSegments[4], (DMUS_SEGF_SECONDARY | DMUS_SEGF_GRID), 0, NULL);
}
m_dwBeatsSinceLastMotif = 0;
}
if (m_pMotifSegments[3])
{
m_pPerformance->Stop(m_pMotifSegments[3], NULL, 0, 0);
}
}
//-----------------------------------------------------------------------------
// Name:
// Desc: Close down all the music stuff.
//-----------------------------------------------------------------------------
void BoidMusic::EndMusic()
{
m_Tool.m_pPerformance = NULL;
if (m_pPerformance)
{
m_pPerformance->Stop( NULL, NULL, 0, 0);
}
if (m_pSegment)
{
m_pSegment->Release();
m_pSegment = NULL;
}
if (m_pBand)
{
if(m_pPerformance)
{
m_pBand->Unload(m_pPerformance);
}
m_pBand->Release();
m_pBand = NULL;
}
if (m_pPort)
{
m_pPort->Release();
m_pPort = NULL;
}
if (m_pDMusic)
{
m_pDMusic->Release();
m_pDMusic = NULL;
}
if (m_pGraph)
{
m_pGraph->Release();
m_pGraph = NULL;
}
long x;
for (x = 0; x< 6; x++)
{
if (m_pTemplateSegments[x])
{
m_pTemplateSegments[x]->Release();
m_pTemplateSegments[x] = NULL;
}
if (m_pPrimarySegments[x])
{
m_pPrimarySegments[x]->Release();
m_pPrimarySegments[x] = NULL;
}
if (m_pMotifSegments[x])
{
m_pMotifSegments[x]->Release();
m_pMotifSegments[x] = NULL;
}
}
if (m_pStyle)
{
m_pStyle->Release();
m_pStyle = NULL;
}
if (m_pChordMap)
{
m_pChordMap->Release();
m_pChordMap = NULL;
}
if (m_pTransitionSegment)
{
m_pTransitionSegment->Release();
m_pTransitionSegment = NULL;
}
if (m_pComposer)
{
m_pComposer->Release();
m_pComposer = NULL;
}
if (m_pLoader)
{
m_pLoader->Release();
m_pLoader = NULL;
}
if (m_pPerformance)
{
m_pPerformance->Stop( NULL, NULL, 0, 0);
m_pPerformance->CloseDown();
m_pPerformance->Release();
m_pPerformance = NULL;
}
CoUninitialize();
}
static char szDirectMusicMedia[] = "Media";
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
BOOL BoidMusic::GetSearchPath(WCHAR wszPath[MAX_PATH])
{
const TCHAR* szDir = DXUtil_GetDXSDKMediaPath();
mbstowcs(wszPath, szDir, MAX_PATH);
return TRUE;
}
// Tool implementation follows. Pretty much all the meat is in the
// ProcessEvent() method.
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
CTool::CTool()
{
m_dwRatio = 100;
m_dwStartRatio = 100;
m_dwEcho = 1;
m_cRef = 0;
m_dwDelay = 96;
m_pPerformance = NULL;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
CTool::~CTool()
{
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
STDMETHODIMP CTool::QueryInterface( const IID &iid, void **ppv)
{
if (iid == IID_IDirectMusicTool)
{
*ppv = static_cast<IDirectMusicTool*>(this);
} else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(this)->AddRef();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CTool::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CTool::Release()
{
if (!InterlockedDecrement(&m_cRef))
{
return 0;
}
return m_cRef;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CTool::ProcessPMsg( IDirectMusicPerformance* pPerf,
DMUS_PMSG* pMsg )
{
HRESULT hr = S_OK;
if (pMsg->pGraph)
{
if (SUCCEEDED(pMsg->pGraph->StampPMsg(pMsg)))
{
hr = DMUS_S_REQUEUE;
}
}
switch( pMsg->dwType )
{
case DMUS_PMSGT_NOTE:
{
/* If we receive a note, first adjust the duration
by m_dwRatio.
*/
DMUS_NOTE_PMSG *pNote = (DMUS_NOTE_PMSG *) pMsg;
if (m_dwRatio < 1) m_dwRatio = 1;
if (m_dwRatio > 400) m_dwRatio = 400;
pNote->mtDuration = MulDiv(pNote->mtDuration,m_dwRatio,100);
/* Then, if it is on the PChannel of the melody,
set it to echo the number of times established
by m_dwEcho. Note that the echo algorithm is
quite simple but powerful: copy the event and play
it on an adjacent PChannel. By playing it on a different
PChannel, we take care of overlapping notes and
we can have it panned differently.
*/
if (m_dwEcho && (pNote->dwPChannel == 7))
{
if (pPerf)
{
DWORD dwX;
if (m_dwEcho > 3) m_dwEcho = 3;
for (dwX = 0; dwX < m_dwEcho; dwX++)
{
DMUS_NOTE_PMSG * pEcho;
if (SUCCEEDED(pPerf->AllocPMsg( sizeof(DMUS_NOTE_PMSG),
(DMUS_PMSG**) &pEcho)))
{
static DWORD dwChannels[3] = { 6, 15, 0 };
memcpy( pEcho, pNote, sizeof(DMUS_NOTE_PMSG) );
pEcho->dwPChannel = dwChannels[dwX];
pEcho->mtTime = pNote->mtTime + (m_dwDelay * (dwX + 1));
pEcho->dwFlags = DMUS_PMSGF_MUSICTIME;
if (pEcho->pGraph) pEcho->pGraph->AddRef();
if (pEcho->pTool) pEcho->pTool->AddRef();
pPerf->SendPMsg( (DMUS_PMSG*)pEcho) ;
}
}
}
}
}
break;
case DMUS_PMSGT_CURVE:
break;
case DMUS_PMSGT_SYSEX:
break;
case DMUS_PMSGT_MIDI:
/* Also, if we receive program changes, volumes, or pans on the
PChannel of the melody, set up the echos to use the same patch,
a diminishing volume, and assign the pans appropriately.
This way, if a different band with different setting is loaded,
the echoed parts will all get reset appropriately.
*/
{
DMUS_MIDI_PMSG *pMidi = (DMUS_MIDI_PMSG *) pMsg;
if (pMidi->dwPChannel == 7)
{
DWORD dwX;
for (dwX = 0;dwX < 3; dwX++)
{
DMUS_MIDI_PMSG * pEcho;
if (SUCCEEDED(m_pPerformance->AllocPMsg( sizeof(DMUS_MIDI_PMSG),
(DMUS_PMSG**) &pEcho)))
{
static DWORD dwChannels[3] = { 6, 15, 0 };
static BYTE bPans[3] = { 80,0,120 };
memcpy( pEcho, pMidi, sizeof(DMUS_MIDI_PMSG) );
pEcho->dwPChannel = dwChannels[dwX];
pEcho->mtTime = pMsg->mtTime + 20;
pEcho->dwFlags = DMUS_PMSGF_MUSICTIME;
if (pMidi->bStatus == 0xB0)
{
if (pMidi->bByte1 == 10)
{
pEcho->bByte2 = bPans[dwX];
}
else if (pMidi->bByte1 == 7)
{
pEcho->bByte2 = pMidi->bByte2 - (((BYTE)dwX+1) * 20);
if (pEcho->bByte2 > 127) pEcho->bByte2 = 10;
}
}
if (pEcho->pGraph) pEcho->pGraph->AddRef();
if (pEcho->pTool) pEcho->pTool->AddRef();
m_pPerformance->SendPMsg( (DMUS_PMSG*)pEcho) ;
}
}
}
}
break;
case DMUS_PMSGT_PATCH:
break;
default:
break;
}
return hr;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CTool::Flush( IDirectMusicPerformance* pPerf,
DMUS_PMSG* pMsg, REFERENCE_TIME rt )
{
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CTool::Init( IDirectMusicGraph* pGraph )
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CTool::GetMsgDeliveryType( DWORD* pdwDeliveryType )
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CTool::GetMediaTypeArraySize( DWORD* pdwNumElements )
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CTool::GetMediaTypes( DWORD** padwMediaTypes,
DWORD dwNumElements )
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT BoidMusic::LoadMusic( HWND hwnd )
{
HRESULT hr;
CoInitialize(NULL);
hr = CoCreateInstance( CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC,
IID_IDirectMusicLoader, (VOID**)&m_pLoader );
if( FAILED(hr) )
{
OutputDebugString("Couldn't create CLSID_DirectMusicLoader\n");
return hr;
}
WCHAR dir[MAX_PATH];
m_pLoader->EnableCache(GUID_DirectMusicAllTypes, TRUE);
hr = E_FAIL;
if (BoidMusic::GetSearchPath(dir))
{
hr = m_pLoader->SetSearchDirectory(GUID_DirectMusicAllTypes, dir, FALSE);
}
if (FAILED(hr))
{
hr = m_pLoader->SetSearchDirectory(GUID_DirectMusicAllTypes, L".", FALSE);
}
if (FAILED(hr))
{
OutputDebugString("Couldn't set DirectMusic search path");
return hr;
}
hr = ::CoCreateInstance( CLSID_DirectMusicComposer, NULL, CLSCTX_INPROC,
IID_IDirectMusicComposer, (VOID**)&m_pComposer);
if( FAILED(hr) )
{
OutputDebugString("Couldn't create CLSID_DirectMusicComposer\n");
return hr;
}
BOOL bResourcesOk = TRUE;
bResourcesOk = bResourcesOk && SUCCEEDED( LoadDLS() );
bResourcesOk = bResourcesOk && LoadStyle();
bResourcesOk = bResourcesOk && LoadChordMap();
bResourcesOk = bResourcesOk && LoadTemplate(0,L"BoidsAA.tpl");
bResourcesOk = bResourcesOk && LoadTemplate(1,L"BoidB1.tpl");
bResourcesOk = bResourcesOk && LoadTemplate(2,L"BoidsC1.tpl");
bResourcesOk = bResourcesOk && LoadTemplate(3,L"BoidsCA.tpl");
bResourcesOk = bResourcesOk && LoadTemplate(4,L"BoidsCB.tpl");
bResourcesOk = bResourcesOk && LoadTemplate(5,L"BoidsCC.tpl");
ComposeSegment(0);
ComposeSegment(1);
ComposeSegment(2);
ComposeSegment(3);
ComposeSegment(4);
ComposeSegment(5);
bResourcesOk = bResourcesOk && LoadSegment();
bResourcesOk = bResourcesOk && GetMotif(0, L"planet");
bResourcesOk = bResourcesOk && GetMotif(1, L"D motif");
bResourcesOk = bResourcesOk && GetMotif(2, L"motif RL med");
bResourcesOk = bResourcesOk && GetMotif(3, L"Cycle");
bResourcesOk = bResourcesOk && GetMotif(4, L"Expand");
bResourcesOk = bResourcesOk && GetMotif(5, L"Collapse");
if (!bResourcesOk)
{
OutputDebugString("Couldn't load DirectMusic resources\n");
return E_FAIL;
}
hr = CoCreateInstance( CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER,
IID_IDirectMusic, (VOID**)&m_pDMusic);
if (FAILED(hr))
{
OutputDebugString("Couldn't create CLSID_DirectMusic\n");
return hr;
}
hr = m_pDMusic->SetDirectSound(NULL, hwnd);
if (FAILED(hr))
{
OutputDebugString("Could't SetDirectSound on IDirectMusic\n");
return hr;
}
DMUS_PORTPARAMS dmos;
DMUS_PORTCAPS dmpc;
GUID guidSynthGUID;
hr = m_pDMusic->GetDefaultPort(&guidSynthGUID);
if (FAILED(hr))
{
OutputDebugString("Could't GetDefaultPort on IDirectMusic\n");
return hr;
}
ZeroMemory(&dmos, sizeof(dmos));
dmos.dwSize = sizeof(DMUS_PORTPARAMS);
dmos.dwChannelGroups = 1;
dmos.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
hr = m_pDMusic->CreatePort( guidSynthGUID, &dmos, &m_pPort, NULL );
if (FAILED(hr))
{
OutputDebugString("Couldn't CreatePort on IDirectMusic\n");
return hr;
}
ZeroMemory(&dmpc, sizeof(dmpc));
dmpc.dwSize = sizeof(DMUS_PORTCAPS);
hr = m_pPort->GetCaps(&dmpc);
if (FAILED(hr))
{
OutputDebugString("Couldn't GetCaps on IDirectMusicPort\n");
return hr;
}
if ((dmpc.dwClass != DMUS_PC_OUTPUTCLASS) || !(dmpc.dwFlags & DMUS_PC_DLS))
{
m_pPort->Release();
m_pPort = NULL;
}
if (!m_pPort)
{
hr = E_FAIL;
for (DWORD index = 0; ; index++)
{
ZeroMemory(&dmpc, sizeof(dmpc));
dmpc.dwSize = sizeof(DMUS_PORTCAPS);
hr = m_pDMusic->EnumPort(index, &dmpc);
if(SUCCEEDED(hr) && hr != S_FALSE)
{
if ( (dmpc.dwClass == DMUS_PC_OUTPUTCLASS) &&
(dmpc.dwFlags & DMUS_PC_DLS) )
{
CopyMemory(&guidSynthGUID, &dmpc.guidPort, sizeof(GUID));
ZeroMemory(&dmos, sizeof(dmos));
dmos.dwSize = sizeof(DMUS_PORTPARAMS);
dmos.dwChannelGroups = 1;
dmos.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
hr = m_pDMusic->CreatePort( guidSynthGUID, &dmos,
&m_pPort, NULL );
break;
}
}
else
{
break;
}
}
}
if (FAILED(hr))
{
OutputDebugString("Couldn't find or CreatePort software synthesizer\n");
return hr;
}
hr = CoCreateInstance( CLSID_DirectMusicPerformance, NULL, CLSCTX_ALL,
IID_IDirectMusicPerformance, (VOID**)&m_pPerformance );
if (FAILED(hr))
{
OutputDebugString("Couldn't create CLSID_DirectMusicPerformance\n");
return hr;
}
hr = m_pPerformance->Init(&m_pDMusic, NULL, NULL);
if (FAILED(hr))
{
OutputDebugString("Couldn't init CLSID_DirectMusicPerformance\n");
return hr;
}
m_pPerformance->AddPort(m_pPort );
m_pPerformance->AssignPChannelBlock(0, m_pPort, 1);
m_hNotify = CreateEvent( NULL, FALSE, FALSE, NULL );
if( m_hNotify )
{
GUID guid;
m_pPerformance->SetNotificationHandle( m_hNotify, 0 );
guid = GUID_NOTIFICATION_MEASUREANDBEAT;
m_pPerformance->AddNotificationType( guid );
}
m_Tool.m_pPerformance = m_pPerformance;
if (m_pBand)
{
m_pBand->Download(m_pPerformance);
}
hr = ::CoCreateInstance( CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC,
IID_IDirectMusicGraph, (VOID**)&m_pGraph );
if (FAILED(hr))
{
OutputDebugString("Couldn't create CLSID_DirectMusicGraph\n");
return hr;
}
m_pPerformance->SetGraph(m_pGraph);
IDirectMusicTool *pTool;
hr = m_Tool.QueryInterface(IID_IDirectMusicTool, (void**)&pTool);
if (FAILED(hr))
{
OutputDebugString("Couldn't InsertTool on graph\n");
return hr;
}
m_pGraph->InsertTool( pTool, 0, NULL, 0);
return S_OK;;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
void BoidMusic::Activate( BOOL bActive )
{
if (m_pDMusic)
{
m_pDMusic->Activate(bActive);
}
}