#include "stdafx.h"
#include "refCInputMIDI.h"

namespace FDK
{
// public:

	CInputMIDI::CInputMIDI( UInt32 nID )
	{
		this->Disposed = gcnew CDisposed();
		this->_hMidiIn = 0;
		this->_listMIDI入力イベント = gcnew List<CInputEvent^>( 32 );

		this->_e入力デバイス種別 = E入力デバイス種別::MIDI入力;
		this->_guid = nullptr;
		this->_ID = (int) nID;
		this->_list入力イベント = gcnew List<CInputEvent^>( 32 );
		this->_strデバイス名 = "";

		this->lock入力イベント = gcnew Object();
		this->lockMIDI入力イベント = gcnew Object();
	}
	CInputMIDI::~CInputMIDI()
	{
		if( this->Disposed->bDispose済みまたは処理中である )
			return;		// 例外は発出しない

		if( !this->Disposed->t開始を宣言する() )
			return;		// 例外は発出しない


		SAFE_REF_DELETE( this->_guid );
		SAFE_REF_DELETE( this->_strデバイス名 );
		{
			lock l( this->lock入力イベント );
			lock m( this->lockMIDI入力イベント );

			if( this->_list入力イベント != nullptr )
			{
				for each( CInputEvent^ ev in this->_list入力イベント )
					delete ev;	// Dispose

				SAFE_REF_DELETE( this->_list入力イベント );

				for each( CInputEvent^ ev in this->_listMIDI入力イベント )
					delete ev;	// Dispose

				SAFE_REF_DELETE( this->_listMIDI入力イベント );
			}
		}
		SAFE_REF_DELETE( this->lock入力イベント );
		SAFE_REF_DELETE( this->lockMIDI入力イベント );

		//GC::SuppressFinalize( this );   --> コンパイラが勝手にやる
	}

	// このメソッドは midiInProc スレッドから呼び出される。（要同期）
	void CInputMIDI::tメッセージからMIDI信号のみ受信( UInt16 wMsg, UInt32 dwInstance, UInt32 dwParam1, UInt32 dwParam2, Int64 n受信システム時刻 )
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CInputMIDI" );

		if( wMsg == 0x03C3 ) // MIM_DATA
		{
			int nStatus		= ( dwParam1       ) & 0x000000F0;
			int nNote		= ( dwParam1 >>  8 ) & 0x000000FF;
			int nVelocity	= ( dwParam1 >> 16 ) & 0x000000FF;

			if( nStatus == 0x90 && nVelocity != 0 )		// MIDI ノート
			{
				CInputEvent^ ev = gcnew CInputEvent();
				ev->guid = this->guid;
				ev->ID = this->ID;
				ev->nKey = nNote;
				ev->b押された = true;
				ev->nTimeStamp = n受信システム時刻;
				ev->nVelocity = nVelocity;

				lock l( this->lockMIDI入力イベント );
				this->_listMIDI入力イベント->Add( ev );
			}
			else if( nStatus == 0xB0 && nNote == 0x04 )	// FootPedalコントロールチェンジ
			{
				CInputEvent^ ev = gcnew CInputEvent();
				ev->guid = this->guid;
				ev->ID = this->ID;
				ev->nKey = 255;		// FP はキー 255 とする
				ev->b押された = true;
				ev->nTimeStamp = n受信システム時刻;
				ev->nVelocity = nVelocity;

				lock l( this->lockMIDI入力イベント );
				this->_listMIDI入力イベント->Add( ev );
			}
		}
	}
	void CInputMIDI::tポーリング( bool bWindowがアクティブ中, bool bバッファ入力を使用する )
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CInputMIDI" );

		lock l( this->lock入力イベント );
		lock m( this->listMIDI入力イベント );

		this->_list入力イベント->Clear();	// リセット

		for( int i = 0; i < this->_listMIDI入力イベント->Count; i++ )
			this->_list入力イベント->Add( this->_listMIDI入力イベント[ i ] );			// Add なので CopyTo は使えない

		this->_listMIDI入力イベント->Clear();	// リセット
	}
}
