OSDN Git Service

c9c99660c5d8f9eb2a26b996832d82a658ee87a4
[strokestylet/CsWin10Desktop3.git] / FDK24 / メディア / サウンド / WASAPI / Mixer.cs
1 using System;
2 using System.Collections.Generic;
3
4 namespace FDK.メディア.サウンド.WASAPI
5 {
6         /// <summary>
7         /// Sound のリストを持ち、そのサウンドデータを合成してWASAPIデバイスへ出力するミキサー。
8         /// </summary>
9         public unsafe class Mixer : IDisposable
10         {
11                 public Mixer()
12                 {
13                 }
14                 public Mixer( int エンドポイントバッファサイズsample ) : this()
15                 {
16                         this.初期化する( エンドポイントバッファサイズsample );
17                 }
18                 public void 初期化する( int エンドポイントバッファサイズsample )
19                 {
20                         lock( this.スレッド間同期 )
21                         {
22                                 if( エンドポイントバッファサイズsample == this.エンドポイントバッファサイズsample )
23                                         return;     // サイズに変更があったときのみ初期化する。
24
25                                 this.エンドポイントバッファサイズsample = エンドポイントバッファサイズsample;
26                                 this.サウンドリスト.Clear();
27
28                                 if( null != this.合成用バッファ )
29                                         FDK.Memory.Free( this.合成用バッファ );
30                                 this.合成用バッファ = FDK.Memory.Alloc( this.エンドポイントバッファサイズsample * ( 4 * 2 ) );       // 1sample = 32bit×2ch
31                         }
32                 }
33                 public void Dispose()
34                 {
35                         lock( this.スレッド間同期 )
36                         {
37                                 this.サウンドリスト.Clear();
38                                 if( null != this.合成用バッファ )
39                                 {
40                                         FDK.Memory.Free( this.合成用バッファ );
41                                         this.合成用バッファ = null;
42                                 }
43                                 this.エンドポイントバッファサイズsample = -1;
44                         }
45                 }
46                 public void サウンドリストをクリアする()
47                 {
48                         lock( this.スレッド間同期 )
49                         {
50                                 this.サウンドリスト.Clear();
51                         }
52                 }
53                 public void サウンドを追加する( Sound sound )
54                 {
55                         lock( this.スレッド間同期 )
56                         {
57                                 this.サウンドリスト.Add( sound );
58                         }
59                 }
60                 public void サウンドを削除する( Sound sound )
61                 {
62                         lock( this.スレッド間同期 )
63                         {
64                                 this.サウンドリスト.Remove( sound );
65                         }
66                 }
67                 public CSCore.CoreAudioAPI.AudioClientBufferFlags エンドポイントへ出力する( void* エンドポイントの出力先, int 出力数sample )
68                 {
69                         lock( this.スレッド間同期 )
70                         {
71                                 if( null == this.合成用バッファ )
72                                         return CSCore.CoreAudioAPI.AudioClientBufferFlags.Silent;
73
74                                 #region " すべてのサウンドについて、合成バッファへ出力する。"
75                                 //-----------------
76                                 bool 最初の出力である = true;
77
78                                 foreach( var sound in this.サウンドリスト )
79                                 {
80                                         var flag = sound.次のサウンドデータを出力する( this.合成用バッファ, 出力数sample, 最初の出力である );
81
82                                         if( false == flag.HasFlag( CSCore.CoreAudioAPI.AudioClientBufferFlags.Silent ) )
83                                                 最初の出力である = false;   // sound が何らかのデータを出力した(戻り値がSILENTじゃなかった)
84                                 }
85
86                                 // 全サウンドが SILENT だったなら、エンドポイントには何も書き込まずに SILENT フラグを返す。
87                                 if( 最初の出力である )
88                                         return CSCore.CoreAudioAPI.AudioClientBufferFlags.Silent;
89                                 //-----------------
90                                 #endregion
91                                 #region " 合成バッファのデータ値(32bit;オーバーサンプル)を16bitに丸めてエンドポイントに出力する。"
92                                 //-----------------
93                                 Int32* 出力元 = (Int32*) ( this.合成用バッファ );
94                                 Int16* 出力先 = (Int16*) エンドポイントの出力先;
95                                 for( int i = 0; i < 出力数sample; i++ )
96                                 {
97                                         Int32 src;
98
99                                         // 音量やミュートの処理は不要。(WASAPI が自動でマスタ音量・ミュート状態に合わせてくれる)
100
101                                         // 左ch
102                                         src = *出力元++;
103                                         if( -32768 > src )
104                                                 src = -32768;
105                                         else if( 32767 < src )
106                                                 src = 32767;
107                                         *出力先++ = (Int16) src;
108
109                                         // 右ch
110                                         src = *出力元++;
111                                         if( -32768 > src )
112                                                 src = -32768;
113                                         else if( 32767 < src )
114                                                 src = 32767;
115                                         *出力先++ = (Int16) src;
116                                 }
117                                 //-----------------
118                                 #endregion
119                         }
120                         return CSCore.CoreAudioAPI.AudioClientBufferFlags.None;
121                 }
122
123                 private int エンドポイントバッファサイズsample = -1;
124                 private readonly List<Sound> サウンドリスト = new List<Sound>();
125                 private void* 合成用バッファ = null;
126                 private readonly object スレッド間同期 = new object();
127         }
128 }