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.

1415 lines
45 KiB

  1. /****************************************************************************
  2. MODULE: SW_CImpI.CPP
  3. Tab Settings: 5 9
  4. Copyright 1995, 1996, Microsoft Corporation, All Rights Reserved.
  5. PURPOSE: IDEffect Implementation.
  6. Function(s):
  7. CImpIDirectInputEffectDriver::DeviceID
  8. CImpIDirectInputEffectDriver::GetVersions
  9. CImpIDirectInputEffectDriver::Escape
  10. CImpIDirectInputEffectDriver::SetGain
  11. CImpIDirectInputEffectDriver::SendForceFeedbackCommand
  12. CImpIDirectInputEffectDriver::GetForceFeedbackState
  13. CImpIDirectInputEffectDriver::DownloadEffect
  14. CImpIDirectInputEffectDriver::DestroyEffect
  15. CImpIDirectInputEffectDriver::StartEffect
  16. CImpIDirectInputEffectDriver::StopEffect
  17. CImpIDirectInputEffectDriver::GetEffectStatus
  18. Author(s): Name:
  19. ---------- ----------------
  20. MEA Manolito E. Adan
  21. Revision History:
  22. -----------------
  23. Version Date Author Comments
  24. ------- ------ ----- -------------------------------------------
  25. 1.0 06-Feb-97 MEA original, Based on SWForce
  26. 23-Feb-97 MEA Modified for DirectInput FF Device Driver
  27. 23-Mar-97 MEA/DS Added VFX support
  28. 13-Mar-99 waltw Deleted unused m_pJoltMidi and accessors
  29. 15-Mar-99 waltw Get version info from ntverp.h (was version.h)
  30. 16-Mar-99 waltw GetFirmwareParams, GetSystemParams,
  31. CMD_Download_RTCSpring, GetDelayParams,
  32. GetJoystickParams, & UpdateJoystickParams
  33. calls removed from DeviceID since they are
  34. called from g_pJoltMidi->Initialize.
  35. ****************************************************************************/
  36. #include <windows.h>
  37. #include <math.h>
  38. #include <assert.h>
  39. #include "dinput.h"
  40. #include "dinputd.h"
  41. #include "SW_objec.hpp"
  42. #include "hau_midi.hpp"
  43. #include "ffd_swff.hpp"
  44. #include "FFDevice.h"
  45. #include "ntverp.h"
  46. #include "CritSec.h"
  47. /****************************************************************************
  48. Declaration of externs
  49. ****************************************************************************/
  50. #ifdef _DEBUG
  51. extern char g_cMsg[160];
  52. extern TCHAR szDeviceName[MAX_SIZE_SNAME];
  53. #endif
  54. extern CJoltMidi *g_pJoltMidi;
  55. // ****************************************************************************
  56. // *** --- Member functions for base class CImpIDirectInputEffectDriver Interface
  57. //
  58. // ****************************************************************************
  59. //
  60. // ----------------------------------------------------------------------------
  61. // Function: CImpIDirectInputEffectDriver::CImpIDirectInputEffectDriver
  62. // Purpose: Constructor(s)/Destructor for CImpIDirectInputEffectDriver Object
  63. // Parameters: PCDirectInputEffectDriver pObj - Ptr to the outer object
  64. //
  65. // Returns:
  66. // Algorithm:
  67. // ----------------------------------------------------------------------------
  68. CImpIDirectInputEffectDriver::CImpIDirectInputEffectDriver(PCDirectInputEffectDriver pObj)
  69. {
  70. m_cRef=0;
  71. m_pObj=pObj;
  72. return;
  73. }
  74. CImpIDirectInputEffectDriver::~CImpIDirectInputEffectDriver(void)
  75. {
  76. #ifdef _DEBUG
  77. OutputDebugString("CImpIDirectInputEffectDriver::~CImpIDirectInputEffectDriver()\n");
  78. #endif
  79. // Destroy the CEffect object we created and release any interfaces
  80. if (g_pJoltMidi)
  81. {
  82. delete g_pJoltMidi;
  83. g_pJoltMidi = NULL;
  84. }
  85. #ifdef _DEBUG
  86. // No critical section here because g_SWFFCriticalSection already destroyed
  87. wsprintf(g_cMsg,"CImpIDirectInputEffectDriver::~CimpIDEffect()\n");
  88. OutputDebugString(g_cMsg);
  89. #endif
  90. }
  91. // ----------------------------------------------------------------------------
  92. // Function: CImpIDirectInputEffectDriver::QueryInterface
  93. // CImpIDirectInputEffectDriver::AddRef
  94. // CImpIDirectInputEffectDriver::Release
  95. //
  96. // Purpose: IUnknown members that delegate to m_pObj
  97. // Parameters:
  98. //
  99. // Returns:
  100. // Algorithm:
  101. // ----------------------------------------------------------------------------
  102. STDMETHODIMP CImpIDirectInputEffectDriver::QueryInterface(REFIID riid, PPVOID ppv)
  103. {
  104. return m_pObj->QueryInterface(riid, ppv);
  105. }
  106. DWORD CImpIDirectInputEffectDriver::AddRef(void)
  107. {
  108. //
  109. // We maintain an "interface reference count" for debugging
  110. // purposes, because the client of an object should match
  111. // AddRef and Release calls through each interface pointer.
  112. //
  113. ++m_cRef;
  114. return m_pObj->AddRef();
  115. }
  116. DWORD CImpIDirectInputEffectDriver::Release(void)
  117. {
  118. // m_cRef is again only for debugging. It doesn't affect
  119. // CSWEffect although the call to m_pObj->Release does.
  120. --m_cRef;
  121. return m_pObj->Release();
  122. }
  123. // ----------------------------------------------------------------------------
  124. // Function: DeviceID
  125. //
  126. // Purpose:
  127. // Parameters: DWORD dwExternalID -The joystick ID number being us
  128. // DWORD fBegin -Nonzero if access to the device is beginning; Zero if ending
  129. // DWORD dwInternalID -Internal joystick id
  130. // LPVOID lpReserved -Reserved for future use (HID)
  131. //
  132. // Returns: SUCCESS or Error code
  133. //
  134. // Algorithm:
  135. // ----------------------------------------------------------------------------
  136. HRESULT CImpIDirectInputEffectDriver::DeviceID(
  137. IN DWORD dwDirectInputVersion,
  138. IN DWORD dwExternalID,
  139. IN DWORD fBegin,
  140. IN DWORD dwInternalID,
  141. LPVOID lpReserved)
  142. {
  143. #ifdef _DEBUG
  144. g_CriticalSection.Enter();
  145. wsprintf(g_cMsg,"CImpIDirectInputEffectDriver::DeviceID(%lu, %lu, %lu, %lu, %lx)\n", dwDirectInputVersion, dwExternalID, fBegin, dwInternalID, lpReserved);
  146. OutputDebugString(g_cMsg);
  147. g_CriticalSection.Leave();
  148. #endif // _DEBUG
  149. assert(NULL == g_pJoltMidi);
  150. // Create and Initialize our CJoltMidi object
  151. #ifdef _DEBUG
  152. OutputDebugString("Creating and Initializing CJoltMidi object\n");
  153. #endif
  154. g_pJoltMidi = new CJoltMidi();
  155. if (NULL == g_pJoltMidi)
  156. {
  157. return (E_OUTOFMEMORY);
  158. }
  159. else
  160. {
  161. return g_pJoltMidi->Initialize(dwExternalID);
  162. }
  163. }
  164. // ----------------------------------------------------------------------------
  165. // Function: GetVersions
  166. //
  167. // Purpose:
  168. // Parameters: LPDIDRIVERVERSIONS pvers -Pointer to structure which receives version info
  169. //
  170. // Returns: SUCCESS or Error code
  171. //
  172. // Algorithm:
  173. // ----------------------------------------------------------------------------
  174. HRESULT CImpIDirectInputEffectDriver::GetVersions(
  175. IN OUT LPDIDRIVERVERSIONS pvers)
  176. {
  177. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  178. LOCAL_PRODUCT_ID* pProductID = g_pJoltMidi->ProductIDPtrOf();
  179. if(pProductID == NULL)
  180. return E_FAIL;
  181. pvers->dwFirmwareRevision = (pProductID->dwFWMajVersion << 8) | (pProductID->dwFWMinVersion);
  182. pvers->dwHardwareRevision = pProductID->dwProductID;
  183. // Get version from ntverp.h (was FULLVersion from version.h)
  184. pvers->dwFFDriverVersion = VER_PRODUCTVERSION_DW;
  185. #ifdef _DEBUG
  186. g_CriticalSection.Enter();
  187. wsprintf(g_cMsg,"CImpIDirectInputEffectDriver::GetVersions(%lu, %lu, %lu)\n", pvers->dwFirmwareRevision, pvers->dwHardwareRevision, pvers->dwFFDriverVersion);
  188. OutputDebugString(g_cMsg);
  189. g_CriticalSection.Leave();
  190. #endif // _DEBUG
  191. return SUCCESS;
  192. }
  193. // ----------------------------------------------------------------------------
  194. // Function: Escape
  195. //
  196. // Purpose:
  197. // Parameters: DWORD dwDeviceID - Device ID
  198. // LPDIEFFESCAPE pEsc - Pointer to a DIFEFESCAPE struct
  199. //
  200. //
  201. // Returns: SUCCESS or Error code
  202. //
  203. // Algorithm:
  204. // ----------------------------------------------------------------------------
  205. HRESULT CImpIDirectInputEffectDriver::Escape(
  206. IN DWORD dwDeviceID,
  207. IN DWORD dwEffectID,
  208. IN OUT LPDIEFFESCAPE pEsc )
  209. {
  210. HRESULT hRet = SUCCESS;
  211. return (hRet);
  212. }
  213. // ----------------------------------------------------------------------------
  214. // Function: SetGain
  215. //
  216. // Purpose:
  217. // Parameters: DWORD dwDeviceID - Device ID
  218. // DWORD dwGain - Device gain
  219. //
  220. //
  221. // Returns: SUCCESS or Error code
  222. //
  223. // Algorithm:
  224. // ----------------------------------------------------------------------------
  225. HRESULT CImpIDirectInputEffectDriver::SetGain(
  226. IN DWORD dwDeviceID,
  227. IN DWORD dwGain)
  228. {
  229. #ifdef _DEBUG
  230. g_CriticalSection.Enter();
  231. wsprintf(g_cMsg, "SetGain: %s Gain=%ld\r\n", &szDeviceName, dwGain);
  232. OutputDebugString(g_cMsg);
  233. g_CriticalSection.Leave();
  234. #endif
  235. if ((dwGain <= 0) || (dwGain > MAX_GAIN)) return (SFERR_INVALID_PARAM);
  236. dwGain = dwGain / SCALE_GAIN;
  237. return(CMD_ModifyParamByIndex(INDEX15, SYSTEM_EFFECT_ID, (USHORT)(dwGain * MAX_SCALE)));
  238. }
  239. // ----------------------------------------------------------------------------
  240. // Function: SendForceFeedbackCommand
  241. //
  242. // Purpose:
  243. // Parameters: DWORD dwDeviceID - Device ID
  244. // DWORD dwState - Command to set Device state
  245. //
  246. //
  247. // Returns: SUCCESS or Error code
  248. //
  249. // Need to map the following DX to Jolt
  250. // DS_FORCE_SHUTDOWN 0x00000001 // Actuators (Motors) are enabled.
  251. // DS_FORCE_ON 0x00000002 // Actuators (Motors) are disabled.
  252. // DS_FORCE_OFF 0x00000003 // All Effects are "Paused"
  253. // DS_CONTINUE 0x00000004 // All "Paused" Effects are continued
  254. // DS_PAUSE 0x00000005 // All Effects are stopped.
  255. // DS_STOP_ALL 0x00000006 // All Effects destroyed,Motors disabled
  256. //
  257. // Jolt Device ulMode:
  258. // SWDEV_SHUTDOWN 1L // All Effects destroyed, Motors disabled
  259. // SWDEV_FORCE_ON 2L // Motors enabled. "Un-Mute"
  260. // SWDEV_FORCE_OFF 3L // Motors disabled. "Mute"
  261. // SWDEV_CONTINUE 4L // All "Paused" Effects are allow to continue
  262. // SWDEV_PAUSE 5L // All Effects are "Paused"
  263. // SWDEV_STOP_ALL 6L // Stops all Effects.
  264. //
  265. // Algorithm:
  266. // ----------------------------------------------------------------------------
  267. HRESULT CImpIDirectInputEffectDriver::SendForceFeedbackCommand(
  268. IN DWORD dwDeviceID,
  269. IN DWORD dwState)
  270. {
  271. #ifdef _DEBUG
  272. g_CriticalSection.Enter();
  273. wsprintf(g_cMsg, "SendForceFeedbackCommand: %s State=%ld\r\n", &szDeviceName, dwState);
  274. OutputDebugString(g_cMsg);
  275. g_CriticalSection.Leave();
  276. #endif
  277. HRESULT hRet = SUCCESS;
  278. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  279. // Convert to Jolt modes
  280. ULONG ulDeviceMode;
  281. switch(dwState)
  282. {
  283. case DISFFC_SETACTUATORSON:
  284. ulDeviceMode = SWDEV_FORCE_ON;
  285. break;
  286. case DISFFC_SETACTUATORSOFF:
  287. ulDeviceMode = SWDEV_FORCE_OFF;
  288. break;
  289. case DISFFC_PAUSE:
  290. ulDeviceMode = SWDEV_PAUSE;
  291. break;
  292. case DISFFC_CONTINUE:
  293. ulDeviceMode = SWDEV_CONTINUE;
  294. break;
  295. case DISFFC_STOPALL:
  296. ulDeviceMode = SWDEV_STOP_ALL;
  297. break;
  298. case DISFFC_RESET:
  299. ulDeviceMode = SWDEV_SHUTDOWN;
  300. break;
  301. default:
  302. return (SFERR_INVALID_PARAM);
  303. }
  304. hRet = CMD_SetDeviceState(ulDeviceMode);
  305. if (SUCCESS == hRet)
  306. g_pJoltMidi->UpdateDeviceMode(ulDeviceMode);
  307. return (hRet);
  308. }
  309. // ----------------------------------------------------------------------------
  310. // Function: GetForceFeedbackState
  311. //
  312. // Purpose:
  313. // Parameters: DWORD dwDeviceID - Device ID
  314. // LPDIDEVICESTATE pDeviceState - Pointer to a DIDEVICESTATE struct
  315. //
  316. // Returns: SUCCESS or Error code and state updated in pDeviceState
  317. //
  318. // Member: dwState
  319. // DS_FORCE_SHUTDOWN 0x00000001
  320. // DS_FORCE_ON 0x00000002
  321. // DS_FORCE_OFF 0x00000003
  322. // DS_CONTINUE 0x00000004
  323. // DS_PAUSE 0x00000005
  324. // DS_STOP_ALL 0x00000006
  325. //
  326. // Member: dwSwitches
  327. // DSW_ACTUATORSON 0x00000001
  328. // DSW_ACTUATORSOFF 0x00000002
  329. // DSW_POWERON 0x00000004
  330. // DSW_POWEROFF 0x00000008
  331. // DSW_SAFETYSWITCHON 0x00000010
  332. // DSW_SAFETYSWITCHOFF 0x00000020
  333. // DSW_USERFFSWITCHON 0x00000040
  334. // DSW_USERFFSWTTCHOFF 0x00000080
  335. //
  336. // Algorithm:
  337. // This is the DI Device State structure
  338. //typedef struct DIDEVICESTATE {
  339. // DWORD dwSize;
  340. // DWORD dwState;
  341. // DWORD dwSwitches;
  342. // DWORD dwLoading;
  343. //} DEVICESTATE, *LPDEVICESTATE;
  344. //
  345. // This is the SideWinder State structure (copy kept in CJoltMidi object)
  346. //typedef struct _SWDEVICESTATE {
  347. // ULONG m_Bytes; // size of this structure
  348. // ULONG m_ForceState; // DS_FORCE_ON || DS_FORCE_OFF || DS_SHUTDOWN
  349. // ULONG m_EffectState; // DS_STOP_ALL || DS_CONTINUE || DS_PAUSE
  350. // ULONG m_HOTS; // Hands On Throttle and Stick Status
  351. // // 0 = Hands Off, 1 = Hands On
  352. // ULONG m_BandWidth; // Percentage of CPU available 1 to 100%
  353. // // Lower number indicates CPU is in trouble!
  354. // ULONG m_ACBrickFault; // 0 = AC Brick OK, 1 = AC Brick Fault
  355. // ULONG m_ResetDetect; // 1 = HW Reset Detected
  356. // ULONG m_ShutdownDetect; // 1 = Shutdown detected
  357. // ULONG m_CommMode; // 0 = Midi, 1-4 = Serial
  358. //} SWDEVICESTATE, *PSWDEVICESTATE;
  359. //
  360. // Note: Apparently, DSW_ACTUATORSON and DSW_ACTUATORSOFF is a mirrored state
  361. // from DS_FORCE_ON and DS_FORCE_OFF as set from SetForceFeedbackState
  362. //
  363. // ----------------------------------------------------------------------------
  364. HRESULT CImpIDirectInputEffectDriver::GetForceFeedbackState(
  365. IN DWORD dwDeviceID,
  366. IN LPDIDEVICESTATE pDeviceState)
  367. {
  368. #ifdef _DEBUG
  369. g_CriticalSection.Enter();
  370. wsprintf(g_cMsg, "GetForceFeedbackState: %s\r\n", &szDeviceName[0]);
  371. OutputDebugString(g_cMsg);
  372. g_CriticalSection.Leave();
  373. #endif
  374. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  375. assert(pDeviceState);
  376. if (NULL == pDeviceState) return (SFERR_INVALID_PARAM);
  377. assert(pDeviceState->dwSize == sizeof(DIDEVICESTATE));
  378. if (pDeviceState->dwSize != sizeof(DIDEVICESTATE) )return (SFERR_INVALID_STRUCT_SIZE);
  379. if ((g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) && (g_ForceFeedbackDevice.GetFirmwareVersionMinor() == 20)) {
  380. if ((g_pJoltMidi) && (g_pJoltMidi->GetSWDeviceStateNoUpdate().m_ForceState == SWDEV_FORCE_OFF)) { // Echo state back to fix 1.20 bug
  381. CMD_SetDeviceState(SWDEV_FORCE_OFF);
  382. } else {
  383. CMD_SetDeviceState(SWDEV_FORCE_ON);
  384. }
  385. }
  386. // zero out the device state structure then pass to GetJoltStatus(LPDEVICESTATE)
  387. pDeviceState->dwState = 0;
  388. //pDeviceState->dwSwitches = 0;
  389. pDeviceState->dwLoad = 0;
  390. HRESULT hRet = g_pJoltMidi->GetJoltStatus(pDeviceState);
  391. #ifdef _DEBUG
  392. g_CriticalSection.Enter();
  393. wsprintf(g_cMsg, "dwState=%.8lx, dwLoad=%d\n",
  394. pDeviceState->dwState, pDeviceState->dwLoad);
  395. OutputDebugString(g_cMsg);
  396. g_CriticalSection.Leave();
  397. #endif
  398. return (hRet);
  399. }
  400. // ----------------------------------------------------------------------------
  401. // Function: DownloadEffect
  402. //
  403. // Purpose:
  404. // Parameters: DWORD dwDeviceID - Device ID
  405. // DWORD dwInternalEffectType - Internal Effect Type
  406. // IN OUT LPDWORD pDnloadID - Pointer to a DWORD for DnloadID
  407. // IN LPCDIEFFECT pEffect - Pointer to a DIEFFECT structure
  408. // IN DWORD dwFlags - for parameters that changed
  409. //
  410. //
  411. // Returns: SUCCESS or Error code
  412. //
  413. // Algorithm:
  414. // The following dwFlags may be sent by the kernel
  415. //
  416. //#define DIEP_ALLPARAMS 0x000000FF - All fields valid
  417. //#define DIEP_AXES 0x00000020 - cAxes and rgdwAxes
  418. //#define DIEP_DIRECTION 0x00000040 - cAxes and rglDirection
  419. //#define DIEP_DURATION 0x00000001 - dwDuration
  420. //#define DIEP_ENVELOPE 0x00000080 - lpEnvelope
  421. //#define DIEP_GAIN 0x00000004 - dwGain
  422. //#define DIEP_NODOWNLOAD 0x80000000 - suppress auto - download
  423. //#define DIEP_SAMPLEPERIOD 0x00000002 - dwSamplePeriod
  424. //#define DIEP_TRIGGERBUTTON 0x00000008 - dwTriggerButton
  425. //#define DIEP_TRIGGERREPEATINTERVAL 0x00000010 - dwTriggerRepeatInterval
  426. //#define DIEP_TYPESPECIFICPARAMS 0x00000100 - cbTypeSpecificParams
  427. // and lpTypeSpecificParams
  428. // Jolt has two options for downloading - Full SysEx or Modify Parameter
  429. // Pass the dwFlags to each CMD_xxx function and let the MIDI function
  430. // determine whether to use SysEx or Modify Parameter.
  431. //
  432. // ----------------------------------------------------------------------------
  433. HRESULT CImpIDirectInputEffectDriver::DownloadEffect(
  434. IN DWORD dwDeviceID,
  435. IN DWORD dwInternalEffectType,
  436. IN OUT LPDWORD pDnloadID,
  437. IN LPCDIEFFECT pEffect,
  438. IN DWORD dwFlags)
  439. {
  440. HRESULT hRet = SUCCESS;
  441. BOOL bTruncated = FALSE; // TRUE if some effect parameters out of range
  442. #ifdef _DEBUG
  443. g_CriticalSection.Enter();
  444. wsprintf(g_cMsg, "%s DownloadEffect. DnloadID= %ld, Type=%lx, dwFlags= %lx\r\n",
  445. &szDeviceName[0], *pDnloadID, dwInternalEffectType, dwFlags);
  446. OutputDebugString(g_cMsg);
  447. g_CriticalSection.Leave();
  448. #endif
  449. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  450. //REVIEW: Still need to do boundary Assertions, structure size check etc...
  451. assert(pDnloadID && pEffect);
  452. if (!pDnloadID || !pEffect) return (SFERR_INVALID_PARAM);
  453. // Compute the Axis Mask equivalent
  454. int nAxes = pEffect->cAxes;
  455. if (nAxes > 2) return (SFERR_NO_SUPPORT);
  456. BYTE bAxisMask = 0;
  457. for (int i=0; i<nAxes; i++)
  458. {
  459. int nAxisNumber = DIDFT_GETINSTANCE(pEffect->rgdwAxes[i]);
  460. bAxisMask |= 1 << nAxisNumber;
  461. }
  462. // check to see if the X and Y axes were switched
  463. BOOL bAxesReversed = FALSE;
  464. if(nAxes == 2 && DIDFT_GETINSTANCE(pEffect->rgdwAxes[0]) == 1)
  465. bAxesReversed = TRUE;
  466. // convert dwTriggerButton to a Button Mask
  467. ULONG ulButtonPlayMask = 0;
  468. if (pEffect->dwTriggerButton != -1)
  469. {
  470. int nButtonNumber = DIDFT_GETINSTANCE(pEffect->dwTriggerButton);
  471. // map button 10 to button 9
  472. if(nButtonNumber == 9)
  473. nButtonNumber = 8;
  474. else if(nButtonNumber == 8)
  475. return SFERR_NO_SUPPORT;
  476. ulButtonPlayMask = 1 << nButtonNumber;
  477. }
  478. // Compute the Direction Angle
  479. ULONG nDirectionAngle2D, nDirectionAngle3D;
  480. nDirectionAngle3D = 0;
  481. if (pEffect->dwFlags & DIEFF_POLAR)
  482. {
  483. if (2 != nAxes) return (SFERR_INVALID_PARAM);
  484. nDirectionAngle2D = pEffect->rglDirection[0]/SCALE_DIRECTION;
  485. }
  486. //else if(pEffect->dwFlags & DIEFF_SPHERICAL)
  487. //{
  488. // nDirectionAngle2D = (pEffect->rglDirection[0]/SCALE_DIRECTION + 90)%360;
  489. //}
  490. else // Rectangular, so convert to Polar
  491. {
  492. // Special case 1D Effects
  493. if (1 == nAxes)
  494. {
  495. if (X_AXIS == (bAxisMask & X_AXIS))
  496. nDirectionAngle2D = 90;
  497. else
  498. nDirectionAngle2D = 0;
  499. }
  500. else
  501. {
  502. // get the x-component
  503. int nXComponent;
  504. if(bAxisMask & X_AXIS)
  505. nXComponent = pEffect->rglDirection[bAxesReversed ? 1 : 0];
  506. else
  507. nXComponent = 0;
  508. // get the y-component
  509. int nYComponent;
  510. if(bAxisMask & Y_AXIS)
  511. {
  512. if(bAxisMask & X_AXIS)
  513. nYComponent = -pEffect->rglDirection[bAxesReversed ? 0 : 1];
  514. else
  515. nYComponent = -pEffect->rglDirection[bAxesReversed ? 1 : 0];
  516. }
  517. else
  518. nYComponent = 0;
  519. // calculate the angle in degrees
  520. double lfAngle = atan2((double)nYComponent, (double)nXComponent)*180.0/3.14159;
  521. // convert it to our kind of angle
  522. int nAngle;
  523. if(lfAngle >= 0.0)
  524. nAngle = -(int)(lfAngle + 0.5) + 90;
  525. else
  526. nAngle = -(int)(lfAngle - 0.5) + 90;
  527. if(nAngle < 0)
  528. nAngle += 360;
  529. else if(nAngle >= 360)
  530. nAngle -= 360;
  531. nDirectionAngle2D = nAngle;
  532. }
  533. }
  534. // Scale the Duration, Gain
  535. ULONG ulDuration;
  536. if(pEffect->dwDuration == INFINITE)
  537. ulDuration = 0;
  538. else
  539. ulDuration = max(1, (ULONG) (pEffect->dwDuration/SCALE_TIME));
  540. ULONG ulGain = (ULONG) (pEffect->dwGain/SCALE_GAIN);
  541. ULONG ulAction = PLAY_STORE;
  542. int nSamples;
  543. // universal characteristics
  544. DWORD dwMagnitude; // DX units
  545. LONG lOffset; // DX units
  546. ULONG ulFrequency; // SW units
  547. ULONG ulMaxLevel;
  548. // Create Jolt Behavior Effects
  549. BE_XXX BE_xxx;
  550. PBE_WALL_PARAM pBE_Wall;
  551. LPDICONDITION pDICondition;
  552. LPDICUSTOMFORCE pDICustomForce;
  553. LPDIENVELOPE pDIEnvelope;
  554. float T;
  555. PLONG pScaledForceData;
  556. // Note: HIWORD(dwInternalEffectType) = Major Type
  557. // LOWORD(dwInternalEffectType) = Minor Type
  558. // Decode the type of Download to use
  559. hRet = SFERR_INVALID_PARAM;
  560. ULONG ulType = HIWORD(dwInternalEffectType);
  561. ULONG ulSubType = LOWORD(dwInternalEffectType);
  562. // if this is a modify, make sure we are not trying to modify
  563. // parameters which are not modifiable
  564. BOOL bAttemptToModifyUnmodifiable = FALSE;
  565. if(*pDnloadID != 0)
  566. {
  567. // get a bitmask of the parameters that can be modified
  568. DWORD dwModifyCaps = 0;
  569. switch(ulType)
  570. {
  571. case EF_BEHAVIOR:
  572. switch(ulSubType)
  573. {
  574. case BE_WALL:
  575. dwModifyCaps = DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_TYPESPECIFICPARAMS;
  576. break;
  577. default:
  578. // all other behavioral/condition effects
  579. dwModifyCaps = DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_TYPESPECIFICPARAMS;
  580. break;
  581. }
  582. break;
  583. case EF_USER_DEFINED:
  584. // custom force
  585. dwModifyCaps = DIEP_DURATION | DIEP_SAMPLEPERIOD | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_DIRECTION;
  586. break;
  587. case EF_ROM_EFFECT:
  588. dwModifyCaps = DIEP_DURATION | DIEP_SAMPLEPERIOD | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_DIRECTION | DIEP_ENVELOPE;
  589. break;
  590. case EF_SYNTHESIZED:
  591. switch(ulSubType)
  592. {
  593. case SE_CONSTANT_FORCE:
  594. dwModifyCaps = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS;
  595. break;
  596. default:
  597. dwModifyCaps = DIEP_DURATION | DIEP_SAMPLEPERIOD | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS;
  598. break;
  599. }
  600. break;
  601. case EF_VFX_EFFECT:
  602. dwModifyCaps = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_DIRECTION;
  603. break;
  604. case EF_RAW_FORCE:
  605. dwModifyCaps = DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS;
  606. break;
  607. case EF_RTC_SPRING:
  608. dwModifyCaps = DIEP_TYPESPECIFICPARAMS;
  609. break;
  610. default:
  611. break;
  612. }
  613. // At this point dwModifyCaps is a bitmask of the parameters that can
  614. // be modified for this type of effect.
  615. // see if there are any bits set that correspond to parameters we cannot modify
  616. DWORD dwModifyFlags = DIEP_DURATION | DIEP_SAMPLEPERIOD | DIEP_GAIN | DIEP_TRIGGERBUTTON
  617. | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION
  618. | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS;
  619. if(~dwModifyCaps & dwFlags & dwModifyFlags)
  620. bAttemptToModifyUnmodifiable = TRUE;
  621. // clear the bits in dwFlags that correspond to parameters we cannot modify
  622. dwFlags &= dwModifyCaps | ~dwModifyFlags;
  623. }
  624. // Map the common Effect parameters
  625. EFFECT effect = {sizeof(EFFECT)};
  626. effect.m_SubType = ulSubType;
  627. effect.m_AxisMask = (ULONG) bAxisMask;
  628. effect.m_DirectionAngle2D = nDirectionAngle2D;
  629. effect.m_DirectionAngle3D = 0;
  630. effect.m_Duration = ulDuration;
  631. effect.m_Gain = ulGain;
  632. effect.m_ButtonPlayMask = ulButtonPlayMask;
  633. ENVELOPE envelope = {sizeof(ENVELOPE)};
  634. SE_PARAM seParam = {sizeof(SE_PARAM)};
  635. switch (ulType)
  636. {
  637. case EF_BEHAVIOR:
  638. pDICondition = (LPDICONDITION) pEffect->lpvTypeSpecificParams;
  639. // Map the EFFECT Type
  640. effect.m_Type = EF_BEHAVIOR;
  641. // Because in DX 1D and 2D conditions have the same type, we must
  642. // convert to appropriate subtype depending on axis mask
  643. if(ulSubType != BE_WALL && ulSubType != BE_DELAY && bAxisMask == (X_AXIS|Y_AXIS))
  644. {
  645. ulSubType++;
  646. effect.m_SubType = ulSubType;
  647. }
  648. switch (ulSubType)
  649. {
  650. case BE_SPRING: // 1D Spring
  651. case BE_DAMPER: // 1D Damper
  652. case BE_INERTIA: // 1D Inertia
  653. case BE_FRICTION: // 1D Friction
  654. if (X_AXIS == bAxisMask)
  655. {
  656. BE_xxx.m_XConstant = pDICondition[0].lPositiveCoefficient/SCALE_CONSTANTS;
  657. BE_xxx.m_YConstant = 0;
  658. BE_xxx.m_Param3 = pDICondition[0].lOffset/SCALE_POSITION;
  659. BE_xxx.m_Param4= 0;
  660. }
  661. else
  662. {
  663. if (Y_AXIS != bAxisMask)
  664. break;
  665. else
  666. {
  667. BE_xxx.m_YConstant = pDICondition[0].lPositiveCoefficient/SCALE_CONSTANTS;
  668. BE_xxx.m_XConstant = 0;
  669. BE_xxx.m_Param4 = -pDICondition[0].lOffset/SCALE_POSITION;
  670. BE_xxx.m_Param3= 0;
  671. }
  672. }
  673. if(dwFlags & DIEP_NODOWNLOAD)
  674. return DI_DOWNLOADSKIPPED;
  675. hRet = CMD_Download_BE_XXX(&effect, NULL, &BE_xxx, (PDNHANDLE) pDnloadID, dwFlags);
  676. break;
  677. case BE_SPRING_2D: // 2D Spring
  678. case BE_DAMPER_2D: // 2D Damper
  679. case BE_INERTIA_2D: // 2D Inertia
  680. case BE_FRICTION_2D: // 2D Friction
  681. // Validate AxisMask is for 2D
  682. if ( (X_AXIS|Y_AXIS) != bAxisMask)
  683. break;
  684. BE_xxx.m_XConstant = pDICondition[bAxesReversed ? 1 : 0].lPositiveCoefficient/SCALE_CONSTANTS;
  685. BE_xxx.m_YConstant = pDICondition[bAxesReversed ? 0 : 1].lPositiveCoefficient/SCALE_CONSTANTS;
  686. BE_xxx.m_Param3 = pDICondition[bAxesReversed ? 1 : 0].lOffset/SCALE_POSITION;
  687. BE_xxx.m_Param4 = -pDICondition[bAxesReversed ? 0 : 1].lOffset/SCALE_POSITION;
  688. if(dwFlags & DIEP_NODOWNLOAD)
  689. return DI_DOWNLOADSKIPPED;
  690. hRet = CMD_Download_BE_XXX(&effect, NULL, &BE_xxx, (PDNHANDLE) pDnloadID, dwFlags);
  691. break;
  692. case BE_WALL:
  693. // check for NULL typespecificparams
  694. if(pEffect->lpvTypeSpecificParams == NULL)
  695. return (SFERR_INVALID_PARAM);
  696. pBE_Wall = (PBE_WALL_PARAM) pEffect->lpvTypeSpecificParams;
  697. // Validate AxisMask is for 2D
  698. if ( (X_AXIS|Y_AXIS) != bAxisMask)
  699. break;
  700. // Range check params
  701. if (pBE_Wall->m_Bytes != sizeof(BE_WALL_PARAM))
  702. return (SFERR_INVALID_PARAM);
  703. if ((pBE_Wall->m_WallType != INNER_WALL) && (pBE_Wall->m_WallType != OUTER_WALL))
  704. return (SFERR_INVALID_PARAM);
  705. if ((pBE_Wall->m_WallConstant < MIN_CONSTANT) || (pBE_Wall->m_WallConstant > MAX_CONSTANT))
  706. return (SFERR_INVALID_PARAM);
  707. if (/*(pBE_Wall->m_WallDistance < 0) || */(pBE_Wall->m_WallDistance > MAX_POSITION))
  708. return (SFERR_INVALID_PARAM);
  709. if ( (pBE_Wall->m_WallAngle == 0)
  710. || (pBE_Wall->m_WallAngle == 9000)
  711. || (pBE_Wall->m_WallAngle == 18000)
  712. || (pBE_Wall->m_WallAngle == 27000) )
  713. {
  714. BE_xxx.m_XConstant = pBE_Wall->m_WallType;
  715. BE_xxx.m_YConstant = pBE_Wall->m_WallConstant/SCALE_CONSTANTS;
  716. BE_xxx.m_Param3 = pBE_Wall->m_WallAngle/SCALE_DIRECTION;
  717. BE_xxx.m_Param4 = pBE_Wall->m_WallDistance/SCALE_POSITION;
  718. if(dwFlags & DIEP_NODOWNLOAD)
  719. return DI_DOWNLOADSKIPPED;
  720. hRet = CMD_Download_BE_XXX(&effect, NULL, &BE_xxx, (PDNHANDLE) pDnloadID, dwFlags);
  721. }
  722. else
  723. return SFERR_INVALID_PARAM;
  724. break;
  725. case BE_DELAY:
  726. if (0 == ulDuration) return (SFERR_INVALID_PARAM);
  727. if(dwFlags & DIEP_NODOWNLOAD)
  728. return DI_DOWNLOADSKIPPED;
  729. hRet = CMD_Download_NOP_DELAY(ulDuration, &effect, (PDNHANDLE) pDnloadID);
  730. break;
  731. default:
  732. return SFERR_NO_SUPPORT;
  733. }
  734. break;
  735. case EF_USER_DEFINED:
  736. {
  737. if(ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE)
  738. return SFERR_NO_SUPPORT;
  739. // check for an envelope (we do not support envelopes)
  740. pDIEnvelope = (LPDIENVELOPE) pEffect->lpEnvelope;
  741. if(pDIEnvelope)
  742. {
  743. // try to be somewhat smart about not supporting envelopes
  744. if(pDIEnvelope->dwAttackTime != 0 && pDIEnvelope->dwAttackLevel != 10000
  745. || pDIEnvelope->dwFadeTime != 0 && pDIEnvelope->dwFadeLevel != 10000)
  746. {
  747. return SFERR_NO_SUPPORT;
  748. }
  749. }
  750. // check for modifying type-specific (we do not support)
  751. if(*pDnloadID != 0 && (dwFlags & DIEP_TYPESPECIFICPARAMS))
  752. return SFERR_NO_SUPPORT;
  753. pDICustomForce = (LPDICUSTOMFORCE) pEffect->lpvTypeSpecificParams;
  754. if (pDICustomForce->cChannels > 1) return (SFERR_NO_SUPPORT);
  755. // Map the EFFECT type
  756. effect.m_Type = EF_USER_DEFINED;
  757. DWORD dwSamplePeriod = pDICustomForce->dwSamplePeriod;
  758. if (dwSamplePeriod == 0) {
  759. dwSamplePeriod = pEffect->dwSamplePeriod;
  760. }
  761. if (dwSamplePeriod == 0) { // 0 indicates use default
  762. return SFERR_NO_SUPPORT;
  763. } else {
  764. T = (float) ((dwSamplePeriod/(float)SCALE_TIME)/1000.);
  765. effect.m_ForceOutputRate = (ULONG) ((float) 1.0/ T);
  766. if (0 == effect.m_ForceOutputRate) effect.m_ForceOutputRate = 1;
  767. }
  768. // Scale the Force values to +/-100
  769. nSamples = pDICustomForce->cSamples;
  770. pScaledForceData = new LONG[nSamples];
  771. if (NULL == pScaledForceData) return (SFERR_DRIVER_ERROR);
  772. for (i=0; i<nSamples; i++)
  773. {
  774. LONG lForceData = pDICustomForce->rglForceData[i];
  775. if(lForceData > DI_FFNOMINALMAX)
  776. {
  777. lForceData = DI_FFNOMINALMAX;
  778. bTruncated = TRUE;
  779. }
  780. else if(lForceData < -DI_FFNOMINALMAX)
  781. {
  782. lForceData = -DI_FFNOMINALMAX;
  783. bTruncated = TRUE;
  784. }
  785. pScaledForceData[i] = lForceData/SCALE_GAIN;
  786. }
  787. if(dwFlags & DIEP_NODOWNLOAD)
  788. return DI_DOWNLOADSKIPPED;
  789. // give a short duration effect the shortest possible duration
  790. // that does not translate to zero, (which implies infinite duration)
  791. if(ulDuration == 1)
  792. {
  793. ulDuration = 2;
  794. effect.m_Duration = ulDuration;
  795. }
  796. hRet = CMD_Download_UD_Waveform(ulDuration, &effect,
  797. pDICustomForce->cSamples,
  798. pScaledForceData,
  799. ulAction, (PDNHANDLE) pDnloadID, dwFlags);
  800. delete [] pScaledForceData;
  801. break;
  802. }
  803. case EF_ROM_EFFECT:
  804. // Map the EFFECT type
  805. effect.m_Type = EF_ROM_EFFECT;
  806. // check for default output rate
  807. if(pEffect->dwSamplePeriod == DEFAULT_ROM_EFFECT_OUTPUTRATE) {
  808. // signal default output rate by setting to -1
  809. effect.m_ForceOutputRate = (ULONG)-1;
  810. } else if (pEffect->dwSamplePeriod == 0) {
  811. effect.m_ForceOutputRate = 100;
  812. } else {
  813. T = (float) ((pEffect->dwSamplePeriod/SCALE_TIME)/1000.);
  814. effect.m_ForceOutputRate = max(1, (ULONG) ((float) 1.0/ T));
  815. }
  816. // check for default duration
  817. if(pEffect->dwDuration == DEFAULT_ROM_EFFECT_DURATION)
  818. {
  819. // signal default duration by setting to -1
  820. ulDuration = (ULONG)-1;
  821. effect.m_Duration = ulDuration;
  822. }
  823. // Setup the default parameters for the Effect
  824. if (SUCCESS != g_pJoltMidi->SetupROM_Fx(&effect))
  825. return (SFERR_INVALID_OBJECT);
  826. // update the duration if it was changed in SetupROM_Fx(...)
  827. ulDuration = effect.m_Duration;
  828. // Map the Envelope
  829. pDIEnvelope = (LPDIENVELOPE) pEffect->lpEnvelope;
  830. dwMagnitude = 10000;
  831. ulMaxLevel = dwMagnitude;
  832. MapEnvelope(ulDuration, dwMagnitude, &ulMaxLevel, pDIEnvelope, &envelope);
  833. // Map the SE_PARAM
  834. // set the frequency
  835. seParam.m_Freq = 0; // unused by ROM Effect
  836. seParam.m_MinAmp = -100;
  837. seParam.m_MaxAmp = 100;
  838. // set the sample rate
  839. seParam.m_SampleRate = effect.m_ForceOutputRate;
  840. if(dwFlags & DIEP_NODOWNLOAD)
  841. return DI_DOWNLOADSKIPPED;
  842. hRet = CMD_Download_SYNTH(&effect, &envelope,
  843. &seParam, ulAction, (USHORT *) pDnloadID, dwFlags);
  844. break;
  845. case EF_SYNTHESIZED:
  846. {
  847. // Map the EFFECT type
  848. effect.m_Type = EF_SYNTHESIZED;
  849. // treat constant force as a special case
  850. int nConstantForceSign = 1;
  851. if(ulSubType == SE_CONSTANT_FORCE)
  852. {
  853. // cast the type-specific parameters to constant force type
  854. LPDICONSTANTFORCE pDIConstantForce = (LPDICONSTANTFORCE) pEffect->lpvTypeSpecificParams;
  855. // see if this is the special case of negative constant force
  856. if(pDIConstantForce->lMagnitude < 0)
  857. nConstantForceSign = -1;
  858. // find the magnitude, offset, and frequency
  859. dwMagnitude = abs(pDIConstantForce->lMagnitude);
  860. lOffset = 0;
  861. ulFrequency = 1;
  862. }
  863. else if(ulSubType == SE_RAMPUP)
  864. {
  865. // cast the type-specific parameters to ramp type
  866. LPDIRAMPFORCE pDIRampForce = (LPDIRAMPFORCE) pEffect->lpvTypeSpecificParams;
  867. // temporary variables
  868. int nStart = pDIRampForce->lStart;
  869. int nEnd = pDIRampForce->lEnd;
  870. // map the subtype based on direction of ramp
  871. if(nEnd < nStart)
  872. {
  873. ulSubType = SE_RAMPDOWN;
  874. effect.m_SubType = ulSubType;
  875. }
  876. // find magnitude, offset, and frequency
  877. dwMagnitude = abs(nStart - nEnd)/2;
  878. lOffset = (nStart + nEnd)/2;
  879. ulFrequency = 1;
  880. }
  881. else
  882. {
  883. // cast the type-specific parameters to periodic type
  884. LPDIPERIODIC pDIPeriodic = (LPDIPERIODIC) pEffect->lpvTypeSpecificParams;
  885. // map the subtype based on the phase
  886. DWORD dwPhase = pDIPeriodic->dwPhase;
  887. if(dwPhase != 0)
  888. {
  889. if(ulSubType == SE_SINE && dwPhase == 9000)
  890. {
  891. ulSubType = SE_COSINE;
  892. effect.m_SubType = ulSubType;
  893. }
  894. else if(ulSubType == SE_SQUAREHIGH && dwPhase == 18000)
  895. {
  896. ulSubType = SE_SQUARELOW;
  897. effect.m_SubType = ulSubType;
  898. }
  899. else if(ulSubType == SE_TRIANGLEUP && dwPhase == 18000)
  900. {
  901. ulSubType = SE_TRIANGLEDOWN;
  902. effect.m_SubType = ulSubType;
  903. }
  904. else
  905. return SFERR_NO_SUPPORT;
  906. }
  907. // find magnitude, offset, and frequency
  908. dwMagnitude = pDIPeriodic->dwMagnitude;
  909. lOffset = pDIPeriodic->lOffset;
  910. T = (float) ((pDIPeriodic->dwPeriod/SCALE_TIME)/1000.);
  911. ulFrequency = max(1, (ULONG) ((float) 1.0/ T));
  912. }
  913. if (pEffect->dwSamplePeriod)
  914. {
  915. T = (float) ((pEffect->dwSamplePeriod/SCALE_TIME)/1000.);
  916. effect.m_ForceOutputRate = max(1, (ULONG) ((float) 1.0/ T));
  917. }
  918. else
  919. effect.m_ForceOutputRate = DEFAULT_JOLT_FORCE_RATE;
  920. // Map the SE_PARAM
  921. // set the frequency and Sample rate
  922. seParam.m_Freq = ulFrequency;
  923. seParam.m_SampleRate = DEFAULT_JOLT_FORCE_RATE;
  924. // see if the offset is out of range
  925. if(lOffset > DI_FFNOMINALMAX)
  926. {
  927. lOffset = DI_FFNOMINALMAX;
  928. bTruncated = TRUE;
  929. }
  930. else if(lOffset < -DI_FFNOMINALMAX)
  931. {
  932. lOffset = -DI_FFNOMINALMAX;
  933. bTruncated = TRUE;
  934. }
  935. // see if the magnitude is out of range
  936. DWORD dwPeak = abs(lOffset) + dwMagnitude;
  937. if(dwPeak > DI_FFNOMINALMAX)
  938. {
  939. dwMagnitude -= dwPeak - DI_FFNOMINALMAX;
  940. bTruncated = TRUE;
  941. }
  942. // MaxLevel is the peak magnitude throughout attack/sustain/decay
  943. ulMaxLevel = dwMagnitude;
  944. // Map the Envelope
  945. pDIEnvelope = (LPDIENVELOPE) pEffect->lpEnvelope;
  946. MapEnvelope(ulDuration, dwMagnitude, &ulMaxLevel, pDIEnvelope, &envelope);
  947. // use MaxLevel and Offset to find MinAmp/MaxAmp
  948. if(ulSubType == SE_CONSTANT_FORCE)
  949. {
  950. // constant force is a special case
  951. seParam.m_MaxAmp = nConstantForceSign*((int)ulMaxLevel + lOffset)/SCALE_GAIN;
  952. seParam.m_MinAmp = 0;
  953. }
  954. else
  955. {
  956. seParam.m_MinAmp = (-(int)ulMaxLevel + lOffset)/SCALE_GAIN;
  957. seParam.m_MaxAmp = ((int)ulMaxLevel + lOffset)/SCALE_GAIN;
  958. }
  959. if(*pDnloadID == 0 && (dwFlags & DIEP_NODOWNLOAD))
  960. return DI_DOWNLOADSKIPPED;
  961. hRet = CMD_Download_SYNTH(&effect, &envelope,
  962. &seParam, ulAction, (USHORT *) pDnloadID, dwFlags);
  963. break;
  964. }
  965. case EF_VFX_EFFECT:
  966. {
  967. PVFX_PARAM pVFXParam = (PVFX_PARAM)pEffect->lpvTypeSpecificParams;
  968. // parameter checking
  969. if(pVFXParam == NULL)
  970. return (SFERR_INVALID_PARAM);
  971. if(pVFXParam->m_Bytes != sizeof(VFX_PARAM))
  972. return (SFERR_INVALID_PARAM);
  973. if(pVFXParam->m_PointerType != VFX_FILENAME && pVFXParam->m_PointerType != VFX_BUFFER)
  974. return (SFERR_INVALID_PARAM);
  975. if(pVFXParam->m_PointerType == VFX_BUFFER && pVFXParam->m_BufferSize == 0)
  976. return (SFERR_INVALID_PARAM);
  977. if(pVFXParam->m_pFileNameOrBuffer == NULL)
  978. return (SFERR_INVALID_PARAM);
  979. // check for modifying type-specific (we do not support)
  980. if(*pDnloadID != 0 && (dwFlags & DIEP_TYPESPECIFICPARAMS))
  981. return SFERR_NO_SUPPORT;
  982. // check for default duration
  983. if(pEffect->dwDuration == DEFAULT_VFX_EFFECT_DURATION)
  984. {
  985. // signal default duration by setting duration to -1
  986. ulDuration = (ULONG)-1;
  987. effect.m_Duration = ulDuration;
  988. }
  989. if(dwFlags & DIEP_NODOWNLOAD)
  990. return DI_DOWNLOADSKIPPED;
  991. hRet = CMD_Download_VFX(&effect, NULL, pVFXParam, ulAction, (USHORT*)pDnloadID, dwFlags);
  992. break;
  993. }
  994. case EF_RAW_FORCE:
  995. {
  996. // cast the type-specific parameters to constant force type
  997. LPDICONSTANTFORCE pDIConstantForce = (LPDICONSTANTFORCE) pEffect->lpvTypeSpecificParams;
  998. if(pDIConstantForce == NULL)
  999. return SFERR_INVALID_PARAM;
  1000. LONG nForceValue = pDIConstantForce->lMagnitude/SCALE_GAIN;
  1001. if(nForceValue > 100 || nForceValue < -100)
  1002. return SFERR_INVALID_PARAM;
  1003. // translate to a FORCE structure
  1004. FORCE force;
  1005. force.m_Bytes = sizeof(FORCE);
  1006. force.m_AxisMask = (ULONG)bAxisMask;
  1007. force.m_DirectionAngle2D = nDirectionAngle2D;
  1008. force.m_DirectionAngle3D = 0;
  1009. force.m_ForceValue = nForceValue;
  1010. if(dwFlags & DIEP_NODOWNLOAD)
  1011. return DI_DOWNLOADSKIPPED;
  1012. hRet = FFD_PutRawForce(&force);
  1013. if(!FAILED(hRet))
  1014. *pDnloadID = SYSTEM_EFFECT_ID;
  1015. break;
  1016. }
  1017. case EF_RTC_SPRING:
  1018. {
  1019. PRTCSPRING_PARAM pRTCSpringParam = (PRTCSPRING_PARAM)pEffect->lpvTypeSpecificParams;
  1020. RTCSPRING_PARAM RTCSpringParam;
  1021. // Parameter validate
  1022. if (pRTCSpringParam == NULL)
  1023. return SFERR_INVALID_PARAM;
  1024. if (pRTCSpringParam->m_Bytes != sizeof(RTCSPRING_PARAM))
  1025. return SFERR_INVALID_PARAM;
  1026. if ((pRTCSpringParam->m_XKConstant < MIN_CONSTANT)
  1027. || (pRTCSpringParam->m_XKConstant > MAX_CONSTANT))
  1028. return (SFERR_INVALID_PARAM);
  1029. if ((pRTCSpringParam->m_YKConstant < MIN_CONSTANT)
  1030. || (pRTCSpringParam->m_YKConstant > MAX_CONSTANT))
  1031. return (SFERR_INVALID_PARAM);
  1032. if ((pRTCSpringParam->m_XAxisCenter < MIN_POSITION)
  1033. || (pRTCSpringParam->m_XAxisCenter > MAX_POSITION))
  1034. return (SFERR_INVALID_PARAM);
  1035. if ((pRTCSpringParam->m_YAxisCenter < MIN_POSITION)
  1036. || (pRTCSpringParam->m_YAxisCenter > MAX_POSITION))
  1037. return (SFERR_INVALID_PARAM);
  1038. if ((pRTCSpringParam->m_XSaturation < MIN_POSITION)
  1039. || (pRTCSpringParam->m_XSaturation > MAX_POSITION))
  1040. return (SFERR_INVALID_PARAM);
  1041. if ((pRTCSpringParam->m_YSaturation < MIN_POSITION)
  1042. || (pRTCSpringParam->m_YSaturation > MAX_POSITION))
  1043. return (SFERR_INVALID_PARAM);
  1044. if ((pRTCSpringParam->m_XDeadBand < MIN_POSITION)
  1045. || (pRTCSpringParam->m_XDeadBand > MAX_POSITION))
  1046. return (SFERR_INVALID_PARAM);
  1047. if ((pRTCSpringParam->m_YDeadBand < MIN_POSITION)
  1048. || (pRTCSpringParam->m_YDeadBand > MAX_POSITION))
  1049. return (SFERR_INVALID_PARAM);
  1050. if(dwFlags & DIEP_NODOWNLOAD)
  1051. return DI_DOWNLOADSKIPPED;
  1052. // Scale to Jolt numbers
  1053. RTCSpringParam.m_XKConstant = pRTCSpringParam->m_XKConstant/SCALE_CONSTANTS;
  1054. RTCSpringParam.m_YKConstant = pRTCSpringParam->m_YKConstant/SCALE_CONSTANTS;
  1055. RTCSpringParam.m_XAxisCenter = pRTCSpringParam->m_XAxisCenter/SCALE_POSITION;
  1056. RTCSpringParam.m_YAxisCenter = -pRTCSpringParam->m_YAxisCenter/SCALE_POSITION;
  1057. RTCSpringParam.m_XSaturation = pRTCSpringParam->m_XSaturation/SCALE_POSITION;
  1058. RTCSpringParam.m_YSaturation = pRTCSpringParam->m_YSaturation/SCALE_POSITION;
  1059. RTCSpringParam.m_XDeadBand = pRTCSpringParam->m_XDeadBand/SCALE_POSITION;
  1060. RTCSpringParam.m_YDeadBand = pRTCSpringParam->m_YDeadBand/SCALE_POSITION;
  1061. hRet = CMD_Download_RTCSpring(&RTCSpringParam, (USHORT*)pDnloadID);
  1062. *pDnloadID = SYSTEM_RTCSPRING_ALIAS_ID; // Jolt returns ID0 for RTC Spring
  1063. // so return an alias to that
  1064. break;
  1065. }
  1066. default:
  1067. hRet = SFERR_INVALID_PARAM;
  1068. }
  1069. #ifdef _DEBUG
  1070. g_CriticalSection.Enter();
  1071. wsprintf(g_cMsg, "DownloadEffect. DnloadID = %ld, hRet=%lx\r\n",
  1072. *pDnloadID, hRet);
  1073. OutputDebugString(g_cMsg);
  1074. g_CriticalSection.Leave();
  1075. #endif
  1076. // after successful download, check to see if kernel told us to start/restart effect
  1077. if(!FAILED(hRet) && *pDnloadID != 0 && (dwFlags & DIEP_START))
  1078. {
  1079. hRet = CMD_StopEffect((USHORT)*pDnloadID);
  1080. if(FAILED(hRet)) return hRet;
  1081. hRet = CMD_PlayEffectSuperimpose((USHORT)*pDnloadID);
  1082. }
  1083. if(!FAILED(hRet) && bTruncated)
  1084. return DI_TRUNCATED;
  1085. else if(!FAILED(hRet) && bAttemptToModifyUnmodifiable)
  1086. return S_FALSE;
  1087. else
  1088. return (hRet);
  1089. }
  1090. // ----------------------------------------------------------------------------
  1091. // Function: DestroyEffect
  1092. //
  1093. // Purpose:
  1094. // Parameters: DWORD dwDeviceID - Device ID
  1095. // DWORD DnloadID - Download ID to destroy
  1096. //
  1097. //
  1098. // Returns: SUCCESS or Error code
  1099. //
  1100. // Algorithm:
  1101. // ----------------------------------------------------------------------------
  1102. HRESULT CImpIDirectInputEffectDriver::DestroyEffect(
  1103. IN DWORD dwDeviceID,
  1104. IN DWORD DnloadID)
  1105. {
  1106. #ifdef _DEBUG
  1107. g_CriticalSection.Enter();
  1108. wsprintf(g_cMsg, "%s DestroyEffect. DnloadID:%ld\r\n",
  1109. &szDeviceName[0], DnloadID);
  1110. OutputDebugString(g_cMsg);
  1111. g_CriticalSection.Leave();
  1112. #endif
  1113. // Note: Cannot allow actually destroying the SYSTEM Effects
  1114. // so either fake it, or stop the System Effect.
  1115. if (SYSTEM_FRICTIONCANCEL_ID == DnloadID)
  1116. return SUCCESS;
  1117. // Note: SYSTEM_EFFECT_ID is used for PutRawForce
  1118. if ( (SYSTEM_EFFECT_ID == DnloadID)
  1119. || (SYSTEM_RTCSPRING_ALIAS_ID == DnloadID)
  1120. || (SYSTEM_RTCSPRING_ID == DnloadID))
  1121. {
  1122. return (StopEffect(dwDeviceID, SYSTEM_EFFECT_ID));
  1123. }
  1124. return(CMD_DestroyEffect((DNHANDLE) DnloadID));
  1125. }
  1126. // ----------------------------------------------------------------------------
  1127. // Function: StartEffect
  1128. //
  1129. // Purpose:
  1130. // Parameters: DWORD dwDeviceID - Device ID
  1131. // DWORD DnloadID - Download ID to Start
  1132. // DWORD dwMode - Playback mode
  1133. // DWORD dwCount - Loop count
  1134. //
  1135. //
  1136. // Returns: SUCCESS or Error code
  1137. //
  1138. // dwMode: Playback mode is available with the following options:
  1139. // PLAY_SOLO - stop other forces playing, make this the only one.
  1140. // PLAY_SUPERIMPOSE- mix with currently playing device
  1141. // Algorithm:
  1142. // ----------------------------------------------------------------------------
  1143. HRESULT CImpIDirectInputEffectDriver::StartEffect(
  1144. IN DWORD dwDeviceID,
  1145. IN DWORD DnloadID,
  1146. IN DWORD dwMode,
  1147. IN DWORD dwCount)
  1148. {
  1149. #ifdef _DEBUG
  1150. g_CriticalSection.Enter();
  1151. wsprintf(g_cMsg, "%s StartEffect. DnloadID:%ld, Mode:%lx, Count:%lx\r\n",
  1152. &szDeviceName[0], DnloadID, dwMode, dwCount);
  1153. OutputDebugString(g_cMsg);
  1154. g_CriticalSection.Leave();
  1155. #endif
  1156. // special case for raw force
  1157. if(SYSTEM_EFFECT_ID == DnloadID)
  1158. {
  1159. // start has no meaning for raw force
  1160. return S_FALSE;
  1161. }
  1162. // Special case RTC Spring ID
  1163. if(SYSTEM_RTCSPRING_ALIAS_ID == DnloadID)
  1164. DnloadID = SYSTEM_RTCSPRING_ID; // Jolt returned ID0 for RTC Spring
  1165. // so return send alias ID
  1166. HRESULT hRet = SUCCESS;
  1167. // Don't support PLAY_LOOP for this version
  1168. if (dwCount != 1) return (SFERR_NO_SUPPORT);
  1169. // Is it PLAY_SOLO?
  1170. if (dwMode & DIES_SOLO)
  1171. {
  1172. hRet = CMD_PlayEffectSolo((DNHANDLE) DnloadID);
  1173. }
  1174. else
  1175. {
  1176. hRet = CMD_PlayEffectSuperimpose((DNHANDLE) DnloadID);
  1177. }
  1178. return (hRet);
  1179. }
  1180. // ----------------------------------------------------------------------------
  1181. // Function: StopEffect
  1182. //
  1183. // Purpose:
  1184. // Parameters: DWORD dwDeviceID - Device ID
  1185. // DWORD DnloadID - Download ID to Stop
  1186. //
  1187. //
  1188. // Returns: SUCCESS or Error code
  1189. //
  1190. // Algorithm:
  1191. // ----------------------------------------------------------------------------
  1192. HRESULT CImpIDirectInputEffectDriver::StopEffect(
  1193. IN DWORD dwDeviceID,
  1194. IN DWORD DnloadID)
  1195. {
  1196. #ifdef _DEBUG
  1197. g_CriticalSection.Enter();
  1198. wsprintf(g_cMsg, "%s StopEffect. DnloadID:%ld\r\n",
  1199. &szDeviceName[0], DnloadID);
  1200. OutputDebugString(g_cMsg);
  1201. g_CriticalSection.Leave();
  1202. #endif
  1203. // special case for putrawforce
  1204. if(SYSTEM_EFFECT_ID == DnloadID)
  1205. {
  1206. // stop has no meaning for raw force
  1207. return S_FALSE;
  1208. }
  1209. else
  1210. {
  1211. // Special case RTC Spring ID
  1212. if(SYSTEM_RTCSPRING_ALIAS_ID == DnloadID)
  1213. DnloadID = SYSTEM_RTCSPRING_ID; // Jolt returned ID0 for RTC Spring
  1214. // so return send alias ID
  1215. }
  1216. return (CMD_StopEffect((DNHANDLE) DnloadID));
  1217. }
  1218. // ----------------------------------------------------------------------------
  1219. // Function: GetEffectStatus
  1220. //
  1221. // Purpose:
  1222. // Parameters: DWORD dwDeviceID - Device ID
  1223. // DWORD DnloadID - Download ID to get Status
  1224. // LPDWORD pdwStatusCode - Pointer to a DWORD for Status
  1225. //
  1226. //
  1227. // Returns: SUCCESS or Error code
  1228. // Status Code: DEV_STS_EFFECT_STOPPED
  1229. // DEV_STS_EFFECT_RUNNING
  1230. //
  1231. // Algorithm:
  1232. // ----------------------------------------------------------------------------
  1233. HRESULT CImpIDirectInputEffectDriver::GetEffectStatus(
  1234. IN DWORD dwDeviceID,
  1235. IN DWORD DnloadID,
  1236. OUT LPDWORD pdwStatusCode)
  1237. {
  1238. HRESULT hRet = SUCCESS;
  1239. #ifdef _DEBUG
  1240. g_CriticalSection.Enter();
  1241. wsprintf(g_cMsg, "GetEffectStatus, DnloadID=%d\r\n", DnloadID);
  1242. OutputDebugString(g_cMsg);
  1243. g_CriticalSection.Leave();
  1244. #endif
  1245. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  1246. // Special case RTC Spring ID
  1247. if(SYSTEM_RTCSPRING_ALIAS_ID == DnloadID)
  1248. DnloadID = SYSTEM_RTCSPRING_ID; // Jolt returned ID0 for RTC Spring
  1249. // so return send alias ID
  1250. assert(pdwStatusCode);
  1251. BYTE bStatusCode = SWDEV_STS_EFFECT_STOPPED;
  1252. hRet = g_pJoltMidi->GetEffectStatus(DnloadID, &bStatusCode);
  1253. if (SUCCESS != hRet) return hRet;
  1254. if (SWDEV_STS_EFFECT_RUNNING == bStatusCode)
  1255. *pdwStatusCode = DIEGES_PLAYING;
  1256. else
  1257. *pdwStatusCode = NULL; // Stopped
  1258. return (hRet);
  1259. }