private void _一定時間が経っていれば空行を挿入する()
        {
            double 今回の入力リスト追加時刻 = QPCTimer.生カウント相対値を秒へ変換して返す(QPCTimer.生カウント);

            // 1秒以上経っていれば改行
            if (1.0 < (今回の入力リスト追加時刻 - this._前回の入力リスト追加時刻))
            {
                this.listView入力リスト.Items.Add("");
            }

            this._前回の入力リスト追加時刻 = 今回の入力リスト追加時刻;
        }
        public void 表示する()
        {
            using (Log.Block(FDKUtilities.現在のメソッド名))
            {
                // (1) メインウィンドウ用の入力管理をいったん破棄し、このダイアログ用の入力管理を生成する。

                App.入力管理.Dispose();

                using (var 入力管理 = new 入力管理(this.Handle))
                {
                    入力管理.キーバインディングを取得する = () => App.システム設定.キーバインディング;
                    入力管理.キーバインディングを保存する = () => App.システム設定.保存する();
                    入力管理.初期化する();


                    // (2) ダイアログを表示。

                    using (var timer = new Timer())
                    {
                        #region " 設定値で初期化。"
                        //----------------
                        foreach (ドラム入力種別 drum in Enum.GetValues(typeof(ドラム入力種別)))
                        {
                            if (drum == ドラム入力種別.Unknown ||
                                drum == ドラム入力種別.HiHat_Control)
                            {
                                continue;                                   // 除外(設定変更不可)
                            }
                            this.comboBoxパッドリスト.Items.Add(drum.ToString());
                        }

                        // 変更後のキーバインディングを、現在の設定値で初期化。

                        this._変更後のキーバインディング = (キーバインディング)App.システム設定.キーバインディング.Clone();


                        // 最初のパッドを選択し、割り当て済みリストを更新。

                        this.comboBoxパッドリスト.SelectedIndex = 0;


                        // その他の初期化。

                        this._前回の入力リスト追加時刻 = QPCTimer.生カウント相対値を秒へ変換して返す(QPCTimer.生カウント);

                        this._FootPedal現在値 = 0;

                        this.textBoxFootPedal現在値.Text = "0";
                        this.textBoxFootPedal最小値.Text = this._変更後のキーバインディング.FootPedal最小値.ToString();
                        this.textBoxFootPedal最大値.Text = this._変更後のキーバインディング.FootPedal最大値.ToString();

                        this._変更あり = false;


                        // 初期メッセージを出力。

                        this.listView入力リスト.Items.Add($"KEYBOARD \"{入力管理.Keyboard.DeviceName}\" の受付を開始しました。");
                        for (int i = 0; i < 入力管理.MidiIn.DeviceName.Count; i++)
                        {
                            this.listView入力リスト.Items.Add($"MIDI IN [{i}] \"{入力管理.MidiIn.DeviceName[ i ]}\" の受付を開始しました。");
                        }
                        this.listView入力リスト.Items.Add("");
                        this.listView入力リスト.Items.Add("* タイミングクロック信号、アクティブ信号は無視します。");
                        this.listView入力リスト.Items.Add("* 入力と入力の間が500ミリ秒以上開いた場合は、間に空行を表示します。");
                        this.listView入力リスト.Items.Add("");
                        this.listView入力リスト.Items.Add("キーボードまたはMIDI信号を入力してください。");
                        //----------------
                        #endregion

                        // タイマーイベントを使って、定期的に、入力値の表示とフットペダル開度ゲージの描画を行う。
                        timer.Interval = 100;
                        timer.Tick    += (sender, arg) => {
                            #region " キーボードをポーリングし、入力値を入力リストへ出力。"
                            //----------------
                            入力管理.Keyboard.ポーリングする();

                            for (int i = 0; i < 入力管理.Keyboard.入力イベントリスト.Count; i++)
                            {
                                var inputEvent = 入力管理.Keyboard.入力イベントリスト[i];

                                if (inputEvent.押された)
                                {
                                    var item = new ListViewItem入力リスト用(InputDeviceType.Keyboard, inputEvent);

                                    if (inputEvent.Key == (int)Key.Escape)                                          // 割り当てされてほしくないキーはここへ。
                                    {
                                        item.割り当て可能 = false;
                                    }

                                    // 既に割り当てられていたらそのドラム種別を表示。
                                    var drumType = this._変更後のキーバインディング.キーボードtoドラム
                                                   .Where((kvp) => (kvp.Key.deviceId == item.inputEvent.DeviceID && kvp.Key.key == item.inputEvent.Key))
                                                   .Select((kvp) => kvp.Value);
                                    if (0 < drumType.Count())
                                    {
                                        item.Text += $" (現在の割り当て: {drumType.ElementAt( 0 )})";
                                    }

                                    this._一定時間が経っていれば空行を挿入する();

                                    this.listView入力リスト.Items.Add(item);
                                    this.listView入力リスト.EnsureVisible(this.listView入力リスト.Items.Count - 1);
                                }
                                else if (inputEvent.離された)
                                {
                                    // キーボードについては表示しない。
                                }
                            }
                            //----------------
                            #endregion

                            #region " MIDI入力をポーリングし、入力値を入力リストへ出力。"
                            //----------------
                            // MidiInChecker の機能もかねて、NoteOFF や ControlChange も表示する。(割り当てはできない。)

                            入力管理.MidiIn.ポーリングする();

                            for (int i = 0; i < 入力管理.MidiIn.入力イベントリスト.Count; i++)
                            {
                                var inputEvent = 入力管理.MidiIn.入力イベントリスト[i];

                                if (inputEvent.押された && (255 == inputEvent.Key) && (4 == inputEvent.Control))
                                {
                                    #region " (A) フットペダルコントロールの場合 → 入力リストではなく専用のUIで表示。"
                                    //----------------
                                    if (this._FootPedal現在値 != inputEvent.Velocity)
                                    {
                                        // 現在値
                                        this._FootPedal現在値            = inputEvent.Velocity;
                                        this.textBoxFootPedal現在値.Text = this._FootPedal現在値.ToString();

                                        // 最大値
                                        if (this._FootPedal現在値 > this._変更後のキーバインディング.FootPedal最大値)
                                        {
                                            this._変更後のキーバインディング.FootPedal最大値 = this._FootPedal現在値;
                                            this.textBoxFootPedal最大値.Text    = this._変更後のキーバインディング.FootPedal最大値.ToString();
                                        }

                                        // 最小値
                                        if (this._FootPedal現在値 <= this._変更後のキーバインディング.FootPedal最小値)
                                        {
                                            this._変更後のキーバインディング.FootPedal最小値 = this._FootPedal現在値;
                                            this.textBoxFootPedal最小値.Text    = this._変更後のキーバインディング.FootPedal最小値.ToString();
                                        }
                                    }
                                    //----------------
                                    #endregion
                                }
                                else
                                {
                                    #region " (B) その他のMIDI入出力 → 入力リストに表示。"
                                    //----------------
                                    var item = new ListViewItem入力リスト用(InputDeviceType.MidiIn, inputEvent);

                                    // 既に割り当てられていたらそのドラム種別を表示。
                                    var drumType = this._変更後のキーバインディング.MIDItoドラム
                                                   .Where((kvp) => (kvp.Key.deviceId == item.inputEvent.DeviceID && kvp.Key.key == item.inputEvent.Key))
                                                   .Select((kvp) => kvp.Value);
                                    if (0 < drumType.Count())
                                    {
                                        item.Text += $" (現在の割り当て: {drumType.ElementAt( 0 )})";
                                    }

                                    this._一定時間が経っていれば空行を挿入する();

                                    this.listView入力リスト.Items.Add(item);
                                    this.listView入力リスト.EnsureVisible(this.listView入力リスト.Items.Count - 1);
                                    //----------------
                                    #endregion
                                }
                            }
                            //----------------
                            #endregion

                            #region " MIDIフットペダルの開度ゲージを描画。"
                            //----------------
                            using (var g = pictureBoxFootPedal.CreateGraphics())
                            {
                                var 全体矩形    = pictureBoxFootPedal.ClientRectangle;
                                var 背景色     = new System.Drawing.SolidBrush(pictureBoxFootPedal.BackColor);
                                var 最大値ゲージ色 = System.Drawing.Brushes.LightBlue;
                                var ゲージ色    = System.Drawing.Brushes.Blue;

                                g.FillRectangle(背景色, 全体矩形);

                                int 最大値用差分   = (int)(全体矩形.Height * (1.0 - this._変更後のキーバインディング.FootPedal最大値 / 127.0));
                                var 最大値ゲージ矩形 = new System.Drawing.Rectangle(
                                    全体矩形.X,
                                    全体矩形.Y + 最大値用差分,
                                    全体矩形.Width,
                                    全体矩形.Height - 最大値用差分);
                                g.FillRectangle(最大値ゲージ色, 最大値ゲージ矩形);

                                int 現在値用差分 = (int)(全体矩形.Height * (1.0 - this._FootPedal現在値 / 127.0));
                                var ゲージ矩形  = new System.Drawing.Rectangle(
                                    全体矩形.X,
                                    全体矩形.Y + 現在値用差分,
                                    全体矩形.Width,
                                    全体矩形.Height - 現在値用差分);
                                g.FillRectangle(ゲージ色, ゲージ矩形);
                            }
                            //----------------
                            #endregion
                        };

                        timer.Start();

                        #region " ダイアログを表示。"
                        //----------------
                        Cursor.Show();

                        var dr = this.ShowDialog(Program.App);

                        if (App.全画面モード)
                        {
                            Cursor.Hide();
                        }
                        //----------------
                        #endregion

                        timer.Stop();

                        if (dr == DialogResult.OK)
                        {
                            // 設定値を反映する。
                            App.システム設定.キーバインディング = (キーバインディング)this._変更後のキーバインディング.Clone();
                            入力管理.キーバインディングを保存する();
                        }
                    }
                }

                // (3) メインウィンドウ用の入力管理を復活する。

                App.入力管理 = new 入力管理(Program.App.Handle)
                {
                    キーバインディングを取得する = () => App.システム設定.キーバインディング,
                    キーバインディングを保存する = () => App.システム設定.保存する(),
                };
                App.入力管理.初期化する();
            }
        }
        public void 表示する()
        {
            using var _ = new LogBlock(Log.現在のメソッド名);

            using var timer = new Timer();

            #region " 設定値で初期化。"
            //----------------
            foreach (ドラム入力種別?drum in Enum.GetValues(typeof(ドラム入力種別)))
            {
                if (!drum.HasValue ||
                    drum == ドラム入力種別.Unknown ||
                    drum == ドラム入力種別.HiHat_Control)
                {
                    continue;   // 除外(設定変更不可)
                }
                this.comboBoxパッドリスト.Items.Add(drum.Value.ToString());
            }

            // 変更後のキーバインディングを、現在の設定値で初期化。
            this._変更後のシステム設定 = Global.App.システム設定.Clone();

            // 最初のパッドを選択し、割り当て済みリストを更新。
            this.comboBoxパッドリスト.SelectedIndex = 0;

            // その他の初期化。
            this._前回の入力リスト追加時刻            = QPCTimer.生カウント相対値を秒へ変換して返す(QPCTimer.生カウント);
            this._FootPedal現在値            = 0;
            this.textBoxFootPedal現在値.Text = "0";
            this.textBoxFootPedal最小値.Text = this._変更後のシステム設定.FootPedal最小値.ToString();
            this.textBoxFootPedal最大値.Text = this._変更後のシステム設定.FootPedal最大値.ToString();
            this._変更あり = false;

            // 初期メッセージを出力。
            this.listView入力リスト.Items.Add($"HID Keyboard の受付を開始しました。");
            for (int i = 0; i < Global.AppForm.MidiIns.DeviceName.Count; i++)
            {
                this.listView入力リスト.Items.Add($"MIDI IN [{i}] '{Global.AppForm.MidiIns.DeviceName[ i ]}' の受付を開始しました。");
            }
            this.listView入力リスト.Items.Add("");
            this.listView入力リスト.Items.Add("* タイミングクロック信号、アクティブ信号は無視します。");
            this.listView入力リスト.Items.Add("* 入力と入力の間が500ミリ秒以上開いた場合は、間に空行を表示します。");
            this.listView入力リスト.Items.Add("");
            this.listView入力リスト.Items.Add("キーボードまたはMIDI信号を入力してください。");
            //----------------
            #endregion

            // タイマーイベントを使って、定期的に、ゲームコントローラ/MIDI入力値の表示と、MIDIフットペダル開度ゲージの描画を行う。
            timer.Interval = 100;
            timer.Tick    += (sender, arg) => {
                #region " ゲームコントローラをポーリングし、入力値を入力リストへ出力。"
                //----------------
                Global.AppForm.GameControllersHID.ポーリングする();

                for (int i = 0; i < Global.AppForm.GameControllersHID.入力イベントリスト.Count; i++)
                {
                    var inputEvent = Global.AppForm.GameControllersHID.入力イベントリスト[i];

                    if (inputEvent.押された)
                    {
                        // 入力リストに表示。
                        var item = new ListViewItem入力リスト用(InputDeviceType.GameController, inputEvent);

                        // 既に割り当てられていたらそのドラム種別を表示。
                        var drumType = this._変更後のシステム設定.ゲームコントローラtoドラム
                                       .Where((kvp) => (kvp.Key.deviceId == item.inputEvent.DeviceID && kvp.Key.key == item.inputEvent.Key))
                                       .Select((kvp) => kvp.Value);
                        if (0 < drumType.Count())
                        {
                            item.Text += $" (現在の割り当て: {drumType.ElementAt( 0 )})";
                        }

                        this._一定時間が経っていれば空行を挿入する();

                        this.listView入力リスト.Items.Add(item);
                        this.listView入力リスト.EnsureVisible(this.listView入力リスト.Items.Count - 1);
                    }
                }
                //----------------
                #endregion

                #region " MIDI入力をポーリングし、入力値を入力リストへ出力。"
                //----------------
                // MidiInChecker の機能もかねて、NoteOFF や ControlChange も表示する。(割り当てはできない。)

                Global.AppForm.MidiIns.ポーリングする();

                for (int i = 0; i < Global.AppForm.MidiIns.入力イベントリスト.Count; i++)
                {
                    var inputEvent = Global.AppForm.MidiIns.入力イベントリスト[i];

                    if (inputEvent.押された && (255 == inputEvent.Key) && (4 == inputEvent.Control))
                    {
                        #region " (A) フットペダルコントロールの場合 → 入力リストではなく専用のUIで表示。"
                        //----------------
                        if (this._FootPedal現在値 != inputEvent.Velocity)
                        {
                            // 現在値
                            this._FootPedal現在値            = inputEvent.Velocity;
                            this.textBoxFootPedal現在値.Text = this._FootPedal現在値.ToString();

                            // 最大値
                            if (this._FootPedal現在値 > this._変更後のシステム設定.FootPedal最大値)
                            {
                                this._変更後のシステム設定.FootPedal最大値 = this._FootPedal現在値;
                                this.textBoxFootPedal最大値.Text = this._変更後のシステム設定.FootPedal最大値.ToString();
                            }

                            // 最小値
                            if (this._FootPedal現在値 <= this._変更後のシステム設定.FootPedal最小値)
                            {
                                this._変更後のシステム設定.FootPedal最小値 = this._FootPedal現在値;
                                this.textBoxFootPedal最小値.Text = this._変更後のシステム設定.FootPedal最小値.ToString();
                            }
                        }
                        //----------------
                        #endregion
                    }
                    else
                    {
                        #region " (B) その他のMIDI入出力 → 入力リストに表示。"
                        //----------------
                        var item = new ListViewItem入力リスト用(InputDeviceType.MidiIn, inputEvent);

                        // 既に割り当てられていたらそのドラム種別を表示。
                        var drumType = this._変更後のシステム設定.MIDItoドラム
                                       .Where((kvp) => (kvp.Key.deviceId == item.inputEvent.DeviceID && kvp.Key.key == item.inputEvent.Key))
                                       .Select((kvp) => kvp.Value);
                        if (0 < drumType.Count())
                        {
                            item.Text += $" (現在の割り当て: {drumType.ElementAt( 0 )})";
                        }

                        this._一定時間が経っていれば空行を挿入する();

                        this.listView入力リスト.Items.Add(item);
                        this.listView入力リスト.EnsureVisible(this.listView入力リスト.Items.Count - 1);
                        //----------------
                        #endregion
                    }
                }
                //----------------
                #endregion

                #region " MIDIフットペダルの開度ゲージを描画。"
                //----------------
                using (var g = pictureBoxFootPedal.CreateGraphics())
                {
                    var 全体矩形    = pictureBoxFootPedal.ClientRectangle;
                    var 背景色     = new System.Drawing.SolidBrush(pictureBoxFootPedal.BackColor);
                    var 最大値ゲージ色 = System.Drawing.Brushes.LightBlue;
                    var ゲージ色    = System.Drawing.Brushes.Blue;

                    g.FillRectangle(背景色, 全体矩形);

                    int 最大値用差分   = (int)(全体矩形.Height * (1.0 - this._変更後のシステム設定.FootPedal最大値 / 127.0));
                    var 最大値ゲージ矩形 = new System.Drawing.Rectangle(
                        全体矩形.X,
                        全体矩形.Y + 最大値用差分,
                        全体矩形.Width,
                        全体矩形.Height - 最大値用差分);
                    g.FillRectangle(最大値ゲージ色, 最大値ゲージ矩形);

                    int 現在値用差分 = (int)(全体矩形.Height * (1.0 - this._FootPedal現在値 / 127.0));
                    var ゲージ矩形  = new System.Drawing.Rectangle(
                        全体矩形.X,
                        全体矩形.Y + 現在値用差分,
                        全体矩形.Width,
                        全体矩形.Height - 現在値用差分);
                    g.FillRectangle(ゲージ色, ゲージ矩形);
                }
                //----------------
                #endregion
            };

            this.KeyPreview = true;            // Control への入力を先に Form が受け取れるようにする。

            this.KeyDown += (sender, arg) => { // ダイアログで RawInput を使う方法が分からないので KeyDown を使う
                #region " キーボードの入力値を入力リストへ出力。"
                //----------------
                var inputEvent = new InputEvent()
                {
                    DeviceID  = 0,
                    Key       = (int)arg.KeyCode,
                    TimeStamp = 0,
                    Velocity  = 100,
                    押された      = true,
                    Control   = 0,
                };

                var item = new ListViewItem入力リスト用(InputDeviceType.Keyboard, inputEvent);

                if (inputEvent.Key == (int)Keys.Escape)      // 割り当てされてほしくないキーはここへ。
                {
                    item.割り当て可能 = false;
                }

                // 既に割り当てられていたらそのドラム種別を表示。
                var drumType = this._変更後のシステム設定.キーボードtoドラム
                               .Where((kvp) => (kvp.Key.deviceId == item.inputEvent.DeviceID && kvp.Key.key == item.inputEvent.Key))
                               .Select((kvp) => kvp.Value);

                if (0 < drumType.Count())
                {
                    item.Text += $" (現在の割り当て: {drumType.ElementAt( 0 )})";
                }

                this._一定時間が経っていれば空行を挿入する();

                this.listView入力リスト.Items.Add(item);
                this.listView入力リスト.EnsureVisible(this.listView入力リスト.Items.Count - 1);
                //----------------
                #endregion
            };

            timer.Start();

            #region " ダイアログを表示。"
            //----------------
            Cursor.Show();

            var dr = this.ShowDialog(Global.AppForm);

            if (Global.AppForm.ScreenMode.IsFullscreenMode)
            {
                Cursor.Hide();
            }
            //----------------
            #endregion

            timer.Stop();

            if (dr == DialogResult.OK)
            {
                // 設定値を反映する。
                Global.App.システム設定 = this._変更後のシステム設定.Clone();
                Global.App.システム設定.保存する();
            }
        }
