//******************************************************************************
//
// Simple MIDI Library / SMWavetableSynthCtrl
//
// Wavetableシンセサイザ制御クラス
//
// Copyright (C) 2018-2021 WADA Masashi. All Rights Reserved.
//
//******************************************************************************

//MEMO:
//
//  Sampler 1  ---+
//  Sampler 2  ---+
//     :          +---> Mixer --> DefaultOutput
//  Sampler 15 ---+
//  Sampler 16 ---+
//
//  16チャンネル分のサンプラーを作成し、サンプラー単位にWavetable（DLS/SF2ファイル）をロードする。
//  プログラムチェンジ発生時はその時点でWavetableをロードするため、演奏に影響が出る可能性がある。
//  Appleが提供するサンプラーをそのまま利用するため、お手軽に実装できているが、コントロールチェンジの
//  対応状況や最大同時発音数など、仕様や性能が不明である。
//  DLS/SF2ファイルによっては、正常に発音されないことがある。

#import "YNBaseLib.h"
#import "SMWavetableSynthCtrl.h"
#import "SMEvent.h"
#import "SMEventMIDI.h"
#import "SMCommon.h"


//******************************************************************************
// コンストラクタ
//******************************************************************************
SMWavetableSynthCtrl::SMWavetableSynthCtrl()
{
	m_pWavetableFilePath = nil;
	m_AUGraph = NULL;
	m_isOpened = false;
}

//******************************************************************************
// デストラクタ
//******************************************************************************
SMWavetableSynthCtrl::~SMWavetableSynthCtrl()
{
	[m_pWavetableFilePath release];
	m_pWavetableFilePath = nil;
	_ReleaseAUGraph();
}

//******************************************************************************
// グラフリリース
//******************************************************************************
void SMWavetableSynthCtrl::_ReleaseAUGraph()
{
	Boolean isRunning = false;
	Boolean isInitialized = false;
	Boolean isOpened = false;
	int ch = 0;
	
	if (m_AUGraph != NULL) {
		AUGraphIsRunning(m_AUGraph, &isRunning);
		if (isRunning) {
			AUGraphStop(m_AUGraph);
		}
		AUGraphIsInitialized(m_AUGraph, &isInitialized);
		if (isInitialized) {
			AUGraphUninitialize(m_AUGraph);
		}
		AUGraphIsOpen(m_AUGraph, &isOpened);
		if (isOpened) {
			AUGraphClose(m_AUGraph);
		}
		DisposeAUGraph(m_AUGraph);
		m_AUGraph = NULL;
	}
	
	m_isOpened = false;
	
	for (ch = 0; ch < SM_MAX_CH_NUM; ch++) {
		m_isWavetableLoaded[ch] = false;
	}
	
	return;
}

//******************************************************************************
// 初期化
//******************************************************************************
int SMWavetableSynthCtrl::Initialize()
{
	int result = 0;
	
	//オーディオ処理グラフ生成
	result = _CreateAUGraph();
	if (result != 0) goto EXIT;
	
	//コントロール番号サポート情報初期化
	_InitControlNoSupport();
	
EXIT:;
	return result;
}

//******************************************************************************
// デバイス表示名称取得
//******************************************************************************
NSString* SMWavetableSynthCtrl::GetDevDisplayName()
{
	return SM_WAVETABLE_SYNTH_DISPLAY_NAME;
}

//******************************************************************************
// デバイス識別名称取得
//******************************************************************************
NSString* SMWavetableSynthCtrl::GetDevIdName()
{
	return SM_WAVETABLE_SYNTH_DEVID_NAME;
}

//******************************************************************************
// メーカー名取得
//******************************************************************************
NSString* SMWavetableSynthCtrl::GetManufacturerName()
{
	return SM_WAVETABLE_SYNTH_MANUFACTURER_NAME;
}

//******************************************************************************
// Wavetableファイルパス設定
//******************************************************************************
int SMWavetableSynthCtrl::SetWavetableFilePath(NSString* pWavetableFilePath)
{
	int result = 0;
	
	[pWavetableFilePath retain];
	[m_pWavetableFilePath release];
	m_pWavetableFilePath = pWavetableFilePath;
	
	return result;
}

