5using System.Runtime.InteropServices;
7using Un4seen.Bass.AddOn.Flac;
10 public static class Flac {
15 private static Dictionary<nint, Stream> streamMap =
new();
17 private static nint globalStreamId;
23 MemoryStream pcm_stream;
29 public override long Position => pcm_stream.Position;
31 public override long BytesCount => pcm_stream.Length;
35 pcm_stream =
new MemoryStream();
36 BASS_FILEPROCS fileProcs =
new BASS_FILEPROCS(CloseProc, LengthProc, ReadProc, SeekProc);
38 m_stream.Position = 0
L;
39 streamMap[globalStreamId] =
m_stream;
41 int streamID = BassFlac.BASS_FLAC_StreamCreateFileUser(BASSStreamSystem.STREAMFILE_BUFFER, BASSFlag.BASS_STREAM_DECODE, fileProcs, globalStreamId);
42 if (streamID == 0)
throw new Exception(
"BASS_FLAC_StreamCreateFileUser failed: " + Bass.BASS_ErrorGetCode());
43 BASS_CHANNELINFO info = Bass.BASS_ChannelGetInfo(streamID);
44 m_channels = info.chans;
45 m_sampleRate = info.freq;
46 byte[] buffer =
new byte[4096];
48 while ((bytesRead = Bass.BASS_ChannelGetData(streamID, buffer, buffer.Length)) > 0) {
49 pcm_stream.Write(buffer, 0, bytesRead);
51 pcm_stream.Position = 0
L;
52 Bass.BASS_StreamFree(streamID);
55 [MonoPInvokeCallback(typeof(FILELENPROC))]
56 private static long LengthProc(IntPtr user) {
57 var stream = streamMap[user];
61 [MonoPInvokeCallback(typeof(FILESEEKPROC))]
62 private static bool SeekProc(
long offset, IntPtr user) {
63 var stream = streamMap[user];
64 stream.Seek(offset,SeekOrigin.Begin);
68 [MonoPInvokeCallback(typeof(FILEREADPROC))]
69 private static int ReadProc(IntPtr buffer,
int length, IntPtr user) {
70 var stream = streamMap[user];
71 byte[] readBuffer =
new byte[length];
72 int bytesRead = stream.Read(readBuffer, 0, length);
73 Marshal.Copy(readBuffer, 0, buffer, bytesRead);
77 [MonoPInvokeCallback(typeof(FILECLOSEPROC))]
78 private static void CloseProc(IntPtr user) {
79 var stream = streamMap[user];
83 public override void Dispose() {
88 public override int Read(
byte[] buffer,
int offset,
int count) {
89 ArgumentNullException.ThrowIfNull(buffer);
92 || offset + count > buffer.Length) {
93 throw new InvalidOperationException(
"Invalid range.");
95 int num = pcm_stream.Read(buffer, offset, (
int)Math.Min(count,
BytesCount -
Position));
103 public override StreamingSource
Duplicate() {
104 MemoryStream memoryStream =
new();
105 m_stream.Position = 0
L;
107 memoryStream.Position = 0
L;
113 ArgumentNullException.ThrowIfNull(stream);
114 long position = stream.Position;
116 byte[] beginSync =
new byte[4];
117 int read = stream.Read(beginSync, 0, beginSync.Length);
118 stream.Position = position;
119 return read < beginSync.Length
120 ?
throw new EndOfStreamException(
"Can not read \"fLaC\" sync.")
121 : beginSync[0] == 0x66 && beginSync[1] == 0x4C && beginSync[2] == 0x61 && beginSync[3] == 0x43;
125 ArgumentNullException.ThrowIfNull(stream);
131 if (streamingSource.BytesCount >
int.MaxValue) {
132 throw new InvalidOperationException(
"Sound data too long.");
134 byte[] array =
new byte[(int)streamingSource.BytesCount];
135 streamingSource.Read(array, 0, array.Length);
136 SoundData soundData =
new(streamingSource.ChannelsCount, streamingSource.SamplingFrequency, array.Length);
137 Buffer.BlockCopy(array, 0, soundData.Data, 0, array.Length);
166 m_reader.Position = value;
171 throw new ArgumentOutOfRangeException();
173 m_reader.Position = num;
177 throw new NotSupportedException(
"Underlying stream cannot be seeked.");
185 stream.Position = 0L;
187 m_stream.Position = 0L;
196 public override int Read(
byte[] buffer,
int offset,
int count) {
197 ArgumentNullException.ThrowIfNull(buffer);
200 || offset + count > buffer.Length) {
201 throw new InvalidOperationException(
"Invalid range.");
213 MemoryStream memoryStream =
new();
214 m_stream.Position = 0L;
216 memoryStream.Position = 0L;
222 ArgumentNullException.ThrowIfNull(stream);
223 long position = stream.Position;
225 ID3v2.SkipTag(stream);
226 byte[] beginSync =
new byte[4];
227 int read = stream.Read(beginSync, 0, beginSync.Length);
228 stream.Position = position;
229 return read < beginSync.Length
230 ?
throw new EndOfStreamException(
"Can not read \"fLaC\" sync.")
231 : beginSync[0] == 0x66 && beginSync[1] == 0x4C && beginSync[2] == 0x61 && beginSync[3] == 0x43;
235 ArgumentNullException.ThrowIfNull(stream);
241 if (streamingSource.
BytesCount >
int.MaxValue) {
242 throw new InvalidOperationException(
"Sound data too long.");
244 byte[] array =
new byte[(int)streamingSource.
BytesCount];
245 streamingSource.
Read(array, 0, array.Length);
247 Buffer.BlockCopy(array, 0, soundData.
Data, 0, array.Length);