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.

4126 lines
132 KiB

  1. //@doc
  2. /******************************************************
  3. **
  4. ** @module EFFECT.CPP | InternalEffect implementation file
  5. **
  6. ** Description:
  7. **
  8. ** History:
  9. ** Created 1/05/98 Matthew L. Coill (mlc)
  10. **
  11. ** 23-Mar-99 waltw IsReallyPlaying now uses data returned by
  12. ** Transmit instead of obsolete GetStatusGateData
  13. **
  14. **
  15. ** (c) 1986-1998 Microsoft Corporation. All Rights Reserved.
  16. ******************************************************/
  17. #include "Effect.h"
  18. #include "DPack.h"
  19. #include "DTrans.h"
  20. #include "FFDevice.h"
  21. #include "joyregst.hpp"
  22. #include "Registry.h"
  23. #include "CritSec.h"
  24. #include "Midi_Obj.hpp"
  25. #include <math.h>
  26. DWORD g_TotalModifiable = DIEP_DURATION | DIEP_SAMPLEPERIOD | DIEP_GAIN | DIEP_TRIGGERBUTTON |
  27. DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE |
  28. DIEP_TYPESPECIFICPARAMS;
  29. //#define ZEP_PRODUCT_ID 0x7F
  30. #define ZEP_PRODUCT_ID 0x15
  31. #define DOWNLOAD_OP_200 0x02
  32. #define STORE_ACTION_200 0x00
  33. #define PLAYSUPER_ACTION_200 0x01
  34. #define PLAYSOLO_ACTION_200 0x02
  35. #define AXIS_ANGLE_200 0x00
  36. #define AXIS_X_200 0x01
  37. #define AXIS_Y_200 0x02
  38. // VFX Default items
  39. #define DEFAULT_VFX_SAMPLEPERIOD 2000
  40. #define DEFAULT_VFX_EFFECT_DIRECTION 0
  41. #define DEFAULT_VFX_EFFECT_GAIN 10000
  42. #define DEFAULT_VFX_EFFECT_DURATION 1000
  43. // Max DIDistance = 10,000 so 10,000/100(percent) = 100
  44. #define DIDISTANCE_TO_PERCENT 100
  45. #define COEFFICIENT_SCALE_1XX 100
  46. #define DURATION_SCALE_1XX 1000
  47. #define GAIN_PERCENTAGE_SCALE 100
  48. #define FREQUENCY_SCALE_1XX 1000000
  49. #define TIME_SCALE_1XX 1000
  50. #define ENVELOPE_TIME_TICKS_1XX 2
  51. #define DURATION_SCALE_200 2000
  52. #define ANGLE_SCALE_200 281.25
  53. #define POSITIVE_PERCENT_SCALE 1.588
  54. #define FRICTION_SCALE_200 157.5
  55. #define GAIN_SCALE_200 78.7
  56. #define PHASE_SCALE_200 2.197
  57. #define WAVELET_SCALE_200 39.215
  58. //#define WAVELET_DISTANCE_200 1215
  59. #define WAVELET_DISTANCE_200 2440
  60. //#define WAVELET_DISTANCE_SCALE_200 39.193
  61. #define WAVELET_DISTANCE_SCALE_200 78.74
  62. #define BEHAVIOUR_CENTER_SCALE_200 158
  63. #define BEHAVIOUR_CENTER_200 63
  64. #define MAX_TIME_200 32766000
  65. // Mofidify index for version 200
  66. #define INDEX_BE_DURATION_200 0
  67. #define INDEX_DELAY_200 1
  68. #define INDEX_DIRECTIONANGLE_200 2
  69. #define INDEX_D1F1_200 (BYTE)3
  70. #define INDEX_D2F2_200 4
  71. #define INDEX_D3F3_200 5
  72. #define INDEX_D4F4_200 6
  73. #define INDEX_BE_BUTTONMAP_200 7
  74. #define INDEX_BE_BUTTONREPEAT_200 8
  75. #define INDEX_BE_GAIN_200 9
  76. #define INDEX_BE_CENTER_200 10
  77. #define INDEX_BE_REPEAT_200 11
  78. // Friction Modify Indecies
  79. #define INDEX_FE_DURATION_200 0
  80. #define INDEX_FE_DELAY_200 1
  81. #define INDEX_FE_DIRECTIONANGLE_200 2
  82. #define INDEX_FE_COEEFICIENT_200 3
  83. #define INDEX_FE_BUTTONMAP_200 4
  84. #define INDEX_FE_BUTTONREPEAT_200 5
  85. #define INDEX_FE_GAIN_200 6
  86. #define INDEX_FE_REPEAT_200 7
  87. // CustomForce Modify Indecies
  88. #define INDEX_CF_DURATION_200 0
  89. #define INDEX_CF_DELAY_200 1
  90. #define INDEX_CF_DIRECTIONANGLE_200 2
  91. #define INDEX_CF_GAIN_200 3
  92. #define INDEX_CF_STARTPERCENT_200 4
  93. #define INDEX_CF_ATTTACK_TIME_200 5
  94. #define INDEX_CF_SUSTAINPERCENT_200 6
  95. #define INDEX_CF_FADESTART_200 7
  96. #define INDEX_CF_ENDPERCENT_200 8
  97. #define INDEX_CF_OFFSET_200 9
  98. #define INDEX_CF_FORCESAMPLE_200 10
  99. #define INDEX_CF_SAMPLE_PERIOD_200 11
  100. #define INDEX_CF_BUTTONMAP_200 12
  101. #define INDEX_CF_BUTTONREPEAT_200 13
  102. #define INDEX_CF_REPEAT_200 14
  103. // Periodic Effect Modify Indecies
  104. #define INDEX_PE_DURATION_200 0
  105. #define INDEX_PE_DIRECTIONANGLE_200 2
  106. #define INDEX_PE_GAIN_200 3
  107. #define INDEX_PE_PHASE_200 4
  108. #define INDEX_PE_STARTPERCENT_200 5
  109. #define INDEX_PE_ATTTACK_TIME_200 6
  110. #define INDEX_PE_SUSTAINPERCENT_200 7
  111. #define INDEX_PE_FADESTART_200 8
  112. #define INDEX_PE_ENDPERCENT_200 9
  113. #define INDEX_PE_PERIOD_200 10
  114. #define INDEX_PE_OFFSET_200 11
  115. #define INDEX_PE_SAMPLE_PERIOD_200 12
  116. #define INDEX_PE_BUTTONMAP_200 13
  117. #define INDEX_PE_BUTTONREPEAT_200 14
  118. #define INDEX_PE_REPEAT_200 15
  119. // ConstantForce Effect Modify Indecies
  120. #define INDEX_CE_DURATION_200 0
  121. #define INDEX_CE_GAIN_200 3
  122. #define INDEX_CE_STARTPERCENT_200 4
  123. #define INDEX_CE_ATTTACK_TIME_200 5
  124. #define INDEX_CE_SUSTAINPERCENT_200 6
  125. #define INDEX_CE_FADESTART_200 7
  126. #define INDEX_CE_ENDPERCENT_200 8
  127. #define INDEX_CE_MAGNITUDE_200 9
  128. #define INDEX_CE_BUTTONMAP_200 11
  129. #define INDEX_CE_BUTTONREPEAT_200 12
  130. #define INDEX_CE_REPEAT_200 13
  131. // Default system param defines (for 1XX)
  132. #define DEF_XY_CONST 22500
  133. #define DEF_ROT_CONST 17272
  134. #define DEF_SLDR_CONST 126
  135. #define DEF_AJ_POS 4
  136. #define DEF_AJ_ROT 2
  137. #define DEF_AJ_SLDR 2
  138. #define DEF_SPR_SCL ((DWORD)-256)
  139. #define DEF_BMP_SCL 60
  140. #define DEF_DMP_SCL ((DWORD)-3436)
  141. #define DEF_INERT_SCL ((DWORD)-2562)
  142. #define DEF_VEL_OFFSET_SCL 54
  143. #define DEF_ACC_OFFSET_SCL 40
  144. #define DEF_Y_MOT_BOOST 19661
  145. #define DEF_X_MOT_SATURATION 254
  146. BYTE g_TriggerMap1XX[] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80 };
  147. BYTE g_TriggerMap200[] = { 0x00, 0x01, 0x02, 0x04, 0x10, 0x20, 0x40, 0x80, 0x08, 0x08, 0x08 };
  148. /******************* Envelope1XX class *******************/
  149. Envelope1XX::Envelope1XX(DIENVELOPE* pDIEnvelope, DWORD baseLine, DWORD duration)
  150. {
  151. // Zero out this monster
  152. ::memset(this, 0, sizeof(Envelope1XX));
  153. if (pDIEnvelope == NULL) {
  154. m_SustainTime = duration;
  155. m_SustainPercent = 100;
  156. return;
  157. }
  158. // Attack/sustain/decay sum to duration
  159. m_AttackTime = pDIEnvelope->dwAttackTime/ENVELOPE_TIME_TICKS_1XX;
  160. if (duration != INFINITE) { // Inifinite duration has only attack
  161. m_SustainTime = (duration- pDIEnvelope->dwFadeTime)/ENVELOPE_TIME_TICKS_1XX;
  162. }
  163. // What is the real maximum
  164. DWORD maxAmp = baseLine;
  165. if (maxAmp < pDIEnvelope->dwAttackLevel) {
  166. maxAmp = pDIEnvelope->dwAttackLevel;
  167. }
  168. if (maxAmp < pDIEnvelope->dwFadeLevel) {
  169. maxAmp = pDIEnvelope->dwFadeLevel;
  170. }
  171. maxAmp /= 100; // For percentage conversion
  172. if (maxAmp == 0) { // Avoid a nasty division error
  173. m_SustainPercent = 100; // Sustain is full (others are 0)
  174. } else {
  175. m_StartPercent = pDIEnvelope->dwAttackLevel/maxAmp;
  176. m_SustainPercent = baseLine/maxAmp;
  177. m_EndPercent = pDIEnvelope->dwFadeLevel/maxAmp;
  178. }
  179. }
  180. /******************* Envelope200 class *******************/
  181. Envelope200::Envelope200(DIENVELOPE* pDIEnvelope, DWORD sustain, DWORD duration, HRESULT& hr)
  182. {
  183. // Zero out this monster
  184. ::memset(this, 0, sizeof(Envelope200));
  185. m_FadeStart = WORD(duration/DURATION_SCALE_200);
  186. DWORD calc = sustain; // -- Modifcation above, now done on gain
  187. // DI Doesn't specify an envelope
  188. if (pDIEnvelope == NULL) {
  189. m_SustainPercent = BYTE(calc/GAIN_SCALE_200); // Base sustain of magnitude
  190. return;
  191. }
  192. // The sun of attack and fade must be less than MAX_TIME
  193. if ((pDIEnvelope->dwAttackTime + pDIEnvelope->dwFadeTime) > MAX_TIME_200) {
  194. hr = DI_TRUNCATED;
  195. if (pDIEnvelope->dwAttackTime > MAX_TIME_200) {
  196. pDIEnvelope->dwAttackTime = MAX_TIME_200;
  197. }
  198. pDIEnvelope->dwFadeTime = MAX_TIME_200 - pDIEnvelope->dwAttackTime;
  199. }
  200. // Attack/sustain/decay sum to duration
  201. m_AttackTime = WORD(pDIEnvelope->dwAttackTime/DURATION_SCALE_200);
  202. if (duration != INFINITE) { // Inifinite duration has only attack (fade-time == DURATION)
  203. m_FadeStart = WORD((duration - pDIEnvelope->dwFadeTime)/DURATION_SCALE_200);
  204. if (m_FadeStart < m_AttackTime) { // We don't want to fade before the end of the attack!
  205. m_FadeStart = m_AttackTime;
  206. }
  207. }
  208. m_SustainPercent = BYTE(float(calc)/GAIN_SCALE_200);
  209. calc = pDIEnvelope->dwAttackLevel;
  210. if (calc > 10000) {
  211. calc = 10000;
  212. hr = DI_TRUNCATED;
  213. }
  214. m_StartPercent = BYTE(float(calc)/GAIN_SCALE_200);
  215. calc = (pDIEnvelope->dwFadeLevel);
  216. if (calc > 10000) {
  217. calc = 10000;
  218. hr = DI_TRUNCATED;
  219. }
  220. m_EndPercent = BYTE(float(calc)/GAIN_SCALE_200);
  221. }
  222. /******************* InternalEffect class ******************/
  223. InternalEffect::InternalEffect() :
  224. m_EffectID(0),
  225. m_DeviceEffectID(0),
  226. m_Duration(0),
  227. m_Gain(0),
  228. m_TriggerPlayButton(0),
  229. m_AxisMask(0),
  230. m_EffectAngle(0),
  231. m_PercentX(0),
  232. m_PercentY(0),
  233. m_PercentAdjustment(0),
  234. m_AxesReversed(FALSE),
  235. m_IsPossiblyPlaying(FALSE)
  236. {
  237. }
  238. InternalEffect::~InternalEffect()
  239. {
  240. }
  241. // Static Creation Functions
  242. InternalEffect* InternalEffect::CreateSpring()
  243. {
  244. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  245. return new BehaviouralEffect1XX(ET_BE_SPRING);
  246. } else { // Assume newer firmware versions will come with an update, or work with this
  247. return new BehaviouralEffect200(ET_SPRING_200);
  248. }
  249. }
  250. InternalEffect* InternalEffect::CreateDamper()
  251. {
  252. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  253. return new BehaviouralEffect1XX(ET_BE_DAMPER);
  254. } else { // Assume newer firmware versions will come with an update, or work with this
  255. return new BehaviouralEffect200(ET_DAMPER_200);
  256. }
  257. }
  258. InternalEffect* InternalEffect::CreateInertia()
  259. {
  260. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  261. return new BehaviouralEffect1XX(ET_BE_INERTIA);
  262. } else { // Assume newer firmware versions will come with an update, or work with this
  263. return new BehaviouralEffect200(ET_INERTIA_200);
  264. }
  265. }
  266. InternalEffect* InternalEffect::CreateFriction()
  267. {
  268. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  269. return new FrictionEffect1XX();
  270. } else { // Assume newer firmware versions will come with an update, or work with this
  271. return new FrictionEffect200();
  272. }
  273. }
  274. InternalEffect* InternalEffect::CreateRTCSpring()
  275. {
  276. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  277. return new RTCSpring1XX();
  278. } else { // Assume newer firmware versions will come with an update, or work with this
  279. return new RTCSpring200();
  280. }
  281. }
  282. InternalEffect* InternalEffect::CreateSystemEffect()
  283. {
  284. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  285. return new SystemEffect1XX();
  286. } else { // Assume newer firmware versions will come with an update, or work with this
  287. return NULL; // NYI
  288. }
  289. }
  290. InternalEffect* InternalEffect::CreateSine()
  291. {
  292. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  293. return new PeriodicEffect1XX(ET_SE_SINE);
  294. } else { // Assume newer firmware versions will come with an update, or work with this
  295. return new PeriodicEffect200(ET_SINE_200);
  296. }
  297. }
  298. InternalEffect* InternalEffect::CreateSquare()
  299. {
  300. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  301. return new PeriodicEffect1XX(ET_SE_SQUAREHIGH);
  302. } else { // Assume newer firmware versions will come with an update, or work with this
  303. return new PeriodicEffect200(ET_SQUARE_200);
  304. }
  305. }
  306. InternalEffect* InternalEffect::CreateTriangle()
  307. {
  308. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  309. return new PeriodicEffect1XX(ET_SE_TRIANGLEUP);
  310. } else { // Assume newer firmware versions will come with an update, or work with this
  311. return new PeriodicEffect200(ET_TRIANGLE_200);
  312. }
  313. }
  314. InternalEffect* InternalEffect::CreateSawtoothUp()
  315. {
  316. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  317. return NULL;
  318. } else { // Assume newer firmware versions will come with an update, or work with this
  319. return new SawtoothEffect200(TRUE);
  320. }
  321. }
  322. InternalEffect* InternalEffect::CreateSawtoothDown()
  323. {
  324. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  325. return NULL;
  326. } else { // Assume newer firmware versions will come with an update, or work with this
  327. return new SawtoothEffect200(FALSE);
  328. }
  329. }
  330. InternalEffect* InternalEffect::CreateCustomForce()
  331. {
  332. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  333. return NULL;
  334. } else { // Assume newer firmware versions will come with an update, or work with this
  335. return new CustomForceEffect200();
  336. }
  337. }
  338. InternalEffect* InternalEffect::CreateConstantForce()
  339. {
  340. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  341. return new PeriodicEffect1XX(ET_SE_CONSTANT_FORCE);
  342. } else { // Assume newer firmware versions will come with an update, or work with this
  343. return new ConstantForceEffect200();
  344. }
  345. }
  346. InternalEffect* InternalEffect::CreateRamp()
  347. {
  348. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  349. return new PeriodicEffect1XX(ET_SE_RAMPUP);
  350. } else { // Assume newer firmware versions will come with an update, or work with this
  351. return new RampEffect200();
  352. }
  353. }
  354. InternalEffect* InternalEffect::CreateWall()
  355. {
  356. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  357. return NULL;
  358. } else { // Assume newer firmware versions will come with an update, or work with this
  359. return new WallEffect200();
  360. }
  361. }
  362. /*
  363. InternalEffect* InternalEffect::CreateDelay()
  364. {
  365. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  366. return new DelayEffect1XX();
  367. } else { // Assume newer firmware versions will come with an update, or work with this
  368. return new BehaviouralEffect1XX(ET_DELAY_200);
  369. }
  370. }
  371. */
  372. InternalEffect* InternalEffect::CreateFromVFX(const DIEFFECT& diOriginal, EFFECT effect, ENVELOPE envelope, BYTE* pEffectParms, DWORD paramSize, HRESULT& hr)
  373. {
  374. InternalEffect* pReturnEffect = NULL;
  375. if (g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) {
  376. return NULL;
  377. }
  378. // Fill in the DIEFFECT structure
  379. DIEFFECT diEffect;
  380. diEffect.dwSize = sizeof(DIEFFECT);
  381. diEffect.dwFlags = DIEFF_POLAR | DIEFF_OBJECTOFFSETS;
  382. // Only set from file, if default is asked for
  383. if (diOriginal.dwDuration == DEFAULT_VFX_EFFECT_DURATION) {
  384. diEffect.dwDuration = effect.m_Duration * 1000; // Zero will work as infinite just fine
  385. } else {
  386. diEffect.dwDuration = diOriginal.dwDuration;
  387. }
  388. // If zero is sent use the one from the file else use the one sent
  389. if (diOriginal.dwSamplePeriod == 0) {
  390. diEffect.dwSamplePeriod = 1000000/effect.m_ForceOutputRate;
  391. } else {
  392. diEffect.dwSamplePeriod = diOriginal.dwSamplePeriod;
  393. }
  394. // Only set from file if default is sent
  395. if (diOriginal.dwGain == DEFAULT_VFX_EFFECT_GAIN) {
  396. diEffect.dwGain = effect.m_Gain * 100;
  397. } else {
  398. diEffect.dwGain = diOriginal.dwGain;
  399. }
  400. // Need to find which bit is set
  401. if (diOriginal.dwTriggerButton == DIEB_NOTRIGGER) {
  402. if (effect.m_ButtonPlayMask == 0) {
  403. diEffect.dwTriggerButton = DIEB_NOTRIGGER;
  404. } else {
  405. DWORD butt = effect.m_ButtonPlayMask;
  406. short int buttNum = 0;
  407. while ((butt & 1) == 0) {
  408. butt >>= 1;
  409. buttNum++;
  410. ASSUME(buttNum >= 32);
  411. }
  412. diEffect.dwTriggerButton = DIDFT_MAKEINSTANCE(buttNum);
  413. }
  414. diEffect.dwTriggerRepeatInterval = 0;
  415. } else {
  416. diEffect.dwTriggerButton = diOriginal.dwTriggerButton;
  417. diEffect.dwTriggerRepeatInterval = diOriginal.dwTriggerRepeatInterval;
  418. }
  419. diEffect.cbTypeSpecificParams = 0;
  420. diEffect.lpvTypeSpecificParams = NULL;
  421. diEffect.cAxes = 2;
  422. diEffect.rgdwAxes = new DWORD[2];
  423. if (diEffect.rgdwAxes == NULL)
  424. {
  425. goto do_dealloc;
  426. }
  427. diEffect.rgdwAxes[0] = DIJOFS_X;
  428. diEffect.rgdwAxes[1] = DIJOFS_Y;
  429. diEffect.rglDirection = new LONG[2];
  430. if (diEffect.rglDirection == NULL)
  431. {
  432. goto do_dealloc;
  433. }
  434. if (diOriginal.rglDirection[0] == DEFAULT_VFX_EFFECT_DIRECTION) {
  435. diEffect.rglDirection[0] = effect.m_DirectionAngle2D * 100;
  436. } else {
  437. diEffect.rglDirection[0] = diOriginal.rglDirection[0];
  438. }
  439. diEffect.rglDirection[1] = 0;
  440. // Envelope
  441. diEffect.lpEnvelope = new DIENVELOPE;
  442. if (diEffect.lpEnvelope == NULL)
  443. {
  444. goto do_dealloc;
  445. }
  446. if (diOriginal.lpEnvelope != NULL) {
  447. ::memcpy(diEffect.lpEnvelope, diOriginal.lpEnvelope, sizeof(DIENVELOPE));
  448. } else {
  449. diEffect.lpEnvelope->dwSize = sizeof(DIENVELOPE);
  450. diEffect.lpEnvelope->dwAttackLevel = envelope.m_StartAmp * (diEffect.dwGain/100);
  451. diEffect.lpEnvelope->dwFadeLevel = envelope.m_EndAmp * (diEffect.dwGain/100);
  452. diEffect.dwGain = diEffect.dwGain/100 * envelope.m_SustainAmp;
  453. if (envelope.m_Type == TIME) { // time is in MSECs
  454. diEffect.lpEnvelope->dwAttackTime = envelope.m_Attack * 1000;
  455. diEffect.lpEnvelope->dwFadeTime = envelope.m_Decay * 1000;
  456. } else { // Percentage of total time
  457. diEffect.lpEnvelope->dwAttackTime = envelope.m_Attack * (diEffect.dwDuration/100);
  458. diEffect.lpEnvelope->dwFadeTime = envelope.m_Decay * (diEffect.dwDuration/100);
  459. }
  460. }
  461. switch(effect.m_Type) {
  462. case EF_BEHAVIOR: {
  463. DICONDITION* pDICondition = new DICONDITION[2];
  464. if (pDICondition == NULL)
  465. {
  466. goto do_dealloc;
  467. }
  468. ::memset(pDICondition, 0, sizeof(DICONDITION) * 2);
  469. diEffect.cbTypeSpecificParams = sizeof(DICONDITION)*2;
  470. diEffect.lpvTypeSpecificParams = pDICondition;
  471. switch (effect.m_SubType) { // Switch for parameter filling
  472. case BE_SPRING_2D:
  473. case BE_DAMPER_2D:
  474. case BE_INERTIA_2D: {
  475. BE_SPRING_2D_PARAM* pParams = (BE_SPRING_2D_PARAM*)pEffectParms;
  476. pDICondition[1].lOffset = pParams->m_YAxisCenter * 100;
  477. pDICondition[1].lPositiveCoefficient = pParams->m_YKconstant * 100;
  478. pDICondition[1].lNegativeCoefficient = pDICondition[1].lPositiveCoefficient;
  479. pDICondition[1].dwPositiveSaturation = 10000;
  480. pDICondition[1].dwNegativeSaturation = 10000;
  481. // purposely fall through for first axis
  482. }
  483. case BE_SPRING:
  484. case BE_DAMPER:
  485. case BE_INERTIA: {
  486. BE_SPRING_PARAM* pParams = (BE_SPRING_PARAM*)pEffectParms;
  487. pDICondition[0].lOffset = pParams->m_AxisCenter * 100;
  488. pDICondition[0].lPositiveCoefficient = pParams->m_Kconstant * 100;
  489. pDICondition[0].lNegativeCoefficient = pDICondition[0].lPositiveCoefficient;
  490. pDICondition[0].dwPositiveSaturation = 10000;
  491. pDICondition[0].dwNegativeSaturation = 10000;
  492. break;
  493. }
  494. case BE_FRICTION_2D: {
  495. BE_FRICTION_2D_PARAM* pParams = (BE_FRICTION_2D_PARAM*)pEffectParms;
  496. pDICondition[1].lPositiveCoefficient = pParams->m_YFconstant * 100;
  497. pDICondition[1].lNegativeCoefficient = pDICondition[1].lPositiveCoefficient;
  498. pDICondition[1].dwPositiveSaturation = 10000;
  499. pDICondition[1].dwNegativeSaturation = 10000;
  500. // purposely fall through for first axis
  501. }
  502. case BE_FRICTION: {
  503. BE_FRICTION_PARAM* pParams = (BE_FRICTION_PARAM*)pEffectParms;
  504. pDICondition[0].lPositiveCoefficient = pParams->m_Fconstant * 100;
  505. pDICondition[0].lNegativeCoefficient = pDICondition[0].lPositiveCoefficient;
  506. pDICondition[0].dwPositiveSaturation = 10000;
  507. pDICondition[0].dwNegativeSaturation = 10000;
  508. break;
  509. }
  510. case BE_WALL: { // This one is strangly simple
  511. delete pDICondition;
  512. diEffect.cbTypeSpecificParams = sizeof(BE_WALL_PARAM);
  513. diEffect.lpvTypeSpecificParams = new BE_WALL_PARAM;
  514. if (diEffect.lpvTypeSpecificParams != NULL) {
  515. ::memcpy(diEffect.lpvTypeSpecificParams, pEffectParms, sizeof(BE_WALL_PARAM));
  516. // need to convert to DI values
  517. BE_WALL_PARAM* pWallParms = (BE_WALL_PARAM*)(diEffect.lpvTypeSpecificParams);
  518. pWallParms->m_WallConstant = pWallParms->m_WallConstant * 100;
  519. pWallParms->m_WallAngle = pWallParms->m_WallAngle * 100;
  520. pWallParms->m_WallDistance = pWallParms->m_WallDistance * 100;
  521. }
  522. break;
  523. }
  524. }
  525. switch (effect.m_SubType) { // Switch for Creation
  526. case BE_SPRING:
  527. case BE_SPRING_2D: {
  528. pReturnEffect = CreateSpring();
  529. break;
  530. }
  531. case BE_DAMPER:
  532. case BE_DAMPER_2D: {
  533. pReturnEffect = CreateDamper();
  534. break;
  535. }
  536. case BE_INERTIA:
  537. case BE_INERTIA_2D: {
  538. pReturnEffect = CreateInertia();
  539. break;
  540. }
  541. case BE_FRICTION:
  542. case BE_FRICTION_2D: {
  543. pReturnEffect = CreateFriction();
  544. break;
  545. }
  546. case BE_WALL: {
  547. pReturnEffect = CreateWall();
  548. break;
  549. }
  550. }
  551. pDICondition = NULL;
  552. break;
  553. }
  554. case EF_USER_DEFINED: {
  555. UD_PARAM* pParams = (UD_PARAM*)pEffectParms;
  556. DICUSTOMFORCE* pUserDefined = new DICUSTOMFORCE;
  557. if (pUserDefined != NULL) {
  558. diEffect.cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
  559. diEffect.lpvTypeSpecificParams = pUserDefined;
  560. pUserDefined->cChannels = 1;
  561. pUserDefined->dwSamplePeriod = diEffect.dwSamplePeriod;
  562. pUserDefined->cSamples = pParams->m_NumVectors;
  563. pUserDefined->rglForceData = pParams->m_pForceData; // Don't copy the data here, just push the pointer
  564. for (UINT nextSample = 0; nextSample < pUserDefined->cSamples; nextSample++) {
  565. ASSUME(pUserDefined->rglForceData[nextSample] <= 100 && pUserDefined->rglForceData[nextSample] >= -100); // Assume it is in the SWForce range (-100..100)
  566. pUserDefined->rglForceData[nextSample] *= 100;
  567. }
  568. pReturnEffect = CreateCustomForce();
  569. }
  570. pUserDefined = NULL;
  571. break;
  572. }
  573. case EF_SYNTHESIZED: { // Fill in the periodic structure
  574. SE_PARAM* pParams = (SE_PARAM*)pEffectParms;
  575. if (effect.m_SubType == SE_CONSTANT_FORCE) { // Special case
  576. DICONSTANTFORCE* pCForce= new DICONSTANTFORCE;
  577. if (pCForce != NULL) {
  578. diEffect.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
  579. diEffect.lpvTypeSpecificParams = pCForce;
  580. pCForce->lMagnitude = pParams->m_MaxAmp * 100;
  581. pCForce = NULL;
  582. pReturnEffect = CreateConstantForce();
  583. }
  584. break;
  585. }
  586. if (effect.m_SubType == SE_RAMPUP || effect.m_SubType == SE_RAMPDOWN) { // Yet another special case
  587. DIRAMPFORCE* pRForce = new DIRAMPFORCE;
  588. if (pRForce != NULL) {
  589. diEffect.cbTypeSpecificParams = sizeof(DIRAMPFORCE);
  590. diEffect.lpvTypeSpecificParams = pRForce;
  591. if (effect.m_SubType == SE_RAMPUP) {
  592. pRForce->lStart = pParams->m_MinAmp * 100;
  593. pRForce->lEnd = pParams->m_MaxAmp * 100;
  594. } else { // RampDown (special case of a special case)
  595. pRForce->lStart = pParams->m_MaxAmp * 100;
  596. pRForce->lEnd = pParams->m_MinAmp * 100;
  597. }
  598. pRForce = NULL;
  599. pReturnEffect = CreateRamp();
  600. }
  601. break;
  602. }
  603. if (pParams->m_SampleRate == 0) {
  604. pParams->m_SampleRate = DEFAULT_JOLT_FORCE_RATE;
  605. }
  606. if (effect.m_ForceOutputRate == 0) {
  607. effect.m_ForceOutputRate = DEFAULT_JOLT_FORCE_RATE;
  608. }
  609. DIPERIODIC* pPeriodic = new DIPERIODIC;
  610. if (pPeriodic == NULL) {
  611. break;
  612. }
  613. diEffect.cbTypeSpecificParams = sizeof(DIPERIODIC);
  614. diEffect.lpvTypeSpecificParams = pPeriodic;
  615. pPeriodic->dwMagnitude = (pParams->m_MaxAmp - pParams->m_MinAmp)/2 * 100;
  616. pPeriodic->lOffset = (pParams->m_MaxAmp + pParams->m_MinAmp)/2 * 100;
  617. pPeriodic->dwPhase = 0;
  618. if (pParams->m_Freq == 0) { // Avoid division by 0
  619. pPeriodic->dwPeriod = 0;
  620. } else {
  621. pPeriodic->dwPeriod = 1000000 / pParams->m_Freq;
  622. }
  623. switch (effect.m_SubType) {
  624. case SE_SINE: {
  625. pReturnEffect = CreateSine();
  626. break;
  627. }
  628. case SE_COSINE: {
  629. pPeriodic->dwPhase = 9000;
  630. pReturnEffect = CreateSine();
  631. break;
  632. }
  633. case SE_SQUAREHIGH: {
  634. pReturnEffect = CreateSquare();
  635. break;
  636. }
  637. case SE_SQUARELOW: {
  638. pPeriodic->dwPhase = 18000;
  639. pReturnEffect = CreateSquare();
  640. break;
  641. }
  642. case SE_TRIANGLEUP: {
  643. pReturnEffect = CreateTriangle();
  644. break;
  645. }
  646. case SE_TRIANGLEDOWN: {
  647. pPeriodic->dwPhase = 18000;
  648. pReturnEffect = CreateTriangle();
  649. break;
  650. }
  651. case SE_SAWTOOTHUP: {
  652. pReturnEffect = CreateSawtoothUp();
  653. break;
  654. }
  655. case SE_SAWTOOTHDOWN: {
  656. pReturnEffect = CreateSawtoothDown();
  657. break;
  658. }
  659. }
  660. pPeriodic = NULL;
  661. break;
  662. }
  663. case EF_RTC_SPRING: {
  664. diEffect.cbTypeSpecificParams = sizeof(RTCSPRING_PARAM);
  665. diEffect.lpvTypeSpecificParams = new RTCSPRING_PARAM;
  666. if (diEffect.lpvTypeSpecificParams != NULL) {
  667. ::memcpy(diEffect.lpvTypeSpecificParams, pEffectParms, sizeof(RTCSPRING_PARAM));
  668. pReturnEffect = CreateRTCSpring();
  669. }
  670. break;
  671. }
  672. }
  673. if (pReturnEffect != NULL) {
  674. hr = pReturnEffect->Create(diEffect);
  675. if (FAILED(hr)) {
  676. delete pReturnEffect;
  677. pReturnEffect = NULL;
  678. }
  679. }
  680. do_dealloc:
  681. // Deallocate allocated DIEFFECT stuff
  682. if (diEffect.lpvTypeSpecificParams != NULL) {
  683. delete diEffect.lpvTypeSpecificParams;
  684. }
  685. if (diEffect.rglDirection != NULL) {
  686. delete diEffect.rglDirection;
  687. }
  688. if (diEffect.rgdwAxes != NULL) {
  689. delete diEffect.rgdwAxes;
  690. }
  691. if (diEffect.lpEnvelope != NULL) {
  692. delete diEffect.lpEnvelope;
  693. }
  694. return pReturnEffect;
  695. }
  696. HRESULT InternalEffect::Create(const DIEFFECT& diEffect)
  697. {
  698. // We don't support more than 2 axes, and 0 is probably an error
  699. if ((diEffect.cAxes > 2) || (diEffect.cAxes == 0)) {
  700. return SFERR_NO_SUPPORT;
  701. }
  702. HRESULT hr = SUCCESS;
  703. // Set up the axis mask
  704. m_AxisMask = 0;
  705. for (unsigned int axisIndex = 0; axisIndex < diEffect.cAxes; axisIndex++) {
  706. DWORD axisNumber = DIDFT_GETINSTANCE(diEffect.rgdwAxes[axisIndex]);
  707. m_AxisMask |= 1 << axisNumber;
  708. }
  709. m_AxesReversed = (DIDFT_GETINSTANCE(diEffect.rgdwAxes[0]) == 1);
  710. // Set the trigger play button
  711. if (diEffect.dwTriggerButton != DIEB_NOTRIGGER) {
  712. m_TriggerPlayButton = DIDFT_GETINSTANCE(diEffect.dwTriggerButton) + 1;
  713. if (m_TriggerPlayButton == 9) { // We don't support button 9 playback (start button?)
  714. return SFERR_NO_SUPPORT;
  715. }
  716. if (m_TriggerPlayButton > 10) { // We don't support mapping above 10
  717. return SFERR_NO_SUPPORT;
  718. }
  719. } else {
  720. m_TriggerPlayButton = 0;
  721. }
  722. m_TriggerRepeat = diEffect.dwTriggerRepeatInterval;
  723. if (m_TriggerRepeat > MAX_TIME_200) {
  724. hr = DI_TRUNCATED;
  725. m_TriggerRepeat = MAX_TIME_200;
  726. }
  727. // Check coordinate sytems and change to polar
  728. if (diEffect.dwFlags & DIEFF_SPHERICAL) { // We don't support sperical (3 axis force)
  729. return SFERR_NO_SUPPORT; // .. since got by axis check, programmer goofed up
  730. }
  731. if (diEffect.dwFlags & DIEFF_POLAR) {
  732. if (diEffect.cAxes != 2) { // Polar coordinate must have two axes of data (because DX says so)
  733. return SFERR_INVALID_PARAM;
  734. }
  735. m_EffectAngle = diEffect.rglDirection[0]; // in [0] even if reversed
  736. if (m_AxesReversed) { // Indicates (-1, 0) as origin instead of (0, -1)
  737. m_EffectAngle += 27000;
  738. }
  739. m_EffectAngle %= 36000;
  740. } else if (diEffect.dwFlags & DIEFF_CARTESIAN) { // Convert to polar
  741. if (diEffect.cAxes == 1) { // Fairly easy conversion
  742. if (X_AXIS & m_AxisMask) {
  743. m_EffectAngle = 9000;
  744. } else {
  745. m_EffectAngle = 0;
  746. }
  747. } else { // Multiple axis cartiesian
  748. int xDirection = diEffect.rglDirection[0];
  749. int yDirection = diEffect.rglDirection[1];
  750. if (m_AxesReversed == TRUE) {
  751. yDirection = xDirection;
  752. xDirection = diEffect.rglDirection[1];
  753. }
  754. double angle = atan2(double(yDirection), double(xDirection)) * 180.0/3.14159;
  755. // Switch it to a proper quadrant integer
  756. int nAngle = 90;
  757. if (angle >= 0.0) {
  758. nAngle -= int(angle + 0.5);
  759. } else {
  760. nAngle -= int(angle - 0.5);
  761. }
  762. if (nAngle < 0) {
  763. nAngle += 360;
  764. } else if (nAngle >= 360) {
  765. nAngle -= 360;
  766. }
  767. m_EffectAngle = nAngle * 100;
  768. }
  769. } else { // What, is there some other format?
  770. ASSUME_NOT_REACHED();
  771. return SFERR_INVALID_PARAM; // Untill someone says otherwise there was an error
  772. }
  773. // Find the percent for each axis (for axis mapping)
  774. double projectionAngle = double(m_EffectAngle)/18000.0 * 3.14159; // Convert to radians
  775. // Sin^2(a) + Cos^2(a) = 1
  776. double xProj = ::sin(projectionAngle); // DI has 0 degs at (1, 0) not (0, 1)
  777. double yProj = ::cos(projectionAngle);
  778. xProj *= xProj;
  779. yProj *= yProj;
  780. m_PercentX = DWORD(xProj * 100.0 + 0.05);
  781. m_PercentY = DWORD(yProj * 100.0 + 0.05);
  782. // Duration and gain
  783. m_Duration = diEffect.dwDuration;
  784. if (m_Duration == INFINITE) {
  785. m_Duration = 0; // 0 represents infinite
  786. } else if (m_Duration > MAX_TIME_200) {
  787. hr = DI_TRUNCATED;
  788. m_Duration = MAX_TIME_200;
  789. }
  790. m_Gain = diEffect.dwGain;
  791. if (m_Gain > 10000) {
  792. hr = DI_TRUNCATED;
  793. m_Gain = 10000;
  794. }
  795. // Sample period
  796. m_SamplePeriod = diEffect.dwSamplePeriod;
  797. if (m_SamplePeriod > MAX_TIME_200) {
  798. hr = DI_TRUNCATED;
  799. m_SamplePeriod = MAX_TIME_200;
  800. } else if (m_SamplePeriod == 0) { // Indicates a default should be used
  801. m_SamplePeriod = 2000; // 500htz is the default (2000 micro-secs period)
  802. }
  803. return hr;
  804. }
  805. HRESULT InternalEffect::Modify(InternalEffect& diEffect, DWORD modFlags)
  806. {
  807. g_pDataPackager->ClearPackets();
  808. return SFERR_NO_SUPPORT;
  809. }
  810. BYTE InternalEffect::ComputeChecksum(const DataPacket& packet, short int numFields)
  811. {
  812. if (packet.m_pData == NULL) {
  813. ASSUME_NOT_REACHED();
  814. return 0;
  815. }
  816. BYTE checkSum = 0;
  817. for (short int index = 5; index < numFields; index++) { // Skip header
  818. checkSum += packet.m_pData[index];
  819. }
  820. return ((-checkSum) & 0x7f);
  821. }
  822. void InternalEffect::FillSysExHeader(DataPacket& packet) const
  823. {
  824. // SysEx Header
  825. packet.m_pData[0] = SYS_EX_CMD; // SysEX CMD
  826. packet.m_pData[1] = 0; // Escape to Manufacturer ID
  827. packet.m_pData[2] = MS_MANUFACTURER_ID & 0x7f; // Manufacturer High Byte
  828. packet.m_pData[3] = (MS_MANUFACTURER_ID >> 8) & 0x7f; // Manufacturer Low Byte (note shifted 8!)
  829. }
  830. void InternalEffect::FillHeader1XX(DataPacket& packet, BYTE effectType, BYTE effectID) const
  831. {
  832. FillSysExHeader(packet);
  833. packet.m_pData[4] = JOLT_PRODUCT_ID; // Product ID
  834. // What to do params
  835. packet.m_pData[5] = DNLOAD_DATA | DL_PLAY_STORE | X_AXIS | Y_AXIS; // OpCode
  836. packet.m_pData[6] = effectType; // Effect Type
  837. packet.m_pData[7] = effectID; // Effect or NEW_EFFECT_ID
  838. // Effect parms
  839. int duration = m_Duration/DURATION_SCALE_1XX;
  840. packet.m_pData[8] = BYTE(duration & 0x7F); // Duration Low MidiByte
  841. packet.m_pData[9] = BYTE(duration >> 7) & 0x7F; // Duration High MidiByte
  842. }
  843. void InternalEffect::FillHeader200(DataPacket& packet, BYTE effectType, BYTE effectID) const
  844. {
  845. FillSysExHeader(packet);
  846. packet.m_pData[4] = ZEP_PRODUCT_ID; // Product ID
  847. // What to do params
  848. // packet.m_pData[5] = DOWNLOAD_OP_200 | STORE_ACTION_200 | X_AXIS_200 | Y_AXIS_200; // OpCode
  849. packet.m_pData[5] = (DOWNLOAD_OP_200 << 4) | (STORE_ACTION_200 << 2) | AXIS_ANGLE_200; // OpCode
  850. packet.m_pData[6] = effectType; // Effect Type
  851. packet.m_pData[7] = effectID; // Effect or NEW_EFFECT_ID
  852. // Effect parms
  853. unsigned short int duration = 0;
  854. if (m_Duration != 0) {
  855. duration = unsigned short(m_Duration/DURATION_SCALE_200);
  856. if (duration == 0) {
  857. duration = 1; // We don't want to round down to 0 (infinite)
  858. }
  859. }
  860. packet.m_pData[8] = BYTE(duration & 0x7F); // Duration Low MidiByte
  861. packet.m_pData[9] = BYTE(duration >> 7) & 0x7F; // Duration High MidiByte
  862. }
  863. HRESULT InternalEffect::FillModifyPacket1XX(BYTE packetIndex, BYTE paramIndex, DWORD value) const
  864. {
  865. DataPacket* setIndexPacket = g_pDataPackager->GetPacket(packetIndex);
  866. if ((setIndexPacket == NULL) || (!setIndexPacket->AllocateBytes(3))) {
  867. g_pDataPackager->ClearPackets();
  868. return SFERR_DRIVER_ERROR;
  869. }
  870. setIndexPacket->m_pData[0] = EFFECT_CMD | DEFAULT_MIDI_CHANNEL;
  871. setIndexPacket->m_pData[1] = SET_INDEX | BYTE(paramIndex << 2);
  872. setIndexPacket->m_pData[2] = m_DeviceEffectID & 0x7F;
  873. setIndexPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_SETINDEX);
  874. setIndexPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
  875. // Packet to set modify data[index] of current effect
  876. DataPacket* modifyParamPacket = g_pDataPackager->GetPacket(packetIndex+1);
  877. if ((modifyParamPacket == NULL) || (!modifyParamPacket->AllocateBytes(3))) {
  878. g_pDataPackager->ClearPackets();
  879. return SFERR_DRIVER_ERROR;
  880. }
  881. modifyParamPacket->m_pData[0] = MODIFY_CMD | DEFAULT_MIDI_CHANNEL;
  882. modifyParamPacket->m_pData[1] = BYTE(value & 0x7f);
  883. modifyParamPacket->m_pData[2] = BYTE(value >> 7) & 0x7f;
  884. modifyParamPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_MODIFYPARAM);
  885. modifyParamPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
  886. return SUCCESS;
  887. }
  888. HRESULT InternalEffect::FillModifyPacket200(BYTE packetIndex, BYTE paramIndex, DWORD value) const
  889. {
  890. BYTE low = BYTE(value & 0x7F);
  891. BYTE high = BYTE(value >> 7) & 0x7F;
  892. return FillModifyPacket200(packetIndex, paramIndex, low, high);
  893. }
  894. HRESULT InternalEffect::FillModifyPacket200(BYTE packetIndex, BYTE paramIndex, BYTE low, BYTE high) const
  895. {
  896. DataPacket* modifyPacket = g_pDataPackager->GetPacket(packetIndex);
  897. if ((modifyPacket == NULL) || (!modifyPacket->AllocateBytes(6))) {
  898. g_pDataPackager->ClearPackets();
  899. return SFERR_DRIVER_ERROR;
  900. }
  901. BYTE id = m_DeviceEffectID;
  902. if (id == 0) {
  903. id = m_EffectID;
  904. }
  905. modifyPacket->m_pData[0] = MODIFY_CMD_200;
  906. modifyPacket->m_pData[1] = 0; // Temporary for checksum calc.
  907. modifyPacket->m_pData[2] = paramIndex & 0x3F;
  908. modifyPacket->m_pData[3] = id & 0x7F;
  909. modifyPacket->m_pData[4] = low & 0x7F;
  910. modifyPacket->m_pData[5] = high & 0x7F;
  911. // New checksum method just to be annoying
  912. BYTE checksum = 0;
  913. for (int i = 0; i < 6; i++) {
  914. checksum += modifyPacket->m_pData[i];
  915. }
  916. checksum = 0 - checksum;
  917. checksum &= 0xFF;
  918. modifyPacket->m_pData[1] = BYTE(checksum & 0x7F);
  919. modifyPacket->m_pData[2] |= BYTE(checksum >> 1) & 0x40;
  920. modifyPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_MODIFYPARAM);
  921. modifyPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
  922. return SUCCESS;
  923. }
  924. BOOL InternalEffect::IsReallyPlaying(BOOL& multiCheckStop)
  925. {
  926. if (multiCheckStop == TRUE) {
  927. return m_IsPossiblyPlaying;
  928. }
  929. multiCheckStop = TRUE;
  930. if (m_IsPossiblyPlaying == FALSE) {
  931. return FALSE;
  932. }
  933. // Do actual check
  934. // Create a command/data packet - send it of to the stick
  935. HRESULT hr = g_pDataPackager->GetEffectStatus(m_DeviceEffectID);
  936. if (hr != SUCCESS) {
  937. return TRUE;
  938. }
  939. ACKNACK ackNack;
  940. hr = g_pDataTransmitter->Transmit(ackNack); // Send it off
  941. if (hr != SUCCESS) {
  942. return TRUE;
  943. }
  944. // Use result returned by GetAckNackData in Transmit
  945. DWORD dwIn = ackNack.dwEffectStatus;
  946. // Interpret result (cooked RUNNING_MASK_200 becomes SWDEV_STS_EFFECT_RUNNING)
  947. m_IsPossiblyPlaying = ((g_ForceFeedbackDevice.GetDriverVersionMajor() != 1) && (dwIn & SWDEV_STS_EFFECT_RUNNING));
  948. return m_IsPossiblyPlaying;
  949. }
  950. /******************* BehviouralEffect class ******************/
  951. HRESULT BehaviouralEffect::Create(const DIEFFECT& diEffect)
  952. {
  953. // Validation Check
  954. ASSUME_NOT_NULL(diEffect.lpvTypeSpecificParams);
  955. if (diEffect.lpvTypeSpecificParams == NULL) {
  956. return SFERR_INVALID_PARAM;
  957. }
  958. // Let the base class do its magic
  959. HRESULT hr = InternalEffect::Create(diEffect);
  960. if (FAILED(hr)) {
  961. return hr;
  962. }
  963. // What axis is where
  964. short int xIndex = 0;
  965. short int yIndex = 1;
  966. if (m_AxesReversed) { // Reverse the index
  967. xIndex = 1;
  968. yIndex = 0;
  969. }
  970. if (diEffect.cAxes == 2) {
  971. if (diEffect.cbTypeSpecificParams == sizeof(DICONDITION)) { // Angled condition
  972. m_AxisMask &= ~Y_AXIS; // Pretend there is only one axis
  973. xIndex = 0; // Doesn't matter if reversed
  974. } else if (diEffect.cbTypeSpecificParams == sizeof(DICONDITION) * 2) { // Two axis effect does no axis mapping
  975. m_PercentX = 100;
  976. m_PercentY = 0;
  977. } else {
  978. return SFERR_INVALID_PARAM;
  979. }
  980. }
  981. // Fill the type specific (reverses array if needed)
  982. BYTE* pTypeSpecificArray = (BYTE*)m_ConditionData;
  983. BYTE* pDITypeSpecific = (BYTE*)(diEffect.lpvTypeSpecificParams);
  984. if ((m_AxisMask & X_AXIS) != 0) {
  985. ::memcpy(pTypeSpecificArray, pDITypeSpecific + xIndex, sizeof(DICONDITION));
  986. } else {
  987. ::memset(pTypeSpecificArray, 0, sizeof(DICONDITION)); // No X zero it out
  988. }
  989. if ((m_AxisMask & Y_AXIS) != 0) {
  990. ::memcpy(pTypeSpecificArray + sizeof(DICONDITION), pDITypeSpecific + yIndex, sizeof(DICONDITION));
  991. } else {
  992. ::memset(pTypeSpecificArray + sizeof(DICONDITION), 0, sizeof(DICONDITION)); // No Y zero it out
  993. }
  994. // Fix for Andretti, it thinks 0 is default
  995. if (m_ConditionData[0].dwPositiveSaturation == 0) {
  996. m_ConditionData[0].dwPositiveSaturation = 10000;
  997. }
  998. if (m_ConditionData[0].dwNegativeSaturation == 0) {
  999. m_ConditionData[0].dwNegativeSaturation = 10000;
  1000. }
  1001. // Check for overzealous numbers
  1002. for (UINT i = 0; i < diEffect.cAxes; i++) {
  1003. if (m_ConditionData[0].lOffset > 10000) {
  1004. hr = DI_TRUNCATED;
  1005. m_ConditionData[0].lOffset = 10000;
  1006. } else if (m_ConditionData[0].lOffset < -10000) {
  1007. hr = DI_TRUNCATED;
  1008. m_ConditionData[0].lOffset = 10000;
  1009. }
  1010. if (m_ConditionData[0].lPositiveCoefficient > 10000) {
  1011. hr = DI_TRUNCATED;
  1012. m_ConditionData[0].lPositiveCoefficient = 10000;
  1013. } else if (m_ConditionData[0].lPositiveCoefficient < -10000) {
  1014. hr = DI_TRUNCATED;
  1015. m_ConditionData[0].lPositiveCoefficient = -10000;
  1016. }
  1017. if (m_ConditionData[0].lNegativeCoefficient > 10000) {
  1018. hr = DI_TRUNCATED;
  1019. m_ConditionData[0].lNegativeCoefficient = 10000;
  1020. } else if (m_ConditionData[0].lNegativeCoefficient < -10000) {
  1021. hr = DI_TRUNCATED;
  1022. m_ConditionData[0].lNegativeCoefficient = -10000;
  1023. }
  1024. if (m_ConditionData[0].dwPositiveSaturation > 10000) {
  1025. hr = DI_TRUNCATED;
  1026. m_ConditionData[0].dwPositiveSaturation = 10000;
  1027. }
  1028. if (m_ConditionData[0].dwNegativeSaturation > 10000) {
  1029. hr = DI_TRUNCATED;
  1030. m_ConditionData[0].dwNegativeSaturation = 10000;
  1031. }
  1032. if (m_ConditionData[0].lDeadBand > 10000) {
  1033. hr = DI_TRUNCATED;
  1034. m_ConditionData[0].lDeadBand = 10000;
  1035. } else if (m_ConditionData[0].lDeadBand < -10000) {
  1036. hr = DI_TRUNCATED;
  1037. m_ConditionData[0].lDeadBand = -10000;
  1038. }
  1039. }
  1040. return hr;
  1041. }
  1042. /******************* BehaviouralEffect1XX class ******************/
  1043. HRESULT BehaviouralEffect1XX::FillCreatePacket(DataPacket& packet) const
  1044. {
  1045. // Packet to set modify data[index] of current effect
  1046. if (!packet.AllocateBytes(22)) {
  1047. return SFERR_DRIVER_ERROR;
  1048. }
  1049. // Fill in the Generic Effect Information
  1050. FillHeader1XX(packet, m_TypeID, NEW_EFFECT_ID);
  1051. packet.m_pData[10]= BYTE(g_TriggerMap1XX[m_TriggerPlayButton] & 0x7F); // Button play mask Low MidiByte
  1052. packet.m_pData[11]= BYTE(g_TriggerMap1XX[m_TriggerPlayButton] >> 7) & 0x7F; // Button play mask High MidiByte
  1053. // Behavioural Specific Parms
  1054. int twoByte = ((ConstantX()/COEFFICIENT_SCALE_1XX) * m_Gain) / GAIN_PERCENTAGE_SCALE;
  1055. packet.m_pData[12]= twoByte & 0x7F; // Spring/Damper/... Constant X Low
  1056. packet.m_pData[13]= (twoByte >> 7) & 0x7F; // Spring/Damper/... Constant X High
  1057. twoByte = ((ConstantY()/COEFFICIENT_SCALE_1XX) * m_Gain) / GAIN_PERCENTAGE_SCALE;
  1058. packet.m_pData[14]= twoByte & 0x7F; // Spring/Damper/... Constant Y Low
  1059. packet.m_pData[15]= (twoByte >> 7) & 0x7F; // Spring/Damper/... Constant Y High
  1060. twoByte = CenterX()/COEFFICIENT_SCALE_1XX;
  1061. packet.m_pData[16]= twoByte & 0x7F; // Spring/Damper/... Center X Low
  1062. packet.m_pData[17]= (twoByte >> 7) & 0x7F; // Spring/Damper/... Center X High
  1063. twoByte = CenterY()/COEFFICIENT_SCALE_1XX;
  1064. packet.m_pData[18]= twoByte & 0x7F; // Spring/Damper/... Center Y Low
  1065. packet.m_pData[19]= (twoByte >> 7) & 0x7F; // Spring/Damper/... Center Y High
  1066. packet.m_pData[20]= ComputeChecksum(packet, 20); // Checksum
  1067. // End of packet
  1068. packet.m_pData[21]= MIDI_EOX; // End of SysEX packet
  1069. return SUCCESS;
  1070. }
  1071. HRESULT BehaviouralEffect1XX::Modify(InternalEffect& newEffect, DWORD modFlags)
  1072. {
  1073. g_pDataPackager->ClearPackets();
  1074. AdjustModifyParams(newEffect, modFlags);
  1075. HRESULT hr = SUCCESS;
  1076. BehaviouralEffect1XX* pEffect = (BehaviouralEffect1XX*)(&newEffect);
  1077. BYTE nextPacket = 0;
  1078. if (modFlags & DIEP_DURATION) {
  1079. hr = FillModifyPacket1XX(nextPacket, INDEX_DURATION, pEffect->m_Duration/DURATION_SCALE_1XX);
  1080. nextPacket += 2;
  1081. }
  1082. if (modFlags & DIEP_TRIGGERBUTTON) {
  1083. hr = FillModifyPacket1XX(nextPacket, INDEX_TRIGGERBUTTONMASK, g_TriggerMap1XX[pEffect->m_TriggerPlayButton]);
  1084. nextPacket += 2;
  1085. }
  1086. BOOL gainChanged = modFlags & DIEP_GAIN;
  1087. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Find which ones
  1088. if (ConstantX() != pEffect->ConstantX() || gainChanged) {
  1089. hr = FillModifyPacket1XX(nextPacket, INDEX_X_COEEFICIENT,
  1090. ((pEffect->ConstantX()/COEFFICIENT_SCALE_1XX) * pEffect->m_Gain) / GAIN_PERCENTAGE_SCALE);
  1091. nextPacket += 2;
  1092. }
  1093. if (ConstantY() != pEffect->ConstantY() || gainChanged) {
  1094. hr = FillModifyPacket1XX(nextPacket, INDEX_Y_COEEFICIENT,
  1095. ((pEffect->ConstantY()/COEFFICIENT_SCALE_1XX) * pEffect->m_Gain) / GAIN_PERCENTAGE_SCALE);
  1096. nextPacket += 2;
  1097. }
  1098. if (m_HasCenter == TRUE) {
  1099. if (CenterX() != pEffect->CenterX()) {
  1100. hr = FillModifyPacket1XX(nextPacket, INDEX_X_CENTER, pEffect->CenterX()/COEFFICIENT_SCALE_1XX);
  1101. nextPacket += 2;
  1102. }
  1103. if (CenterY() != pEffect->CenterY()) {
  1104. hr = FillModifyPacket1XX(nextPacket, INDEX_Y_CENTER, pEffect->CenterY()/COEFFICIENT_SCALE_1XX);
  1105. }
  1106. }
  1107. }
  1108. return hr;
  1109. }
  1110. void BehaviouralEffect1XX::AdjustModifyParams(InternalEffect& newEffect, DWORD& modFlags) const
  1111. {
  1112. // Check to see if values being modified are acceptable
  1113. DWORD possMod = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TYPESPECIFICPARAMS;
  1114. if ((g_TotalModifiable & modFlags & possMod) == 0) { // Nothing to modify?
  1115. modFlags = 0;
  1116. return;
  1117. }
  1118. BehaviouralEffect1XX* pEffect = (BehaviouralEffect1XX*)(&newEffect);
  1119. unsigned short numPackets = 0;
  1120. if (modFlags & DIEP_DURATION) {
  1121. if (m_Duration == pEffect->m_Duration) {
  1122. modFlags &= ~DIEP_DURATION; // Remove duration flag, unchanged
  1123. } else {
  1124. numPackets += 2;
  1125. }
  1126. }
  1127. if (modFlags & DIEP_TRIGGERBUTTON) {
  1128. if (m_TriggerPlayButton == pEffect->m_TriggerPlayButton) {
  1129. modFlags &= ~DIEP_TRIGGERBUTTON; // Remove trigger flag, unchanged
  1130. } else {
  1131. numPackets += 2;
  1132. }
  1133. }
  1134. int numTypeSpecificChanged = 0;
  1135. if (modFlags & DIEP_GAIN) { // Did gain really change
  1136. numTypeSpecificChanged = 4;
  1137. } else {
  1138. modFlags &= ~DIEP_GAIN;
  1139. }
  1140. // If type specific or gain
  1141. if ((modFlags & DIEP_TYPESPECIFICPARAMS) || (numTypeSpecificChanged == 0)) { // Find which ones
  1142. if (numTypeSpecificChanged == 0) { // Kx, Ky not already taken care of by gain?
  1143. if (ConstantX() != pEffect->ConstantX()) {
  1144. numTypeSpecificChanged = 2;
  1145. }
  1146. if (ConstantY() != pEffect->ConstantY()) {
  1147. numTypeSpecificChanged += 2;
  1148. }
  1149. }
  1150. if ((m_HasCenter == TRUE) && (modFlags & DIEP_TYPESPECIFICPARAMS)) { // Don't check these if gain only
  1151. if (CenterX() != pEffect->CenterX()) {
  1152. numTypeSpecificChanged += 2;
  1153. }
  1154. if (CenterY() != pEffect->CenterY()) {
  1155. numTypeSpecificChanged += 2;
  1156. }
  1157. }
  1158. }
  1159. if (numTypeSpecificChanged == 0) {
  1160. modFlags &= ~DIEP_TYPESPECIFICPARAMS; // No type specific changed
  1161. } else {
  1162. numPackets += (unsigned short)numTypeSpecificChanged;
  1163. }
  1164. if (numPackets == 0) { // That was easy nothing changed
  1165. return;
  1166. }
  1167. g_pDataPackager->AllocateDataPackets(numPackets);
  1168. }
  1169. /******************* RTCSpring1XX class ******************/
  1170. RTCSpring1XX::RTCSpring1XX() : BehaviouralEffect()
  1171. {
  1172. m_EffectID = SYSTEM_RTCSPRING_ID;
  1173. // Set defaults
  1174. m_ConditionData[0].lPositiveCoefficient = DEFAULT_RTC_KX;
  1175. m_ConditionData[1].lPositiveCoefficient = DEFAULT_RTC_KY;
  1176. m_ConditionData[0].lOffset = DEFAULT_RTC_X0;
  1177. m_ConditionData[1].lOffset = DEFAULT_RTC_Y0;
  1178. m_ConditionData[0].dwPositiveSaturation = DEFAULT_RTC_XSAT;
  1179. m_ConditionData[1].dwPositiveSaturation = DEFAULT_RTC_YSAT;
  1180. m_ConditionData[0].lDeadBand = DEFAULT_RTC_XDBAND;
  1181. m_ConditionData[1].lDeadBand = DEFAULT_RTC_YDBAND;
  1182. }
  1183. HRESULT RTCSpring1XX::Create(const DIEFFECT& diEffect)
  1184. {
  1185. // Validation Check
  1186. if (diEffect.cbTypeSpecificParams != sizeof(DICONDITION) * 2) {
  1187. return SFERR_INVALID_PARAM;
  1188. }
  1189. if (diEffect.lpvTypeSpecificParams == NULL) {
  1190. ASSUME_NOT_REACHED();
  1191. return SFERR_INVALID_PARAM;
  1192. }
  1193. // Get the data
  1194. DICONDITION* condition = (DICONDITION*)(diEffect.lpvTypeSpecificParams);
  1195. m_ConditionData[0].lPositiveCoefficient = condition[0].lPositiveCoefficient;
  1196. m_ConditionData[1].lPositiveCoefficient = condition[1].lPositiveCoefficient;
  1197. m_ConditionData[0].lOffset = condition[0].lOffset;
  1198. m_ConditionData[1].lOffset = condition[1].lOffset;
  1199. m_ConditionData[0].dwPositiveSaturation = condition[0].dwPositiveSaturation;
  1200. m_ConditionData[1].dwPositiveSaturation = condition[1].dwPositiveSaturation;
  1201. m_ConditionData[0].lDeadBand = condition[0].lDeadBand;
  1202. m_ConditionData[1].lDeadBand = condition[1].lDeadBand;
  1203. return SUCCESS;
  1204. }
  1205. HRESULT RTCSpring1XX::FillCreatePacket(DataPacket& packet) const
  1206. {
  1207. ASSUME_NOT_REACHED();
  1208. return SUCCESS;
  1209. }
  1210. HRESULT RTCSpring1XX::Modify(InternalEffect& newEffect, DWORD modFlags)
  1211. {
  1212. // Sanity Check
  1213. if (g_pDataPackager == NULL) {
  1214. ASSUME_NOT_REACHED();
  1215. return SFERR_DRIVER_ERROR;
  1216. }
  1217. g_pDataPackager->ClearPackets();
  1218. RTCSpring1XX* pNewRTCSpring = (RTCSpring1XX*)(&newEffect);
  1219. // Find number of packets needed
  1220. unsigned short numPackets = 0;
  1221. if (ConstantX() != pNewRTCSpring->ConstantX()) {
  1222. numPackets += 2;
  1223. }
  1224. if (ConstantY() != pNewRTCSpring->ConstantY()) {
  1225. numPackets += 2;
  1226. }
  1227. if (CenterX() != pNewRTCSpring->CenterX()) {
  1228. numPackets += 2;
  1229. }
  1230. if (CenterY() != pNewRTCSpring->CenterY()) {
  1231. numPackets += 2;
  1232. }
  1233. if (SaturationX() != pNewRTCSpring->SaturationX()) {
  1234. numPackets += 2;
  1235. }
  1236. if (SaturationY() != pNewRTCSpring->SaturationY()) {
  1237. numPackets += 2;
  1238. }
  1239. if (DeadBandX() != pNewRTCSpring->DeadBandX()) {
  1240. numPackets += 2;
  1241. }
  1242. if (DeadBandY() != pNewRTCSpring->DeadBandY()) {
  1243. numPackets += 2;
  1244. }
  1245. if (numPackets == 0) {
  1246. return SUCCESS;
  1247. }
  1248. // Allocate a packets for sending modify command
  1249. if (!g_pDataPackager->AllocateDataPackets(numPackets)) {
  1250. return SFERR_DRIVER_ERROR;
  1251. }
  1252. // Fill the packets
  1253. BYTE nextPacket = 0;
  1254. if (ConstantX() != pNewRTCSpring->ConstantX()) {
  1255. FillModifyPacket1XX(nextPacket, INDEX_RTC_COEEFICIENT_X, pNewRTCSpring->ConstantX());
  1256. nextPacket += 2;
  1257. }
  1258. if (ConstantY() != pNewRTCSpring->ConstantY()) {
  1259. FillModifyPacket1XX(nextPacket, INDEX_RTC_COEEFICIENT_Y, pNewRTCSpring->ConstantY());
  1260. nextPacket += 2;
  1261. }
  1262. if (CenterX() != pNewRTCSpring->CenterX()) {
  1263. FillModifyPacket1XX(nextPacket, INDEX_RTC_CENTER_X, pNewRTCSpring->CenterX());
  1264. nextPacket += 2;
  1265. }
  1266. if (CenterY() != pNewRTCSpring->CenterY()) {
  1267. FillModifyPacket1XX(nextPacket, INDEX_RTC_CENTER_Y, pNewRTCSpring->CenterY());
  1268. nextPacket += 2;
  1269. }
  1270. if (SaturationX() != pNewRTCSpring->SaturationX()) {
  1271. FillModifyPacket1XX(nextPacket, INDEX_RTC_SATURATION_X, pNewRTCSpring->SaturationX());
  1272. nextPacket += 2;
  1273. }
  1274. if (SaturationY() != pNewRTCSpring->SaturationY()) {
  1275. FillModifyPacket1XX(nextPacket, INDEX_RTC_SATURATION_Y, pNewRTCSpring->SaturationY());
  1276. nextPacket += 2;
  1277. }
  1278. if (DeadBandX() != pNewRTCSpring->DeadBandX()) {
  1279. FillModifyPacket1XX(nextPacket, INDEX_RTC_DEADBAND_X, pNewRTCSpring->DeadBandX());
  1280. nextPacket += 2;
  1281. }
  1282. if (DeadBandY() != pNewRTCSpring->DeadBandY()) {
  1283. FillModifyPacket1XX(nextPacket, INDEX_RTC_DEADBAND_Y, pNewRTCSpring->DeadBandY());
  1284. }
  1285. return SUCCESS;
  1286. }
  1287. /******************* BehaviouralEffect200 class ******************/
  1288. BYTE BehaviouralEffect200::GetRepeatIndex() const
  1289. {
  1290. return INDEX_BE_REPEAT_200;
  1291. }
  1292. void BehaviouralEffect200::ComputeDsAndFs()
  1293. {
  1294. // Assume single axis for now (X) - Will have to add second axis mapping
  1295. // Figure out distances
  1296. // long int d2 = m_ConditionData[0].lOffset - m_ConditionData[0].lDeadBand;
  1297. // long int d3 = m_ConditionData[0].lOffset + m_ConditionData[0].lDeadBand;
  1298. long int d2 = - m_ConditionData[0].lDeadBand;
  1299. long int d3 = m_ConditionData[0].lDeadBand;
  1300. long int d1 = -10000;
  1301. long int d4 = 10000;
  1302. // Compute force at -100 percent position
  1303. float negCoeff = float(m_ConditionData[0].lNegativeCoefficient)/float(10000.0);
  1304. long int f100Neg = long int((10000 + d2) * negCoeff);
  1305. // Check vs proper saturation
  1306. if (negCoeff > 0) {
  1307. if (unsigned long(f100Neg) > m_ConditionData[0].dwNegativeSaturation) {
  1308. f100Neg = m_ConditionData[0].dwNegativeSaturation;
  1309. d1 = long int (-1 * f100Neg/negCoeff) - d2; // Refigure D1
  1310. }
  1311. } else if (negCoeff < 0) {
  1312. if (unsigned long(-f100Neg) > m_ConditionData[0].dwNegativeSaturation) {
  1313. f100Neg = -1 * m_ConditionData[0].dwNegativeSaturation;
  1314. d1 = long int (-1 * f100Neg/negCoeff) - d2; // Refigure D1
  1315. }
  1316. }
  1317. // Compute Force include axis-mapping
  1318. f100Neg = long int(f100Neg/100 * (m_PercentX + (m_PercentY * g_ForceFeedbackDevice.GetYMappingPercent(m_TypeID))/100));
  1319. m_Fs[0] = BYTE(float(f100Neg/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  1320. // Compute force at +100 percent position
  1321. float posCoeff = float(-m_ConditionData[0].lPositiveCoefficient)/float(10000.0);
  1322. long int f100Pos = long int((10000 - d3) * posCoeff);
  1323. // Check vs proper saturation
  1324. if (posCoeff > 0) {
  1325. if (unsigned long(f100Pos) > m_ConditionData[0].dwPositiveSaturation) {
  1326. f100Pos = m_ConditionData[0].dwPositiveSaturation;
  1327. d4 = long int (f100Pos/posCoeff) + d3; // Refigure D4
  1328. }
  1329. } else if (posCoeff < 0) {
  1330. if (unsigned long(-f100Pos) > m_ConditionData[0].dwPositiveSaturation) {
  1331. f100Pos = -1 * m_ConditionData[0].dwPositiveSaturation;
  1332. d4 = long int(f100Pos/posCoeff) + d3; // Refigure D4
  1333. }
  1334. }
  1335. // Compute Force include axis-mapping
  1336. f100Pos = long int(f100Pos/100 * (m_PercentX + (m_PercentY * g_ForceFeedbackDevice.GetYMappingPercent(m_TypeID))/100));
  1337. m_Fs[3] = BYTE(float(f100Pos/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  1338. // Convert to device percentages (0 to +126 --- +63 = 0 percent)
  1339. m_Ds[0] = BYTE(float(d1/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  1340. m_Ds[1] = BYTE(float(d2/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  1341. m_Ds[2] = BYTE(float(d3/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  1342. m_Ds[3] = BYTE(float(d4/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  1343. if (m_TypeID == ET_SPRING_200) { // Add proper offsets (squished by max percent)
  1344. // Convert forces to device percentages (0 to +126 --- +63 = 0 percent)
  1345. // m_Fs[0] - Done above
  1346. LONG offset = LONG(float(float(g_ForceFeedbackDevice.GetSpringOffset())/10000.0) * float(f100Neg));
  1347. m_Fs[1] = BYTE(float(offset/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  1348. offset = LONG(float(float(g_ForceFeedbackDevice.GetSpringOffset())/10000.0) * float(f100Pos));
  1349. m_Fs[2] = BYTE(float(offset/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  1350. // m_Fs[3] - Done above
  1351. } else {
  1352. // Convert forces to device percentages (0 to +126 --- +63 = 0 percent)
  1353. // m_Fs[0] - Done above
  1354. m_Fs[1] = 63; // 0
  1355. m_Fs[2] = 63; // 0
  1356. // m_Fs[3] - Done above
  1357. }
  1358. }
  1359. HRESULT BehaviouralEffect200::Create(const DIEFFECT& diEffect)
  1360. {
  1361. HRESULT hr = BehaviouralEffect::Create(diEffect);
  1362. if (FAILED(hr)) {
  1363. return hr;
  1364. }
  1365. // Compute behavioural params
  1366. ComputeDsAndFs();
  1367. return hr;
  1368. }
  1369. UINT BehaviouralEffect200::GetModifyOnlyNeeded() const
  1370. {
  1371. UINT retCount = 0;
  1372. if (m_TriggerPlayButton != 0) { // Trigger Button
  1373. retCount++;
  1374. }
  1375. if (m_TriggerRepeat != 0) { // Trigger repeat
  1376. retCount++;
  1377. }
  1378. if (m_Gain != 10000) { // Gain
  1379. retCount++;
  1380. }
  1381. if (m_ConditionData[0].lOffset != 0) { // Center of behaviour
  1382. retCount++;
  1383. }
  1384. return retCount;
  1385. }
  1386. HRESULT BehaviouralEffect200::FillModifyOnlyParms() const
  1387. {
  1388. if (g_pDataPackager == NULL) {
  1389. ASSUME_NOT_REACHED(); // This is only called from DataPackager::Create()
  1390. return SFERR_DRIVER_ERROR;
  1391. }
  1392. HRESULT hr = SUCCESS;
  1393. BYTE nextPacket = 1;
  1394. if (m_TriggerPlayButton != 0) { // Trigger Button
  1395. hr = FillModifyPacket200(nextPacket, INDEX_BE_BUTTONMAP_200, g_TriggerMap200[m_TriggerPlayButton]);
  1396. nextPacket++;
  1397. }
  1398. if (m_TriggerRepeat != 0) { // Trigger repeat
  1399. hr = FillModifyPacket200(nextPacket, INDEX_BE_BUTTONREPEAT_200, m_TriggerRepeat/DURATION_SCALE_200);
  1400. nextPacket++;
  1401. }
  1402. if (m_Gain != 10000) { // Gain
  1403. hr = FillModifyPacket200(nextPacket, INDEX_BE_GAIN_200, DWORD(float(m_Gain)/GAIN_SCALE_200));
  1404. nextPacket++;
  1405. }
  1406. if (m_ConditionData[0].lOffset != 0) { // Center of behaviour
  1407. long int deviceUnits = m_ConditionData[0].lOffset/BEHAVIOUR_CENTER_SCALE_200 + BEHAVIOUR_CENTER_200;
  1408. BYTE lowByte = BYTE(deviceUnits & 0x7F);
  1409. BYTE highByte = BYTE(deviceUnits >> 7) & 0x7F;
  1410. hr = FillModifyPacket200(nextPacket, INDEX_BE_CENTER_200, lowByte, highByte);
  1411. nextPacket++;
  1412. }
  1413. return hr;
  1414. }
  1415. HRESULT BehaviouralEffect200::FillCreatePacket(DataPacket& packet) const
  1416. {
  1417. // Packet to set modify data[index] of current effect
  1418. if (!packet.AllocateBytes(21)) {
  1419. return SFERR_DRIVER_ERROR;
  1420. }
  1421. // Fill in the Generic Effect Information
  1422. FillHeader200(packet, m_TypeID, NEW_EFFECT_ID);
  1423. // All of the below items fit in one MidiByte (0..126/127) after conversion
  1424. unsigned short effectAngle = unsigned short(float(m_EffectAngle)/ANGLE_SCALE_200);
  1425. packet.m_pData[10]= BYTE(effectAngle & 0x7F); // Effect Angle
  1426. // Computed in create
  1427. packet.m_pData[11]= m_Ds[0];
  1428. packet.m_pData[12]= m_Fs[0];
  1429. packet.m_pData[13]= m_Ds[1];
  1430. packet.m_pData[14]= m_Fs[1];
  1431. packet.m_pData[15]= m_Ds[2];
  1432. packet.m_pData[16]= m_Fs[2];
  1433. packet.m_pData[17]= m_Ds[3];
  1434. packet.m_pData[18]= m_Fs[3];
  1435. // End this puppy
  1436. packet.m_pData[19]= ComputeChecksum(packet, 19); // Checksum
  1437. packet.m_pData[20]= MIDI_EOX; // End of SysEX packet
  1438. return SUCCESS;
  1439. }
  1440. HRESULT BehaviouralEffect200::Modify(InternalEffect& newEffect, DWORD modFlags)
  1441. {
  1442. g_pDataPackager->ClearPackets();
  1443. HRESULT adjustResult = AdjustModifyParams(newEffect, modFlags);
  1444. if (FAILED(adjustResult)) {
  1445. return adjustResult;
  1446. }
  1447. HRESULT hr = SUCCESS;
  1448. BehaviouralEffect200* pEffect = (BehaviouralEffect200*)(&newEffect);
  1449. BYTE nextPacket = 0;
  1450. if (modFlags & DIEP_DURATION) {
  1451. hr = FillModifyPacket200(nextPacket, INDEX_BE_DURATION_200, pEffect->m_Duration/DURATION_SCALE_200);
  1452. nextPacket++;
  1453. }
  1454. if (modFlags & DIEP_TRIGGERBUTTON) {
  1455. hr = FillModifyPacket200(nextPacket, INDEX_BE_BUTTONMAP_200, g_TriggerMap200[pEffect->m_TriggerPlayButton]);
  1456. nextPacket++;
  1457. }
  1458. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  1459. hr = FillModifyPacket200(nextPacket, INDEX_BE_BUTTONREPEAT_200, pEffect->m_TriggerRepeat/DURATION_SCALE_200);
  1460. nextPacket++;
  1461. }
  1462. if (modFlags & DIEP_GAIN) {
  1463. hr = FillModifyPacket200(nextPacket, INDEX_BE_GAIN_200, DWORD(float(pEffect->m_Gain)/GAIN_SCALE_200));
  1464. nextPacket++;
  1465. }
  1466. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Send changed items
  1467. for (int i = 0; i < 4; i++) {
  1468. if ((m_Ds[i] != pEffect->m_Ds[i]) || (m_Fs[i] != pEffect->m_Fs[i])) {
  1469. hr = FillModifyPacket200(nextPacket, INDEX_D1F1_200 + i, pEffect->m_Ds[i], pEffect->m_Fs[i]);
  1470. nextPacket++;
  1471. }
  1472. }
  1473. if (m_ConditionData[0].lOffset != pEffect->m_ConditionData[0].lOffset) { // Center of behaviour
  1474. long int deviceUnits = pEffect->m_ConditionData[0].lOffset/BEHAVIOUR_CENTER_SCALE_200 + BEHAVIOUR_CENTER_200;
  1475. BYTE lowByte = BYTE(deviceUnits & 0x7F);
  1476. BYTE highByte = BYTE(deviceUnits >> 7) & 0x7F;
  1477. hr = FillModifyPacket200(nextPacket, INDEX_BE_CENTER_200, lowByte, highByte);
  1478. nextPacket++;
  1479. }
  1480. }
  1481. if (hr == SUCCESS) {
  1482. return adjustResult;
  1483. }
  1484. return hr;
  1485. }
  1486. HRESULT BehaviouralEffect200::AdjustModifyParams(InternalEffect& newEffect, DWORD& modFlags)
  1487. {
  1488. // Check to see if values being modified are acceptable
  1489. DWORD possMod = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_DIRECTION;
  1490. /* if ((g_TotalModifiable & modFlags & possMod) == 0) { // Nothing to modify?
  1491. modFlags = 0;
  1492. return SFERR_NO_SUPPORT;
  1493. }
  1494. */
  1495. BehaviouralEffect200* pEffect = (BehaviouralEffect200*)(&newEffect);
  1496. unsigned short numPackets = 0;
  1497. HRESULT hr = SUCCESS;;
  1498. if ((modFlags & (~possMod & DIEP_ALLPARAMS)) != 0) {
  1499. modFlags &= possMod;
  1500. hr = S_FALSE; // Cannot modify all they asked for
  1501. }
  1502. BOOL playingChecked = FALSE;
  1503. if (modFlags & DIEP_DURATION) {
  1504. if (m_Duration == pEffect->m_Duration) {
  1505. modFlags &= ~DIEP_DURATION; // Remove duration flag, unchanged
  1506. } else {
  1507. if (IsReallyPlaying(playingChecked) == TRUE) {
  1508. return DIERR_EFFECTPLAYING;
  1509. } else {
  1510. numPackets++;
  1511. }
  1512. }
  1513. }
  1514. if (modFlags & DIEP_TRIGGERBUTTON) {
  1515. if (m_TriggerPlayButton == pEffect->m_TriggerPlayButton) {
  1516. modFlags &= ~DIEP_TRIGGERBUTTON; // Remove trigger flag, unchanged
  1517. } else {
  1518. numPackets++;
  1519. }
  1520. }
  1521. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  1522. if (m_TriggerRepeat == pEffect->m_TriggerRepeat) {
  1523. modFlags &= ~DIEP_TRIGGERREPEATINTERVAL; // Remove trigger repeat flag, unchanged
  1524. } else {
  1525. numPackets++;
  1526. }
  1527. }
  1528. if (modFlags & DIEP_GAIN) { // Did gain really change
  1529. if (m_Gain == pEffect->m_Gain) {
  1530. modFlags &= ~DIEP_GAIN; // Remove trigger flag, unchanged
  1531. } else {
  1532. numPackets++;
  1533. }
  1534. }
  1535. if (modFlags & DIEP_DIRECTION) {
  1536. modFlags |= DIEP_TYPESPECIFICPARAMS;
  1537. }
  1538. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Find which ones (if any)
  1539. int numTypeSpecificChanged = 0;
  1540. for (int i = 0; i < 4; i++) {
  1541. // Ds and Fs are changed togeather
  1542. if ((m_Ds[i] != pEffect->m_Ds[i]) || (m_Fs[i] != pEffect->m_Fs[i])) {
  1543. numTypeSpecificChanged++;
  1544. }
  1545. }
  1546. if (m_ConditionData[0].lOffset != pEffect->m_ConditionData[0].lOffset) { // Center of behaviour
  1547. numTypeSpecificChanged++;
  1548. }
  1549. if (numTypeSpecificChanged == 0) {
  1550. modFlags &= ~DIEP_TYPESPECIFICPARAMS; // No type specific changed
  1551. } else {
  1552. numPackets += (USHORT)numTypeSpecificChanged;
  1553. }
  1554. }
  1555. if (numPackets != 0) { // Was anything really changed
  1556. g_pDataPackager->AllocateDataPackets(numPackets);
  1557. }
  1558. return hr;
  1559. }
  1560. /******************* RTCSpring200 class ******************/
  1561. RTCSpring200::RTCSpring200() : BehaviouralEffect200(ET_SPRING_200)
  1562. {
  1563. m_EffectID = ID_RTCSPRING_200;
  1564. // Set defaults
  1565. m_ConditionData[0].lPositiveCoefficient = DEFAULT_RTC_KX;
  1566. m_ConditionData[1].lPositiveCoefficient = DEFAULT_RTC_KY;
  1567. m_ConditionData[0].lNegativeCoefficient = DEFAULT_RTC_KX;
  1568. m_ConditionData[1].lNegativeCoefficient = DEFAULT_RTC_KY;
  1569. m_ConditionData[0].lOffset = DEFAULT_RTC_X0;
  1570. m_ConditionData[1].lOffset = DEFAULT_RTC_Y0;
  1571. m_ConditionData[0].dwPositiveSaturation = DEFAULT_RTC_XSAT;
  1572. m_ConditionData[1].dwPositiveSaturation = DEFAULT_RTC_YSAT;
  1573. m_ConditionData[0].dwNegativeSaturation = DEFAULT_RTC_XSAT;
  1574. m_ConditionData[1].dwNegativeSaturation = DEFAULT_RTC_YSAT;
  1575. m_ConditionData[0].lDeadBand = DEFAULT_RTC_XDBAND;
  1576. m_ConditionData[1].lDeadBand = DEFAULT_RTC_YDBAND;
  1577. }
  1578. HRESULT RTCSpring200::Create(const DIEFFECT& diEffect)
  1579. {
  1580. // Validation Check
  1581. ASSUME_NOT_NULL(diEffect.lpvTypeSpecificParams);
  1582. if (diEffect.lpvTypeSpecificParams == NULL) {
  1583. return SFERR_INVALID_PARAM;
  1584. }
  1585. if (diEffect.cbTypeSpecificParams == sizeof(DICONDITION)*2) {
  1586. ::memcpy(m_ConditionData, diEffect.lpvTypeSpecificParams, sizeof(DICONDITION)*2);
  1587. } else if (diEffect.cbTypeSpecificParams == sizeof(DICONDITION)) {
  1588. ::memcpy(m_ConditionData, diEffect.lpvTypeSpecificParams, sizeof(DICONDITION));
  1589. ::memset(m_ConditionData + 1, 0, sizeof(DICONDITION));
  1590. } else if (diEffect.cbTypeSpecificParams == sizeof(RTCSPRING_PARAM)) {
  1591. ::memset(m_ConditionData, 0, sizeof(DICONDITION)*2);
  1592. RTCSPRING_PARAM* pOldRTCParam = (RTCSPRING_PARAM*)(diEffect.lpvTypeSpecificParams);
  1593. m_ConditionData[0].lPositiveCoefficient = pOldRTCParam->m_XKConstant;
  1594. m_ConditionData[1].lPositiveCoefficient = pOldRTCParam->m_YKConstant;
  1595. m_ConditionData[0].lNegativeCoefficient = pOldRTCParam->m_XKConstant;
  1596. m_ConditionData[1].lNegativeCoefficient = pOldRTCParam->m_YKConstant;
  1597. m_ConditionData[0].lOffset = pOldRTCParam->m_XAxisCenter;
  1598. m_ConditionData[1].lOffset = pOldRTCParam->m_YAxisCenter;
  1599. m_ConditionData[0].dwPositiveSaturation = DWORD(pOldRTCParam->m_XSaturation);
  1600. m_ConditionData[1].dwPositiveSaturation = DWORD(pOldRTCParam->m_YSaturation);
  1601. m_ConditionData[0].dwNegativeSaturation = DWORD(pOldRTCParam->m_XSaturation);
  1602. m_ConditionData[1].dwNegativeSaturation = DWORD(pOldRTCParam->m_YSaturation);
  1603. m_ConditionData[0].lDeadBand = pOldRTCParam->m_XDeadBand;
  1604. m_ConditionData[1].lDeadBand = pOldRTCParam->m_YDeadBand;
  1605. } else {
  1606. return SFERR_INVALID_PARAM;
  1607. }
  1608. // Check parameters for truncation
  1609. BOOL truncated = FALSE;
  1610. if (m_ConditionData[0].lPositiveCoefficient > 10000) {
  1611. truncated = TRUE;
  1612. m_ConditionData[0].lPositiveCoefficient = 10000;
  1613. } else if (m_ConditionData[0].lPositiveCoefficient < -10000) {
  1614. truncated = TRUE;
  1615. m_ConditionData[0].lPositiveCoefficient = -10000;
  1616. }
  1617. if (m_ConditionData[0].lNegativeCoefficient > 10000) {
  1618. truncated = TRUE;
  1619. m_ConditionData[0].lNegativeCoefficient = 10000;
  1620. } else if (m_ConditionData[0].lNegativeCoefficient < -10000) {
  1621. truncated = TRUE;
  1622. m_ConditionData[0].lNegativeCoefficient = -10000;
  1623. }
  1624. if (m_ConditionData[0].lOffset > 10000) {
  1625. truncated = TRUE;
  1626. m_ConditionData[0].lOffset = 10000;
  1627. } else if (m_ConditionData[0].lOffset < -10000) {
  1628. truncated = TRUE;
  1629. m_ConditionData[0].lOffset = -10000;
  1630. }
  1631. if (m_ConditionData[0].dwPositiveSaturation > 10000) {
  1632. truncated = TRUE;
  1633. m_ConditionData[0].dwPositiveSaturation = 10000;
  1634. }
  1635. if (m_ConditionData[0].dwNegativeSaturation > 10000) {
  1636. truncated = TRUE;
  1637. m_ConditionData[0].dwNegativeSaturation = 10000;
  1638. }
  1639. if (m_ConditionData[0].lDeadBand > 10000) {
  1640. truncated = TRUE;
  1641. m_ConditionData[0].lDeadBand = 10000;
  1642. } else if (m_ConditionData[0].lDeadBand < -10000) {
  1643. truncated = TRUE;
  1644. m_ConditionData[0].lDeadBand = -10000;
  1645. }
  1646. m_PercentX = 100;
  1647. m_PercentY = 0;
  1648. // Compute behavioural params
  1649. ComputeDsAndFs();
  1650. if (truncated == TRUE) {
  1651. return DI_TRUNCATED;
  1652. }
  1653. return SUCCESS;
  1654. }
  1655. HRESULT RTCSpring200::FillCreatePacket(DataPacket& packet) const
  1656. {
  1657. return SUCCESS;
  1658. }
  1659. UINT RTCSpring200::GetModifyOnlyNeeded() const
  1660. {
  1661. return 3; // One is added for create. There is no Create, so we return 1 less than needed
  1662. }
  1663. HRESULT RTCSpring200::FillModifyOnlyParms() const
  1664. {
  1665. if (g_pDataPackager == NULL) {
  1666. ASSUME_NOT_REACHED(); // This is only called from DataPackager::Create()
  1667. return SFERR_DRIVER_ERROR;
  1668. }
  1669. for (BYTE i = 0; i < 4; i++) {
  1670. FillModifyPacket200(i, INDEX_D1F1_200 + i, m_Ds[i], m_Fs[i]);
  1671. }
  1672. return SUCCESS;
  1673. }
  1674. HRESULT RTCSpring200::Modify(InternalEffect& newEffect, DWORD modFlags)
  1675. {
  1676. // Sanity Check
  1677. if (g_pDataPackager == NULL) {
  1678. ASSUME_NOT_REACHED();
  1679. return SFERR_DRIVER_ERROR;
  1680. }
  1681. g_pDataPackager->AllocateDataPackets(4);
  1682. RTCSpring200* pNewRTCSpring = (RTCSpring200*)(&newEffect);
  1683. for (BYTE i = 0; i < 4; i++) {
  1684. FillModifyPacket200(i, INDEX_D1F1_200 + i, pNewRTCSpring->m_Ds[i], pNewRTCSpring->m_Fs[i]);
  1685. }
  1686. return SUCCESS;
  1687. }
  1688. /************** FictionEffect1XX class **********************/
  1689. override HRESULT FrictionEffect1XX::FillCreatePacket(DataPacket& packet) const
  1690. {
  1691. // Packet to set modify data[index] of current effect
  1692. if (!packet.AllocateBytes(22)) {
  1693. return SFERR_DRIVER_ERROR;
  1694. }
  1695. // Fill in the Generic Effect Information
  1696. FillHeader1XX(packet, m_TypeID, NEW_EFFECT_ID);
  1697. packet.m_pData[10]= BYTE(g_TriggerMap1XX[m_TriggerPlayButton] & 0x7F); // Button play mask Low MidiByte
  1698. packet.m_pData[11]= BYTE(g_TriggerMap1XX[m_TriggerPlayButton] >> 7) & 0x7F; // Button play mask High MidiByte
  1699. // Friction Specific Parms
  1700. int twoByte = ((ConstantX()/COEFFICIENT_SCALE_1XX) * m_Gain) / GAIN_PERCENTAGE_SCALE;
  1701. packet.m_pData[12]= twoByte & 0x7F; // Spring/Damper/... Constant X Low
  1702. packet.m_pData[13]= (twoByte >> 7) & 0x7F; // Spring/Damper/... Constant X High
  1703. twoByte = ((ConstantY()/COEFFICIENT_SCALE_1XX) * m_Gain) / GAIN_PERCENTAGE_SCALE;
  1704. packet.m_pData[14]= twoByte & 0x7F; // Spring/Damper/... Constant Y Low
  1705. packet.m_pData[15]= (twoByte >> 7) & 0x7F; // Spring/Damper/... Constant Y High
  1706. packet.m_pData[20]= ComputeChecksum(packet, 20); // Checksum
  1707. // End of packet
  1708. packet.m_pData[21]= MIDI_EOX; // End of SysEX packet
  1709. return SUCCESS;
  1710. }
  1711. /******************* FrictionEffect200 class *********************/
  1712. BYTE FrictionEffect200::GetRepeatIndex() const
  1713. {
  1714. return INDEX_FE_REPEAT_200;
  1715. }
  1716. UINT FrictionEffect200::GetModifyOnlyNeeded() const
  1717. {
  1718. UINT retCount = 0;
  1719. if (m_TriggerPlayButton != 0) { // Trigger Button
  1720. retCount++;
  1721. }
  1722. if (m_TriggerRepeat != 0) { // Trigger repeat
  1723. retCount++;
  1724. }
  1725. if (m_Gain != 10000) { // Gain
  1726. retCount++;
  1727. }
  1728. return retCount;
  1729. }
  1730. HRESULT FrictionEffect200::FillModifyOnlyParms() const
  1731. {
  1732. if (g_pDataPackager == NULL) {
  1733. ASSUME_NOT_REACHED(); // This is only called from DataPackager::Create()
  1734. return SFERR_DRIVER_ERROR;
  1735. }
  1736. HRESULT hr = SUCCESS;
  1737. BYTE nextPacket = 1;
  1738. if (m_TriggerPlayButton != 0) { // Trigger Button
  1739. hr = FillModifyPacket200(nextPacket, INDEX_FE_BUTTONMAP_200, g_TriggerMap200[m_TriggerPlayButton]);
  1740. nextPacket++;
  1741. }
  1742. if (m_TriggerRepeat != 0) { // Trigger repeat
  1743. hr = FillModifyPacket200(nextPacket, INDEX_FE_BUTTONREPEAT_200, m_TriggerRepeat/DURATION_SCALE_200);
  1744. nextPacket++;
  1745. }
  1746. if (m_Gain != 10000) { // Gain
  1747. hr = FillModifyPacket200(nextPacket, INDEX_FE_GAIN_200, DWORD(float(m_Gain)/GAIN_SCALE_200));
  1748. nextPacket++;
  1749. }
  1750. return hr;
  1751. }
  1752. HRESULT FrictionEffect200::FillCreatePacket(DataPacket& packet) const
  1753. {
  1754. // Packet to set modify data[index] of current effect
  1755. if (!packet.AllocateBytes(14)) {
  1756. return SFERR_DRIVER_ERROR;
  1757. }
  1758. // Fill in the Generic Effect Information
  1759. FillHeader200(packet, m_TypeID, NEW_EFFECT_ID);
  1760. // All of the below items fit in one MidiByte (0..126/127) after conversion
  1761. unsigned short effectAngle = unsigned short(float(m_EffectAngle)/ANGLE_SCALE_200);
  1762. packet.m_pData[10]= BYTE(effectAngle & 0x7F); // Effect Angle
  1763. // Computed in create
  1764. packet.m_pData[11]= BYTE(float(ConstantX() + 10000)/FRICTION_SCALE_200) & 0x7F;
  1765. // End this puppy
  1766. packet.m_pData[12]= ComputeChecksum(packet, 12); // Checksum
  1767. packet.m_pData[13]= MIDI_EOX; // End of SysEX packet
  1768. return SUCCESS;
  1769. }
  1770. HRESULT FrictionEffect200::Modify(InternalEffect& newEffect, DWORD modFlags)
  1771. {
  1772. g_pDataPackager->ClearPackets();
  1773. HRESULT adjustResult = AdjustModifyParams(newEffect, modFlags);
  1774. if (FAILED(adjustResult)) {
  1775. return adjustResult;
  1776. }
  1777. FrictionEffect200* pEffect = (FrictionEffect200*)(&newEffect);
  1778. BYTE nextPacket = 0;
  1779. DWORD calc_byte;
  1780. HRESULT hr = SUCCESS;
  1781. if (modFlags & DIEP_DURATION) {
  1782. hr = FillModifyPacket200(nextPacket, INDEX_FE_DURATION_200, pEffect->m_Duration/DURATION_SCALE_200);
  1783. nextPacket++;
  1784. }
  1785. if (modFlags & DIEP_TRIGGERBUTTON) {
  1786. hr = FillModifyPacket200(nextPacket, INDEX_FE_BUTTONMAP_200, g_TriggerMap200[pEffect->m_TriggerPlayButton]);
  1787. nextPacket++;
  1788. }
  1789. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  1790. hr = FillModifyPacket200(nextPacket, INDEX_FE_BUTTONREPEAT_200, pEffect->m_TriggerRepeat/DURATION_SCALE_200);
  1791. nextPacket++;
  1792. }
  1793. if (modFlags & DIEP_GAIN) {
  1794. calc_byte = DWORD(float(pEffect->m_Gain)/GAIN_SCALE_200);
  1795. hr = FillModifyPacket200(nextPacket, INDEX_FE_GAIN_200, calc_byte);
  1796. nextPacket++;
  1797. }
  1798. if (modFlags & DIEP_SAMPLEPERIOD) {
  1799. calc_byte = DWORD(pEffect->m_SamplePeriod/DURATION_SCALE_200);
  1800. hr = FillModifyPacket200(nextPacket, INDEX_PE_SAMPLE_PERIOD_200, calc_byte);
  1801. nextPacket++;
  1802. }
  1803. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Send changed items
  1804. if (ConstantX() != pEffect->ConstantX()) {
  1805. calc_byte = DWORD(float(pEffect->ConstantX() + 10000)/FRICTION_SCALE_200) & 0x7F;
  1806. hr = FillModifyPacket200(nextPacket, INDEX_FE_COEEFICIENT_200, calc_byte);
  1807. nextPacket++;
  1808. }
  1809. }
  1810. if (hr == SUCCESS) {
  1811. return adjustResult;
  1812. }
  1813. return hr;
  1814. }
  1815. HRESULT FrictionEffect200::AdjustModifyParams(InternalEffect& newEffect, DWORD& modFlags)
  1816. {
  1817. // Check to see if values being modified are acceptable
  1818. DWORD possMod = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_DIRECTION;
  1819. /* if ((g_TotalModifiable & modFlags & possMod) == 0) { // Nothing to modify?
  1820. modFlags = 0;
  1821. return SFERR_NO_SUPPORT;
  1822. }
  1823. */
  1824. FrictionEffect200* pEffect = (FrictionEffect200*)(&newEffect);
  1825. unsigned short numPackets = 0;
  1826. BOOL playingChecked = FALSE;
  1827. HRESULT hr = SUCCESS;
  1828. if ((modFlags & (~possMod & DIEP_ALLPARAMS)) != 0) {
  1829. modFlags &= possMod;
  1830. hr = S_FALSE; // Cannot modify all they asked for
  1831. }
  1832. if (modFlags & DIEP_DURATION) {
  1833. if (m_Duration == pEffect->m_Duration) {
  1834. modFlags &= ~DIEP_DURATION; // Remove duration flag, unchanged
  1835. } else {
  1836. if (IsReallyPlaying(playingChecked) == TRUE) {
  1837. return DIERR_EFFECTPLAYING;
  1838. } else {
  1839. numPackets++;
  1840. }
  1841. }
  1842. }
  1843. if (modFlags & DIEP_TRIGGERBUTTON) {
  1844. if (m_TriggerPlayButton == pEffect->m_TriggerPlayButton) {
  1845. modFlags &= ~DIEP_TRIGGERBUTTON; // Remove trigger flag, unchanged
  1846. } else {
  1847. numPackets++;
  1848. }
  1849. }
  1850. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  1851. if (m_TriggerRepeat == pEffect->m_TriggerRepeat) {
  1852. modFlags &= ~DIEP_TRIGGERREPEATINTERVAL; // Remove trigger reapeat flag, unchanged
  1853. } else {
  1854. numPackets++;
  1855. }
  1856. }
  1857. if (modFlags & DIEP_GAIN) {
  1858. if (m_Gain == pEffect->m_Gain) {
  1859. modFlags &= ~DIEP_GAIN; // Remove gain flag, unchanged
  1860. } else {
  1861. numPackets++;
  1862. }
  1863. }
  1864. if (modFlags & DIEP_SAMPLEPERIOD) {
  1865. if (m_SamplePeriod == pEffect->m_SamplePeriod) {
  1866. modFlags &= ~DIEP_SAMPLEPERIOD; // Remove sample period flag, unchanged
  1867. } else {
  1868. numPackets++;
  1869. }
  1870. }
  1871. if (modFlags & DIEP_DIRECTION) {
  1872. modFlags |= DIEP_TYPESPECIFICPARAMS;
  1873. }
  1874. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Type specific change flagged
  1875. // Computed in create
  1876. if (ConstantX() == pEffect->ConstantX()) {
  1877. modFlags &= ~DIEP_TYPESPECIFICPARAMS; // Nothing really changed
  1878. } else {
  1879. numPackets++;
  1880. }
  1881. }
  1882. if (numPackets != 0) {
  1883. g_pDataPackager->AllocateDataPackets(numPackets);
  1884. }
  1885. return hr;
  1886. }
  1887. /******************* PeriodicEffect class *********************/
  1888. PeriodicEffect::PeriodicEffect() : InternalEffect(),
  1889. m_pEnvelope(NULL)
  1890. {
  1891. ::memset(&m_PeriodicData, 0, sizeof(m_PeriodicData));
  1892. }
  1893. PeriodicEffect::~PeriodicEffect()
  1894. {
  1895. if (m_pEnvelope != NULL) {
  1896. delete m_pEnvelope;
  1897. m_pEnvelope = NULL;
  1898. }
  1899. }
  1900. HRESULT PeriodicEffect::Create(const DIEFFECT& diEffect)
  1901. {
  1902. // Validation Check
  1903. ASSUME_NOT_NULL(diEffect.lpvTypeSpecificParams);
  1904. if (diEffect.lpvTypeSpecificParams == NULL) {
  1905. return SFERR_INVALID_PARAM;
  1906. }
  1907. if (diEffect.cbTypeSpecificParams != sizeof(m_PeriodicData)) {
  1908. return SFERR_INVALID_PARAM;
  1909. }
  1910. // Let the base class do its magic
  1911. HRESULT hr = InternalEffect::Create(diEffect);
  1912. if (FAILED(hr)) {
  1913. return hr;
  1914. }
  1915. // Fill the type specific
  1916. ::memcpy(&m_PeriodicData, diEffect.lpvTypeSpecificParams, sizeof(m_PeriodicData));
  1917. if (m_PeriodicData.dwMagnitude > 10000) {
  1918. m_PeriodicData.dwMagnitude = 10000;
  1919. hr = DI_TRUNCATED;
  1920. }
  1921. if (m_PeriodicData.lOffset > 10000) {
  1922. m_PeriodicData.lOffset = 10000;
  1923. hr = DI_TRUNCATED;
  1924. } else if (m_PeriodicData.lOffset < -10000) {
  1925. m_PeriodicData.lOffset = -10000;
  1926. hr = DI_TRUNCATED;
  1927. }
  1928. if (m_PeriodicData.dwPeriod > MAX_TIME_200) {
  1929. m_PeriodicData.dwPeriod = MAX_TIME_200;
  1930. hr = DI_TRUNCATED;
  1931. }
  1932. return hr;
  1933. }
  1934. /******************* PeriodicEffect1XX class ******************/
  1935. HRESULT PeriodicEffect1XX::Create(const DIEFFECT& diEffect)
  1936. {
  1937. if (diEffect.lpvTypeSpecificParams == NULL) {
  1938. ASSUME_NOT_REACHED(); // DI is flaking
  1939. return SFERR_INVALID_PARAM;
  1940. }
  1941. HRESULT hr;
  1942. if (diEffect.cbTypeSpecificParams == sizeof(DICONSTANTFORCE)) { // Special case Constant Force
  1943. if (m_TypeID != ET_SE_CONSTANT_FORCE) {
  1944. ASSUME_NOT_REACHED(); // DI is flaking
  1945. return SFERR_INVALID_PARAM;
  1946. }
  1947. DIPERIODIC periodic;
  1948. DICONSTANTFORCE* pConstantForce = (DICONSTANTFORCE*)(diEffect.lpvTypeSpecificParams);
  1949. if (pConstantForce->lMagnitude < 0) {
  1950. periodic.lOffset = -1; // We use offset to indicate sign
  1951. periodic.dwMagnitude = DWORD(0 - pConstantForce->lMagnitude);
  1952. } else {
  1953. periodic.lOffset = 1;
  1954. periodic.dwMagnitude = DWORD(pConstantForce->lMagnitude);
  1955. }
  1956. periodic.dwPhase = 0;
  1957. periodic.dwPeriod = 0; // Conversion will make a freq of 1
  1958. DIEFFECT* pDIEffect = (DIEFFECT*)(&diEffect); // Hack to temp remove constness
  1959. pDIEffect->cbTypeSpecificParams = sizeof(DIPERIODIC);
  1960. pDIEffect->lpvTypeSpecificParams = &periodic; // Replace Constant Force Parms with periodic
  1961. hr = PeriodicEffect::Create(diEffect);
  1962. pDIEffect->cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
  1963. pDIEffect->lpvTypeSpecificParams = pConstantForce; // Return parms back
  1964. } else if (diEffect.cbTypeSpecificParams == sizeof(DIRAMPFORCE)) { // Special case RampForce
  1965. if (m_TypeID != ET_SE_RAMPUP) {
  1966. ASSUME_NOT_REACHED(); // DI is flaking
  1967. return SFERR_INVALID_PARAM;
  1968. }
  1969. DIPERIODIC periodic;
  1970. DIRAMPFORCE* pRampForce = (DIRAMPFORCE*)(diEffect.lpvTypeSpecificParams);
  1971. if (pRampForce->lStart < pRampForce->lEnd) {
  1972. m_TypeID = ET_SE_RAMPDOWN;
  1973. periodic.dwMagnitude = DWORD(pRampForce->lEnd - pRampForce->lStart)/2;
  1974. } else {
  1975. periodic.dwMagnitude = DWORD(pRampForce->lStart - pRampForce->lEnd)/2;
  1976. }
  1977. periodic.lOffset = (pRampForce->lStart + pRampForce->lEnd)/2;
  1978. periodic.dwPeriod = 0; // Conversion will make a freq of 1
  1979. DIEFFECT* pDIEffect = (DIEFFECT*)(&diEffect); // Hack to temp remove constness
  1980. pDIEffect->cbTypeSpecificParams = sizeof(DIPERIODIC);
  1981. pDIEffect->lpvTypeSpecificParams = &periodic; // Replace Constant Force Parms with periodic
  1982. hr = PeriodicEffect::Create(diEffect);
  1983. pDIEffect->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
  1984. pDIEffect->lpvTypeSpecificParams = pRampForce; // Return parms back
  1985. } else {
  1986. hr = PeriodicEffect::Create(diEffect);
  1987. }
  1988. // How did creation go?
  1989. if (hr != SUCCESS) {
  1990. return hr; // Not so good
  1991. }
  1992. ASSUME(m_pEnvelope == NULL);
  1993. m_pEnvelope = new Envelope1XX(diEffect.lpEnvelope, Offset(), m_Duration);
  1994. // Is it closer to sine or cosine
  1995. if (m_TypeID == ET_SE_SINE) {
  1996. if (((Phase() >= 4500) && (Phase() < 13500)) || ((Phase() >= 22500) && (Phase() < 31500))) {
  1997. m_TypeID = ET_SE_COSINE;
  1998. }
  1999. } else if ((Phase() >= 9000) && (Phase() < 27000)) {
  2000. if (m_TypeID == SE_SQUAREHIGH) {
  2001. m_TypeID = SE_SQUARELOW;
  2002. } else if (m_TypeID == SE_TRIANGLEUP) {
  2003. m_TypeID = SE_TRIANGLEDOWN;
  2004. }
  2005. }
  2006. return SUCCESS;
  2007. }
  2008. void PeriodicEffect1XX::DIToJolt(DWORD mag, DWORD off, DWORD gain, DWORD& max, DWORD& min) const
  2009. {
  2010. if (m_TypeID == ET_SE_CONSTANT_FORCE) {
  2011. ASSUME(off == -1 || off == 1); // Indicates sign for ConstantForce
  2012. min = 0;
  2013. max = off * (mag/GAIN_PERCENTAGE_SCALE) * gain;
  2014. } else {
  2015. DWORD half = ((mag/GAIN_PERCENTAGE_SCALE) * gain)/2;
  2016. min = off - half;
  2017. max = off + half;
  2018. }
  2019. }
  2020. DWORD PeriodicEffect1XX::DIPeriodToJoltFreq(DWORD period)
  2021. {
  2022. if (period == 0) {
  2023. return 1;
  2024. }
  2025. DWORD freq = FREQUENCY_SCALE_1XX/period;
  2026. if (freq == 0) {
  2027. freq = 1;
  2028. } else if (freq > 500) {
  2029. freq = 500;
  2030. }
  2031. return freq;
  2032. }
  2033. HRESULT PeriodicEffect1XX::FillCreatePacket(DataPacket& packet) const
  2034. {
  2035. // Sanity check
  2036. if (m_pEnvelope == NULL) {
  2037. ASSUME_NOT_REACHED(); // Should never happen
  2038. return SFERR_DRIVER_ERROR;
  2039. }
  2040. // Packet to set modify data[index] of current effect
  2041. if (!packet.AllocateBytes(34)) {
  2042. return SFERR_DRIVER_ERROR;
  2043. }
  2044. // Fill in the Generic Effect Information
  2045. FillHeader1XX(packet, m_TypeID, NEW_EFFECT_ID);
  2046. // Periodic Specific Parms (Freq, Max, Min)
  2047. packet.m_pData[10]= BYTE(g_TriggerMap1XX[m_TriggerPlayButton] & 0x7F); // Button play mask Low MidiByte
  2048. packet.m_pData[11]= BYTE(g_TriggerMap1XX[m_TriggerPlayButton] >> 7) & 0x7F; // Button play mask High MidiByte
  2049. packet.m_pData[12] = BYTE(m_EffectAngle & 0x7F); // DirectionAngle Low
  2050. packet.m_pData[13] = BYTE(m_EffectAngle >> 7) & 0x7F; // DirectionAngle High
  2051. packet.m_pData[14] = 100; // Gain (encoded in coeficents)
  2052. packet.m_pData[15]= BYTE(500 & 0x7F); // ForceOutput Rate LowByte
  2053. packet.m_pData[16]= BYTE(500 >> 7) & 0x7F; // ForceOutput Rate HighByte
  2054. packet.m_pData[17]= 0x7F; // Percent LowByte
  2055. packet.m_pData[18]= 0; // Percent HighByte
  2056. // Envelope
  2057. // Envelope1XX* pEnvelope = dynamic_cast<Envelope1XX*>(m_pEnvelope);
  2058. Envelope1XX* pEnvelope = (Envelope1XX*)(m_pEnvelope);
  2059. packet.m_pData[19] = BYTE(pEnvelope->m_StartPercent & 0x7F); // Initial attack level
  2060. packet.m_pData[20] = BYTE(pEnvelope->m_AttackTime& 0x7F); // AttackTime Low
  2061. packet.m_pData[21] = BYTE(pEnvelope->m_AttackTime>> 7) & 0x7F; // AttackTime High
  2062. packet.m_pData[22] = BYTE(pEnvelope->m_SustainPercent & 0x7F); // Sustain level
  2063. packet.m_pData[23] = BYTE(pEnvelope->m_SustainTime & 0x7F); // SustainTime Low
  2064. packet.m_pData[24] = BYTE(pEnvelope->m_SustainTime >> 7) & 0x7F; // SustainTime High
  2065. packet.m_pData[25] = BYTE(pEnvelope->m_EndPercent & 0x7F); // What to decay to
  2066. // -- Duration of decay is ficugred from total duration
  2067. DWORD freq = DIPeriodToJoltFreq(Period());
  2068. packet.m_pData[26]= BYTE(freq & 0x7F); // Frequency LowByte
  2069. packet.m_pData[27]= BYTE(freq >> 7) & 0x7F; // Frequency HighByte
  2070. DWORD max, min;
  2071. DIToJolt(Magnitude(), Offset(), m_Gain, max, min);
  2072. min /= COEFFICIENT_SCALE_1XX;
  2073. max /= COEFFICIENT_SCALE_1XX;
  2074. packet.m_pData[28]= BYTE(max & 0x7F); // Max LowByte
  2075. packet.m_pData[29]= BYTE(max >> 7) & 0x7F; // Max HighByte
  2076. packet.m_pData[30]= BYTE(min & 0x7F); // Min LowByte
  2077. packet.m_pData[31]= BYTE(min >> 7) & 0x7F; // Min HighByte
  2078. packet.m_pData[32]= ComputeChecksum(packet, 32); // Checksum
  2079. // End of packet
  2080. packet.m_pData[33]= MIDI_EOX; // End of SysEX packet
  2081. return SUCCESS;
  2082. }
  2083. HRESULT PeriodicEffect1XX::AdjustModifyParams(InternalEffect& newEffect, DWORD& modFlags) const
  2084. {
  2085. // Check to see if values being modified are acceptable
  2086. DWORD possMod = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TYPESPECIFICPARAMS;
  2087. if ((g_TotalModifiable & modFlags & possMod) == 0) { // Nothing to modify?
  2088. modFlags = 0;
  2089. return SFERR_NO_SUPPORT;
  2090. }
  2091. PeriodicEffect1XX* pEffect = (PeriodicEffect1XX*)(&newEffect);
  2092. unsigned short numPackets = 0;
  2093. if (modFlags & DIEP_DURATION) {
  2094. if (m_Duration == pEffect->m_Duration) {
  2095. modFlags &= ~DIEP_DURATION; // Remove duration flag, unchanged
  2096. } else {
  2097. numPackets += 2;
  2098. }
  2099. }
  2100. if (modFlags & DIEP_TRIGGERBUTTON) {
  2101. if (m_TriggerPlayButton == pEffect->m_TriggerPlayButton) {
  2102. modFlags &= ~DIEP_TRIGGERBUTTON; // Remove trigger flag, unchanged
  2103. } else {
  2104. numPackets += 2;
  2105. }
  2106. }
  2107. // Either gain or type specific changed
  2108. if (modFlags & (DIEP_GAIN | DIEP_TYPESPECIFICPARAMS)) {
  2109. DWORD oldMax, oldMin, newMax, newMin;
  2110. DIToJolt(Magnitude(), Offset(), m_Gain, oldMax, oldMin);
  2111. DIToJolt(pEffect->Magnitude(), pEffect->Offset(), pEffect->m_Gain, newMax, newMin);
  2112. int numTypeSpecificChanged = 0;
  2113. // Max changed?
  2114. if (oldMax != newMax) {
  2115. numTypeSpecificChanged = 2;
  2116. }
  2117. // Min changed?
  2118. if (oldMin != newMin) {
  2119. numTypeSpecificChanged += 2;
  2120. }
  2121. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Don't check these if gain only
  2122. // Phase (1XX cannot change)
  2123. if (Phase() != pEffect->Phase()) {
  2124. return SFERR_NO_SUPPORT;
  2125. }
  2126. // Period
  2127. if (Period() != pEffect->Period()) {
  2128. numTypeSpecificChanged += 2;
  2129. }
  2130. }
  2131. if (numTypeSpecificChanged == 0) {
  2132. modFlags &= ~(DIEP_TYPESPECIFICPARAMS | DIEP_GAIN); // Nothing really changed
  2133. } else {
  2134. numPackets += (USHORT)numTypeSpecificChanged;
  2135. }
  2136. }
  2137. if (numPackets != 0) {
  2138. g_pDataPackager->AllocateDataPackets(numPackets);
  2139. }
  2140. return SUCCESS;
  2141. }
  2142. HRESULT PeriodicEffect1XX::Modify(InternalEffect& newEffect, DWORD modFlags)
  2143. {
  2144. g_pDataPackager->ClearPackets();
  2145. HRESULT hr = AdjustModifyParams(newEffect, modFlags);
  2146. if (hr != SUCCESS) {
  2147. return hr;
  2148. }
  2149. PeriodicEffect1XX* pEffect = (PeriodicEffect1XX*)(&newEffect);
  2150. BYTE nextPacket = 0;
  2151. if (modFlags & DIEP_DURATION) {
  2152. hr = FillModifyPacket1XX(nextPacket, INDEX_DURATION, pEffect->m_Duration/DURATION_SCALE_1XX);
  2153. nextPacket += 2;
  2154. }
  2155. if (modFlags & DIEP_TRIGGERBUTTON) {
  2156. hr = FillModifyPacket1XX(nextPacket, INDEX_TRIGGERBUTTONMASK, g_TriggerMap1XX[pEffect->m_TriggerPlayButton]);
  2157. nextPacket += 2;
  2158. }
  2159. if (modFlags & (DIEP_GAIN | DIEP_TYPESPECIFICPARAMS)) {
  2160. DWORD oldMax, oldMin, newMax, newMin;
  2161. DIToJolt(Magnitude(), Offset(), m_Gain, oldMax, oldMin);
  2162. DIToJolt(pEffect->Magnitude(), pEffect->Offset(), pEffect->m_Gain, newMax, newMin);
  2163. if (oldMax != newMax) {
  2164. hr = FillModifyPacket1XX(nextPacket, INDEX_X_COEEFICIENT, (newMax/COEFFICIENT_SCALE_1XX));
  2165. nextPacket += 2;
  2166. }
  2167. if (oldMin != newMin) {
  2168. hr = FillModifyPacket1XX(nextPacket, INDEX_X_COEEFICIENT, (newMin/COEFFICIENT_SCALE_1XX));
  2169. nextPacket += 2;
  2170. }
  2171. if (Period() != pEffect->Period()) {
  2172. hr = FillModifyPacket1XX(nextPacket, INDEX_X_CENTER, pEffect->Period()/COEFFICIENT_SCALE_1XX);
  2173. nextPacket += 2;
  2174. }
  2175. }
  2176. return hr;
  2177. }
  2178. /******************* PeriodicEffect200 class ******************/
  2179. BYTE PeriodicEffect200::GetRepeatIndex() const
  2180. {
  2181. return INDEX_PE_REPEAT_200;
  2182. }
  2183. long int PeriodicEffect200::Phase() const
  2184. {
  2185. long int phase = m_PeriodicData.dwPhase;
  2186. if (m_EffectAngle <= 18000) {
  2187. phase += 18000;
  2188. phase %= 36000;
  2189. }
  2190. return phase;
  2191. }
  2192. HRESULT PeriodicEffect200::Create(const DIEFFECT& diEffect)
  2193. {
  2194. HRESULT hr = PeriodicEffect::Create(diEffect);
  2195. // How did creation go?
  2196. if (FAILED(hr)) {
  2197. return hr; // Not so good
  2198. }
  2199. ASSUME(m_pEnvelope == NULL);
  2200. m_PercentAdjustment = m_PercentX + (m_PercentY * g_ForceFeedbackDevice.GetYMappingPercent(m_TypeID))/100;
  2201. m_Gain = m_Gain/100 * m_PercentAdjustment;
  2202. m_pEnvelope = new Envelope200(diEffect.lpEnvelope, Magnitude(), m_Duration, hr);
  2203. return hr;
  2204. }
  2205. UINT PeriodicEffect200::GetModifyOnlyNeeded() const
  2206. {
  2207. UINT retCount = 0;
  2208. if ((m_SamplePeriod/DURATION_SCALE_200) != 1) {
  2209. retCount++;
  2210. }
  2211. if (m_TriggerPlayButton != 0) { // Trigger Button
  2212. retCount++;
  2213. }
  2214. if (m_TriggerRepeat != 0) { // Trigger repeat
  2215. retCount++;
  2216. }
  2217. return retCount;
  2218. }
  2219. HRESULT PeriodicEffect200::FillModifyOnlyParms() const
  2220. {
  2221. if (g_pDataPackager == NULL) {
  2222. ASSUME_NOT_REACHED(); // This is only called from DataPackager::Create()
  2223. return SFERR_DRIVER_ERROR;
  2224. }
  2225. HRESULT hr = SUCCESS;
  2226. BYTE nextPacket = 1;
  2227. DWORD calc_byte = DWORD(m_SamplePeriod/DURATION_SCALE_200);
  2228. if (calc_byte != 1) { // Sample period
  2229. hr = FillModifyPacket200(nextPacket, INDEX_PE_SAMPLE_PERIOD_200, calc_byte);
  2230. nextPacket++;
  2231. }
  2232. if (m_TriggerPlayButton != 0) { // Trigger Button
  2233. hr = FillModifyPacket200(nextPacket, INDEX_PE_BUTTONMAP_200, g_TriggerMap200[m_TriggerPlayButton]);
  2234. nextPacket++;
  2235. }
  2236. if (m_TriggerRepeat != 0) { // Trigger repeat
  2237. hr = FillModifyPacket200(nextPacket, INDEX_PE_BUTTONREPEAT_200, m_TriggerRepeat/DURATION_SCALE_200);
  2238. nextPacket++;
  2239. }
  2240. return hr;
  2241. }
  2242. HRESULT PeriodicEffect200::FillCreatePacket(DataPacket& packet) const
  2243. {
  2244. // Sanity check
  2245. if (m_pEnvelope == NULL) {
  2246. ASSUME_NOT_REACHED(); // Should never happen
  2247. return SFERR_DRIVER_ERROR;
  2248. }
  2249. // Packet to set modify data[index] of current effect
  2250. if (!packet.AllocateBytes(26)) {
  2251. return SFERR_DRIVER_ERROR;
  2252. }
  2253. // Fill in the Generic Effect Information
  2254. FillHeader200(packet, m_TypeID, NEW_EFFECT_ID);
  2255. unsigned short calc_byte = unsigned short(float(m_EffectAngle)/ANGLE_SCALE_200);
  2256. packet.m_pData[10]= BYTE(calc_byte & 0x7F); // Effect Angle
  2257. calc_byte = unsigned short(float(m_Gain)/GAIN_SCALE_200);
  2258. packet.m_pData[11]= BYTE(calc_byte & 0x7F); // Gain
  2259. calc_byte = unsigned short(float(Phase())/PHASE_SCALE_200);
  2260. packet.m_pData[12]= BYTE(calc_byte & 0x7F); // Phase Low
  2261. packet.m_pData[13]= BYTE(calc_byte >> 7) & 0x7F; // Phase High
  2262. // Envelope
  2263. Envelope200* pEnvelope = (Envelope200*)(m_pEnvelope);
  2264. packet.m_pData[14] = BYTE(pEnvelope->m_StartPercent & 0x7F); // Initial attack level
  2265. packet.m_pData[15] = BYTE(pEnvelope->m_AttackTime& 0x7F); // AttackTime Low
  2266. packet.m_pData[16] = BYTE(pEnvelope->m_AttackTime>> 7) & 0x7F; // AttackTime High
  2267. packet.m_pData[17] = BYTE(pEnvelope->m_SustainPercent & 0x7F); // Sustain level
  2268. packet.m_pData[18] = BYTE(pEnvelope->m_FadeStart & 0x7F); // SustainTime Low
  2269. packet.m_pData[19] = BYTE(pEnvelope->m_FadeStart >> 7) & 0x7F; // SustainTime High
  2270. packet.m_pData[20] = BYTE(pEnvelope->m_EndPercent & 0x7F); // What to decay to
  2271. // -- Duration of decay is figured by the firmware from total duration
  2272. calc_byte = unsigned short(Period()/DURATION_SCALE_200);
  2273. if (calc_byte == 0) {
  2274. calc_byte = 1;
  2275. }
  2276. packet.m_pData[21] = BYTE(calc_byte & 0x7F); // Period Low MidiByte
  2277. packet.m_pData[22] = BYTE(calc_byte >> 7) & 0x7F; // Period High MidiByte
  2278. // Convert offset to device percentage (0 to +126 --- +63 = 0 percent)
  2279. calc_byte = unsigned short(float(Offset()/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE);
  2280. packet.m_pData[23] = BYTE(calc_byte & 0x7F); // Offset
  2281. packet.m_pData[24]= ComputeChecksum(packet, 24); // Checksum
  2282. // End of packet
  2283. packet.m_pData[25]= MIDI_EOX; // End of SysEX packet
  2284. return SUCCESS;
  2285. }
  2286. HRESULT PeriodicEffect200::AdjustModifyParams(InternalEffect& newEffect, DWORD& modFlags)
  2287. {
  2288. // Check to see if values being modified are acceptable
  2289. DWORD possMod = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_SAMPLEPERIOD | DIEP_ENVELOPE | DIEP_DIRECTION;
  2290. if ((g_TotalModifiable & modFlags & possMod) == 0) { // Nothing to modify?
  2291. modFlags = 0;
  2292. return SFERR_NO_SUPPORT;
  2293. }
  2294. PeriodicEffect200* pEffect = (PeriodicEffect200*)(&newEffect);
  2295. unsigned short numPackets = 0;
  2296. HRESULT hr = SUCCESS;
  2297. if ((modFlags & (DIEP_AXES)) != 0) {
  2298. hr = S_FALSE; // Cannot modify all they asked for
  2299. }
  2300. BOOL playingChecked = FALSE;
  2301. if (modFlags & DIEP_DURATION) {
  2302. if (m_Duration == pEffect->m_Duration) {
  2303. modFlags &= ~DIEP_DURATION; // Remove duration flag, unchanged
  2304. } else {
  2305. if (IsReallyPlaying(playingChecked) == TRUE) {
  2306. return DIERR_EFFECTPLAYING;
  2307. } else {
  2308. modFlags |= DIEP_ENVELOPE; // Duration change forces envelope change
  2309. numPackets++;
  2310. }
  2311. }
  2312. }
  2313. if (modFlags & DIEP_DIRECTION) {
  2314. modFlags |= (DIEP_GAIN | DIEP_TYPESPECIFICPARAMS);
  2315. if (m_EffectAngle != pEffect->m_EffectAngle) {
  2316. numPackets++;
  2317. } else {
  2318. modFlags &= ~DIEP_DIRECTION;
  2319. }
  2320. }
  2321. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Check type specific
  2322. int numTypeSpecificChanged = 0;
  2323. if (Phase() != pEffect->Phase()) {
  2324. numTypeSpecificChanged++;
  2325. }
  2326. if (Period() != pEffect->Period()) {
  2327. numTypeSpecificChanged++;
  2328. }
  2329. if (Offset() != pEffect->Offset()) {
  2330. numTypeSpecificChanged++;
  2331. }
  2332. if (Magnitude() != pEffect->Magnitude()) {
  2333. modFlags |= DIEP_ENVELOPE; // This effects the envelope
  2334. }
  2335. if (numTypeSpecificChanged == 0) {
  2336. modFlags &= ~DIEP_TYPESPECIFICPARAMS; // Nothing really changed
  2337. } else {
  2338. numPackets += (USHORT)numTypeSpecificChanged;
  2339. }
  2340. }
  2341. if (modFlags & DIEP_ENVELOPE) {
  2342. int numEnvelopeChanged = 0;
  2343. if (m_pEnvelope == NULL || pEffect->m_pEnvelope == NULL) {
  2344. ASSUME_NOT_REACHED(); // Envelope should always be created!
  2345. } else {
  2346. Envelope200* pOldEnvelope = (Envelope200*)(m_pEnvelope);
  2347. Envelope200* pNewEnvelope = (Envelope200*)(pEffect->m_pEnvelope);
  2348. if (pOldEnvelope->m_AttackTime != pNewEnvelope->m_AttackTime) {
  2349. numEnvelopeChanged++;
  2350. }
  2351. if (pOldEnvelope->m_FadeStart != pNewEnvelope->m_FadeStart) {
  2352. numEnvelopeChanged++;
  2353. }
  2354. if (pOldEnvelope->m_StartPercent != pNewEnvelope->m_StartPercent) {
  2355. numEnvelopeChanged++;
  2356. }
  2357. if (pOldEnvelope->m_SustainPercent != pNewEnvelope->m_SustainPercent) {
  2358. numEnvelopeChanged++;
  2359. }
  2360. if (pOldEnvelope->m_EndPercent != pNewEnvelope->m_EndPercent) {
  2361. numEnvelopeChanged++;
  2362. }
  2363. }
  2364. if (numEnvelopeChanged == 0) {
  2365. modFlags &= ~DIEP_ENVELOPE; // Remove envelope flag, unchanged
  2366. } else {
  2367. numPackets += (USHORT)numEnvelopeChanged;
  2368. }
  2369. }
  2370. if (modFlags & DIEP_TRIGGERBUTTON) {
  2371. if (m_TriggerPlayButton == pEffect->m_TriggerPlayButton) {
  2372. modFlags &= ~DIEP_TRIGGERBUTTON; // Remove trigger flag, unchanged
  2373. } else {
  2374. numPackets++;
  2375. }
  2376. }
  2377. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  2378. if (m_TriggerRepeat == pEffect->m_TriggerRepeat) {
  2379. modFlags &= ~DIEP_TRIGGERREPEATINTERVAL; // Remove trigger reapeat flag, unchanged
  2380. } else {
  2381. numPackets++;
  2382. }
  2383. }
  2384. if (modFlags & DIEP_GAIN) {
  2385. if (m_Gain == pEffect->m_Gain) {
  2386. modFlags &= ~DIEP_GAIN; // Remove gain flag, unchanged
  2387. } else {
  2388. numPackets++;
  2389. }
  2390. }
  2391. if (modFlags & DIEP_SAMPLEPERIOD) {
  2392. if (m_SamplePeriod == pEffect->m_SamplePeriod) {
  2393. modFlags &= ~DIEP_SAMPLEPERIOD; // Remove sample period flag, unchanged
  2394. } else {
  2395. numPackets++;
  2396. }
  2397. }
  2398. if (numPackets != 0) {
  2399. g_pDataPackager->AllocateDataPackets(numPackets);
  2400. }
  2401. return hr;
  2402. }
  2403. HRESULT PeriodicEffect200::Modify(InternalEffect& newEffect, DWORD modFlags)
  2404. {
  2405. g_pDataPackager->ClearPackets();
  2406. HRESULT adjustReturned = AdjustModifyParams(newEffect, modFlags);
  2407. if (FAILED(adjustReturned)) {
  2408. return adjustReturned;
  2409. }
  2410. HRESULT hr = SUCCESS;
  2411. PeriodicEffect200* pEffect = (PeriodicEffect200*)(&newEffect);
  2412. BYTE nextPacket = 0;
  2413. DWORD calc_byte;
  2414. if (modFlags & DIEP_DURATION) {
  2415. hr = FillModifyPacket200(nextPacket, INDEX_PE_DURATION_200, pEffect->m_Duration/DURATION_SCALE_200);
  2416. nextPacket++;
  2417. }
  2418. if (modFlags & DIEP_DIRECTION) {
  2419. hr = FillModifyPacket200(nextPacket, INDEX_PE_DIRECTIONANGLE_200, unsigned short(float(pEffect->m_EffectAngle)/ANGLE_SCALE_200));
  2420. nextPacket++;
  2421. }
  2422. if (modFlags & DIEP_ENVELOPE) {
  2423. Envelope200* pOldEnvelope = (Envelope200*)(m_pEnvelope);
  2424. Envelope200* pNewEnvelope = (Envelope200*)(pEffect->m_pEnvelope);
  2425. if (pOldEnvelope->m_StartPercent != pNewEnvelope->m_StartPercent) {
  2426. hr = FillModifyPacket200(nextPacket, INDEX_PE_STARTPERCENT_200, pNewEnvelope->m_StartPercent);
  2427. nextPacket++;
  2428. }
  2429. if (pOldEnvelope->m_AttackTime != pNewEnvelope->m_AttackTime) {
  2430. hr = FillModifyPacket200(nextPacket, INDEX_PE_ATTTACK_TIME_200, pNewEnvelope->m_AttackTime);
  2431. nextPacket++;
  2432. }
  2433. if (pOldEnvelope->m_SustainPercent != pNewEnvelope->m_SustainPercent) {
  2434. hr = FillModifyPacket200(nextPacket, INDEX_PE_SUSTAINPERCENT_200, pNewEnvelope->m_SustainPercent);
  2435. nextPacket++;
  2436. }
  2437. if (pOldEnvelope->m_FadeStart != pNewEnvelope->m_FadeStart) {
  2438. hr = FillModifyPacket200(nextPacket, INDEX_PE_FADESTART_200, pNewEnvelope->m_FadeStart);
  2439. nextPacket++;
  2440. }
  2441. if (pOldEnvelope->m_EndPercent != pNewEnvelope->m_EndPercent) {
  2442. hr = FillModifyPacket200(nextPacket, INDEX_PE_ENDPERCENT_200, pNewEnvelope->m_EndPercent);
  2443. nextPacket++;
  2444. }
  2445. }
  2446. if (modFlags & DIEP_TRIGGERBUTTON) {
  2447. hr = FillModifyPacket200(nextPacket, INDEX_PE_BUTTONMAP_200, g_TriggerMap200[pEffect->m_TriggerPlayButton]);
  2448. nextPacket++;
  2449. }
  2450. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  2451. hr = FillModifyPacket200(nextPacket, INDEX_PE_BUTTONREPEAT_200, pEffect->m_TriggerRepeat/DURATION_SCALE_200);
  2452. nextPacket++;
  2453. }
  2454. if (modFlags & DIEP_GAIN) {
  2455. calc_byte = DWORD(float(pEffect->m_Gain)/GAIN_SCALE_200);
  2456. hr = FillModifyPacket200(nextPacket, INDEX_PE_GAIN_200, calc_byte);
  2457. nextPacket++;
  2458. }
  2459. if (modFlags & DIEP_SAMPLEPERIOD) {
  2460. calc_byte = DWORD(pEffect->m_SamplePeriod/DURATION_SCALE_200);
  2461. hr = FillModifyPacket200(nextPacket, INDEX_PE_SAMPLE_PERIOD_200, calc_byte);
  2462. nextPacket++;
  2463. }
  2464. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Send changed items
  2465. if (Phase() != pEffect->Phase()) {
  2466. calc_byte = DWORD(float(pEffect->Phase())/PHASE_SCALE_200);
  2467. hr = FillModifyPacket200(nextPacket, INDEX_PE_PHASE_200, calc_byte);
  2468. nextPacket++;
  2469. }
  2470. if (Period() != pEffect->Period()) {
  2471. hr = FillModifyPacket200(nextPacket, INDEX_PE_PERIOD_200, pEffect->Period()/DURATION_SCALE_200);
  2472. nextPacket++;
  2473. }
  2474. if (Offset() != pEffect->Offset()) {
  2475. calc_byte = DWORD(float(pEffect->Offset()/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE);
  2476. hr = FillModifyPacket200(nextPacket, INDEX_PE_OFFSET_200, calc_byte);
  2477. nextPacket++;
  2478. }
  2479. }
  2480. if (hr == SUCCESS) {
  2481. return adjustReturned;
  2482. }
  2483. return hr;
  2484. }
  2485. /******************* SawtoothEffect200 class ******************/
  2486. HRESULT SawtoothEffect200::Create(const DIEFFECT& diEffect)
  2487. {
  2488. HRESULT retVal = PeriodicEffect200::Create(diEffect);
  2489. if ((m_IsUp && (m_EffectAngle < 18000)) || (!m_IsUp && (m_EffectAngle > 18000))) { // SawtoothUp use 0 degrees
  2490. m_EffectAngle = 18000;
  2491. } else { // SawtoothDown use 180 degress
  2492. m_EffectAngle = 0;
  2493. }
  2494. return retVal;
  2495. }
  2496. long int SawtoothEffect200::Phase() const
  2497. {
  2498. return m_PeriodicData.dwPhase;
  2499. }
  2500. /******************* RampEffect200 class ******************/
  2501. HRESULT RampEffect200::Create(const DIEFFECT& diEffect)
  2502. {
  2503. // Sanity checks
  2504. if (diEffect.cbTypeSpecificParams != sizeof(DIRAMPFORCE)) {
  2505. ASSUME_NOT_REACHED();
  2506. return SFERR_INVALID_PARAM;
  2507. }
  2508. if (diEffect.lpvTypeSpecificParams == NULL) {
  2509. ASSUME_NOT_REACHED();
  2510. return SFERR_INVALID_PARAM;
  2511. }
  2512. // Ramps cannot have infinite duration
  2513. if (diEffect.dwDuration == INFINITE) {
  2514. ASSUME_NOT_REACHED();
  2515. return SFERR_INVALID_PARAM;
  2516. }
  2517. // Create periodic structure and put in the correct values
  2518. DIPERIODIC periodic;
  2519. DIRAMPFORCE* pRampForce = (DIRAMPFORCE*)(diEffect.lpvTypeSpecificParams);
  2520. periodic.dwPhase = 0;
  2521. periodic.dwPeriod = diEffect.dwDuration;
  2522. periodic.lOffset = -(pRampForce->lStart + pRampForce->lEnd)/2;
  2523. if (pRampForce->lStart < pRampForce->lEnd) { // What direction are we
  2524. m_IsUp = TRUE;
  2525. periodic.dwMagnitude = DWORD(pRampForce->lEnd - pRampForce->lStart)/2;
  2526. } else {
  2527. m_IsUp = FALSE;
  2528. periodic.dwMagnitude = DWORD(pRampForce->lStart - pRampForce->lEnd)/2;
  2529. }
  2530. // Replace the periodic structure (ignorning constness), call sawtooth create, then put the old back
  2531. DIEFFECT* pDIEffect = (DIEFFECT*)(&diEffect); // Hack to temp remove constness
  2532. pDIEffect->cbTypeSpecificParams = sizeof(DIPERIODIC);
  2533. pDIEffect->lpvTypeSpecificParams = &periodic; // Replace Ramp Parms with periodic
  2534. HRESULT retVal = SawtoothEffect200::Create(diEffect);
  2535. pDIEffect->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
  2536. pDIEffect->lpvTypeSpecificParams = pRampForce; // Return parms back
  2537. // We are done
  2538. return retVal;
  2539. }
  2540. override HRESULT RampEffect200::Modify(InternalEffect& newEffect, DWORD modFlags)
  2541. {
  2542. if (modFlags & DIEP_DURATION) {
  2543. modFlags |= DIEP_TYPESPECIFICPARAMS;
  2544. }
  2545. if (modFlags & DIEP_TYPESPECIFICPARAMS) {
  2546. RampEffect200* pEffect = (RampEffect200*)(&newEffect);
  2547. if (m_IsUp != pEffect->m_IsUp) {
  2548. modFlags |= DIEP_DIRECTION;
  2549. }
  2550. }
  2551. return SawtoothEffect200::Modify(newEffect, modFlags);
  2552. }
  2553. /******************* ConstantForceEffect class ******************/
  2554. ConstantForceEffect::ConstantForceEffect() : InternalEffect(),
  2555. m_pEnvelope(NULL)
  2556. {
  2557. }
  2558. ConstantForceEffect::~ConstantForceEffect()
  2559. {
  2560. if (m_pEnvelope != NULL) {
  2561. delete m_pEnvelope;
  2562. m_pEnvelope = NULL;
  2563. }
  2564. }
  2565. HRESULT ConstantForceEffect::Create(const DIEFFECT& diEffect)
  2566. {
  2567. // Zero out old struct
  2568. ::memset(&m_ConstantForceData, 0, sizeof(m_ConstantForceData));
  2569. // Validation Check
  2570. if (diEffect.lpvTypeSpecificParams == NULL) {
  2571. ASSUME_NOT_REACHED();
  2572. return SFERR_INVALID_PARAM;
  2573. }
  2574. if (diEffect.cbTypeSpecificParams != sizeof(m_ConstantForceData)) {
  2575. ASSUME_NOT_REACHED();
  2576. return SFERR_INVALID_PARAM;
  2577. }
  2578. // Let the base class do its magic
  2579. HRESULT hr = InternalEffect::Create(diEffect);
  2580. if (FAILED(hr)) {
  2581. return hr;
  2582. }
  2583. // Copy data to local store
  2584. ::memcpy(&m_ConstantForceData, diEffect.lpvTypeSpecificParams, sizeof(m_ConstantForceData));
  2585. // Check the data for truncation
  2586. if (m_ConstantForceData.lMagnitude > 10000) {
  2587. m_ConstantForceData.lMagnitude = 10000;
  2588. hr = DI_TRUNCATED;
  2589. } else if (m_ConstantForceData.lMagnitude < -10000) {
  2590. m_ConstantForceData.lMagnitude = -10000;
  2591. hr = DI_TRUNCATED;
  2592. }
  2593. return hr;
  2594. }
  2595. /******************* ConstantForceEffect200 class ******************/
  2596. BYTE ConstantForceEffect200::GetRepeatIndex() const
  2597. {
  2598. return INDEX_CE_REPEAT_200;
  2599. }
  2600. HRESULT ConstantForceEffect200::Create(const DIEFFECT& diEffect)
  2601. {
  2602. HRESULT hr = ConstantForceEffect::Create(diEffect);
  2603. // How did creation go?
  2604. if (FAILED(hr)) {
  2605. return hr; // Not so good
  2606. }
  2607. ASSUME(m_pEnvelope == NULL);
  2608. m_PercentAdjustment = m_PercentX + (m_PercentY * g_ForceFeedbackDevice.GetYMappingPercent(ET_CONSTANTFORCE_200))/100;
  2609. m_Gain = m_Gain/100 * m_PercentAdjustment;
  2610. if (m_ConstantForceData.lMagnitude < 0) {
  2611. m_pEnvelope = new Envelope200(diEffect.lpEnvelope, -Magnitude(), m_Duration, hr);
  2612. m_ConstantForceData.lMagnitude = -10000;
  2613. } else {
  2614. m_pEnvelope = new Envelope200(diEffect.lpEnvelope, Magnitude(), m_Duration, hr);
  2615. m_ConstantForceData.lMagnitude = 10000;
  2616. }
  2617. if (m_EffectAngle <= 18000) {
  2618. m_ConstantForceData.lMagnitude *= -1;
  2619. }
  2620. return hr;
  2621. }
  2622. UINT ConstantForceEffect200::GetModifyOnlyNeeded() const
  2623. {
  2624. UINT retCount = 0;
  2625. if (m_TriggerPlayButton != 0) { // Trigger Button
  2626. retCount++;
  2627. }
  2628. if (m_TriggerRepeat != 0) { // Trigger repeat
  2629. retCount++;
  2630. }
  2631. return retCount;
  2632. }
  2633. HRESULT ConstantForceEffect200::FillModifyOnlyParms() const
  2634. {
  2635. if (g_pDataPackager == NULL) {
  2636. ASSUME_NOT_REACHED(); // This is only called from DataPackager::Create()
  2637. return SFERR_DRIVER_ERROR;
  2638. }
  2639. HRESULT hr = SUCCESS;
  2640. BYTE nextPacket = 1;
  2641. if (m_TriggerPlayButton != 0) { // Trigger Button
  2642. hr = FillModifyPacket200(nextPacket, INDEX_CE_BUTTONMAP_200, g_TriggerMap200[m_TriggerPlayButton]);
  2643. nextPacket++;
  2644. }
  2645. if (m_TriggerRepeat != 0) { // Trigger repeat
  2646. hr = FillModifyPacket200(nextPacket, INDEX_CE_BUTTONREPEAT_200, m_TriggerRepeat/DURATION_SCALE_200);
  2647. nextPacket++;
  2648. }
  2649. return hr;
  2650. }
  2651. HRESULT ConstantForceEffect200::FillCreatePacket(DataPacket& packet) const
  2652. {
  2653. // Sanity check
  2654. if (m_pEnvelope == NULL) {
  2655. ASSUME_NOT_REACHED(); // Should never happen
  2656. return SFERR_DRIVER_ERROR;
  2657. }
  2658. // Packet to set modify data[index] of current effect
  2659. if (!packet.AllocateBytes(22)) {
  2660. return SFERR_DRIVER_ERROR;
  2661. }
  2662. // Fill in the Generic Effect Information
  2663. FillHeader200(packet, ET_CONSTANTFORCE_200, NEW_EFFECT_ID);
  2664. unsigned short calc_byte = unsigned short(float(m_EffectAngle)/ANGLE_SCALE_200);
  2665. packet.m_pData[10]= BYTE(calc_byte & 0x7F); // Effect Angle
  2666. calc_byte = unsigned short(float(m_Gain)/GAIN_SCALE_200);
  2667. packet.m_pData[11]= BYTE(calc_byte & 0x7F); // Gain
  2668. // Envelope
  2669. Envelope200* pEnvelope = (Envelope200*)(m_pEnvelope);
  2670. packet.m_pData[12] = BYTE(pEnvelope->m_StartPercent & 0x7F); // Initial attack level
  2671. packet.m_pData[13] = BYTE(pEnvelope->m_AttackTime& 0x7F); // AttackTime Low
  2672. packet.m_pData[14] = BYTE(pEnvelope->m_AttackTime>> 7) & 0x7F; // AttackTime High
  2673. packet.m_pData[15] = BYTE(pEnvelope->m_SustainPercent & 0x7F); // Sustain level
  2674. packet.m_pData[16] = BYTE(pEnvelope->m_FadeStart & 0x7F); // SustainTime Low
  2675. packet.m_pData[17] = BYTE(pEnvelope->m_FadeStart >> 7) & 0x7F; // SustainTime High
  2676. packet.m_pData[18] = BYTE(pEnvelope->m_EndPercent & 0x7F); // What to decay to
  2677. // -- Duration of decay is figured by the firmware from total duration
  2678. /* short directionHack = 1;
  2679. if (m_EffectAngle <= 18000) {
  2680. directionHack = -1;
  2681. }
  2682. */
  2683. // Convert magnitude to device percentage (0 to +126 --- +63 = 0 percent)
  2684. // calc_byte = unsigned short(float(directionHack * Magnitude()/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE);
  2685. calc_byte = unsigned short(float(Magnitude()/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE);
  2686. packet.m_pData[19] = BYTE(calc_byte & 0x7F); // Offset
  2687. packet.m_pData[20]= ComputeChecksum(packet, 20); // Checksum
  2688. // End of packet
  2689. packet.m_pData[21]= MIDI_EOX; // End of SysEX packet
  2690. return SUCCESS;
  2691. }
  2692. HRESULT ConstantForceEffect200::Modify(InternalEffect& newEffect, DWORD modFlags)
  2693. {
  2694. g_pDataPackager->ClearPackets();
  2695. HRESULT adjustResult = AdjustModifyParams(newEffect, modFlags);
  2696. if (FAILED(adjustResult)) {
  2697. return adjustResult;
  2698. }
  2699. HRESULT hr = SUCCESS;
  2700. ConstantForceEffect200* pEffect = (ConstantForceEffect200*)(&newEffect);
  2701. BYTE nextPacket = 0;
  2702. if (modFlags & DIEP_DURATION) {
  2703. hr = FillModifyPacket200(nextPacket, INDEX_CE_DURATION_200, pEffect->m_Duration/DURATION_SCALE_200);
  2704. nextPacket++;
  2705. }
  2706. if (modFlags & DIEP_ENVELOPE) {
  2707. Envelope200* pOldEnvelope = (Envelope200*)(m_pEnvelope);
  2708. Envelope200* pNewEnvelope = (Envelope200*)(pEffect->m_pEnvelope);
  2709. if (pOldEnvelope->m_StartPercent != pNewEnvelope->m_StartPercent) {
  2710. hr = FillModifyPacket200(nextPacket, INDEX_CE_STARTPERCENT_200, pNewEnvelope->m_StartPercent);
  2711. nextPacket++;
  2712. }
  2713. if (pOldEnvelope->m_AttackTime != pNewEnvelope->m_AttackTime) {
  2714. hr = FillModifyPacket200(nextPacket, INDEX_CE_ATTTACK_TIME_200, pNewEnvelope->m_AttackTime);
  2715. nextPacket++;
  2716. }
  2717. if (pOldEnvelope->m_SustainPercent != pNewEnvelope->m_SustainPercent) {
  2718. hr = FillModifyPacket200(nextPacket, INDEX_CE_SUSTAINPERCENT_200, pNewEnvelope->m_SustainPercent);
  2719. nextPacket++;
  2720. }
  2721. if (pOldEnvelope->m_FadeStart != pNewEnvelope->m_FadeStart) {
  2722. hr = FillModifyPacket200(nextPacket, INDEX_CE_FADESTART_200, pNewEnvelope->m_FadeStart);
  2723. nextPacket++;
  2724. }
  2725. if (pOldEnvelope->m_EndPercent != pNewEnvelope->m_EndPercent) {
  2726. hr = FillModifyPacket200(nextPacket, INDEX_CE_ENDPERCENT_200, pNewEnvelope->m_EndPercent);
  2727. nextPacket++;
  2728. }
  2729. }
  2730. if (modFlags & DIEP_TRIGGERBUTTON) {
  2731. hr = FillModifyPacket200(nextPacket, INDEX_CE_BUTTONMAP_200, g_TriggerMap200[pEffect->m_TriggerPlayButton]);
  2732. nextPacket++;
  2733. }
  2734. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  2735. hr = FillModifyPacket200(nextPacket, INDEX_CE_BUTTONREPEAT_200, pEffect->m_TriggerRepeat/DURATION_SCALE_200);
  2736. nextPacket++;
  2737. }
  2738. if (modFlags & DIEP_GAIN) {
  2739. DWORD calc = DWORD(float(pEffect->m_Gain)/GAIN_SCALE_200);
  2740. hr = FillModifyPacket200(nextPacket, INDEX_CE_GAIN_200, calc);
  2741. nextPacket++;
  2742. }
  2743. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Send changed items
  2744. if (Magnitude() != pEffect->Magnitude()) {
  2745. /* short directionHack = 1;
  2746. if (pEffect->m_EffectAngle <= 18000) {
  2747. directionHack = -1;
  2748. }
  2749. DWORD calc = DWORD(float(directionHack * pEffect->Magnitude()/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE);
  2750. */ DWORD calc = DWORD(float(pEffect->Magnitude()/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE);
  2751. hr = FillModifyPacket200(nextPacket, INDEX_CE_MAGNITUDE_200, calc);
  2752. nextPacket++;
  2753. }
  2754. }
  2755. // Did adjust have anything bad to say?
  2756. if (hr == SUCCESS) {
  2757. return adjustResult;
  2758. }
  2759. return hr;
  2760. }
  2761. HRESULT ConstantForceEffect200::AdjustModifyParams(InternalEffect& newEffect, DWORD& modFlags)
  2762. {
  2763. // Check to see if values being modified are acceptable
  2764. DWORD possMod = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_ENVELOPE | DIEP_DIRECTION;
  2765. if ((g_TotalModifiable & modFlags & possMod) == 0) { // Nothing to modify?
  2766. modFlags = 0;
  2767. return S_FALSE;
  2768. }
  2769. BOOL playingChecked = FALSE;
  2770. HRESULT hr = SUCCESS;
  2771. if ((modFlags & (DIEP_SAMPLEPERIOD | DIEP_AXES)) != 0) {
  2772. hr = S_FALSE; // Cannot modify all they asked for
  2773. }
  2774. ConstantForceEffect200* pEffect = (ConstantForceEffect200*)(&newEffect);
  2775. unsigned short numPackets = 0;
  2776. if (modFlags & DIEP_DURATION) {
  2777. if (m_Duration == pEffect->m_Duration) {
  2778. modFlags &= ~DIEP_DURATION; // Remove duration flag, unchanged
  2779. } else {
  2780. if (IsReallyPlaying(playingChecked) == TRUE) {
  2781. return DIERR_EFFECTPLAYING;
  2782. } else {
  2783. modFlags |= DIEP_ENVELOPE; // Duration change forces envelope change
  2784. numPackets++;
  2785. }
  2786. }
  2787. }
  2788. if (modFlags & DIEP_DIRECTION) {
  2789. modFlags |= (DIEP_GAIN | DIEP_TYPESPECIFICPARAMS); // If angle is greater than 180 magnitude is inverted
  2790. }
  2791. if (modFlags & DIEP_GAIN) {
  2792. if (m_Gain == pEffect->m_Gain) {
  2793. modFlags &= ~DIEP_GAIN; // Remove gain flag, unchanged
  2794. } else {
  2795. numPackets++;
  2796. }
  2797. }
  2798. if (modFlags & DIEP_TYPESPECIFICPARAMS) {
  2799. if (Magnitude() == pEffect->Magnitude()) {
  2800. modFlags &= ~DIEP_TYPESPECIFICPARAMS; // Nothing typespecific really changed
  2801. } else {
  2802. numPackets++;
  2803. }
  2804. modFlags |= DIEP_ENVELOPE;
  2805. }
  2806. if (modFlags & DIEP_ENVELOPE) {
  2807. int numEnvelopeChanged = 0;
  2808. if (m_pEnvelope == NULL || pEffect->m_pEnvelope == NULL) {
  2809. ASSUME_NOT_REACHED(); // Envelope should always be created!
  2810. } else {
  2811. Envelope200* pOldEnvelope = (Envelope200*)(m_pEnvelope);
  2812. Envelope200* pNewEnvelope = (Envelope200*)(pEffect->m_pEnvelope);
  2813. if (pOldEnvelope->m_AttackTime != pNewEnvelope->m_AttackTime) {
  2814. numEnvelopeChanged++;
  2815. }
  2816. if (pOldEnvelope->m_FadeStart != pNewEnvelope->m_FadeStart) {
  2817. numEnvelopeChanged++;
  2818. }
  2819. if (pOldEnvelope->m_StartPercent != pNewEnvelope->m_StartPercent) {
  2820. numEnvelopeChanged++;
  2821. }
  2822. if (pOldEnvelope->m_SustainPercent != pNewEnvelope->m_SustainPercent) {
  2823. numEnvelopeChanged++;
  2824. }
  2825. if (pOldEnvelope->m_EndPercent != pNewEnvelope->m_EndPercent) {
  2826. numEnvelopeChanged++;
  2827. }
  2828. }
  2829. if (numEnvelopeChanged == 0) {
  2830. modFlags &= ~DIEP_ENVELOPE; // Remove envelope flag, unchanged
  2831. } else {
  2832. numPackets += (USHORT)numEnvelopeChanged;
  2833. }
  2834. }
  2835. if (modFlags & DIEP_TRIGGERBUTTON) {
  2836. if (m_TriggerPlayButton == pEffect->m_TriggerPlayButton) {
  2837. modFlags &= ~DIEP_TRIGGERBUTTON; // Remove trigger flag, unchanged
  2838. } else {
  2839. numPackets++;
  2840. }
  2841. }
  2842. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  2843. if (m_TriggerRepeat == pEffect->m_TriggerRepeat) {
  2844. modFlags &= ~DIEP_TRIGGERREPEATINTERVAL; // Remove trigger repeat flag, unchanged
  2845. } else {
  2846. numPackets++;
  2847. }
  2848. }
  2849. if (numPackets != 0) {
  2850. g_pDataPackager->AllocateDataPackets(numPackets);
  2851. }
  2852. return hr;
  2853. }
  2854. /******************* class CustomForceEffect ***********************/
  2855. CustomForceEffect::CustomForceEffect() : InternalEffect()
  2856. {
  2857. m_CustomForceData.rglForceData = NULL;
  2858. }
  2859. CustomForceEffect::~CustomForceEffect()
  2860. {
  2861. if (m_CustomForceData.rglForceData != NULL) {
  2862. delete[] (m_CustomForceData.rglForceData);
  2863. m_CustomForceData.rglForceData = NULL;
  2864. }
  2865. }
  2866. HRESULT CustomForceEffect::Create(const DIEFFECT& diEffect)
  2867. {
  2868. // Zero out old struct
  2869. ::memset(&m_CustomForceData, 0, sizeof(m_CustomForceData));
  2870. // Validation Check
  2871. if (diEffect.lpvTypeSpecificParams == NULL) {
  2872. ASSUME_NOT_REACHED();
  2873. return SFERR_INVALID_PARAM;
  2874. }
  2875. if (diEffect.cbTypeSpecificParams != sizeof(m_CustomForceData)) {
  2876. ASSUME_NOT_REACHED();
  2877. return SFERR_INVALID_PARAM;
  2878. }
  2879. DICUSTOMFORCE* pDICustom = (DICUSTOMFORCE*)(diEffect.lpvTypeSpecificParams);
  2880. if (pDICustom->cChannels == 0) {
  2881. ASSUME_NOT_REACHED();
  2882. return SFERR_INVALID_PARAM;
  2883. }
  2884. // We are a little different from every one else (instead of 0 beiing devcie default, it is custom sample period)
  2885. BOOL useCustomForceSamplePeriod = (diEffect.dwSamplePeriod == 0);
  2886. // Let the base class do its magic
  2887. HRESULT hr = InternalEffect::Create(diEffect);
  2888. if (FAILED(hr)) {
  2889. return hr;
  2890. }
  2891. // Copy data to local store
  2892. m_CustomForceData.cChannels = pDICustom->cChannels;
  2893. m_CustomForceData.dwSamplePeriod = pDICustom->dwSamplePeriod;
  2894. if (m_CustomForceData.dwSamplePeriod > MAX_TIME_200) {
  2895. m_CustomForceData.dwSamplePeriod = MAX_TIME_200;
  2896. hr = DI_TRUNCATED;
  2897. }
  2898. if (useCustomForceSamplePeriod) {
  2899. if (m_CustomForceData.dwSamplePeriod == 0) { // These both can't be zero
  2900. return SFERR_NO_SUPPORT;
  2901. }
  2902. m_SamplePeriod = m_CustomForceData.dwSamplePeriod;
  2903. }
  2904. m_CustomForceData.cSamples = pDICustom->cSamples;
  2905. long int* pForceData = NULL;
  2906. try { // They could probably ask for anything
  2907. pForceData = new long int[m_CustomForceData.cSamples];
  2908. } catch (...) {
  2909. return SFERR_DRIVER_ERROR;
  2910. }
  2911. if (pForceData == NULL)
  2912. {
  2913. return SFERR_DRIVER_ERROR;
  2914. }
  2915. ::memcpy(pForceData, pDICustom->rglForceData, sizeof(long int) * m_CustomForceData.cSamples);
  2916. m_CustomForceData.rglForceData = pForceData;
  2917. pForceData = NULL;
  2918. return hr;
  2919. }
  2920. /******************* class CustomForceEffect200 ***********************/
  2921. CustomForceEffect200::CustomForceEffect200() : CustomForceEffect(),
  2922. m_pEnvelope(NULL)
  2923. {
  2924. }
  2925. CustomForceEffect200::~CustomForceEffect200()
  2926. {
  2927. if (m_pEnvelope != NULL) {
  2928. delete m_pEnvelope;
  2929. m_pEnvelope = NULL;
  2930. }
  2931. }
  2932. BYTE CustomForceEffect200::GetRepeatIndex() const
  2933. {
  2934. return INDEX_CF_REPEAT_200;
  2935. }
  2936. HRESULT CustomForceEffect200::Create(const DIEFFECT& diEffect)
  2937. {
  2938. HRESULT hr = CustomForceEffect::Create(diEffect);
  2939. // How did creation go?
  2940. if (FAILED(hr)) {
  2941. return hr; // Not so good
  2942. }
  2943. ASSUME(m_pEnvelope == NULL);
  2944. m_PercentAdjustment = m_PercentX + (m_PercentY * g_ForceFeedbackDevice.GetYMappingPercent(ET_CUSTOMFORCE_200))/100;
  2945. m_Gain = m_Gain/100 * m_PercentAdjustment;
  2946. m_pEnvelope = new Envelope200(diEffect.lpEnvelope, 10000, m_Duration, hr); // Sustain Mag is 100 percent
  2947. return hr;
  2948. }
  2949. UINT CustomForceEffect200::GetModifyOnlyNeeded() const
  2950. {
  2951. UINT retCount = 0;
  2952. if (m_TriggerPlayButton != 0) { // Trigger Button
  2953. retCount++;
  2954. }
  2955. if (m_TriggerRepeat != 0) { // Trigger repeat
  2956. retCount++;
  2957. }
  2958. // Envelope parms
  2959. ASSUME_NOT_NULL(m_pEnvelope);
  2960. if (m_pEnvelope != NULL) { // Already converted to device units
  2961. if (m_pEnvelope->m_StartPercent != 127) {
  2962. retCount++;
  2963. }
  2964. if (m_pEnvelope->m_AttackTime != 0) {
  2965. retCount++;
  2966. }
  2967. if (m_pEnvelope->m_SustainPercent != 127) {
  2968. retCount++;
  2969. }
  2970. if (m_pEnvelope->m_FadeStart != 0) {
  2971. retCount++;
  2972. }
  2973. if (m_pEnvelope->m_EndPercent != 127) {
  2974. retCount++;
  2975. }
  2976. }
  2977. return retCount;
  2978. }
  2979. HRESULT CustomForceEffect200::FillModifyOnlyParms() const
  2980. {
  2981. if (g_pDataPackager == NULL) {
  2982. ASSUME_NOT_REACHED(); // This is only called from DataPackager::Create()
  2983. return SFERR_DRIVER_ERROR;
  2984. }
  2985. HRESULT hr = SUCCESS;
  2986. BYTE nextPacket = 1;
  2987. if (m_TriggerPlayButton != 0) { // Trigger Button
  2988. hr = FillModifyPacket200(nextPacket, INDEX_CF_BUTTONMAP_200, g_TriggerMap200[m_TriggerPlayButton]);
  2989. nextPacket++;
  2990. }
  2991. if (m_TriggerRepeat != 0) { // Trigger repeat
  2992. hr = FillModifyPacket200(nextPacket, INDEX_CF_BUTTONREPEAT_200, m_TriggerRepeat/DURATION_SCALE_200);
  2993. nextPacket++;
  2994. }
  2995. // Envelope parms
  2996. ASSUME_NOT_NULL(m_pEnvelope);
  2997. if (m_pEnvelope != NULL) { // Already converted to device units
  2998. if (m_pEnvelope->m_StartPercent != 127) {
  2999. hr = FillModifyPacket200(nextPacket, INDEX_CF_STARTPERCENT_200, m_pEnvelope->m_StartPercent);
  3000. nextPacket++;
  3001. }
  3002. if (m_pEnvelope->m_AttackTime != 0) {
  3003. hr = FillModifyPacket200(nextPacket, INDEX_CF_ATTTACK_TIME_200, m_pEnvelope->m_AttackTime);
  3004. nextPacket++;
  3005. }
  3006. if (m_pEnvelope->m_SustainPercent != 127) {
  3007. hr = FillModifyPacket200(nextPacket, INDEX_CF_SUSTAINPERCENT_200, m_pEnvelope->m_SustainPercent);
  3008. nextPacket++;
  3009. }
  3010. if (m_pEnvelope->m_FadeStart != 0) {
  3011. hr = FillModifyPacket200(nextPacket, INDEX_CF_FADESTART_200, m_pEnvelope->m_FadeStart);
  3012. nextPacket++;
  3013. }
  3014. if (m_pEnvelope->m_EndPercent != 127) {
  3015. hr = FillModifyPacket200(nextPacket, INDEX_CF_ENDPERCENT_200, m_pEnvelope->m_EndPercent);
  3016. nextPacket++;
  3017. }
  3018. }
  3019. return hr;
  3020. }
  3021. HRESULT CustomForceEffect200::FillCreatePacket(DataPacket& packet) const
  3022. {
  3023. if (m_CustomForceData.cChannels == 0) {
  3024. ASSUME_NOT_REACHED(); // Already checked this
  3025. return SFERR_INVALID_PARAM;
  3026. }
  3027. // Create waveform packet
  3028. BYTE* pWaveForm = NULL;
  3029. try { // Who knows how much we are being asked to allocate
  3030. pWaveForm = new BYTE[m_CustomForceData.cSamples / m_CustomForceData.cChannels * 2]; // This is the max possible
  3031. } catch(...) {
  3032. return SFERR_DRIVER_ERROR;
  3033. }
  3034. if (pWaveForm == NULL)
  3035. {
  3036. return SFERR_DRIVER_ERROR;
  3037. }
  3038. HRESULT hr = SUCCESS;
  3039. // Fill wavelet packet
  3040. if (m_CustomForceData.rglForceData[0] > 10000) {
  3041. m_CustomForceData.rglForceData[0] = 10000;
  3042. hr = DI_TRUNCATED;
  3043. } else if (m_CustomForceData.rglForceData[0] < -10000) {
  3044. m_CustomForceData.rglForceData[0] = -10000;
  3045. hr = DI_TRUNCATED;
  3046. }
  3047. unsigned short wave_byte = unsigned short(float(m_CustomForceData.rglForceData[0] + 10000)/WAVELET_SCALE_200);
  3048. pWaveForm[0] = BYTE(wave_byte & 0x3F);
  3049. pWaveForm[1] = BYTE(wave_byte >> 6) & 0x07;
  3050. UINT waveletCount = 2;
  3051. UINT iPrev = 0;
  3052. for (UINT i = (0 + m_CustomForceData.cChannels); i < m_CustomForceData.cSamples; i += m_CustomForceData.cChannels) {
  3053. if (m_CustomForceData.rglForceData[i] > 10000) {
  3054. m_CustomForceData.rglForceData[i] = 10000;
  3055. hr = DI_TRUNCATED;
  3056. } else if (m_CustomForceData.rglForceData[i] < -10000) {
  3057. m_CustomForceData.rglForceData[i] = -10000;
  3058. hr = DI_TRUNCATED;
  3059. }
  3060. LONG distance = m_CustomForceData.rglForceData[i] - m_CustomForceData.rglForceData[iPrev];
  3061. if ((distance >= 0) && (distance <= WAVELET_DISTANCE_200) ||
  3062. (distance < 0) && (-distance <= WAVELET_DISTANCE_200)) { // Relative (single byte)
  3063. wave_byte = unsigned short((float(distance + WAVELET_DISTANCE_200)/WAVELET_DISTANCE_SCALE_200) + 0.5f);
  3064. ASSUME(wave_byte <= 62);
  3065. pWaveForm[waveletCount++] = (BYTE(wave_byte) & 0x3F) | 0x40;
  3066. } else { // Non relative (double byte)
  3067. wave_byte = unsigned short(float(m_CustomForceData.rglForceData[i] + 10000)/WAVELET_SCALE_200);
  3068. pWaveForm[waveletCount++] = BYTE(wave_byte & 0x3F);
  3069. pWaveForm[waveletCount++] = BYTE(wave_byte >> 6) & 0x07;
  3070. }
  3071. iPrev = i;
  3072. }
  3073. // Packet to set modify data[index] of current effect
  3074. UINT totalBytes = 19 + waveletCount; // Header (10) + Fixed (7) + Footer(2) + waveBytes
  3075. if (!packet.AllocateBytes(totalBytes)) {
  3076. return SFERR_DRIVER_ERROR;
  3077. }
  3078. // Fill in the Generic Effect Information
  3079. FillHeader200(packet, ET_CUSTOMFORCE_200, NEW_EFFECT_ID);
  3080. // unsigned short calc_byte = unsigned short(float(m_EffectAngle)/ANGLE_SCALE_200);
  3081. // packet.m_pData[10]= BYTE(calc_byte & 0x7F); // Effect Angle
  3082. if (m_EffectAngle <= 18000) { // Custom for device units
  3083. packet.m_pData[10]= BYTE(64);
  3084. } else {
  3085. packet.m_pData[10]= BYTE(0);
  3086. }
  3087. unsigned short calc_byte = unsigned short(float(m_Gain)/GAIN_SCALE_200);
  3088. packet.m_pData[11]= BYTE(calc_byte & 0x7F); // Gain
  3089. calc_byte = unsigned short(m_CustomForceData.dwSamplePeriod/DURATION_SCALE_200);
  3090. packet.m_pData[12] = BYTE(calc_byte & 0x7F); // Force Sample Interval Low
  3091. packet.m_pData[13] = BYTE(calc_byte >> 7) & 0x7F; // Force Sample Interval High
  3092. calc_byte = unsigned short(m_SamplePeriod/DURATION_SCALE_200);
  3093. packet.m_pData[14] = BYTE(calc_byte & 0x7F); // Force Output Interval Low
  3094. packet.m_pData[15] = BYTE(calc_byte >> 7) & 0x7F; // Force Output Interval High
  3095. packet.m_pData[16] = 63; // Constant force offset (0 - DI Doesn't support)
  3096. // Fill in the wavelet info (already converted to device units
  3097. for (UINT nextWaveIndex = 0; nextWaveIndex < waveletCount; nextWaveIndex++) {
  3098. packet.m_pData[17 + nextWaveIndex] = pWaveForm[nextWaveIndex];
  3099. }
  3100. packet.m_pData[totalBytes-2]= ComputeChecksum(packet, totalBytes-2); // Checksum
  3101. // End of packet
  3102. packet.m_pData[totalBytes-1]= MIDI_EOX; // End of SysEX packet
  3103. // Clean up
  3104. delete[] pWaveForm; // can't modify it, no need to save it
  3105. pWaveForm = NULL;
  3106. return hr;
  3107. }
  3108. HRESULT CustomForceEffect200::Modify(InternalEffect& newEffect, DWORD modFlags)
  3109. {
  3110. g_pDataPackager->ClearPackets();
  3111. HRESULT adjustResult = AdjustModifyParams(newEffect, modFlags);
  3112. if (FAILED(adjustResult)) {
  3113. return adjustResult;
  3114. }
  3115. HRESULT hr = SUCCESS;
  3116. CustomForceEffect200* pEffect = (CustomForceEffect200*)(&newEffect);
  3117. BYTE nextPacket = 0;
  3118. if (modFlags & DIEP_DURATION) {
  3119. hr = FillModifyPacket200(nextPacket, INDEX_CF_DURATION_200, pEffect->m_Duration/DURATION_SCALE_200);
  3120. nextPacket++;
  3121. }
  3122. if (modFlags & DIEP_ENVELOPE) {
  3123. Envelope200* pOldEnvelope = (Envelope200*)(m_pEnvelope);
  3124. Envelope200* pNewEnvelope = (Envelope200*)(pEffect->m_pEnvelope);
  3125. if (pOldEnvelope->m_StartPercent != pNewEnvelope->m_StartPercent) {
  3126. hr = FillModifyPacket200(nextPacket, INDEX_CF_STARTPERCENT_200, pNewEnvelope->m_StartPercent);
  3127. nextPacket++;
  3128. }
  3129. if (pOldEnvelope->m_AttackTime != pNewEnvelope->m_AttackTime) {
  3130. hr = FillModifyPacket200(nextPacket, INDEX_CF_ATTTACK_TIME_200, pNewEnvelope->m_AttackTime);
  3131. nextPacket++;
  3132. }
  3133. if (pOldEnvelope->m_SustainPercent != pNewEnvelope->m_SustainPercent) {
  3134. hr = FillModifyPacket200(nextPacket, INDEX_CF_SUSTAINPERCENT_200, pNewEnvelope->m_SustainPercent);
  3135. nextPacket++;
  3136. }
  3137. if (pOldEnvelope->m_FadeStart != pNewEnvelope->m_FadeStart) {
  3138. hr = FillModifyPacket200(nextPacket, INDEX_CF_FADESTART_200, pNewEnvelope->m_FadeStart);
  3139. nextPacket++;
  3140. }
  3141. if (pOldEnvelope->m_EndPercent != pNewEnvelope->m_EndPercent) {
  3142. hr = FillModifyPacket200(nextPacket, INDEX_CF_ENDPERCENT_200, pNewEnvelope->m_EndPercent);
  3143. nextPacket++;
  3144. }
  3145. }
  3146. if (modFlags & DIEP_DIRECTION) {
  3147. if (pEffect->m_EffectAngle > 18000) {
  3148. hr = FillModifyPacket200(nextPacket, INDEX_CF_DIRECTIONANGLE_200, 0, 0);
  3149. } else {
  3150. hr = FillModifyPacket200(nextPacket, INDEX_CF_DIRECTIONANGLE_200, BYTE(64), 0);
  3151. }
  3152. nextPacket++;
  3153. }
  3154. if (modFlags & DIEP_TRIGGERBUTTON) {
  3155. hr = FillModifyPacket200(nextPacket, INDEX_CF_BUTTONMAP_200, g_TriggerMap200[pEffect->m_TriggerPlayButton]);
  3156. nextPacket++;
  3157. }
  3158. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  3159. hr = FillModifyPacket200(nextPacket, INDEX_CF_BUTTONREPEAT_200, pEffect->m_TriggerRepeat/DURATION_SCALE_200);
  3160. nextPacket++;
  3161. }
  3162. if (modFlags & DIEP_GAIN) {
  3163. DWORD calc = DWORD(float(pEffect->m_Gain)/GAIN_SCALE_200);
  3164. hr = FillModifyPacket200(nextPacket, INDEX_CF_GAIN_200, calc);
  3165. nextPacket++;
  3166. }
  3167. if (modFlags & DIEP_SAMPLEPERIOD) {
  3168. hr = FillModifyPacket200(nextPacket, INDEX_CF_SAMPLE_PERIOD_200, DWORD(pEffect->m_SamplePeriod/DURATION_SCALE_200));
  3169. nextPacket++;
  3170. }
  3171. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Send changed items
  3172. hr = FillModifyPacket200(nextPacket, INDEX_CF_FORCESAMPLE_200, DWORD(pEffect->m_CustomForceData.dwSamplePeriod)/DURATION_SCALE_200);
  3173. nextPacket++;
  3174. }
  3175. if (hr == SUCCESS) {
  3176. return adjustResult;
  3177. }
  3178. return hr;
  3179. }
  3180. HRESULT CustomForceEffect200::AdjustModifyParams(InternalEffect& newEffect, DWORD& modFlags)
  3181. {
  3182. // Check to see if values being modified are acceptable
  3183. DWORD possMod = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_ENVELOPE | DIEP_SAMPLEPERIOD | DIEP_DIRECTION;
  3184. if ((g_TotalModifiable & modFlags & possMod) == 0) { // Nothing to modify?
  3185. modFlags = 0;
  3186. return SFERR_NO_SUPPORT;
  3187. }
  3188. CustomForceEffect200* pEffect = (CustomForceEffect200*)(&newEffect);
  3189. unsigned short numPackets = 0;
  3190. HRESULT hr = SUCCESS;
  3191. if ((modFlags & (DIEP_AXES)) != 0) {
  3192. hr = S_FALSE; // Cannot modify all they asked for
  3193. }
  3194. BOOL playingChecked = FALSE;
  3195. if (modFlags & DIEP_DURATION) {
  3196. if (m_Duration == pEffect->m_Duration) {
  3197. modFlags &= ~DIEP_DURATION; // Remove duration flag, unchanged
  3198. } else {
  3199. if (IsReallyPlaying(playingChecked) == FALSE) {
  3200. modFlags |= DIEP_ENVELOPE; // Duration change forces envelope change
  3201. numPackets++;
  3202. } else {
  3203. return DIERR_EFFECTPLAYING;
  3204. }
  3205. }
  3206. }
  3207. if (modFlags & DIEP_DIRECTION) {
  3208. modFlags &= ~DIEP_DIRECTION;
  3209. if (m_EffectAngle != pEffect->m_EffectAngle) {
  3210. modFlags |= DIEP_GAIN;
  3211. if (int(m_EffectAngle / 18000) != int(pEffect->m_EffectAngle / 18000)) {
  3212. modFlags |= DIEP_DIRECTION;
  3213. numPackets++;
  3214. }
  3215. }
  3216. }
  3217. if (modFlags & DIEP_ENVELOPE) {
  3218. int numEnvelopeChanged = 0;
  3219. if (m_pEnvelope == NULL || pEffect->m_pEnvelope == NULL) {
  3220. ASSUME_NOT_REACHED(); // Envelope should always be created!
  3221. } else {
  3222. Envelope200* pOldEnvelope = (Envelope200*)(m_pEnvelope);
  3223. Envelope200* pNewEnvelope = (Envelope200*)(pEffect->m_pEnvelope);
  3224. if (pOldEnvelope->m_AttackTime != pNewEnvelope->m_AttackTime) {
  3225. numEnvelopeChanged++;
  3226. }
  3227. if (pOldEnvelope->m_FadeStart != pNewEnvelope->m_FadeStart) {
  3228. numEnvelopeChanged++;
  3229. }
  3230. if (pOldEnvelope->m_StartPercent != pNewEnvelope->m_StartPercent) {
  3231. numEnvelopeChanged++;
  3232. }
  3233. if (pOldEnvelope->m_SustainPercent != pNewEnvelope->m_SustainPercent) {
  3234. numEnvelopeChanged++;
  3235. }
  3236. if (pOldEnvelope->m_EndPercent != pNewEnvelope->m_EndPercent) {
  3237. numEnvelopeChanged++;
  3238. }
  3239. }
  3240. if (numEnvelopeChanged == 0) {
  3241. modFlags &= ~DIEP_ENVELOPE; // Remove envelope flag, unchanged
  3242. } else {
  3243. numPackets += (USHORT)numEnvelopeChanged;
  3244. }
  3245. }
  3246. if (modFlags & DIEP_TRIGGERBUTTON) {
  3247. if (m_TriggerPlayButton == pEffect->m_TriggerPlayButton) {
  3248. modFlags &= ~DIEP_TRIGGERBUTTON; // Remove trigger flag, unchanged
  3249. } else {
  3250. numPackets++;
  3251. }
  3252. }
  3253. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  3254. if (m_TriggerRepeat == pEffect->m_TriggerRepeat) {
  3255. modFlags &= ~DIEP_TRIGGERREPEATINTERVAL; // Remove trigger repeat flag, unchanged
  3256. } else {
  3257. numPackets++;
  3258. }
  3259. }
  3260. if (modFlags & DIEP_GAIN) {
  3261. if (m_Gain == pEffect->m_Gain) {
  3262. modFlags &= ~DIEP_GAIN; // Remove gain flag, unchanged
  3263. } else {
  3264. numPackets++;
  3265. }
  3266. }
  3267. if (modFlags & DIEP_SAMPLEPERIOD) {
  3268. if (m_SamplePeriod == pEffect->m_SamplePeriod) {
  3269. modFlags &= ~DIEP_SAMPLEPERIOD; // Remove sample period flag, unchanged
  3270. } else {
  3271. numPackets++;
  3272. }
  3273. }
  3274. if (modFlags & DIEP_TYPESPECIFICPARAMS) {
  3275. if (m_CustomForceData.dwSamplePeriod == pEffect->m_CustomForceData.dwSamplePeriod) {
  3276. modFlags &= ~DIEP_TYPESPECIFICPARAMS; // Nothing typespecific really changed
  3277. } else {
  3278. numPackets ++;
  3279. }
  3280. }
  3281. if (numPackets != 0) {
  3282. g_pDataPackager->AllocateDataPackets(numPackets);
  3283. }
  3284. return hr;
  3285. }
  3286. /******************* class WallEffect ***********************/
  3287. HRESULT WallEffect::Create(const DIEFFECT& diEffect)
  3288. {
  3289. // Zero out old struct
  3290. ::memset(&m_WallData, 0, sizeof(BE_WALL_PARAM));
  3291. // Validation Check
  3292. if (diEffect.lpvTypeSpecificParams == NULL) {
  3293. ASSUME_NOT_REACHED();
  3294. return SFERR_INVALID_PARAM;
  3295. }
  3296. if (diEffect.cbTypeSpecificParams != sizeof(BE_WALL_PARAM)) {
  3297. ASSUME_NOT_REACHED();
  3298. return SFERR_INVALID_PARAM;
  3299. }
  3300. // Let the base class do its magic
  3301. HRESULT hr = InternalEffect::Create(diEffect);
  3302. if (FAILED(hr)) {
  3303. return hr;
  3304. }
  3305. // Copy data to local store
  3306. ::memcpy(&m_WallData, diEffect.lpvTypeSpecificParams, sizeof(BE_WALL_PARAM));
  3307. m_WallData.m_WallAngle %= 36000; // No telling what we might have been sent
  3308. if (m_WallData.m_WallDistance > 10000) {
  3309. m_WallData.m_WallDistance = 10000;
  3310. hr = DI_TRUNCATED;
  3311. }
  3312. if (m_WallData.m_WallConstant > 10000) {
  3313. m_WallData.m_WallConstant = 10000;
  3314. hr = DI_TRUNCATED;
  3315. } else if (m_WallData.m_WallConstant < -10000) {
  3316. m_WallData.m_WallConstant = -10000;
  3317. hr = DI_TRUNCATED;
  3318. }
  3319. return hr;
  3320. }
  3321. /******************* class WallEffect200 ***********************/
  3322. BYTE WallEffect200::GetRepeatIndex() const
  3323. {
  3324. return INDEX_BE_REPEAT_200;
  3325. }
  3326. HRESULT WallEffect200::Create(const DIEFFECT& diEffect)
  3327. {
  3328. ::memset(m_Ds, 0, 4);
  3329. ::memset(m_Fs, 0, 4);
  3330. HRESULT hr = WallEffect::Create(diEffect);
  3331. if (FAILED(hr)) {
  3332. return hr;
  3333. }
  3334. ComputeDsAndFs();
  3335. return hr;
  3336. }
  3337. void WallEffect200::ComputeDsAndFs()
  3338. {
  3339. // Projection method - not so smart
  3340. double xProjection = m_WallData.m_WallDistance;
  3341. // With angles greater than 180 Wall flips across X axis
  3342. BOOL wallInner = (m_WallData.m_WallType == WALL_INNER);
  3343. if (m_WallData.m_WallAngle > 18000) {
  3344. xProjection = -xProjection;
  3345. } else if (xProjection == 0) {
  3346. wallInner = !wallInner;
  3347. }
  3348. BYTE xProjectionScaled = BYTE((xProjection/double(DIDISTANCE_TO_PERCENT) + 100.0)/POSITIVE_PERCENT_SCALE) & 0x7F;
  3349. if (((xProjection <= 0) && (wallInner)) || ((xProjection > 0) && (!wallInner))) {
  3350. m_Fs[0] = BYTE(float(-m_WallData.m_WallConstant/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  3351. m_Ds[0] = xProjectionScaled;
  3352. m_Ds[2] = 127; // Positive Max
  3353. } else {
  3354. m_Fs[0] = BYTE(float(m_WallData.m_WallConstant/DIDISTANCE_TO_PERCENT + 100)/POSITIVE_PERCENT_SCALE) & 0x7F;
  3355. m_Ds[0] = 0; // Negative Max
  3356. m_Ds[2] = xProjectionScaled;
  3357. }
  3358. // Simplistic mapping: if there is no mapping value is nothing for Y walls
  3359. if (g_ForceFeedbackDevice.GetYMappingPercent(ET_WALL_200) == 0) {
  3360. if (m_WallData.m_WallAngle == 0000 || m_WallData.m_WallAngle == 18000) { // Y axis walls
  3361. m_Fs[0] = 63; // 0
  3362. }
  3363. }
  3364. m_Ds[1] = m_Ds[0];
  3365. m_Ds[3] = m_Ds[2];
  3366. m_Fs[1] = m_Fs[0];
  3367. m_Fs[2] = m_Fs[0];
  3368. m_Fs[3] = m_Fs[0];
  3369. }
  3370. UINT WallEffect200::GetModifyOnlyNeeded() const
  3371. {
  3372. UINT retCount = 0;
  3373. if (m_TriggerPlayButton != 0) { // Trigger Button
  3374. retCount++;
  3375. }
  3376. if (m_TriggerRepeat != 0) { // Trigger repeat
  3377. retCount++;
  3378. }
  3379. if (m_Gain != 10000) { // Gain
  3380. retCount++;
  3381. }
  3382. return retCount;
  3383. }
  3384. HRESULT WallEffect200::FillModifyOnlyParms() const
  3385. {
  3386. if (g_pDataPackager == NULL) {
  3387. ASSUME_NOT_REACHED(); // This is only called from DataPackager::Create()
  3388. return SFERR_DRIVER_ERROR;
  3389. }
  3390. HRESULT hr = SUCCESS;
  3391. BYTE nextPacket = 1;
  3392. if (m_TriggerPlayButton != 0) { // Trigger Button
  3393. hr = FillModifyPacket200(nextPacket, INDEX_BE_BUTTONMAP_200, g_TriggerMap200[m_TriggerPlayButton]);
  3394. nextPacket++;
  3395. }
  3396. if (m_TriggerRepeat != 0) { // Trigger repeat
  3397. hr = FillModifyPacket200(nextPacket, INDEX_BE_BUTTONREPEAT_200, m_TriggerRepeat/DURATION_SCALE_200);
  3398. nextPacket++;
  3399. }
  3400. if (m_Gain != 10000) { // Gain
  3401. hr = FillModifyPacket200(nextPacket, INDEX_BE_GAIN_200, DWORD(float(m_Gain)/GAIN_SCALE_200));
  3402. nextPacket++;
  3403. }
  3404. return hr;
  3405. }
  3406. HRESULT WallEffect200::FillCreatePacket(DataPacket& packet) const
  3407. {
  3408. // Packet to set modify data[index] of current effect
  3409. if (!packet.AllocateBytes(21)) {
  3410. return SFERR_DRIVER_ERROR;
  3411. }
  3412. // Fill in the Generic Effect Information
  3413. FillHeader200(packet, ET_WALL_200, NEW_EFFECT_ID);
  3414. // All of the below items fit in one MidiByte (0..126/127) after conversion
  3415. packet.m_pData[10]= 0; // Effect Angle is along positive x.
  3416. // Computed in create
  3417. packet.m_pData[11]= m_Ds[0];
  3418. packet.m_pData[12]= m_Fs[0];
  3419. packet.m_pData[13]= m_Ds[1];
  3420. packet.m_pData[14]= m_Fs[1];
  3421. packet.m_pData[15]= m_Ds[2];
  3422. packet.m_pData[16]= m_Fs[2];
  3423. packet.m_pData[17]= m_Ds[3];
  3424. packet.m_pData[18]= m_Fs[3];
  3425. // End this puppy
  3426. packet.m_pData[19]= ComputeChecksum(packet, 19); // Checksum
  3427. packet.m_pData[20]= MIDI_EOX; // End of SysEX packet
  3428. return SUCCESS;
  3429. }
  3430. HRESULT WallEffect200::Modify(InternalEffect& newEffect, DWORD modFlags)
  3431. {
  3432. g_pDataPackager->ClearPackets();
  3433. HRESULT adjustResult = AdjustModifyParams(newEffect, modFlags);
  3434. if (FAILED(adjustResult)) {
  3435. return adjustResult;
  3436. }
  3437. HRESULT hr = SUCCESS;
  3438. WallEffect200* pEffect = (WallEffect200*)(&newEffect);
  3439. BYTE nextPacket = 0;
  3440. if (modFlags & DIEP_DURATION) {
  3441. hr = FillModifyPacket200(nextPacket, INDEX_BE_DURATION_200, pEffect->m_Duration/DURATION_SCALE_200);
  3442. nextPacket++;
  3443. }
  3444. if (modFlags & DIEP_TRIGGERBUTTON) {
  3445. hr = FillModifyPacket200(nextPacket, INDEX_BE_BUTTONMAP_200, g_TriggerMap200[pEffect->m_TriggerPlayButton]);
  3446. nextPacket++;
  3447. }
  3448. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  3449. hr = FillModifyPacket200(nextPacket, INDEX_BE_BUTTONREPEAT_200, DWORD(float(pEffect->m_TriggerRepeat)/DURATION_SCALE_200));
  3450. nextPacket++;
  3451. }
  3452. if (modFlags & DIEP_GAIN) {
  3453. hr = FillModifyPacket200(nextPacket, INDEX_BE_GAIN_200, DWORD(float(pEffect->m_Gain)/GAIN_SCALE_200));
  3454. nextPacket++;
  3455. }
  3456. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Send changed items
  3457. for (int i = 0; i < 4; i++) {
  3458. if ((m_Ds[i] != pEffect->m_Ds[i]) || (m_Fs[i] != pEffect->m_Fs[i])) {
  3459. hr = FillModifyPacket200(nextPacket, INDEX_D1F1_200 + i, pEffect->m_Ds[i], pEffect->m_Fs[i]);
  3460. nextPacket++;
  3461. }
  3462. }
  3463. }
  3464. if (hr == SUCCESS) {
  3465. return adjustResult;
  3466. }
  3467. return hr;
  3468. }
  3469. HRESULT WallEffect200::AdjustModifyParams(InternalEffect& newEffect, DWORD& modFlags)
  3470. {
  3471. // Check to see if values being modified are acceptable
  3472. DWORD possMod = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
  3473. /* if ((g_TotalModifiable & modFlags & possMod) == 0) { // Nothing to modify?
  3474. modFlags = 0;
  3475. return SFERR_NO_SUPPORT;
  3476. }
  3477. */
  3478. WallEffect200* pEffect = (WallEffect200*)(&newEffect);
  3479. unsigned short numPackets = 0;
  3480. HRESULT hr = SUCCESS;
  3481. if ((modFlags & (~possMod & DIEP_ALLPARAMS)) != 0) {
  3482. modFlags &= possMod;
  3483. hr = S_FALSE; // Cannot modify all they asked for
  3484. }
  3485. BOOL playingChecked = FALSE;
  3486. if (modFlags & DIEP_DURATION) {
  3487. if (m_Duration == pEffect->m_Duration) {
  3488. modFlags &= ~DIEP_DURATION; // Remove duration flag, unchanged
  3489. } else {
  3490. if (IsReallyPlaying(playingChecked) == FALSE) {
  3491. numPackets++;
  3492. } else {
  3493. return DIERR_EFFECTPLAYING;
  3494. }
  3495. }
  3496. }
  3497. if (modFlags & DIEP_TRIGGERBUTTON) {
  3498. if (m_TriggerPlayButton == pEffect->m_TriggerPlayButton) {
  3499. modFlags &= ~DIEP_TRIGGERBUTTON; // Remove trigger flag, unchanged
  3500. } else {
  3501. numPackets++;
  3502. }
  3503. }
  3504. if (modFlags & DIEP_TRIGGERREPEATINTERVAL) {
  3505. if (m_TriggerRepeat == pEffect->m_TriggerRepeat) {
  3506. modFlags &= ~DIEP_TRIGGERREPEATINTERVAL; // Remove trigger repeat flag, unchanged
  3507. } else {
  3508. numPackets++;
  3509. }
  3510. }
  3511. if (modFlags & DIEP_GAIN) { // Did gain really change
  3512. if (m_Gain == pEffect->m_Gain) {
  3513. modFlags &= ~DIEP_GAIN; // Remove trigger flag, unchanged
  3514. } else {
  3515. numPackets++;
  3516. }
  3517. }
  3518. // if (modFlags & DIEP_DIRECTION) {
  3519. // modFlags |= DIEP_TYPESPECIFICPARAMS;
  3520. // }
  3521. if (modFlags & DIEP_TYPESPECIFICPARAMS) { // Find which ones (if any)
  3522. int numTypeSpecificChanged = 0;
  3523. for (int i = 0; i < 4; i++) {
  3524. // Ds and Fs are changed togeather
  3525. if ((m_Ds[i] != pEffect->m_Ds[i]) || (m_Fs[i] != pEffect->m_Fs[i])) {
  3526. numTypeSpecificChanged++;
  3527. }
  3528. }
  3529. if (numTypeSpecificChanged == 0) {
  3530. modFlags &= ~DIEP_TYPESPECIFICPARAMS; // No type specific changed
  3531. } else {
  3532. numPackets += (USHORT)numTypeSpecificChanged;
  3533. }
  3534. }
  3535. if (numPackets != 0) { // That was easy nothing changed
  3536. g_pDataPackager->AllocateDataPackets(numPackets);
  3537. }
  3538. return hr;
  3539. }
  3540. /******************* class SystemEffect1XX ***********************/
  3541. SystemEffect1XX::SystemEffect1XX() : SystemEffect(),
  3542. m_SystemStickData()
  3543. {
  3544. }
  3545. HRESULT SystemEffect1XX::Create(const DIEFFECT& diEffect)
  3546. {
  3547. // Validation Check
  3548. if (diEffect.cbTypeSpecificParams != sizeof(SystemStickData1XX)) {
  3549. return SFERR_INVALID_PARAM;
  3550. }
  3551. if (diEffect.lpvTypeSpecificParams == NULL) {
  3552. ASSUME_NOT_REACHED();
  3553. return SFERR_INVALID_PARAM;
  3554. }
  3555. // Get the data from the DIEFFECT
  3556. ::memcpy(&m_SystemStickData, diEffect.lpvTypeSpecificParams, sizeof(SystemStickData1XX));
  3557. return SUCCESS;
  3558. }
  3559. HRESULT SystemEffect1XX::FillCreatePacket(DataPacket& packet) const
  3560. {
  3561. ASSUME_NOT_REACHED();
  3562. return SUCCESS;
  3563. }
  3564. HRESULT SystemEffect1XX::Modify(InternalEffect& newEffect, DWORD modFlags)
  3565. {
  3566. // Sanity Check
  3567. if (g_pDataPackager == NULL) {
  3568. ASSUME_NOT_REACHED();
  3569. return SFERR_DRIVER_ERROR;
  3570. }
  3571. SystemEffect1XX* pNewSystemEffect = (SystemEffect1XX*)(&newEffect);
  3572. // Find number of packets needed
  3573. unsigned short numPackets = 28; // Always need to send system commands when asked (have no idea what is on the stick
  3574. // Allocate a packets for sending modify command
  3575. if (!g_pDataPackager->AllocateDataPackets(numPackets)) {
  3576. return SFERR_DRIVER_ERROR;
  3577. }
  3578. // Fill the packets
  3579. BYTE nextPacket = 0;
  3580. FillModifyPacket1XX(nextPacket, INDEX0, pNewSystemEffect->m_SystemStickData.dwXYConst/2);
  3581. nextPacket += 2;
  3582. FillModifyPacket1XX(nextPacket, INDEX1, pNewSystemEffect->m_SystemStickData.dwRotConst/2);
  3583. nextPacket += 2;
  3584. FillModifyPacket1XX(nextPacket, INDEX2, pNewSystemEffect->m_SystemStickData.dwSldrConst);
  3585. nextPacket += 2;
  3586. FillModifyPacket1XX(nextPacket, INDEX3, pNewSystemEffect->m_SystemStickData.dwAJRot);
  3587. nextPacket += 2;
  3588. FillModifyPacket1XX(nextPacket, INDEX4, pNewSystemEffect->m_SystemStickData.dwAJRot);
  3589. nextPacket += 2;
  3590. FillModifyPacket1XX(nextPacket, INDEX5, pNewSystemEffect->m_SystemStickData.dwAJSldr);
  3591. nextPacket += 2;
  3592. FillModifyPacket1XX(nextPacket, INDEX6, pNewSystemEffect->m_SystemStickData.dwSprScl);
  3593. nextPacket += 2;
  3594. FillModifyPacket1XX(nextPacket, INDEX7, pNewSystemEffect->m_SystemStickData.dwBmpScl);
  3595. nextPacket += 2;
  3596. FillModifyPacket1XX(nextPacket, INDEX8, pNewSystemEffect->m_SystemStickData.dwDmpScl);
  3597. nextPacket += 2;
  3598. FillModifyPacket1XX(nextPacket, INDEX9, pNewSystemEffect->m_SystemStickData.dwInertScl);
  3599. nextPacket += 2;
  3600. FillModifyPacket1XX(nextPacket, INDEX10, pNewSystemEffect->m_SystemStickData.dwVelOffScl);
  3601. nextPacket += 2;
  3602. FillModifyPacket1XX(nextPacket, INDEX11, pNewSystemEffect->m_SystemStickData.dwAccOffScl);
  3603. nextPacket += 2;
  3604. FillModifyPacket1XX(nextPacket, INDEX12, pNewSystemEffect->m_SystemStickData.dwYMotBoost/2);
  3605. nextPacket += 2;
  3606. FillModifyPacket1XX(nextPacket, INDEX13, pNewSystemEffect->m_SystemStickData.dwXMotSat);
  3607. return SUCCESS;
  3608. }
  3609. /******************* class SystemStickData1XX ***********************/
  3610. SystemStickData1XX::SystemStickData1XX()
  3611. {
  3612. dwXYConst = DEF_XY_CONST;
  3613. dwRotConst = DEF_ROT_CONST;
  3614. dwSldrConst = DEF_SLDR_CONST;
  3615. dwAJPos = DEF_AJ_POS;
  3616. dwAJRot = DEF_AJ_ROT;
  3617. dwAJSldr = DEF_AJ_SLDR;
  3618. dwSprScl = DEF_SPR_SCL;
  3619. dwBmpScl = DEF_BMP_SCL;
  3620. dwDmpScl = DEF_DMP_SCL;
  3621. dwInertScl = DEF_INERT_SCL;
  3622. dwVelOffScl = DEF_VEL_OFFSET_SCL;
  3623. dwAccOffScl = DEF_ACC_OFFSET_SCL;
  3624. dwYMotBoost = DEF_Y_MOT_BOOST;
  3625. dwXMotSat = DEF_X_MOT_SATURATION;
  3626. dwReserved = 0;
  3627. dwMasterGain = 0;
  3628. }
  3629. #define REGSTR_VAL_JOYSTICK_PARAMS "JoystickParams"
  3630. void SystemStickData1XX::SetFromRegistry(DWORD dwDeviceID)
  3631. {
  3632. // try to open the registry key
  3633. HKEY hkey = joyOpenOEMForceFeedbackKey(dwDeviceID);
  3634. if (hkey != NULL) {
  3635. RegistryKey ffKey(hkey);
  3636. ffKey.ShouldClose(TRUE);
  3637. DWORD numBytes = sizeof(SystemStickData1XX);
  3638. if (ffKey.QueryValue(REGSTR_VAL_JOYSTICK_PARAMS, (BYTE*)this, numBytes) == SUCCESS) {
  3639. return;
  3640. }
  3641. }
  3642. // We were either not able to open the key or get the value (Use defaults)
  3643. dwXYConst = DEF_XY_CONST;
  3644. dwRotConst = DEF_ROT_CONST;
  3645. dwSldrConst = DEF_SLDR_CONST;
  3646. dwAJPos = DEF_AJ_POS;
  3647. dwAJRot = DEF_AJ_ROT;
  3648. dwAJSldr = DEF_AJ_SLDR;
  3649. dwSprScl = DEF_SPR_SCL;
  3650. dwBmpScl = DEF_BMP_SCL;
  3651. dwDmpScl = DEF_DMP_SCL;
  3652. dwInertScl = DEF_INERT_SCL;
  3653. dwVelOffScl = DEF_VEL_OFFSET_SCL;
  3654. dwAccOffScl = DEF_ACC_OFFSET_SCL;
  3655. dwYMotBoost = DEF_Y_MOT_BOOST;
  3656. dwXMotSat = DEF_X_MOT_SATURATION;
  3657. dwReserved = 0;
  3658. dwMasterGain = 0;
  3659. }