--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Diagnostics;
+using System.Threading;
+using Un4seen.Bass;
+//using Un4seen.BassAsio;
+//using Un4seen.BassWasapi;
+//using Un4seen.Bass.AddOn.Mix;
+using Un4seen.Bass.AddOn.Fx;
+
+namespace FDK
+{
+ public class CBeatDetect : IDisposable
+ {
+ public struct stBeatPos
+ {
+ public float fBeatTime;
+ public int n小節番号;
+ public int nGrid;
+ public int n小節内Grid;
+ public bool b無効; //
+ public bool bレーン表示する; // 未使用
+
+ public stBeatPos( float _fBeatTime, int _n小節番号, int _nGrid, int _n小節内Grid, bool _b無効, bool _bレーン表示する )
+ {
+ fBeatTime = _fBeatTime;
+ n小節番号 = _n小節番号;
+ nGrid = _nGrid;
+ n小節内Grid = _n小節内Grid;
+ b無効 = _b無効;
+ bレーン表示する= _bレーン表示する;
+ }
+ }
+
+ #region [ コンストラクタ ]
+ public CBeatDetect()
+ {
+ Initialize();
+ }
+ public CBeatDetect( string _filename )
+ {
+ this.filename = _filename;
+ Initialize();
+ }
+ #endregion
+ #region [ 初期化(コンストラクタから呼び出される) ]
+ private void Initialize()
+ {
+ if ( this.listBeatPositions == null )
+ {
+ this.listBeatPositions = new List<stBeatPos>();
+ }
+
+ #region [ BASS registration ]
+ // BASS.NET ユーザ登録(BASSスプラッシュが非表示になる)。
+
+ BassNet.Registration( "dtx2013@gmail.com", "2X9181017152222" );
+ #endregion
+ #region [ BASS Version Check ]
+ // BASS のバージョンチェック。
+ int nBASSVersion = Utils.HighWord( Bass.BASS_GetVersion() );
+ if ( nBASSVersion != Bass.BASSVERSION )
+ throw new DllNotFoundException( string.Format( "bass.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSVersion, Bass.BASSVERSION ) );
+
+ int nBASSFXVersion = Utils.HighWord( BassFx.BASS_FX_GetVersion() );
+ if ( nBASSFXVersion != BassFx.BASSFXVERSION )
+ throw new DllNotFoundException( string.Format( "bass_fx.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSFXVersion, BassFx.BASSFXVERSION ) );
+ #endregion
+
+ #region [ BASS の設定。]
+ //this.bIsBASSFree = true;
+ //Debug.Assert( Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 ), // 0:BASSストリームの自動更新を行わない。(サウンド出力しないため)
+ // string.Format( "BASS_SetConfig() に失敗しました。[{0}", Bass.BASS_ErrorGetCode() ) );
+ #endregion
+ #region [ BASS の初期化。]
+ int nデバイス = 0; // 0:"no sound" … BASS からはデバイスへアクセスさせない。
+ //int nデバイス = -1; // 0:"no sound" … BASS からはデバイスへアクセスさせない。
+ int n周波数 = 44100; // 仮決め。lデバイス(≠ドライバ)がネイティブに対応している周波数であれば何でもいい?ようだ。いずれにしろBASSMXで自動的にリサンプリングされる。
+ if ( !Bass.BASS_Init( nデバイス, n周波数, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero ) )
+ throw new Exception( string.Format( "BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.BASS_ErrorGetCode().ToString() ) );
+ #endregion
+
+ #region [ 指定されたサウンドファイルをBASSでオープンし、必要最小限の情報を取得する。]
+ //this.hBassStream = Bass.BASS_StreamCreateFile( this.filename, 0, 0, BASSFlag.BASS_STREAM_PRESCAN | BASSFlag.BASS_STREAM_DECODE );
+ this.hBassStream = Bass.BASS_StreamCreateFile( this.filename, 0, 0, BASSFlag.BASS_STREAM_DECODE );
+ //this.hBassStream = Bass.BASS_StreamCreateFile( this.filename, 0, 0, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN );
+ if ( this.hBassStream == 0 )
+ throw new Exception( string.Format( "{0}: サウンドストリームの生成に失敗しました。(BASS_StreamCreateFile)[{1}]", filename, Bass.BASS_ErrorGetCode().ToString() ) );
+
+ this.nTotalBytes = Bass.BASS_ChannelGetLength( this.hBassStream );
+
+ this.nTotalSeconds = Bass.BASS_ChannelBytes2Seconds( this.hBassStream, nTotalBytes );
+ if ( !Bass.BASS_ChannelGetAttribute( this.hBassStream, BASSAttribute.BASS_ATTRIB_FREQ, ref fFreq ) )
+ {
+ string errmes = string.Format( "サウンドストリームの周波数取得に失敗しました。(BASS_ChannelGetAttribute)[{0}]", Bass.BASS_ErrorGetCode().ToString() );
+ Bass.BASS_Free();
+ throw new Exception( errmes );
+ }
+
+
+
+ int bs = Bass.BASS_ChannelSetFX( this.hBassStream, BASSFXType.BASS_FX_BFX_BQF, 1 );
+
+ BASS_BFX_BQF param = new BASS_BFX_BQF(
+ BASSBFXBQF.BASS_BFX_BQF_LOWPASS, // filter
+ 800.0f, // center default=200
+ 15, // gain deafult=0
+ 0, // bandwidth
+ 1, //0.67f, // Q
+ 0, // s
+ BASSFXChan.BASS_BFX_CHANALL //chans
+ );
+
+ bool b = Bass.BASS_FXSetParameters( bs, param );
+ if ( b == false )
+ {
+ Debug.WriteLine( "effect set failed: " + Bass.BASS_ErrorGetCode().ToString() );
+ }
+ //bool b2 = Bass.BASS_ChannelPlay( this.hBassStream, false );
+ //if ( b2 == false )
+ //{
+ // Debug.WriteLine( "plyback failed: " + Bass.BASS_ErrorGetCode().ToString() );
+ //}
+ #endregion
+ }
+ #endregion
+
+ /// <summary>
+ /// 曲全体のテンポを取得する
+ /// </summary>
+ /// <returns>テンポ値</returns>
+ /// <remarks>テンポ値の範囲は70-300</remarks>
+ public float GetTempo()
+ {
+ fTempo = BassFx.BASS_FX_BPM_DecodeGet(
+ this.hBassStream,
+ 0,
+ nTotalSeconds,
+ ( 300 << 16 ) + 70, // MAX BPM=320, MIN BPM=70
+ //0,
+ BASSFXBpm.BASS_FX_BPM_DEFAULT, //BASSFXBpm.BASS_FX_BPM_MULT2,
+ null,
+ IntPtr.Zero );
+ return fTempo;
+ }
+ /// <summary>
+ /// 曲の一部分のテンポを取得する
+ /// </summary>
+ /// <param name="startSec">開始位置</param>
+ /// <param name="endSec">終了位置</param>
+ /// <returns>テンポ値</returns>
+ /// <remarks>テンポ値の範囲は70-300</remarks>
+ public float GetTempo( double startSec, double endSec )
+ {
+ fTempo = BassFx.BASS_FX_BPM_DecodeGet(
+ this.hBassStream,
+ startSec,
+ endSec,
+ ( 300 << 16 ) + 70, // MAX BPM=320, MIN BPM=70
+ //0,
+ BASSFXBpm.BASS_FX_BPM_DEFAULT, //BASSFXBpm.BASS_FX_BPM_MULT2,
+ null,
+ IntPtr.Zero );
+ return fTempo;
+ }
+
+
+ /// <summary>
+ /// Beatの検出位置をListで返す
+ /// </summary>
+ /// <returns>Beat検出位置群</returns>
+ public List<stBeatPos> GetBeatPositions()
+ {
+ #region [ BeatPosition格納リストの初期化 ]
+ if ( this.listBeatPositions != null )
+ {
+ this.listBeatPositions.Clear();
+ }
+ else
+ {
+ this.listBeatPositions = new List<stBeatPos>();
+ }
+ #endregion
+
+ BPMBEATPROC _beatProc = new BPMBEATPROC( GetBeat_ProgressCallback );
+
+ //
+ //
+ // LPFを通してから、BeatDecodeGetしてみること。
+ //
+ //
+
+ bool ret = BassFx.BASS_FX_BPM_BeatDecodeGet(
+ this.hBassStream,
+ 0,
+ nTotalSeconds,
+ //0,
+ BASSFXBpm.BASS_FX_BPM_DEFAULT, //BASSFXBpm.BASS_FX_BPM_MULT2,
+ _beatProc,
+ IntPtr.Zero );
+
+ return this.listBeatPositions;
+ }
+
+ private void GetBeat_ProgressCallback( int channel, double beatpos, IntPtr user )
+ {
+ stBeatPos sbp = new stBeatPos(
+ (float) beatpos,
+ 0,
+ 0,
+ 0,
+ false,
+ true
+ );
+
+
+ listBeatPositions.Add( sbp );
+// Debug.WriteLine( "Beat at: " + beatpos.ToString() );
+ }
+
+
+
+
+ public void Dispose() // 使い終わったら必ずDispose()すること。BASSのリソースを握りっぱなしにすると、他の再生に不都合が生じるため。
+ {
+ BassFx.BASS_FX_BPM_Free( this.hBassStream );
+ Bass.BASS_StreamFree( this.hBassStream );
+ this.hBassStream = -1;
+ Bass.BASS_Free();
+ }
+
+ // =============
+ private string filename = "";
+ private int hBassStream = -1;
+ private long nTotalBytes = 0;
+ private double nTotalSeconds = 0.0f;
+ private float fFreq = 0.0f;
+ private float fTempo;
+ private List<stBeatPos> listBeatPositions = null;
+ }
+}