//----------------------------------------------------------------------------- // File: Music.cpp // // Desc: // // Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #define STRICT #include #include #include #include #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(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast(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); } }