HRESULT CMackieControlXT::GetStatusText( LPSTR pszStatus, DWORD* pdwLen )
{
	if (NULL == pdwLen)
		return E_POINTER;

	CCriticalSectionAuto csa1(&m_cs);

	CString strStatus;

	if (0x00 == m_bDeviceType)
	{
		strStatus = "Connecting...";
	}
	else
	{
		strStatus = "Mackie Control XT OK";
	}

	// Return results to caller
	if (NULL == pszStatus)
	{
		*pdwLen = DWORD(strStatus.GetLength() + 1);
	}
	else
	{
		TCHAR2Char(pszStatus, strStatus, *pdwLen);
	}

	return S_OK;
}
HRESULT CMackieControlMaster::Save( IStream* pStm, BOOL bClearDirty )
{
	TRACE("CMackieControlMaster::Save()\n");

	CCriticalSectionAuto csa1(&m_cs);
	CCriticalSectionAuto csa2(m_cState.GetCS());

	// Version information
	DWORD dwVer = PERSISTENCE_VERSION;
	if (FAILED(SafeWrite(pStm, &dwVer, sizeof(dwVer))))
	{
		TRACE("CMackieControlMaster::Save(): dwVer failed\n");
		return E_FAIL;
	}

	int n = 0;

	// Function key bindings
	for (n = 0; n < NUM_USER_FUNCTION_KEYS; n++)
	{
		DWORD dwCmdId = m_cState.GetUserFunctionKey(n);

		if (FAILED(SafeWrite(pStm, &dwCmdId, sizeof(dwCmdId))))
		{
			TRACE("CMackieControlMaster::Save(): key dwCmdId %d failed\n", n);
			return E_FAIL;
		}
	}

	// Foot switch bindings
	for (n = 0; n < NUM_USER_FOOT_SWITCHES; n++)
	{
		DWORD dwCmdId = m_cState.GetUserFootSwitch(n);

		if (FAILED(SafeWrite(pStm, &dwCmdId, sizeof(dwCmdId))))
		{
			TRACE("CMackieControlMaster::Save(): foot dwCmdId %d failed\n", n);
			return E_FAIL;
		}
	}

	// Master fader offset
	DWORD dwOffset = m_cState.GetMasterFaderOffset(m_cState.GetMasterFaderType());
	if (FAILED(SafeWrite(pStm, &dwOffset, sizeof(dwOffset))))
	{
		TRACE("CMackieControlMaster::Save(): master fader offset failed\n");
		return E_FAIL;
	}

	// Jog resolution
	JogResolution eJogResolution = m_cState.GetJogResolution(); 
	if (FAILED(SafeWrite(pStm, &eJogResolution, sizeof(eJogResolution))))
	{
		TRACE("CMackieControlMaster::Save(): m_eJogResolution failed\n");
		return E_FAIL;
	}

	// Transport resolution
	JogResolution eTransportResolution = m_cState.GetTransportResolution(); 
	if (FAILED(SafeWrite(pStm, &eTransportResolution, sizeof(eTransportResolution))))
	{
		TRACE("CMackieControlMaster::Save(): m_eTransportResolution failed\n");
		return E_FAIL;
	}

	// Time display format
	bool bDisplaySMPTE = m_cState.GetDisplaySMPTE();
	if (FAILED(SafeWrite(pStm, &bDisplaySMPTE, sizeof(bDisplaySMPTE))))
	{
		TRACE("CMackieControlMaster::Save(): m_bDisplaySMPTE failed\n");
		return E_FAIL;
	}

	// Disable faders
	bool bDisableFaders = m_cState.GetDisableFaders();
	if (FAILED(SafeWrite(pStm, &bDisableFaders, sizeof(bDisableFaders))))
	{
		TRACE("CMackieControlMaster::Save(): bDisableFaders failed\n");
		return E_FAIL;
	}

	// Disable relay click
	bool bDisableRelayClick = m_cState.GetDisableRelayClick();
	if (FAILED(SafeWrite(pStm, &bDisableRelayClick, sizeof(bDisableRelayClick))))
	{
		TRACE("CMackieControlMaster::Save(): bDisableRelayClick failed\n");
		return E_FAIL;
	}

	// Disable LCD updates
	bool bDisableLCDUpdates = m_cState.GetDisableLCDUpdates();
	if (FAILED(SafeWrite(pStm, &bDisableLCDUpdates, sizeof(bDisableLCDUpdates))))
	{
		TRACE("CMackieControlMaster::Save(): bDisableLCDUpdates failed\n");
		return E_FAIL;
	}

	// Solo selects channel
	bool bSoloSelectsChannel = m_cState.GetSoloSelectsChannel();
	if (FAILED(SafeWrite(pStm, &bSoloSelectsChannel, sizeof(bSoloSelectsChannel))))
	{
		TRACE("CMackieControlMaster::Save(): m_bSoloSelectsChannel failed\n");
		return E_FAIL;
	}

	// Unit information (offsets)
	{
		vectorMackieControlInformation vInfo;

		m_cState.GetUnitOffsets(&vInfo);

		DWORD dwNumUnits = (DWORD)vInfo.size();
		if (FAILED(SafeWrite(pStm, &dwNumUnits, sizeof(dwNumUnits))))
		{
			TRACE("CMackieControlMaster::Save(): vectorMackieControlInformation dwNumUnits failed\n");
			return E_FAIL;
		}

		for (DWORD n = 0; n < dwNumUnits; n++)
		{
			if (!vInfo[n].Save(pStm))
				return E_FAIL;
		}
	}

	// Added in PERSISTENCE_VERSION = 3

	// Fader touch selects channel
	bool bFaderTouchSelectsChannel = m_cState.GetFaderTouchSelectsChannel();
	if (FAILED(SafeWrite(pStm, &bFaderTouchSelectsChannel, sizeof(bFaderTouchSelectsChannel))))
	{
		TRACE("CMackieControlMaster::Save(): bFaderTouchSelectsChannel failed\n");
		return E_FAIL;
	}

	// Select highlights track
	bool bSelectHighlightsTrack = m_cState.GetSelectHighlightsTrack();
	if (FAILED(SafeWrite(pStm, &bSelectHighlightsTrack, sizeof(bSelectHighlightsTrack))))
	{
		TRACE("CMackieControlMaster::Save(): bSelectHighlightsTrack failed\n");
		return E_FAIL;
	}

	// Added in PERSISTENCE_VERSION = 4

	// Master fader type
	SONAR_MIXER_STRIP eMixerStrip = m_cState.GetMasterFaderType();
	if (FAILED(SafeWrite(pStm, &eMixerStrip, sizeof(eMixerStrip))))
	{
		TRACE("CMackieControlMaster::Save(): eMixerStrip failed\n");
		return E_FAIL;
	}

	// Added in PERSISTENCE_VERSION = 5
	LevelMeters eLevelMeters = m_cState.GetDisplayLevelMeters();
	if (FAILED(SafeWrite(pStm, &eLevelMeters, sizeof(eLevelMeters))))
	{
		TRACE("CMackieControlMaster::Save(): eLevelMeters failed\n");
		return E_FAIL;
	}

	if (bClearDirty)
		m_bDirty = FALSE;

	return S_OK;
}
HRESULT CMackieControlMaster::Load( IStream* pStm )
{
	TRACE("CMackieControlMaster::Load()\n");

	CCriticalSectionAuto csa1(&m_cs);
	CCriticalSectionAuto csa2(m_cState.GetCS());

	// Version information
	DWORD dwVer;
	if (FAILED(SafeRead(pStm, &dwVer, sizeof(dwVer))))
	{
		TRACE("CMackieControlMaster::Load(): dwVer failed\n");
		return E_FAIL;
	}

	if (dwVer > PERSISTENCE_VERSION)
	{
		TRACE("CMackieControlMaster::Load(): version mismatch\n");
		return E_FAIL;
	}

	int n = 0; 

	// Function key bindings
	for (n = 0; n < NUM_USER_FUNCTION_KEYS; n++)
	{
		DWORD dwCmdId;

		if (FAILED(SafeRead(pStm, &dwCmdId, sizeof(dwCmdId))))
		{
			TRACE("CMackieControlMaster::Load(): key dwCmdId %d failed\n", n);
			return E_FAIL;
		}

		m_cState.SetUserFunctionKey(n, dwCmdId);
	}

	// Foot switch bindings
	for (n = 0; n < NUM_USER_FOOT_SWITCHES; n++)
	{
		DWORD dwCmdId;

		if (FAILED(SafeRead(pStm, &dwCmdId, sizeof(dwCmdId))))
		{
			TRACE("CMackieControlMaster::Load(): foot dwCmdId %d failed\n", n);
			return E_FAIL;
		}

		m_cState.SetUserFootSwitch(n, dwCmdId);
	}

	// Master fader offset
	DWORD dwMasterFaderOffset;
	if (FAILED(SafeRead(pStm, &dwMasterFaderOffset, sizeof(dwMasterFaderOffset))))
	{
		TRACE("CMackieControlMaster::Load(): master fader offset failed\n");
		return E_FAIL;
	}
	if (dwVer < 4)
		SafeSetMasterFaderOffset(m_cState.GetMasterFaderType(), dwMasterFaderOffset);

	// Jog resolution
	JogResolution eJogResolution;
	if (FAILED(SafeRead(pStm, &eJogResolution, sizeof(eJogResolution))))
	{
		TRACE("CMackieControlMaster::Load(): m_eJogResolution failed\n");
		return E_FAIL;
	}
	m_cState.SetJogResolution(eJogResolution);

	// Transport resolution
	JogResolution eTransportResolution;
	if (FAILED(SafeRead(pStm, &eTransportResolution, sizeof(eTransportResolution))))
	{
		TRACE("CMackieControlMaster::Load(): m_eTransportResolution failed\n");
		return E_FAIL;
	}
	m_cState.SetTransportResolution(eTransportResolution);

	// Time display format
	bool bDisplaySMPTE;
	if (FAILED(SafeRead(pStm, &bDisplaySMPTE, sizeof(bDisplaySMPTE))))
	{
		TRACE("CMackieControlMaster::Load(): m_bDisplaySMPTE failed\n");
		return E_FAIL;
	}
	m_cState.SetDisplaySMPTE(bDisplaySMPTE);

	// Disable faders
	bool bDisableFaders;
	if (FAILED(SafeRead(pStm, &bDisableFaders, sizeof(bDisableFaders))))
	{
		TRACE("CMackieControlMaster::Load(): bDisableFaders failed\n");
		return E_FAIL;
	}
	m_cState.SetDisableFaders(bDisableFaders);

	// Disable relay click
	bool bDisableRelayClick;
	if (FAILED(SafeRead(pStm, &bDisableRelayClick, sizeof(bDisableRelayClick))))
	{
		TRACE("CMackieControlMaster::Load(): bDisableRelayClick failed\n");
		return E_FAIL;
	}
	m_cState.SetDisableRelayClick(bDisableRelayClick);
	SetRelayClick(!bDisableRelayClick);

	// Disable LCD updates
	bool bDisableLCDUpdates;
	if (FAILED(SafeRead(pStm, &bDisableLCDUpdates, sizeof(bDisableLCDUpdates))))
	{
		TRACE("CMackieControlMaster::Load(): bDisableLCDUpdates failed\n");
		return E_FAIL;
	}
	m_cState.SetDisableLCDUpdates(bDisableLCDUpdates);

	// Solo selects channel
	bool bSoloSelectsChannel;
	if (FAILED(SafeRead(pStm, &bSoloSelectsChannel, sizeof(bSoloSelectsChannel))))
	{
		TRACE("CMackieControlMaster::Load(): m_bSoloSelectsChannel failed\n");
		return E_FAIL;
	}
	m_cState.SetSoloSelectsChannel(bSoloSelectsChannel);

	// Unit information (offsets)
	{
		DWORD dwNumUnits;
		if (FAILED(SafeRead(pStm, &dwNumUnits, sizeof(dwNumUnits))))
		{
			TRACE("CMackieControlMaster::Load(): vectorMackieControlInformation dwNumUnits failed\n");
			return E_FAIL;
		}

		vectorMackieControlInformation vInfo;

		for (n = 0; n < (int)dwNumUnits; n++)
		{
			CMackieControlInformation cInfo;

			if (!cInfo.Load(pStm))
				return E_FAIL;

			vInfo.push_back(cInfo);
		}

		m_cState.SetUnitOffsets(&vInfo);
	}

	if (dwVer >= 3)
	{
		// Fader touch selects channel
		bool bFaderTouchSelectsChannel;
		if (FAILED(SafeRead(pStm, &bFaderTouchSelectsChannel, sizeof(bFaderTouchSelectsChannel))))
		{
			TRACE("CMackieControlMaster::Load(): bFaderTouchSelectsChannel failed\n");
			return E_FAIL;
		}
		m_cState.SetFaderTouchSelectsChannel(bFaderTouchSelectsChannel);

		// Select highlights track
		bool bSelectHighlightsTrack;
		if (FAILED(SafeRead(pStm, &bSelectHighlightsTrack, sizeof(bSelectHighlightsTrack))))
		{
			TRACE("CMackieControlMaster::Load(): bSelectHighlightsTrack failed\n");
			return E_FAIL;
		}
		m_cState.SetSelectHighlightsTrack(bSelectHighlightsTrack);
	}

	if (dwVer >= 4)
	{
		// Master fader type
		SONAR_MIXER_STRIP eMixerStrip;
		if (FAILED(SafeRead(pStm, &eMixerStrip, sizeof(eMixerStrip))))
		{
			TRACE("CMackieControlMaster::Load(): eMixerStrip failed\n");
			return E_FAIL;
		}
		m_cState.SetMasterFaderType(eMixerStrip);

		SafeSetMasterFaderOffset(eMixerStrip, dwMasterFaderOffset);
	}

	if (dwVer >= 5)
	{
		// Level meters
		LevelMeters eLevelMeters;
		if (FAILED(SafeRead(pStm, &eLevelMeters, sizeof(eLevelMeters))))
		{
			TRACE("CMackieControlMaster::Load(): eLevelMeters failed\n");
			return E_FAIL;
		}
		m_cState.SetDisplayLevelMeters(eLevelMeters);
	}

	m_bDirty = FALSE;

	return S_OK;
}
HRESULT CMackieControlMaster::GetStatusText( LPSTR pszStatus, DWORD* pdwLen )
{
	if (NULL == pdwLen)
		return E_POINTER;

	CCriticalSectionAuto csa1(&m_cs);

	CString strStatus;

	if (0x00 == m_bDeviceType)
	{
		strStatus = "Connecting...";
	}
	else
	{
		CCriticalSectionAuto csa2(m_cState.GetCS());

		switch (m_cState.GetMixerStrip())
		{
			case MIX_STRIP_TRACK:
				strStatus = "Trks";
				break;

			case MIX_STRIP_AUX:
				strStatus = "Auxs";
				break;

			case MIX_STRIP_MAIN:
				strStatus = "VMns";
				break;

			case MIX_STRIP_BUS:
				strStatus = "Bus";
				break;

			case MIX_STRIP_MASTER:
				strStatus = "Mstr";
				break;

			default:
				strStatus = "Err0";
				break;
		}

		DWORD dwOffset = m_cState.GetStripNumOffset();
		DWORD dwFirst = m_cState.GetFirstFaderNumber() + dwOffset + 1;
		DWORD dwLast = m_cState.GetLastFaderNumber() + dwOffset + 1;

		CString strBuf;
		strBuf.Format(" %d-%d, ", dwFirst, dwLast);
		strStatus += strBuf;

		switch (m_SwMasterFader.GetMixerStrip())
		{
			case MIX_STRIP_TRACK:
				strBuf.Format("Trk %d", m_SwMasterFader.GetStripNum() + 1);
				break;

			case MIX_STRIP_AUX:
				strBuf.Format("Aux %d", m_SwMasterFader.GetStripNum() + 1);
				break;

			case MIX_STRIP_MAIN:
				strBuf.Format("VMn %c", m_SwMasterFader.GetStripNum() + 'A');
				break;

			case MIX_STRIP_BUS:
				strBuf.Format("Bus %d", m_SwMasterFader.GetStripNum() + 1);
				break;

			case MIX_STRIP_MASTER:
				strBuf.Format("Mstr %d", m_SwMasterFader.GetStripNum() + 1);
				break;

			default:
				strBuf = "Err1";
				break;
		}
		strStatus += strBuf;

		strStatus += ", Jog: ";

		switch (m_cState.GetJogResolution())
		{
			case JOG_MEASURES:
				strStatus += "Meas.";
				break;

			case JOG_BEATS:
				strStatus += "Beats";
				break;

			case JOG_TICKS:
				strStatus += "Ticks";
				break;

			default:
				strStatus += "Err2";
				break;
		}
	}

	// Return results to caller
	if (NULL == pszStatus)
	{
		*pdwLen = (DWORD)::strlen(strStatus) + 1;
	}
	else
	{
		::strlcpy(pszStatus, strStatus, *pdwLen);
	}

	return S_OK;
}