OSDN Git Service

#28821 DTXMania: rev701でのworkaroundを削除。
authoryyagi <yyagi@16f42ceb-6dc6-49c8-ba94-f2d53467949d>
Mon, 14 Apr 2014 16:56:55 +0000 (16:56 +0000)
committeryyagi <yyagi@16f42ceb-6dc6-49c8-ba94-f2d53467949d>
Mon, 14 Apr 2014 16:56:55 +0000 (16:56 +0000)
#28821 DTXMania: 再生速度を落としている場合に、mp3で音が途中で切れることがある問題の修正。mp3のサイズ取得方法を変更した。
更に、mp3をBASSでストリーム再生せずに、オンメモリでデコードして再生するためのオプションを追加(Config.ini の、 NoMP3Streaming)。 特殊なmp3を使用すると、シーク位置がおかしくなる場合があるため。

git-svn-id: http://svn.osdn.jp/svnroot/dtxmania/branches/140113(DTXMania098%20with%2028821%20DTXVmode)@702 16f42ceb-6dc6-49c8-ba94-f2d53467949d

DTXManiaプロジェクト/コード/全体/CConfigIni.cs
DTXManiaプロジェクト/コード/全体/CDTXMania.cs
FDK17プロジェクト/コード/03.サウンド/CSound.cs
実行時フォルダ(DTXCreator)/dll/FDK.dll
実行時フォルダ/DTXManiaGR.exe
実行時フォルダ/dll/FDK.dll

index 4ed66cb..ffeba64 100644 (file)
@@ -675,6 +675,7 @@ namespace DTXMania
                public bool bViewerShowDebugStatus;\r
                public bool bViewerTimeStretch;\r
                public bool bViewerDrums有効, bViewerGuitar有効;\r
+               public bool bNoMP3Streaming;                            // 2014.4.14 yyagi; mp3のシーク位置がおかしくなる場合は、これをtrueにすることで、wavにデコードしてからオンメモリ再生する\r
 #if false\r
                [StructLayout( LayoutKind.Sequential )]\r
                public struct STAUTOPLAY                                                                // C定数のEレーンとindexを一致させること\r
@@ -1174,6 +1175,8 @@ namespace DTXMania
                        bViewerTimeStretch = false;\r
                        bViewerDrums有効 = true;\r
                        bViewerGuitar有効 = true;\r
+\r
+                       this.bNoMP3Streaming = false;\r
                }\r
                public CConfigIni( string iniファイル名 )\r
                        : this()\r
@@ -1523,6 +1526,13 @@ namespace DTXMania
                        sw.WriteLine( "; (Only available when you're using using WASAPI or ASIO)" );    //\r
                        sw.WriteLine( "TimeStretch={0}", this.bTimeStretch ? 1 : 0 );                                   //\r
                        sw.WriteLine();\r
+                       sw.WriteLine( "; WASAPI/ASIO使用時に、MP3をストリーム再生するかどうか(0:ストリーム再生する, 1:しない" );                 //\r
+                       sw.WriteLine( "; (mp3のシークがおかしくなる場合は、これを1にしてください) " ); //\r
+                       sw.WriteLine( "; Set \"0\" if you'd like to use mp3 streaming playback on WASAPI/ASIO." );              //\r
+                       sw.WriteLine( "; Set \"1\" not to use streaming playback for mp3." );                   //\r
+                       sw.WriteLine( "; (If you feel illegal seek with mp3, please set it to 1.)" );   //\r
+                       sw.WriteLine( "NoMP3Streaming={0}", this.bNoMP3Streaming ? 1 : 0 );                             //\r
+                       sw.WriteLine();\r
                        #region [ Adjust ]\r
                        sw.WriteLine( "; 判定タイミング調整(ドラム, ギター, ベース)(-99~99)[ms]" );         // #23580 2011.1.3 yyagi\r
                        sw.WriteLine("; Revision value to adjust judgement timing for the drums, guitar and bass.");    //\r
@@ -2438,6 +2448,10 @@ namespace DTXMania
                                                                                                this.nVelocityMin.RD = C変換.n値を文字列から取得して範囲内に丸めて返す( str4, 0, 127, this.nVelocityMin.RD );\r
                                                                                        }\r
                                                                                        #endregion\r