Exemple #4
0
        public override void 高速進行する()
        {
            try
            {
                if (this._初めての進行描画)
                {
                    this._初めての進行描画 = false;
                }

                // 高速進行

                this._FPS.FPSをカウントしプロパティを更新する();

                switch (this.現在のフェーズ)
                {
                case フェーズ.フェードイン:
                    if (this._フェードインカウンタ.終了値に達した)
                    {
                        #region " フェードインが終わったので、演奏開始。 "
                        //----------------
                        Log.Info("演奏を開始します。");

                        this._描画開始チップ番号 = 0;     // -1 から 0 に変われば演奏開始。

                        App.サウンドタイマ.リセットする();

                        this.現在のフェーズ = フェーズ.表示;

                        // ここで break; すると、次の表示フェーズまで1フレーム分の時間(数ミリ秒)が空いてしまう。
                        // なので、フレームが空かないように、ここですぐさま最初の表示フェーズを実行する。
                        this.高速進行する();
                        //----------------
                        #endregion
                    }
                    break;

                case フェーズ.表示:

                    // ※注:クリアや失敗の判定は、ここではなく、進行描画側で行っている。

                    double 現在の演奏時刻sec = this._演奏開始からの経過時間secを返す();
                    long   現在の演奏時刻qpc = QPCTimer.生カウント;


                    // AutoPlay 判定

                    #region " 自動ヒット処理。"
                    //----------------
                    this._描画範囲内のすべてのチップに対して(現在の演奏時刻sec, (chip, index, ヒット判定バーと描画との時間sec, ヒット判定バーと発声との時間sec, ヒット判定バーとの距離dpx) => {
                        var ユーザ設定       = App.ユーザ管理.ログオン中のユーザ;
                        var ドラムチッププロパティ = ユーザ設定.ドラムチッププロパティ管理[chip.チップ種別];
                        var AutoPlay    = ユーザ設定.AutoPlay[ドラムチッププロパティ.AutoPlay種別];

                        bool チップはヒット済みである           = this._チップの演奏状態[chip].ヒット済みである;
                        bool チップはまだヒットされていない        = !(チップはヒット済みである);
                        bool チップはMISSエリアに達している      = (ヒット判定バーと描画との時間sec > ユーザ設定.最大ヒット距離sec[判定種別.OK]);
                        bool チップは描画についてヒット判定バーを通過した = (0 <= ヒット判定バーと描画との時間sec);
                        bool チップは発声についてヒット判定バーを通過した = (0 <= ヒット判定バーと発声との時間sec);

                        if (チップはまだヒットされていない && チップはMISSエリアに達している)
                        {
                            #region " MISS判定。"
                            //----------------
                            if (AutoPlay && ドラムチッププロパティ.AutoPlayON_Miss判定)
                            {
                                this._チップのヒット処理を行う(
                                    chip,
                                    判定種別.MISS,
                                    ドラムチッププロパティ.AutoPlayON_自動ヒット_再生,
                                    ドラムチッププロパティ.AutoPlayON_自動ヒット_判定,
                                    ドラムチッププロパティ.AutoPlayON_自動ヒット_非表示,
                                    ヒット判定バーと発声との時間sec);
                                return;
                            }
                            else if (!AutoPlay && ドラムチッププロパティ.AutoPlayOFF_Miss判定)
                            {
                                this._チップのヒット処理を行う(
                                    chip,
                                    判定種別.MISS,
                                    ドラムチッププロパティ.AutoPlayOFF_ユーザヒット_再生,
                                    ドラムチッププロパティ.AutoPlayOFF_ユーザヒット_判定,
                                    ドラムチッププロパティ.AutoPlayOFF_ユーザヒット_非表示,
                                    ヒット判定バーと発声との時間sec);

                                this.成績.エキサイトゲージを加算する(判定種別.MISS);       // 手動演奏なら MISS はエキサイトゲージに反映。
                                return;
                            }
                            else
                            {
                                // 通過。
                            }
                            //----------------
                            #endregion
                        }

                        // ヒット処理(1) 発声時刻
                        if (チップは発声についてヒット判定バーを通過した)         // ヒット済みかどうかには関係ない
                        {
                            #region " 自動ヒット判定。"
                            //----------------
                            if ((AutoPlay && ドラムチッププロパティ.AutoPlayON_自動ヒット_再生) ||
                                (!AutoPlay && ドラムチッププロパティ.AutoPlayOFF_自動ヒット_再生))
                            {
                                // チップの発声がまだなら発声を行う。

                                if (!(this._チップの演奏状態[chip].発声済みである))
                                {
                                    this.チップの発声を行う(chip, ユーザ設定.ドラムの音を発声する);
                                    this._チップの演奏状態[chip].発声済みである = true;
                                }
                            }
                            //----------------
                            #endregion
                        }

                        // ヒット処理(2) 描画時刻
                        if (チップはまだヒットされていない && チップは描画についてヒット判定バーを通過した)
                        {
                            #region " 自動ヒット判定。"
                            //----------------
                            if (AutoPlay && ドラムチッププロパティ.AutoPlayON_自動ヒット)
                            {
                                this._チップのヒット処理を行う(
                                    chip,
                                    判定種別.PERFECT,       // AutoPlay 時は Perfect 扱い。
                                    ドラムチッププロパティ.AutoPlayON_自動ヒット_再生,
                                    ドラムチッププロパティ.AutoPlayON_自動ヒット_判定,
                                    ドラムチッププロパティ.AutoPlayON_自動ヒット_非表示,
                                    ヒット判定バーと発声との時間sec);

                                //this.成績.エキサイトゲージを加算する( 判定種別.PERFECT ); -> エキサイトゲージには反映しない。

                                this._ドラムキットとヒットバーEXPERT.ヒットアニメ開始(ドラムチッププロパティ.表示レーン種別);

                                return;
                            }
                            else if (!AutoPlay && ドラムチッププロパティ.AutoPlayOFF_自動ヒット)
                            {
                                this._チップのヒット処理を行う(
                                    chip,
                                    判定種別.PERFECT,       // AutoPlay OFF でも自動ヒットする場合は Perfect 扱い。
                                    ドラムチッププロパティ.AutoPlayOFF_自動ヒット_再生,
                                    ドラムチッププロパティ.AutoPlayOFF_自動ヒット_判定,
                                    ドラムチッププロパティ.AutoPlayOFF_自動ヒット_非表示,
                                    ヒット判定バーと発声との時間sec);

                                //this.成績.エキサイトゲージを加算する( 判定種別.PERFECT ); -> エキサイトゲージには反映しない。

                                this._ドラムキットとヒットバーEXPERT.ヒットアニメ開始(ドラムチッププロパティ.表示レーン種別);

                                return;
                            }
                            else
                            {
                                // 通過。
                            }
                            //----------------
                            #endregion
                        }
                    });
                    //----------------
                    #endregion


                    // 入力(1) 手動演奏

                    App.入力管理.すべての入力デバイスをポーリングする(入力履歴を記録する: false);

                    #region " ユーザヒット処理。"
                    //----------------
                    {
                        var ヒット処理済み入力 = new List <ドラム入力イベント>();    // ヒット処理が終わった入力は、二重処理しないよう、この中に追加しておく。

                        var ユーザ設定 = App.ユーザ管理.ログオン中のユーザ;

                        #region " 描画範囲内のすべてのチップについて、対応する入力があればヒット処理を行う。"
                        //----------------
                        this._描画範囲内のすべてのチップに対して(現在の演奏時刻sec, (chip, index, ヒット判定バーと描画との時間sec, ヒット判定バーと発声との時間sec, ヒット判定バーとの距離) => {
                            // ユーザ入力については、判定位置調整を適用する。(自動ヒットについては適用しない。)

                            ヒット判定バーと描画との時間sec += (App.システム設定.判定位置調整ms / 1000.0);
                            ヒット判定バーと発声との時間sec += (App.システム設定.判定位置調整ms / 1000.0);

                            #region " チップにヒットしている入力を探す。"
                            //----------------
                            var ドラムチッププロパティ = ユーザ設定.ドラムチッププロパティ管理[chip.チップ種別];
                            var AutoPlayである = ユーザ設定.AutoPlay[ドラムチッププロパティ.AutoPlay種別];

                            bool チップはヒット済みである           = this._チップの演奏状態[chip].ヒット済みである;
                            bool チップはMISSエリアに達している      = (ヒット判定バーと描画との時間sec > ユーザ設定.最大ヒット距離sec[判定種別.OK]);
                            bool チップは描画についてヒット判定バーを通過した = (0 <= ヒット判定バーと描画との時間sec);
                            bool チップは発声についてヒット判定バーを通過した = (0 <= ヒット判定バーと発声との時間sec);

                            if (チップはヒット済みである ||                                                               // ヒット済みなら何もしない。
                                AutoPlayである ||                                                                // AutoPlay チップなので何もしない。
                                !(ドラムチッププロパティ.AutoPlayOFF_ユーザヒット) ||                                          // このチップは AutoPlay OFF の時でもユーザヒットの対象ではないので何もしない。
                                !(ヒット判定バーと描画との時間sec >= -(ユーザ設定.最大ヒット距離sec[判定種別.OK]) && !(チップはMISSエリアに達している))) // チップはヒット可能エリアの外にあるので何もしない。
                            {
                                return;
                            }

                            var チップにヒットしている入力 = App.入力管理.ポーリング結果.FirstOrDefault((入力) => {
                                if (入力.InputEvent.離された ||                   // 押下入力じゃないなら無視。
                                    ヒット処理済み入力.Contains(入力) ||               // すでに今回のターンで処理済み(=処理済み入力リストに追加済み)なら無視。
                                    入力.Type == ドラム入力種別.HiHat_Control)       // HiHat_Control 入力はここでは無視。
                                {
                                    return(false);
                                }

                                var チップの入力グループ = ドラムチッププロパティ.入力グループ種別;

                                // (A) 入力グループ種別 が Unknown の場合 → ドラム入力種別で比較
                                if (チップの入力グループ == 入力グループ種別.Unknown)
                                {
                                    return(ドラムチッププロパティ.ドラム入力種別 == 入力.Type);
                                }
                                // (B) 入力グループ種別が Unknown ではない場合 → 入力グループ種別で比較
                                else
                                {
                                    var 入力の入力グループ種別リスト =
                                        from kvp in ユーザ設定.ドラムチッププロパティ管理.チップtoプロパティ
                                        where (kvp.Value.ドラム入力種別 == 入力.Type)
                                        select kvp.Value.入力グループ種別;

                                    foreach (var 入力の入力グループ種別 in 入力の入力グループ種別リスト)
                                    {
                                        if (チップの入力グループ == 入力の入力グループ種別)
                                        {
                                            return(true);
                                        }
                                    }
                                }
                                return(false);
                            });
                            //----------------
                            #endregion

                            if (null != チップにヒットしている入力)      // チップにヒットした入力があった
                            {
                                #region " チップの手動ヒット処理。"
                                //----------------

                                ヒット処理済み入力.Add(チップにヒットしている入力);          // この入力はこのチップでヒット処理した。

                                // 入力とチップとの時間差を算出。
                                double ヒット判定バーと入力との時間sec = QPCTimer.生カウント相対値を秒へ変換して返す(現在の演奏時刻qpc - チップにヒットしている入力.InputEvent.TimeStamp);         // 常に正
                                double 入力とチップの間隔sec      = Math.Abs(ヒット判定バーと入力との時間sec - ヒット判定バーと描画との時間sec);

                                // 時間差から判定を算出。
                                var 判定 =
                                    (入力とチップの間隔sec <= ユーザ設定.最大ヒット距離sec[判定種別.PERFECT]) ? 判定種別.PERFECT :
                                    (入力とチップの間隔sec <= ユーザ設定.最大ヒット距離sec[判定種別.GREAT]) ? 判定種別.GREAT :
                                    (入力とチップの間隔sec <= ユーザ設定.最大ヒット距離sec[判定種別.GOOD]) ? 判定種別.GOOD : 判定種別.OK;

                                // ヒット処理。
                                this._チップのヒット処理を行う(
                                    chip,
                                    判定,
                                    (ユーザ設定.ドラムの音を発声する) ? ドラムチッププロパティ.AutoPlayOFF_ユーザヒット_再生 : false,
                                    ドラムチッププロパティ.AutoPlayOFF_ユーザヒット_判定,
                                    ドラムチッププロパティ.AutoPlayOFF_ユーザヒット_非表示,
                                    ヒット判定バーと発声との時間sec);

                                // エキサイトゲージに反映する。
                                this.成績.エキサイトゲージを加算する(判定);

                                //----------------
                                #endregion
                            }
                        });
                        //----------------
                        #endregion

                        #region " ヒットしてようがしてまいが起こすアクションを実行。"
                        //----------------
                        {
                            var アクション済み入力 = new List <ドラム入力イベント>();     // ヒット処理が終わった入力は、二重処理しないよう、この中に追加しておく。

                            foreach (var 入力 in App.入力管理.ポーリング結果)
                            {
                                // 押下入力じゃないなら無視。
                                if (入力.InputEvent.離された)
                                {
                                    continue;
                                }

                                var プロパティs = ユーザ設定.ドラムチッププロパティ管理.チップtoプロパティ.Where((kvp) => (kvp.Value.ドラム入力種別 == 入力.Type));

                                if (プロパティs.Count() > 0)
                                {
                                    //for( int i = 0; i < プロパティs.Count(); i++ )
                                    int i = 0;      // 1つの入力で処理するのは、1つの表示レーン種別のみ。
                                    {
                                        var laneType = プロパティs.ElementAt(i).Value.表示レーン種別;

                                        if (ユーザ設定.演奏モード == PlayMode.BASIC)
                                        {
                                            this._ドラムパッドBASIC.ヒットする(laneType);
                                            this._レーンフラッシュBASIC.開始する(laneType);
                                        }
                                        if (ユーザ設定.演奏モード == PlayMode.EXPERT)
                                        {
                                            this._ドラムキットとヒットバーEXPERT.ヒットアニメ開始(laneType);
                                            this._レーンフラッシュEXPERT.開始する(laneType);
                                        }
                                    }
                                }
                            }
                        }
                        //----------------
                        #endregion

                        #region " どのチップにもヒットしなかった入力は空打ちとみなし、空打ち音を再生する。"
                        //----------------
                        if (ユーザ設定.ドラムの音を発声する)
                        {
                            foreach (var 入力 in App.入力管理.ポーリング結果)
                            {
                                if (ヒット処理済み入力.Contains(入力) ||        // ヒット済みなら無視。
                                    入力.InputEvent.離された)              // 押下じゃないなら無視。
                                {
                                    continue;
                                }

                                var プロパティs = ユーザ設定.ドラムチッププロパティ管理.チップtoプロパティ.Where((kvp) => (kvp.Value.ドラム入力種別 == 入力.Type));

                                for (int i = 0; i < プロパティs.Count(); i++)
                                {
                                    var prop = プロパティs.ElementAt(i).Value;

                                    if (0 < App.演奏スコア.空打ちチップマップ.Count)
                                    {
                                        #region " DTX他の場合(空うちチップマップ使用)"
                                        //----------------
                                        int zz = App.演奏スコア.空打ちチップマップ[prop.レーン種別];

                                        // (A) 空打ちチップの指定があるなら、それを発声する。
                                        if (0 != zz)
                                        {
                                            App.WAV管理.発声する(zz, prop.チップ種別, prop.発声前消音, prop.消音グループ種別, true);
                                        }

                                        // (B) 空打ちチップの指定がないなら、一番近いチップを検索し、それを発声する。
                                        else
                                        {
                                            var chip = this.指定された時刻に一番近いチップを返す(現在の演奏時刻sec, 入力.Type);

                                            if (null != chip)
                                            {
                                                this.チップの発声を行う(chip, true);
                                                break;      // 複数のチップが該当する場合でも、最初のチップの発声のみ行う。
                                            }
                                        }
                                        //----------------
                                        #endregion
                                    }
                                    else
                                    {
                                        #region " SSTFの場合(空うちチップマップ未使用)"
                                        //----------------
                                        App.ドラムサウンド.発声する(prop.チップ種別, 0, prop.発声前消音, prop.消音グループ種別);
                                        //----------------
                                        #endregion
                                    }
                                }
                            }
                        }
                        //----------------
                        #endregion

                        ヒット処理済み入力 = null;
                    }
                    //----------------
                    #endregion


                    // 入力(2) 演奏以外の操作(※演奏中なのでドラム入力は無視。)

                    if (App.入力管理.Keyboard.キーが押された(0, Key.Escape))
                    {
                        #region " ESC → 演奏中断 "
                        //----------------
                        Log.Info("ESC キーが押されました。演奏を中断します。");

                        this.BGMを停止する();
                        App.WAV管理.すべての発声を停止する();        // DTXでのBGMサウンドはこっちに含まれる。

                        // 進行描画スレッドへの通知フェーズを挟む。
                        this.現在のフェーズ = フェーズ.キャンセル通知;
                        //----------------
                        #endregion
                    }
                    if (App.入力管理.Keyboard.キーが押された(0, Key.Up))
                    {
                        #region " 上 → 譜面スクロールを加速 "
                        //----------------
                        const double 最大倍率 = 8.0;
                        App.ユーザ管理.ログオン中のユーザ.譜面スクロール速度 = Math.Min(App.ユーザ管理.ログオン中のユーザ.譜面スクロール速度 + 0.5, 最大倍率);
                        //----------------
                        #endregion
                    }
                    if (App.入力管理.Keyboard.キーが押された(0, Key.Down))
                    {
                        #region " 下 → 譜面スクロールを減速 "
                        //----------------
                        const double 最小倍率 = 0.5;
                        App.ユーザ管理.ログオン中のユーザ.譜面スクロール速度 = Math.Max(App.ユーザ管理.ログオン中のユーザ.譜面スクロール速度 - 0.5, 最小倍率);
                        //----------------
                        #endregion
                    }
                    if (App.ユーザ管理.ログオン中のユーザ.演奏モード == PlayMode.EXPERT)
                    {
                        #region " ハイハットの開閉 "
                        //----------------
                        foreach (var ev in App.入力管理.MidiIn.入力イベントリスト.Where((ie) => (255 == ie.Key)))
                        {
                            this._ドラムキットとヒットバーEXPERT.ハイハットの開度を設定する(ev.Velocity);
                        }
                        //----------------
                        #endregion
                    }
                    break;

                case フェーズ.キャンセル完了:
                case フェーズ.キャンセル時フェードアウト:
                case フェーズ.キャンセル通知:
                case フェーズ.クリア:
                    break;
                }
            }
            catch (Exception e)
            {
                Log.ERROR($"!!! 高速進行スレッドで例外が発生しました !!! [{Folder.絶対パスをフォルダ変数付き絶対パスに変換して返す( e.Message )}]");
            }
        }