public void 登録する(チップ種別 chipType, int subChipId, VariablePath サウンドファイルパス)
        {
            if (File.Exists(サウンドファイルパス.数なしパス))
            {
                lock (this._Sound利用権)
                {
                    // すでに辞書に存在してるなら、解放して削除する。
                    if (this._チップtoコンテキスト.ContainsKey((chipType, subChipId)))
                    {
                        this._チップtoコンテキスト[(chipType, subChipId)]?.Dispose();
                        this._チップtoコンテキスト.Remove((chipType, subChipId));
                    }

                    // コンテキストを作成する。
                    var context = new Cコンテキスト(this._多重度);

                    // サウンドファイルを読み込んでデコードする。
                    context.SampleSource = SampleSourceFactory.Create(App.サウンドデバイス, サウンドファイルパス);

                    // 多重度分のサウンドを生成する。
                    for (int i = 0; i < context.Sounds.Length; i++)
                    {
                        context.Sounds[i] = new Sound(App.サウンドデバイス, context.SampleSource);
                    }

                    // コンテキストを辞書に追加する。
                    this._チップtoコンテキスト.Add((chipType, subChipId), context);

                    Log.Info($"ドラムサウンドを生成しました。[({chipType.ToString()},{subChipId}) = {サウンドファイルパス.変数付きパス}]");
                }
            }
Beispiel #2
0
        /// <summary>
        ///		WAVファイルを登録する。
        /// </summary>
        /// <param name="wav番号">登録する番号。0~1295。すでに登録されている場合は上書き更新される。</param>
        /// <param name="サウンドファイル">登録するサウンドファイルのパス。</param>
        public void 登録する(SoundDevice device, int wav番号, VariablePath サウンドファイル, bool 多重再生する)
        {
            #region " パラメータチェック。"
            //----------------
            if (null == device)
            {
                throw new ArgumentNullException();
            }

            if ((0 > wav番号) || (1295 < wav番号))
            {
                throw new ArgumentOutOfRangeException($"WAV番号が範囲を超えています。[{wav番号}]");
            }

            if (!(File.Exists(サウンドファイル.数なしパス)))
            {
                Log.WARNING($"サウンドファイルが存在しません。[{サウンドファイル.変数付きパス}]");
                return;
            }
            //----------------
            #endregion

            // 先に SampleSource を生成する。
            var sampleSource = (ISampleSource)null;
            try
            {
                sampleSource = SampleSourceFactory.Create(device, サウンドファイル.数なしパス);
            }
            catch
            {
                Log.WARNING($"サウンドのデコードに失敗しました。[{サウンドファイル.変数付きパス}");
                return;
            }

            // すでに登録済みなら解放する。
            if (this._WavContexts.ContainsKey(wav番号))
            {
                this._WavContexts[wav番号].Dispose();
                this._WavContexts.Remove(wav番号);
            }

            // 新しいContextを生成して登録する。
            var context = new WavContext(wav番号, (多重再生する) ? this._既定の多重度 : 1);

            context.SampleSource = sampleSource;

            for (int i = 0; i < context.Sounds.Length; i++)
            {
                context.Sounds[i] = new Sound(device, context.SampleSource);
            }

            this._WavContexts.Add(wav番号, context);

            Log.Info($"サウンドを読み込みました。[{サウンドファイル.変数付きパス}]");
        }
        private ISampleSource?_SampleSourceを生成する(VariablePath 音声ファイルの絶対パス)
        {
            ISampleSource?sampleSource = null;

            // キャッシュにある?
            lock (this._キャッシュ用排他)
            {
                if (this._サンプルソースキャッシュ.ContainsKey(音声ファイルの絶対パス.数なしパス))
                {
                    // あるなら、対応する ISampleSource を取得。
                    sampleSource = this._サンプルソースキャッシュ[音声ファイルの絶対パス.数なしパス];
                }
            }

            if (sampleSource is null)
            {
                // ファイルから ISampleSource を生成する。
                sampleSource = SampleSourceFactory.Create(Global.App.サウンドデバイス, 音声ファイルの絶対パス);
                if (sampleSource is null)
                {
                    return(null);    // 失敗した
                }
                // ISampleSource をキャッシュに登録する。
                lock (this._キャッシュ用排他)
                {
                    this._サンプルソースキャッシュ.Add(音声ファイルの絶対パス.数なしパス, sampleSource);
                    this._キャッシュ世代リスト.Add(音声ファイルの絶対パス.数なしパス);
                }

                // キャッシュが一定数を超えたら、一番古いものから削除する。
                if (_キャッシュする個数 < this._キャッシュ世代リスト.Count)
                {
                    lock (this._キャッシュ用排他)
                    {
                        var path = this._キャッシュ世代リスト.Last();     // リストの末尾の最後の
                        this._サンプルソースキャッシュ[path].Dispose();     // ISampleSource を解放して
                        this._キャッシュ世代リスト.Remove(path);          // キャッシュからも
                        this._サンプルソースキャッシュ.Remove(path);        // 削除。
                    }
                }
            }
            else
            {
                // キャッシュの世代リストで、今取得したソースが一番若くなるように操作する。
                lock (this._キャッシュ用排他)
                {
                    this._キャッシュ世代リスト.Remove(音声ファイルの絶対パス.数なしパス);     // 冤罪の位置から除去して
                    this._キャッシュ世代リスト.Add(音声ファイルの絶対パス.数なしパス);        // 一番最新の位置へ。
                }
            }

            // ISampleSource を返す。
            return(sampleSource);
        }
Beispiel #4
0
        internal Sound(AudioDevice audioDevice, string file, SoundFlags flags) : base(audioDevice)
        {
            if (string.IsNullOrEmpty(file))
            {
                throw new ArgumentNullException("file");
            }
            if (!System.IO.File.Exists(file))
            {
                throw new System.IO.FileNotFoundException("file", file);
            }

            this.File       = file;
            this.Flags      = flags;
            this.Supports3D = flags.HasFlag(SoundFlags.Support3D);
            this.IsStreamed = flags.HasFlag(SoundFlags.Streamed);
            this.AllowRead  = flags.HasFlag(SoundFlags.AllowRead);

            instances = new List <WeakReference <SoundInstance> >();

            if (!IsStreamed)
            {
                using (var source = SampleSourceFactory.FromFile(file))
                {
                    var bufferCount  = Supports3D ? source.Channels : 1;
                    var channelCount = Supports3D ? 1 : source.Channels;
                    var sampleRate   = source.SampleRate;
                    var samples      = source.ReadAll();

                    buffers = new List <AudioBuffer <short> >();
                    short[] samplesChannel = new short[samples.Length / bufferCount];
                    for (int i = 0; i < bufferCount; i++)
                    {
                        SampleConverter.To16Bit(samples, samplesChannel, i, bufferCount);
                        var buffer = new AudioBuffer <short>(audioDevice, !AllowRead);
                        buffer.SetData(AudioFormat.Short16, channelCount, samplesChannel, sampleRate);
                        buffers.Add(buffer);
                    }
                }
            }
        }
Beispiel #5
0
        protected override void On開始する()
        {
            // グローバルリソースを生成。(最低限。残りは起動ステージから グローバルリソースを生成する() が呼び出されたときに行われる。)

            App進行描画.乱数 = new Random(DateTime.Now.Millisecond);
            //App進行描画.システム設定 = システム設定.読み込む();   --> App() で初期化する。
            App進行描画.WAVキャッシュレンタル = new キャッシュデータレンタル <CSCore.ISampleSource>()
            {
                ファイルからデータを生成する = (path) => SampleSourceFactory.Create(App進行描画.サウンドデバイス, path, App進行描画.ユーザ管理.ログオン中のユーザ.再生速度),
            };
            App進行描画.サウンドデバイス = new サウンドデバイス(CSCore.CoreAudioAPI.AudioClientShareMode.Shared)
            {
                音量 = 0.5f, // マスタ音量(小:0~1:大)... 0.5を超えるとだいたいWASAPI共有モードのリミッターに抑制されるようになる
            };
            App進行描画.サウンドタイマ  = new SoundTimer(App進行描画.サウンドデバイス);
            App進行描画.ドラムサウンド  = new ドラムサウンド();
            App進行描画.システムサウンド = new システムサウンド();
            //App進行描画.システムサウンド.読み込む();  --> 起動ステージで行う。
            App進行描画.入力管理 = new 入力管理(this.AppForm.キーボード)
            {
                キーバインディングを取得する = () => App進行描画.システム設定.キー割り当て,
                キーバインディングを保存する = () => App進行描画.システム設定.保存する(),
            };
            App進行描画.入力管理.初期化する();
            App進行描画.ユーザ管理 = new ユーザ管理();
            App進行描画.ユーザ管理.ユーザリスト.SelectItem((user) => (user.ユーザID == "AutoPlayer"));        // ひとまずAutoPlayerを選択。


            // ステージを生成。(残りは起動ステージから グローバルリソースを生成する() が呼び出されたときにおこなれる。)

            this.起動ステージ         = new 起動.起動ステージ();
            this.演奏ステージ_ビュアーモード = new 演奏.演奏ステージ_ビュアーモード();


            // 最初のステージを設定し、活性化する。

            this.現在のステージ = this.起動ステージ;
            this.現在のステージ.活性化する();
        }
Beispiel #6
0
        protected override void On開始()
        {
            using (Log.Block(FDKUtilities.現在のメソッド名))
            {
                // グローバルリソースを生成。(最低限。残りは起動ステージから グローバルリソースを生成する() が呼び出されたときに行われる。)

                App進行描画.乱数 = new Random(DateTime.Now.Millisecond);
                //App進行描画.システム設定 = システム設定.読み込む();   --> App() で初期化する。
                App進行描画.WAVキャッシュレンタル = new キャッシュデータレンタル <CSCore.ISampleSource>()
                {
                    ファイルからデータを生成する = (path) => SampleSourceFactory.Create(App進行描画.サウンドデバイス, path, App進行描画.ユーザ管理.ログオン中のユーザ.再生速度),
                };
                App進行描画.サウンドデバイス    = new SoundDevice(CSCore.CoreAudioAPI.AudioClientShareMode.Shared);
                App進行描画.サウンドデバイス.音量 = 0.5f; // マスタ音量(小:0~1:大)... 0.5を超えるとだいたいWASAPI共有モードのリミッターに抑制されるようになる
                                            // ※↑「音量」はコンストラクタの実行後でないと set できないので、初期化子にはしないこと。(挙動は不明)

                App進行描画.サウンドタイマ  = new SoundTimer(App進行描画.サウンドデバイス);
                App進行描画.ドラムサウンド  = new ドラムサウンド();
                App進行描画.システムサウンド = new システムサウンド();
                //App進行描画.システムサウンド.読み込む();  --> 起動ステージで行う。
                App進行描画.入力管理  = new 入力管理(App進行描画.システム設定, this.AppForm.キーボード);
                App進行描画.ユーザ管理 = new ユーザ管理();
                App進行描画.ユーザ管理.ユーザリスト.SelectItem((user) => (user.ユーザID == "AutoPlayer"));        // ひとまずAutoPlayerを選択。


                // ステージを生成。(残りは起動ステージから グローバルリソースを生成する() が呼び出されたときにおこなれる。)

                this.起動ステージ         = new 起動.起動ステージ();
                this.演奏ステージ_ビュアーモード = new 演奏.演奏ステージ_ビュアーモード();


                // 最初のステージを設定し、活性化する。

                this.現在のステージ = this.起動ステージ;
                this.現在のステージ.活性化する();
            }
        }
Beispiel #7
0
            /// <summary>
            ///     <see cref="_音声ファイルパス"/>から、<see cref="_SampleSource"/>と<see cref="Sound"/> を生成する。
            /// </summary>
            private void _プレビュー音声を生成する()
            {
                if (null != this.Sound)
                {
                    return;  // 生成済み
                }
                // (1) サンプルソースを生成する。
                if (null == this._SampleSource)
                {
                    // 未生成の場合、生成する。
                    this._SampleSource = SampleSourceFactory.Create(
                        App進行描画.サウンドデバイス,
                        new VariablePath(this._音声ファイルパス).数なしパス,
                        再生速度: 1.0);    // プレビューは常に再生速度 = 1.0

                    if (null == this._SampleSource)
                    {
                        return;
                    }
                }

                // (2) サンプルソースからサウンドを生成する。
                this.Sound = new Sound(App進行描画.サウンドデバイス, this._SampleSource);
            }
        protected override void On活性化(グラフィックデバイス gd)
        {
            using (Log.Block(FDKUtilities.現在のメソッド名))
            {
                Debug.Assert(null != App.演奏スコア, "演奏スコアが指定されていません。");

                this.キャプチャ画面 = null;

                this.成績 = new 成績();
                this.成績.スコアと設定を反映する(App.演奏スコア, App.ユーザ管理.ログオン中のユーザ);

                this._描画開始チップ番号            = -1;
                this._小節線色                 = new SolidColorBrush(gd.D2DDeviceContext, Color.White);
                this._拍線色                  = new SolidColorBrush(gd.D2DDeviceContext, Color.LightGray);
                this._ドラムチップ画像の矩形リスト       = new 矩形リスト(@"$(System)images\ドラムチップ矩形.xml");                  // デバイスリソースは持たないので、子Activityではない。
                this._現在進行描画中の譜面スクロール速度の倍率 = App.ユーザ管理.ログオン中のユーザ.譜面スクロール速度;
                this._ドラムチップアニメ            = new LoopCounter(0, 200, 3);
                this._背景動画                 = null;
                this._BGM                  = null;
                this._背景動画開始済み             = false;
                this._BGM再生開始済み            = false;
                //this._デコード済みWaveSource = null;	--> キャッシュなので消さない。
                this._プレイヤー名表示.前 = App.ユーザ管理.ログオン中のユーザ.ユーザ名;

                this._チップの演奏状態 = new Dictionary <チップ, チップの演奏状態>();
                foreach (var chip in App.演奏スコア.チップリスト)
                {
                    this._チップの演奏状態.Add(chip, new チップの演奏状態(chip));
                }

                if (null != App.演奏スコア)
                {
                    #region " 背景動画とBGMを生成する。"
                    //----------------
                    if (App.演奏スコア.背景動画ファイル名.Nullでも空でもない())
                    {
                        #region " (A) SST準拠の動画とBGM "
                        //----------------
                        Log.Info("背景動画とBGMを読み込みます。");

                        // 動画を子リストに追加。
                        this.子リスト.Add(this._背景動画 = new 動画(App.演奏スコア.背景動画ファイル名));

                        // 動画から音声パートを抽出して BGM を作成。
                        try
                        {
                            this._デコード済みWaveSource?.Dispose();
                            this._デコード済みWaveSource = SampleSourceFactory.Create(App.サウンドデバイス, App.演奏スコア.背景動画ファイル名);

                            this._BGM?.Dispose();
                            this._BGM = new Sound(App.サウンドデバイス, this._デコード済みWaveSource);
                        }
                        catch (InvalidDataException)
                        {
                            // DTXの動画のようにサウンドを含まない動画の場合、この例外が発生するだろう。
                            Log.WARNING("背景動画ファイルからBGMを生成することに失敗しました。");
                            this._BGM = null;
                        }
                        //----------------
                        #endregion
                    }
                    else if (0 < App.演奏スコア.dicAVI.Count)
                    {
                        #region " (B) DTX準拠の動画 "
                        //----------------
                        Log.Info("背景動画を読み込みます。");

                        // #AVIzz がいくつ宣言されてても、最初のAVIだけを対象とする。
                        var path = Path.Combine(App.演奏スコア.PATH_WAV, App.演奏スコア.dicAVI.ElementAt(0).Value);

                        // 動画を子リストに追加。
                        this.子リスト.Add(this._背景動画 = new 動画(path));

                        // BGM パートは使わない。
                        this._BGM = null;
                        //----------------
                        #endregion
                    }
                    else
                    {
                        Log.Info("背景動画とBGMはありません。");
                    }
                    //----------------
                    #endregion

                    #region " WAVを生成する(ある場合)。"
                    //----------------
                    App.WAV管理 = new 曲.WAV管理();

                    foreach (var kvp in App.演奏スコア.dicWAV)
                    {
                        var path = Path.Combine(App.演奏スコア.PATH_WAV, kvp.Value.ファイルパス);
                        App.WAV管理.登録する(App.サウンドデバイス, kvp.Key, path.ToVariablePath(), kvp.Value.多重再生する);
                    }
                    //----------------
                    #endregion
                }

                this.現在のフェーズ   = フェーズ.フェードイン;
                this._初めての進行描画 = true;
            }
        }
Beispiel #9
0
        internal SoundInstance(AudioDevice audioDevice, Sound sound)  : base(audioDevice)
        {
            if (sound == null)
            {
                throw new ArgumentNullException("sound");
            }
            if (sound.IsDisposed)
            {
                throw new ArgumentException("Sound is disposed.", "sound");
            }

            this.Sound = sound;

            IDs = new List <int>();
            if (sound.IsStreamed)
            {
                source = SampleSourceFactory.FromFile(sound.File);
            }
            int bufferCount;

            if (sound.IsStreamed)
            {
                bufferCount = sound.Supports3D ? source.Channels : 1;
            }
            else
            {
                bufferCount = sound.Buffers.Count;
            }

            IDs.AddRange(AL.GenSources(bufferCount));
            DotGame.OpenAL.AudioDevice.CheckALError();

            if (sound.IsStreamed)
            {
                ringbuffers = new AudioBuffer <short> [bufferCount, RINGBUFFER_COUNT];
                for (int i = 0; i < bufferCount; i++)
                {
                    for (int j = 0; j < RINGBUFFER_COUNT; j++)
                    {
                        ringbuffers[i, j] = new AudioBuffer <short>(AudioDeviceInternal, false);
                    }
                }
                ringBufferIndex = 0;
            }
            else
            {
                var buffers = sound.Buffers;
                for (int i = 0; i < buffers.Count; i++)
                {
                    AL.Source(IDs[i], ALSourcei.Buffer, buffers[i].ID);
                    DotGame.OpenAL.AudioDevice.CheckALError();
                }
            }

            if (AudioDevice.Capabilities.SupportsEfx)
            {
                directFilter = AudioDeviceInternal.Efx.GenFilter();
                AudioDeviceInternal.Efx.Filter(directFilter, EfxFilteri.FilterType, (int)EfxFilterType.Lowpass);
                Set(ALSourcei.EfxDirectFilter, directFilter);
            }

            sound.Register(this);
        }