OSDN Git Service

#43055 データ単位が8bitのwavファイルを再生するとノイズまみれの再生となる問題を修正。
[dtxmania/dtxmania.git] / FDK / コード / 03.サウンド / Cmp3.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Runtime.InteropServices;
5 using System.IO;
6 using System.Diagnostics;
7 using System.Threading;
8 using Un4seen.Bass;
9 using Un4seen.Bass.Misc;
10
11
12 namespace FDK
13 {
14         public unsafe class Cmp3 : SoundDecoder
15         {
16                 private int stream_in = -1;
17                 private bool bBASS_Already_Init = false;
18
19                 public override int Open( string filename )
20                 {
21                         bBASS_Already_Init = !Bass.BASS_Init(0, 48000, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
22                         // WASAPI/ASIO使用時は(BASS_ERROR_ALREADYとなって)falseが返るので、覚えておく。
23                         // 後でCmp3.Close()時にBASSを終了させないようにするため。
24
25                         stream_in = Bass.BASS_StreamCreateFile(filename, 0, 0, BASSFlag.BASS_DEFAULT | BASSFlag.BASS_STREAM_DECODE);
26                         if (stream_in == 0)
27                         {
28                                 BASSError be = Bass.BASS_ErrorGetCode();
29                                 Trace.TraceInformation("Cmp3: StreamCreateFile error: " + be.ToString());
30                                 return -1;
31                         }
32                         nTotalPCMSize = Bass.BASS_ChannelGetLength(stream_in);
33
34                         #region [ Getting WAVEFORMEX info ]
35                         var chinfo = Bass.BASS_ChannelGetInfo(stream_in);
36                         int wBitsPerSample = (chinfo.origres==0)? 16 : chinfo.origres;          // for no3, origres might be zero
37
38                         wfx = new CWin32.WAVEFORMATEX(
39                                 (ushort)1,                                                              // wFormatTag
40                                 (ushort)chinfo.chans,                                   // nChannels
41                                 (uint)chinfo.freq,                                              // nSamplesPerSec
42                                 (uint)(chinfo.freq * chinfo.chans * wBitsPerSample / 8 ),       // nAvgBytesPerSec == SampleRate(freq) * NumChannels(chans) * BitsPerSample/8
43                                 (ushort)(chinfo.chans * wBitsPerSample / 8),                            // nBlockAlign== NumChannels * BitsPerSample/8
44                                 (ushort)( wBitsPerSample ),                                                                     // wBitsPerSample (8, 16, ...)
45                                 (ushort)0                                                                                                       // cbSize                               
46                         );
47                         Trace.TraceInformation($"chans={chinfo.chans}, freq={chinfo.freq}, chinfo.origres={chinfo.origres}, BitsPerSample={wBitsPerSample}, nAvgBytePerSec={wfx.nAvgBytesPerSec}, nBlockAlign={wfx.nBlockAlign}");
48                         Trace.TraceInformation( $"totalPCMSize={nTotalPCMSize}:{nTotalPCMSize.ToString("x8")}" );
49                         #endregion
50
51                         //string fn = Path.GetFileName(filename); 
52                         //Trace.TraceInformation("filename=" + fn + ", size=(decode): " + wavdata.Length + ", channelgetlength=" + _TotalPCMSize2 + ", " + _TotalPCMSize) ;
53
54                         return 0;
55                 }
56
57                 public override int Decode(ref byte[] Dest, long offset)
58                 {
59                         #region [ decode ]
60                         int LEN = 65536;
61                         byte[] data = new byte[LEN]; // 2 x 16-bit and length in is bytes
62
63                         for (int i = 0; i < offset; i++ )
64                         {
65                                 Dest[ i ] = 0;
66                         }
67
68                         long len = 0;
69                         long p = offset;
70                         do
71                         {
72                                 len = Bass.BASS_ChannelGetData(stream_in, data, LEN);
73                                 if (len < 0)
74                                 {
75                                         BASSError be = Bass.BASS_ErrorGetCode();
76                                         Trace.TraceInformation("Cmp3: BASS_ChannelGetData Error: " + be.ToString());
77                                         break;
78                                 }
79                                 if (p + len > nTotalPCMSize + offset)
80                                 {
81                                         len = nTotalPCMSize - p + offset;
82                                 }
83                                 Array.Copy(data, 0, Dest, p, len);
84                                 p += len;
85                         } while (p < nTotalPCMSize + offset);
86                         #endregion
87
88 //SaveWav(filename, Dest);
89
90                         data = null;
91                         return 0;
92                 }
93
94                 public override void Close()
95                 {
96                         if (!bBASS_Already_Init)
97                         {
98                                 Bass.BASS_StreamFree(stream_in);
99                                 Bass.BASS_Free();
100                         }
101                 }
102
103                 /// <summary>
104                 /// save wav file (for debugging)
105                 /// </summary>
106                 /// <param name="filename">input mp3/xa filename</param>
107                 private void SaveWav(string filename, byte[] Dest)
108                 {
109                         string outfile = Path.GetFileName(filename);
110                         var fs = new FileStream(outfile + ".wav", FileMode.Create);
111                         var st = new BinaryWriter(fs);
112
113                         st.Write(new byte[] { 0x52, 0x49, 0x46, 0x46 });      // 'RIFF'
114                         st.Write((int)(nTotalPCMSize + 44 - 8));            // RIFF chunk size
115                         st.Write(new byte[] { 0x57, 0x41, 0x56, 0x45 });      // 'WAVE'
116                         st.Write(new byte[] { 0x66, 0x6D, 0x74, 0x20 });      // 'fmt '
117                         st.Write(new byte[] { 0x10, 0x00, 0x00, 0x00 });      // chunk size 16bytes
118                         st.Write(new byte[] { 0x01, 0x00 }, 0, 2);                  // formatTag 0001 PCM
119                         st.Write((short)wfx.nChannels);                              // channels
120                         st.Write((int)wfx.nSamplesPerSec);                             // samples per sec
121                         st.Write((int)wfx.nAvgBytesPerSec);          // avg bytesper sec
122                         st.Write((short)wfx.nBlockAlign);                        // blockalign = 16bit * mono/stereo
123                         st.Write((short)wfx.wBitsPerSample);                  // bitspersample = 16bits
124
125                         st.Write(new byte[] { 0x64, 0x61, 0x74, 0x61 });      // 'data'
126                         st.Write((int) nTotalPCMSize);      // datasize 
127                         
128                         st.Write(Dest);
129 Trace.TraceInformation($"wrote ({outfile}.wav) fsLength=" + fs.Length + ", TotalPCMSize=" + nTotalPCMSize + ", diff=" + (fs.Length - nTotalPCMSize));
130                         st.Dispose();
131                         fs.Dispose();
132                 }
133         }
134 }