Leaked source code of windows server 2003
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.

2150 lines
68 KiB

  1. /****************************************************************************
  2. MODULE: HAU_MIDI.CPP
  3. Tab stops 5 9
  4. Copyright 1995, 1996, Microsoft Corporation, All Rights Reserved.
  5. PURPOSE: Methods for Jolt Midi device command Protocol
  6. FUNCTIONS: Classes methods
  7. Author(s): Name:
  8. ---------- ----------------
  9. MEA Manolito E. Adan
  10. Revision History:
  11. -----------------
  12. Version Date Author Comments
  13. ------- ------ ----- -------------------------------------------
  14. 1.0 02-Apr-96 MEA Original
  15. 19-Sep-96 MEA Removed ES1.0 specific code
  16. 05-Dec-96 MEA Removed ALLACK debug switch
  17. 1.1 17-Mar-97 MEA DX-FF mode
  18. 14-Apr-97 MEA Added support for RTC spring
  19. 16-Mar-99 waltw Add checks for NULL g_pJoltMidi
  20. ****************************************************************************/
  21. #include <windows.h>
  22. #include <mmsystem.h>
  23. #include <assert.h>
  24. #include "hau_midi.hpp"
  25. #include "midi.hpp"
  26. #include "midi_obj.hpp"
  27. #include "dx_map.hpp"
  28. #include "sw_objec.hpp"
  29. #include "ffd_swff.hpp"
  30. #include "joyregst.hpp"
  31. #include "FFDevice.h"
  32. /****************************************************************************
  33. Declaration of externs
  34. ****************************************************************************/
  35. /****************************************************************************
  36. Declaration of variables
  37. ****************************************************************************/
  38. //
  39. // Globals specific to hau_midi
  40. //
  41. extern CJoltMidi *g_pJoltMidi;
  42. #ifdef _DEBUG
  43. extern char g_cMsg[160];
  44. #endif
  45. // *** ---------------------------------------------------------------------***
  46. // Function: CMD_Init
  47. // Purpose: Inits JOLT for MIDI channel
  48. // Parameters:
  49. // none
  50. //
  51. // Returns: SUCCESS - if successful, else
  52. // a device Error code
  53. //
  54. // Algorithm:
  55. //
  56. // Comments:
  57. //
  58. // *** ---------------------------------------------------------------------***
  59. HRESULT CMD_Init(void)
  60. {
  61. HRESULT hRet;
  62. BYTE bChannel = DEFAULT_MIDI_CHANNEL;
  63. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  64. g_pJoltMidi->SetMidiChannel(bChannel); // Force this channel
  65. hRet = CMD_MIDI_Assign(bChannel);
  66. return(hRet);
  67. }
  68. //
  69. // --- EFFECT_CMDs
  70. //
  71. /****************************************************************************
  72. FUNCTION: CMD_Force_Out
  73. PARAMETERS: IN LONG lForceData - Actual force
  74. IN ULONG ulAxisMask - Axis Mask
  75. RETURNS: SUCCESS or FAILURE
  76. COMMENTS: Sends force vector to MIDI channel
  77. Byte 0 = EFFECT_CMD + Channel #
  78. D7 D6 D5 D4 D3 D2 D1 D0
  79. -- -- -- -- -- -- -- --
  80. Byte 1 = Low byte of Force 0 v4 v3 v2 v1 v0 d d
  81. Byte 2 = High byte of Force 0 v11 v10 v9 v8 v7 v6 v5
  82. where: d d
  83. - -
  84. 0 0 reserved
  85. 0 1 PUT_FORCE_X
  86. 1 0 PUT_FORCE_Y
  87. 1 1 PUT_FORCE_XY
  88. ****************************************************************************/
  89. HRESULT CMD_Force_Out(LONG lForceData, ULONG ulAxisMask)
  90. {
  91. HRESULT hRet;
  92. BYTE cData1;
  93. BYTE cData2;
  94. BYTE cAxis;
  95. BYTE cStatus = EFFECT_CMD;
  96. switch(ulAxisMask)
  97. {
  98. case X_AXIS:
  99. cAxis = PUT_FORCE_X;
  100. break;
  101. case Y_AXIS:
  102. cAxis = PUT_FORCE_Y;
  103. break;
  104. case (X_AXIS | Y_AXIS):
  105. cAxis = PUT_FORCE_XY;
  106. break;
  107. default:
  108. return (SFERR_INVALID_PARAM);
  109. break;
  110. }
  111. cData1 = ((int) lForceData << 2) & 0x7c;
  112. cData1 = cData1 | cAxis;
  113. cData2 = ((int) lForceData >> 5) & 0x7f;
  114. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  115. hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD, cData1, cData2);
  116. if (SUCCESS != hRet)
  117. return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
  118. DRIVER_ERROR_MIDI_OUTPUT));
  119. // Note: PutForce used to not expect an ACK/NACK, only used to slow down
  120. // transmission to Jolt and prevent any lockups
  121. //Sleep(SHORT_MSG_TIMEOUT);
  122. //ACKNACK AckNack = {sizeof(ACKNACK)};
  123. //hRet = g_pJoltMidi->GetAckNackData(g_pJoltMidi->DelayParamsPtrOf()->dwForceOutDelay, &AckNack);
  124. #if 0
  125. static DWORD dwMod = 0;
  126. dwMod++;
  127. if(dwMod%g_pJoltMidi->DelayParamsPtrOf()->dwForceOutMod == 0)
  128. Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwForceOutDelay);
  129. #endif
  130. DWORD dwIn;
  131. int nDelayCount = g_pJoltMidi->DelayParamsPtrOf()->dwForceOutDelay;
  132. for(int i=0; i<nDelayCount; i++)
  133. g_pDriverCommunicator->GetStatusGateData(dwIn);
  134. return (SUCCESS);
  135. }
  136. // *** ---------------------------------------------------------------------***
  137. // Function: CMD_DestroyEffect
  138. // Purpose: Destroys the Effect from Device
  139. // Parameters:
  140. // IN DNHANDLE DnloadID - an Effect ID
  141. //
  142. // Returns: SUCCESS if successful command sent, else
  143. // SFERR_INVALID_OBJECT
  144. // SFERR_NO_SUPPORT
  145. //
  146. // Algorithm:
  147. //
  148. // Comments:
  149. // The Device's Effect ID and memory is returned to free pool.
  150. // Byte 0 = EFFECT_CMD + Channel #
  151. // D7 D6 D5 D4 D3 D2 D1 D0
  152. // -- -- -- -- -- -- -- --
  153. // Byte 1 = DESTROY_EFFECT 0 0 0 1 0 0 0 0
  154. // Byte 2 = EffectID (7 bits) 0 E E E E E E E
  155. //
  156. //
  157. // *** ---------------------------------------------------------------------***
  158. HRESULT CMD_DestroyEffect(
  159. IN DNHANDLE DnloadID)
  160. {
  161. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  162. // Check for valid Effect
  163. CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
  164. assert(NULL != pMidiEffect);
  165. if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
  166. // Send the command
  167. HRESULT hRet = pMidiEffect->DestroyEffect();
  168. if (SUCCESS != hRet)
  169. return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
  170. DRIVER_ERROR_MIDI_OUTPUT));
  171. ACKNACK AckNack = {sizeof(ACKNACK)};
  172. // Wait for ACK. Note: WinMM has callback Event notification
  173. // while Backdoor and serial does not.
  174. if (COMM_WINMM == g_pJoltMidi->COMMInterfaceOf())
  175. {
  176. hRet = g_pJoltMidi->GetAckNackData(ACKNACK_EFFECT_STATUS_TIMEOUT, &AckNack, REGBITS_DESTROYEFFECT);
  177. }
  178. else
  179. hRet = g_pJoltMidi->GetAckNackData(SHORT_MSG_TIMEOUT, &AckNack, REGBITS_DESTROYEFFECT);
  180. // :
  181. if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
  182. if (ACK != AckNack.dwAckNack)
  183. return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
  184. // Delete the Effect
  185. delete pMidiEffect;
  186. return (hRet);
  187. }
  188. // *** ---------------------------------------------------------------------***
  189. // Function: CMD_PlayEffectSuperimpose
  190. // Purpose: Plays the Effect in Device
  191. // Parameters:
  192. // IN DNHANDLE DnloadID - an Effect ID
  193. //
  194. // Returns: SUCCESS if successful command sent, else
  195. // SFERR_INVALID_OBJECT
  196. // SFERR_NO_SUPPORT
  197. //
  198. // Algorithm: This is PLAY_SUPERIMPOSE mode
  199. //
  200. // Comments:
  201. // Byte 0 = EFFECT_CMD + Channel #
  202. // D7 D6 D5 D4 D3 D2 D1 D0
  203. // -- -- -- -- -- -- -- --
  204. // Byte 1 = PLAY_EFFECT_SUPERIMPOSE 0 0 1 0 0 0 0 0
  205. // Byte 2 = EffectID (7 bits) 0 E E E E E E E
  206. //
  207. // *** ---------------------------------------------------------------------***
  208. HRESULT CMD_PlayEffectSuperimpose(
  209. IN DNHANDLE DnloadID)
  210. {
  211. HRESULT hRet;
  212. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  213. // Check for valid Effect
  214. CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
  215. assert(pMidiEffect);
  216. if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
  217. #if 0
  218. // Hack to fix firmware bug #1138 which causes an infinite duration
  219. // effect not to be felt on re-start once the effect has been stopped.
  220. // The hack is to "change" the duration from infinite to infinite
  221. ULONG ulDuration = pMidiEffect->DurationOf();
  222. if(ulDuration == 0)
  223. {
  224. // see if it is a PL or an atomic effect
  225. ULONG ulSubType = pMidiEffect->SubTypeOf();
  226. BOOL bProcessList = (ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE);
  227. if(!bProcessList)
  228. hRet = CMD_ModifyParamByIndex(INDEX0, DnloadID, 0);
  229. }
  230. #endif
  231. // Update the playback mode for this Effect
  232. pMidiEffect->SetPlayMode(PLAY_SUPERIMPOSE);
  233. assert((BYTE) DnloadID < MAX_EFFECT_IDS);
  234. hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD,PLAY_EFFECT_SUPERIMPOSE,(BYTE)DnloadID);
  235. if (SUCCESS != hRet)
  236. return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
  237. DRIVER_ERROR_MIDI_OUTPUT));
  238. ACKNACK AckNack = {sizeof(ACKNACK)};
  239. hRet = g_pJoltMidi->GetAckNackData(LONG_MSG_TIMEOUT, &AckNack, REGBITS_PLAYEFFECT);
  240. // :
  241. if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
  242. if (ACK != AckNack.dwAckNack)
  243. return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
  244. return (hRet);
  245. }
  246. // *** ---------------------------------------------------------------------***
  247. // Function: CMD_PlayEffectSolo
  248. // Purpose: Plays the Effect in Device as PLAY_SOLO
  249. // Parameters:
  250. // IN DNHANDLE EffectID - an Effect ID
  251. //
  252. // Returns: SUCCESS if successful command sent, else
  253. // SFERR_INVALID_OBJECT
  254. // SFERR_NO_SUPPORT
  255. //
  256. // Algorithm: This is PLAY_SOLO mode
  257. //
  258. // Comments:
  259. // Byte 0 = EFFECT_CMD + Channel #
  260. // D7 D6 D5 D4 D3 D2 D1 D0
  261. // -- -- -- -- -- -- -- --
  262. // Byte 1 = PLAY_EFFECT_SOLO 0 0 0 0 0 0 0 0
  263. // Byte 2 = EffectID (7 bits) 0 E E E E E E E
  264. //
  265. // *** ---------------------------------------------------------------------***
  266. HRESULT CMD_PlayEffectSolo(
  267. IN DNHANDLE DnloadID)
  268. {
  269. HRESULT hRet;
  270. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  271. // Check for valid Effect
  272. CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
  273. assert(pMidiEffect);
  274. if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
  275. #if 0
  276. // Hack to fix firmware bug #1138 which causes an infinite duration
  277. // effect not to be felt on re-start once the effect has been stopped.
  278. // The hack is to "change" the duration from infinite to infinite
  279. ULONG ulDuration = pMidiEffect->DurationOf();
  280. if(ulDuration == 0)
  281. {
  282. // see if it is a PL or an atomic effect
  283. ULONG ulSubType = pMidiEffect->SubTypeOf();
  284. BOOL bProcessList = (ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE);
  285. if(!bProcessList)
  286. hRet = CMD_ModifyParamByIndex(INDEX0, DnloadID, 0);
  287. }
  288. #endif
  289. // Update the playback mode for this Effect
  290. pMidiEffect->SetPlayMode(PLAY_SOLO);
  291. hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD,PLAY_EFFECT_SOLO, (BYTE) DnloadID);
  292. if (SUCCESS != hRet)
  293. return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
  294. DRIVER_ERROR_MIDI_OUTPUT));
  295. ACKNACK AckNack = {sizeof(ACKNACK)};
  296. hRet = g_pJoltMidi->GetAckNackData(LONG_MSG_TIMEOUT, &AckNack, REGBITS_PLAYEFFECT);
  297. // :
  298. if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
  299. if (ACK != AckNack.dwAckNack)
  300. return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
  301. return (hRet);
  302. }
  303. // *** ---------------------------------------------------------------------***
  304. // Function: CMD_StopEffect
  305. // Purpose: Stops the Effect in Device
  306. // Parameters:
  307. // IN DNHANDLE EffectID - an Effect ID
  308. //
  309. // Returns: SUCCESS if successful command sent, else
  310. // SFERR_INVALID_OBJECT
  311. // SFERR_NO_SUPPORT
  312. //
  313. // Algorithm:
  314. //
  315. // Comments:
  316. // Byte 0 = EFFECT_CMD + Channel #
  317. // D7 D6 D5 D4 D3 D2 D1 D0
  318. // -- -- -- -- -- -- -- --
  319. // Byte 1 = STOP_EFFECT 0 0 1 1 0 0 0 0
  320. // Byte 2 = EffectID (7 bits) 0 E E E E E E E
  321. //
  322. // *** ---------------------------------------------------------------------***
  323. HRESULT CMD_StopEffect(
  324. IN DNHANDLE DnloadID)
  325. {
  326. HRESULT hRet;
  327. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  328. // Check for valid Effect
  329. CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
  330. assert(pMidiEffect);
  331. if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
  332. hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD, STOP_EFFECT, (BYTE) DnloadID);
  333. if (SUCCESS != hRet)
  334. return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
  335. DRIVER_ERROR_MIDI_OUTPUT));
  336. ACKNACK AckNack = {sizeof(ACKNACK)};
  337. hRet = g_pJoltMidi->GetAckNackData(SHORT_MSG_TIMEOUT, &AckNack, REGBITS_STOPEFFECT);
  338. // :
  339. if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
  340. if (ACK != AckNack.dwAckNack)
  341. return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
  342. return (hRet);
  343. }
  344. // *** ---------------------------------------------------------------------***
  345. // Function: CMD_SetIndex
  346. // Purpose: Sets the autoincrementing Index for MODIFY_CMD
  347. // Parameters:
  348. // IN int nIndex - Index value 0 - 15
  349. // IN DNHANDLE DnloadID - Effect ID in stick
  350. //
  351. // Returns: SUCCESS if successful command sent, else
  352. // SFERR_INVALID_OBJECT
  353. // SFERR_NO_SUPPORT
  354. // SFERR_INVALID_PARAM
  355. // Algorithm:
  356. //
  357. // Comments:
  358. // Byte 0 = EFFECT_CMD + Channel #
  359. // D7 D6 D5 D4 D3 D2 D1 D0
  360. // -- -- -- -- -- -- -- --
  361. // Byte 1 = SET_INDEX+index 0 1 i i i i 0 0
  362. // Byte 2 = EffectID (7 bits) 0 E E E E E E E
  363. //
  364. // *** ---------------------------------------------------------------------***
  365. HRESULT CMD_SetIndex(
  366. IN int nIndex,
  367. IN DNHANDLE DnloadID)
  368. {
  369. HRESULT hRet;
  370. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  371. // Check for valid Effect
  372. if (SYSTEM_EFFECT_ID != DnloadID)
  373. {
  374. CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
  375. assert(pMidiEffect);
  376. if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
  377. }
  378. assert((nIndex <= MAX_INDEX) && (nIndex >= 0));
  379. if ((nIndex < 0) || (nIndex > MAX_INDEX)) return (SFERR_INVALID_PARAM);
  380. BYTE cByte1;
  381. cByte1 = SET_INDEX | (BYTE) (nIndex << 2);
  382. hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD, cByte1, (BYTE) DnloadID);
  383. if (SUCCESS != hRet)
  384. return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
  385. DRIVER_ERROR_MIDI_OUTPUT));
  386. // Note: SetIndex used to not require ACK/NACK
  387. ACKNACK AckNack = {sizeof(ACKNACK)};
  388. // hRet = g_pJoltMidi->GetAckNackData(SHORT_MSG_TIMEOUT, &AckNack);
  389. hRet = g_pJoltMidi->GetAckNackData(FALSE, &AckNack, REGBITS_SETINDEX);
  390. // :
  391. if (SUCCESS != hRet)
  392. return (SFERR_DRIVER_ERROR);
  393. if (ACK != AckNack.dwAckNack)
  394. return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
  395. return (hRet);
  396. }
  397. // *** ---------------------------------------------------------------------***
  398. // Function: CMD_ModifyParam
  399. // Purpose: Modifies an Effect parameter
  400. // Parameters:
  401. // IN WORD dwNewParam - 14 bit (signed) parameter value
  402. //
  403. // Returns: SUCCESS if successful command sent, else
  404. // SFERR_INVALID_OBJECT
  405. // SFERR_NO_SUPPORT
  406. // SFERR_INVALID_PARAM
  407. // Algorithm:
  408. //
  409. // Comments:
  410. // Byte 0 = MODIFY_CMD + Channel #
  411. // D7 D6 D5 D4 D3 D2 D1 D0
  412. // -- -- -- -- -- -- -- --
  413. // Byte 1 = Low 7 bits data 0 v v v v v v v
  414. // Byte 2 = High 7 bits data 0 v v v v v v v
  415. //
  416. // *** ---------------------------------------------------------------------***
  417. HRESULT CMD_ModifyParam(
  418. IN WORD wNewParam)
  419. {
  420. HRESULT hRet;
  421. BYTE cByte1, cByte2;
  422. cByte1 = wNewParam & 0x7f;
  423. cByte2 = (BYTE) ((wNewParam >> 7) & 0x7f);
  424. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  425. hRet = g_pJoltMidi->MidiSendShortMsg(MODIFY_CMD, cByte1, cByte2);
  426. if (SUCCESS != hRet)
  427. return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
  428. DRIVER_ERROR_MIDI_OUTPUT));
  429. // Note: ModifyParam used to not require an ACK/NACK
  430. ACKNACK AckNack = {sizeof(ACKNACK)};
  431. // hRet = g_pJoltMidi->GetAckNackData(SHORT_MSG_TIMEOUT, &AckNack);
  432. hRet = g_pJoltMidi->GetAckNackData(FALSE, &AckNack, REGBITS_MODIFYPARAM);
  433. // :
  434. if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
  435. if (ACK != AckNack.dwAckNack)
  436. return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
  437. return (hRet);
  438. }
  439. // *** ---------------------------------------------------------------------***
  440. // Function: CMD_ModifyParamByIndex
  441. // Purpose: Modifies an Effect parameter, given an Index
  442. // Parameters:
  443. // IN int nIndex - Index 0 to 15
  444. // IN DNHANDLE DnloadID - Download ID
  445. // IN WORD dwNewParam - 14 bit (signed) parameter value
  446. //
  447. // Returns: SUCCESS if successful command sent, else
  448. // SFERR_NO_SUPPORT
  449. // SFERR_INVALID_PARAM
  450. // Algorithm:
  451. //
  452. // Comments:
  453. // Assumes DnloadID is already valid
  454. // Calls SetIndex followed by ModifyParam
  455. //
  456. // *** ---------------------------------------------------------------------***
  457. HRESULT CMD_ModifyParamByIndex(
  458. IN int nIndex,
  459. IN DNHANDLE DnloadID,
  460. IN WORD wNewParam)
  461. {
  462. HRESULT hRet;
  463. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  464. if ((nIndex < 0) || (nIndex > MAX_INDEX))
  465. return (SFERR_INVALID_PARAM);
  466. int i;
  467. for (i=0; i<MAX_RETRY_COUNT; i++)
  468. {
  469. hRet = CMD_SetIndex(nIndex,DnloadID);
  470. Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwSetIndexDelay);
  471. if (SUCCESS == hRet) break;
  472. #ifdef _DEBUG
  473. OutputDebugString("CMD_SetIndex Failed. Retrying again\n");
  474. #endif
  475. }
  476. if (SUCCESS != hRet)
  477. return (hRet);
  478. else
  479. {
  480. for (i=0; i<MAX_RETRY_COUNT; i++)
  481. {
  482. hRet = CMD_ModifyParam(wNewParam);
  483. Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwModifyParamDelay);
  484. if (SUCCESS == hRet) break;
  485. #ifdef _DEBUG
  486. OutputDebugString("CMD_SetIndex Failed. Retrying again\n");
  487. #endif
  488. }
  489. }
  490. return (hRet);
  491. }
  492. //
  493. // --- SYSTEM_CMDs
  494. //
  495. // *** ---------------------------------------------------------------------***
  496. // Function: CMD_SetDeviceState
  497. // Purpose: Sets the FF device State
  498. // Parameters:
  499. // ULONG ulMode
  500. //
  501. // Returns: SUCCESS - if successful, else
  502. // Device error code
  503. //
  504. // Algorithm:
  505. // Comments:
  506. // ulMode:
  507. // DEV_SHUTDOWN 1L // All Effects destroyed, Motors disabled
  508. // DEV_FORCE_ON 2L // Motors enabled. "Un-Mute"
  509. // DEV_FORCE_OFF 3L // Motors disabled. "Mute"
  510. // DEV_CONTINUE 4L // All "Paused" Effects are allow to continue
  511. // DEV_PAUSE 5L // All Effects are "Paused"
  512. // DEV_STOP_ALL 6L // Stops all Effects.
  513. //
  514. // Byte 0 = SYSTEM_CMD + Channel #
  515. // D7 D6 D5 D4 D3 D2 D1 D0
  516. // -- -- -- -- -- -- -- --
  517. // Byte 1 = Set Device Type 0 0 0 0 0 0 0 1
  518. // Byte 2 = not used, set to 0 0 0 0 0 0 0 0 0
  519. //
  520. //
  521. // *** ---------------------------------------------------------------------***
  522. HRESULT CMD_SetDeviceState(
  523. IN ULONG ulMode)
  524. {
  525. HRESULT hRet = SUCCESS;
  526. assert(g_pJoltMidi);
  527. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  528. BYTE bChannel = g_pJoltMidi->MidiChannelOf();
  529. MIDIINFO *pMidiOutInfo = g_pJoltMidi->MidiOutInfoOf();
  530. switch (ulMode)
  531. {
  532. case DEV_RESET:
  533. hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_SHUTDOWN, 0);
  534. break;
  535. case DEV_FORCE_ON:
  536. hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_FORCE_ON, 0);
  537. break;
  538. case DEV_FORCE_OFF:
  539. hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_FORCE_OFF, 0);
  540. break;
  541. case DEV_CONTINUE:
  542. hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_CONTINUE, 0);
  543. break;
  544. case DEV_PAUSE:
  545. hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_PAUSE, 0);
  546. break;
  547. case DEV_STOP_ALL:
  548. hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_STOP_ALL, 0);
  549. break;
  550. case SWDEV_KILL_MIDI:
  551. hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_KILL_MIDI, 0);
  552. break;
  553. default:
  554. return SFERR_INVALID_PARAM;
  555. }
  556. if (SUCCESS != hRet)
  557. return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
  558. DRIVER_ERROR_MIDI_OUTPUT));
  559. // Wait for ACK or NACK
  560. ACKNACK AckNack = {sizeof(ACKNACK)};
  561. if (DEV_RESET == ulMode)
  562. { // Wait for Jolt to complete the cycle
  563. Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwHWResetDelay);
  564. hRet = g_pJoltMidi->GetAckNackData(ACKNACK_TIMEOUT, &AckNack, REGBITS_SETDEVICESTATE);
  565. }
  566. else
  567. {
  568. Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwDigitalOverdrivePrechargeCmdDelay);
  569. hRet = g_pJoltMidi->GetAckNackData(FALSE, &AckNack, REGBITS_SETDEVICESTATE);
  570. }
  571. // :
  572. if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
  573. if (ACK != AckNack.dwAckNack)
  574. return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
  575. // Special case Shutdown
  576. if (DEV_RESET == ulMode)
  577. {
  578. // Delete all Effects except built-in RTC Spring and FRICTION cancel.
  579. g_pJoltMidi->DeleteDownloadedEffects();
  580. }
  581. Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwPostSetDeviceStateDelay);
  582. return (hRet);
  583. }
  584. // *** ---------------------------------------------------------------------***
  585. // Function: CMD_GetEffectStatus
  586. // Purpose: Returns Status of Effect ID
  587. // Parameters:
  588. // DNHANDLE DnloadID - Effect ID
  589. // PBYTE pStatusCode - Status Code
  590. //
  591. // Returns: SUCCESS - if successful, else
  592. // a device Error code
  593. // *pStatusCode set to - SWDEV_STS_EFFECT_STOPPED
  594. // SWDEV_STS_EFFECT_RUNNING
  595. //
  596. // Algorithm:
  597. //
  598. // Comments:
  599. // Byte 0 = STATUS_CMD + Channel #
  600. // D7 D6 D5 D4 D3 D2 D1 D0
  601. // -- -- -- -- -- -- -- --
  602. // Byte 1 = Effect ID 0 0 0 0 0 1 0 0
  603. // Byte 2 = not used, set to 0 0 0 0 0 0 0 0 0
  604. //
  605. // *** ---------------------------------------------------------------------***
  606. HRESULT CMD_GetEffectStatus(DNHANDLE DnloadID, PBYTE pStatusCode)
  607. {
  608. HRESULT hRet;
  609. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  610. hRet = g_pJoltMidi->MidiSendShortMsg(STATUS_CMD, (BYTE) DnloadID, 0);
  611. if (SUCCESS != hRet)
  612. return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
  613. DRIVER_ERROR_MIDI_OUTPUT));
  614. Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwGetEffectStatusDelay);// enough for about 3 bytes of data being sent at 330us/byte
  615. DWORD dwIn;
  616. hRet = g_pDriverCommunicator->GetStatusGateData(dwIn);
  617. if (SUCCESS != hRet) return (hRet);
  618. if ((g_ForceFeedbackDevice.GetDriverVersionMajor() != 1) && (dwIn & RUNNING_MASK_200))
  619. {
  620. *pStatusCode = SWDEV_STS_EFFECT_RUNNING;
  621. }
  622. else
  623. {
  624. *pStatusCode = SWDEV_STS_EFFECT_STOPPED;
  625. }
  626. return (hRet);
  627. }
  628. //
  629. // --- System Exclusive Commands
  630. //
  631. // System Exclusive Command:MIDI_ASSIGN
  632. //
  633. // *** ---------------------------------------------------------------------***
  634. // Function: CMD_MIDI_Assign
  635. // Purpose: Inits JOLT MIDI channel
  636. // Parameters: BYTE bMidiChannel - Channel to assign
  637. //
  638. // Returns: SUCCESS or Error code
  639. //
  640. //
  641. // Algorithm:
  642. //
  643. // Comments: SYS_EX type command
  644. //
  645. // Body D7 D6 D5 D4 D3 D2 D1 D0
  646. // ------ -- -- -- -- -- -- -- --
  647. // Byte 0 = MIDI_ASSIGN 0 0 0 1 0 0 0 0
  648. // Byte 1 = channel#(0-15) e.g. 5 0 0 0 0 0 1 0 1
  649. // Byte 2 = not used, set to 0 0 0 0 0 0 0 0 0
  650. //
  651. // *** ---------------------------------------------------------------------***
  652. HRESULT CMD_MIDI_Assign(
  653. IN BYTE bMidiChannel)
  654. {
  655. HRESULT hRet;
  656. PMIDI_ASSIGN_SYS_EX lpData;
  657. CMidiAssign *pMidiAssign;
  658. assert((bMidiChannel > 0) && (bMidiChannel < MAX_MIDI_CHANNEL));
  659. pMidiAssign = new CMidiAssign;
  660. assert(pMidiAssign);
  661. if (!pMidiAssign) return (SFERR_DRIVER_ERROR);
  662. pMidiAssign->SetMidiAssignChannel(bMidiChannel);
  663. lpData = (PMIDI_ASSIGN_SYS_EX) pMidiAssign->GenerateSysExPacket();
  664. assert(lpData);
  665. if(!lpData) return (SFERR_DRIVER_ERROR);
  666. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  667. // Prepare the buffer for SysEx output
  668. g_pJoltMidi->MidiAssignBuffer((LPSTR) lpData,
  669. (DWORD) sizeof(MIDI_ASSIGN_SYS_EX), TRUE);
  670. // Send the message and Wait for the ACK
  671. hRet = g_pJoltMidi->MidiSendLongMsg();
  672. if (SUCCESS == hRet)
  673. {
  674. ACKNACK AckNack = {sizeof(ACKNACK)};
  675. // Wait for ACK. Note: WinMM has callback Event notification
  676. // while Backdoor and serial does not.
  677. if (COMM_WINMM == g_pJoltMidi->COMMInterfaceOf())
  678. {
  679. hRet = g_pJoltMidi->GetAckNackData(ACKNACK_TIMEOUT, &AckNack, REGBITS_DEVICEINIT);
  680. }
  681. else
  682. hRet = g_pJoltMidi->GetAckNackData(FALSE, &AckNack, REGBITS_DEVICEINIT);
  683. // :
  684. if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
  685. if (ACK != AckNack.dwAckNack)
  686. hRet = g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode);
  687. }
  688. else
  689. hRet = SFERR_DRIVER_ERROR;
  690. // Release the Midi buffers and delete the MIDI sys_ex object
  691. g_pJoltMidi->MidiAssignBuffer((LPSTR) lpData, 0, FALSE);
  692. delete pMidiAssign;
  693. return (hRet);
  694. }
  695. //
  696. // System Exclusive Command:DNLOAD_DATA
  697. //
  698. /****************************************************************************
  699. FUNCTION: CMD_Download_BE_XXX
  700. PARAMETERS: PEFFECT pEffect - Ptr to a EFFECT data structure
  701. PENVELOPE pEnvelope - Ptr to an ENVELOPE data structure
  702. PBE_XXX pBE_XXX - Ptr to a BE_XXX data structure
  703. PDNHANDLE pDnloadID - Ptr to a HANDLE storage
  704. DWORD dwFlags - dwFlags from Kernel
  705. RETURNS: SUCCESS or ERROR code
  706. COMMENTS: Downloads BE_XXX type Effect params to the device
  707. Uses SysEx prototype and ModifyParam methods
  708. Note: Normally pEnvelope = NULL
  709. ****************************************************************************/
  710. HRESULT CMD_Download_BE_XXX(
  711. IN PEFFECT pEffect,
  712. IN PENVELOPE pEnvelope,
  713. IN PBE_XXX pBE_XXX,
  714. IN OUT PDNHANDLE pDnloadID,
  715. IN DWORD dwFlags)
  716. {
  717. HRESULT hRet = SUCCESS;
  718. PBEHAVIORAL_SYS_EX lpData;
  719. CMidiBehavioral *pMidiBehavioral;
  720. BOOL fXConstantChanged=FALSE;
  721. BOOL fYConstantChanged=FALSE;
  722. BOOL fParam3Changed=FALSE;
  723. BOOL fParam4Changed=FALSE;
  724. assert(pEffect && pBE_XXX && pDnloadID);
  725. if ((NULL == pEffect) || (NULL == pBE_XXX) || (NULL == pDnloadID))
  726. return (SFERR_INVALID_PARAM);
  727. DNHANDLE DnloadID =*pDnloadID;
  728. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  729. // scale the constants using the fudge factor
  730. PFIRMWARE_PARAMS pFirmwareParams = g_pJoltMidi->FirmwareParamsPtrOf();
  731. switch(pEffect->m_SubType)
  732. {
  733. case BE_INERTIA:
  734. case BE_INERTIA_2D:
  735. pBE_XXX->m_XConstant = (((int)pBE_XXX->m_XConstant)*((int)pFirmwareParams->dwScaleMx))/((int)100);
  736. pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleMy))/((int)100);
  737. break;
  738. case BE_SPRING:
  739. case BE_SPRING_2D:
  740. pBE_XXX->m_XConstant = (((int)pBE_XXX->m_XConstant)*((int)pFirmwareParams->dwScaleKx))/((int)100);
  741. pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleKy))/((int)100);
  742. break;
  743. case BE_DAMPER:
  744. case BE_DAMPER_2D:
  745. pBE_XXX->m_XConstant = (((int)pBE_XXX->m_XConstant)*((int)pFirmwareParams->dwScaleBx))/((int)100);
  746. pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleBy))/((int)100);
  747. break;
  748. case BE_FRICTION:
  749. case BE_FRICTION_2D:
  750. pBE_XXX->m_XConstant = (((int)pBE_XXX->m_XConstant)*((int)pFirmwareParams->dwScaleFx))/((int)100);
  751. pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleFy))/((int)100);
  752. break;
  753. case BE_WALL:
  754. pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleW))/((int)100);
  755. break;
  756. default:
  757. // do not scale
  758. break;
  759. }
  760. // If Create New, then create a new object, using SysEx
  761. // else, update the existing Effect object, using ModifyParam
  762. if (NULL == DnloadID) // New, Make a new object, use SysEx
  763. {
  764. if ((BE_FRICTION == pEffect->m_SubType) || (BE_FRICTION_2D == pEffect->m_SubType))
  765. {
  766. pMidiBehavioral = new CMidiFriction(pEffect, pEnvelope, pBE_XXX);
  767. assert(pMidiBehavioral);
  768. }
  769. else // Wall
  770. if (BE_WALL == pEffect->m_SubType)
  771. {
  772. pMidiBehavioral = new CMidiWall(pEffect, pEnvelope, pBE_XXX);
  773. assert(pMidiBehavioral);
  774. }
  775. // BE_SPRINGxx, BE_DAMPERxx, BE_INERTIAxx
  776. else
  777. {
  778. pMidiBehavioral = new CMidiBehavioral(pEffect, pEnvelope, pBE_XXX);
  779. assert(pMidiBehavioral);
  780. }
  781. if (NULL == pMidiBehavioral) return (SFERR_INVALID_OBJECT);
  782. // Generate Sys_Ex packet then prepare for output
  783. lpData = (PBEHAVIORAL_SYS_EX) pMidiBehavioral->GenerateSysExPacket();
  784. assert(lpData);
  785. if (!lpData) return (SFERR_DRIVER_ERROR);
  786. // Store the PrimaryBuffer ptr to CMidiEffect::m_pBuffer;
  787. pMidiBehavioral->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
  788. hRet = pMidiBehavioral->SendPacket(pDnloadID, pMidiBehavioral->MidiBufferSizeOf());
  789. if (SUCCESS != hRet) // Create NEW, Failure
  790. {
  791. delete pMidiBehavioral;
  792. }
  793. }
  794. else // Modify existing
  795. {
  796. pMidiBehavioral = (CMidiBehavioral *) g_pJoltMidi->GetEffectByID(*pDnloadID);
  797. assert(pMidiBehavioral);
  798. if (NULL == pMidiBehavioral) return (SFERR_INVALID_OBJECT);
  799. // Check if Type specific params have changed.
  800. if (BE_WALL == pEffect->m_SubType)
  801. {
  802. if ((pBE_XXX->m_XConstant) != pMidiBehavioral->XConstantOf())
  803. fXConstantChanged=TRUE; // Wall Type
  804. if ((pBE_XXX->m_YConstant) != pMidiBehavioral->YConstantOf())
  805. fYConstantChanged=TRUE; // Wall Constant
  806. if ((pBE_XXX->m_Param3) != pMidiBehavioral->Param3Of())
  807. fParam3Changed=TRUE; // Wall Angle
  808. if ((pBE_XXX->m_Param4) != pMidiBehavioral->Param4Of())
  809. fParam4Changed=TRUE; // Wall Distance
  810. }
  811. else
  812. {
  813. if ((pBE_XXX->m_XConstant) != pMidiBehavioral->XConstantOf())
  814. fXConstantChanged=TRUE;
  815. if ((pBE_XXX->m_YConstant) != pMidiBehavioral->YConstantOf())
  816. fYConstantChanged=TRUE;
  817. if ((BE_FRICTION != pEffect->m_SubType) && (BE_FRICTION_2D != pEffect->m_SubType))
  818. {
  819. if ((pBE_XXX->m_Param3) != pMidiBehavioral->Param3Of())
  820. fParam3Changed=TRUE;
  821. if ((pBE_XXX->m_Param4) != pMidiBehavioral->Param4Of())
  822. fParam4Changed=TRUE;
  823. }
  824. }
  825. // Fill in the common Effect and Behavioral specific parameters
  826. // Only update Duration and Button Play as common effect parameters
  827. // Double check if DURATION and TRIGGERBUTTON changed, to speed operation
  828. DWORD dwTempFlags = 0;
  829. if (pEffect->m_Duration != pMidiBehavioral->DurationOf())
  830. dwTempFlags = dwTempFlags | DIEP_DURATION;
  831. if (pEffect->m_ButtonPlayMask != pMidiBehavioral->ButtonPlayMaskOf())
  832. dwTempFlags = dwTempFlags | DIEP_TRIGGERBUTTON;
  833. pMidiBehavioral->SetEffectParams(pEffect, pBE_XXX);
  834. hRet = ModifyEffectParams(DnloadID, pEffect, dwTempFlags);
  835. if (SUCCESS!=hRet) return hRet;
  836. if (BE_WALL == pEffect->m_SubType)
  837. {
  838. // Generate Sys_Ex packet then prepare for output
  839. lpData = (PBEHAVIORAL_SYS_EX) pMidiBehavioral->GenerateSysExPacket();
  840. assert(lpData);
  841. if (!lpData) return (SFERR_DRIVER_ERROR);
  842. // Store the PrimaryBuffer ptr to CMidiEffect::m_pBuffer;
  843. pMidiBehavioral->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
  844. hRet = pMidiBehavioral->SendPacket(pDnloadID, pMidiBehavioral->MidiBufferSizeOf());
  845. }
  846. else // Use ModifyParameter
  847. {
  848. // Type Specific Params
  849. if (dwFlags & DIEP_TYPESPECIFICPARAMS)
  850. {
  851. if (fYConstantChanged) // KY/BY/MY/FY
  852. {
  853. hRet = CMD_ModifyParamByIndex(INDEX3, DnloadID, (SHORT) (pBE_XXX->m_YConstant * MAX_SCALE));
  854. if (SUCCESS!=hRet) return hRet;
  855. }
  856. if(fXConstantChanged) // KX/BX/MX/FX
  857. {
  858. hRet = CMD_ModifyParamByIndex(INDEX2, DnloadID, (SHORT) (pBE_XXX->m_XConstant * MAX_SCALE));
  859. if (SUCCESS!=hRet) return hRet;
  860. }
  861. if (fParam4Changed) // CY/VY/AY
  862. {
  863. hRet = CMD_ModifyParamByIndex(INDEX5, DnloadID, (SHORT) (pBE_XXX->m_Param4 * MAX_SCALE));
  864. if (SUCCESS!=hRet) return hRet;
  865. }
  866. if (fParam3Changed) // CX/VX/AX
  867. {
  868. hRet = CMD_ModifyParamByIndex(INDEX4, DnloadID, (SHORT) (pBE_XXX->m_Param3 * MAX_SCALE));
  869. if (SUCCESS!=hRet) return hRet;
  870. }
  871. }
  872. }
  873. }
  874. return (hRet);
  875. }
  876. /****************************************************************************
  877. FUNCTION: CMD_Download_RTCSpring
  878. PARAMETERS: PRTCSPRING_PARAM pRTCSpring - Ptr to a RTCSPRING_PARAM structure
  879. PDNHANDLE pDnloadID - Ptr to a HANDLE storage
  880. RETURNS: SUCCESS or ERROR code
  881. COMMENTS: Downloads RTCSPRING type Effect params to the device
  882. Uses SysEx prototype and ModifyParam methods
  883. ****************************************************************************/
  884. HRESULT CMD_Download_RTCSpring(
  885. IN PRTCSPRING_PARAM pRTCSpring,
  886. IN OUT PDNHANDLE pDnloadID)
  887. {
  888. HRESULT hRet = SUCCESS;
  889. CMidiRTCSpring *pMidiRTCSpring;
  890. assert(pRTCSpring && pDnloadID);
  891. if ((NULL == pRTCSpring) || (NULL == pDnloadID))
  892. return (SFERR_INVALID_PARAM);
  893. DNHANDLE DnloadID = SYSTEM_RTCSPRING_ID;
  894. *pDnloadID = DnloadID;
  895. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  896. // Note: RTC Spring is a permanent System Effect ID 2
  897. pMidiRTCSpring = (CMidiRTCSpring *) g_pJoltMidi->GetEffectByID(DnloadID);
  898. assert(pMidiRTCSpring);
  899. if (NULL == pMidiRTCSpring) return (SFERR_INVALID_OBJECT);
  900. // Check if Type specific params have changed, if so, Modify it
  901. if ((pRTCSpring->m_XKConstant) != pMidiRTCSpring->XKConstantOf())
  902. {
  903. if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX0, DnloadID,
  904. (SHORT) (pRTCSpring->m_XKConstant * MAX_SCALE))))
  905. return hRet;
  906. }
  907. if ((pRTCSpring->m_YKConstant) != pMidiRTCSpring->YKConstantOf())
  908. {
  909. if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX1, DnloadID,
  910. (SHORT) (pRTCSpring->m_YKConstant * MAX_SCALE))))
  911. return hRet;
  912. }
  913. if ((pRTCSpring->m_XAxisCenter) != pMidiRTCSpring->XAxisCenterOf())
  914. {
  915. if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX2, DnloadID,
  916. (SHORT) (pRTCSpring->m_XAxisCenter * MAX_SCALE))))
  917. return hRet;
  918. }
  919. if ((pRTCSpring->m_YAxisCenter) != pMidiRTCSpring->YAxisCenterOf())
  920. {
  921. if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX3, DnloadID,
  922. (SHORT) (pRTCSpring->m_YAxisCenter * MAX_SCALE))))
  923. return hRet;
  924. }
  925. if ((pRTCSpring->m_XSaturation) != pMidiRTCSpring->XSaturationOf())
  926. {
  927. if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX4, DnloadID,
  928. (SHORT) (pRTCSpring->m_XSaturation * MAX_SCALE))))
  929. return hRet;
  930. }
  931. if ((pRTCSpring->m_YSaturation) != pMidiRTCSpring->YSaturationOf())
  932. {
  933. if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX5, DnloadID,
  934. (SHORT) (pRTCSpring->m_YSaturation * MAX_SCALE))))
  935. return hRet;
  936. }
  937. if ((pRTCSpring->m_XDeadBand) != pMidiRTCSpring->XDeadBandOf())
  938. {
  939. if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX6, DnloadID,
  940. (SHORT) (pRTCSpring->m_XDeadBand * MAX_SCALE))))
  941. return hRet;
  942. }
  943. if ((pRTCSpring->m_YDeadBand) != pMidiRTCSpring->YDeadBandOf())
  944. {
  945. hRet=CMD_ModifyParamByIndex(INDEX7, DnloadID,
  946. (SHORT) (pRTCSpring->m_YDeadBand * MAX_SCALE));
  947. }
  948. pMidiRTCSpring->SetEffectParams(pRTCSpring);
  949. return (hRet);
  950. }
  951. /****************************************************************************
  952. FUNCTION: CMD_Dnload_NOP_DELAY
  953. PARAMETERS: ULONG ulDuration - Duration delay
  954. RETURNS: SUCCESS or ERROR code
  955. COMMENTS: Downloads NOP_DELAY Effect params to the device
  956. Uses SysEx prototype
  957. ****************************************************************************/
  958. HRESULT CMD_Download_NOP_DELAY(
  959. IN ULONG ulDuration,
  960. IN PEFFECT pEffect,
  961. IN OUT PDNHANDLE pDnloadID)
  962. {
  963. HRESULT hRet = SUCCESS;
  964. PNOP_SYS_EX lpData;
  965. CMidiDelay *pMidiDelay;
  966. BOOL fCreateNew = FALSE;
  967. assert(pDnloadID);
  968. assert(0 != ulDuration);
  969. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  970. // If Create New, then create a new object,
  971. // else, update the existing Effect object.
  972. if (NULL == *pDnloadID) fCreateNew = TRUE;
  973. if (fCreateNew) // New, Make a new object
  974. {
  975. pMidiDelay = new CMidiDelay(pEffect);
  976. assert(pMidiDelay);
  977. if (NULL == pMidiDelay) return (SFERR_INVALID_OBJECT);
  978. pMidiDelay->SetEffectID(NEW_EFFECT_ID);
  979. }
  980. else // Modify existing
  981. {
  982. pMidiDelay = (CMidiDelay *) g_pJoltMidi->GetEffectByID(*pDnloadID);
  983. assert(pMidiDelay);
  984. if (NULL == pMidiDelay) return (SFERR_INVALID_OBJECT);
  985. pMidiDelay->SetEffectID((BYTE) *pDnloadID);
  986. }
  987. pMidiDelay->SetDuration(ulDuration);
  988. // Generate Sys_Ex packet then prepare for output
  989. lpData = (PNOP_SYS_EX) pMidiDelay->GenerateSysExPacket();
  990. assert(lpData);
  991. if (!lpData) return (SFERR_DRIVER_ERROR);
  992. pMidiDelay->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
  993. hRet = pMidiDelay->SendPacket(pDnloadID, sizeof(NOP_SYS_EX));
  994. if (FAILED(hRet) && fCreateNew) // Create NEW, Failure
  995. {
  996. delete pMidiDelay;
  997. }
  998. return (hRet);
  999. }
  1000. /****************************************************************************
  1001. FUNCTION: CMD_Dnload_UD_Waveform
  1002. PARAMETERS: ULONG ulDuration - what fun!
  1003. PEFFECT pEffect - Ptr to an EFFECT structure
  1004. ULONG ulNumVectors- Number of vectors in the array
  1005. PLONG pUD_Array - Ptr to a UD_WAVEFORM byte array
  1006. ULONG ulAction - Mode for download
  1007. PDNHANDLE pDnloadID - Ptr to a DNHANDLE store
  1008. DWORD dwFlags - dwFlags from Kernel
  1009. RETURNS: SUCCESS or ERROR code
  1010. COMMENTS: Downloads UD_WAVEFORM Effect params to the device
  1011. Uses SysEx prototype
  1012. ****************************************************************************/
  1013. HRESULT CMD_Download_UD_Waveform(
  1014. IN ULONG ulDuration,
  1015. IN PEFFECT pEffect,
  1016. IN ULONG ulNumVectors,
  1017. IN PLONG pUD_Array,
  1018. IN ULONG ulAction,
  1019. IN OUT PDNHANDLE pDnloadID,
  1020. IN DWORD dwFlags)
  1021. {
  1022. HRESULT hRet = SUCCESS;
  1023. PUD_WAVEFORM_SYS_EX lpData;
  1024. CMidiUD_Waveform *pMidiUD_Waveform;
  1025. assert(pEffect && pUD_Array);
  1026. assert(ulNumVectors > 0);
  1027. assert(pDnloadID);
  1028. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  1029. // If Create New, then create a new object,
  1030. // else, update the existing Effect object.
  1031. DNHANDLE DnloadID = *pDnloadID;
  1032. if (NULL == DnloadID) // New, Make a new object
  1033. {
  1034. pMidiUD_Waveform = new CMidiUD_Waveform(pEffect, ulNumVectors, pUD_Array);
  1035. assert(pMidiUD_Waveform);
  1036. if (NULL == pMidiUD_Waveform) return (SFERR_INVALID_OBJECT);
  1037. if (0 == pMidiUD_Waveform->MidiBufferSizeOf())
  1038. {
  1039. delete pMidiUD_Waveform;
  1040. return (SFERR_INVALID_PARAM);
  1041. }
  1042. // Generate Sys_Ex packet then prepare for output
  1043. lpData = (PUD_WAVEFORM_SYS_EX) pMidiUD_Waveform->GenerateSysExPacket();
  1044. assert(lpData);
  1045. if (!lpData) return (SFERR_DRIVER_ERROR);
  1046. // Store the PrimaryBuffer ptr to CMidiEffect::m_pBuffer;
  1047. pMidiUD_Waveform->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
  1048. hRet = pMidiUD_Waveform->SendPacket(pDnloadID, pMidiUD_Waveform->MidiBufferSizeOf());
  1049. if (SUCCESS != hRet) // Create NEW, Failure
  1050. {
  1051. delete pMidiUD_Waveform;
  1052. }
  1053. }
  1054. else // Modify existing
  1055. {
  1056. pMidiUD_Waveform = (CMidiUD_Waveform *) g_pJoltMidi->GetEffectByID(DnloadID);
  1057. assert(pMidiUD_Waveform);
  1058. if (NULL == pMidiUD_Waveform) return (SFERR_INVALID_OBJECT);
  1059. // fix the output rate (waveform is compressed)
  1060. pEffect->m_ForceOutputRate = pEffect->m_ForceOutputRate*pMidiUD_Waveform->ForceOutRateOf()/pMidiUD_Waveform->OriginalEffectParamOf()->m_ForceOutputRate;
  1061. // Modify EFFECT, and ENVELOPE params
  1062. hRet = ModifyEffectParams(DnloadID, pEffect, dwFlags);
  1063. if (SUCCESS!=hRet) return hRet;
  1064. }
  1065. return (hRet);
  1066. }
  1067. /****************************************************************************
  1068. FUNCTION: CMD_Dnload_SYNTH
  1069. PARAMETERS: PSYNTH pSynth - Ptr to a SYNTH data structure
  1070. PDNHANDLE pDnloadID - Ptr to a HANDLE storage
  1071. RETURNS: SUCCESS or ERROR code
  1072. COMMENTS: Downloads SE_xxx Effect params to the device
  1073. Uses SysEx prototype
  1074. Algorithm:
  1075. The following dwFlags may be sent by the kernel
  1076. #define DIEP_ALLPARAMS 0x000000FF - All fields valid
  1077. #define DIEP_AXES 0x00000020 - cAxes and rgdwAxes
  1078. #define DIEP_DIRECTION 0x00000040 - cAxes and rglDirection
  1079. #define DIEP_DURATION 0x00000001 - dwDuration
  1080. #define DIEP_ENVELOPE 0x00000080 - lpEnvelope
  1081. #define DIEP_GAIN 0x00000004 - dwGain
  1082. #define DIEP_NODOWNLOAD 0x80000000 - suppress auto - download
  1083. #define DIEP_SAMPLEPERIOD 0x00000002 - dwSamplePeriod
  1084. #define DIEP_TRIGGERBUTTON 0x00000008 - dwTriggerButton
  1085. #define DIEP_TRIGGERREPEATINTERVAL 0x00000010 - dwTriggerRepeatInterval
  1086. #define DIEP_TYPESPECIFICPARAMS 0x00000100 - cbTypeSpecificParams
  1087. and lpTypeSpecificParams
  1088. Jolt has two options for downloading - Full SysEx or Modify Parameter
  1089. Pass the dwFlags to each CMD_xxx function and let the MIDI function
  1090. determine whether to use SysEx or Modify Parameter.
  1091. ****************************************************************************/
  1092. HRESULT CMD_Download_SYNTH(
  1093. IN PEFFECT pEffect,
  1094. IN PENVELOPE pEnvelope,
  1095. IN PSE_PARAM pSE_Param,
  1096. IN ULONG ulAction,
  1097. IN OUT PDNHANDLE pDnloadID,
  1098. IN DWORD dwFlags)
  1099. {
  1100. HRESULT hRet = SUCCESS;
  1101. PSE_WAVEFORM_SYS_EX lpData;
  1102. CMidiSynthesized *pMidiSynthesized;
  1103. BOOL fFreqChanged = FALSE;
  1104. BOOL fMaxAmpChanged = FALSE;
  1105. BOOL fMinAmpChanged = FALSE;
  1106. DNHANDLE DnloadID =*pDnloadID;
  1107. assert(pEffect && pEnvelope && pSE_Param && pDnloadID);
  1108. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  1109. // If Create New, then create a new object, and use SysEx method
  1110. // else, update the existing Effect object. using ModifyParam method
  1111. if (NULL == DnloadID) // New, Make a new object
  1112. {
  1113. pMidiSynthesized = new CMidiSynthesized(pEffect, pEnvelope, pSE_Param);
  1114. assert(pMidiSynthesized);
  1115. if (NULL == pMidiSynthesized) return (SFERR_DRIVER_ERROR);
  1116. // Generate Sys_Ex packet then prepare for output
  1117. lpData = (PSE_WAVEFORM_SYS_EX) pMidiSynthesized->GenerateSysExPacket();
  1118. assert(lpData);
  1119. if (!lpData) return (SFERR_DRIVER_ERROR);
  1120. pMidiSynthesized->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
  1121. hRet = pMidiSynthesized->SendPacket(pDnloadID, sizeof(SE_WAVEFORM_SYS_EX));
  1122. if (SUCCESS != hRet) // Create NEW, Failure
  1123. {
  1124. delete pMidiSynthesized;
  1125. pMidiSynthesized = NULL;
  1126. return hRet;
  1127. }
  1128. // Hack to fix firmware bug #1138 which causes an infinite duration
  1129. // effect not to be felt on re-start once the effect has been stopped.
  1130. // The hack is to "change" the duration from infinite to infinite
  1131. ULONG ulDuration = pMidiSynthesized->DurationOf();
  1132. if(ulDuration == 0)
  1133. {
  1134. hRet = CMD_ModifyParamByIndex(INDEX0, *pDnloadID, 0);
  1135. }
  1136. return (hRet);
  1137. }
  1138. else // Modify existing
  1139. {
  1140. pMidiSynthesized = (CMidiSynthesized *) g_pJoltMidi->GetEffectByID(DnloadID);
  1141. assert(pMidiSynthesized);
  1142. if (NULL == pMidiSynthesized) return (SFERR_INVALID_OBJECT);
  1143. // check to see if they are trying to change sub-type (not allowed)
  1144. if((dwFlags & DIEP_TYPESPECIFICPARAMS) && pEffect->m_SubType != pMidiSynthesized->SubTypeOf())
  1145. return SFERR_NO_SUPPORT;
  1146. if(dwFlags & DIEP_NODOWNLOAD)
  1147. return DI_DOWNLOADSKIPPED;
  1148. // Check if Type specific params have changed.
  1149. if (pSE_Param->m_Freq != pMidiSynthesized->FreqOf())
  1150. fFreqChanged=TRUE;
  1151. if ((pSE_Param->m_MaxAmp) != pMidiSynthesized->MaxAmpOf())
  1152. fMaxAmpChanged=TRUE;
  1153. if ((pSE_Param->m_MinAmp) != pMidiSynthesized->MinAmpOf())
  1154. fMinAmpChanged=TRUE;
  1155. // Fill in the common Effect and Synth specific parameters
  1156. pMidiSynthesized->SetEffectParams(pEffect, pSE_Param, ulAction);
  1157. // // Fill in the Envelope
  1158. // pMidiSynthesized->SetEnvelope(pEnvelope);
  1159. // Modify EFFECT, ENVELOPE and Type Specific
  1160. hRet = ModifyEffectParams(DnloadID, pEffect, dwFlags);
  1161. if (SUCCESS!=hRet) return hRet;
  1162. hRet = ModifyEnvelopeParams(pMidiSynthesized, DnloadID, pEffect->m_Duration, pEnvelope, dwFlags);
  1163. if (SUCCESS!=hRet) return hRet;
  1164. // Fill in the Envelope
  1165. pMidiSynthesized->SetEnvelope(pEnvelope);
  1166. // Type Specific Params
  1167. if (dwFlags & DIEP_TYPESPECIFICPARAMS)
  1168. {
  1169. if(fFreqChanged)
  1170. {
  1171. hRet = CMD_ModifyParamByIndex(INDEX12, DnloadID, (SHORT) pSE_Param->m_Freq);
  1172. if (SUCCESS!=hRet) return hRet;
  1173. }
  1174. if (fMaxAmpChanged)
  1175. {
  1176. hRet = CMD_ModifyParamByIndex(INDEX13, DnloadID, (SHORT) (pSE_Param->m_MaxAmp * MAX_SCALE));
  1177. if (SUCCESS!=hRet) return hRet;
  1178. }
  1179. if (fMinAmpChanged)
  1180. {
  1181. hRet = CMD_ModifyParamByIndex(INDEX14, DnloadID, (SHORT) (pSE_Param->m_MinAmp * MAX_SCALE));
  1182. if (SUCCESS!=hRet) return hRet;
  1183. }
  1184. }
  1185. }
  1186. return (hRet);
  1187. }
  1188. /****************************************************************************
  1189. FUNCTION: CMD_Download_VFX
  1190. PARAMETERS: PSYNTH pSynth - Ptr to a SYNTH data structure
  1191. PDNHANDLE pDnloadID - Ptr to a HANDLE storage
  1192. RETURNS: SUCCESS or ERROR code
  1193. COMMENTS: Downloads SE_xxx Effect params to the device
  1194. Uses SysEx prototype
  1195. Algorithm:
  1196. The following dwFlags may be sent by the kernel
  1197. #define DIEP_ALLPARAMS 0x000000FF - All fields valid
  1198. #define DIEP_DIRECTION 0x00000040 - cAxes and rglDirection
  1199. #define DIEP_GAIN 0x00000004 - dwGain
  1200. #define DIEP_NODOWNLOAD 0x80000000 - suppress auto - download
  1201. #define DIEP_TRIGGERBUTTON 0x00000008 - dwTriggerButton
  1202. #define DIEP_TRIGGERREPEATINTERVAL 0x00000010 - dwTriggerRepeatInterval
  1203. #define DIEP_TYPESPECIFICPARAMS 0x00000100 - cbTypeSpecificParams
  1204. and lpTypeSpecificParams
  1205. Jolt has two options for downloading - Full SysEx or Modify Parameter
  1206. Pass the dwFlags to each CMD_xxx function and let the MIDI function
  1207. determine whether to use SysEx or Modify Parameter.
  1208. ****************************************************************************/
  1209. HRESULT CMD_Download_VFX(
  1210. IN PEFFECT pEffect,
  1211. IN PENVELOPE pEnvelope,
  1212. IN PVFX_PARAM pVFXParam,
  1213. IN ULONG ulAction,
  1214. IN OUT PDNHANDLE pDnloadID,
  1215. IN DWORD dwFlags)
  1216. {
  1217. HRESULT hRet = SUCCESS;
  1218. DNHANDLE DnloadID = *pDnloadID;
  1219. assert(pEffect && !pEnvelope && pVFXParam);
  1220. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  1221. BOOL bModify = DnloadID != 0;
  1222. if(*pDnloadID == 0)
  1223. {
  1224. // make a new object
  1225. if(pVFXParam->m_PointerType == VFX_FILENAME)
  1226. hRet = CreateEffectFromFile((LPCTSTR)pVFXParam->m_pFileNameOrBuffer, ulAction, (USHORT*)pDnloadID, dwFlags);
  1227. else if(pVFXParam->m_PointerType == VFX_BUFFER)
  1228. hRet = CreateEffectFromBuffer(pVFXParam->m_pFileNameOrBuffer, pVFXParam->m_BufferSize, ulAction, (USHORT*)pDnloadID, dwFlags);
  1229. else
  1230. hRet = SFERR_INVALID_PARAM;
  1231. if(FAILED(hRet)) return hRet;
  1232. DnloadID = *pDnloadID;
  1233. }
  1234. // modify an existing object or the effect just created
  1235. // get the effect associated with this ID
  1236. CMidiEffect* pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
  1237. assert(pMidiEffect);
  1238. if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
  1239. // change the button play mask only on a modify
  1240. if (bModify && (dwFlags & DIEP_TRIGGERBUTTON))
  1241. {
  1242. // get the button play mask
  1243. ULONG ulButtonPlayMask = pEffect->m_ButtonPlayMask;
  1244. // modify the param in the CMidiEffect
  1245. pMidiEffect->SetButtonPlaymask(ulButtonPlayMask);
  1246. // modify the param in the stick
  1247. hRet = CMD_ModifyParamByIndex(INDEX1, DnloadID, (SHORT)ulButtonPlayMask);
  1248. if (SUCCESS!=hRet) return hRet;
  1249. }
  1250. // see if it is a PL or an atomic effect
  1251. ULONG ulSubType = pMidiEffect->SubTypeOf();
  1252. BOOL bProcessList = (ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE);
  1253. // modify gain and direction
  1254. if(bProcessList)
  1255. {
  1256. // modify gain and direction for each sub-effect
  1257. // convert the pointer to CMidiProcessList
  1258. CMidiProcessList* pMidiProcessList = (CMidiProcessList*)pMidiEffect;
  1259. // get the number of sub-effects and the array
  1260. UINT ulNumEffects = pMidiProcessList->NumEffectsOf();
  1261. PBYTE pEffectArray = pMidiProcessList->EffectArrayOf();
  1262. assert(pEffectArray);
  1263. if(pEffectArray == NULL) return (SFERR_INVALID_OBJECT);
  1264. // calculate the nominal duration of the process list
  1265. ULONG ulNominalDuration = 0;
  1266. for(UINT i=0; i<ulNumEffects; i++)
  1267. {
  1268. // get the download ID of the next sub-effect
  1269. DNHANDLE SubDnloadID = pEffectArray[i];
  1270. // get the sub-effect
  1271. CMidiEffect* pMidiSubEffect = g_pJoltMidi->GetEffectByID(SubDnloadID);
  1272. assert(pMidiSubEffect);
  1273. if (NULL == pMidiSubEffect) return (SFERR_INVALID_OBJECT);
  1274. // get the original effect param
  1275. PEFFECT pOriginalEffectParam = pMidiSubEffect->OriginalEffectParamOf();
  1276. // get the original duration of this sub-effect
  1277. ULONG ulSubEffectDuration = pOriginalEffectParam->m_Duration;
  1278. //ASSERT(ulSubEffectDuration != 0);
  1279. // update the nominal duration of the overall effect to reflect this sub-effect
  1280. if(ulSubType == PL_CONCATENATE)
  1281. ulNominalDuration += ulSubEffectDuration;
  1282. else
  1283. ulNominalDuration = max(ulNominalDuration, ulSubEffectDuration);
  1284. }
  1285. // iterate throught the list of sub-effects
  1286. for(i=0; i<ulNumEffects; i++)
  1287. {
  1288. // get the download ID of the next sub-effect
  1289. DNHANDLE SubDnloadID = pEffectArray[i];
  1290. // get the sub-effect
  1291. CMidiEffect* pMidiSubEffect = g_pJoltMidi->GetEffectByID(SubDnloadID);
  1292. assert(pMidiSubEffect);
  1293. if (NULL == pMidiSubEffect) return (SFERR_INVALID_OBJECT);
  1294. // get the original effect param
  1295. PEFFECT pOriginalEffectParam = pMidiSubEffect->OriginalEffectParamOf();
  1296. // Direction? Note: No Direction modify for Behaviorals!!!!
  1297. if ((dwFlags & DIEP_DIRECTION) && (EF_BEHAVIOR != pOriginalEffectParam->m_Type))
  1298. {
  1299. // calculate the new angle
  1300. ULONG nOriginalAngle2D = pOriginalEffectParam->m_DirectionAngle2D;
  1301. ULONG nDeltaAngle2D = pEffect->m_DirectionAngle2D;
  1302. ULONG nNewAngle2D = (nOriginalAngle2D + nDeltaAngle2D)%360;
  1303. // modify the param in the midi sub-effect
  1304. pMidiSubEffect->SetDirectionAngle(nNewAngle2D);
  1305. // modify the parameter in the stick
  1306. hRet = CMD_ModifyParamByIndex(INDEX2, SubDnloadID, (SHORT)nNewAngle2D);
  1307. if (SUCCESS!=hRet) return hRet;
  1308. }
  1309. // Gain?
  1310. // Gain? Note: No Gain modify for Behaviorals!!!!
  1311. if ((dwFlags & DIEP_GAIN) && (EF_BEHAVIOR != pOriginalEffectParam->m_Type))
  1312. {
  1313. // calculate the new gain
  1314. ULONG nOriginalGain = pOriginalEffectParam->m_Gain;
  1315. ULONG nOverallGain = pEffect->m_Gain;
  1316. ULONG nNewGain = nOverallGain*nOriginalGain/100;
  1317. // modify the param in the midi effect
  1318. pMidiSubEffect->SetGain((BYTE)nNewGain);
  1319. // modify the parameter in the stick
  1320. hRet = CMD_ModifyParamByIndex(INDEX3, SubDnloadID, (SHORT) (nNewGain * MAX_SCALE));
  1321. if (SUCCESS!=hRet) return hRet;
  1322. }
  1323. if(dwFlags & DIEP_DURATION)
  1324. {
  1325. // calculate the new duration
  1326. ULONG nOriginalDuration = pOriginalEffectParam->m_Duration;
  1327. ULONG nOverallDuration = pEffect->m_Duration;
  1328. ULONG nNewDuration;
  1329. if(nOverallDuration == (ULONG)-1)
  1330. {
  1331. // default length
  1332. nNewDuration = nOriginalDuration;
  1333. }
  1334. else if(nOverallDuration == 0)
  1335. {
  1336. // infinite duration
  1337. // for a concatenated process list we make the last effect infinite, others default
  1338. // for a superimpose process list we make all effects infinite
  1339. if(ulSubType == PL_CONCATENATE)
  1340. {
  1341. if(i == ulNumEffects-1)
  1342. {
  1343. // make last effect in PL infinite
  1344. nNewDuration = 0;
  1345. }
  1346. else
  1347. {
  1348. // make other effects default
  1349. nNewDuration = nOriginalDuration;
  1350. }
  1351. }
  1352. else
  1353. {
  1354. assert(ulSubType == PL_SUPERIMPOSE);
  1355. // make effects infinite
  1356. nNewDuration = 0;
  1357. }
  1358. }
  1359. else
  1360. {
  1361. // scale the duration (at least 1mS)
  1362. nNewDuration = nOriginalDuration*nOverallDuration/ulNominalDuration;
  1363. nNewDuration = max(1, nNewDuration);
  1364. }
  1365. // modify the parameter in the midi sub-effect
  1366. pMidiSubEffect->SetDuration(nNewDuration);
  1367. // modify the parameter in the stick
  1368. if (nNewDuration != 0)
  1369. {
  1370. nNewDuration = (ULONG) ( (float) nNewDuration/TICKRATE);
  1371. if (nNewDuration <= 0)
  1372. nNewDuration = 1;
  1373. }
  1374. hRet = CMD_ModifyParamByIndex(INDEX0, SubDnloadID, (SHORT) nNewDuration);
  1375. if (SUCCESS!=hRet) return hRet;
  1376. }
  1377. }
  1378. }
  1379. else
  1380. {
  1381. // modify gain and direction for the atomic effect
  1382. // get the original effect param
  1383. PEFFECT pOriginalEffectParam = pMidiEffect->OriginalEffectParamOf();
  1384. // Direction? Note: No Direction modify for Behaviorals!!!!
  1385. if ((dwFlags & DIEP_DIRECTION) && (EF_BEHAVIOR != pOriginalEffectParam->m_Type))
  1386. {
  1387. // calculate the new angle
  1388. ULONG nOriginalAngle2D = pOriginalEffectParam->m_DirectionAngle2D;
  1389. ULONG nDeltaAngle2D = pEffect->m_DirectionAngle2D;
  1390. ULONG nNewAngle2D = (nOriginalAngle2D + nDeltaAngle2D)%360;
  1391. // modify the param in the midi effect
  1392. pMidiEffect->SetDirectionAngle(nNewAngle2D);
  1393. // modify the parameter in the stick
  1394. hRet = CMD_ModifyParamByIndex(INDEX2, DnloadID, (SHORT)nNewAngle2D);
  1395. if (SUCCESS!=hRet) return hRet;
  1396. }
  1397. // Gain?
  1398. // Gain? Note: No Gain modify for Behaviorals!!!!
  1399. if ((dwFlags & DIEP_GAIN) && (EF_BEHAVIOR != pOriginalEffectParam->m_Type))
  1400. {
  1401. // calculate the new gain
  1402. ULONG nOriginalGain = pOriginalEffectParam->m_Gain;
  1403. ULONG nOverallGain = pEffect->m_Gain;
  1404. ULONG nNewGain = nOverallGain*nOriginalGain/100;
  1405. // modify the param in the midi effect
  1406. pMidiEffect->SetGain((BYTE)nNewGain);
  1407. // modify the parameter in the stick
  1408. hRet = CMD_ModifyParamByIndex(INDEX3, DnloadID, (SHORT) (nNewGain * MAX_SCALE));
  1409. if (SUCCESS!=hRet) return hRet;
  1410. }
  1411. if(dwFlags & DIEP_DURATION)
  1412. {
  1413. // calculate the new duration
  1414. ULONG nOriginalDuration = pOriginalEffectParam->m_Duration;
  1415. ULONG nOverallDuration = pEffect->m_Duration;
  1416. ULONG nNewDuration;
  1417. if(nOverallDuration == (ULONG)-1)
  1418. {
  1419. // default length
  1420. nNewDuration = nOriginalDuration;
  1421. }
  1422. else if(nOverallDuration == 0)
  1423. {
  1424. // infinite duration -- make effect infinite
  1425. nNewDuration = 0;
  1426. }
  1427. else
  1428. {
  1429. // scale the duration (at least 1mS)
  1430. nNewDuration = nOverallDuration;
  1431. }
  1432. // modify the parameter in the midi effect
  1433. pMidiEffect->SetDuration(nNewDuration);
  1434. // modify the parameter in the stick
  1435. if (nNewDuration != 0)
  1436. {
  1437. nNewDuration = (ULONG) ( (float) nNewDuration/TICKRATE);
  1438. if (nNewDuration <= 0)
  1439. nNewDuration = 1;
  1440. }
  1441. hRet = CMD_ModifyParamByIndex(INDEX0, DnloadID, (SHORT) nNewDuration);
  1442. if (SUCCESS!=hRet) return hRet;
  1443. }
  1444. }
  1445. return hRet;
  1446. }
  1447. //
  1448. // --- System Exclusive Command:PROCESS_DATA
  1449. //
  1450. // *** ---------------------------------------------------------------------***
  1451. // Function: CMD_ProcessEffect
  1452. // Purpose: Processes the List
  1453. // IN ULONG ulButtonPlayMask
  1454. // IN OUT PDNHANDLE pDnloadID - Storage for new Download ID
  1455. // IN int nNumEffects - Number of Effect IDs in the array
  1456. // IN ULONG ulProcessMode - Processing mode
  1457. // IN PDNHANDLE pPListArray - Pointer to an array of Effect IDs
  1458. //
  1459. // Returns: SUCCESS - if successful, else
  1460. // E_INVALID_PARAM
  1461. // SFERR_NO_SUPPORT
  1462. //
  1463. // Algorithm:
  1464. //
  1465. // Comments:
  1466. // The following processing is available:
  1467. // CONCATENATE: Enew = E1 followed by E2
  1468. // SUPERIMPOSE: Enew = E1 (t1) + E2 (t1) + E1 (t2)
  1469. // + E2 (t2) + . . . E1 (tn) + E2 (tn)
  1470. //
  1471. // ulProcessMode:
  1472. // Processing mode:
  1473. // CONCATENATE - CONCATENATE
  1474. // SUPERIMPOSE - Mix or overlay
  1475. //
  1476. // pPListArray:
  1477. // The array of Effect IDs must be one more than the actual number
  1478. // of Effect IDs to use.
  1479. //
  1480. // Byte 0 = MIDI_CMD_EFFECT + Channel #
  1481. // D7 D6 D5 D4 D3 D2 D1 D0
  1482. // -- -- -- -- -- -- -- --
  1483. // Byte 1 = Low byte of Force 0
  1484. // Byte 2 = High byte of Force 0
  1485. //
  1486. // *** ---------------------------------------------------------------------***
  1487. HRESULT CMD_ProcessEffect(
  1488. IN ULONG ulButtonPlayMask,
  1489. IN OUT PDNHANDLE pDnloadID,
  1490. IN int nNumEffects,
  1491. IN ULONG ulProcessMode,
  1492. IN PDNHANDLE pPListArray,
  1493. IN ULONG ulAction)
  1494. {
  1495. HRESULT hRet = SUCCESS;
  1496. PPROCESS_LIST_SYS_EX lpData;
  1497. CMidiProcessList *pMidiProcessList;
  1498. assert(pDnloadID && pPListArray);
  1499. if ((NULL == pDnloadID) || (NULL == pPListArray))
  1500. return (SFERR_INVALID_PARAM);
  1501. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  1502. DNHANDLE DnloadID = *pDnloadID;
  1503. // If Create New, then create a new object,
  1504. // else, update the existing Effect object.
  1505. // Build the special Parameter
  1506. PLIST PList;
  1507. PList.ulNumEffects = (ULONG) nNumEffects;
  1508. PList.ulProcessMode = ulProcessMode;
  1509. PList.pEffectArray = pPListArray;
  1510. PList.ulAction = ulAction;
  1511. if (NULL == DnloadID) // New, Make a new object
  1512. {
  1513. // make sure we are not trying to create a PL within a PL
  1514. for(int i=0; i<nNumEffects; i++)
  1515. {
  1516. // get the next sub-effect
  1517. int nID = pPListArray[i];
  1518. CMidiEffect* pMidiEffect = g_pJoltMidi->GetEffectByID(DNHANDLE(nID));
  1519. if(pMidiEffect == NULL)
  1520. return SFERR_INVALID_PARAM;
  1521. // make sure it is not a process list
  1522. ULONG ulSubType = pMidiEffect->SubTypeOf();
  1523. if(ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE)
  1524. return SFERR_INVALID_PARAM;
  1525. }
  1526. // create the CMidiProcessList object
  1527. pMidiProcessList = new CMidiProcessList(ulButtonPlayMask, &PList);
  1528. assert(pMidiProcessList);
  1529. pMidiProcessList->SetEffectID(NEW_EFFECT_ID);
  1530. pMidiProcessList->SetSubType(ulProcessMode);
  1531. }
  1532. else // Modify existing
  1533. {
  1534. pMidiProcessList = (CMidiProcessList *) g_pJoltMidi->GetEffectByID(DnloadID);
  1535. assert(pMidiProcessList);
  1536. if (NULL == pMidiProcessList) return (SFERR_INVALID_OBJECT);
  1537. pMidiProcessList->SetEffectID((BYTE) DnloadID);
  1538. }
  1539. // Fill in the parameters
  1540. pMidiProcessList->SetParams(ulButtonPlayMask, &PList);
  1541. if (PLAY_FOREVER == (ulAction & PLAY_FOREVER))
  1542. pMidiProcessList->SetDuration(0);
  1543. // Generate Sys_Ex packet then prepare for output
  1544. lpData = (PPROCESS_LIST_SYS_EX) pMidiProcessList->GenerateSysExPacket();
  1545. assert(lpData);
  1546. if (!lpData) return (SFERR_DRIVER_ERROR);
  1547. int nSizeBuf = sizeof(SYS_EX_HDR) + 5 + nNumEffects + 2;
  1548. pMidiProcessList->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
  1549. hRet = pMidiProcessList->SendPacket(pDnloadID, nSizeBuf);
  1550. if (SUCCESS != hRet) // Create NEW, Failure
  1551. {
  1552. delete pMidiProcessList;
  1553. }
  1554. else
  1555. {
  1556. // workaround to FW bug #1211, modify PL type with same PL type
  1557. ULONG ulSubType;
  1558. if (PL_SUPERIMPOSE == ulProcessMode)
  1559. ulSubType = PLIST_SUPERIMPOSE;
  1560. else
  1561. ulSubType = PLIST_CONCATENATE;
  1562. hRet = CMD_ModifyParamByIndex(INDEX0, *pDnloadID, (SHORT) ulSubType);
  1563. }
  1564. return (hRet);
  1565. }
  1566. //
  1567. // --- System Exclusive Command:PROCESS_DATA
  1568. //
  1569. // *** ---------------------------------------------------------------------***
  1570. // Function: CMD_VFXProcessEffect
  1571. // Purpose: Processes the List
  1572. // IN ULONG ulButtonPlayMask
  1573. // IN OUT PDNHANDLE pDnloadID - Storage for new Download ID
  1574. // IN int nNumEffects - Number of Effect IDs in the array
  1575. // IN ULONG ulProcessMode - Processing mode
  1576. // IN PDNHANDLE pPListArray - Pointer to an array of Effect IDs
  1577. //
  1578. // Returns: SUCCESS - if successful, else
  1579. // E_INVALID_PARAM
  1580. // SFERR_NO_SUPPORT
  1581. //
  1582. // Algorithm:
  1583. //
  1584. // Comments:
  1585. // The following processing is available:
  1586. // CONCATENATE: Enew = E1 followed by E2
  1587. // SUPERIMPOSE: Enew = E1 (t1) + E2 (t1) + E1 (t2)
  1588. // + E2 (t2) + . . . E1 (tn) + E2 (tn)
  1589. //
  1590. // ulProcessMode:
  1591. // Processing mode:
  1592. // CONCATENATE - CONCATENATE
  1593. // SUPERIMPOSE - Mix or overlay
  1594. //
  1595. // pPListArray:
  1596. // The array of Effect IDs must be one more than the actual number
  1597. // of Effect IDs to use.
  1598. //
  1599. // Byte 0 = MIDI_CMD_EFFECT + Channel #
  1600. // D7 D6 D5 D4 D3 D2 D1 D0
  1601. // -- -- -- -- -- -- -- --
  1602. // Byte 1 = Low byte of Force 0
  1603. // Byte 2 = High byte of Force 0
  1604. //
  1605. // *** ---------------------------------------------------------------------***
  1606. HRESULT CMD_VFXProcessEffect(
  1607. IN ULONG ulButtonPlayMask,
  1608. IN OUT PDNHANDLE pDnloadID,
  1609. IN int nNumEffects,
  1610. IN ULONG ulProcessMode,
  1611. IN PDNHANDLE pPListArray,
  1612. IN ULONG ulAction)
  1613. {
  1614. HRESULT hRet = SUCCESS;
  1615. PPROCESS_LIST_SYS_EX lpData;
  1616. CMidiVFXProcessList *pMidiProcessList;
  1617. assert(pDnloadID && pPListArray);
  1618. if ((NULL == pDnloadID) || (NULL == pPListArray))
  1619. return (SFERR_INVALID_PARAM);
  1620. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  1621. DNHANDLE DnloadID = *pDnloadID;
  1622. // If Create New, then create a new object,
  1623. // else, update the existing Effect object.
  1624. // Build the special Parameter
  1625. PLIST PList;
  1626. PList.ulNumEffects = (ULONG) nNumEffects;
  1627. PList.ulProcessMode = ulProcessMode;
  1628. PList.pEffectArray = pPListArray;
  1629. PList.ulAction = ulAction;
  1630. if (NULL == DnloadID) // New, Make a new object
  1631. {
  1632. // make sure we are not trying to create a PL within a PL
  1633. for(int i=0; i<nNumEffects; i++)
  1634. {
  1635. // get the next sub-effect
  1636. int nID = pPListArray[i];
  1637. CMidiEffect* pMidiEffect = g_pJoltMidi->GetEffectByID(DNHANDLE(nID));
  1638. if(pMidiEffect == NULL)
  1639. return SFERR_INVALID_PARAM;
  1640. // make sure it is not a process list
  1641. ULONG ulSubType = pMidiEffect->SubTypeOf();
  1642. if(ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE)
  1643. return SFERR_INVALID_PARAM;
  1644. }
  1645. pMidiProcessList = new CMidiVFXProcessList(ulButtonPlayMask, &PList);
  1646. assert(pMidiProcessList);
  1647. if (!pMidiProcessList) return (SFERR_DRIVER_ERROR);
  1648. pMidiProcessList->SetEffectID(NEW_EFFECT_ID);
  1649. pMidiProcessList->SetSubType(ulProcessMode);
  1650. }
  1651. else // Modify existing
  1652. {
  1653. pMidiProcessList = (CMidiVFXProcessList *) g_pJoltMidi->GetEffectByID(DnloadID);
  1654. assert(pMidiProcessList);
  1655. if (NULL == pMidiProcessList) return (SFERR_INVALID_OBJECT);
  1656. pMidiProcessList->SetEffectID((BYTE) DnloadID);
  1657. }
  1658. // Fill in the parameters
  1659. pMidiProcessList->SetParams(ulButtonPlayMask, &PList);
  1660. if (PLAY_FOREVER == (ulAction & PLAY_FOREVER))
  1661. pMidiProcessList->SetDuration(0);
  1662. // Generate Sys_Ex packet then prepare for output
  1663. lpData = (PPROCESS_LIST_SYS_EX) pMidiProcessList->GenerateSysExPacket();
  1664. assert(lpData);
  1665. if (!lpData) return (SFERR_DRIVER_ERROR);
  1666. int nSizeBuf = sizeof(SYS_EX_HDR) + 5 + nNumEffects + 2;
  1667. pMidiProcessList->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
  1668. hRet = pMidiProcessList->SendPacket(pDnloadID, nSizeBuf);
  1669. if (SUCCESS != hRet) // Create NEW, Failure
  1670. {
  1671. delete pMidiProcessList;
  1672. }
  1673. else
  1674. {
  1675. // workaround to FW bug #1211, modify PL type with same PL type
  1676. ULONG ulSubType;
  1677. if (PL_SUPERIMPOSE == ulProcessMode)
  1678. ulSubType = PLIST_SUPERIMPOSE;
  1679. else
  1680. ulSubType = PLIST_CONCATENATE;
  1681. hRet = CMD_ModifyParamByIndex(INDEX0, *pDnloadID, (SHORT) ulSubType);
  1682. }
  1683. return (hRet);
  1684. }
  1685. /****************************************************************************
  1686. FUNCTION: ModifyEffectParams
  1687. PARAMETERS: DNHANDLE DnloadID - Download ID
  1688. PEFFECT pEffect - Ptr to EFFECT structure
  1689. DWORD dwFlags - Flags indicating which changed
  1690. RETURNS: SUCCESS or ERROR code
  1691. COMMENTS: Modifies EFFECT parameters
  1692. Algorithm:
  1693. ****************************************************************************/
  1694. HRESULT ModifyEffectParams(
  1695. IN DNHANDLE DnloadID,
  1696. IN PEFFECT pEffect,
  1697. IN DWORD dwFlags)
  1698. {
  1699. HRESULT hRet = SUCCESS;
  1700. // Check dwFlags for each parameter that changed.
  1701. // Duration?
  1702. ULONG ulDuration = pEffect->m_Duration;
  1703. if (dwFlags & DIEP_DURATION)
  1704. {
  1705. if (ulDuration != 0)
  1706. {
  1707. ulDuration = (ULONG) ( (float) ulDuration/TICKRATE);
  1708. if (ulDuration <= 0)
  1709. ulDuration = 1;
  1710. }
  1711. hRet = CMD_ModifyParamByIndex(INDEX0, DnloadID, (SHORT) ulDuration);
  1712. if (SUCCESS!=hRet) return hRet;
  1713. }
  1714. // ButtonPlayback?
  1715. if (dwFlags & DIEP_TRIGGERBUTTON)
  1716. {
  1717. hRet = CMD_ModifyParamByIndex(INDEX1, DnloadID, (SHORT) pEffect->m_ButtonPlayMask);
  1718. if (SUCCESS!=hRet) return hRet;
  1719. }
  1720. // Direction?
  1721. if (dwFlags & DIEP_DIRECTION)
  1722. {
  1723. hRet = CMD_ModifyParamByIndex(INDEX2, DnloadID, (SHORT) pEffect->m_DirectionAngle2D);
  1724. if (SUCCESS!=hRet) return hRet;
  1725. }
  1726. // Gain?
  1727. if (dwFlags & DIEP_GAIN)
  1728. {
  1729. hRet = CMD_ModifyParamByIndex(INDEX3, DnloadID, (SHORT) (pEffect->m_Gain * MAX_SCALE));
  1730. if (SUCCESS!=hRet) return hRet;
  1731. }
  1732. // Force Output Rate
  1733. if (dwFlags & DIEP_SAMPLEPERIOD )
  1734. {
  1735. hRet = CMD_ModifyParamByIndex(INDEX4, DnloadID, (SHORT) (pEffect->m_ForceOutputRate));
  1736. if (SUCCESS!=hRet) return hRet;
  1737. }
  1738. return (hRet);
  1739. }
  1740. /****************************************************************************
  1741. FUNCTION: ModifyEnvelopeParams
  1742. PARAMETERS: CMidiSynthesized * pMidiEffect - Ptr to Effect object
  1743. DNHANDLE DnloadID - Download ID
  1744. PENVELOPE pEnvelope - Ptr to ENVELOPE structure
  1745. DWORD dwFlags - Flags indicating which changed
  1746. RETURNS: SUCCESS or ERROR code
  1747. COMMENTS: Modifies ENVELOPE parameters
  1748. Algorithm:
  1749. ****************************************************************************/
  1750. HRESULT ModifyEnvelopeParams(
  1751. IN CMidiSynthesized *pMidiEffect,
  1752. IN DNHANDLE DnloadID,
  1753. IN ULONG ulDuration,
  1754. IN PENVELOPE pEnvelope,
  1755. IN DWORD dwFlags)
  1756. {
  1757. HRESULT hRet=SUCCESS;
  1758. ULONG ulTimeToSustain;
  1759. ULONG ulTimeToDecay;
  1760. // Envelope?
  1761. if (dwFlags & DIEP_ENVELOPE)
  1762. {
  1763. if (PERCENTAGE == pEnvelope->m_Type)
  1764. {
  1765. ulTimeToSustain = (ULONG) ((pEnvelope->m_Attack * ulDuration) /100.);
  1766. ulTimeToDecay = (ULONG) ((pEnvelope->m_Attack + pEnvelope->m_Sustain)
  1767. * ulDuration /100.);
  1768. }
  1769. else // TIME option envelope
  1770. {
  1771. ulTimeToSustain = (ULONG) (pEnvelope->m_Attack);
  1772. ulTimeToDecay = (ULONG) (pEnvelope->m_Attack + pEnvelope->m_Sustain);
  1773. }
  1774. ulTimeToSustain = (ULONG) ( (float) ulTimeToSustain/TICKRATE);
  1775. ulTimeToDecay = (ULONG) ( (float) ulTimeToDecay/TICKRATE);
  1776. // REVIEW: Do a parameters changed check in order to speed this up - TOO MANY BYTES!!!
  1777. if (pEnvelope->m_Attack != (pMidiEffect->EnvelopePtrOf())->m_Attack)
  1778. {
  1779. hRet = CMD_ModifyParamByIndex(INDEX7, DnloadID, (SHORT) ulTimeToSustain);
  1780. if (SUCCESS!=hRet) return hRet;
  1781. }
  1782. if ( (pEnvelope->m_Attack != (pMidiEffect->EnvelopePtrOf())->m_Attack)
  1783. || (pEnvelope->m_Sustain != (pMidiEffect->EnvelopePtrOf())->m_Sustain) )
  1784. {
  1785. hRet = CMD_ModifyParamByIndex(INDEX8, DnloadID, (SHORT) ulTimeToDecay);
  1786. if (SUCCESS!=hRet) return hRet;
  1787. }
  1788. if (pEnvelope->m_StartAmp != (pMidiEffect->EnvelopePtrOf())->m_StartAmp)
  1789. {
  1790. hRet = CMD_ModifyParamByIndex(INDEX9, DnloadID, (SHORT) (pEnvelope->m_StartAmp * MAX_SCALE));
  1791. if (SUCCESS!=hRet) return hRet;
  1792. }
  1793. if (pEnvelope->m_SustainAmp != (pMidiEffect->EnvelopePtrOf())->m_SustainAmp)
  1794. {
  1795. hRet = CMD_ModifyParamByIndex(INDEX10, DnloadID, (SHORT) (pEnvelope->m_SustainAmp * MAX_SCALE));
  1796. if (SUCCESS!=hRet) return hRet;
  1797. }
  1798. if (pEnvelope->m_EndAmp != (pMidiEffect->EnvelopePtrOf())->m_EndAmp)
  1799. {
  1800. hRet = CMD_ModifyParamByIndex(INDEX11, DnloadID, (SHORT) (pEnvelope->m_EndAmp * MAX_SCALE));
  1801. if (SUCCESS!=hRet) return hRet;
  1802. }
  1803. }
  1804. return (hRet);
  1805. }
  1806. /****************************************************************************
  1807. FUNCTION: MapEnvelope
  1808. PARAMETERS: ULONG ulDuration - Total Duration
  1809. ULONG dwMagnitude
  1810. ULONG * pMaxLevel
  1811. LPDIENVELOPE pIDEnvelope- Ptr to DIENVELOPE structure
  1812. PENVELOPE pEnvelope - SWForce ENVELOPE
  1813. RETURNS: none
  1814. COMMENTS: Maps DIENVELOPE to ENVELOPE
  1815. Algorithm:
  1816. ****************************************************************************/
  1817. void MapEnvelope(
  1818. IN ULONG ulDuration,
  1819. IN ULONG dwMagnitude,
  1820. IN ULONG * pMaxLevel,
  1821. IN LPDIENVELOPE pDIEnvelope,
  1822. IN OUT PENVELOPE pEnvelope)
  1823. {
  1824. ULONG ulMaxLevel = *pMaxLevel;
  1825. if (pDIEnvelope)
  1826. {
  1827. // if there is an envelope, MaxLevel must look at attack/fade
  1828. ulMaxLevel = max(ulMaxLevel, pDIEnvelope->dwAttackLevel);
  1829. ulMaxLevel = max(ulMaxLevel, pDIEnvelope->dwFadeLevel);
  1830. pEnvelope->m_Type = TIME;
  1831. // find attack/sustain/decay which sum to ulDuration
  1832. pEnvelope->m_Attack = pDIEnvelope->dwAttackTime/SCALE_TIME;
  1833. pEnvelope->m_Decay = pDIEnvelope->dwFadeTime/SCALE_TIME;
  1834. // REVIEW: is this correct for ulDuration == 0?
  1835. if(ulDuration != 0)
  1836. pEnvelope->m_Sustain = ulDuration - pEnvelope->m_Attack - pEnvelope->m_Decay;
  1837. else
  1838. pEnvelope->m_Sustain = 0;
  1839. // convert to StartAmp/SustainAmp/EndAmp, which is a % of the magnitude
  1840. if(ulMaxLevel != 0)
  1841. {
  1842. pEnvelope->m_StartAmp = pDIEnvelope->dwAttackLevel*100/ulMaxLevel;
  1843. pEnvelope->m_SustainAmp = dwMagnitude*100/ulMaxLevel;
  1844. pEnvelope->m_EndAmp = pDIEnvelope->dwFadeLevel*100/ulMaxLevel;
  1845. }
  1846. else
  1847. {
  1848. pEnvelope->m_StartAmp = pDIEnvelope->dwAttackLevel;
  1849. pEnvelope->m_SustainAmp = 100;
  1850. pEnvelope->m_EndAmp = pDIEnvelope->dwFadeLevel;
  1851. }
  1852. }
  1853. else // No Envelope
  1854. {
  1855. pEnvelope->m_Type = TIME;
  1856. pEnvelope->m_Attack = 0;
  1857. pEnvelope->m_Sustain = ulDuration;
  1858. pEnvelope->m_Decay = 0;
  1859. pEnvelope->m_StartAmp = 0;
  1860. pEnvelope->m_SustainAmp = 100;
  1861. pEnvelope->m_EndAmp = 0;
  1862. }
  1863. *pMaxLevel = ulMaxLevel;
  1864. }