OSDN Git Service

43ed9dc73b9247be0c8391b772fd768112a99bc5
[dtxmania/dtxmania.git] / FDK / コード / 06.Tempo / CBeatDetect.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Diagnostics;
5 using System.Threading;
6 using Un4seen.Bass;
7 //using Un4seen.BassAsio;
8 //using Un4seen.BassWasapi;
9 //using Un4seen.Bass.AddOn.Mix;
10 using Un4seen.Bass.AddOn.Fx;
11
12 namespace FDK
13 {
14         public class CBeatDetect : IDisposable
15         {
16                 public struct stBeatPos
17                 {
18                         public float fBeatTime;
19                         public int n小節番号;
20                         public int nGrid;
21                         public int n小節内Grid;
22                         public bool b無効;                                    // 
23                         public bool bレーン表示する;             // 未使用
24
25                         public stBeatPos( float _fBeatTime, int _n小節番号, int _nGrid, int _n小節内Grid, bool _b無効, bool _bレーン表示する )
26                         {
27                                 fBeatTime = _fBeatTime;
28                                 n小節番号 = _n小節番号;
29                                 nGrid = _nGrid;
30                                 n小節内Grid = _n小節内Grid;
31                                 b無効 = _b無効;
32                                 bレーン表示する= _bレーン表示する;
33                         }
34                 }
35
36                 #region [ コンストラクタ ]
37                 public CBeatDetect()
38                 {
39                         Initialize();
40                 }
41                 public CBeatDetect( string _filename )
42                 {
43                         this.filename = _filename;
44                         Initialize();
45                 }
46                 #endregion
47                 #region [ 初期化(コンストラクタから呼び出される) ]
48                 private void Initialize()
49                 {
50                         if ( this.listBeatPositions == null )
51                         {
52                                 this.listBeatPositions = new List<stBeatPos>();
53                         }
54
55                         #region [ BASS registration ]
56                         // BASS.NET ユーザ登録(BASSスプラッシュが非表示になる)。
57
58                         BassNet.Registration( "dtx2013@gmail.com", "2X9181017152222" );
59                         #endregion
60                         #region [ BASS Version Check ]
61                         // BASS のバージョンチェック。
62                         int nBASSVersion = Utils.HighWord( Bass.BASS_GetVersion() );
63                         if ( nBASSVersion != Bass.BASSVERSION )
64                                 throw new DllNotFoundException( string.Format( "bass.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSVersion, Bass.BASSVERSION ) );
65
66                         int nBASSFXVersion = Utils.HighWord( BassFx.BASS_FX_GetVersion() );
67                         if ( nBASSFXVersion != BassFx.BASSFXVERSION )
68                                 throw new DllNotFoundException( string.Format( "bass_fx.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSFXVersion, BassFx.BASSFXVERSION ) );
69                         #endregion
70
71                         #region [ BASS の設定。]
72                         //this.bIsBASSFree = true;
73                         //Debug.Assert( Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 ),          // 0:BASSストリームの自動更新を行わない。(サウンド出力しないため)
74                         //    string.Format( "BASS_SetConfig() に失敗しました。[{0}", Bass.BASS_ErrorGetCode() ) );
75                         #endregion
76                         #region [ BASS の初期化。]
77                         int nデバイス = 0;          // 0:"no sound" … BASS からはデバイスへアクセスさせない。
78                         //int nデバイス = -1;               // 0:"no sound" … BASS からはデバイスへアクセスさせない。
79                         int n周波数 = 44100; // 仮決め。lデバイス(≠ドライバ)がネイティブに対応している周波数であれば何でもいい?ようだ。いずれにしろBASSMXで自動的にリサンプリングされる。
80                         if ( !Bass.BASS_Init( nデバイス, n周波数, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero ) )
81                                 throw new Exception( string.Format( "BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.BASS_ErrorGetCode().ToString() ) );
82                         #endregion
83
84                         #region [ 指定されたサウンドファイルをBASSでオープンし、必要最小限の情報を取得する。]
85                         //this.hBassStream = Bass.BASS_StreamCreateFile( this.filename, 0, 0, BASSFlag.BASS_STREAM_PRESCAN | BASSFlag.BASS_STREAM_DECODE );
86                         this.hBassStream = Bass.BASS_StreamCreateFile( this.filename, 0, 0, BASSFlag.BASS_STREAM_DECODE );
87                         //this.hBassStream = Bass.BASS_StreamCreateFile( this.filename, 0, 0, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN );
88                         if ( this.hBassStream == 0 )
89                                 throw new Exception( string.Format( "{0}: サウンドストリームの生成に失敗しました。(BASS_StreamCreateFile)[{1}]", filename, Bass.BASS_ErrorGetCode().ToString() ) );
90
91                         this.nTotalBytes = Bass.BASS_ChannelGetLength( this.hBassStream );
92
93                         this.nTotalSeconds = Bass.BASS_ChannelBytes2Seconds( this.hBassStream, nTotalBytes );
94                         if ( !Bass.BASS_ChannelGetAttribute( this.hBassStream, BASSAttribute.BASS_ATTRIB_FREQ, ref fFreq ) )
95                         {
96                                 string errmes = string.Format( "サウンドストリームの周波数取得に失敗しました。(BASS_ChannelGetAttribute)[{0}]", Bass.BASS_ErrorGetCode().ToString() );
97                                 Bass.BASS_Free();
98                                 throw new Exception( errmes );
99                         }
100
101
102
103                         int bs = Bass.BASS_ChannelSetFX( this.hBassStream, BASSFXType.BASS_FX_BFX_BQF, 1 );
104
105                         BASS_BFX_BQF param = new BASS_BFX_BQF(
106                                 BASSBFXBQF.BASS_BFX_BQF_LOWPASS,        // filter
107                                 800.0f,                                                         // center       default=200
108                                 15,                                                                     // gain deafult=0
109                                 0,                                                                      // bandwidth
110                                 1,      //0.67f,                                                                        // Q
111                                 0,                                                                      // s
112                                 BASSFXChan.BASS_BFX_CHANALL                     //chans
113                         );
114
115                         bool b = Bass.BASS_FXSetParameters( bs, param );
116                         if ( b == false )
117                         {
118                                 Debug.WriteLine( "effect set failed: " + Bass.BASS_ErrorGetCode().ToString() );
119                         }
120                         //bool b2 = Bass.BASS_ChannelPlay( this.hBassStream, false );
121                         //if ( b2 == false )
122                         //{
123                         //    Debug.WriteLine( "plyback failed: " + Bass.BASS_ErrorGetCode().ToString() );
124                         //}
125                         #endregion
126                 }
127                 #endregion
128
129                 /// <summary>
130                 /// 曲全体のテンポを取得する
131                 /// </summary>
132                 /// <returns>テンポ値</returns>
133                 /// <remarks>テンポ値の範囲は70-300</remarks>
134                 public float GetTempo()
135                 {
136                         fTempo = BassFx.BASS_FX_BPM_DecodeGet(
137                                 this.hBassStream,
138                                 0,
139                                 nTotalSeconds,
140                                 ( 300 << 16 ) + 70,             // MAX BPM=320, MIN BPM=70
141                                 //0,
142                                 BASSFXBpm.BASS_FX_BPM_DEFAULT,          //BASSFXBpm.BASS_FX_BPM_MULT2,
143                                 null,
144                                 IntPtr.Zero );
145                         return fTempo;
146                 }
147                 /// <summary>
148                 /// 曲の一部分のテンポを取得する
149                 /// </summary>
150                 /// <param name="startSec">開始位置</param>
151                 /// <param name="endSec">終了位置</param>
152                 /// <returns>テンポ値</returns>
153                 /// <remarks>テンポ値の範囲は70-300</remarks>
154                 public float GetTempo( double startSec, double endSec )
155                 {
156                         fTempo = BassFx.BASS_FX_BPM_DecodeGet(
157                                 this.hBassStream,
158                                 startSec,
159                                 endSec,
160                                 ( 300 << 16 ) + 70,             // MAX BPM=320, MIN BPM=70
161                                 //0,
162                                 BASSFXBpm.BASS_FX_BPM_DEFAULT,          //BASSFXBpm.BASS_FX_BPM_MULT2,
163                                 null,
164                                 IntPtr.Zero );
165                         return fTempo;
166                 }
167
168
169                 /// <summary>
170                 /// Beatの検出位置をListで返す
171                 /// </summary>
172                 /// <returns>Beat検出位置群</returns>
173                 public List<stBeatPos> GetBeatPositions()
174                 {
175                         #region [  BeatPosition格納リストの初期化 ]
176                         if ( this.listBeatPositions != null )
177                         {
178                                 this.listBeatPositions.Clear();
179                         }
180                         else
181                         {
182                                 this.listBeatPositions = new List<stBeatPos>();
183                         }
184                         #endregion
185
186                         BPMBEATPROC _beatProc = new BPMBEATPROC( GetBeat_ProgressCallback );
187
188                         //
189                         //
190                         // LPFを通してから、BeatDecodeGetしてみること。
191                         //
192                         //
193
194                         bool ret = BassFx.BASS_FX_BPM_BeatDecodeGet(
195                                 this.hBassStream,
196                                 0,
197                                 nTotalSeconds,
198                                 //0,
199                                 BASSFXBpm.BASS_FX_BPM_DEFAULT,          //BASSFXBpm.BASS_FX_BPM_MULT2,
200                                 _beatProc,
201                                 IntPtr.Zero );
202
203                         return this.listBeatPositions;
204                 }
205
206                 private void GetBeat_ProgressCallback( int channel, double beatpos, IntPtr user )
207                 {
208                         stBeatPos sbp = new stBeatPos(
209                                 (float) beatpos,
210                                 0,
211                                 0,
212                                 0,
213                                 false,
214                                 true
215                         );                              
216                                 
217
218                         listBeatPositions.Add( sbp );
219 //                      Debug.WriteLine( "Beat at: " + beatpos.ToString() );
220                 }
221
222
223         
224                 
225                 public void Dispose()   // 使い終わったら必ずDispose()すること。BASSのリソースを握りっぱなしにすると、他の再生に不都合が生じるため。
226                 {
227                         BassFx.BASS_FX_BPM_Free( this.hBassStream );
228                         Bass.BASS_StreamFree( this.hBassStream );
229                         this.hBassStream = -1;
230                         Bass.BASS_Free();
231                 }
232         
233                 // =============
234                 private string filename = "";
235                 private int hBassStream = -1;
236                 private long nTotalBytes = 0;
237                 private double nTotalSeconds = 0.0f;
238                 private float fFreq = 0.0f;
239                 private float fTempo;
240                 private List<stBeatPos> listBeatPositions = null;
241         }
242 }