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.
 
 
 
 
 
 

2151 lines
68 KiB

/****************************************************************************
MODULE: HAU_MIDI.CPP
Tab stops 5 9
Copyright 1995, 1996, Microsoft Corporation, All Rights Reserved.
PURPOSE: Methods for Jolt Midi device command Protocol
FUNCTIONS: Classes methods
Author(s): Name:
---------- ----------------
MEA Manolito E. Adan
Revision History:
-----------------
Version Date Author Comments
------- ------ ----- -------------------------------------------
1.0 02-Apr-96 MEA Original
19-Sep-96 MEA Removed ES1.0 specific code
05-Dec-96 MEA Removed ALLACK debug switch
1.1 17-Mar-97 MEA DX-FF mode
14-Apr-97 MEA Added support for RTC spring
16-Mar-99 waltw Add checks for NULL g_pJoltMidi
****************************************************************************/
#include <windows.h>
#include <mmsystem.h>
#include <assert.h>
#include "hau_midi.hpp"
#include "midi.hpp"
#include "midi_obj.hpp"
#include "dx_map.hpp"
#include "sw_objec.hpp"
#include "ffd_swff.hpp"
#include "joyregst.hpp"
#include "FFDevice.h"
/****************************************************************************
Declaration of externs
****************************************************************************/
/****************************************************************************
Declaration of variables
****************************************************************************/
//
// Globals specific to hau_midi
//
extern CJoltMidi *g_pJoltMidi;
#ifdef _DEBUG
extern char g_cMsg[160];
#endif
// *** ---------------------------------------------------------------------***
// Function: CMD_Init
// Purpose: Inits JOLT for MIDI channel
// Parameters:
// none
//
// Returns: SUCCESS - if successful, else
// a device Error code
//
// Algorithm:
//
// Comments:
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_Init(void)
{
HRESULT hRet;
BYTE bChannel = DEFAULT_MIDI_CHANNEL;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
g_pJoltMidi->SetMidiChannel(bChannel); // Force this channel
hRet = CMD_MIDI_Assign(bChannel);
return(hRet);
}
//
// --- EFFECT_CMDs
//
/****************************************************************************
FUNCTION: CMD_Force_Out
PARAMETERS: IN LONG lForceData - Actual force
IN ULONG ulAxisMask - Axis Mask
RETURNS: SUCCESS or FAILURE
COMMENTS: Sends force vector to MIDI channel
Byte 0 = EFFECT_CMD + Channel #
D7 D6 D5 D4 D3 D2 D1 D0
-- -- -- -- -- -- -- --
Byte 1 = Low byte of Force 0 v4 v3 v2 v1 v0 d d
Byte 2 = High byte of Force 0 v11 v10 v9 v8 v7 v6 v5
where: d d
- -
0 0 reserved
0 1 PUT_FORCE_X
1 0 PUT_FORCE_Y
1 1 PUT_FORCE_XY
****************************************************************************/
HRESULT CMD_Force_Out(LONG lForceData, ULONG ulAxisMask)
{
HRESULT hRet;
BYTE cData1;
BYTE cData2;
BYTE cAxis;
BYTE cStatus = EFFECT_CMD;
switch(ulAxisMask)
{
case X_AXIS:
cAxis = PUT_FORCE_X;
break;
case Y_AXIS:
cAxis = PUT_FORCE_Y;
break;
case (X_AXIS | Y_AXIS):
cAxis = PUT_FORCE_XY;
break;
default:
return (SFERR_INVALID_PARAM);
break;
}
cData1 = ((int) lForceData << 2) & 0x7c;
cData1 = cData1 | cAxis;
cData2 = ((int) lForceData >> 5) & 0x7f;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD, cData1, cData2);
if (SUCCESS != hRet)
return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
DRIVER_ERROR_MIDI_OUTPUT));
// Note: PutForce used to not expect an ACK/NACK, only used to slow down
// transmission to Jolt and prevent any lockups
//Sleep(SHORT_MSG_TIMEOUT);
//ACKNACK AckNack = {sizeof(ACKNACK)};
//hRet = g_pJoltMidi->GetAckNackData(g_pJoltMidi->DelayParamsPtrOf()->dwForceOutDelay, &AckNack);
#if 0
static DWORD dwMod = 0;
dwMod++;
if(dwMod%g_pJoltMidi->DelayParamsPtrOf()->dwForceOutMod == 0)
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwForceOutDelay);
#endif
DWORD dwIn;
int nDelayCount = g_pJoltMidi->DelayParamsPtrOf()->dwForceOutDelay;
for(int i=0; i<nDelayCount; i++)
g_pDriverCommunicator->GetStatusGateData(dwIn);
return (SUCCESS);
}
// *** ---------------------------------------------------------------------***
// Function: CMD_DestroyEffect
// Purpose: Destroys the Effect from Device
// Parameters:
// IN DNHANDLE DnloadID - an Effect ID
//
// Returns: SUCCESS if successful command sent, else
// SFERR_INVALID_OBJECT
// SFERR_NO_SUPPORT
//
// Algorithm:
//
// Comments:
// The Device's Effect ID and memory is returned to free pool.
// Byte 0 = EFFECT_CMD + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = DESTROY_EFFECT 0 0 0 1 0 0 0 0
// Byte 2 = EffectID (7 bits) 0 E E E E E E E
//
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_DestroyEffect(
IN DNHANDLE DnloadID)
{
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// Check for valid Effect
CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
assert(NULL != pMidiEffect);
if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
// Send the command
HRESULT hRet = pMidiEffect->DestroyEffect();
if (SUCCESS != hRet)
return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
DRIVER_ERROR_MIDI_OUTPUT));
ACKNACK AckNack = {sizeof(ACKNACK)};
// Wait for ACK. Note: WinMM has callback Event notification
// while Backdoor and serial does not.
if (COMM_WINMM == g_pJoltMidi->COMMInterfaceOf())
{
hRet = g_pJoltMidi->GetAckNackData(ACKNACK_EFFECT_STATUS_TIMEOUT, &AckNack, REGBITS_DESTROYEFFECT);
}
else
hRet = g_pJoltMidi->GetAckNackData(SHORT_MSG_TIMEOUT, &AckNack, REGBITS_DESTROYEFFECT);
// :
if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
if (ACK != AckNack.dwAckNack)
return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
// Delete the Effect
delete pMidiEffect;
return (hRet);
}
// *** ---------------------------------------------------------------------***
// Function: CMD_PlayEffectSuperimpose
// Purpose: Plays the Effect in Device
// Parameters:
// IN DNHANDLE DnloadID - an Effect ID
//
// Returns: SUCCESS if successful command sent, else
// SFERR_INVALID_OBJECT
// SFERR_NO_SUPPORT
//
// Algorithm: This is PLAY_SUPERIMPOSE mode
//
// Comments:
// Byte 0 = EFFECT_CMD + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = PLAY_EFFECT_SUPERIMPOSE 0 0 1 0 0 0 0 0
// Byte 2 = EffectID (7 bits) 0 E E E E E E E
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_PlayEffectSuperimpose(
IN DNHANDLE DnloadID)
{
HRESULT hRet;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// Check for valid Effect
CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiEffect);
if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
#if 0
// Hack to fix firmware bug #1138 which causes an infinite duration
// effect not to be felt on re-start once the effect has been stopped.
// The hack is to "change" the duration from infinite to infinite
ULONG ulDuration = pMidiEffect->DurationOf();
if(ulDuration == 0)
{
// see if it is a PL or an atomic effect
ULONG ulSubType = pMidiEffect->SubTypeOf();
BOOL bProcessList = (ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE);
if(!bProcessList)
hRet = CMD_ModifyParamByIndex(INDEX0, DnloadID, 0);
}
#endif
// Update the playback mode for this Effect
pMidiEffect->SetPlayMode(PLAY_SUPERIMPOSE);
assert((BYTE) DnloadID < MAX_EFFECT_IDS);
hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD,PLAY_EFFECT_SUPERIMPOSE,(BYTE)DnloadID);
if (SUCCESS != hRet)
return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
DRIVER_ERROR_MIDI_OUTPUT));
ACKNACK AckNack = {sizeof(ACKNACK)};
hRet = g_pJoltMidi->GetAckNackData(LONG_MSG_TIMEOUT, &AckNack, REGBITS_PLAYEFFECT);
// :
if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
if (ACK != AckNack.dwAckNack)
return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
return (hRet);
}
// *** ---------------------------------------------------------------------***
// Function: CMD_PlayEffectSolo
// Purpose: Plays the Effect in Device as PLAY_SOLO
// Parameters:
// IN DNHANDLE EffectID - an Effect ID
//
// Returns: SUCCESS if successful command sent, else
// SFERR_INVALID_OBJECT
// SFERR_NO_SUPPORT
//
// Algorithm: This is PLAY_SOLO mode
//
// Comments:
// Byte 0 = EFFECT_CMD + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = PLAY_EFFECT_SOLO 0 0 0 0 0 0 0 0
// Byte 2 = EffectID (7 bits) 0 E E E E E E E
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_PlayEffectSolo(
IN DNHANDLE DnloadID)
{
HRESULT hRet;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// Check for valid Effect
CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiEffect);
if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
#if 0
// Hack to fix firmware bug #1138 which causes an infinite duration
// effect not to be felt on re-start once the effect has been stopped.
// The hack is to "change" the duration from infinite to infinite
ULONG ulDuration = pMidiEffect->DurationOf();
if(ulDuration == 0)
{
// see if it is a PL or an atomic effect
ULONG ulSubType = pMidiEffect->SubTypeOf();
BOOL bProcessList = (ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE);
if(!bProcessList)
hRet = CMD_ModifyParamByIndex(INDEX0, DnloadID, 0);
}
#endif
// Update the playback mode for this Effect
pMidiEffect->SetPlayMode(PLAY_SOLO);
hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD,PLAY_EFFECT_SOLO, (BYTE) DnloadID);
if (SUCCESS != hRet)
return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
DRIVER_ERROR_MIDI_OUTPUT));
ACKNACK AckNack = {sizeof(ACKNACK)};
hRet = g_pJoltMidi->GetAckNackData(LONG_MSG_TIMEOUT, &AckNack, REGBITS_PLAYEFFECT);
// :
if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
if (ACK != AckNack.dwAckNack)
return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
return (hRet);
}
// *** ---------------------------------------------------------------------***
// Function: CMD_StopEffect
// Purpose: Stops the Effect in Device
// Parameters:
// IN DNHANDLE EffectID - an Effect ID
//
// Returns: SUCCESS if successful command sent, else
// SFERR_INVALID_OBJECT
// SFERR_NO_SUPPORT
//
// Algorithm:
//
// Comments:
// Byte 0 = EFFECT_CMD + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = STOP_EFFECT 0 0 1 1 0 0 0 0
// Byte 2 = EffectID (7 bits) 0 E E E E E E E
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_StopEffect(
IN DNHANDLE DnloadID)
{
HRESULT hRet;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// Check for valid Effect
CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiEffect);
if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD, STOP_EFFECT, (BYTE) DnloadID);
if (SUCCESS != hRet)
return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
DRIVER_ERROR_MIDI_OUTPUT));
ACKNACK AckNack = {sizeof(ACKNACK)};
hRet = g_pJoltMidi->GetAckNackData(SHORT_MSG_TIMEOUT, &AckNack, REGBITS_STOPEFFECT);
// :
if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
if (ACK != AckNack.dwAckNack)
return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
return (hRet);
}
// *** ---------------------------------------------------------------------***
// Function: CMD_SetIndex
// Purpose: Sets the autoincrementing Index for MODIFY_CMD
// Parameters:
// IN int nIndex - Index value 0 - 15
// IN DNHANDLE DnloadID - Effect ID in stick
//
// Returns: SUCCESS if successful command sent, else
// SFERR_INVALID_OBJECT
// SFERR_NO_SUPPORT
// SFERR_INVALID_PARAM
// Algorithm:
//
// Comments:
// Byte 0 = EFFECT_CMD + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = SET_INDEX+index 0 1 i i i i 0 0
// Byte 2 = EffectID (7 bits) 0 E E E E E E E
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_SetIndex(
IN int nIndex,
IN DNHANDLE DnloadID)
{
HRESULT hRet;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// Check for valid Effect
if (SYSTEM_EFFECT_ID != DnloadID)
{
CMidiEffect *pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiEffect);
if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
}
assert((nIndex <= MAX_INDEX) && (nIndex >= 0));
if ((nIndex < 0) || (nIndex > MAX_INDEX)) return (SFERR_INVALID_PARAM);
BYTE cByte1;
cByte1 = SET_INDEX | (BYTE) (nIndex << 2);
hRet = g_pJoltMidi->MidiSendShortMsg(EFFECT_CMD, cByte1, (BYTE) DnloadID);
if (SUCCESS != hRet)
return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
DRIVER_ERROR_MIDI_OUTPUT));
// Note: SetIndex used to not require ACK/NACK
ACKNACK AckNack = {sizeof(ACKNACK)};
// hRet = g_pJoltMidi->GetAckNackData(SHORT_MSG_TIMEOUT, &AckNack);
hRet = g_pJoltMidi->GetAckNackData(FALSE, &AckNack, REGBITS_SETINDEX);
// :
if (SUCCESS != hRet)
return (SFERR_DRIVER_ERROR);
if (ACK != AckNack.dwAckNack)
return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
return (hRet);
}
// *** ---------------------------------------------------------------------***
// Function: CMD_ModifyParam
// Purpose: Modifies an Effect parameter
// Parameters:
// IN WORD dwNewParam - 14 bit (signed) parameter value
//
// Returns: SUCCESS if successful command sent, else
// SFERR_INVALID_OBJECT
// SFERR_NO_SUPPORT
// SFERR_INVALID_PARAM
// Algorithm:
//
// Comments:
// Byte 0 = MODIFY_CMD + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = Low 7 bits data 0 v v v v v v v
// Byte 2 = High 7 bits data 0 v v v v v v v
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_ModifyParam(
IN WORD wNewParam)
{
HRESULT hRet;
BYTE cByte1, cByte2;
cByte1 = wNewParam & 0x7f;
cByte2 = (BYTE) ((wNewParam >> 7) & 0x7f);
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
hRet = g_pJoltMidi->MidiSendShortMsg(MODIFY_CMD, cByte1, cByte2);
if (SUCCESS != hRet)
return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
DRIVER_ERROR_MIDI_OUTPUT));
// Note: ModifyParam used to not require an ACK/NACK
ACKNACK AckNack = {sizeof(ACKNACK)};
// hRet = g_pJoltMidi->GetAckNackData(SHORT_MSG_TIMEOUT, &AckNack);
hRet = g_pJoltMidi->GetAckNackData(FALSE, &AckNack, REGBITS_MODIFYPARAM);
// :
if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
if (ACK != AckNack.dwAckNack)
return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
return (hRet);
}
// *** ---------------------------------------------------------------------***
// Function: CMD_ModifyParamByIndex
// Purpose: Modifies an Effect parameter, given an Index
// Parameters:
// IN int nIndex - Index 0 to 15
// IN DNHANDLE DnloadID - Download ID
// IN WORD dwNewParam - 14 bit (signed) parameter value
//
// Returns: SUCCESS if successful command sent, else
// SFERR_NO_SUPPORT
// SFERR_INVALID_PARAM
// Algorithm:
//
// Comments:
// Assumes DnloadID is already valid
// Calls SetIndex followed by ModifyParam
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_ModifyParamByIndex(
IN int nIndex,
IN DNHANDLE DnloadID,
IN WORD wNewParam)
{
HRESULT hRet;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
if ((nIndex < 0) || (nIndex > MAX_INDEX))
return (SFERR_INVALID_PARAM);
int i;
for (i=0; i<MAX_RETRY_COUNT; i++)
{
hRet = CMD_SetIndex(nIndex,DnloadID);
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwSetIndexDelay);
if (SUCCESS == hRet) break;
#ifdef _DEBUG
OutputDebugString("CMD_SetIndex Failed. Retrying again\n");
#endif
}
if (SUCCESS != hRet)
return (hRet);
else
{
for (i=0; i<MAX_RETRY_COUNT; i++)
{
hRet = CMD_ModifyParam(wNewParam);
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwModifyParamDelay);
if (SUCCESS == hRet) break;
#ifdef _DEBUG
OutputDebugString("CMD_SetIndex Failed. Retrying again\n");
#endif
}
}
return (hRet);
}
//
// --- SYSTEM_CMDs
//
// *** ---------------------------------------------------------------------***
// Function: CMD_SetDeviceState
// Purpose: Sets the FF device State
// Parameters:
// ULONG ulMode
//
// Returns: SUCCESS - if successful, else
// Device error code
//
// Algorithm:
// Comments:
// ulMode:
// DEV_SHUTDOWN 1L // All Effects destroyed, Motors disabled
// DEV_FORCE_ON 2L // Motors enabled. "Un-Mute"
// DEV_FORCE_OFF 3L // Motors disabled. "Mute"
// DEV_CONTINUE 4L // All "Paused" Effects are allow to continue
// DEV_PAUSE 5L // All Effects are "Paused"
// DEV_STOP_ALL 6L // Stops all Effects.
//
// Byte 0 = SYSTEM_CMD + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = Set Device Type 0 0 0 0 0 0 0 1
// Byte 2 = not used, set to 0 0 0 0 0 0 0 0 0
//
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_SetDeviceState(
IN ULONG ulMode)
{
HRESULT hRet = SUCCESS;
assert(g_pJoltMidi);
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
BYTE bChannel = g_pJoltMidi->MidiChannelOf();
MIDIINFO *pMidiOutInfo = g_pJoltMidi->MidiOutInfoOf();
switch (ulMode)
{
case DEV_RESET:
hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_SHUTDOWN, 0);
break;
case DEV_FORCE_ON:
hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_FORCE_ON, 0);
break;
case DEV_FORCE_OFF:
hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_FORCE_OFF, 0);
break;
case DEV_CONTINUE:
hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_CONTINUE, 0);
break;
case DEV_PAUSE:
hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_PAUSE, 0);
break;
case DEV_STOP_ALL:
hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_STOP_ALL, 0);
break;
case SWDEV_KILL_MIDI:
hRet = g_pJoltMidi->MidiSendShortMsg(SYSTEM_CMD, SWDEV_KILL_MIDI, 0);
break;
default:
return SFERR_INVALID_PARAM;
}
if (SUCCESS != hRet)
return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
DRIVER_ERROR_MIDI_OUTPUT));
// Wait for ACK or NACK
ACKNACK AckNack = {sizeof(ACKNACK)};
if (DEV_RESET == ulMode)
{ // Wait for Jolt to complete the cycle
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwHWResetDelay);
hRet = g_pJoltMidi->GetAckNackData(ACKNACK_TIMEOUT, &AckNack, REGBITS_SETDEVICESTATE);
}
else
{
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwDigitalOverdrivePrechargeCmdDelay);
hRet = g_pJoltMidi->GetAckNackData(FALSE, &AckNack, REGBITS_SETDEVICESTATE);
}
// :
if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
if (ACK != AckNack.dwAckNack)
return (g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode));
// Special case Shutdown
if (DEV_RESET == ulMode)
{
// Delete all Effects except built-in RTC Spring and FRICTION cancel.
g_pJoltMidi->DeleteDownloadedEffects();
}
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwPostSetDeviceStateDelay);
return (hRet);
}
// *** ---------------------------------------------------------------------***
// Function: CMD_GetEffectStatus
// Purpose: Returns Status of Effect ID
// Parameters:
// DNHANDLE DnloadID - Effect ID
// PBYTE pStatusCode - Status Code
//
// Returns: SUCCESS - if successful, else
// a device Error code
// *pStatusCode set to - SWDEV_STS_EFFECT_STOPPED
// SWDEV_STS_EFFECT_RUNNING
//
// Algorithm:
//
// Comments:
// Byte 0 = STATUS_CMD + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = Effect ID 0 0 0 0 0 1 0 0
// Byte 2 = not used, set to 0 0 0 0 0 0 0 0 0
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_GetEffectStatus(DNHANDLE DnloadID, PBYTE pStatusCode)
{
HRESULT hRet;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
hRet = g_pJoltMidi->MidiSendShortMsg(STATUS_CMD, (BYTE) DnloadID, 0);
if (SUCCESS != hRet)
return (g_pJoltMidi->LogError(SFERR_DRIVER_ERROR,
DRIVER_ERROR_MIDI_OUTPUT));
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwGetEffectStatusDelay);// enough for about 3 bytes of data being sent at 330us/byte
DWORD dwIn;
hRet = g_pDriverCommunicator->GetStatusGateData(dwIn);
if (SUCCESS != hRet) return (hRet);
if ((g_ForceFeedbackDevice.GetDriverVersionMajor() != 1) && (dwIn & RUNNING_MASK_200))
{
*pStatusCode = SWDEV_STS_EFFECT_RUNNING;
}
else
{
*pStatusCode = SWDEV_STS_EFFECT_STOPPED;
}
return (hRet);
}
//
// --- System Exclusive Commands
//
// System Exclusive Command:MIDI_ASSIGN
//
// *** ---------------------------------------------------------------------***
// Function: CMD_MIDI_Assign
// Purpose: Inits JOLT MIDI channel
// Parameters: BYTE bMidiChannel - Channel to assign
//
// Returns: SUCCESS or Error code
//
//
// Algorithm:
//
// Comments: SYS_EX type command
//
// Body D7 D6 D5 D4 D3 D2 D1 D0
// ------ -- -- -- -- -- -- -- --
// Byte 0 = MIDI_ASSIGN 0 0 0 1 0 0 0 0
// Byte 1 = channel#(0-15) e.g. 5 0 0 0 0 0 1 0 1
// Byte 2 = not used, set to 0 0 0 0 0 0 0 0 0
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_MIDI_Assign(
IN BYTE bMidiChannel)
{
HRESULT hRet;
PMIDI_ASSIGN_SYS_EX lpData;
CMidiAssign *pMidiAssign;
assert((bMidiChannel > 0) && (bMidiChannel < MAX_MIDI_CHANNEL));
pMidiAssign = new CMidiAssign;
assert(pMidiAssign);
if (!pMidiAssign) return (SFERR_DRIVER_ERROR);
pMidiAssign->SetMidiAssignChannel(bMidiChannel);
lpData = (PMIDI_ASSIGN_SYS_EX) pMidiAssign->GenerateSysExPacket();
assert(lpData);
if(!lpData) return (SFERR_DRIVER_ERROR);
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// Prepare the buffer for SysEx output
g_pJoltMidi->MidiAssignBuffer((LPSTR) lpData,
(DWORD) sizeof(MIDI_ASSIGN_SYS_EX), TRUE);
// Send the message and Wait for the ACK
hRet = g_pJoltMidi->MidiSendLongMsg();
if (SUCCESS == hRet)
{
ACKNACK AckNack = {sizeof(ACKNACK)};
// Wait for ACK. Note: WinMM has callback Event notification
// while Backdoor and serial does not.
if (COMM_WINMM == g_pJoltMidi->COMMInterfaceOf())
{
hRet = g_pJoltMidi->GetAckNackData(ACKNACK_TIMEOUT, &AckNack, REGBITS_DEVICEINIT);
}
else
hRet = g_pJoltMidi->GetAckNackData(FALSE, &AckNack, REGBITS_DEVICEINIT);
// :
if (SUCCESS != hRet) return (SFERR_DRIVER_ERROR);
if (ACK != AckNack.dwAckNack)
hRet = g_pJoltMidi->LogError(SFERR_DEVICE_NACK, AckNack.dwErrorCode);
}
else
hRet = SFERR_DRIVER_ERROR;
// Release the Midi buffers and delete the MIDI sys_ex object
g_pJoltMidi->MidiAssignBuffer((LPSTR) lpData, 0, FALSE);
delete pMidiAssign;
return (hRet);
}
//
// System Exclusive Command:DNLOAD_DATA
//
/****************************************************************************
FUNCTION: CMD_Download_BE_XXX
PARAMETERS: PEFFECT pEffect - Ptr to a EFFECT data structure
PENVELOPE pEnvelope - Ptr to an ENVELOPE data structure
PBE_XXX pBE_XXX - Ptr to a BE_XXX data structure
PDNHANDLE pDnloadID - Ptr to a HANDLE storage
DWORD dwFlags - dwFlags from Kernel
RETURNS: SUCCESS or ERROR code
COMMENTS: Downloads BE_XXX type Effect params to the device
Uses SysEx prototype and ModifyParam methods
Note: Normally pEnvelope = NULL
****************************************************************************/
HRESULT CMD_Download_BE_XXX(
IN PEFFECT pEffect,
IN PENVELOPE pEnvelope,
IN PBE_XXX pBE_XXX,
IN OUT PDNHANDLE pDnloadID,
IN DWORD dwFlags)
{
HRESULT hRet = SUCCESS;
PBEHAVIORAL_SYS_EX lpData;
CMidiBehavioral *pMidiBehavioral;
BOOL fXConstantChanged=FALSE;
BOOL fYConstantChanged=FALSE;
BOOL fParam3Changed=FALSE;
BOOL fParam4Changed=FALSE;
assert(pEffect && pBE_XXX && pDnloadID);
if ((NULL == pEffect) || (NULL == pBE_XXX) || (NULL == pDnloadID))
return (SFERR_INVALID_PARAM);
DNHANDLE DnloadID =*pDnloadID;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// scale the constants using the fudge factor
PFIRMWARE_PARAMS pFirmwareParams = g_pJoltMidi->FirmwareParamsPtrOf();
switch(pEffect->m_SubType)
{
case BE_INERTIA:
case BE_INERTIA_2D:
pBE_XXX->m_XConstant = (((int)pBE_XXX->m_XConstant)*((int)pFirmwareParams->dwScaleMx))/((int)100);
pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleMy))/((int)100);
break;
case BE_SPRING:
case BE_SPRING_2D:
pBE_XXX->m_XConstant = (((int)pBE_XXX->m_XConstant)*((int)pFirmwareParams->dwScaleKx))/((int)100);
pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleKy))/((int)100);
break;
case BE_DAMPER:
case BE_DAMPER_2D:
pBE_XXX->m_XConstant = (((int)pBE_XXX->m_XConstant)*((int)pFirmwareParams->dwScaleBx))/((int)100);
pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleBy))/((int)100);
break;
case BE_FRICTION:
case BE_FRICTION_2D:
pBE_XXX->m_XConstant = (((int)pBE_XXX->m_XConstant)*((int)pFirmwareParams->dwScaleFx))/((int)100);
pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleFy))/((int)100);
break;
case BE_WALL:
pBE_XXX->m_YConstant = (((int)pBE_XXX->m_YConstant)*((int)pFirmwareParams->dwScaleW))/((int)100);
break;
default:
// do not scale
break;
}
// If Create New, then create a new object, using SysEx
// else, update the existing Effect object, using ModifyParam
if (NULL == DnloadID) // New, Make a new object, use SysEx
{
if ((BE_FRICTION == pEffect->m_SubType) || (BE_FRICTION_2D == pEffect->m_SubType))
{
pMidiBehavioral = new CMidiFriction(pEffect, pEnvelope, pBE_XXX);
assert(pMidiBehavioral);
}
else // Wall
if (BE_WALL == pEffect->m_SubType)
{
pMidiBehavioral = new CMidiWall(pEffect, pEnvelope, pBE_XXX);
assert(pMidiBehavioral);
}
// BE_SPRINGxx, BE_DAMPERxx, BE_INERTIAxx
else
{
pMidiBehavioral = new CMidiBehavioral(pEffect, pEnvelope, pBE_XXX);
assert(pMidiBehavioral);
}
if (NULL == pMidiBehavioral) return (SFERR_INVALID_OBJECT);
// Generate Sys_Ex packet then prepare for output
lpData = (PBEHAVIORAL_SYS_EX) pMidiBehavioral->GenerateSysExPacket();
assert(lpData);
if (!lpData) return (SFERR_DRIVER_ERROR);
// Store the PrimaryBuffer ptr to CMidiEffect::m_pBuffer;
pMidiBehavioral->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
hRet = pMidiBehavioral->SendPacket(pDnloadID, pMidiBehavioral->MidiBufferSizeOf());
if (SUCCESS != hRet) // Create NEW, Failure
{
delete pMidiBehavioral;
}
}
else // Modify existing
{
pMidiBehavioral = (CMidiBehavioral *) g_pJoltMidi->GetEffectByID(*pDnloadID);
assert(pMidiBehavioral);
if (NULL == pMidiBehavioral) return (SFERR_INVALID_OBJECT);
// Check if Type specific params have changed.
if (BE_WALL == pEffect->m_SubType)
{
if ((pBE_XXX->m_XConstant) != pMidiBehavioral->XConstantOf())
fXConstantChanged=TRUE; // Wall Type
if ((pBE_XXX->m_YConstant) != pMidiBehavioral->YConstantOf())
fYConstantChanged=TRUE; // Wall Constant
if ((pBE_XXX->m_Param3) != pMidiBehavioral->Param3Of())
fParam3Changed=TRUE; // Wall Angle
if ((pBE_XXX->m_Param4) != pMidiBehavioral->Param4Of())
fParam4Changed=TRUE; // Wall Distance
}
else
{
if ((pBE_XXX->m_XConstant) != pMidiBehavioral->XConstantOf())
fXConstantChanged=TRUE;
if ((pBE_XXX->m_YConstant) != pMidiBehavioral->YConstantOf())
fYConstantChanged=TRUE;
if ((BE_FRICTION != pEffect->m_SubType) && (BE_FRICTION_2D != pEffect->m_SubType))
{
if ((pBE_XXX->m_Param3) != pMidiBehavioral->Param3Of())
fParam3Changed=TRUE;
if ((pBE_XXX->m_Param4) != pMidiBehavioral->Param4Of())
fParam4Changed=TRUE;
}
}
// Fill in the common Effect and Behavioral specific parameters
// Only update Duration and Button Play as common effect parameters
// Double check if DURATION and TRIGGERBUTTON changed, to speed operation
DWORD dwTempFlags = 0;
if (pEffect->m_Duration != pMidiBehavioral->DurationOf())
dwTempFlags = dwTempFlags | DIEP_DURATION;
if (pEffect->m_ButtonPlayMask != pMidiBehavioral->ButtonPlayMaskOf())
dwTempFlags = dwTempFlags | DIEP_TRIGGERBUTTON;
pMidiBehavioral->SetEffectParams(pEffect, pBE_XXX);
hRet = ModifyEffectParams(DnloadID, pEffect, dwTempFlags);
if (SUCCESS!=hRet) return hRet;
if (BE_WALL == pEffect->m_SubType)
{
// Generate Sys_Ex packet then prepare for output
lpData = (PBEHAVIORAL_SYS_EX) pMidiBehavioral->GenerateSysExPacket();
assert(lpData);
if (!lpData) return (SFERR_DRIVER_ERROR);
// Store the PrimaryBuffer ptr to CMidiEffect::m_pBuffer;
pMidiBehavioral->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
hRet = pMidiBehavioral->SendPacket(pDnloadID, pMidiBehavioral->MidiBufferSizeOf());
}
else // Use ModifyParameter
{
// Type Specific Params
if (dwFlags & DIEP_TYPESPECIFICPARAMS)
{
if (fYConstantChanged) // KY/BY/MY/FY
{
hRet = CMD_ModifyParamByIndex(INDEX3, DnloadID, (SHORT) (pBE_XXX->m_YConstant * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
if(fXConstantChanged) // KX/BX/MX/FX
{
hRet = CMD_ModifyParamByIndex(INDEX2, DnloadID, (SHORT) (pBE_XXX->m_XConstant * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
if (fParam4Changed) // CY/VY/AY
{
hRet = CMD_ModifyParamByIndex(INDEX5, DnloadID, (SHORT) (pBE_XXX->m_Param4 * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
if (fParam3Changed) // CX/VX/AX
{
hRet = CMD_ModifyParamByIndex(INDEX4, DnloadID, (SHORT) (pBE_XXX->m_Param3 * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
}
}
}
return (hRet);
}
/****************************************************************************
FUNCTION: CMD_Download_RTCSpring
PARAMETERS: PRTCSPRING_PARAM pRTCSpring - Ptr to a RTCSPRING_PARAM structure
PDNHANDLE pDnloadID - Ptr to a HANDLE storage
RETURNS: SUCCESS or ERROR code
COMMENTS: Downloads RTCSPRING type Effect params to the device
Uses SysEx prototype and ModifyParam methods
****************************************************************************/
HRESULT CMD_Download_RTCSpring(
IN PRTCSPRING_PARAM pRTCSpring,
IN OUT PDNHANDLE pDnloadID)
{
HRESULT hRet = SUCCESS;
CMidiRTCSpring *pMidiRTCSpring;
assert(pRTCSpring && pDnloadID);
if ((NULL == pRTCSpring) || (NULL == pDnloadID))
return (SFERR_INVALID_PARAM);
DNHANDLE DnloadID = SYSTEM_RTCSPRING_ID;
*pDnloadID = DnloadID;
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// Note: RTC Spring is a permanent System Effect ID 2
pMidiRTCSpring = (CMidiRTCSpring *) g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiRTCSpring);
if (NULL == pMidiRTCSpring) return (SFERR_INVALID_OBJECT);
// Check if Type specific params have changed, if so, Modify it
if ((pRTCSpring->m_XKConstant) != pMidiRTCSpring->XKConstantOf())
{
if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX0, DnloadID,
(SHORT) (pRTCSpring->m_XKConstant * MAX_SCALE))))
return hRet;
}
if ((pRTCSpring->m_YKConstant) != pMidiRTCSpring->YKConstantOf())
{
if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX1, DnloadID,
(SHORT) (pRTCSpring->m_YKConstant * MAX_SCALE))))
return hRet;
}
if ((pRTCSpring->m_XAxisCenter) != pMidiRTCSpring->XAxisCenterOf())
{
if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX2, DnloadID,
(SHORT) (pRTCSpring->m_XAxisCenter * MAX_SCALE))))
return hRet;
}
if ((pRTCSpring->m_YAxisCenter) != pMidiRTCSpring->YAxisCenterOf())
{
if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX3, DnloadID,
(SHORT) (pRTCSpring->m_YAxisCenter * MAX_SCALE))))
return hRet;
}
if ((pRTCSpring->m_XSaturation) != pMidiRTCSpring->XSaturationOf())
{
if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX4, DnloadID,
(SHORT) (pRTCSpring->m_XSaturation * MAX_SCALE))))
return hRet;
}
if ((pRTCSpring->m_YSaturation) != pMidiRTCSpring->YSaturationOf())
{
if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX5, DnloadID,
(SHORT) (pRTCSpring->m_YSaturation * MAX_SCALE))))
return hRet;
}
if ((pRTCSpring->m_XDeadBand) != pMidiRTCSpring->XDeadBandOf())
{
if (SUCCESS != (hRet=CMD_ModifyParamByIndex(INDEX6, DnloadID,
(SHORT) (pRTCSpring->m_XDeadBand * MAX_SCALE))))
return hRet;
}
if ((pRTCSpring->m_YDeadBand) != pMidiRTCSpring->YDeadBandOf())
{
hRet=CMD_ModifyParamByIndex(INDEX7, DnloadID,
(SHORT) (pRTCSpring->m_YDeadBand * MAX_SCALE));
}
pMidiRTCSpring->SetEffectParams(pRTCSpring);
return (hRet);
}
/****************************************************************************
FUNCTION: CMD_Dnload_NOP_DELAY
PARAMETERS: ULONG ulDuration - Duration delay
RETURNS: SUCCESS or ERROR code
COMMENTS: Downloads NOP_DELAY Effect params to the device
Uses SysEx prototype
****************************************************************************/
HRESULT CMD_Download_NOP_DELAY(
IN ULONG ulDuration,
IN PEFFECT pEffect,
IN OUT PDNHANDLE pDnloadID)
{
HRESULT hRet = SUCCESS;
PNOP_SYS_EX lpData;
CMidiDelay *pMidiDelay;
BOOL fCreateNew = FALSE;
assert(pDnloadID);
assert(0 != ulDuration);
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// If Create New, then create a new object,
// else, update the existing Effect object.
if (NULL == *pDnloadID) fCreateNew = TRUE;
if (fCreateNew) // New, Make a new object
{
pMidiDelay = new CMidiDelay(pEffect);
assert(pMidiDelay);
if (NULL == pMidiDelay) return (SFERR_INVALID_OBJECT);
pMidiDelay->SetEffectID(NEW_EFFECT_ID);
}
else // Modify existing
{
pMidiDelay = (CMidiDelay *) g_pJoltMidi->GetEffectByID(*pDnloadID);
assert(pMidiDelay);
if (NULL == pMidiDelay) return (SFERR_INVALID_OBJECT);
pMidiDelay->SetEffectID((BYTE) *pDnloadID);
}
pMidiDelay->SetDuration(ulDuration);
// Generate Sys_Ex packet then prepare for output
lpData = (PNOP_SYS_EX) pMidiDelay->GenerateSysExPacket();
assert(lpData);
if (!lpData) return (SFERR_DRIVER_ERROR);
pMidiDelay->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
hRet = pMidiDelay->SendPacket(pDnloadID, sizeof(NOP_SYS_EX));
if (FAILED(hRet) && fCreateNew) // Create NEW, Failure
{
delete pMidiDelay;
}
return (hRet);
}
/****************************************************************************
FUNCTION: CMD_Dnload_UD_Waveform
PARAMETERS: ULONG ulDuration - what fun!
PEFFECT pEffect - Ptr to an EFFECT structure
ULONG ulNumVectors- Number of vectors in the array
PLONG pUD_Array - Ptr to a UD_WAVEFORM byte array
ULONG ulAction - Mode for download
PDNHANDLE pDnloadID - Ptr to a DNHANDLE store
DWORD dwFlags - dwFlags from Kernel
RETURNS: SUCCESS or ERROR code
COMMENTS: Downloads UD_WAVEFORM Effect params to the device
Uses SysEx prototype
****************************************************************************/
HRESULT CMD_Download_UD_Waveform(
IN ULONG ulDuration,
IN PEFFECT pEffect,
IN ULONG ulNumVectors,
IN PLONG pUD_Array,
IN ULONG ulAction,
IN OUT PDNHANDLE pDnloadID,
IN DWORD dwFlags)
{
HRESULT hRet = SUCCESS;
PUD_WAVEFORM_SYS_EX lpData;
CMidiUD_Waveform *pMidiUD_Waveform;
assert(pEffect && pUD_Array);
assert(ulNumVectors > 0);
assert(pDnloadID);
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// If Create New, then create a new object,
// else, update the existing Effect object.
DNHANDLE DnloadID = *pDnloadID;
if (NULL == DnloadID) // New, Make a new object
{
pMidiUD_Waveform = new CMidiUD_Waveform(pEffect, ulNumVectors, pUD_Array);
assert(pMidiUD_Waveform);
if (NULL == pMidiUD_Waveform) return (SFERR_INVALID_OBJECT);
if (0 == pMidiUD_Waveform->MidiBufferSizeOf())
{
delete pMidiUD_Waveform;
return (SFERR_INVALID_PARAM);
}
// Generate Sys_Ex packet then prepare for output
lpData = (PUD_WAVEFORM_SYS_EX) pMidiUD_Waveform->GenerateSysExPacket();
assert(lpData);
if (!lpData) return (SFERR_DRIVER_ERROR);
// Store the PrimaryBuffer ptr to CMidiEffect::m_pBuffer;
pMidiUD_Waveform->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
hRet = pMidiUD_Waveform->SendPacket(pDnloadID, pMidiUD_Waveform->MidiBufferSizeOf());
if (SUCCESS != hRet) // Create NEW, Failure
{
delete pMidiUD_Waveform;
}
}
else // Modify existing
{
pMidiUD_Waveform = (CMidiUD_Waveform *) g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiUD_Waveform);
if (NULL == pMidiUD_Waveform) return (SFERR_INVALID_OBJECT);
// fix the output rate (waveform is compressed)
pEffect->m_ForceOutputRate = pEffect->m_ForceOutputRate*pMidiUD_Waveform->ForceOutRateOf()/pMidiUD_Waveform->OriginalEffectParamOf()->m_ForceOutputRate;
// Modify EFFECT, and ENVELOPE params
hRet = ModifyEffectParams(DnloadID, pEffect, dwFlags);
if (SUCCESS!=hRet) return hRet;
}
return (hRet);
}
/****************************************************************************
FUNCTION: CMD_Dnload_SYNTH
PARAMETERS: PSYNTH pSynth - Ptr to a SYNTH data structure
PDNHANDLE pDnloadID - Ptr to a HANDLE storage
RETURNS: SUCCESS or ERROR code
COMMENTS: Downloads SE_xxx Effect params to the device
Uses SysEx prototype
Algorithm:
The following dwFlags may be sent by the kernel
#define DIEP_ALLPARAMS 0x000000FF - All fields valid
#define DIEP_AXES 0x00000020 - cAxes and rgdwAxes
#define DIEP_DIRECTION 0x00000040 - cAxes and rglDirection
#define DIEP_DURATION 0x00000001 - dwDuration
#define DIEP_ENVELOPE 0x00000080 - lpEnvelope
#define DIEP_GAIN 0x00000004 - dwGain
#define DIEP_NODOWNLOAD 0x80000000 - suppress auto - download
#define DIEP_SAMPLEPERIOD 0x00000002 - dwSamplePeriod
#define DIEP_TRIGGERBUTTON 0x00000008 - dwTriggerButton
#define DIEP_TRIGGERREPEATINTERVAL 0x00000010 - dwTriggerRepeatInterval
#define DIEP_TYPESPECIFICPARAMS 0x00000100 - cbTypeSpecificParams
and lpTypeSpecificParams
Jolt has two options for downloading - Full SysEx or Modify Parameter
Pass the dwFlags to each CMD_xxx function and let the MIDI function
determine whether to use SysEx or Modify Parameter.
****************************************************************************/
HRESULT CMD_Download_SYNTH(
IN PEFFECT pEffect,
IN PENVELOPE pEnvelope,
IN PSE_PARAM pSE_Param,
IN ULONG ulAction,
IN OUT PDNHANDLE pDnloadID,
IN DWORD dwFlags)
{
HRESULT hRet = SUCCESS;
PSE_WAVEFORM_SYS_EX lpData;
CMidiSynthesized *pMidiSynthesized;
BOOL fFreqChanged = FALSE;
BOOL fMaxAmpChanged = FALSE;
BOOL fMinAmpChanged = FALSE;
DNHANDLE DnloadID =*pDnloadID;
assert(pEffect && pEnvelope && pSE_Param && pDnloadID);
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
// If Create New, then create a new object, and use SysEx method
// else, update the existing Effect object. using ModifyParam method
if (NULL == DnloadID) // New, Make a new object
{
pMidiSynthesized = new CMidiSynthesized(pEffect, pEnvelope, pSE_Param);
assert(pMidiSynthesized);
if (NULL == pMidiSynthesized) return (SFERR_DRIVER_ERROR);
// Generate Sys_Ex packet then prepare for output
lpData = (PSE_WAVEFORM_SYS_EX) pMidiSynthesized->GenerateSysExPacket();
assert(lpData);
if (!lpData) return (SFERR_DRIVER_ERROR);
pMidiSynthesized->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
hRet = pMidiSynthesized->SendPacket(pDnloadID, sizeof(SE_WAVEFORM_SYS_EX));
if (SUCCESS != hRet) // Create NEW, Failure
{
delete pMidiSynthesized;
pMidiSynthesized = NULL;
return hRet;
}
// Hack to fix firmware bug #1138 which causes an infinite duration
// effect not to be felt on re-start once the effect has been stopped.
// The hack is to "change" the duration from infinite to infinite
ULONG ulDuration = pMidiSynthesized->DurationOf();
if(ulDuration == 0)
{
hRet = CMD_ModifyParamByIndex(INDEX0, *pDnloadID, 0);
}
return (hRet);
}
else // Modify existing
{
pMidiSynthesized = (CMidiSynthesized *) g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiSynthesized);
if (NULL == pMidiSynthesized) return (SFERR_INVALID_OBJECT);
// check to see if they are trying to change sub-type (not allowed)
if((dwFlags & DIEP_TYPESPECIFICPARAMS) && pEffect->m_SubType != pMidiSynthesized->SubTypeOf())
return SFERR_NO_SUPPORT;
if(dwFlags & DIEP_NODOWNLOAD)
return DI_DOWNLOADSKIPPED;
// Check if Type specific params have changed.
if (pSE_Param->m_Freq != pMidiSynthesized->FreqOf())
fFreqChanged=TRUE;
if ((pSE_Param->m_MaxAmp) != pMidiSynthesized->MaxAmpOf())
fMaxAmpChanged=TRUE;
if ((pSE_Param->m_MinAmp) != pMidiSynthesized->MinAmpOf())
fMinAmpChanged=TRUE;
// Fill in the common Effect and Synth specific parameters
pMidiSynthesized->SetEffectParams(pEffect, pSE_Param, ulAction);
// // Fill in the Envelope
// pMidiSynthesized->SetEnvelope(pEnvelope);
// Modify EFFECT, ENVELOPE and Type Specific
hRet = ModifyEffectParams(DnloadID, pEffect, dwFlags);
if (SUCCESS!=hRet) return hRet;
hRet = ModifyEnvelopeParams(pMidiSynthesized, DnloadID, pEffect->m_Duration, pEnvelope, dwFlags);
if (SUCCESS!=hRet) return hRet;
// Fill in the Envelope
pMidiSynthesized->SetEnvelope(pEnvelope);
// Type Specific Params
if (dwFlags & DIEP_TYPESPECIFICPARAMS)
{
if(fFreqChanged)
{
hRet = CMD_ModifyParamByIndex(INDEX12, DnloadID, (SHORT) pSE_Param->m_Freq);
if (SUCCESS!=hRet) return hRet;
}
if (fMaxAmpChanged)
{
hRet = CMD_ModifyParamByIndex(INDEX13, DnloadID, (SHORT) (pSE_Param->m_MaxAmp * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
if (fMinAmpChanged)
{
hRet = CMD_ModifyParamByIndex(INDEX14, DnloadID, (SHORT) (pSE_Param->m_MinAmp * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
}
}
return (hRet);
}
/****************************************************************************
FUNCTION: CMD_Download_VFX
PARAMETERS: PSYNTH pSynth - Ptr to a SYNTH data structure
PDNHANDLE pDnloadID - Ptr to a HANDLE storage
RETURNS: SUCCESS or ERROR code
COMMENTS: Downloads SE_xxx Effect params to the device
Uses SysEx prototype
Algorithm:
The following dwFlags may be sent by the kernel
#define DIEP_ALLPARAMS 0x000000FF - All fields valid
#define DIEP_DIRECTION 0x00000040 - cAxes and rglDirection
#define DIEP_GAIN 0x00000004 - dwGain
#define DIEP_NODOWNLOAD 0x80000000 - suppress auto - download
#define DIEP_TRIGGERBUTTON 0x00000008 - dwTriggerButton
#define DIEP_TRIGGERREPEATINTERVAL 0x00000010 - dwTriggerRepeatInterval
#define DIEP_TYPESPECIFICPARAMS 0x00000100 - cbTypeSpecificParams
and lpTypeSpecificParams
Jolt has two options for downloading - Full SysEx or Modify Parameter
Pass the dwFlags to each CMD_xxx function and let the MIDI function
determine whether to use SysEx or Modify Parameter.
****************************************************************************/
HRESULT CMD_Download_VFX(
IN PEFFECT pEffect,
IN PENVELOPE pEnvelope,
IN PVFX_PARAM pVFXParam,
IN ULONG ulAction,
IN OUT PDNHANDLE pDnloadID,
IN DWORD dwFlags)
{
HRESULT hRet = SUCCESS;
DNHANDLE DnloadID = *pDnloadID;
assert(pEffect && !pEnvelope && pVFXParam);
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
BOOL bModify = DnloadID != 0;
if(*pDnloadID == 0)
{
// make a new object
if(pVFXParam->m_PointerType == VFX_FILENAME)
hRet = CreateEffectFromFile((LPCTSTR)pVFXParam->m_pFileNameOrBuffer, ulAction, (USHORT*)pDnloadID, dwFlags);
else if(pVFXParam->m_PointerType == VFX_BUFFER)
hRet = CreateEffectFromBuffer(pVFXParam->m_pFileNameOrBuffer, pVFXParam->m_BufferSize, ulAction, (USHORT*)pDnloadID, dwFlags);
else
hRet = SFERR_INVALID_PARAM;
if(FAILED(hRet)) return hRet;
DnloadID = *pDnloadID;
}
// modify an existing object or the effect just created
// get the effect associated with this ID
CMidiEffect* pMidiEffect = g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiEffect);
if (NULL == pMidiEffect) return (SFERR_INVALID_OBJECT);
// change the button play mask only on a modify
if (bModify && (dwFlags & DIEP_TRIGGERBUTTON))
{
// get the button play mask
ULONG ulButtonPlayMask = pEffect->m_ButtonPlayMask;
// modify the param in the CMidiEffect
pMidiEffect->SetButtonPlaymask(ulButtonPlayMask);
// modify the param in the stick
hRet = CMD_ModifyParamByIndex(INDEX1, DnloadID, (SHORT)ulButtonPlayMask);
if (SUCCESS!=hRet) return hRet;
}
// see if it is a PL or an atomic effect
ULONG ulSubType = pMidiEffect->SubTypeOf();
BOOL bProcessList = (ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE);
// modify gain and direction
if(bProcessList)
{
// modify gain and direction for each sub-effect
// convert the pointer to CMidiProcessList
CMidiProcessList* pMidiProcessList = (CMidiProcessList*)pMidiEffect;
// get the number of sub-effects and the array
UINT ulNumEffects = pMidiProcessList->NumEffectsOf();
PBYTE pEffectArray = pMidiProcessList->EffectArrayOf();
assert(pEffectArray);
if(pEffectArray == NULL) return (SFERR_INVALID_OBJECT);
// calculate the nominal duration of the process list
ULONG ulNominalDuration = 0;
for(UINT i=0; i<ulNumEffects; i++)
{
// get the download ID of the next sub-effect
DNHANDLE SubDnloadID = pEffectArray[i];
// get the sub-effect
CMidiEffect* pMidiSubEffect = g_pJoltMidi->GetEffectByID(SubDnloadID);
assert(pMidiSubEffect);
if (NULL == pMidiSubEffect) return (SFERR_INVALID_OBJECT);
// get the original effect param
PEFFECT pOriginalEffectParam = pMidiSubEffect->OriginalEffectParamOf();
// get the original duration of this sub-effect
ULONG ulSubEffectDuration = pOriginalEffectParam->m_Duration;
//ASSERT(ulSubEffectDuration != 0);
// update the nominal duration of the overall effect to reflect this sub-effect
if(ulSubType == PL_CONCATENATE)
ulNominalDuration += ulSubEffectDuration;
else
ulNominalDuration = max(ulNominalDuration, ulSubEffectDuration);
}
// iterate throught the list of sub-effects
for(i=0; i<ulNumEffects; i++)
{
// get the download ID of the next sub-effect
DNHANDLE SubDnloadID = pEffectArray[i];
// get the sub-effect
CMidiEffect* pMidiSubEffect = g_pJoltMidi->GetEffectByID(SubDnloadID);
assert(pMidiSubEffect);
if (NULL == pMidiSubEffect) return (SFERR_INVALID_OBJECT);
// get the original effect param
PEFFECT pOriginalEffectParam = pMidiSubEffect->OriginalEffectParamOf();
// Direction? Note: No Direction modify for Behaviorals!!!!
if ((dwFlags & DIEP_DIRECTION) && (EF_BEHAVIOR != pOriginalEffectParam->m_Type))
{
// calculate the new angle
ULONG nOriginalAngle2D = pOriginalEffectParam->m_DirectionAngle2D;
ULONG nDeltaAngle2D = pEffect->m_DirectionAngle2D;
ULONG nNewAngle2D = (nOriginalAngle2D + nDeltaAngle2D)%360;
// modify the param in the midi sub-effect
pMidiSubEffect->SetDirectionAngle(nNewAngle2D);
// modify the parameter in the stick
hRet = CMD_ModifyParamByIndex(INDEX2, SubDnloadID, (SHORT)nNewAngle2D);
if (SUCCESS!=hRet) return hRet;
}
// Gain?
// Gain? Note: No Gain modify for Behaviorals!!!!
if ((dwFlags & DIEP_GAIN) && (EF_BEHAVIOR != pOriginalEffectParam->m_Type))
{
// calculate the new gain
ULONG nOriginalGain = pOriginalEffectParam->m_Gain;
ULONG nOverallGain = pEffect->m_Gain;
ULONG nNewGain = nOverallGain*nOriginalGain/100;
// modify the param in the midi effect
pMidiSubEffect->SetGain((BYTE)nNewGain);
// modify the parameter in the stick
hRet = CMD_ModifyParamByIndex(INDEX3, SubDnloadID, (SHORT) (nNewGain * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
if(dwFlags & DIEP_DURATION)
{
// calculate the new duration
ULONG nOriginalDuration = pOriginalEffectParam->m_Duration;
ULONG nOverallDuration = pEffect->m_Duration;
ULONG nNewDuration;
if(nOverallDuration == (ULONG)-1)
{
// default length
nNewDuration = nOriginalDuration;
}
else if(nOverallDuration == 0)
{
// infinite duration
// for a concatenated process list we make the last effect infinite, others default
// for a superimpose process list we make all effects infinite
if(ulSubType == PL_CONCATENATE)
{
if(i == ulNumEffects-1)
{
// make last effect in PL infinite
nNewDuration = 0;
}
else
{
// make other effects default
nNewDuration = nOriginalDuration;
}
}
else
{
assert(ulSubType == PL_SUPERIMPOSE);
// make effects infinite
nNewDuration = 0;
}
}
else
{
// scale the duration (at least 1mS)
nNewDuration = nOriginalDuration*nOverallDuration/ulNominalDuration;
nNewDuration = max(1, nNewDuration);
}
// modify the parameter in the midi sub-effect
pMidiSubEffect->SetDuration(nNewDuration);
// modify the parameter in the stick
if (nNewDuration != 0)
{
nNewDuration = (ULONG) ( (float) nNewDuration/TICKRATE);
if (nNewDuration <= 0)
nNewDuration = 1;
}
hRet = CMD_ModifyParamByIndex(INDEX0, SubDnloadID, (SHORT) nNewDuration);
if (SUCCESS!=hRet) return hRet;
}
}
}
else
{
// modify gain and direction for the atomic effect
// get the original effect param
PEFFECT pOriginalEffectParam = pMidiEffect->OriginalEffectParamOf();
// Direction? Note: No Direction modify for Behaviorals!!!!
if ((dwFlags & DIEP_DIRECTION) && (EF_BEHAVIOR != pOriginalEffectParam->m_Type))
{
// calculate the new angle
ULONG nOriginalAngle2D = pOriginalEffectParam->m_DirectionAngle2D;
ULONG nDeltaAngle2D = pEffect->m_DirectionAngle2D;
ULONG nNewAngle2D = (nOriginalAngle2D + nDeltaAngle2D)%360;
// modify the param in the midi effect
pMidiEffect->SetDirectionAngle(nNewAngle2D);
// modify the parameter in the stick
hRet = CMD_ModifyParamByIndex(INDEX2, DnloadID, (SHORT)nNewAngle2D);
if (SUCCESS!=hRet) return hRet;
}
// Gain?
// Gain? Note: No Gain modify for Behaviorals!!!!
if ((dwFlags & DIEP_GAIN) && (EF_BEHAVIOR != pOriginalEffectParam->m_Type))
{
// calculate the new gain
ULONG nOriginalGain = pOriginalEffectParam->m_Gain;
ULONG nOverallGain = pEffect->m_Gain;
ULONG nNewGain = nOverallGain*nOriginalGain/100;
// modify the param in the midi effect
pMidiEffect->SetGain((BYTE)nNewGain);
// modify the parameter in the stick
hRet = CMD_ModifyParamByIndex(INDEX3, DnloadID, (SHORT) (nNewGain * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
if(dwFlags & DIEP_DURATION)
{
// calculate the new duration
ULONG nOriginalDuration = pOriginalEffectParam->m_Duration;
ULONG nOverallDuration = pEffect->m_Duration;
ULONG nNewDuration;
if(nOverallDuration == (ULONG)-1)
{
// default length
nNewDuration = nOriginalDuration;
}
else if(nOverallDuration == 0)
{
// infinite duration -- make effect infinite
nNewDuration = 0;
}
else
{
// scale the duration (at least 1mS)
nNewDuration = nOverallDuration;
}
// modify the parameter in the midi effect
pMidiEffect->SetDuration(nNewDuration);
// modify the parameter in the stick
if (nNewDuration != 0)
{
nNewDuration = (ULONG) ( (float) nNewDuration/TICKRATE);
if (nNewDuration <= 0)
nNewDuration = 1;
}
hRet = CMD_ModifyParamByIndex(INDEX0, DnloadID, (SHORT) nNewDuration);
if (SUCCESS!=hRet) return hRet;
}
}
return hRet;
}
//
// --- System Exclusive Command:PROCESS_DATA
//
// *** ---------------------------------------------------------------------***
// Function: CMD_ProcessEffect
// Purpose: Processes the List
// IN ULONG ulButtonPlayMask
// IN OUT PDNHANDLE pDnloadID - Storage for new Download ID
// IN int nNumEffects - Number of Effect IDs in the array
// IN ULONG ulProcessMode - Processing mode
// IN PDNHANDLE pPListArray - Pointer to an array of Effect IDs
//
// Returns: SUCCESS - if successful, else
// E_INVALID_PARAM
// SFERR_NO_SUPPORT
//
// Algorithm:
//
// Comments:
// The following processing is available:
// CONCATENATE: Enew = E1 followed by E2
// SUPERIMPOSE: Enew = E1 (t1) + E2 (t1) + E1 (t2)
// + E2 (t2) + . . . E1 (tn) + E2 (tn)
//
// ulProcessMode:
// Processing mode:
// CONCATENATE - CONCATENATE
// SUPERIMPOSE - Mix or overlay
//
// pPListArray:
// The array of Effect IDs must be one more than the actual number
// of Effect IDs to use.
//
// Byte 0 = MIDI_CMD_EFFECT + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = Low byte of Force 0
// Byte 2 = High byte of Force 0
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_ProcessEffect(
IN ULONG ulButtonPlayMask,
IN OUT PDNHANDLE pDnloadID,
IN int nNumEffects,
IN ULONG ulProcessMode,
IN PDNHANDLE pPListArray,
IN ULONG ulAction)
{
HRESULT hRet = SUCCESS;
PPROCESS_LIST_SYS_EX lpData;
CMidiProcessList *pMidiProcessList;
assert(pDnloadID && pPListArray);
if ((NULL == pDnloadID) || (NULL == pPListArray))
return (SFERR_INVALID_PARAM);
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
DNHANDLE DnloadID = *pDnloadID;
// If Create New, then create a new object,
// else, update the existing Effect object.
// Build the special Parameter
PLIST PList;
PList.ulNumEffects = (ULONG) nNumEffects;
PList.ulProcessMode = ulProcessMode;
PList.pEffectArray = pPListArray;
PList.ulAction = ulAction;
if (NULL == DnloadID) // New, Make a new object
{
// make sure we are not trying to create a PL within a PL
for(int i=0; i<nNumEffects; i++)
{
// get the next sub-effect
int nID = pPListArray[i];
CMidiEffect* pMidiEffect = g_pJoltMidi->GetEffectByID(DNHANDLE(nID));
if(pMidiEffect == NULL)
return SFERR_INVALID_PARAM;
// make sure it is not a process list
ULONG ulSubType = pMidiEffect->SubTypeOf();
if(ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE)
return SFERR_INVALID_PARAM;
}
// create the CMidiProcessList object
pMidiProcessList = new CMidiProcessList(ulButtonPlayMask, &PList);
assert(pMidiProcessList);
pMidiProcessList->SetEffectID(NEW_EFFECT_ID);
pMidiProcessList->SetSubType(ulProcessMode);
}
else // Modify existing
{
pMidiProcessList = (CMidiProcessList *) g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiProcessList);
if (NULL == pMidiProcessList) return (SFERR_INVALID_OBJECT);
pMidiProcessList->SetEffectID((BYTE) DnloadID);
}
// Fill in the parameters
pMidiProcessList->SetParams(ulButtonPlayMask, &PList);
if (PLAY_FOREVER == (ulAction & PLAY_FOREVER))
pMidiProcessList->SetDuration(0);
// Generate Sys_Ex packet then prepare for output
lpData = (PPROCESS_LIST_SYS_EX) pMidiProcessList->GenerateSysExPacket();
assert(lpData);
if (!lpData) return (SFERR_DRIVER_ERROR);
int nSizeBuf = sizeof(SYS_EX_HDR) + 5 + nNumEffects + 2;
pMidiProcessList->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
hRet = pMidiProcessList->SendPacket(pDnloadID, nSizeBuf);
if (SUCCESS != hRet) // Create NEW, Failure
{
delete pMidiProcessList;
}
else
{
// workaround to FW bug #1211, modify PL type with same PL type
ULONG ulSubType;
if (PL_SUPERIMPOSE == ulProcessMode)
ulSubType = PLIST_SUPERIMPOSE;
else
ulSubType = PLIST_CONCATENATE;
hRet = CMD_ModifyParamByIndex(INDEX0, *pDnloadID, (SHORT) ulSubType);
}
return (hRet);
}
//
// --- System Exclusive Command:PROCESS_DATA
//
// *** ---------------------------------------------------------------------***
// Function: CMD_VFXProcessEffect
// Purpose: Processes the List
// IN ULONG ulButtonPlayMask
// IN OUT PDNHANDLE pDnloadID - Storage for new Download ID
// IN int nNumEffects - Number of Effect IDs in the array
// IN ULONG ulProcessMode - Processing mode
// IN PDNHANDLE pPListArray - Pointer to an array of Effect IDs
//
// Returns: SUCCESS - if successful, else
// E_INVALID_PARAM
// SFERR_NO_SUPPORT
//
// Algorithm:
//
// Comments:
// The following processing is available:
// CONCATENATE: Enew = E1 followed by E2
// SUPERIMPOSE: Enew = E1 (t1) + E2 (t1) + E1 (t2)
// + E2 (t2) + . . . E1 (tn) + E2 (tn)
//
// ulProcessMode:
// Processing mode:
// CONCATENATE - CONCATENATE
// SUPERIMPOSE - Mix or overlay
//
// pPListArray:
// The array of Effect IDs must be one more than the actual number
// of Effect IDs to use.
//
// Byte 0 = MIDI_CMD_EFFECT + Channel #
// D7 D6 D5 D4 D3 D2 D1 D0
// -- -- -- -- -- -- -- --
// Byte 1 = Low byte of Force 0
// Byte 2 = High byte of Force 0
//
// *** ---------------------------------------------------------------------***
HRESULT CMD_VFXProcessEffect(
IN ULONG ulButtonPlayMask,
IN OUT PDNHANDLE pDnloadID,
IN int nNumEffects,
IN ULONG ulProcessMode,
IN PDNHANDLE pPListArray,
IN ULONG ulAction)
{
HRESULT hRet = SUCCESS;
PPROCESS_LIST_SYS_EX lpData;
CMidiVFXProcessList *pMidiProcessList;
assert(pDnloadID && pPListArray);
if ((NULL == pDnloadID) || (NULL == pPListArray))
return (SFERR_INVALID_PARAM);
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
DNHANDLE DnloadID = *pDnloadID;
// If Create New, then create a new object,
// else, update the existing Effect object.
// Build the special Parameter
PLIST PList;
PList.ulNumEffects = (ULONG) nNumEffects;
PList.ulProcessMode = ulProcessMode;
PList.pEffectArray = pPListArray;
PList.ulAction = ulAction;
if (NULL == DnloadID) // New, Make a new object
{
// make sure we are not trying to create a PL within a PL
for(int i=0; i<nNumEffects; i++)
{
// get the next sub-effect
int nID = pPListArray[i];
CMidiEffect* pMidiEffect = g_pJoltMidi->GetEffectByID(DNHANDLE(nID));
if(pMidiEffect == NULL)
return SFERR_INVALID_PARAM;
// make sure it is not a process list
ULONG ulSubType = pMidiEffect->SubTypeOf();
if(ulSubType == PL_CONCATENATE || ulSubType == PL_SUPERIMPOSE)
return SFERR_INVALID_PARAM;
}
pMidiProcessList = new CMidiVFXProcessList(ulButtonPlayMask, &PList);
assert(pMidiProcessList);
if (!pMidiProcessList) return (SFERR_DRIVER_ERROR);
pMidiProcessList->SetEffectID(NEW_EFFECT_ID);
pMidiProcessList->SetSubType(ulProcessMode);
}
else // Modify existing
{
pMidiProcessList = (CMidiVFXProcessList *) g_pJoltMidi->GetEffectByID(DnloadID);
assert(pMidiProcessList);
if (NULL == pMidiProcessList) return (SFERR_INVALID_OBJECT);
pMidiProcessList->SetEffectID((BYTE) DnloadID);
}
// Fill in the parameters
pMidiProcessList->SetParams(ulButtonPlayMask, &PList);
if (PLAY_FOREVER == (ulAction & PLAY_FOREVER))
pMidiProcessList->SetDuration(0);
// Generate Sys_Ex packet then prepare for output
lpData = (PPROCESS_LIST_SYS_EX) pMidiProcessList->GenerateSysExPacket();
assert(lpData);
if (!lpData) return (SFERR_DRIVER_ERROR);
int nSizeBuf = sizeof(SYS_EX_HDR) + 5 + nNumEffects + 2;
pMidiProcessList->SetMidiBufferPtr((LPSTR) g_pJoltMidi->PrimaryBufferPtrOf());
hRet = pMidiProcessList->SendPacket(pDnloadID, nSizeBuf);
if (SUCCESS != hRet) // Create NEW, Failure
{
delete pMidiProcessList;
}
else
{
// workaround to FW bug #1211, modify PL type with same PL type
ULONG ulSubType;
if (PL_SUPERIMPOSE == ulProcessMode)
ulSubType = PLIST_SUPERIMPOSE;
else
ulSubType = PLIST_CONCATENATE;
hRet = CMD_ModifyParamByIndex(INDEX0, *pDnloadID, (SHORT) ulSubType);
}
return (hRet);
}
/****************************************************************************
FUNCTION: ModifyEffectParams
PARAMETERS: DNHANDLE DnloadID - Download ID
PEFFECT pEffect - Ptr to EFFECT structure
DWORD dwFlags - Flags indicating which changed
RETURNS: SUCCESS or ERROR code
COMMENTS: Modifies EFFECT parameters
Algorithm:
****************************************************************************/
HRESULT ModifyEffectParams(
IN DNHANDLE DnloadID,
IN PEFFECT pEffect,
IN DWORD dwFlags)
{
HRESULT hRet = SUCCESS;
// Check dwFlags for each parameter that changed.
// Duration?
ULONG ulDuration = pEffect->m_Duration;
if (dwFlags & DIEP_DURATION)
{
if (ulDuration != 0)
{
ulDuration = (ULONG) ( (float) ulDuration/TICKRATE);
if (ulDuration <= 0)
ulDuration = 1;
}
hRet = CMD_ModifyParamByIndex(INDEX0, DnloadID, (SHORT) ulDuration);
if (SUCCESS!=hRet) return hRet;
}
// ButtonPlayback?
if (dwFlags & DIEP_TRIGGERBUTTON)
{
hRet = CMD_ModifyParamByIndex(INDEX1, DnloadID, (SHORT) pEffect->m_ButtonPlayMask);
if (SUCCESS!=hRet) return hRet;
}
// Direction?
if (dwFlags & DIEP_DIRECTION)
{
hRet = CMD_ModifyParamByIndex(INDEX2, DnloadID, (SHORT) pEffect->m_DirectionAngle2D);
if (SUCCESS!=hRet) return hRet;
}
// Gain?
if (dwFlags & DIEP_GAIN)
{
hRet = CMD_ModifyParamByIndex(INDEX3, DnloadID, (SHORT) (pEffect->m_Gain * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
// Force Output Rate
if (dwFlags & DIEP_SAMPLEPERIOD )
{
hRet = CMD_ModifyParamByIndex(INDEX4, DnloadID, (SHORT) (pEffect->m_ForceOutputRate));
if (SUCCESS!=hRet) return hRet;
}
return (hRet);
}
/****************************************************************************
FUNCTION: ModifyEnvelopeParams
PARAMETERS: CMidiSynthesized * pMidiEffect - Ptr to Effect object
DNHANDLE DnloadID - Download ID
PENVELOPE pEnvelope - Ptr to ENVELOPE structure
DWORD dwFlags - Flags indicating which changed
RETURNS: SUCCESS or ERROR code
COMMENTS: Modifies ENVELOPE parameters
Algorithm:
****************************************************************************/
HRESULT ModifyEnvelopeParams(
IN CMidiSynthesized *pMidiEffect,
IN DNHANDLE DnloadID,
IN ULONG ulDuration,
IN PENVELOPE pEnvelope,
IN DWORD dwFlags)
{
HRESULT hRet=SUCCESS;
ULONG ulTimeToSustain;
ULONG ulTimeToDecay;
// Envelope?
if (dwFlags & DIEP_ENVELOPE)
{
if (PERCENTAGE == pEnvelope->m_Type)
{
ulTimeToSustain = (ULONG) ((pEnvelope->m_Attack * ulDuration) /100.);
ulTimeToDecay = (ULONG) ((pEnvelope->m_Attack + pEnvelope->m_Sustain)
* ulDuration /100.);
}
else // TIME option envelope
{
ulTimeToSustain = (ULONG) (pEnvelope->m_Attack);
ulTimeToDecay = (ULONG) (pEnvelope->m_Attack + pEnvelope->m_Sustain);
}
ulTimeToSustain = (ULONG) ( (float) ulTimeToSustain/TICKRATE);
ulTimeToDecay = (ULONG) ( (float) ulTimeToDecay/TICKRATE);
// REVIEW: Do a parameters changed check in order to speed this up - TOO MANY BYTES!!!
if (pEnvelope->m_Attack != (pMidiEffect->EnvelopePtrOf())->m_Attack)
{
hRet = CMD_ModifyParamByIndex(INDEX7, DnloadID, (SHORT) ulTimeToSustain);
if (SUCCESS!=hRet) return hRet;
}
if ( (pEnvelope->m_Attack != (pMidiEffect->EnvelopePtrOf())->m_Attack)
|| (pEnvelope->m_Sustain != (pMidiEffect->EnvelopePtrOf())->m_Sustain) )
{
hRet = CMD_ModifyParamByIndex(INDEX8, DnloadID, (SHORT) ulTimeToDecay);
if (SUCCESS!=hRet) return hRet;
}
if (pEnvelope->m_StartAmp != (pMidiEffect->EnvelopePtrOf())->m_StartAmp)
{
hRet = CMD_ModifyParamByIndex(INDEX9, DnloadID, (SHORT) (pEnvelope->m_StartAmp * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
if (pEnvelope->m_SustainAmp != (pMidiEffect->EnvelopePtrOf())->m_SustainAmp)
{
hRet = CMD_ModifyParamByIndex(INDEX10, DnloadID, (SHORT) (pEnvelope->m_SustainAmp * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
if (pEnvelope->m_EndAmp != (pMidiEffect->EnvelopePtrOf())->m_EndAmp)
{
hRet = CMD_ModifyParamByIndex(INDEX11, DnloadID, (SHORT) (pEnvelope->m_EndAmp * MAX_SCALE));
if (SUCCESS!=hRet) return hRet;
}
}
return (hRet);
}
/****************************************************************************
FUNCTION: MapEnvelope
PARAMETERS: ULONG ulDuration - Total Duration
ULONG dwMagnitude
ULONG * pMaxLevel
LPDIENVELOPE pIDEnvelope- Ptr to DIENVELOPE structure
PENVELOPE pEnvelope - SWForce ENVELOPE
RETURNS: none
COMMENTS: Maps DIENVELOPE to ENVELOPE
Algorithm:
****************************************************************************/
void MapEnvelope(
IN ULONG ulDuration,
IN ULONG dwMagnitude,
IN ULONG * pMaxLevel,
IN LPDIENVELOPE pDIEnvelope,
IN OUT PENVELOPE pEnvelope)
{
ULONG ulMaxLevel = *pMaxLevel;
if (pDIEnvelope)
{
// if there is an envelope, MaxLevel must look at attack/fade
ulMaxLevel = max(ulMaxLevel, pDIEnvelope->dwAttackLevel);
ulMaxLevel = max(ulMaxLevel, pDIEnvelope->dwFadeLevel);
pEnvelope->m_Type = TIME;
// find attack/sustain/decay which sum to ulDuration
pEnvelope->m_Attack = pDIEnvelope->dwAttackTime/SCALE_TIME;
pEnvelope->m_Decay = pDIEnvelope->dwFadeTime/SCALE_TIME;
// REVIEW: is this correct for ulDuration == 0?
if(ulDuration != 0)
pEnvelope->m_Sustain = ulDuration - pEnvelope->m_Attack - pEnvelope->m_Decay;
else
pEnvelope->m_Sustain = 0;
// convert to StartAmp/SustainAmp/EndAmp, which is a % of the magnitude
if(ulMaxLevel != 0)
{
pEnvelope->m_StartAmp = pDIEnvelope->dwAttackLevel*100/ulMaxLevel;
pEnvelope->m_SustainAmp = dwMagnitude*100/ulMaxLevel;
pEnvelope->m_EndAmp = pDIEnvelope->dwFadeLevel*100/ulMaxLevel;
}
else
{
pEnvelope->m_StartAmp = pDIEnvelope->dwAttackLevel;
pEnvelope->m_SustainAmp = 100;
pEnvelope->m_EndAmp = pDIEnvelope->dwFadeLevel;
}
}
else // No Envelope
{
pEnvelope->m_Type = TIME;
pEnvelope->m_Attack = 0;
pEnvelope->m_Sustain = ulDuration;
pEnvelope->m_Decay = 0;
pEnvelope->m_StartAmp = 0;
pEnvelope->m_SustainAmp = 100;
pEnvelope->m_EndAmp = 0;
}
*pMaxLevel = ulMaxLevel;
}