+                                                                                       else if ( str3.Equals( "NoMP3Streaming" ) )\r
+                                                                                       {\r
+                                                                                               this.bNoMP3Streaming = C変換.bONorOFF( str4[ 0 ] );\r
+                                                                                       }\r
                                                                                        continue;\r
                                                                                }\r
                                                                        //-----------------------------\r
index eb02329..ae0c841 100644 (file)
@@ -2028,6 +2028,7 @@ for (int i = 0; i < 3; i++) {
        \r
                                ShowWindowTitleWithSoundType();\r
                                FDK.CSound管理.bIsTimeStretch = CDTXMania.ConfigIni.bTimeStretch;\r
+                               FDK.CSound管理.bIsMP3DecodeByWindowsCodec = CDTXMania.ConfigIni.bNoMP3Streaming;\r
                                Trace.TraceInformation( "サウンドデバイスの初期化を完了しました。" );\r
                        }\r
                        catch (Exception e)\r
index dee014d..a3d85ef 100644 (file)
@@ -34,6 +34,14 @@ namespace FDK
                public static IntPtr WindowHandle;\r
 \r
                public static bool bIsTimeStretch = false;\r
+\r
+               /// <summary>\r
+               /// BASS時、mp3をストリーミング再生せずに、デコードしたraw wavをオンメモリ再生する場合はtrueにする。\r
+               /// 特殊なmp3を使用時はシークが乱れるので、必要に応じてtrueにすること。(Config.iniのNoMP3Streamingで設定可能。)\r
+               /// ただし、trueにすると、その分再生開始までの時間が長くなる。\r
+               /// </summary>\r
+               public static bool bIsMP3DecodeByWindowsCodec = false;\r
+\r
                public static int nMixing = 0;\r
                public int GetMixingStreams()\r
                {\r
@@ -443,7 +451,7 @@ namespace FDK
 \r
                public bool b演奏終了後も再生が続くチップである = false;       // これがtrueなら、本サウンドの再生終了のコールバック時に自動でミキサーから削除する\r
 \r
-               private STREAMPROC _cbStreamXA;         // make it global, so that the GC can not remove it\r
+               //private STREAMPROC _cbStreamXA;               // make it global, so that the GC can not remove it\r
                private SYNCPROC _cbEndofStream;        // ストリームの終端まで再生されたときに呼び出されるコールバック\r
 //             private WaitCallback _cbRemoveMixerChannel;\r
 \r
@@ -617,22 +625,22 @@ namespace FDK
                }\r
                public void tASIOサウンドを作成する( string strファイル名, int hMixer )\r
                {\r
-                       this.tBASSサウンドを作成する( strファイル名, hMixer, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_LOOP );           // BASSFlag.BASS_SAMPLE_LOOP は、koh-heyさん指摘のmp3低速再生時に再生停止する問題のworkaround。\r
+                       this.tBASSサウンドを作成する( strファイル名, hMixer, BASSFlag.BASS_STREAM_DECODE );\r
                        this.eデバイス種別 = ESoundDeviceType.ASIO;               // 作成後に設定する。(作成に失敗してると例外発出されてここは実行されない)\r
                }\r
                public void tASIOサウンドを作成する( byte[] byArrWAVファイルイメージ, int hMixer )\r
                {\r
-                       this.tBASSサウンドを作成する( byArrWAVファイルイメージ, hMixer, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_LOOP );             // BASSFlag.BASS_SAMPLE_LOOP は、koh-heyさん指摘のmp3低速再生時に再生停止する問題のworkaround。\r
+                       this.tBASSサウンドを作成する( byArrWAVファイルイメージ, hMixer, BASSFlag.BASS_STREAM_DECODE );\r
                        this.eデバイス種別 = ESoundDeviceType.ASIO;               // 作成後に設定する。(作成に失敗してると例外発出されてここは実行されない)\r
                }\r
                public void tWASAPIサウンドを作成する( string strファイル名, int hMixer, ESoundDeviceType eデバイス種別 )\r
                {\r
-                       this.tBASSサウンドを作成する( strファイル名, hMixer, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_SAMPLE_LOOP );              // BASSFlag.BASS_SAMPLE_LOOP は、koh-heyさん指摘のmp3低速再生時に再生停止する問題のworkaround。\r
+                       this.tBASSサウンドを作成する( strファイル名, hMixer, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT );\r
                        this.eデバイス種別 = eデバイス種別;         // 作成後に設定する。(作成に失敗してると例外発出されてここは実行されない)\r
                }\r
                public void tWASAPIサウンドを作成する( byte[] byArrWAVファイルイメージ, int hMixer, ESoundDeviceType eデバイス種別 )\r
                {\r
-                       this.tBASSサウンドを作成する( byArrWAVファイルイメージ, hMixer, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_SAMPLE_LOOP );                // BASSFlag.BASS_SAMPLE_LOOP は、koh-heyさん指摘のmp3低速再生時に再生停止する問題のworkaround。\r
+                       this.tBASSサウンドを作成する( byArrWAVファイルイメージ, hMixer, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT );\r
                        this.eデバイス種別 = eデバイス種別;         // 作成後に設定する。(作成に失敗してると例外発出されてここは実行されない)\r
                }\r
                public void tDirectSoundサウンドを作成する( string strファイル名, DirectSound DirectSound )\r
