2 using System.Collections.Generic;
4 using System.Runtime.InteropServices;
6 using System.Diagnostics;
7 using System.Threading;
9 using Un4seen.Bass.Misc;
14 public unsafe class Cmp3 : SoundDecoder
16 private int stream_in = -1;
17 private bool bBASS_Already_Init = false;
19 public override int Open( string filename )
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を終了させないようにするため。
25 stream_in = Bass.BASS_StreamCreateFile(filename, 0, 0, BASSFlag.BASS_DEFAULT | BASSFlag.BASS_STREAM_DECODE);
28 BASSError be = Bass.BASS_ErrorGetCode();
29 Trace.TraceInformation("Cmp3: StreamCreateFile error: " + be.ToString());
32 nTotalPCMSize = Bass.BASS_ChannelGetLength(stream_in);
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
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, ...)
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")}" );
51 //string fn = Path.GetFileName(filename);
52 //Trace.TraceInformation("filename=" + fn + ", size=(decode): " + wavdata.Length + ", channelgetlength=" + _TotalPCMSize2 + ", " + _TotalPCMSize) ;
57 public override int Decode(ref byte[] Dest, long offset)
61 byte[] data = new byte[LEN]; // 2 x 16-bit and length in is bytes
63 for (int i = 0; i < offset; i++ )
72 len = Bass.BASS_ChannelGetData(stream_in, data, LEN);
75 BASSError be = Bass.BASS_ErrorGetCode();
76 Trace.TraceInformation("Cmp3: BASS_ChannelGetData Error: " + be.ToString());
79 if (p + len > nTotalPCMSize + offset)
81 len = nTotalPCMSize - p + offset;
83 Array.Copy(data, 0, Dest, p, len);
85 } while (p < nTotalPCMSize + offset);
88 //SaveWav(filename, Dest);
94 public override void Close()
96 if (!bBASS_Already_Init)
98 Bass.BASS_StreamFree(stream_in);
104 /// save wav file (for debugging)
106 /// <param name="filename">input mp3/xa filename</param>
107 private void SaveWav(string filename, byte[] Dest)
109 string outfile = Path.GetFileName(filename);
110 var fs = new FileStream(outfile + ".wav", FileMode.Create);
111 var st = new BinaryWriter(fs);
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
125 st.Write(new byte[] { 0x64, 0x61, 0x74, 0x61 }); // 'data'
126 st.Write((int) nTotalPCMSize); // datasize
129 Trace.TraceInformation($"wrote ({outfile}.wav) fsLength=" + fs.Length + ", TotalPCMSize=" + nTotalPCMSize + ", diff=" + (fs.Length - nTotalPCMSize));