Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1917 lines
48 KiB

  1. /**********************************************************************
  2. Copyright (c) 1992-1999 Microsoft Corporation
  3. config.c
  4. DESCRIPTION:
  5. Code to configure the mapper when a device is added or deleted.
  6. HISTORY:
  7. 02/21/93 [jimge] created.
  8. *********************************************************************/
  9. #include "preclude.h"
  10. #include <windows.h>
  11. #include <winerror.h>
  12. #include <windowsx.h>
  13. #include <mmsystem.h>
  14. #include <mmreg.h>
  15. #include <mmddk.h>
  16. #include <regstr.h>
  17. #include "idf.h"
  18. #include <memory.h>
  19. #include <ctype.h>
  20. #include "midimap.h"
  21. #include "debug.h"
  22. //=========================== Globals ======================================
  23. //
  24. static TCHAR BCODE gszMidiMapKey[] =
  25. REGSTR_PATH_MULTIMEDIA TEXT ("\\MIDIMap");
  26. static TCHAR BCODE gszSchemeListKey[] =
  27. REGSTR_PATH_PRIVATEPROPERTIES TEXT ("\\MIDI\\Schemes");
  28. static TCHAR BCODE gsz2Keys[] =
  29. TEXT ("%s\\%s");
  30. static TCHAR BCODE gszMediaRsrcKey[] =
  31. REGSTR_PATH_MEDIARESOURCES TEXT ("\\MIDI");
  32. static TCHAR BCODE gszDriverKey[] =
  33. REGSTR_PATH_MEDIARESOURCES TEXT ("\\MIDI\\%s");
  34. #ifdef DEBUG
  35. static TCHAR BCODE gszSystemINI[] = TEXT ("system.ini");
  36. static TCHAR BCODE gszMIDIMapSect[] = TEXT ("MIDIMAP");
  37. static TCHAR BCODE gszRunOnceValue[] = TEXT ("RunOnce");
  38. static TCHAR BCODE gszBreakOnConfigValue[]=TEXT ("BreakOnConfig");
  39. #endif
  40. static TCHAR BCODE gszUseSchemeValue[] = TEXT ("UseScheme");
  41. static TCHAR BCODE gszCurSchemeValue[] = TEXT ("CurrentScheme");
  42. static TCHAR BCODE gszCurInstrValue[] = TEXT ("CurrentInstrument");
  43. static TCHAR BCODE gszChannelsValue[] = TEXT ("Channels");
  44. static TCHAR BCODE gszPortValue[] = TEXT ("Port");
  45. static TCHAR BCODE gszDefinitionValue[] = TEXT ("Definition");
  46. static TCHAR BCODE gszFriendlyNameValue[]= TEXT ("FriendlyName");
  47. static TCHAR BCODE gszDescription[] = TEXT ("Description");
  48. static TCHAR BCODE gszAutoSchemeValue[] = TEXT ("AutoScheme");
  49. static TCHAR BCODE gszDefaultFile[] = TEXT ("<internal>");
  50. static TCHAR BCODE gszDefaultInstr[] = TEXT ("Default");
  51. static TCHAR BCODE gszDoRunOnce[] = TEXT ("RunDll32.exe mmsys.cpl,RunOnceSchemeInit");
  52. static TCHAR BCODE gszSetupKey[] = TEXT ("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup");
  53. static TCHAR BCODE gszMachineDir[] = TEXT ("WinDir");
  54. static TCHAR BCODE gszConfigDir[] = TEXT ("config\\");
  55. extern BOOL gfReconfigured;
  56. //=========================== Prototypes ===================================
  57. //
  58. PRIVATE void FNLOCAL ConfigureFromToast(
  59. void);
  60. PRIVATE void FNLOCAL ConfigureScheme(
  61. LPTSTR pstrScheme);
  62. PRIVATE void FNLOCAL ConfigureInstrument(
  63. LPTSTR pstrInstr);
  64. PRIVATE UINT FNLOCAL AddDevice(
  65. WORD wChannelMask,
  66. UINT uDeviceID,
  67. LPTSTR pstrDefinition);
  68. #define PSIK_INVALID ((UINT)(-1))
  69. PRIVATE PPORT FNLOCAL GetPort(
  70. UINT uDeviceID);
  71. PRIVATE void FNLOCAL PortAddRef(
  72. PPORT pport);
  73. PRIVATE void FNLOCAL PortReleaseRef(
  74. PPORT pport);
  75. PRIVATE PINSTRUMENT FNLOCAL GetInstrument(
  76. LPTSTR pstrFilename,
  77. LPTSTR pstrInstrument);
  78. PRIVATE void FNLOCAL InstrumentAddRef(
  79. PINSTRUMENT pinstrument);
  80. PRIVATE void FNLOCAL InstrumentReleaseRef(
  81. PINSTRUMENT pinstrument);
  82. PRIVATE PINSTRUMENT FNLOCAL LoadInstrument(
  83. LPTSTR pstrFileName,
  84. LPTSTR pstrInstrument);
  85. PRIVATE PINSTRUMENT FNLOCAL MakeDefInstrument(
  86. void);
  87. #define GDID_INVALID ((UINT)(-2))
  88. PRIVATE BOOL FNLOCAL GetIDFDirectory(
  89. LPTSTR pszDir,
  90. DWORD cchDir);
  91. PRIVATE VOID FNLOCAL ValidateChannelTypes(
  92. VOID);
  93. //extern UINT FAR PASCAL wmmMIDIRunOnce();
  94. #if 1
  95. /***************************************************************************
  96. @doc internal
  97. @api void | Configure | Configure the mapper.
  98. @comm
  99. Uses new Windowws 2000 message to winmm to get the
  100. current preferred MIDI ID.
  101. ***************************************************************************/
  102. BOOL FNGLOBAL Configure(DWORD fdwUpdate)
  103. {
  104. UINT MidiOutId;
  105. DWORD dwFlags;
  106. MMRESULT mmr;
  107. gfReconfigured = TRUE;
  108. mmr = midiOutMessage((HMIDIOUT)(UINT_PTR)MIDI_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&MidiOutId, (DWORD_PTR)&dwFlags);
  109. if (!mmr && (MIDI_MAPPER != MidiOutId)) AddDevice(ALL_CHANNELS, MidiOutId, TEXT("\0"));
  110. return FALSE;
  111. }
  112. #else
  113. // Obsolete in Windows 2000:
  114. /***************************************************************************
  115. @doc internal
  116. @api void | Configure | Configure the mapper.
  117. @comm
  118. Read HKCU\...\UseScheme to determine if we're loading a scheme or
  119. instrument.
  120. Read either HKCU\...\CurrentScheme or HKCU\...\CurrentInstrument
  121. and call the correct configuration routine.
  122. ***************************************************************************/
  123. BOOL FNGLOBAL Configure(
  124. DWORD fdwUpdate)
  125. {
  126. HKEY hKeyMidiMap = NULL;
  127. HKEY hKeySchemes = NULL;
  128. LPTSTR pstrValueStr = NULL;
  129. DWORD cbValueStr;
  130. DWORD cbValue;
  131. DWORD dwType;
  132. DWORD dwUseScheme;
  133. DWORD dwAutoScheme;
  134. MMRESULT mmr;
  135. MIDIOUTCAPS moc;
  136. #ifdef DEBUG
  137. DWORD dwBreak;
  138. DWORD dwRunOnce;
  139. #endif
  140. BOOL fRanRunOnce = FALSE;
  141. static TCHAR szConfigErr[256];
  142. static TCHAR szConfigErrMsg[256];
  143. DPF(2, TEXT ("--- Configure start ---"));
  144. #ifdef DEBUG
  145. dwBreak = (DWORD)GetPrivateProfileInt(gszMIDIMapSect, gszBreakOnConfigValue, 0, gszSystemINI);
  146. if (dwBreak)
  147. DebugBreak();
  148. #endif
  149. SET_CONFIGERR;
  150. SET_NEEDRUNONCE;
  151. // Rest of configuration assumes we're starting from total scratch
  152. //
  153. assert(NULL == gpportList);
  154. assert(NULL == gpinstrumentList);
  155. #ifdef DEBUG
  156. dwRunOnce = (DWORD)GetPrivateProfileInt(gszMIDIMapSect, gszRunOnceValue, 1, gszSystemINI);
  157. #endif
  158. // Create List of Active MIDIOUT devices
  159. if (!mdev_Init())
  160. {
  161. DPF(1, TEXT ("Could not mdev_Init"));
  162. goto Configure_Cleanup;
  163. }
  164. if (ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER,
  165. gszMidiMapKey,
  166. &hKeyMidiMap))
  167. {
  168. DPF(1, TEXT ("Could not open MidiMap"));
  169. goto Configure_Cleanup;
  170. }
  171. cbValueStr = max(CB_MAXSCHEME, CB_MAXINSTR) * sizeof(TCHAR);
  172. if (NULL == (pstrValueStr = (LPTSTR)LocalAlloc(LPTR, (UINT)cbValueStr)))
  173. {
  174. DPF(1, TEXT ("No memory for pstrValueStr"));
  175. goto Configure_Cleanup;
  176. }
  177. // Get Scheme Values
  178. #if 0
  179. cbValue = sizeof(dwUseScheme);
  180. if (ERROR_SUCCESS != RegQueryValueEx(hKeyMidiMap,
  181. gszUseSchemeValue,
  182. NULL,
  183. &dwType,
  184. (LPSTR)&dwUseScheme,
  185. &cbValue))
  186. {
  187. DPF(1, TEXT ("Missing UseScheme; assuming scheme"));
  188. dwUseScheme = 1;
  189. }
  190. #else
  191. // Windows 2000 does not support schemes.
  192. dwUseScheme = 0;
  193. #endif
  194. cbValue = sizeof(dwAutoScheme);
  195. if (ERROR_SUCCESS != RegQueryValueEx(hKeyMidiMap,
  196. gszAutoSchemeValue,
  197. NULL,
  198. &dwType,
  199. (LPSTR)&dwAutoScheme,
  200. &cbValue))
  201. {
  202. DPF(1, TEXT ("Missing AutoScheme; assuming TRUE"));
  203. dwAutoScheme = 1;
  204. }
  205. if (dwUseScheme)
  206. {
  207. // Get Scheme Name
  208. cbValue = cbValueStr;
  209. if (ERROR_SUCCESS != RegQueryValueEx(hKeyMidiMap,
  210. gszCurSchemeValue,
  211. NULL,
  212. &dwType,
  213. (LPSTR)pstrValueStr,
  214. &cbValue))
  215. {
  216. DPF(1, TEXT ("Could not read scheme"));
  217. // Couldn't read scheme? Let's try to get the first one
  218. //
  219. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE,
  220. gszSchemeListKey,
  221. &hKeySchemes))
  222. {
  223. if (ERROR_SUCCESS == RegEnumKey(hKeySchemes,
  224. 0,
  225. pstrValueStr,
  226. cbValueStr))
  227. {
  228. CLR_CONFIGERR;
  229. DPF(1, TEXT ("Using default scheme %s"), (LPTSTR)pstrValueStr);
  230. }
  231. else
  232. {
  233. DPF(1, TEXT ("Could not enum schemes key"));
  234. }
  235. }
  236. else
  237. {
  238. DPF(1, TEXT ("Could not open [%s]"), (LPTSTR)gszSchemeListKey);
  239. }
  240. }
  241. else
  242. {
  243. CLR_CONFIGERR;
  244. CLR_NEEDRUNONCE;
  245. }
  246. if (!IS_CONFIGERR)
  247. {
  248. DPF(1, TEXT ("Using scheme [%s]"), (LPTSTR)pstrValueStr);
  249. ConfigureScheme(pstrValueStr);
  250. }
  251. }
  252. else
  253. {
  254. // Not using scheme -- try to configure via instrument description
  255. //
  256. cbValue = cbValueStr;
  257. if (ERROR_SUCCESS == RegQueryValueEx(hKeyMidiMap,
  258. gszCurInstrValue,
  259. NULL,
  260. &dwType,
  261. (LPSTR)pstrValueStr,
  262. &cbValue))
  263. {
  264. CLR_CONFIGERR;
  265. CLR_NEEDRUNONCE;
  266. DPF(1, TEXT ("Using instrument [%s]"), (LPTSTR)pstrValueStr);
  267. ConfigureInstrument(pstrValueStr);
  268. // If we're autoconfigure and the device we're using isn't
  269. // marked as an internal synth and we've added a new device,
  270. // do the runonce in case we can find an internal synth
  271. //
  272. if (dwAutoScheme && ((fdwUpdate & 0xFFFF) == DRV_F_ADD))
  273. {
  274. //assert(gpportList->pNext == NULL);
  275. if (gpportList == NULL)
  276. {
  277. DPF(0, TEXT ("Configure: gpportList = NULL"));
  278. goto Configure_Cleanup;
  279. }
  280. DPF(1, TEXT ("AutoScheme && DRV_F_ADD"));
  281. mmr = midiOutGetDevCaps(gpportList->uDeviceID,
  282. &moc,
  283. sizeof(moc));
  284. if (MMSYSERR_NOERROR != mmr ||
  285. MOD_MIDIPORT == moc.wTechnology)
  286. {
  287. UINT cDev;
  288. UINT idxDev;
  289. DPF(1, TEXT ("Bogus or internal"));
  290. cDev = midiOutGetNumDevs();
  291. for (idxDev = 0; idxDev < cDev; ++idxDev)
  292. if (MMSYSERR_NOERROR == midiOutGetDevCaps(
  293. idxDev,
  294. &moc,
  295. sizeof(moc)) &&
  296. MOD_MIDIPORT != moc.wTechnology)
  297. {
  298. DPF(1, TEXT ("AutoConf: External or bogus port; RunOnce!"));
  299. CLR_DONERUNONCE;
  300. SET_NEEDRUNONCE;
  301. break;
  302. }
  303. }
  304. }
  305. }
  306. }
  307. // In all cases, if we are autoscheme and there is a new driver,
  308. // do runonce.
  309. //
  310. if (dwAutoScheme && mdev_NewDrivers())
  311. {
  312. DPF(1, TEXT ("New driver(s); force runonce."));
  313. CLR_DONERUNONCE;
  314. SET_NEEDRUNONCE;
  315. }
  316. Configure_Cleanup:
  317. // Safe to call this even if mdev_Init() failed
  318. //
  319. mdev_Free();
  320. if (IS_CONFIGERR)
  321. {
  322. ConfigureFromToast();
  323. }
  324. if (IS_NEEDRUNONCE && !IS_DONERUNONCE)
  325. {
  326. #ifdef DEBUG
  327. if (dwRunOnce)
  328. {
  329. #endif
  330. DPF(2, TEXT ("Configuration inconsistent -- calling RunOnce"));
  331. // WinExec(gszDoRunOnce, 0);
  332. SET_INRUNONCE;
  333. wmmMIDIRunOnce();
  334. CLR_INRUNONCE;
  335. fRanRunOnce = TRUE;
  336. #ifdef DEBUG
  337. }
  338. else
  339. {
  340. DPF(1, TEXT ("Debug and RunOnce==0, not executing RunOnce"));
  341. }
  342. #endif
  343. SET_DONERUNONCE;
  344. }
  345. ValidateChannelTypes();
  346. // Call our own midiOutGetDevCaps handler to walk the new list of
  347. // ports and figure out what we support
  348. //
  349. modGetDevCaps(&moc, sizeof(moc));
  350. DPF(2, TEXT ("--- Configure end ---"));
  351. if (NULL != pstrValueStr)
  352. LocalFree((HGLOBAL)pstrValueStr);
  353. if (NULL != hKeyMidiMap)
  354. RegCloseKey(hKeyMidiMap);
  355. if (NULL != hKeySchemes)
  356. RegCloseKey(hKeySchemes);
  357. return fRanRunOnce;
  358. }
  359. #endif
  360. void FNGLOBAL Unconfigure(
  361. void)
  362. {
  363. PCHANNEL pchannel;
  364. UINT idxChannel;
  365. UINT idx2;
  366. for (idxChannel = 0; idxChannel < MAX_CHANNELS; idxChannel++)
  367. {
  368. if (NULL != (pchannel = gapChannel[idxChannel]))
  369. {
  370. if (pchannel->pport)
  371. {
  372. for (idx2 = idxChannel+1; idx2 < MAX_CHANNELS; idx2++)
  373. if (NULL != gapChannel[idx2] &&
  374. pchannel->pport == gapChannel[idx2]->pport)
  375. gapChannel[idx2]->pport = NULL;
  376. PortReleaseRef(pchannel->pport);
  377. }
  378. if (pchannel->pinstrument)
  379. InstrumentReleaseRef(pchannel->pinstrument);
  380. LocalFree((HLOCAL)pchannel);
  381. gapChannel[idxChannel] = NULL;
  382. }
  383. }
  384. }
  385. /***************************************************************************
  386. @doc internal
  387. @api void | ConfigureFromToast | Build a configuration to use a 1:1 mapping
  388. of the first internal driver we can find. We use this only if the registry
  389. is totally blown and we have no other choice.
  390. ***************************************************************************/
  391. PRIVATE void FNLOCAL ConfigureFromToast(
  392. void)
  393. {
  394. UINT WavetableMidiOutId;
  395. UINT OtherMidiOutId;
  396. UINT FmMidiOutId;
  397. UINT SoftwareMidiOutId;
  398. UINT ExternalMidiOutId;
  399. UINT MidiOutId;
  400. UINT cMidiOutId;
  401. MIDIOUTCAPS moc;
  402. DPF(1, TEXT ("ConfigureFromToast()"));
  403. CLR_CONFIGERR;
  404. // In case there's any partial junk leftover
  405. Unconfigure();
  406. //
  407. //
  408. //
  409. WavetableMidiOutId = (-1);
  410. OtherMidiOutId = (-1);
  411. FmMidiOutId = (-1);
  412. SoftwareMidiOutId = (-1);
  413. ExternalMidiOutId = (-1);
  414. cMidiOutId = midiOutGetNumDevs();
  415. if (0 != cMidiOutId)
  416. {
  417. for (MidiOutId = 0; MidiOutId < cMidiOutId; MidiOutId++)
  418. {
  419. if (!midiOutGetDevCaps(MidiOutId, &moc, sizeof(moc)))
  420. {
  421. if (MOD_SWSYNTH == moc.wTechnology &&
  422. MM_MSFT_WDMAUDIO_MIDIOUT == moc.wPid &&
  423. MM_MICROSOFT == moc.wMid)
  424. {
  425. SoftwareMidiOutId = MidiOutId;
  426. } else if (MOD_FMSYNTH == moc.wTechnology) {
  427. FmMidiOutId = MidiOutId;
  428. } else if (MOD_MIDIPORT == moc.wTechnology) {
  429. ExternalMidiOutId = MidiOutId;
  430. } else if (MOD_WAVETABLE == moc.wTechnology) {
  431. WavetableMidiOutId = MidiOutId;
  432. } else {
  433. OtherMidiOutId = MidiOutId;
  434. }
  435. }
  436. }
  437. }
  438. if ((-1) != WavetableMidiOutId) MidiOutId = WavetableMidiOutId;
  439. else if ((-1) != SoftwareMidiOutId) MidiOutId = SoftwareMidiOutId;
  440. else if ((-1) != OtherMidiOutId) MidiOutId = OtherMidiOutId;
  441. else if ((-1) != FmMidiOutId) MidiOutId = FmMidiOutId;
  442. else if ((-1) != ExternalMidiOutId) MidiOutId = ExternalMidiOutId;
  443. else MidiOutId = (-1);
  444. if ((-1) == MidiOutId)
  445. {
  446. SET_CONFIGERR;
  447. DPF(1, TEXT (":-( Could not even find an internal device."));
  448. return;
  449. }
  450. DPF(1, TEXT ("CFT: Using device %u"), MidiOutId);
  451. if (!AddDevice(0xFFFF,
  452. MidiOutId,
  453. TEXT("\0")))
  454. {
  455. DPF(1, TEXT ("CFT: AddDevice failed!!!"));
  456. SET_CONFIGERR;
  457. }
  458. }
  459. /***************************************************************************
  460. @doc internal
  461. @api void | ConfigureScheme | Read configuration from registry and set up
  462. data structures.
  463. @parm PSTR | pstrScheme | The scheme to load.
  464. @comm
  465. hkeyScheme = Open key from HKLM\...\Schemes\%scheme%
  466. Enumerate subkeys of Scheme -- each subkey is an alias
  467. GetKey of enumeration key into pstrDevKey
  468. GetValue of Channels= Value
  469. hkeyAlias = Open key from HKLM\...\Midi\%pstrDevKey%
  470. GetValue of Key=
  471. GetValue of Port=
  472. GetValue of File=
  473. GetValue of Instrument=
  474. If everything succeeded, add entry to configuration
  475. ***************************************************************************/
  476. PRIVATE void FNLOCAL ConfigureScheme(
  477. LPTSTR pstrScheme)
  478. {
  479. UINT cbKeyBuffer;
  480. LPTSTR pstrKeyBuffer = NULL;
  481. LPTSTR pstrAlias = NULL;
  482. LPTSTR pstrDevKey = NULL;
  483. LPTSTR pstrDefinition = NULL;
  484. DWORD dwChannelMask;
  485. DWORD dwType;
  486. DWORD cbValue;
  487. DWORD idxEnumKey;
  488. LPTSTR pstrMMDevKey;
  489. UINT uChannels;
  490. UINT uTotalChannels = 0;
  491. UINT uDeviceID;
  492. BOOL fSuccess;
  493. HKEY hkeyScheme = NULL;
  494. HKEY hkeyAlias = NULL;
  495. // Assume something will fail
  496. //
  497. SET_CONFIGERR;
  498. cbKeyBuffer = max(sizeof(gszSchemeListKey) + 1 + CB_MAXSCHEME, sizeof(gszDriverKey) + CB_MAXALIAS);
  499. if (NULL == (pstrKeyBuffer = (LPTSTR)LocalAlloc(LPTR, cbKeyBuffer)) ||
  500. NULL == (pstrAlias = (LPTSTR)LocalAlloc(LPTR, CB_MAXALIAS)) ||
  501. NULL == (pstrDevKey = (LPTSTR)LocalAlloc(LPTR, CB_MAXDEVKEY)) ||
  502. NULL == (pstrDefinition= (LPTSTR)LocalAlloc(LPTR, CB_MAXDEFINITION)))
  503. {
  504. DPF(1, TEXT ("No memory to read configuration!"));
  505. goto Configure_Cleanup;
  506. }
  507. wsprintf(pstrKeyBuffer, gsz2Keys, (LPTSTR)gszSchemeListKey, (LPSTR)pstrScheme);
  508. // NOTE: RegOpenKeyEx does not exist in Chicago
  509. //
  510. if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,
  511. pstrKeyBuffer,
  512. &hkeyScheme))
  513. {
  514. SET_NEEDRUNONCE;
  515. DPF(1, TEXT ("Could not open Schemes\\%s"), (LPTSTR)pstrScheme);
  516. goto Configure_Cleanup;
  517. }
  518. // NOTE: RegEnumKeyEx does not exist in Chicago
  519. //
  520. idxEnumKey = 0;
  521. while (ERROR_SUCCESS == RegEnumKey(hkeyScheme,
  522. idxEnumKey++,
  523. pstrAlias,
  524. CB_MAXALIAS))
  525. {
  526. DPF(1, TEXT ("enum scheme component %lu"), idxEnumKey);
  527. if (ERROR_SUCCESS == RegOpenKey(hkeyScheme,
  528. pstrAlias,
  529. &hkeyAlias))
  530. {
  531. cbValue = CB_MAXDEVKEY;
  532. fSuccess = (ERROR_SUCCESS == RegQueryValue(hkeyAlias,
  533. NULL,
  534. pstrDevKey,
  535. &cbValue));
  536. if (!fSuccess)
  537. {
  538. DPF(1, TEXT ("Failure after hkeyAlias"));
  539. SET_NEEDRUNONCE;
  540. goto Configure_Cleanup;
  541. }
  542. DPF(2, TEXT ("hkeyAlias key=%s"), (LPTSTR)pstrDevKey);
  543. cbValue = sizeof(dwChannelMask);
  544. if (ERROR_SUCCESS != RegQueryValueEx(hkeyAlias,
  545. gszChannelsValue,
  546. NULL,
  547. &dwType,
  548. (LPBYTE)&dwChannelMask,
  549. &cbValue))
  550. {
  551. DPF(1, TEXT ("wChannelMask undefined -- using all channels"));
  552. dwChannelMask = 0xFFFF;
  553. SET_NEEDRUNONCE;
  554. }
  555. RegCloseKey(hkeyAlias);
  556. hkeyAlias = NULL;
  557. if (fSuccess)
  558. {
  559. wsprintf(pstrKeyBuffer, gszDriverKey, (LPTSTR)pstrDevKey);
  560. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE,
  561. pstrKeyBuffer,
  562. &hkeyAlias))
  563. {
  564. pstrMMDevKey = pstrDevKey;
  565. while (*pstrMMDevKey && *pstrMMDevKey != TEXT ('\\'))
  566. ++pstrMMDevKey;
  567. *pstrMMDevKey = TEXT ('\0');
  568. DPF(1, TEXT ("pstrMMDevKey %s"), (LPTSTR)pstrDevKey);
  569. cbValue = CB_MAXDEFINITION * sizeof (TCHAR);
  570. if (ERROR_SUCCESS != RegQueryValueEx(hkeyAlias,
  571. gszDefinitionValue,
  572. NULL,
  573. &dwType,
  574. (LPSTR)pstrDefinition,
  575. &cbValue))
  576. {
  577. DPF(1, TEXT ("pstrDefinition undefined -- using 1:1 mapping"));
  578. *pstrDefinition = TEXT ('\0');
  579. }
  580. uDeviceID = mdev_GetDeviceID(pstrDevKey);
  581. if (NO_DEVICEID != uDeviceID)
  582. {
  583. // Success!!!! Add the entry
  584. //
  585. DPF(1, TEXT ("AddDevice("));
  586. DPF(1, TEXT (" dwChannelMask=%08lX,"), dwChannelMask);
  587. DPF(1, TEXT (" uDeviceID=%u,"), uDeviceID);
  588. DPF(1, TEXT (" pstrDefinition=%s)"), (LPSTR)pstrDefinition);
  589. if (0 == (uChannels = AddDevice(
  590. (WORD)dwChannelMask,
  591. uDeviceID,
  592. pstrDefinition)))
  593. {
  594. SET_CONFIGERR;
  595. goto Configure_Cleanup;
  596. }
  597. uTotalChannels += uChannels;
  598. }
  599. RegCloseKey(hkeyAlias);
  600. hkeyAlias = NULL;
  601. }
  602. else
  603. {
  604. DPF(1, TEXT ("Could not open Aliases\\%s"), (LPTSTR)pstrAlias);
  605. }
  606. }
  607. }
  608. else
  609. {
  610. DPF(1, TEXT ("Could not open Schemes\\%s"), (LPTSTR)pstrAlias);
  611. }
  612. }
  613. // Fall-through is only path to success.
  614. //
  615. if (uTotalChannels)
  616. {
  617. CLR_CONFIGERR;
  618. }
  619. else
  620. {
  621. DPF(1, TEXT ("No channels configured; we're toast!"));
  622. SET_NEEDRUNONCE;
  623. }
  624. Configure_Cleanup:
  625. if (NULL != pstrKeyBuffer)
  626. LocalFree((HLOCAL)pstrKeyBuffer);
  627. if (NULL != pstrAlias)
  628. LocalFree((HLOCAL)pstrAlias);
  629. if (NULL != pstrDevKey)
  630. LocalFree((HLOCAL)pstrDevKey);
  631. if (NULL != pstrDefinition)
  632. LocalFree((HLOCAL)pstrDefinition);
  633. if (NULL != hkeyScheme)
  634. RegCloseKey(hkeyScheme);
  635. if (NULL != hkeyAlias)
  636. RegCloseKey(hkeyAlias);
  637. }
  638. /***************************************************************************
  639. @doc internal
  640. @api void | ConfigureInstrument | Read configuration from registry and set up
  641. data structures.
  642. @parm PSTR | pstrInstrument | The instrument to load.
  643. @comm
  644. ***************************************************************************/
  645. PRIVATE void FNLOCAL ConfigureInstrument(
  646. LPTSTR pstrInstr)
  647. {
  648. HKEY hKeyMediaRsrc = NULL;
  649. LPTSTR pstrKeyBuffer = NULL;
  650. LPTSTR pstrDevKey = NULL;
  651. LPTSTR pstrDefinition = NULL;
  652. #ifndef WINNT
  653. LPTSTR pstrSrc;
  654. LPTSTR pstrDst;
  655. #endif // End WINNT
  656. DWORD dwType;
  657. DWORD cbValue;
  658. UINT cbKeyBuffer;
  659. UINT uDeviceID;
  660. SET_CONFIGERR;
  661. cbKeyBuffer = max(sizeof(gszSchemeListKey) + 1 + CB_MAXSCHEME, sizeof(gszDriverKey) + CB_MAXALIAS);
  662. if (NULL == (pstrKeyBuffer = (LPTSTR)LocalAlloc (LPTR, cbKeyBuffer * sizeof(TCHAR))) ||
  663. NULL == (pstrDefinition= (LPTSTR)LocalAlloc (LPTR, CB_MAXDEFINITION * sizeof(TCHAR))) ||
  664. NULL == (pstrDevKey = (LPTSTR)LocalAlloc (LPTR, CB_MAXDEVKEY * sizeof(TCHAR))))
  665. {
  666. DPF(1, TEXT ("No memory to read configuration!"));
  667. goto Configure_Cleanup;
  668. }
  669. #ifdef WINNT
  670. lstrcpy (pstrDevKey, pstrInstr);
  671. #else
  672. pstrSrc = pstrInstr;
  673. pstrDst = pstrDevKey;
  674. while (*pstrSrc && *pstrSrc != TEXT ('\\'))
  675. *pstrDst++ = *pstrSrc++;
  676. *pstrDst = TEXT ('\0');
  677. #endif // WINNT
  678. wsprintf(pstrKeyBuffer, gszDriverKey, (LPTSTR)pstrInstr);
  679. if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,
  680. pstrKeyBuffer,
  681. &hKeyMediaRsrc))
  682. {
  683. DPF(1, TEXT ("Could not open DevKey %s!"), (LPTSTR)pstrKeyBuffer);
  684. SET_NEEDRUNONCE;
  685. goto Configure_Cleanup;
  686. }
  687. cbValue = CB_MAXDEFINITION;
  688. if (ERROR_SUCCESS != RegQueryValueEx(hKeyMediaRsrc,
  689. gszDefinitionValue,
  690. NULL,
  691. &dwType,
  692. (LPSTR)pstrDefinition,
  693. &cbValue))
  694. {
  695. DPF(1, TEXT ("pstrDefinition undefined -- using 1:1 mapping"));
  696. *pstrDefinition = TEXT ('\0');
  697. }
  698. uDeviceID = mdev_GetDeviceID(pstrDevKey);
  699. if (NO_DEVICEID != uDeviceID)
  700. {
  701. // Success!!!! Add the entry
  702. //
  703. DPF(1, TEXT ("AddDevice("));
  704. DPF(1, TEXT (" uDeviceID=%u"), uDeviceID);
  705. DPF(1, TEXT (" pstrDefinition=%s)"), (LPTSTR)pstrDefinition);
  706. if (0 != AddDevice(ALL_CHANNELS,
  707. uDeviceID,
  708. pstrDefinition))
  709. {
  710. CLR_CONFIGERR;
  711. }
  712. }
  713. Configure_Cleanup:
  714. if (NULL != pstrDefinition)
  715. LocalFree((HLOCAL)pstrDefinition);
  716. if (NULL != pstrKeyBuffer)
  717. LocalFree((HLOCAL)pstrKeyBuffer);
  718. if (NULL != pstrDevKey)
  719. LocalFree((HLOCAL)pstrDevKey);
  720. if (NULL != hKeyMediaRsrc)
  721. RegCloseKey(hKeyMediaRsrc);
  722. }
  723. PRIVATE UINT FNLOCAL AddDevice(
  724. WORD wChannelMask,
  725. UINT uDeviceID,
  726. LPTSTR pstrDefinition)
  727. {
  728. UINT uRet = 0;
  729. WORD wChannelBit;
  730. WORD wAddedMask = 0;
  731. UINT idxChannel;
  732. UINT cbDefinition;
  733. PPORT pport = NULL;
  734. PINSTRUMENT pinstrument = NULL;
  735. PCHANNEL pchannel;
  736. LPTSTR pstrFile = NULL;
  737. LPTSTR pstrInstrument = NULL;
  738. DPF(1, TEXT ("AddDevice: uDeviceID %u pstrDefinition %s"),
  739. uDeviceID,
  740. (LPTSTR)pstrDefinition);
  741. // Parse definition
  742. //
  743. // pstrFile -> filename
  744. // pstrInstrument -> instrument (empty string if none specified)
  745. //
  746. cbDefinition = lstrlen(pstrDefinition);
  747. if (cbDefinition)
  748. {
  749. pstrFile = pstrDefinition;
  750. if (pstrDefinition[cbDefinition-1] == '>')
  751. {
  752. pstrInstrument = pstrDefinition + cbDefinition - 1;
  753. *pstrInstrument-- = TEXT ('\0');
  754. while (pstrInstrument != pstrDefinition && *pstrInstrument != TEXT ('<'))
  755. pstrInstrument--;
  756. if (pstrInstrument == pstrDefinition)
  757. {
  758. DPF(1, TEXT ("Bogus definition [%s]"), (LPTSTR)pstrDefinition);
  759. goto Cleanup_AddDevice;
  760. }
  761. *pstrInstrument++ = TEXT ('\0');
  762. }
  763. else
  764. {
  765. pstrInstrument = pstrDefinition + cbDefinition;
  766. }
  767. DPF(1, TEXT ("AddDevice: pstrFile [%s]"), (LPTSTR)pstrFile);
  768. DPF(1, TEXT ("AddDevice: pstrInstrument: [%s]"), (LPTSTR)pstrInstrument);
  769. pinstrument = GetInstrument(pstrFile, pstrInstrument);
  770. if (NULL == pinstrument)
  771. {
  772. DPF(1, TEXT ("Config Err: Could not load instrument!"));
  773. goto Cleanup_AddDevice;
  774. }
  775. }
  776. else
  777. {
  778. DPF(1, TEXT ("Using default instrument"));
  779. // No definition given; use default instrument
  780. //
  781. pinstrument = NULL;
  782. }
  783. // Ok, now iterate through and try to allocate structures
  784. //
  785. pport = GetPort(uDeviceID);
  786. if (NULL == pport)
  787. {
  788. DPF(1, TEXT ("Config Err: No memory for port structure!"));
  789. goto Cleanup_AddDevice;
  790. }
  791. PortAddRef(pport);
  792. wChannelBit = 1;
  793. for (idxChannel = 0; idxChannel < MAX_CHANNELS; idxChannel++, wChannelBit <<= 1)
  794. {
  795. if (wChannelMask & wChannelBit)
  796. {
  797. if (gapChannel[idxChannel])
  798. {
  799. DPF(1, TEXT ("Config Err: Attempt to overload channel!"));
  800. uRet = 0;
  801. goto Cleanup_AddDevice;
  802. }
  803. pchannel = (PCHANNEL)LocalAlloc(LPTR, sizeof(CHANNEL));
  804. if (NULL == pchannel)
  805. {
  806. uRet = 0;
  807. DPF(1, TEXT ("Config Err: LocalAlloc() failed on PCHANNEL"));
  808. goto Cleanup_AddDevice;
  809. }
  810. pchannel->fwChannel = 0;
  811. pchannel->pport = pport;
  812. pchannel->uChannel = idxChannel; // MSG to change this???
  813. pchannel->pinstrument = pinstrument;
  814. pchannel->pbPatchMap = NULL;
  815. if (pinstrument && DRUM_CHANNEL != idxChannel)
  816. pchannel->pbPatchMap = pinstrument->pbPatchMap;
  817. // Port owns mask of channels which are used on itself
  818. //
  819. pport->wChannelMask |= (1 << idxChannel);
  820. if (!pinstrument)
  821. pchannel->pbKeyMap = NULL;
  822. else if (idxChannel != DRUM_CHANNEL)
  823. pchannel->pbKeyMap = pinstrument->pbGeneralKeyMap;
  824. else
  825. pchannel->pbKeyMap = pinstrument->pbDrumKeyMap;
  826. if (pinstrument)
  827. InstrumentAddRef(pinstrument);
  828. gapChannel[idxChannel] = pchannel;
  829. wAddedMask |= wChannelBit;
  830. ++uRet;
  831. }
  832. }
  833. Cleanup_AddDevice:
  834. if (!uRet)
  835. {
  836. DPF(1, TEXT ("AddDevice: gfConfigErr set!!!!"));
  837. // Something failed! Clean up everything we touched.
  838. //
  839. if (NULL != pport)
  840. {
  841. PortReleaseRef(pport);
  842. if (NULL != pinstrument)
  843. {
  844. InstrumentAddRef(pinstrument);
  845. wChannelBit = 1;
  846. for (idxChannel = 0; idxChannel < MAX_CHANNELS; idxChannel++)
  847. {
  848. if (wAddedMask & wChannelBit)
  849. {
  850. InstrumentReleaseRef(pinstrument);
  851. LocalFree((HLOCAL)gapChannel[idxChannel]);
  852. gapChannel[idxChannel] = NULL;
  853. }
  854. wChannelBit <<= 1;
  855. }
  856. InstrumentReleaseRef(pinstrument);
  857. }
  858. }
  859. }
  860. return uRet;
  861. }
  862. /***************************************************************************
  863. @doc internal
  864. @api PPORT | GetPort | Finds the port structure associated with
  865. the given device key and device ID, creating a blank port
  866. structure if one is not found.
  867. @parm UINT | uDeviceID | The device ID of the port to get
  868. @rdesc The PPORT describing the port or NULL if there was no port
  869. found and no memory to create a new port structure.
  870. ***************************************************************************/
  871. PRIVATE PPORT FNLOCAL GetPort(
  872. UINT uDeviceID)
  873. {
  874. PPORT pport;
  875. for (pport = gpportList; pport; pport = pport->pNext)
  876. if (pport->uDeviceID == uDeviceID)
  877. break;
  878. if (NULL == pport)
  879. {
  880. pport = (PPORT)LocalAlloc(LPTR, sizeof(PORT));
  881. if (NULL != pport)
  882. {
  883. pport->cRef = 0;
  884. pport->fwPort = 0;
  885. pport->wChannelMask = 0;
  886. pport->uDeviceID = uDeviceID;
  887. pport->hmidi = (HMIDIOUT)NULL;
  888. pport->pNext = gpportList;
  889. gpportList = pport;
  890. ++gcPorts;
  891. }
  892. }
  893. else
  894. {
  895. DPF(1, TEXT ("Out of memory trying to create pport for device ID %u"),
  896. (UINT)uDeviceID);
  897. }
  898. return pport;
  899. }
  900. PRIVATE void FNLOCAL PortAddRef(
  901. PPORT pport)
  902. {
  903. ++pport->cRef;
  904. }
  905. PRIVATE void FNLOCAL PortReleaseRef(
  906. PPORT pport)
  907. {
  908. PPORT pportPrev;
  909. PPORT pportCurr;
  910. assert(NULL == pport->hmidi);
  911. if (0 == --pport->cRef)
  912. {
  913. pportPrev = NULL;
  914. pportCurr = gpportList;
  915. while (pportCurr)
  916. {
  917. if (pport == pportCurr)
  918. break;
  919. pportPrev = pportCurr;
  920. pportCurr = pportCurr->pNext;
  921. }
  922. if (pportCurr)
  923. {
  924. if (pportPrev)
  925. pportPrev->pNext = pport->pNext;
  926. else
  927. gpportList = pport->pNext;
  928. }
  929. LocalFree((HLOCAL)pport);
  930. }
  931. }
  932. /***************************************************************************
  933. @doc internal
  934. @api PINSTRUMENT | GetInstrument | Called to get a pointer to an instrument
  935. structure.
  936. @parm PSTR | pstrFilename | Filename of IDF file to use.
  937. @parm PSTR | pstrInstrument | Description of instrument within file to use.
  938. @rdesc TRUE on success.
  939. ***************************************************************************/
  940. PRIVATE PINSTRUMENT FNLOCAL GetInstrument(
  941. LPTSTR pstrFilename,
  942. LPTSTR pstrInstrument)
  943. {
  944. PINSTRUMENT pinstrument;
  945. static WORD wMask;
  946. // See if we already have this instrument name in our list.
  947. // If so, no need to load another instance of it.
  948. //
  949. for (pinstrument = gpinstrumentList; pinstrument; pinstrument = pinstrument->pNext)
  950. {
  951. if ((!lstrcmpi(pinstrument->pstrInstrument, pstrInstrument)) &&
  952. (!lstrcmpi(pinstrument->pstrFilename, pstrFilename)))
  953. break;
  954. }
  955. // Instrument not already loaded? Try to load it.
  956. //
  957. if (NULL == pinstrument)
  958. {
  959. if (lstrcmpi(gszDefaultFile, pstrFilename) ||
  960. lstrcmpi(gszDefaultInstr, pstrInstrument))
  961. {
  962. // Not default 1:1 mapping, try to load IDF
  963. //
  964. pinstrument = LoadInstrument(pstrFilename, pstrInstrument);
  965. if (NULL == pinstrument)
  966. pinstrument = MakeDefInstrument();
  967. }
  968. else
  969. {
  970. // Generate a dummy mapping
  971. //
  972. pinstrument = MakeDefInstrument();
  973. }
  974. }
  975. return pinstrument;
  976. }
  977. PRIVATE void FNLOCAL InstrumentAddRef(
  978. PINSTRUMENT pinstrument)
  979. {
  980. ++pinstrument->cRef;
  981. }
  982. PRIVATE void FNLOCAL InstrumentReleaseRef(
  983. PINSTRUMENT pinstrument)
  984. {
  985. PINSTRUMENT pinstrumentPrev;
  986. PINSTRUMENT pinstrumentCurr;
  987. if (0 == --pinstrument->cRef)
  988. {
  989. pinstrumentPrev = NULL;
  990. pinstrumentCurr = gpinstrumentList;
  991. while (pinstrumentCurr)
  992. {
  993. if (pinstrument == pinstrumentCurr)
  994. break;
  995. pinstrumentPrev = pinstrumentCurr;
  996. pinstrumentCurr = pinstrumentCurr->pNext;
  997. }
  998. if (pinstrumentCurr)
  999. {
  1000. if (pinstrumentPrev)
  1001. {
  1002. pinstrumentPrev->pNext = pinstrument->pNext;
  1003. }
  1004. else
  1005. {
  1006. gpinstrumentList = pinstrument->pNext;
  1007. }
  1008. }
  1009. if (pinstrument->pstrFilename)
  1010. LocalFree((HLOCAL)pinstrument->pstrFilename);
  1011. if (pinstrument->pstrInstrument)
  1012. LocalFree((HLOCAL)pinstrument->pstrInstrument);
  1013. if (pinstrument->pbPatchMap)
  1014. LocalFree((HLOCAL)pinstrument->pbPatchMap);
  1015. if (pinstrument->pbDrumKeyMap)
  1016. LocalFree((HLOCAL)pinstrument->pbDrumKeyMap);
  1017. if (pinstrument->pbGeneralKeyMap)
  1018. LocalFree((HLOCAL)pinstrument->pbGeneralKeyMap);
  1019. LocalFree((HLOCAL)pinstrument);
  1020. }
  1021. }
  1022. /***************************************************************************
  1023. @doc internal
  1024. @api PINSTRUMENT | LoadInstrument | Allocate memory for and load the
  1025. contents of an instrument description from an IDF file.
  1026. @parm PSTR | pstrFileName | File name of the IDF to read from.
  1027. @parm PSTR | pstrInstrument | Instrument name within the IDF file
  1028. to load the instrument from.
  1029. @comm Load the instrument and add it to the global list of instruments.
  1030. We use GlobalAlloc here instead of LocalAlloc since this isn't done
  1031. very often and so we don't fragment our local heap by allocating/
  1032. deallocating lots of little pieces.
  1033. @rdesc TRUE on success; else FALSE.
  1034. ***************************************************************************/
  1035. PRIVATE PINSTRUMENT FNLOCAL LoadInstrument(
  1036. LPTSTR pstrFileName,
  1037. LPTSTR pstrInstrument)
  1038. {
  1039. HMMIO hmmio;
  1040. MMCKINFO chkRIFF;
  1041. MMCKINFO chkParent;
  1042. MMRESULT mmr;
  1043. LPIDFHEADER lpIDFheader;
  1044. LPIDFINSTCAPS lpIDFinstcaps;
  1045. LPIDFCHANNELINFO rglpChanInfo[MAX_CHANNELS];
  1046. LPIDFCHANNELINFO lpChanInfo;
  1047. LPIDFKEYMAP rglpIDFkeymap[MAX_CHAN_TYPES];
  1048. LPIDFPATCHMAPHDR lpIDFpatchmaphdr;
  1049. LPIDFCHANNELHDR lpIDFchanhdr;
  1050. BOOL fFound;
  1051. BOOL fSuccess;
  1052. PINSTRUMENT pinstrument = NULL;
  1053. PCHANINIT pchaninit;
  1054. UINT idx;
  1055. LPTSTR lpsz;
  1056. LPTSTR pszName = NULL;
  1057. UINT cbSize;
  1058. UINT cchSize;
  1059. LPSTR pszCHAR;
  1060. LPTSTR pszTCHAR;
  1061. LPTSTR pszID = NULL;
  1062. // Determine if the IDF has any path elements in it.
  1063. //
  1064. for (lpsz = pstrFileName; *lpsz; lpsz++)
  1065. if (TEXT ('\\') == *lpsz || TEXT ('/') == *lpsz || TEXT (':') == *lpsz)
  1066. break;
  1067. if (!*lpsz)
  1068. {
  1069. // Just a filename; precede it with path
  1070. //
  1071. cbSize = CB_MAXPATH * sizeof (TCHAR);
  1072. if (NULL == (pszName = (LPTSTR)LocalAlloc(LPTR, cbSize)))
  1073. return NULL;
  1074. if (! GetIDFDirectory(pszName, CB_MAXPATH))
  1075. lstrcpy(pszName, TEXT (".\\"));
  1076. lstrcat(pszName, pstrFileName);
  1077. lpsz = (LPTSTR)pszName;
  1078. }
  1079. else
  1080. {
  1081. lpsz = pstrFileName;
  1082. }
  1083. DPF(1, TEXT ("LoadInstrument: %s"), lpsz);
  1084. // Try to open the IDF.
  1085. //
  1086. if (NULL == (hmmio = mmioOpen(lpsz, NULL, MMIO_ALLOCBUF|MMIO_READ)))
  1087. {
  1088. DPF(1, TEXT ("LoadInstrument: Cannot open [%s]!"), (LPTSTR)pstrFileName);
  1089. goto LoadInstrument_Cleanup;
  1090. }
  1091. // Descend into the main RIFF chunk
  1092. //
  1093. chkRIFF.fccType = mmioFOURCC('I', 'D', 'F', ' ');
  1094. if (MMSYSERR_NOERROR != (mmr = mmioDescend(hmmio, &chkRIFF, NULL, MMIO_FINDRIFF)))
  1095. {
  1096. DPF(1, TEXT ("mmioDescend returned %u on RIFF chunk"), mmr);
  1097. mmioClose(hmmio, 0);
  1098. goto LoadInstrument_Cleanup;
  1099. }
  1100. // Ensure valid format and scan for the instrument the caller specified.
  1101. //
  1102. fFound = FALSE;
  1103. fSuccess = FALSE;
  1104. pinstrument = NULL;
  1105. while (!fFound)
  1106. {
  1107. chkParent.fccType = mmioFOURCC('M', 'M', 'A', 'P');
  1108. if (MMSYSERR_NOERROR != (mmr = mmioDescend(hmmio, &chkParent, &chkRIFF, MMIO_FINDLIST)))
  1109. {
  1110. DPF(1, TEXT ("mmioDescend returned %u before [%s] found."), (UINT)mmr, (LPTSTR)pstrInstrument);
  1111. mmioClose(hmmio, 0);
  1112. goto LoadInstrument_Cleanup;
  1113. }
  1114. if (NULL == (lpIDFheader = ReadHeaderChunk(hmmio, &chkParent)))
  1115. {
  1116. DPF(1, TEXT ("No header chunk!"));
  1117. }
  1118. else
  1119. {
  1120. // Copy ID single byte string to UNICODE string
  1121. //
  1122. cchSize = lstrlenA (lpIDFheader->abInstID);
  1123. cbSize = cchSize + 1 * sizeof(TCHAR);
  1124. pszID = (LPTSTR) LocalAlloc(LPTR, cbSize);
  1125. pszCHAR = (LPSTR)lpIDFheader->abInstID;
  1126. pszTCHAR = pszID;
  1127. while (0 != (*pszTCHAR++ = *pszCHAR++))
  1128. ;
  1129. if (NULL == pszID)
  1130. {
  1131. mmioClose(hmmio,0);
  1132. goto LoadInstrument_Cleanup;
  1133. }
  1134. DPF(1, TEXT ("Header chunk found! [%s]"), (LPTSTR)pszID);
  1135. // NOTE: Unspecified pstrInstrument (empty string) means get
  1136. // first one
  1137. //
  1138. if ((!*pstrInstrument) || !lstrcmpi(pszID, pstrInstrument))
  1139. fFound = TRUE;
  1140. #ifdef DEBUG
  1141. if (!*pstrInstrument)
  1142. {
  1143. DPF(1, TEXT ("LoadInstrument: Asked for first; got [%s]"), (LPTSTR)pszID);
  1144. }
  1145. #endif
  1146. if (pszID)
  1147. LocalFree ((HLOCAL)pszID);
  1148. if (fFound)
  1149. {
  1150. DPF(1,TEXT ("Instrument found!"));
  1151. // Pull in the rest of the stuff we need from the IDF. Don't
  1152. // actually try to allocate the instrument structure
  1153. // until we're sure eveything is OK.
  1154. //
  1155. lpIDFinstcaps = ReadCapsChunk(hmmio, &chkParent);
  1156. lpIDFchanhdr = ReadChannelChunk(hmmio, &chkParent, (LPIDFCHANNELINFO BSTACK *)rglpChanInfo);
  1157. lpIDFpatchmaphdr = ReadPatchMapChunk(hmmio, &chkParent);
  1158. ReadKeyMapChunk(hmmio, &chkParent, (LPIDFKEYMAP BSTACK *)rglpIDFkeymap);
  1159. if (lpIDFinstcaps && lpIDFchanhdr)
  1160. {
  1161. // We read all the chunks - now construct the PINSTRUMENT
  1162. // and add it to the list.
  1163. //
  1164. pinstrument = (PINSTRUMENT)LocalAlloc(LPTR, sizeof(INSTRUMENT));
  1165. if (NULL == pinstrument)
  1166. {
  1167. DPF(1, TEXT ("[Local]Alloc failed on PINSTRUMENT!!!"));
  1168. }
  1169. else
  1170. {
  1171. pinstrument->pstrInstrument = NULL;
  1172. pinstrument->cRef = 0;
  1173. pinstrument->fdwInstrument = lpIDFchanhdr->fdwFlags;
  1174. pinstrument->dwGeneralMask = lpIDFchanhdr->dwGeneralMask;
  1175. pinstrument->dwDrumMask = lpIDFchanhdr->dwDrumMask;
  1176. pinstrument->pbPatchMap = NULL;
  1177. pinstrument->pbDrumKeyMap = NULL;
  1178. pinstrument->pbGeneralKeyMap = NULL;
  1179. pchaninit = pinstrument->rgChanInit;
  1180. for (idx = 0; idx < MAX_CHANNELS; idx++)
  1181. {
  1182. pchaninit->cbInit = 0;
  1183. pchaninit->pbInit = NULL;
  1184. pchaninit++;
  1185. }
  1186. // Save the instrument name and file name so we can identify future
  1187. // instances.
  1188. //
  1189. cbSize = lstrlen(pstrFileName)+1 * sizeof (TCHAR);
  1190. pinstrument->pstrFilename = (LPTSTR)LocalAlloc(LPTR, cbSize);
  1191. if (NULL == pinstrument->pstrFilename)
  1192. goto Instrument_Alloc_Failed;
  1193. lstrcpy(pinstrument->pstrFilename, pstrFileName);
  1194. cbSize = lstrlen(pstrInstrument)+1 * sizeof (TCHAR);
  1195. pinstrument->pstrInstrument = (LPTSTR)LocalAlloc(LPTR, cbSize);
  1196. if (NULL == pinstrument->pstrInstrument)
  1197. goto Instrument_Alloc_Failed;
  1198. lstrcpy(pinstrument->pstrInstrument, pstrInstrument);
  1199. // Alloc and save the patch and key maps, if any
  1200. //
  1201. if (NULL != lpIDFpatchmaphdr)
  1202. {
  1203. pinstrument->pbPatchMap = (PBYTE)LocalAlloc(LPTR, sizeof(lpIDFpatchmaphdr->abPatchMap));
  1204. if (NULL == pinstrument->pbPatchMap)
  1205. goto Instrument_Alloc_Failed;
  1206. hmemcpy(
  1207. pinstrument->pbPatchMap,
  1208. lpIDFpatchmaphdr->abPatchMap,
  1209. sizeof(lpIDFpatchmaphdr->abPatchMap));
  1210. }
  1211. // Alloc and copy whatever key maps were in the IDF
  1212. //
  1213. if (rglpIDFkeymap[IDX_CHAN_GEN])
  1214. {
  1215. pinstrument->pbGeneralKeyMap = (PBYTE)LocalAlloc(LPTR, sizeof(rglpIDFkeymap[IDX_CHAN_GEN]->abKeyMap));
  1216. if (NULL == pinstrument->pbGeneralKeyMap)
  1217. goto Instrument_Alloc_Failed;
  1218. hmemcpy(
  1219. pinstrument->pbGeneralKeyMap,
  1220. rglpIDFkeymap[IDX_CHAN_GEN]->abKeyMap,
  1221. sizeof(rglpIDFkeymap[IDX_CHAN_GEN]->abKeyMap));
  1222. }
  1223. if (rglpIDFkeymap[IDX_CHAN_DRUM])
  1224. {
  1225. pinstrument->pbDrumKeyMap = (PBYTE)LocalAlloc(LPTR, sizeof(rglpIDFkeymap[IDX_CHAN_DRUM]->abKeyMap));
  1226. if (NULL == pinstrument->pbDrumKeyMap)
  1227. goto Instrument_Alloc_Failed;
  1228. hmemcpy(
  1229. pinstrument->pbDrumKeyMap,
  1230. rglpIDFkeymap[IDX_CHAN_DRUM]->abKeyMap,
  1231. sizeof(rglpIDFkeymap[IDX_CHAN_DRUM]->abKeyMap));
  1232. }
  1233. // Now build the channel init structures
  1234. //
  1235. for (idx = 0; idx < MAX_CHANNELS; idx++)
  1236. {
  1237. if (NULL != (lpChanInfo = rglpChanInfo[idx]))
  1238. {
  1239. if (lpChanInfo->cbInitData & 0xFFFF0000)
  1240. {
  1241. DPF(1, TEXT ("IDF specifies init data > 64K! Ignored."));
  1242. continue;
  1243. }
  1244. pchaninit = &pinstrument->rgChanInit[idx];
  1245. if (lpChanInfo->cbInitData)
  1246. {
  1247. if (NULL == (pchaninit->pbInit = (PBYTE)
  1248. LocalAlloc(LPTR, (UINT)lpChanInfo->cbInitData)))
  1249. goto Instrument_Alloc_Failed;
  1250. hmemcpy(
  1251. pchaninit->pbInit,
  1252. lpChanInfo->abData,
  1253. (UINT)lpChanInfo->cbInitData);
  1254. pchaninit->cbInit = lpChanInfo->cbInitData;
  1255. }
  1256. }
  1257. }
  1258. }
  1259. }
  1260. Instrument_Alloc_Failed:
  1261. // Make sure we free anything the parse threw at us.
  1262. //
  1263. if (NULL != lpIDFinstcaps)
  1264. GlobalFreePtr(lpIDFinstcaps);
  1265. if (NULL != lpIDFpatchmaphdr)
  1266. GlobalFreePtr(lpIDFpatchmaphdr);
  1267. if (NULL != lpIDFchanhdr)
  1268. GlobalFreePtr(lpIDFchanhdr);
  1269. for (idx = 0; idx < MAX_CHAN_TYPES; idx++)
  1270. if (NULL != rglpIDFkeymap[idx])
  1271. GlobalFreePtr(rglpIDFkeymap[idx]);
  1272. }
  1273. }
  1274. GlobalFreePtr(lpIDFheader);
  1275. mmioAscend(hmmio, &chkParent, 0);
  1276. }
  1277. if (!fSuccess)
  1278. {
  1279. // Clean up anything we might have possibly allocated
  1280. //
  1281. }
  1282. if (pinstrument)
  1283. {
  1284. DPF(1, TEXT ("LoadInstrument success!"));
  1285. pinstrument->pNext = gpinstrumentList;
  1286. gpinstrumentList = pinstrument;
  1287. }
  1288. else
  1289. {
  1290. DPF(1, TEXT ("LoadInstrument failure."));
  1291. }
  1292. mmioAscend(hmmio, &chkRIFF, 0);
  1293. mmioClose(hmmio, 0);
  1294. LoadInstrument_Cleanup:
  1295. if (pszName)
  1296. LocalFree((HLOCAL)pszName);
  1297. return pinstrument;
  1298. }
  1299. PRIVATE PINSTRUMENT FNLOCAL MakeDefInstrument(
  1300. void)
  1301. {
  1302. PINSTRUMENT pinstrument;
  1303. PCHANINIT pchaninit;
  1304. UINT idx;
  1305. UINT cbSize;
  1306. pinstrument = (PINSTRUMENT)LocalAlloc(LPTR, sizeof(INSTRUMENT));
  1307. if (NULL == pinstrument)
  1308. {
  1309. DPF(1, TEXT ("[Local]Alloc failed on PINSTRUMENT!!!"));
  1310. return NULL;
  1311. }
  1312. pinstrument->pstrInstrument = NULL;
  1313. pinstrument->cRef = 0;
  1314. pinstrument->fdwInstrument = 0;
  1315. pinstrument->pbPatchMap = NULL;
  1316. pinstrument->pbDrumKeyMap = NULL;
  1317. pinstrument->pbGeneralKeyMap = NULL;
  1318. pchaninit = pinstrument->rgChanInit;
  1319. for (idx = 0; idx < MAX_CHANNELS; idx++, pchaninit++)
  1320. {
  1321. pchaninit->cbInit = 0;
  1322. pchaninit->pbInit = NULL;
  1323. }
  1324. // Save the instrument name and file name so we can identify future
  1325. // instances.
  1326. //
  1327. cbSize = (lstrlen(gszDefaultFile) + 1) * sizeof(TCHAR);
  1328. pinstrument->pstrFilename = (LPTSTR)LocalAlloc(LPTR, cbSize);
  1329. if (NULL == pinstrument->pstrFilename)
  1330. {
  1331. LocalFree((HLOCAL)pinstrument);
  1332. return NULL;
  1333. }
  1334. lstrcpy(pinstrument->pstrFilename, gszDefaultFile);
  1335. cbSize = (lstrlen(gszDefaultInstr) + 1) * sizeof(TCHAR);
  1336. pinstrument->pstrInstrument = (LPTSTR)LocalAlloc(LPTR, cbSize);
  1337. if (NULL == pinstrument->pstrInstrument)
  1338. {
  1339. LocalFree((HLOCAL)pinstrument->pstrFilename);
  1340. LocalFree((HLOCAL)pinstrument);
  1341. return NULL;
  1342. }
  1343. lstrcpy(pinstrument->pstrInstrument, gszDefaultInstr);
  1344. return pinstrument;
  1345. }
  1346. /***************************************************************************
  1347. @doc internal
  1348. @api BOOL | UpdateInstruments | Called to reconfigure the mapper when
  1349. control panel pokes at it.
  1350. @rdesc TRUE on success; FALSE if the request was deferred because
  1351. there are open instances.
  1352. ***************************************************************************/
  1353. BOOL FNGLOBAL UpdateInstruments(
  1354. BOOL fFromCPL,
  1355. DWORD fdwUpdate)
  1356. {
  1357. if (IS_INRUNONCE)
  1358. {
  1359. DPF(1, TEXT ("Got reconfig while RunOnce going...ignored"));
  1360. return TRUE;
  1361. }
  1362. if ((fdwUpdate & 0xFFFF) == DRV_F_PROP_INSTR)
  1363. {
  1364. DPF(1, TEXT ("Reconfig from CPL or RunOnce"));
  1365. }
  1366. DPF(1, TEXT ("UpdateInstruments called."));
  1367. if (IS_DEVSOPENED)
  1368. {
  1369. SET_RECONFIGURE;
  1370. return FALSE;
  1371. }
  1372. else
  1373. {
  1374. Unconfigure();
  1375. if (Configure(fdwUpdate))
  1376. {
  1377. Unconfigure();
  1378. if (Configure(fdwUpdate))
  1379. DPF(1, TEXT ("Tried to reconfigure more than twice -- uh-oh"));
  1380. }
  1381. }
  1382. return TRUE;
  1383. }
  1384. /*+ GetIDFDirectory
  1385. *
  1386. *-=================================================================*/
  1387. PRIVATE BOOL FNLOCAL GetIDFDirectory (
  1388. LPTSTR pszDir,
  1389. DWORD cchDir)
  1390. {
  1391. HKEY hKey;
  1392. UINT cbSize;
  1393. *pszDir = 0;
  1394. cbSize = cchDir * sizeof(TCHAR);
  1395. if (!RegOpenKey (HKEY_LOCAL_MACHINE, gszSetupKey, &hKey))
  1396. {
  1397. RegQueryValueEx (hKey,
  1398. gszMachineDir,
  1399. NULL,
  1400. NULL,
  1401. (LPBYTE)pszDir,
  1402. &cbSize);
  1403. RegCloseKey (hKey);
  1404. cchDir = cbSize / sizeof(TCHAR);
  1405. if (!cchDir--)
  1406. return FALSE;
  1407. }
  1408. else if (!GetWindowsDirectory(pszDir, (UINT)cchDir))
  1409. return FALSE;
  1410. cchDir = lstrlen (pszDir);
  1411. if (pszDir[cchDir -1] != TEXT ('\\'))
  1412. pszDir[cchDir++] = TEXT ('\\');
  1413. lstrcpy (pszDir + cchDir, gszConfigDir);
  1414. return TRUE;
  1415. }
  1416. /***************************************************************************
  1417. @doc internal
  1418. @api VOID | ValidateChannelTypes | Ensure that the given channel
  1419. assignments in the registry are correct in terms of the IDF's. Make an
  1420. attempt to find a drum channel if needed; it might be on channel 16
  1421. for a hindered driver.
  1422. ***************************************************************************/
  1423. PRIVATE VOID FNLOCAL DeassignChannel(
  1424. UINT uChannel)
  1425. {
  1426. UINT idx;
  1427. assert(uChannel < MAX_CHANNELS);
  1428. if (!gapChannel[uChannel])
  1429. return;
  1430. for (idx = 0; idx < MAX_CHANNELS; idx++)
  1431. {
  1432. if (gapChannel[idx])
  1433. {
  1434. if ((idx != uChannel) &&
  1435. (gapChannel[uChannel]->pport == gapChannel[idx]->pport))
  1436. {
  1437. break;
  1438. }
  1439. }
  1440. }
  1441. if (idx == MAX_CHANNELS)
  1442. PortReleaseRef(gapChannel[uChannel]->pport);
  1443. InstrumentReleaseRef(gapChannel[uChannel]->pinstrument);
  1444. LocalFree((HLOCAL)gapChannel[uChannel]);
  1445. gapChannel[uChannel] = NULL;
  1446. }
  1447. PRIVATE VOID FNLOCAL ValidateChannelTypes(
  1448. VOID)
  1449. {
  1450. UINT idxChan;
  1451. DWORD dwChanBit;
  1452. DWORD dwIDFMask;
  1453. PCHANNEL pchannel;
  1454. UINT uNewDrumChan;
  1455. PINSTRUMENT pinst;
  1456. DPF(2, TEXT (" --- ValidateChannelTypes ---"));
  1457. // First, mute any channel that doesn't match the correct channel type
  1458. //
  1459. for (idxChan = 0, dwChanBit = 1;
  1460. idxChan < MAX_CHANNELS;
  1461. ++idxChan, dwChanBit <<= 1)
  1462. {
  1463. if (NULL == (pchannel = gapChannel[idxChan]))
  1464. {
  1465. DPF(2, TEXT (" Channel %u was never allocated"), idxChan);
  1466. continue;
  1467. }
  1468. if (NULL == pchannel->pinstrument)
  1469. {
  1470. DPF(2, TEXT (" Channel %u contains default instrument"), idxChan);
  1471. continue;
  1472. }
  1473. dwIDFMask = (idxChan != DRUM_CHANNEL) ?
  1474. pchannel->pinstrument->dwGeneralMask :
  1475. pchannel->pinstrument->dwDrumMask;
  1476. if (dwIDFMask & dwChanBit)
  1477. continue;
  1478. DPF(2, TEXT (" Muting channel %u"), idxChan);
  1479. pchannel->fwChannel |= CHAN_F_MUTED;
  1480. }
  1481. // Now, if the drum channel is assigned but muted, attempt to find a drum
  1482. // channel on the same instrument.
  1483. //
  1484. if (NULL == (pchannel = gapChannel[DRUM_CHANNEL]))
  1485. {
  1486. DPF(2, TEXT (" No drum channel"));
  1487. goto Validate_Cleanup;
  1488. }
  1489. if (!(pchannel->fwChannel & CHAN_F_MUTED))
  1490. {
  1491. DPF(2, TEXT (" Drum channel already valid"));
  1492. goto Validate_Cleanup;
  1493. }
  1494. pinst = pchannel->pinstrument;
  1495. assert(pinst);
  1496. dwIDFMask = pchannel->pinstrument->dwDrumMask;
  1497. for (uNewDrumChan = 0, dwChanBit = 1;
  1498. uNewDrumChan < MAX_CHANNELS;
  1499. ++uNewDrumChan, dwChanBit <<= 1)
  1500. if (dwChanBit & dwIDFMask)
  1501. break;
  1502. if (uNewDrumChan != MAX_CHANNELS)
  1503. {
  1504. DPF(2, TEXT (" New drum channel %u"), uNewDrumChan);
  1505. // We've found a new drum channel; mute anything that's using it as a
  1506. // general channel
  1507. //
  1508. for (idxChan = 0; idxChan < MAX_CHANNELS; ++idxChan)
  1509. if (idxChan != DRUM_CHANNEL &&
  1510. gapChannel[idxChan] &&
  1511. gapChannel[idxChan]->pinstrument == pinst &&
  1512. gapChannel[idxChan]->uChannel == uNewDrumChan)
  1513. {
  1514. DPF(2, TEXT (" Channel %u was on new drum channel"), idxChan);
  1515. gapChannel[idxChan]->fwChannel |= CHAN_F_MUTED;
  1516. }
  1517. // Now assign it is a drum channel
  1518. //
  1519. pchannel->fwChannel &= ~CHAN_F_MUTED;
  1520. pchannel->uChannel = uNewDrumChan;
  1521. pchannel->pbPatchMap = NULL;
  1522. pchannel->pbKeyMap = pinst->pbDrumKeyMap;
  1523. }
  1524. // Now go through and deassign all muted channels. This will free
  1525. // their memory
  1526. //
  1527. Validate_Cleanup:
  1528. DPF(2, TEXT (" Validate cleanup"));
  1529. for (idxChan = 0; idxChan < MAX_CHANNELS; ++idxChan)
  1530. if (gapChannel[idxChan] &&
  1531. (gapChannel[idxChan]->fwChannel & CHAN_F_MUTED))
  1532. {
  1533. DPF(2, TEXT (" Deassign %u"), idxChan);
  1534. DeassignChannel(idxChan);
  1535. }
  1536. DPF(2, TEXT (" --- Validate End ---"));
  1537. }