@@ -713,7 +721,7 @@ namespace FDK
                        int nPCMサイズbyte;\r
                        CWin32.WAVEFORMATEX cw32wfx;\r
                        tオンメモリ方式でデコードする( strファイル名, out this.byArrWAVファイルイメージ,\r
-                       out nPCMデータの先頭インデックス, out nPCMサイズbyte, out cw32wfx );\r
+                       out nPCMデータの先頭インデックス, out nPCMサイズbyte, out cw32wfx, false );\r
 \r
                        wfx.AverageBytesPerSecond = (int) cw32wfx.nAvgBytesPerSec;\r
                        wfx.BitsPerSample = (short) cw32wfx.wBitsPerSample;\r
@@ -1073,7 +1081,12 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ
                {\r
                        if( this.bBASSサウンドである )\r
                        {\r
-                               BassMix.BASS_Mixer_ChannelSetPosition( this.hBassStream, Bass.BASS_ChannelSeconds2Bytes( this.hBassStream, n位置ms * this.db周波数倍率 * this.db再生速度 / 1000.0 ), BASSMode.BASS_POS_BYTES );\r
+                               bool b = BassMix.BASS_Mixer_ChannelSetPosition( this.hBassStream, Bass.BASS_ChannelSeconds2Bytes( this.hBassStream, n位置ms * this.db周波数倍率 * this.db再生速度 / 1000.0 ), BASSMode.BASS_POS_BYTES );\r
+                               if ( !b )\r
+                               {\r
+                                       BASSError be = Bass.BASS_ErrorGetCode();\r
+                                       Trace.TraceInformation( Path.GetFileName( this.strファイル名 ) + ": Seek error: " + be.ToString() );\r
+                               }\r
                        }\r
                        else if( this.bDirectSoundである )\r
                        {\r
@@ -1303,7 +1316,14 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ
                {\r
                        if ( String.Compare( Path.GetExtension( strファイル名 ), ".xa", true ) == 0 )      // caselessで文字列比較\r
                        {\r
-                               tBASSサウンドを作成するXA( strファイル名, hMixer, flags );\r
+                               tBASSサウンドを作成するXAmp3( strファイル名, hMixer, flags );\r
+                               return;\r
+                       }\r
+                       else if ( String.Compare( Path.GetExtension( strファイル名 ), ".mp3", true ) == 0 && CSound管理.bIsMP3DecodeByWindowsCodec )\r
+                       {\r
+                               // 特定mp3を特定低速度で再生させたときに音が途中で切れる問題(koh-heyさん問題)のworkaround。\r
+                               // mp3をオンメモリでwavにデコードして、再生してしまう。\r
+                               tBASSサウンドを作成するXAmp3( strファイル名, hMixer, flags );\r
                                return;\r
                        }\r
 \r
@@ -1338,14 +1358,14 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ
        \r
                        tBASSサウンドを作成する・ストリーム生成後の共通処理( hMixer );\r
                }\r
-               private void tBASSサウンドを作成するXA( string strファイル名, int hMixer, BASSFlag flags )\r
+               private void tBASSサウンドを作成するXAmp3( string strファイル名, int hMixer, BASSFlag flags )\r
                {\r
                        int nPCMデータの先頭インデックス;\r
                        CWin32.WAVEFORMATEX wfx;\r
                        int totalPCMSize;\r
 \r
                        tオンメモリ方式でデコードする( strファイル名, out this.byArrWAVファイルイメージ,\r
-                               out nPCMデータの先頭インデックス, out totalPCMSize, out wfx );\r
+                               out nPCMデータの先頭インデックス, out totalPCMSize, out wfx, true );\r
 \r
                        nBytes = totalPCMSize;\r
 \r
@@ -1354,12 +1374,13 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ
                        this.hGC = GCHandle.Alloc( this.byArrWAVファイルイメージ, GCHandleType.Pinned );                // byte[] をピン留め\r
 \r
 \r
-                       _cbStreamXA = new STREAMPROC( CallbackPlayingXA );\r
+                       //_cbStreamXA = new STREAMPROC( CallbackPlayingXA );\r
 \r
                        // BASSファイルストリームを作成。\r
 \r
                        //this.hBassStream = Bass.BASS_StreamCreate( xa.xaheader.nSamplesPerSec, xa.xaheader.nChannels, BASSFlag.BASS_STREAM_DECODE, _myStreamCreate, IntPtr.Zero );\r
-                       this._hBassStream = Bass.BASS_StreamCreate( (int) wfx.nSamplesPerSec, (int) wfx.nChannels, BASSFlag.BASS_STREAM_DECODE, _cbStreamXA, IntPtr.Zero );\r
+                       //this._hBassStream = Bass.BASS_StreamCreate( (int) wfx.nSamplesPerSec, (int) wfx.nChannels, BASSFlag.BASS_STREAM_DECODE, _cbStreamXA, IntPtr.Zero );\r
+                       this._hBassStream = Bass.BASS_StreamCreateFile( this.hGC.AddrOfPinnedObject(), 0L, nBytes, flags );\r
                        if ( this._hBassStream == 0 )\r
                        {\r
                                hGC.Free();\r
@@ -1408,7 +1429,9 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ
                        CSound.listインスタンス.Add( this );\r
 \r
                        // n総演奏時間の取得; DTXMania用に追加。\r
-                       double seconds = Bass.BASS_ChannelBytes2Seconds( this._hBassStream, nBytes );\r
+                       long length = Bass.BASS_ChannelGetLength( _hBassStream );                                               //\r
+                       double seconds = Bass.BASS_ChannelBytes2Seconds( this._hBassStream, length );   //\r
+                       //double seconds = Bass.BASS_ChannelBytes2Seconds( this._hBassStream, nBytes ); // nBytesを使うと、mp3の低速再生時に途中で切れる場合がある。\r
                        this.n総演奏時間ms = (int) ( seconds * 1000 );\r
                        this.pos = 0;\r
                        this.hMixer = hMixer;\r
@@ -1492,7 +1515,8 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ
 \r
                #region [ tオンメモリ方式でデコードする() ]\r
                public void tオンメモリ方式でデコードする( string strファイル名, out byte[] buffer,\r
-                       out int nPCMデータの先頭インデックス, out int totalPCMSize, out CWin32.WAVEFORMATEX wfx )\r
+                       out int nPCMデータの先頭インデックス, out int totalPCMSize, out CWin32.WAVEFORMATEX wfx,\r
+                       bool bIntegrateWaveHeader )\r
                {\r
                        nPCMデータの先頭インデックス = 0;\r
                        //int nPCMサイズbyte = (int) ( xa.xaheader.nSamples * xa.xaheader.nChannels * 2 );   // nBytes = Bass.BASS_ChannelGetLength( this.hBassStream );\r
@@ -1535,8 +1559,10 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ
                                throw new Exception( string.Format( "GetTotalPCMSize() に失敗しました。({0})", strファイル名 ) );\r
                        }\r
                        totalPCMSize += ( ( totalPCMSize % 2 ) != 0 ) ? 1 : 0;\r
-                       buffer = new byte[ totalPCMSize ];\r
-                       GCHandle handle = GCHandle.Alloc( buffer, GCHandleType.Pinned );\r
+                       int wavheadersize = ( bIntegrateWaveHeader ) ? 44 : 0;\r
+                       byte[] buffer_rawdata = new byte[ totalPCMSize ];\r
+                       buffer = new byte[ wavheadersize + totalPCMSize ];\r
+                       GCHandle handle = GCHandle.Alloc( buffer_rawdata, GCHandleType.Pinned );\r
                        try\r
                        {\r
                                if ( sounddecoder.Decode( nHandle, handle.AddrOfPinnedObject(), (uint) totalPCMSize, 0 ) < 0 )\r
@@ -1544,6 +1570,50 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ
                                        buffer = null;\r
                                        throw new Exception( string.Format( "デコードに失敗しました。({0})", strファイル名 ) );\r
                                }\r
+                               if ( bIntegrateWaveHeader )\r
+                               {\r
+                                       // wave headerを書き込む\r
+\r
+                                       int wfx拡張領域_Length = 0;\r
+                                       var ms = new MemoryStream();\r
+                                       var bw = new BinaryWriter( ms );\r
+                                       bw.Write( new byte[] { 0x52, 0x49, 0x46, 0x46 } );              // 'RIFF'\r
+                                       bw.Write( (UInt32) totalPCMSize + 44 - 8 );                             // ファイルサイズ - 8 [byte];今は不明なので後で上書きする。\r
+                                       bw.Write( new byte[] { 0x57, 0x41, 0x56, 0x45 } );              // 'WAVE'\r
+                                       bw.Write( new byte[] { 0x66, 0x6D, 0x74, 0x20 } );              // 'fmt '\r
+                                       bw.Write( (UInt32) ( 16 + ( ( wfx拡張領域_Length > 0 ) ? ( 2/*sizeof(WAVEFORMATEX.cbSize)*/ + wfx拡張領域_Length ) : 0 ) ) );   // fmtチャンクのサイズ[byte]\r
+                                       bw.Write( (UInt16) wfx.wFormatTag );                                    // フォーマットID(リニアPCMなら1)\r
+                                       bw.Write( (UInt16) wfx.nChannels );                                             // チャンネル数\r
+                                       bw.Write( (UInt32) wfx.nSamplesPerSec );                                // サンプリングレート\r
+                                       bw.Write( (UInt32) wfx.nAvgBytesPerSec );                               // データ速度\r
+                                       bw.Write( (UInt16) wfx.nBlockAlign );                                   // ブロックサイズ\r
+                                       bw.Write( (UInt16) wfx.wBitsPerSample );                                // サンプルあたりのビット数\r
+                                       //if ( wfx拡張領域_Length > 0 )\r
+                                       //{\r
+                                       //    bw.Write( (UInt16) wfx拡張領域.Length );                      // 拡張領域のサイズ[byte]\r
+                                       //    bw.Write( wfx拡張領域 );                                                      // 拡張データ\r
+                                       //}\r
+                                       bw.Write( new byte[] { 0x64, 0x61, 0x74, 0x61 } );              // 'data'\r
+                                       //int nDATAチャンクサイズ位置 = (int) ms.Position;\r
+                                       bw.Write( (UInt32) totalPCMSize );                                              // dataチャンクのサイズ[byte];今は不明なので後で上書きする。\r
+\r
+                                       byte[] bs = ms.ToArray();\r
+\r
+                                       bw.Close();\r
+                                       ms.Close();\r
+\r
+                                       for ( int i = 0; i < bs.Length; i++ )\r
+                                       {\r
+                                               buffer[ i ] = bs[ i ];\r
+                                       }\r
+                               }\r
+                               int s = ( bIntegrateWaveHeader ) ? 44 : 0;\r
+                               for ( int i = 0; i < totalPCMSize; i++ )\r
+                               {\r
+                                       buffer[ i + s ] = buffer_rawdata[ i ];\r
+                               }\r
+                               totalPCMSize += wavheadersize;\r
+                               nPCMデータの先頭インデックス = wavheadersize;\r
                        }\r
                        finally\r
                        {\r
index 56e221f..b0b9fff 100644 (file)
Binary files a/実行時フォルダ(DTXCreator)/dll/FDK.dll and b/実行時フォルダ(DTXCreator)/dll/FDK.dll differ
index f67d488..11e6f2c 100644 (file)
Binary files a/実行時フォルダ/DTXManiaGR.exe and b/実行時フォルダ/DTXManiaGR.exe differ
index 56e221f..b0b9fff 100644 (file)
Binary files a/実行時フォルダ/dll/FDK.dll and b/実行時フォルダ/dll/FDK.dll differ