//******************************************************************************
// デバイスオープン
//******************************************************************************
int SMWavetableSynthCtrl::Open()
{
	int result = 0;
	OSStatus status = 0;
	
	//サンプラーユニット初期化
	result = _InitSamplerUnits();
	if (result != 0) goto EXIT;
	
	//グラフ開始
	status = AUGraphStart(m_AUGraph);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
	m_isOpened = true;
	
EXIT:;
	return result;
}
//******************************************************************************
// デバイスクローズ
//******************************************************************************
int SMWavetableSynthCtrl::Close()
{
	int result = 0;
	OSStatus status = 0;
	
	if (!m_isOpened) goto EXIT;
	
	//演奏停止
	status = AUGraphStop(m_AUGraph);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
	m_isOpened = false;
	
EXIT:;
	return result;
}

//******************************************************************************
// MIDIメッセージ送信
//******************************************************************************
int SMWavetableSynthCtrl::SendShortMsg(
		unsigned char* pMsg,
		unsigned int size
	)
{
	int result = 0;
	OSStatus status = 0;
	unsigned char data[3] = {0, 0, 0};
	unsigned char controlNo = 0;
	unsigned char ch = 0;
	unsigned char bankSelectMSB = 0;
	unsigned char bankSelectLSB = 0;
	SMEvent event;
	SMEventMIDI eventMIDI;
	
	if (size > 3) {
		result = YN_SET_ERR(@"Program error.", size, 0);
		goto EXIT;
	}
	
	if (size >= 1) {
		data[0] = pMsg[0];
	}
	if (size >= 2) {
		data[1] = pMsg[1];
	}
	if (size >= 3) {
		data[2] = pMsg[2];
	}
	
	//コントロールチェンジを送信する場合は送信可否を判定する
	if ((data[0] & 0xF0) == 0xB0) {
		//コントロール番号
		controlNo = data[1];
		if (controlNo >= 128) {
			//コントロール番号異常なので送信しない
			goto EXIT;
		}
		else if (m_ControlNoSupport[controlNo] == 0) {
			//サポートしていないコントロール番号なので送信しない
			goto EXIT;
		}
	}
	
	//MIDIイベント解析
	event.SetMIDIData(data[0], &(data[1]) ,size - 1);
	eventMIDI.Attach(&event);
	ch = eventMIDI.GetChNo();
	
	//バンクセレクトを記憶
	if (eventMIDI.GetChMsg() == SMEventMIDI::ControlChange) {
		if (eventMIDI.GetCCNo() == 0) {
			m_BankSelectMSB[ch] = eventMIDI.GetCCValue();
		}
		else if (eventMIDI.GetCCNo() == 32) {
			m_BankSelectLSB[ch] = eventMIDI.GetCCValue();
		}
	}
	
	//プログラムチェンジ
	if (eventMIDI.GetChMsg() == SMEventMIDI::ProgramChange) {
		//MIDIデータ指定のバンクセレクト(MSB/LSB)でWavetable読み込みを試みる
		result = _LoadInstrument(
						ch,
						m_UnitSampler[ch],
						m_BankSelectMSB[ch],
						m_BankSelectLSB[ch],
						eventMIDI.GetProgramNo()
					);
		if (result != 0) {
			//Wavetable読み込み失敗時はデフォルト値でリトライする
			if (ch != SM_WAVETABLE_SYNTH_PERCUSSION_CH) {
				//チャンネル#10以外
				bankSelectMSB = kAUSampler_DefaultMelodicBankMSB; //121
				bankSelectLSB = kAUSampler_DefaultBankLSB; //0
			}
			else {
				//チャンネル#10：ドラム／パーカッション用
				bankSelectMSB = kAUSampler_DefaultPercussionBankMSB; //120
				bankSelectLSB = kAUSampler_DefaultBankLSB; //0
			}
			result = _LoadInstrument(
							ch,
							m_UnitSampler[ch],
							bankSelectMSB,
							bankSelectLSB,
							eventMIDI.GetProgramNo()
						);
			if (result != 0) {
				//ロード失敗はエラーとせず処理を続行する
				result = 0;
			}
		}
	}
	
	//MIDIイベント送信
	status = MusicDeviceMIDIEvent(
					m_UnitSampler[ch],	//ユニット
					data[0],			//ステータス
					data[1],			//データ1
					data[2],			//データ2
					0					//サンプルオフセット
				);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// システムエクスクルーシブ送信
//******************************************************************************
int SMWavetableSynthCtrl::SendLongMsg(
		unsigned char* pMsg,
		unsigned int size
	)
{
	int result = 0;
	OSStatus status = 0;
	int ch = 0;
	
	for (ch = 0; ch < SM_MAX_CH_NUM; ch++) {
		//システムエクスクルーシブ送信
		status = MusicDeviceSysEx(
						m_UnitSampler[0],	//出力ユニット
						pMsg,				//データ位置
						(UInt32)size		//データサイズ
					);
		if (status != noErr) {
			result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
			goto EXIT;
		}
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// 全ノートオフ
//******************************************************************************
int SMWavetableSynthCtrl::NoteOffAll()
{
	int result = 0;
	unsigned char i = 0;
	unsigned char msg[3];
	
	//全トラックノートオフ
	for (i = 0; i < SM_MAX_CH_NUM; i++) {
		msg[0] = 0xB0 | i;
		msg[1] = 0x7B;
		msg[2] = 0x00;
		result = SendShortMsg(msg, 3);
		if (result != 0) goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// 全サウンドオフ
//******************************************************************************
int SMWavetableSynthCtrl::SoundOffAll()
{
	int result = 0;
	unsigned char i = 0;
	unsigned char msg[3];
	
	//全トラックノートオフ
	for (i = 0; i < SM_MAX_CH_NUM; i++) {
		msg[0] = 0xB0 | i;
		msg[1] = 0x78;
		msg[2] = 0x00;
		result = SendShortMsg(msg, 3);
		if (result != 0) goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// オーディオ処理グラフ生成
//******************************************************************************
int SMWavetableSynthCtrl::_CreateAUGraph()
{
	int result = 0;
	OSStatus status = 0;
	
	_ReleaseAUGraph();
	
	//オーディオ処理グラフ生成
	status = NewAUGraph(&m_AUGraph);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
	//ノード生成
	result = _CreateNodes();
	if (result != 0) goto EXIT;
	
	//グラフを開く
	status = AUGraphOpen(m_AUGraph);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
	//オーディオユニット取得
	result = _GetAudioUnits();
	if (result != 0) goto EXIT;
	
	//サンプラーユニット初期化
	//result = _InitSamplerUnits();
	//if (result != 0) goto EXIT;
	
	//マルチチャンネルミキサーユニット初期化
	result = _InitMixerUnit();
	if (result != 0) goto EXIT;
	
	//出力ユニット初期化
	result = _InitOutputUnit();
	if (result != 0) goto EXIT;
	
	// ノード接続
	result = _ConnectNodes();
	if (result != 0) goto EXIT;
	
	//グラフ初期化
	status = AUGraphInitialize(m_AUGraph);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}

EXIT:;
	return result;
}

//******************************************************************************
// ノード生成
//******************************************************************************
int SMWavetableSynthCtrl::_CreateNodes()
{
	int result = 0;
	OSStatus status = 0;
	int i = 0;
	AudioComponentDescription cd;
	
	//ノード生成：サンプラー
	for (i = 0; i < SM_MAX_CH_NUM; i++) {
		cd.componentType         = kAudioUnitType_MusicDevice;
		cd.componentSubType      = kAudioUnitSubType_Sampler;
		cd.componentManufacturer = kAudioUnitManufacturer_Apple;
		cd.componentFlags        = 0;
		cd.componentFlagsMask    = 0;
		status = AUGraphAddNode(m_AUGraph, &cd, &m_NodeSampler[i]);
		if (status != noErr) {
			result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
			goto EXIT;
		}
	}
	
	//ノード生成：マルチチャンネルミキサー
	cd.componentType         = kAudioUnitType_Mixer;
	cd.componentSubType      = kAudioUnitSubType_MultiChannelMixer;
	cd.componentManufacturer = kAudioUnitManufacturer_Apple;
	cd.componentFlags = 0;
	cd.componentFlagsMask = 0;
	status = AUGraphAddNode(m_AUGraph, &cd, &m_NodeMixer);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
	//ノード生成：出力
	cd.componentType         = kAudioUnitType_Output;
	cd.componentSubType      = kAudioUnitSubType_DefaultOutput;
	cd.componentManufacturer = kAudioUnitManufacturer_Apple;
	cd.componentFlags = 0;
	cd.componentFlagsMask = 0;
	status = AUGraphAddNode(m_AUGraph, &cd, &m_NodeOutput);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// ノード接続
//******************************************************************************
int SMWavetableSynthCtrl::_ConnectNodes()
{
	int result = 0;
	OSStatus status = 0;
	int i = 0;
	
	//ノード接続：サンプラー -> マルチチャンネルミキサー
	for (i = 0; i < SM_MAX_CH_NUM; i++) {
		status = AUGraphConnectNodeInput(
							m_AUGraph,			//入力元グラフ
							m_NodeSampler[i],	//入力元ノード
							0,					//送信元出力番号
							m_NodeMixer,		//出力先ノード
							i					//宛先入力番号
						);
		if (status != noErr) {
			result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
			goto EXIT;
		}
	}
	
	//ノード接続：マルチチャンネルミキサー -> 出力
	status = AUGraphConnectNodeInput(
							m_AUGraph,		//入力元グラフ
							m_NodeMixer,	//入力元ノード
							0,				//入力元出力番号
							m_NodeOutput,	//出力先ノード
							0				//出力先入力番号
						);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// オーディオユニット取得
//******************************************************************************
int SMWavetableSynthCtrl::_GetAudioUnits()
{
	int result = 0;
	OSStatus status = 0;
	AudioComponentDescription cd;
	int i = 0;
	
	//サンプラーユニットを取得
	for (i = 0; i < SM_MAX_CH_NUM; i++) {
		status = AUGraphNodeInfo(
							m_AUGraph,			//グラフ
							m_NodeSampler[i],	//ノード
							&cd,				//コンポーネント定義
							&m_UnitSampler[i]	//ユニット
						);
		if (status != noErr) {
			result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
			goto EXIT;
		}
	}
	
	//マルチチャンネルミキサーユニットを取得
	status = AUGraphNodeInfo(
						m_AUGraph,		//グラフ
						m_NodeMixer,	//ノード
						&cd,			//コンポーネント定義
						&m_UnitMixer	//ユニット
					);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
	//出力ユニットを取得
	status = AUGraphNodeInfo(
						m_AUGraph,		//グラフ
						m_NodeOutput,	//ノード
						&cd,			//コンポーネント定義
						&m_UnitOutput	//ユニット
					);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// サンプラーユニット初期化
//******************************************************************************
int SMWavetableSynthCtrl::_InitSamplerUnits()
{
	int result = 0;
	unsigned char ch = 0;
	unsigned char presetId = 0;
	unsigned char bankSelectMSB = 0;
	unsigned char bankSelectLSB = 0;
	
	//バンクセレクト初期化
	for (ch = 0; ch < SM_MAX_CH_NUM; ch++) {
		if (ch != SM_WAVETABLE_SYNTH_PERCUSSION_CH) {
			//チャンネル#10以外
			m_BankSelectMSB[ch] = 0;
			m_BankSelectLSB[ch] = 0;
		}
		else {
			//チャンネル#10：ドラム／パーカッション用
			m_BankSelectMSB[ch] = 1; //SoundFontの仕様による
			m_BankSelectLSB[ch] = 0;
		}
	}
	
	//Wavetable読み込み
	for (ch = 0; ch <  SM_MAX_CH_NUM; ch++) {
		result = _LoadInstrument(ch, m_UnitSampler[ch], m_BankSelectMSB[ch], m_BankSelectLSB[ch], presetId);
		if (result != 0) {
			//Wavetable読み込み失敗時はデフォルト値でリトライする
			if (ch != SM_WAVETABLE_SYNTH_PERCUSSION_CH) {
				//チャンネル#10以外
				bankSelectMSB = kAUSampler_DefaultMelodicBankMSB; //121
				bankSelectLSB = kAUSampler_DefaultBankLSB; //0
			}
			else {
				//チャンネル#10：ドラム／パーカッション用
				bankSelectMSB = kAUSampler_DefaultPercussionBankMSB; //120
				bankSelectLSB = kAUSampler_DefaultBankLSB; //0
			}
			result = _LoadInstrument(ch, m_UnitSampler[ch], bankSelectMSB, bankSelectLSB, presetId);
			if (result != 0) {
				//ロード失敗はエラーとせず処理を続行する
				result = 0;
			}
		}
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// ミキサーユニット初期化
//******************************************************************************
int SMWavetableSynthCtrl::_InitMixerUnit()
{
	int result = 0;
	OSStatus status = 0;
	UInt32 busCount = SM_MAX_CH_NUM;
	Float64 sampleRate = SM_WAVETABLE_SYNTH_MIXER_SAMPLE_RATE;
	AudioUnitParameterValue volume = 1.0;
	int i = 0;
	
	//バス数
	status = AudioUnitSetProperty(
						m_UnitMixer,				//ユニット
						kAudioUnitProperty_ElementCount,	//プロパティID
						kAudioUnitScope_Input,		//プロパティスコープ
						0,							//プロパティ要素
						&busCount,					//プロパティ値
						sizeof(busCount)			//プロパティ値のサイズ
					);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
	for (i = 0; i < SM_MAX_CH_NUM; i++) {
		//ボリューム：入力
		// iOSと異なりmacOSはボリュームのデフォルト値がゼロであるため必ず設定する
		status = AudioUnitSetParameter(
							m_UnitMixer,				//ユニット
							kMultiChannelMixerParam_Volume,	//プロパティID
							kAudioUnitScope_Input,		//プロパティスコープ
							i,							//パラメータ要素
							volume,						//パラメータ
							0							//バッファオフセット
						);
		if (status != noErr) {
			result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
			goto EXIT;
		}
	}
	
	//ボリューム：出力
	// iOSと異なりmacOSはボリュームのデフォルト値がゼロであるため必ず設定する
	status = AudioUnitSetParameter(
						m_UnitMixer,				//ユニット
						kMultiChannelMixerParam_Volume,	//プロパティID
						kAudioUnitScope_Output,		//プロパティスコープ
						0,							//パラメータ要素
						volume,						//パラメータ
						0							//バッファオフセット
					);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
	//出力サンプルレート
	status = AudioUnitSetProperty(
						m_UnitMixer,				//ユニット
						kAudioUnitProperty_SampleRate,	//プロパティID
						kAudioUnitScope_Output,		//プロパティスコープ
						0,							//プロパティ要素
						&sampleRate,				//プロパティ値
						sizeof(sampleRate)			//プロパティ値のサイズ
					);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// 出力ユニット初期化
//******************************************************************************
int SMWavetableSynthCtrl::_InitOutputUnit()
{
	int result = 0;
	
	//処理なし
	
	return result;
}

//******************************************************************************
// Wavetable読み込み
//******************************************************************************
int SMWavetableSynthCtrl::_LoadInstrument(
		unsigned char ch,
		AudioUnit audioUnit,
		UInt8 bankMSB,
		UInt8 bankLSB,
		UInt8 presetId
	)
{
	int result = 0;
	OSStatus status = 0;
	AUSamplerInstrumentData instData;
	
	//Wavetableファイルパス未設定の場合は何もしない
	if ((m_pWavetableFilePath == nil) || ([m_pWavetableFilePath length] == 0)) {
		goto EXIT;
	}
	
	//Wavetableデータ作成
	NSLog(@"Loading instrument. MSB:%d LSB:%d Preset:%d", bankMSB, bankLSB, presetId);
	instData.fileURL = (CFURLRef)[NSURL fileURLWithPath:m_pWavetableFilePath]; //DLS/SF2ファイルURL
	instData.instrumentType = kInstrumentType_SF2Preset;	//kInstrumentType_DLSPreset と値は同じ
	instData.bankMSB = bankMSB;								//CC#0  MSB
	instData.bankLSB = bankLSB;								//CC#32 LSB
	instData.presetID = presetId;							//プログラムチェンジ
	
	//Wavetableファイル読み込み
	status  = AudioUnitSetProperty(
						audioUnit,						//オーディオユニット
						kAUSamplerProperty_LoadInstrument,	//プロパティID
						kAudioUnitScope_Global,			//プロパティスコープ
						0,								//プロパティ要素
						&instData,						//プロパティ値
						sizeof(instData)				//プロパティ値のサイズ
					);
	if (status != noErr) {
		result = YN_SET_ERR(@"AudioToolbox API error.", status, 0);
		NSLog(@"Loading instrument failed.");
		goto EXIT;
	}
	
	m_isWavetableLoaded[ch] = true;
	
EXIT:;
	return result;
}

//******************************************************************************
// コントロール番号サポート情報初期化
//******************************************************************************
void SMWavetableSynthCtrl::_InitControlNoSupport()
{
	int ccNo = 0;
	
	for (ccNo = 0; ccNo < SM_MAX_CC_NUM; ccNo++) {
		m_ControlNoSupport[ccNo] = 1; //ok
	}
	
/*
	//Mac OS X 10.7 (Lion) Apple DLS Music Device のサポート状況
	m_ControlNoSupport[0]  = 1;  // ok : Bank Select MSB
	m_ControlNoSupport[1]  = 1;  // ok : Modulation Wheel or Lever
	m_ControlNoSupport[2]  = 0;  //    : Breath Controller
	m_ControlNoSupport[3]  = 0;  //    : --
	m_ControlNoSupport[4]  = 0;  //    : Foot Controller
	m_ControlNoSupport[5]  = 0;  //    : Portamento Time
	m_ControlNoSupport[6]  = 1;  // ok : Data Entry MSB
	m_ControlNoSupport[7]  = 1;  // ok : Channel Volume, fomerly Main Volume
	m_ControlNoSupport[8]  = 0;  //    : Balance
	m_ControlNoSupport[9]  = 0;  //    : --
	m_ControlNoSupport[10] = 1;  // ok : Pan
	m_ControlNoSupport[11] = 1;  // ok : Expression Controller
	m_ControlNoSupport[12] = 0;  //    : Effect Control 1
	m_ControlNoSupport[13] = 0;  //    : Effect Control 2
	m_ControlNoSupport[14] = 0;  //    : --
	m_ControlNoSupport[15] = 0;  //    : --
	m_ControlNoSupport[16] = 0;  //    : General Purpose Controller 1
	m_ControlNoSupport[17] = 0;  //    : General Purpose Controller 2
	m_ControlNoSupport[18] = 0;  //    : General Purpose Controller 3
	m_ControlNoSupport[19] = 0;  //    : General Purpose Controller 4
	m_ControlNoSupport[20] = 0;  //    : --
	m_ControlNoSupport[21] = 0;  //    : --
	m_ControlNoSupport[22] = 0;  //    : --
	m_ControlNoSupport[23] = 0;  //    : --
	m_ControlNoSupport[24] = 0;  //    : --
	m_ControlNoSupport[25] = 0;  //    : --
	m_ControlNoSupport[26] = 0;  //    : --
	m_ControlNoSupport[27] = 0;  //    : --
	m_ControlNoSupport[28] = 0;  //    : --
	m_ControlNoSupport[29] = 0;  //    : --
	m_ControlNoSupport[30] = 0;  //    : --
	m_ControlNoSupport[31] = 0;  //    : --
	m_ControlNoSupport[32] = 1;  // ok : LSB for Control 0 : Bank Select LSB
	m_ControlNoSupport[33] = 1;  // ok : LSB for Control 1 : Modulation Wheel or Lever
	m_ControlNoSupport[34] = 0;  //    : LSB for Control 2 : Breath Controller
	m_ControlNoSupport[35] = 0;  //    : LSB for Control 3 : --
	m_ControlNoSupport[36] = 0;  //    : LSB for Control 4 : Foot Controller
	m_ControlNoSupport[37] = 0;  //    : LSB for Control 5 : Portamento Time
	m_ControlNoSupport[38] = 1;  // ok : LSB for Control 6 : Data Entry
	m_ControlNoSupport[39] = 1;  // ok : LSB for Control 7 : Channel Volume, formerly Main Volume
	m_ControlNoSupport[40] = 0;  //    : LSB for Control 8 : Balance
	m_ControlNoSupport[41] = 0;  //    : LSB for Control 9 : --
	m_ControlNoSupport[42] = 1;  // ok : LSB for Control 10 : Pan
	m_ControlNoSupport[43] = 1;  // ok : LSB for Control 11 : Expression Controller
	m_ControlNoSupport[44] = 0;  //    : LSB for Control 12 : Effect Control 1
	m_ControlNoSupport[45] = 0;  //    : LSB for Control 13 : Effect Control 2
	m_ControlNoSupport[46] = 0;  //    : LSB for Control 14 : --
	m_ControlNoSupport[47] = 0;  //    : LSB for Control 15 : --
	m_ControlNoSupport[48] = 0;  //    : LSB for Control 16 : General Purpase Controller 1
	m_ControlNoSupport[49] = 0;  //    : LSB for Control 17 : General Purpase Controller 2
	m_ControlNoSupport[50] = 0;  //    : LSB for Control 18 : General Purpase Controller 3
	m_ControlNoSupport[51] = 0;  //    : LSB for Control 19 : General Purpase Controller 4
	m_ControlNoSupport[52] = 0;  //    : LSB for Control 20 : --
	m_ControlNoSupport[53] = 0;  //    : LSB for Control 21 : --
	m_ControlNoSupport[54] = 0;  //    : LSB for Control 22 : --
	m_ControlNoSupport[55] = 0;  //    : LSB for Control 23 : --
	m_ControlNoSupport[56] = 0;  //    : LSB for Control 24 : --
	m_ControlNoSupport[57] = 0;  //    : LSB for Control 25 : --
	m_ControlNoSupport[58] = 0;  //    : LSB for Control 26 : --
	m_ControlNoSupport[59] = 0;  //    : LSB for Control 27 : --
	m_ControlNoSupport[60] = 0;  //    : LSB for Control 28 : --
	m_ControlNoSupport[61] = 0;  //    : LSB for Control 29 : --
	m_ControlNoSupport[62] = 0;  //    : LSB for Control 30 : --
	m_ControlNoSupport[63] = 0;  //    : LSB for Control 31 : --
	m_ControlNoSupport[64] = 1;  // ok : Damper Pedal On/Off
	m_ControlNoSupport[65] = 1;  // ok : Portamento On/Off
	m_ControlNoSupport[66] = 1;  // ok : Sostenuto On/Off
	m_ControlNoSupport[67] = 1;  // ok : Soft Pedal On/Off
	m_ControlNoSupport[68] = 0;  //    : Legato Footswitch
	m_ControlNoSupport[69] = 0;  //    : Hold 2
	m_ControlNoSupport[70] = 0;  //    : Sound Controller 1 : defalut - Sound Variation
	m_ControlNoSupport[71] = 0;  //    : Sound Controller 2 : defalut - Timbre/Harmonic Intens.
	m_ControlNoSupport[72] = 0;  //    : Sound Controller 3 : defalut - Release Time
	m_ControlNoSupport[73] = 0;  //    : Sound Controller 4 : defalut - Attack Time
	m_ControlNoSupport[74] = 0;  //    : Sound Controller 5 : defalut - Brighteness
	m_ControlNoSupport[75] = 0;  //    : Sound Controller 6 : defalut - Decay Time
	m_ControlNoSupport[76] = 0;  //    : Sound Controller 7 : defalut - Vibrato Rate
	m_ControlNoSupport[77] = 0;  //    : Sound Controller 8 : defalut - Vibrato Depth
	m_ControlNoSupport[78] = 0;  //    : Sound Controller 9 : defalut - Vibrato Delay
	m_ControlNoSupport[79] = 0;  //    : Sound Controller 10 : --
	m_ControlNoSupport[80] = 0;  //    : General Purpose Controller 5
	m_ControlNoSupport[81] = 0;  //    : General Purpose Controller 6
	m_ControlNoSupport[82] = 0;  //    : General Purpose Controller 7
	m_ControlNoSupport[83] = 0;  //    : General Purpose Controller 8
	m_ControlNoSupport[84] = 0;  //    : Portamento Control
	m_ControlNoSupport[85] = 0;  //    : --
	m_ControlNoSupport[86] = 0;  //    : --
	m_ControlNoSupport[87] = 0;  //    : --
	m_ControlNoSupport[88] = 0;  //    : High Resolution Velocity Prefix
	m_ControlNoSupport[89] = 0;  //    : --
	m_ControlNoSupport[90] = 0;  //    : --
	m_ControlNoSupport[91] = 1;  // ok : Effect 1 Depth : default - Reverb Send Level
	m_ControlNoSupport[92] = 0;  //    : Effect 2 Depth : formerly Tremolo Depth
	m_ControlNoSupport[93] = 0;  //    : Effect 3 Depth : default - Chorus Send Level
	m_ControlNoSupport[94] = 0;  //    : Effect 4 Depth : formerly Celeste Depth
	m_ControlNoSupport[95] = 0;  //    : Effect 5 Depth : formerly Phaser Depth
	m_ControlNoSupport[96] = 0;  //    : Data Increment
	m_ControlNoSupport[97] = 0;  //    : Data Decrement
	m_ControlNoSupport[98] = 0;  //    : NRPN LSB
	m_ControlNoSupport[99] = 0;  //    : NRPN MSB
	m_ControlNoSupport[100] = 1;  // ok : RPN LSB
	m_ControlNoSupport[101] = 1;  // ok : RPN MSB
	m_ControlNoSupport[102] = 0;  //    : --
	m_ControlNoSupport[103] = 0;  //    : --
	m_ControlNoSupport[104] = 0;  //    : --
	m_ControlNoSupport[105] = 0;  //    : --
	m_ControlNoSupport[106] = 0;  //    : --
	m_ControlNoSupport[107] = 0;  //    : --
	m_ControlNoSupport[108] = 0;  //    : --
	m_ControlNoSupport[109] = 0;  //    : --
	m_ControlNoSupport[110] = 0;  //    : --
	m_ControlNoSupport[111] = 0;  //    : --
	m_ControlNoSupport[112] = 0;  //    : --
	m_ControlNoSupport[113] = 0;  //    : --
	m_ControlNoSupport[114] = 0;  //    : --
	m_ControlNoSupport[115] = 0;  //    : --
	m_ControlNoSupport[116] = 0;  //    : --
	m_ControlNoSupport[117] = 0;  //    : --
	m_ControlNoSupport[118] = 0;  //    : --
	m_ControlNoSupport[119] = 0;  //    : --
	m_ControlNoSupport[120] = 1;  // ok : Channel Mode Message : All Sound Off
	m_ControlNoSupport[121] = 1;  // ok : Channel Mode Message : Reset All Controllers
	m_ControlNoSupport[122] = 0;  //    : Channel Mode Message : Local Control On/Off
	m_ControlNoSupport[123] = 1;  // ok : Channel Mode Message : All Notes Off
	m_ControlNoSupport[124] = 0;  //    : Channel Mode Message : Omni Mode Off
	m_ControlNoSupport[125] = 0;  //    : Channel Mode Message : Omni Mode On
	m_ControlNoSupport[126] = 0;  //    : Channel Mode Message : Mono Mode On
	m_ControlNoSupport[127] = 0;  //    : Channel Mode Message : Poly Mode On
*/
	
	return;
}


