Example #1
0
        public static bool IsFlacAvailable()
        {
            IntPtr context = IntPtr.Zero;

            try
            {
                context = LibFLAC.FLAC__stream_decoder_new();
                return(context != IntPtr.Zero);
            }
            catch {
                return(false);
            }
            finally
            {
                if (context != IntPtr.Zero)
                {
                    LibFLAC.FLAC__stream_decoder_finish(context);
                    LibFLAC.FLAC__stream_decoder_delete(context);
                }
            }
        }
Example #2
0
        private void ParseFlac(string path)
        {
            // reference
            // https://github.com/tgsstdio/BirdNest.Audio/blob/c1474db37be323355f6415cdd9011bc7f2550689/NAudioFLAC/Library/FLACFileReader.cs
            var context = IntPtr.Zero;

            try
            {
                context = LibFLAC.FLAC__stream_decoder_new();
                if (context == IntPtr.Zero)
                {
                    throw new Exception("FLAC open failed");
                }
                int[] w_buf        = null;
                int   sample_index = 0;
                LibFLAC.StreamDecoderWriteStatus Write(IntPtr _, IntPtr frame_ptr, IntPtr buffer_ptr, IntPtr __)
                {
                    var frame = (LibFLAC.FlacFrame)Marshal.PtrToStructure(frame_ptr, typeof(LibFLAC.FlacFrame));

                    if (w_buf == null)
                    {
                        w_buf = new int[frame.Header.BlockSize * ChannelCount];
                    }
                    for (var c = 0; c < ChannelCount; ++c)
                    {
                        var buf = Marshal.ReadIntPtr(buffer_ptr, c * IntPtr.Size);
                        Marshal.Copy(buf, w_buf, c * frame.Header.BlockSize, frame.Header.BlockSize);
                    }
                    for (int i = 0; i < frame.Header.BlockSize; ++i)
                    {
                        for (int c = 0; c < ChannelCount; c++)
                        {
                            int sample = w_buf[i + c * frame.Header.BlockSize];

                            switch (BitsPerSample)
                            {
                            case 24:
                                sample = sample >> 8;
                                Samples[c][i + sample_index] = (short)sample;
                                break;

                            case 16:
                                Samples[c][i + sample_index] = (short)sample;
                                break;

                            default:
                                break;
                            }
                        }
                    }
                    sample_index += frame.Header.BlockSize;
                    return(LibFLAC.StreamDecoderWriteStatus.WriteStatusContinue);
                }
                void Metadata(IntPtr _, IntPtr metadata_ptr, IntPtr __)
                {
                    var metadata = (LibFLAC.FLACMetaData)Marshal.PtrToStructure(metadata_ptr, typeof(LibFLAC.FLACMetaData));

                    if (metadata.MetaDataType == LibFLAC.FLACMetaDataType.StreamInfo)
                    {
                        var stream_info_mem = GCHandle.Alloc(metadata.Data, GCHandleType.Pinned);
                        try
                        {
                            var stream_info = (LibFLAC.FLACStreamInfo)Marshal.PtrToStructure(stream_info_mem.AddrOfPinnedObject(), typeof(LibFLAC.FLACStreamInfo));
                            Samples    = new List <short[]>();
                            SampleRate = (uint)stream_info.SampleRate;
                            var len = (long)(stream_info.TotalSamplesHi << 32) + stream_info.TotalSamplesLo;
                            for (int c = 0; c < stream_info.Channels; ++c)
                            {
                                Samples.Add(new short[len]);
                            }
                            ChannelCount  = (ushort)stream_info.Channels;
                            BitsPerSample = (ushort)stream_info.BitsPerSample;
                            BlockAlign    = 4;
                            AudioFormat   = 1;
                        }
                        finally
                        {
                            stream_info_mem.Free();
                        }
                        if (BitsPerSample != 16 && BitsPerSample != 24)
                        {
                            throw new Exception("FLAC currently support 16/24sbit only.");
                        }
                    }
                }
                void Error(IntPtr _, LibFLAC.DecodeError status, IntPtr __)
                {
                    throw new Exception("FLAC decode error");
                }

                var status_code = LibFLAC.FLAC__stream_decoder_init_file(context, path, Write, Metadata, Error, IntPtr.Zero);
                if (status_code != 0)
                {
                    throw new Exception($"FLAC open error{status_code}");
                }
                var result = LibFLAC.FLAC__stream_decoder_process_until_end_of_stream(context);
                if (!result)
                {
                    throw new Exception($"FLAC decode process failed");
                }
            }
            finally
            {
                LibFLAC.FLAC__stream_decoder_finish(context);
                LibFLAC.FLAC__stream_decoder_delete(context);
            }
        }