├── XNA4Sample ├── sample.mp3 ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── BaseGame.cs ├── XNAMP3.cs └── XNA4Sample.csproj ├── Images └── MP3SharpHeader.png ├── MP3Sharp.UnitTests ├── sample.mp3 ├── Properties │ └── AssemblyInfo.cs ├── UnitTest1.cs └── MP3Sharp.UnitTests.csproj ├── .gitattributes ├── MP3Sharp ├── Decoding │ ├── OutputChannelsEnum.cs │ ├── Decoders │ │ ├── LayerIII │ │ │ ├── SBI.cs │ │ │ ├── ChannelData.cs │ │ │ ├── Layer3SideInfo.cs │ │ │ ├── ScaleFactorData.cs │ │ │ ├── GranuleInfo.cs │ │ │ └── ScaleFactorTable.cs │ │ ├── IFrameDecoder.cs │ │ ├── LayerIIDecoder.cs │ │ ├── LayerI │ │ │ ├── SubbandLayer1IntensityStereo.cs │ │ │ ├── SubbandLayer1Stereo.cs │ │ │ └── SubbandLayer1.cs │ │ ├── ASubband.cs │ │ ├── LayerIDecoder.cs │ │ └── LayerII │ │ │ ├── SubbandLayer2IntensityStereo.cs │ │ │ └── SubbandLayer2Stereo.cs │ ├── DecoderErrors.cs │ ├── BitstreamErrors.cs │ ├── Crc16.cs │ ├── ABuffer.cs │ ├── DecoderException.cs │ ├── BitstreamException.cs │ ├── SampleBuffer.cs │ ├── PushbackStream.cs │ ├── BitReserve.cs │ ├── OutputChannels.cs │ ├── CircularByteBuffer.cs │ ├── Equalizer.cs │ ├── Decoder.cs │ └── Bitstream.cs ├── SoundFormat.cs ├── Properties │ └── AssemblyInfo.cs ├── IO │ ├── RandomAccessFileStream.cs │ ├── WaveFileBuffer.cs │ └── WaveFile.cs ├── MP3SharpException.cs ├── MP3Sharp.csproj ├── Support │ └── SupportClass.cs ├── Buffer16BitStereo.cs └── MP3Stream.cs ├── readme.md ├── XNA4Sample.sln ├── .gitignore └── license.txt /XNA4Sample/sample.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZaneDubya/MP3Sharp/HEAD/XNA4Sample/sample.mp3 -------------------------------------------------------------------------------- /Images/MP3SharpHeader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZaneDubya/MP3Sharp/HEAD/Images/MP3SharpHeader.png -------------------------------------------------------------------------------- /MP3Sharp.UnitTests/sample.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZaneDubya/MP3Sharp/HEAD/MP3Sharp.UnitTests/sample.mp3 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | # Custom for Visual Studio 4 | *.cs diff=csharp 5 | 6 | # Standard to msysgit 7 | *.doc diff=astextplain 8 | *.DOC diff=astextplain 9 | *.docx diff=astextplain 10 | *.DOCX diff=astextplain 11 | *.dot diff=astextplain 12 | *.DOT diff=astextplain 13 | *.pdf diff=astextplain 14 | *.PDF diff=astextplain 15 | *.rtf diff=astextplain 16 | *.RTF diff=astextplain 17 | -------------------------------------------------------------------------------- /MP3Sharp/Decoding/OutputChannelsEnum.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * OutputChannelsEnum.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding { 18 | internal enum OutputChannelsEnum { 19 | BothChannels = 0, 20 | LeftChannel = 1, 21 | RightChannel = 2, 22 | DownmixChannels = 3 23 | } 24 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerIII/SBI.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * SBI.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerIII { 18 | public class SBI { 19 | internal int[] L; 20 | internal int[] S; 21 | 22 | internal SBI() { 23 | L = new int[23]; 24 | S = new int[14]; 25 | } 26 | 27 | internal SBI(int[] thel, int[] thes) { 28 | L = thel; 29 | S = thes; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/DecoderErrors.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * DecoderErrors.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding { 18 | /// 19 | /// This interface provides constants describing the error 20 | /// codes used by the Decoder to indicate errors. 21 | /// 22 | internal struct DecoderErrors { 23 | internal const int UNKNOWN_ERROR = BitstreamErrors.DECODER_ERROR + 0; 24 | internal const int UNSUPPORTED_LAYER = BitstreamErrors.DECODER_ERROR + 1; 25 | } 26 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerIII/ChannelData.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * ChannelData.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerIII { 18 | public class ChannelData { 19 | internal GranuleInfo[] Granules; 20 | internal int[] ScaleFactorBits; 21 | 22 | internal ChannelData() { 23 | ScaleFactorBits = new int[4]; 24 | Granules = new GranuleInfo[2]; 25 | Granules[0] = new GranuleInfo(); 26 | Granules[1] = new GranuleInfo(); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerIII/Layer3SideInfo.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * Layer3SideInfo.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerIII { 18 | public class Layer3SideInfo { 19 | internal ChannelData[] Channels; 20 | internal int MainDataBegin; 21 | internal int PrivateBits; 22 | 23 | internal Layer3SideInfo() { 24 | Channels = new ChannelData[2]; 25 | Channels[0] = new ChannelData(); 26 | Channels[1] = new ChannelData(); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerIII/ScaleFactorData.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * ScaleFactorData.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerIII { 18 | public class ScaleFactorData { 19 | internal int[] L; /* [cb] */ 20 | internal int[][] S; /* [window][cb] */ 21 | 22 | internal ScaleFactorData() { 23 | L = new int[23]; 24 | S = new int[3][]; 25 | for (int i = 0; i < 3; i++) { 26 | S[i] = new int[13]; 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /MP3Sharp/SoundFormat.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * SoundFormat.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp { 18 | /// 19 | /// Describes sound formats that can be produced by the Mp3Stream class. 20 | /// 21 | public enum SoundFormat { 22 | /// 23 | /// PCM encoded, 16-bit Mono sound format. 24 | /// 25 | Pcm16BitMono, 26 | 27 | /// 28 | /// PCM encoded, 16-bit Stereo sound format. 29 | /// 30 | Pcm16BitStereo 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/IFrameDecoder.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * IFrameDecoder.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders { 18 | /// 19 | /// Implementations of FrameDecoder are responsible for decoding 20 | /// an MPEG audio frame. 21 | /// 22 | //REVIEW: the interface currently is too thin. There should be 23 | // methods to specify the output buffer, the synthesis filters and 24 | // possibly other objects used by the decoder. 25 | public interface IFrameDecoder { 26 | /// 27 | /// Decodes one frame of MPEG audio. 28 | /// 29 | void DecodeFrame(); 30 | } 31 | } -------------------------------------------------------------------------------- /MP3Sharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("MP3Sharp")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("MP3Sharp")] 12 | [assembly: AssemblyCopyright("")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("2c379a78-8a96-48a5-81e5-ea0ae696aa5b")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /MP3Sharp.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MP3Sharp.UnitTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MP3Sharp.UnitTests")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a1e79dd1-de8b-4ba9-a704-16d9a2504187")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MP3Sharp/Decoding/BitstreamErrors.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * BitstreamErrors.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding { 18 | /// 19 | /// This struct describes all error codes that can be thrown 20 | /// in BistreamExceptions. 21 | /// 22 | internal struct BitstreamErrors { 23 | internal const int UNKNOWN_ERROR = BITSTREAM_ERROR + 0; 24 | internal const int UNKNOWN_SAMPLE_RATE = BITSTREAM_ERROR + 1; 25 | internal const int STREA_ERROR = BITSTREAM_ERROR + 2; 26 | internal const int UNEXPECTED_EOF = BITSTREAM_ERROR + 3; 27 | internal const int STREAM_EOF = BITSTREAM_ERROR + 4; 28 | internal const int BITSTREAM_LAST = 0x1ff; 29 | 30 | internal const int BITSTREAM_ERROR = 0x100; 31 | internal const int DECODER_ERROR = 0x200; 32 | } 33 | } -------------------------------------------------------------------------------- /MP3Sharp/IO/RandomAccessFileStream.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * RandomAccessFileStream.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using System.IO; 19 | 20 | namespace MP3Sharp.IO { 21 | public class RandomAccessFileStream { 22 | internal static FileStream CreateRandomAccessFile(string fileName, string mode) { 23 | FileStream newFile; 24 | 25 | if (string.Compare(mode, "rw", StringComparison.Ordinal) == 0) 26 | newFile = new FileStream(fileName, FileMode.OpenOrCreate, 27 | FileAccess.ReadWrite); 28 | else if (string.Compare(mode, "r", StringComparison.Ordinal) == 0) 29 | newFile = new FileStream(fileName, FileMode.Open, FileAccess.Read); 30 | else 31 | throw new ArgumentException(); 32 | 33 | return newFile; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerIII/GranuleInfo.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * GranuleInfo.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerIII { 18 | public class GranuleInfo { 19 | internal int BigValues; 20 | internal int BlockType; 21 | internal int Count1TableSelect; 22 | internal int GlobalGain; 23 | internal int MixedBlockFlag; 24 | internal int Part23Length; 25 | internal int Preflag; 26 | internal int Region0Count; 27 | internal int Region1Count; 28 | internal int ScaleFacCompress; 29 | internal int ScaleFacScale; 30 | internal int[] SubblockGain; 31 | internal int[] TableSelect; 32 | internal int WindowSwitchingFlag; 33 | 34 | internal GranuleInfo() { 35 | TableSelect = new int[3]; 36 | SubblockGain = new int[3]; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerIII/ScaleFactorTable.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * ScaleFactorTable.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerIII { 18 | public class ScaleFactorTable { 19 | internal int[] L; 20 | internal int[] S; 21 | 22 | private LayerIIIDecoder _EnclosingInstance; 23 | 24 | internal ScaleFactorTable(LayerIIIDecoder enclosingInstance) { 25 | InitBlock(enclosingInstance); 26 | L = new int[5]; 27 | S = new int[3]; 28 | } 29 | 30 | internal ScaleFactorTable(LayerIIIDecoder enclosingInstance, int[] thel, int[] thes) { 31 | InitBlock(enclosingInstance); 32 | L = thel; 33 | S = thes; 34 | } 35 | 36 | internal LayerIIIDecoder EnclosingInstance => _EnclosingInstance; 37 | 38 | private void InitBlock(LayerIIIDecoder enclosingInstance) { 39 | _EnclosingInstance = enclosingInstance; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # MP3Sharp 2 | Decode MP3 files to PCM bitstreams entirely in .NET managed code: 3 | 4 | 5 | # SETUP 6 | To use MP3Sharp, you will need: an audio device that accepts PCM data, an array of bytes to act as the PCM data buffer (default size is 4096 bytes), and a MP3 file. That's it! 7 | 8 | The default interface to MP3Sharp is the MP3Stream class. An instance of MP3Stream takes a filepath to a MP3 file as a parameter and outputs PCM data: 9 | ```CSharp 10 | // open the mp3 file. 11 | MP3Stream stream = new MP3Stream(@"sample.mp3"); 12 | // Create the buffer. 13 | byte[] buffer = new byte[4096]; 14 | // read the entire mp3 file. 15 | int bytesReturned = 1; 16 | int totalBytesRead = 0; 17 | while (bytesReturned > 0) 18 | { 19 | bytesReturned = stream.Read(buffer, 0, buffer.Length); 20 | totalBytesRead += bytesReturned; 21 | } 22 | // close the stream after we're done with it. 23 | stream.Close(); 24 | ``` 25 | So simple! 26 | 27 | ## LICENSE 28 | MP3Sharp is licensed under the [LGPL Version 3](https://github.com/ZaneDubya/MP3Sharp/blob/master/license.txt). 29 | 30 | ## CREDITS 31 | MP3Sharp is a port of JavaLayer, a MP3 decoder written by [JavaZoom](http://www.javazoom.net) and released under the LGPL. JavaLayer was initially ported to C# by [Robert Burke](http://www.robburke.net/), in what he modestly describes as a 'half day project'. [tekHedd](http://www.byteheaven.com/) added some significant speed optimizations. This repository includes bug fixes (fixes for correctly outputting VBR, mono, and ability to loop without crashing; nice!). The sample MP3 file used in this project is by [BenSound](http://www.bensound.com), and is included under the terms of the Creative Commons - Attribution - No Derivative Works license. 32 | -------------------------------------------------------------------------------- /XNA4Sample/Program.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * Program.cs 3 | // * Copyright (c) 2015 the authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using MP3Sharp; 19 | 20 | namespace XNA4Sample { 21 | #if WINDOWS || XBOX 22 | static class Program { 23 | /// 24 | /// The main entry point for the application. 25 | /// 26 | static void Main(string[] args) { 27 | using (BaseGame game = new BaseGame()) { 28 | game.Run(); 29 | } 30 | } 31 | 32 | static void ExampleReadEntireMP3File() { 33 | MP3Stream stream = new MP3Stream("@sample.mp3"); 34 | 35 | // Create the buffer 36 | const int NUMBER_OF_PCM_BYTES_TO_READ_PER_CHUNK = 4096; 37 | byte[] buffer = new byte[NUMBER_OF_PCM_BYTES_TO_READ_PER_CHUNK]; 38 | 39 | int bytesReturned = -1; 40 | int totalBytes = 0; 41 | while (bytesReturned != 0) { 42 | bytesReturned = stream.Read(buffer, 0, buffer.Length); 43 | totalBytes += bytesReturned; 44 | } 45 | Console.WriteLine("Read a total of " + totalBytes + " bytes."); 46 | 47 | stream.Close(); 48 | stream = null; 49 | } 50 | } 51 | #endif 52 | } 53 | 54 | -------------------------------------------------------------------------------- /MP3Sharp/MP3SharpException.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * MP3SharpException.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using System.IO; 19 | using System.Runtime.Serialization; 20 | using MP3Sharp.Support; 21 | 22 | namespace MP3Sharp { 23 | /// 24 | /// MP3SharpException is the base class for all API-level 25 | /// exceptions thrown by MP3Sharp. To facilitate conversion and 26 | /// common handling of exceptions from other domains, the class 27 | /// can delegate some functionality to a contained Throwable instance. 28 | /// 29 | [Serializable] 30 | public class MP3SharpException : Exception { 31 | internal MP3SharpException() { } 32 | 33 | internal MP3SharpException(string message) : base(message) { } 34 | 35 | internal MP3SharpException(string message, Exception inner) : base(message, inner) { } 36 | 37 | protected MP3SharpException(SerializationInfo info, StreamingContext context) : base(info, context) { } 38 | 39 | internal void PrintStackTrace() { 40 | SupportClass.WriteStackTrace(this, Console.Error); 41 | } 42 | 43 | internal void PrintStackTrace(StreamWriter ps) { 44 | if (InnerException == null) { 45 | SupportClass.WriteStackTrace(this, ps); 46 | } 47 | else { 48 | SupportClass.WriteStackTrace(InnerException, Console.Error); 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /XNA4Sample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * AssemblyInfo.cs 3 | // * Copyright (c) 2015 the authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System.Reflection; 18 | using System.Runtime.InteropServices; 19 | 20 | // General Information about an assembly is controlled through the following 21 | // set of attributes. Change these attribute values to modify the information 22 | // associated with an assembly. 23 | [assembly: AssemblyTitle("XNA4Sample")] 24 | [assembly: AssemblyProduct("XNA4Sample")] 25 | [assembly: AssemblyDescription("")] 26 | [assembly: AssemblyCompany("")] 27 | [assembly: AssemblyCopyright("Copyright © 2015")] 28 | [assembly: AssemblyTrademark("")] 29 | [assembly: AssemblyCulture("")] 30 | 31 | // Setting ComVisible to false makes the types in this assembly not visible 32 | // to COM components. If you need to access a type in this assembly from 33 | // COM, set the ComVisible attribute to true on that type. Only Windows 34 | // assemblies support COM. 35 | [assembly: ComVisible(false)] 36 | 37 | // On Windows, the following GUID is for the ID of the typelib if this 38 | // project is exposed to COM. On other platforms, it unique identifies the 39 | // title storage container when deploying this assembly to the device. 40 | [assembly: Guid("c976a841-e38f-43cb-aee9-5b7514908ac2")] 41 | 42 | // Version information for an assembly consists of the following four values: 43 | // 44 | // Major Version 45 | // Minor Version 46 | // Build Number 47 | // Revision 48 | // 49 | [assembly: AssemblyVersion("1.0.0.0")] -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Crc16.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * Crc16.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using MP3Sharp.Support; 18 | 19 | namespace MP3Sharp.Decoding { 20 | /// 21 | /// 16-Bit CRC checksum 22 | /// 23 | public sealed class Crc16 { 24 | private static readonly short Polynomial; 25 | private short _CRC; 26 | 27 | static Crc16() { 28 | Polynomial = (short)SupportClass.Identity(0x8005); 29 | } 30 | 31 | internal Crc16() { 32 | _CRC = (short)SupportClass.Identity(0xFFFF); 33 | } 34 | 35 | /// 36 | /// Feed a bitstring to the crc calculation (length between 0 and 32, not inclusive). 37 | /// 38 | internal void AddBits(int bitstring, int length) { 39 | int bitmask = 1 << (length - 1); 40 | do 41 | if (((_CRC & 0x8000) == 0) ^ ((bitstring & bitmask) == 0)) { 42 | _CRC <<= 1; 43 | _CRC ^= Polynomial; 44 | } 45 | else 46 | _CRC <<= 1; 47 | while ((bitmask = SupportClass.URShift(bitmask, 1)) != 0); 48 | } 49 | 50 | /// 51 | /// Return the calculated checksum. 52 | /// Erase it for next calls to add_bits(). 53 | /// 54 | internal short Checksum() { 55 | short sum = _CRC; 56 | _CRC = (short)SupportClass.Identity(0xFFFF); 57 | return sum; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerIIDecoder.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * LayerIIDecoder.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using MP3Sharp.Decoding.Decoders.LayerII; 18 | 19 | namespace MP3Sharp.Decoding.Decoders { 20 | /// 21 | /// Implements decoding of MPEG Audio Layer II frames. 22 | /// 23 | public class LayerIIDecoder : LayerIDecoder { 24 | protected override void CreateSubbands() { 25 | int i; 26 | switch (Mode) { 27 | case Header.SINGLE_CHANNEL: { 28 | for (i = 0; i < NuSubbands; ++i) 29 | Subbands[i] = new SubbandLayer2(i); 30 | break; 31 | } 32 | case Header.JOINT_STEREO: { 33 | for (i = 0; i < Header.IntensityStereoBound(); ++i) 34 | Subbands[i] = new SubbandLayer2Stereo(i); 35 | for (; i < NuSubbands; ++i) 36 | Subbands[i] = new SubbandLayer2IntensityStereo(i); 37 | break; 38 | } 39 | default: { 40 | for (i = 0; i < NuSubbands; ++i) 41 | Subbands[i] = new SubbandLayer2Stereo(i); 42 | break; 43 | } 44 | } 45 | } 46 | 47 | protected override void ReadScaleFactorSelection() { 48 | for (int i = 0; i < NuSubbands; ++i) 49 | ((SubbandLayer2)Subbands[i]).ReadScaleFactorSelection(Stream, CRC); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/ABuffer.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * ABuffer.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding { 18 | /// 19 | /// Base Class for audio output. 20 | /// 21 | public abstract class ABuffer { 22 | internal const int OBUFFERSIZE = 2 * 1152; // max. 2 * 1152 samples per frame 23 | internal const int MAXCHANNELS = 2; // max. number of channels 24 | 25 | /// 26 | /// Takes a 16 Bit PCM sample. 27 | /// 28 | protected abstract void Append(int channel, short sampleValue); 29 | 30 | /// 31 | /// Accepts 32 new PCM samples. 32 | /// 33 | internal virtual void AppendSamples(int channel, float[] samples) { 34 | for (int i = 0; i < 32; i++) { 35 | Append(channel, Clip(samples[i])); 36 | } 37 | } 38 | 39 | /// 40 | /// Clip Sample to 16 Bits 41 | /// 42 | private static short Clip(float sample) => sample > 32767.0f ? (short)32767 : sample < -32768.0f ? (short)-32768 : (short)sample; 43 | 44 | /// 45 | /// Write the samples to the file or directly to the audio hardware. 46 | /// 47 | internal abstract void WriteBuffer(int val); 48 | 49 | internal abstract void Close(); 50 | 51 | /// 52 | /// Clears all data in the buffer (for seeking). 53 | /// 54 | internal abstract void ClearBuffer(); 55 | 56 | /// 57 | /// Notify the buffer that the user has stopped the stream. 58 | /// 59 | internal abstract void SetStopFlag(); 60 | } 61 | } -------------------------------------------------------------------------------- /MP3Sharp.UnitTests/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System.Reflection; 4 | 5 | namespace MP3Sharp.UnitTests 6 | { 7 | [TestClass] 8 | public class UnitTest1 9 | { 10 | [TestMethod] 11 | public void MP3Stream_basic_properties() 12 | { 13 | using (var mp3 = Assembly.GetExecutingAssembly().GetManifestResourceStream("MP3Sharp.UnitTests.sample.mp3")) 14 | using (var stream = new MP3Stream(mp3)) 15 | { 16 | Assert.IsFalse(stream.IsEOF); 17 | Assert.AreEqual(stream.Length, mp3.Length); 18 | Assert.IsTrue(stream.CanRead); 19 | Assert.IsTrue(stream.CanSeek); 20 | Assert.IsFalse(stream.CanWrite); 21 | Assert.AreEqual(0, stream.ChunkSize); 22 | Assert.AreEqual(370, stream.Position); 23 | Assert.AreEqual(44100, stream.Frequency); 24 | Assert.AreEqual(2, stream.ChannelCount); 25 | Assert.AreEqual(SoundFormat.Pcm16BitStereo, stream.Format); 26 | 27 | byte[] buffer = new byte[4096]; 28 | int bytesReturned = 1; 29 | int totalBytesRead = 0; 30 | while (bytesReturned > 0) 31 | { 32 | bytesReturned = stream.Read(buffer, 0, buffer.Length); 33 | totalBytesRead += bytesReturned; 34 | } 35 | 36 | Assert.IsTrue(stream.IsEOF); 37 | } 38 | } 39 | 40 | [TestMethod] 41 | public void MP3Stream_read_md5() 42 | { 43 | var md5 = System.Security.Cryptography.MD5.Create(); 44 | 45 | using (var mp3 = Assembly.GetExecutingAssembly().GetManifestResourceStream("MP3Sharp.UnitTests.sample.mp3")) 46 | using (var stream = new MP3Stream(mp3)) 47 | using (var memory = new System.IO.MemoryStream()) 48 | { 49 | byte[] buffer = new byte[4096]; 50 | int bytesRead; 51 | 52 | while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) 53 | { 54 | memory.Write(buffer, 0, bytesRead); 55 | } 56 | 57 | byte[] md5hash = md5.ComputeHash(memory.ToArray()); 58 | Assert.AreEqual(9576522144988971710UL, BitConverter.ToUInt64(md5hash, 0)); 59 | Assert.AreEqual(4012292588662891826UL, BitConverter.ToUInt64(md5hash, 8)); 60 | } 61 | } 62 | 63 | } 64 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/DecoderException.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * DecoderException.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using System.Runtime.Serialization; 19 | 20 | namespace MP3Sharp.Decoding { 21 | /// 22 | /// The DecoderException represents the class of 23 | /// errors that can occur when decoding MPEG audio. 24 | /// 25 | [Serializable] 26 | public class DecoderException : MP3SharpException { 27 | private int _ErrorCode; 28 | 29 | internal DecoderException(string message, Exception inner) : base(message, inner) { 30 | InitBlock(); 31 | } 32 | 33 | internal DecoderException(int errorcode, Exception inner) : this(GetErrorString(errorcode), inner) { 34 | InitBlock(); 35 | _ErrorCode = errorcode; 36 | } 37 | 38 | protected DecoderException(SerializationInfo info, StreamingContext context) : base(info, context) { 39 | _ErrorCode = info.GetInt32("ErrorCode"); 40 | } 41 | 42 | internal virtual int ErrorCode => _ErrorCode; 43 | 44 | public override void GetObjectData(SerializationInfo info, StreamingContext context) { 45 | if (info == null) { 46 | throw new ArgumentNullException(nameof(info)); 47 | } 48 | 49 | info.AddValue("ErrorCode", _ErrorCode); 50 | base.GetObjectData(info, context); 51 | } 52 | 53 | private void InitBlock() { 54 | _ErrorCode = DecoderErrors.UNKNOWN_ERROR; 55 | } 56 | 57 | internal static string GetErrorString(int errorcode) => 58 | // REVIEW: use resource file to map error codes 59 | // to locale-sensitive strings. 60 | "Decoder errorcode " + Convert.ToString(errorcode, 16); 61 | } 62 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerI/SubbandLayer1IntensityStereo.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * SubbandLayer1IntensityStereo.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerI { 18 | /// 19 | /// public class for layer I subbands in joint stereo mode. 20 | /// 21 | public class SubbandLayer1IntensityStereo : SubbandLayer1 { 22 | protected float Channel2Scalefactor; 23 | 24 | internal SubbandLayer1IntensityStereo(int subbandnumber) 25 | : base(subbandnumber) { } 26 | 27 | /// 28 | /// * 29 | /// 30 | internal override void ReadScaleFactor(Bitstream stream, Header header) { 31 | if (Allocation != 0) { 32 | Scalefactor = ScaleFactors[stream.GetBitsFromBuffer(6)]; 33 | Channel2Scalefactor = ScaleFactors[stream.GetBitsFromBuffer(6)]; 34 | } 35 | } 36 | 37 | /// 38 | /// * 39 | /// 40 | internal override bool PutNextSample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) { 41 | if (Allocation != 0) { 42 | Sample = Sample * Factor + Offset; // requantization 43 | if (channels == OutputChannels.BOTH_CHANNELS) { 44 | float sample1 = Sample * Scalefactor, sample2 = Sample * Channel2Scalefactor; 45 | filter1.AddSample(sample1, Subbandnumber); 46 | filter2.AddSample(sample2, Subbandnumber); 47 | } 48 | else if (channels == OutputChannels.LEFT_CHANNEL) { 49 | float sample1 = Sample * Scalefactor; 50 | filter1.AddSample(sample1, Subbandnumber); 51 | } 52 | else { 53 | float sample2 = Sample * Channel2Scalefactor; 54 | filter1.AddSample(sample2, Subbandnumber); 55 | } 56 | } 57 | return true; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /XNA4Sample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.1300 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XNA4Sample", "XNA4Sample\XNA4Sample.csproj", "{78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MP3Sharp", "MP3Sharp\MP3Sharp.csproj", "{2C379A78-8A96-48A5-81E5-EA0AE696AA5B}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|Mixed Platforms = Debug|Mixed Platforms 14 | Debug|x86 = Debug|x86 15 | Release|Any CPU = Release|Any CPU 16 | Release|Mixed Platforms = Release|Mixed Platforms 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Debug|Any CPU.ActiveCfg = Debug|x86 21 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 22 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Debug|Mixed Platforms.Build.0 = Debug|x86 23 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Debug|x86.ActiveCfg = Debug|x86 24 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Debug|x86.Build.0 = Debug|x86 25 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Release|Any CPU.ActiveCfg = Release|x86 26 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Release|Mixed Platforms.ActiveCfg = Release|x86 27 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Release|Mixed Platforms.Build.0 = Release|x86 28 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Release|x86.ActiveCfg = Release|x86 29 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778}.Release|x86.Build.0 = Release|x86 30 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 33 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 34 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Debug|x86.ActiveCfg = Debug|Any CPU 35 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 38 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Release|Mixed Platforms.Build.0 = Release|Any CPU 39 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B}.Release|x86.ActiveCfg = Release|Any CPU 40 | EndGlobalSection 41 | GlobalSection(SolutionProperties) = preSolution 42 | HideSolutionNode = FALSE 43 | EndGlobalSection 44 | GlobalSection(ExtensibilityGlobals) = postSolution 45 | SolutionGuid = {6D46F2F6-6964-41FC-A49E-47A12366356F} 46 | EndGlobalSection 47 | EndGlobal 48 | -------------------------------------------------------------------------------- /MP3Sharp/Decoding/BitstreamException.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * BitstreamException.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using System.Runtime.Serialization; 19 | 20 | namespace MP3Sharp.Decoding { 21 | /// 22 | /// Instances of BitstreamException are thrown 23 | /// when operations on a Bitstream fail. 24 | ///

25 | /// The exception provides details of the exception condition 26 | /// in two ways: 27 | ///

    28 | ///
  1. 29 | /// as an error-code describing the nature of the error 30 | ///
  2. 31 | ///

    32 | ///
  3. 33 | /// as the Throwable instance, if any, that was thrown 34 | /// indicating that an exceptional condition has occurred. 35 | ///
  4. 36 | ///
37 | ///

38 | ///
39 | [Serializable] 40 | public class BitstreamException : MP3SharpException { 41 | private int _ErrorCode; 42 | 43 | internal BitstreamException(string message, Exception inner) : base(message, inner) { 44 | InitBlock(); 45 | } 46 | 47 | internal BitstreamException(int errorcode, Exception inner) : this(GetErrorString(errorcode), inner) { 48 | InitBlock(); 49 | _ErrorCode = errorcode; 50 | } 51 | 52 | protected BitstreamException(SerializationInfo info, StreamingContext context) : base(info, context) { 53 | _ErrorCode = info.GetInt32("ErrorCode"); 54 | } 55 | 56 | internal virtual int ErrorCode => _ErrorCode; 57 | 58 | public override void GetObjectData(SerializationInfo info, StreamingContext context) { 59 | if (info == null) { 60 | throw new ArgumentNullException(nameof(info)); 61 | } 62 | 63 | info.AddValue("ErrorCode", _ErrorCode); 64 | base.GetObjectData(info, context); 65 | } 66 | 67 | private void InitBlock() { 68 | _ErrorCode = BitstreamErrors.UNKNOWN_ERROR; 69 | } 70 | 71 | internal static string GetErrorString(int errorcode) => "Bitstream errorcode " + Convert.ToString(errorcode, 16); 72 | } 73 | } -------------------------------------------------------------------------------- /XNA4Sample/BaseGame.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * BaseGame.cs 3 | // * Copyright (c) 2015 the authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using Microsoft.Xna.Framework; 18 | using Microsoft.Xna.Framework.Graphics; 19 | using Microsoft.Xna.Framework.Input; 20 | 21 | namespace XNA4Sample { 22 | /// 23 | /// This is the main type for your game 24 | /// 25 | public class BaseGame : Game { 26 | private readonly GraphicsDeviceManager _Graphics; 27 | private SpriteBatch _SpriteBatch; 28 | 29 | public BaseGame() { 30 | _Graphics = new GraphicsDeviceManager(this); 31 | Content.RootDirectory = "Content"; 32 | } 33 | 34 | /// 35 | /// LoadContent will be called once per game and is the place to load 36 | /// all of your content. 37 | /// 38 | protected override void LoadContent() { 39 | _SpriteBatch = new SpriteBatch(GraphicsDevice); 40 | XNAMP3 mp3 = new XNAMP3("sample.mp3"); 41 | mp3.Play(repeat: true); 42 | } 43 | 44 | /// 45 | /// UnloadContent will be called once per game and is the place to unload 46 | /// all content. 47 | /// 48 | protected override void UnloadContent() { 49 | 50 | } 51 | 52 | /// 53 | /// Allows the game to run logic such as updating the world, 54 | /// checking for collisions, gathering input, and playing audio. 55 | /// 56 | /// Provides a snapshot of timing values. 57 | protected override void Update(GameTime gameTime) { 58 | // Allows the game to exit 59 | if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 60 | Exit(); 61 | base.Update(gameTime); 62 | } 63 | 64 | /// 65 | /// This is called when the game should draw itself. 66 | /// 67 | /// Provides a snapshot of timing values. 68 | protected override void Draw(GameTime gameTime) { 69 | GraphicsDevice.Clear(Color.CornflowerBlue); 70 | base.Draw(gameTime); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/ASubband.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * ASubband.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders { 18 | /// 19 | /// Abstract base class for subband classes of layer I and II 20 | /// 21 | public abstract class ASubband { 22 | /* 23 | * Changes from version 1.1 to 1.2: 24 | * - array size increased by one, although a scalefactor with index 63 25 | * is illegal (to prevent segmentation faults) 26 | */ 27 | // Scalefactors for layer I and II, Annex 3-B.1 in ISO/IEC DIS 11172: 28 | internal static readonly float[] ScaleFactors = { 29 | 2.00000000000000f, 1.58740105196820f, 1.25992104989487f, 1.00000000000000f, 0.79370052598410f, 30 | 0.62996052494744f, 0.50000000000000f, 0.39685026299205f, 0.31498026247372f, 0.25000000000000f, 31 | 0.19842513149602f, 0.15749013123686f, 0.12500000000000f, 0.09921256574801f, 0.07874506561843f, 32 | 0.06250000000000f, 0.04960628287401f, 0.03937253280921f, 0.03125000000000f, 0.02480314143700f, 33 | 0.01968626640461f, 0.01562500000000f, 0.01240157071850f, 0.00984313320230f, 0.00781250000000f, 34 | 0.00620078535925f, 0.00492156660115f, 0.00390625000000f, 0.00310039267963f, 0.00246078330058f, 35 | 0.00195312500000f, 0.00155019633981f, 0.00123039165029f, 0.00097656250000f, 0.00077509816991f, 36 | 0.00061519582514f, 0.00048828125000f, 0.00038754908495f, 0.00030759791257f, 0.00024414062500f, 37 | 0.00019377454248f, 0.00015379895629f, 0.00012207031250f, 0.00009688727124f, 0.00007689947814f, 38 | 0.00006103515625f, 0.00004844363562f, 0.00003844973907f, 0.00003051757813f, 0.00002422181781f, 39 | 0.00001922486954f, 0.00001525878906f, 0.00001211090890f, 0.00000961243477f, 0.00000762939453f, 40 | 0.00000605545445f, 0.00000480621738f, 0.00000381469727f, 0.00000302772723f, 0.00000240310869f, 41 | 0.00000190734863f, 0.00000151386361f, 0.00000120155435f, 0.00000000000000f 42 | }; 43 | 44 | internal abstract void ReadAllocation(Bitstream stream, Header header, Crc16 crc); 45 | 46 | internal abstract void ReadScaleFactor(Bitstream stream, Header header); 47 | 48 | internal abstract bool ReadSampleData(Bitstream stream); 49 | 50 | internal abstract bool PutNextSample(int channels, SynthesisFilter filter1, SynthesisFilter filter2); 51 | } 52 | } -------------------------------------------------------------------------------- /XNA4Sample/XNAMP3.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * XNAMP3.cs 3 | // * Copyright (c) 2015 the authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using Microsoft.Xna.Framework.Audio; 19 | using MP3Sharp; 20 | 21 | namespace XNA4Sample { 22 | class XNAMP3 : IDisposable { 23 | private MP3Stream _Stream; 24 | private DynamicSoundEffectInstance _Instance; 25 | 26 | private const int NUMBER_OF_PCM_BYTES_TO_READ_PER_CHUNK = 4096; 27 | private readonly byte[] _WaveBuffer = new byte[NUMBER_OF_PCM_BYTES_TO_READ_PER_CHUNK]; 28 | 29 | private bool _Repeat; 30 | private bool _Playing; 31 | 32 | public XNAMP3(string path) { 33 | _Stream = new MP3Stream(path, NUMBER_OF_PCM_BYTES_TO_READ_PER_CHUNK); 34 | _Instance = new DynamicSoundEffectInstance(_Stream.Frequency, AudioChannels.Stereo); 35 | } 36 | 37 | public void Dispose() { 38 | if (_Playing) { 39 | Stop(); 40 | } 41 | _Instance.Dispose(); 42 | _Instance = null; 43 | _Stream.Close(); 44 | _Stream = null; 45 | } 46 | 47 | public void Play(bool repeat = false) { 48 | if (_Playing) { 49 | Stop(); 50 | } 51 | _Playing = true; 52 | _Repeat = repeat; 53 | SubmitBuffer(3); 54 | _Instance.BufferNeeded += InstanceBufferNeeded; 55 | _Instance.Play(); 56 | } 57 | 58 | public void Stop() { 59 | if (_Playing) { 60 | _Playing = false; 61 | _Instance.Stop(); 62 | _Instance.BufferNeeded -= InstanceBufferNeeded; 63 | } 64 | } 65 | 66 | private void InstanceBufferNeeded(object sender, EventArgs e) { 67 | SubmitBuffer(); 68 | } 69 | 70 | private void SubmitBuffer(int count = 1) { 71 | while (count > 0) { 72 | ReadFromStream(); 73 | _Instance.SubmitBuffer(_WaveBuffer); 74 | count--; 75 | } 76 | } 77 | 78 | private void ReadFromStream() { 79 | int bytesReturned = _Stream.Read(_WaveBuffer, 0, _WaveBuffer.Length); 80 | if (bytesReturned != NUMBER_OF_PCM_BYTES_TO_READ_PER_CHUNK) { 81 | if (_Repeat) { 82 | _Stream.Position = 0; 83 | _Stream.Read(_WaveBuffer, bytesReturned, _WaveBuffer.Length - bytesReturned); 84 | } 85 | else { 86 | if (bytesReturned == 0) { 87 | Stop(); 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /MP3Sharp/IO/WaveFileBuffer.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * WaveFileBuffer.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using System.IO; 19 | using MP3Sharp.Decoding; 20 | 21 | namespace MP3Sharp.IO { 22 | /// Implements an Obuffer by writing the data to a file in RIFF WAVE format. 23 | public class WaveFileBuffer : ABuffer { 24 | private readonly short[] _Buffer; 25 | private readonly short[] _Bufferp; 26 | private readonly int _Channels; 27 | private readonly WaveFile _OutWave; 28 | 29 | internal WaveFileBuffer(int numberOfChannels, int freq, string fileName) { 30 | if (fileName == null) 31 | throw new NullReferenceException("FileName"); 32 | 33 | _Buffer = new short[OBUFFERSIZE]; 34 | _Bufferp = new short[MAXCHANNELS]; 35 | _Channels = numberOfChannels; 36 | 37 | for (int i = 0; i < numberOfChannels; ++i) 38 | _Bufferp[i] = (short)i; 39 | 40 | _OutWave = new WaveFile(); 41 | 42 | int rc = _OutWave.OpenForWrite(fileName, null, freq, 16, (short)_Channels); 43 | } 44 | 45 | internal WaveFileBuffer(int numberOfChannels, int freq, Stream stream) { 46 | _Buffer = new short[OBUFFERSIZE]; 47 | _Bufferp = new short[MAXCHANNELS]; 48 | _Channels = numberOfChannels; 49 | 50 | for (int i = 0; i < numberOfChannels; ++i) 51 | _Bufferp[i] = (short)i; 52 | 53 | _OutWave = new WaveFile(); 54 | 55 | int rc = _OutWave.OpenForWrite(null, stream, freq, 16, (short)_Channels); 56 | } 57 | 58 | /// 59 | /// Takes a 16 Bit PCM sample. 60 | /// 61 | protected override void Append(int channel, short valueRenamed) { 62 | _Buffer[_Bufferp[channel]] = valueRenamed; 63 | _Bufferp[channel] = (short)(_Bufferp[channel] + _Channels); 64 | } 65 | 66 | internal override void WriteBuffer(int val) { 67 | int rc = _OutWave.WriteData(_Buffer, _Bufferp[0]); 68 | for (int i = 0; i < _Channels; ++i) 69 | _Bufferp[i] = (short)i; 70 | } 71 | 72 | internal void Close(bool justWriteLengthBytes) { 73 | _OutWave.Close(justWriteLengthBytes); 74 | } 75 | 76 | internal override void Close() { 77 | _OutWave.Close(); 78 | } 79 | 80 | /// 81 | /// * 82 | /// 83 | internal override void ClearBuffer() { } 84 | 85 | /// 86 | /// * 87 | /// 88 | internal override void SetStopFlag() { } 89 | } 90 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/SampleBuffer.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * SampleBuffer.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding { 18 | /// 19 | /// The SampleBuffer class implements an output buffer 20 | /// that provides storage for a fixed size block of samples. 21 | /// 22 | public class SampleBuffer : ABuffer { 23 | private readonly short[] _Buffer; 24 | private readonly int[] _Bufferp; 25 | private readonly int _Channels; 26 | private readonly int _Frequency; 27 | 28 | internal SampleBuffer(int sampleFrequency, int numberOfChannels) { 29 | _Buffer = new short[OBUFFERSIZE]; 30 | _Bufferp = new int[MAXCHANNELS]; 31 | _Channels = numberOfChannels; 32 | _Frequency = sampleFrequency; 33 | 34 | for (int i = 0; i < numberOfChannels; ++i) 35 | _Bufferp[i] = (short)i; 36 | } 37 | 38 | internal virtual int ChannelCount => _Channels; 39 | 40 | internal virtual int SampleFrequency => _Frequency; 41 | 42 | internal virtual short[] Buffer => _Buffer; 43 | 44 | internal virtual int BufferLength => _Bufferp[0]; 45 | 46 | /// 47 | /// Takes a 16 Bit PCM sample. 48 | /// 49 | protected override void Append(int channel, short valueRenamed) { 50 | _Buffer[_Bufferp[channel]] = valueRenamed; 51 | _Bufferp[channel] += _Channels; 52 | } 53 | 54 | internal override void AppendSamples(int channel, float[] samples) { 55 | int pos = _Bufferp[channel]; 56 | 57 | short s; 58 | float fs; 59 | for (int i = 0; i < 32;) { 60 | fs = samples[i++]; 61 | fs = fs > 32767.0f ? 32767.0f : fs < -32767.0f ? -32767.0f : fs; 62 | 63 | //UPGRADE_WARNING: Narrowing conversions may produce unexpected results in C#. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1042"' 64 | s = (short)fs; 65 | _Buffer[pos] = s; 66 | pos += _Channels; 67 | } 68 | 69 | _Bufferp[channel] = pos; 70 | } 71 | 72 | /// 73 | /// Write the samples to the file (Random Acces). 74 | /// 75 | internal override void WriteBuffer(int val) { 76 | // for (int i = 0; i < channels; ++i) 77 | // bufferp[i] = (short)i; 78 | } 79 | 80 | internal override void Close() { } 81 | 82 | /// 83 | /// * 84 | /// 85 | internal override void ClearBuffer() { 86 | for (int i = 0; i < _Channels; ++i) 87 | _Bufferp[i] = (short)i; 88 | } 89 | 90 | /// 91 | /// * 92 | /// 93 | internal override void SetStopFlag() { } 94 | } 95 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/PushbackStream.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * PushbackStream.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using System.IO; 19 | 20 | namespace MP3Sharp.Decoding { 21 | /// 22 | /// A PushbackStream is a stream that can "push back" or "unread" data. This is useful in situations where it is convenient for a 23 | /// fragment of code to read an indefinite number of data bytes that are delimited by a particular byte value; after reading the 24 | /// terminating byte, the code fragment can "unread" it, so that the next read operation on the input stream will reread the byte 25 | /// that was pushed back. 26 | /// 27 | public class PushbackStream { 28 | private readonly int _BackBufferSize; 29 | private readonly CircularByteBuffer _CircularByteBuffer; 30 | private readonly Stream _Stream; 31 | private readonly byte[] _TemporaryBuffer; 32 | private int _NumForwardBytesInBuffer; 33 | 34 | internal PushbackStream(Stream s, int backBufferSize) { 35 | _Stream = s; 36 | _BackBufferSize = backBufferSize; 37 | _TemporaryBuffer = new byte[_BackBufferSize]; 38 | _CircularByteBuffer = new CircularByteBuffer(_BackBufferSize); 39 | } 40 | 41 | internal int Read(sbyte[] readBuffer, int offset, int length) { 42 | // Read 43 | int index = 0; 44 | bool canReadStream = true; 45 | while (index < length && canReadStream) { 46 | if (_NumForwardBytesInBuffer > 0) { 47 | // from memory 48 | _NumForwardBytesInBuffer--; 49 | readBuffer[offset + index] = (sbyte)_CircularByteBuffer[_NumForwardBytesInBuffer]; 50 | index++; 51 | } 52 | else { 53 | // from stream 54 | int countBytesToRead = length - index > _TemporaryBuffer.Length ? _TemporaryBuffer.Length : length - index; 55 | int countBytesRead = _Stream.Read(_TemporaryBuffer, 0, countBytesToRead); 56 | canReadStream = countBytesRead >= countBytesToRead; 57 | for (int i = 0; i < countBytesRead; i++) { 58 | _CircularByteBuffer.Push(_TemporaryBuffer[i]); 59 | readBuffer[offset + index + i] = (sbyte)_TemporaryBuffer[i]; 60 | } 61 | index += countBytesRead; 62 | } 63 | } 64 | return index; 65 | } 66 | 67 | internal void UnRead(int length) { 68 | _NumForwardBytesInBuffer += length; 69 | if (_NumForwardBytesInBuffer > _BackBufferSize) { 70 | throw new Exception("The backstream cannot unread the requested number of bytes."); 71 | } 72 | } 73 | 74 | internal void Close() { 75 | _Stream.Close(); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerI/SubbandLayer1Stereo.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * SubbandLayer1Stereo.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerI { 18 | /// 19 | /// public class for layer I subbands in stereo mode. 20 | /// 21 | public class SubbandLayer1Stereo : SubbandLayer1 { 22 | protected int Channel2Allocation; 23 | protected float Channel2Factor, Channel2Offset; 24 | protected float Channel2Sample; 25 | protected int Channel2Samplelength; 26 | protected float Channel2Scalefactor; 27 | 28 | internal SubbandLayer1Stereo(int subbandnumber) 29 | : base(subbandnumber) { } 30 | 31 | /// 32 | /// * 33 | /// 34 | internal override void ReadAllocation(Bitstream stream, Header header, Crc16 crc) { 35 | Allocation = stream.GetBitsFromBuffer(4); 36 | if (Allocation > 14) { 37 | return; 38 | } 39 | Channel2Allocation = stream.GetBitsFromBuffer(4); 40 | if (crc != null) { 41 | crc.AddBits(Allocation, 4); 42 | crc.AddBits(Channel2Allocation, 4); 43 | } 44 | if (Allocation != 0) { 45 | Samplelength = Allocation + 1; 46 | Factor = TableFactor[Allocation]; 47 | Offset = TableOffset[Allocation]; 48 | } 49 | if (Channel2Allocation != 0) { 50 | Channel2Samplelength = Channel2Allocation + 1; 51 | Channel2Factor = TableFactor[Channel2Allocation]; 52 | Channel2Offset = TableOffset[Channel2Allocation]; 53 | } 54 | } 55 | 56 | /// 57 | /// * 58 | /// 59 | internal override void ReadScaleFactor(Bitstream stream, Header header) { 60 | if (Allocation != 0) 61 | Scalefactor = ScaleFactors[stream.GetBitsFromBuffer(6)]; 62 | if (Channel2Allocation != 0) 63 | Channel2Scalefactor = ScaleFactors[stream.GetBitsFromBuffer(6)]; 64 | } 65 | 66 | /// 67 | /// * 68 | /// 69 | internal override bool ReadSampleData(Bitstream stream) { 70 | bool returnvalue = base.ReadSampleData(stream); 71 | if (Channel2Allocation != 0) { 72 | Channel2Sample = stream.GetBitsFromBuffer(Channel2Samplelength); 73 | } 74 | return returnvalue; 75 | } 76 | 77 | /// 78 | /// * 79 | /// 80 | internal override bool PutNextSample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) { 81 | base.PutNextSample(channels, filter1, filter2); 82 | if (Channel2Allocation != 0 && channels != OutputChannels.LEFT_CHANNEL) { 83 | float sample2 = (Channel2Sample * Channel2Factor + Channel2Offset) * Channel2Scalefactor; 84 | if (channels == OutputChannels.BOTH_CHANNELS) 85 | filter2.AddSample(sample2, Subbandnumber); 86 | else 87 | filter1.AddSample(sample2, Subbandnumber); 88 | } 89 | return true; 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | # User-specific files 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Rr]eleases/ 14 | x64/ 15 | x86/ 16 | build/ 17 | bld/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Visual Studio 2015 cache/options directory 22 | .vs/ 23 | 24 | # Roslyn cache directories 25 | *.ide/ 26 | 27 | # MSTest test Results 28 | [Tt]est[Rr]esult*/ 29 | [Bb]uild[Ll]og.* 30 | 31 | #NUNIT 32 | *.VisualState.xml 33 | TestResult.xml 34 | 35 | # Build Results of an ATL Project 36 | [Dd]ebugPS/ 37 | [Rr]eleasePS/ 38 | dlldata.c 39 | 40 | *_i.c 41 | *_p.c 42 | *_i.h 43 | *.ilk 44 | *.meta 45 | *.obj 46 | *.pch 47 | *.pdb 48 | *.pgc 49 | *.pgd 50 | *.rsp 51 | *.sbr 52 | *.tlb 53 | *.tli 54 | *.tlh 55 | *.tmp 56 | *.tmp_proj 57 | *.log 58 | *.vspscc 59 | *.vssscc 60 | .builds 61 | *.pidb 62 | *.svclog 63 | *.scc 64 | 65 | # Chutzpah Test files 66 | _Chutzpah* 67 | 68 | # Visual C++ cache files 69 | ipch/ 70 | *.aps 71 | *.ncb 72 | *.opensdf 73 | *.sdf 74 | *.cachefile 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | *.vspx 80 | 81 | # TFS 2012 Local Workspace 82 | $tf/ 83 | 84 | # Guidance Automation Toolkit 85 | *.gpState 86 | 87 | # ReSharper is a .NET coding add-in 88 | _ReSharper*/ 89 | *.[Rr]e[Ss]harper 90 | *.DotSettings.user 91 | 92 | # JustCode is a .NET coding addin-in 93 | .JustCode 94 | 95 | # TeamCity is a build add-in 96 | _TeamCity* 97 | 98 | # DotCover is a Code Coverage Tool 99 | *.dotCover 100 | 101 | # NCrunch 102 | _NCrunch_* 103 | .*crunch*.local.xml 104 | 105 | # MightyMoose 106 | *.mm.* 107 | AutoTest.Net/ 108 | 109 | # Web workbench (sass) 110 | .sass-cache/ 111 | 112 | # Installshield output folder 113 | [Ee]xpress/ 114 | 115 | # DocProject is a documentation generator add-in 116 | DocProject/buildhelp/ 117 | DocProject/Help/*.HxT 118 | DocProject/Help/*.HxC 119 | DocProject/Help/*.hhc 120 | DocProject/Help/*.hhk 121 | DocProject/Help/*.hhp 122 | DocProject/Help/Html2 123 | DocProject/Help/html 124 | 125 | # Click-Once directory 126 | publish/ 127 | 128 | # Publish Web Output 129 | *.[Pp]ublish.xml 130 | *.azurePubxml 131 | # TODO: Comment the next line if you want to checkin your web deploy settings 132 | # but database connection strings (with potential passwords) will be unencrypted 133 | *.pubxml 134 | *.publishproj 135 | 136 | # NuGet Packages 137 | *.nupkg 138 | # The packages folder can be ignored because of Package Restore 139 | **/packages/* 140 | # except build/, which is used as an MSBuild target. 141 | !**/packages/build/ 142 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 143 | #!**/packages/repositories.config 144 | 145 | # Windows Azure Build Output 146 | csx/ 147 | *.build.csdef 148 | 149 | # Windows Store app package directory 150 | AppPackages/ 151 | 152 | # Others 153 | sql/ 154 | *.Cache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | 165 | # RIA/Silverlight projects 166 | Generated_Code/ 167 | 168 | # Backup & report files from converting an old project file 169 | # to a newer Visual Studio version. Backup files are not needed, 170 | # because we have git ;-) 171 | _UpgradeReport_Files/ 172 | Backup*/ 173 | UpgradeLog*.XML 174 | UpgradeLog*.htm 175 | 176 | # SQL Server files 177 | *.mdf 178 | *.ldf 179 | 180 | # Business Intelligence projects 181 | *.rdl.data 182 | *.bim.layout 183 | *.bim_*.settings 184 | 185 | # Microsoft Fakes 186 | FakesAssemblies/ 187 | 188 | # ========================= 189 | # Operating System Files 190 | # ========================= 191 | 192 | # OSX 193 | # ========================= 194 | 195 | .DS_Store 196 | .AppleDouble 197 | .LSOverride 198 | 199 | # Thumbnails 200 | ._* 201 | 202 | # Files that might appear on external disk 203 | .Spotlight-V100 204 | .Trashes 205 | 206 | # Directories potentially created on remote AFP share 207 | .AppleDB 208 | .AppleDesktop 209 | Network Trash Folder 210 | Temporary Items 211 | .apdisk 212 | 213 | # Windows 214 | # ========================= 215 | 216 | # Windows image file caches 217 | Thumbs.db 218 | ehthumbs.db 219 | 220 | # Folder config file 221 | Desktop.ini 222 | 223 | # Recycle Bin used on file shares 224 | $RECYCLE.BIN/ 225 | 226 | # Windows Installer files 227 | *.cab 228 | *.msi 229 | *.msm 230 | *.msp 231 | 232 | # Windows shortcuts 233 | *.lnk 234 | -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerIDecoder.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * LayerIDecoder.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using MP3Sharp.Decoding.Decoders.LayerI; 18 | 19 | namespace MP3Sharp.Decoding.Decoders { 20 | /// 21 | /// Implements decoding of MPEG Audio Layer I frames. 22 | /// 23 | public class LayerIDecoder : IFrameDecoder { 24 | protected ABuffer Buffer; 25 | protected readonly Crc16 CRC; 26 | protected SynthesisFilter Filter1, Filter2; 27 | protected Header Header; 28 | protected int Mode; 29 | protected int NuSubbands; 30 | protected Bitstream Stream; 31 | protected ASubband[] Subbands; 32 | 33 | protected int WhichChannels; 34 | // new Crc16[1] to enable CRC checking. 35 | 36 | internal LayerIDecoder() { 37 | CRC = new Crc16(); 38 | } 39 | 40 | public virtual void DecodeFrame() { 41 | NuSubbands = Header.NumberSubbands(); 42 | Subbands = new ASubband[32]; 43 | Mode = Header.Mode(); 44 | 45 | CreateSubbands(); 46 | 47 | ReadAllocation(); 48 | ReadScaleFactorSelection(); 49 | 50 | if (CRC != null || Header.IsChecksumOK()) { 51 | ReadScaleFactors(); 52 | 53 | ReadSampleData(); 54 | } 55 | } 56 | 57 | internal virtual void Create(Bitstream stream0, Header header0, SynthesisFilter filtera, SynthesisFilter filterb, 58 | ABuffer buffer0, int whichCh0) { 59 | Stream = stream0; 60 | Header = header0; 61 | Filter1 = filtera; 62 | Filter2 = filterb; 63 | Buffer = buffer0; 64 | WhichChannels = whichCh0; 65 | } 66 | 67 | protected virtual void CreateSubbands() { 68 | int i; 69 | if (Mode == Header.SINGLE_CHANNEL) 70 | for (i = 0; i < NuSubbands; ++i) 71 | Subbands[i] = new SubbandLayer1(i); 72 | else if (Mode == Header.JOINT_STEREO) { 73 | for (i = 0; i < Header.IntensityStereoBound(); ++i) 74 | Subbands[i] = new SubbandLayer1Stereo(i); 75 | for (; i < NuSubbands; ++i) 76 | Subbands[i] = new SubbandLayer1IntensityStereo(i); 77 | } 78 | else { 79 | for (i = 0; i < NuSubbands; ++i) 80 | Subbands[i] = new SubbandLayer1Stereo(i); 81 | } 82 | } 83 | 84 | protected virtual void ReadAllocation() { 85 | // start to read audio data: 86 | for (int i = 0; i < NuSubbands; ++i) 87 | Subbands[i].ReadAllocation(Stream, Header, CRC); 88 | } 89 | 90 | protected virtual void ReadScaleFactorSelection() { 91 | // scale factor selection not present for layer I. 92 | } 93 | 94 | protected virtual void ReadScaleFactors() { 95 | for (int i = 0; i < NuSubbands; ++i) 96 | Subbands[i].ReadScaleFactor(Stream, Header); 97 | } 98 | 99 | protected virtual void ReadSampleData() { 100 | bool readReady = false; 101 | bool writeReady = false; 102 | int hdrMode = Header.Mode(); 103 | do { 104 | int i; 105 | for (i = 0; i < NuSubbands; ++i) 106 | readReady = Subbands[i].ReadSampleData(Stream); 107 | do { 108 | for (i = 0; i < NuSubbands; ++i) 109 | writeReady = Subbands[i].PutNextSample(WhichChannels, Filter1, Filter2); 110 | 111 | Filter1.calculate_pc_samples(Buffer); 112 | if (WhichChannels == OutputChannels.BOTH_CHANNELS && hdrMode != Header.SINGLE_CHANNEL) 113 | Filter2.calculate_pc_samples(Buffer); 114 | } while (!writeReady); 115 | } while (!readReady); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /MP3Sharp.UnitTests/MP3Sharp.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {07CE2D84-445C-420A-BB83-AA94A74F8FB4} 7 | Library 8 | Properties 9 | MP3Sharp.UnitTests 10 | MP3Sharp.UnitTests 11 | v4.0 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 3.5 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | {bf3b29f8-da04-4973-93db-144a5bbe2472} 65 | MP3Sharp 66 | 67 | 68 | 69 | 70 | 71 | 72 | False 73 | 74 | 75 | False 76 | 77 | 78 | False 79 | 80 | 81 | False 82 | 83 | 84 | 85 | 86 | 87 | 88 | 95 | -------------------------------------------------------------------------------- /MP3Sharp/Decoding/BitReserve.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * BitReserve.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding { 18 | /// 19 | /// Implementation of Bit Reservoir for Layer III. 20 | /// The implementation stores single bits as a word in the buffer. If 21 | /// a bit is set, the corresponding word in the buffer will be non-zero. 22 | /// If a bit is clear, the corresponding word is zero. Although this 23 | /// may seem waseful, this can be a factor of two quicker than 24 | /// packing 8 bits to a byte and extracting. 25 | /// 26 | 27 | // REVIEW: there is no range checking, so buffer underflow or overflow 28 | // can silently occur. 29 | internal sealed class BitReserve { 30 | /// 31 | /// Size of the internal buffer to store the reserved bits. 32 | /// Must be a power of 2. And x8, as each bit is stored as a single 33 | /// entry. 34 | /// 35 | private const int BUFSIZE = 4096 * 8; 36 | 37 | /// 38 | /// Mask that can be used to quickly implement the 39 | /// modulus operation on BUFSIZE. 40 | /// 41 | private const int BUFSIZE_MASK = BUFSIZE - 1; 42 | 43 | private int[] _Buffer; 44 | private int _Offset, _Totbit, _BufByteIdx; 45 | 46 | internal BitReserve() { 47 | InitBlock(); 48 | 49 | _Offset = 0; 50 | _Totbit = 0; 51 | _BufByteIdx = 0; 52 | } 53 | 54 | private void InitBlock() { 55 | _Buffer = new int[BUFSIZE]; 56 | } 57 | 58 | /// 59 | /// Return totbit Field. 60 | /// 61 | internal int HssTell() => _Totbit; 62 | 63 | /// 64 | /// Read a number bits from the bit stream. 65 | /// 66 | internal int ReadBits(int n) { 67 | _Totbit += n; 68 | 69 | int val = 0; 70 | 71 | int pos = _BufByteIdx; 72 | if (pos + n < BUFSIZE) { 73 | while (n-- > 0) { 74 | val <<= 1; 75 | val |= _Buffer[pos++] != 0 ? 1 : 0; 76 | } 77 | } 78 | else { 79 | while (n-- > 0) { 80 | val <<= 1; 81 | val |= _Buffer[pos] != 0 ? 1 : 0; 82 | pos = (pos + 1) & BUFSIZE_MASK; 83 | } 84 | } 85 | _BufByteIdx = pos; 86 | return val; 87 | } 88 | 89 | /// 90 | /// Read 1 bit from the bit stream. 91 | /// 92 | internal int ReadOneBit() { 93 | _Totbit++; 94 | int val = _Buffer[_BufByteIdx]; 95 | _BufByteIdx = (_BufByteIdx + 1) & BUFSIZE_MASK; 96 | return val; 97 | } 98 | 99 | /// 100 | /// Write 8 bits into the bit stream. 101 | /// 102 | internal void PutBuffer(int val) { 103 | int ofs = _Offset; 104 | _Buffer[ofs++] = val & 0x80; 105 | _Buffer[ofs++] = val & 0x40; 106 | _Buffer[ofs++] = val & 0x20; 107 | _Buffer[ofs++] = val & 0x10; 108 | _Buffer[ofs++] = val & 0x08; 109 | _Buffer[ofs++] = val & 0x04; 110 | _Buffer[ofs++] = val & 0x02; 111 | _Buffer[ofs++] = val & 0x01; 112 | if (ofs == BUFSIZE) 113 | _Offset = 0; 114 | else 115 | _Offset = ofs; 116 | } 117 | 118 | /// 119 | /// Rewind n bits in Stream. 120 | /// 121 | internal void RewindStreamBits(int bitCount) { 122 | _Totbit -= bitCount; 123 | _BufByteIdx -= bitCount; 124 | if (_BufByteIdx < 0) 125 | _BufByteIdx += BUFSIZE; 126 | } 127 | 128 | /// 129 | /// Rewind n bytes in Stream. 130 | /// 131 | internal void RewindStreamBytes(int byteCount) { 132 | int bits = byteCount << 3; 133 | _Totbit -= bits; 134 | _BufByteIdx -= bits; 135 | if (_BufByteIdx < 0) 136 | _BufByteIdx += BUFSIZE; 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerI/SubbandLayer1.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * SubbandLayer1.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerI { 18 | /// 19 | /// public class for layer I subbands in single channel mode. 20 | /// Used for single channel mode 21 | /// and in derived class for intensity stereo mode 22 | /// 23 | public class SubbandLayer1 : ASubband { 24 | // Factors and offsets for sample requantization 25 | internal static readonly float[] TableFactor = { 26 | 0.0f, 1.0f / 2.0f * (4.0f / 3.0f), 1.0f / 4.0f * (8.0f / 7.0f), 1.0f / 8.0f * (16.0f / 15.0f), 27 | 1.0f / 16.0f * (32.0f / 31.0f), 1.0f / 32.0f * (64.0f / 63.0f), 1.0f / 64.0f * (128.0f / 127.0f), 28 | 1.0f / 128.0f * (256.0f / 255.0f), 1.0f / 256.0f * (512.0f / 511.0f), 1.0f / 512.0f * (1024.0f / 1023.0f), 29 | 1.0f / 1024.0f * (2048.0f / 2047.0f), 1.0f / 2048.0f * (4096.0f / 4095.0f), 1.0f / 4096.0f * (8192.0f / 8191.0f), 30 | 1.0f / 8192.0f * (16384.0f / 16383.0f), 1.0f / 16384.0f * (32768.0f / 32767.0f) 31 | }; 32 | 33 | internal static readonly float[] TableOffset = { 34 | 0.0f, (1.0f / 2.0f - 1.0f) * (4.0f / 3.0f), (1.0f / 4.0f - 1.0f) * (8.0f / 7.0f), 35 | (1.0f / 8.0f - 1.0f) * (16.0f / 15.0f), (1.0f / 16.0f - 1.0f) * (32.0f / 31.0f), 36 | (1.0f / 32.0f - 1.0f) * (64.0f / 63.0f), (1.0f / 64.0f - 1.0f) * (128.0f / 127.0f), 37 | (1.0f / 128.0f - 1.0f) * (256.0f / 255.0f), (1.0f / 256.0f - 1.0f) * (512.0f / 511.0f), 38 | (1.0f / 512.0f - 1.0f) * (1024.0f / 1023.0f), (1.0f / 1024.0f - 1.0f) * (2048.0f / 2047.0f), 39 | (1.0f / 2048.0f - 1.0f) * (4096.0f / 4095.0f), (1.0f / 4096.0f - 1.0f) * (8192.0f / 8191.0f), 40 | (1.0f / 8192.0f - 1.0f) * (16384.0f / 16383.0f), (1.0f / 16384.0f - 1.0f) * (32768.0f / 32767.0f) 41 | }; 42 | 43 | protected int Allocation; 44 | protected float Factor, Offset; 45 | protected float Sample; 46 | protected int Samplelength; 47 | protected int Samplenumber; 48 | protected float Scalefactor; 49 | protected readonly int Subbandnumber; 50 | 51 | /// 52 | /// Construtor. 53 | /// 54 | internal SubbandLayer1(int subbandnumber) { 55 | Subbandnumber = subbandnumber; 56 | Samplenumber = 0; 57 | } 58 | 59 | /// 60 | /// * 61 | /// 62 | internal override void ReadAllocation(Bitstream stream, Header header, Crc16 crc) { 63 | if ((Allocation = stream.GetBitsFromBuffer(4)) == 15) { } 64 | // cerr << "WARNING: stream contains an illegal allocation!\n"; 65 | // MPEG-stream is corrupted! 66 | crc?.AddBits(Allocation, 4); 67 | if (Allocation != 0) { 68 | Samplelength = Allocation + 1; 69 | Factor = TableFactor[Allocation]; 70 | Offset = TableOffset[Allocation]; 71 | } 72 | } 73 | 74 | /// 75 | /// * 76 | /// 77 | internal override void ReadScaleFactor(Bitstream stream, Header header) { 78 | if (Allocation != 0) 79 | Scalefactor = ScaleFactors[stream.GetBitsFromBuffer(6)]; 80 | } 81 | 82 | /// 83 | /// * 84 | /// 85 | internal override bool ReadSampleData(Bitstream stream) { 86 | if (Allocation != 0) { 87 | Sample = stream.GetBitsFromBuffer(Samplelength); 88 | } 89 | if (++Samplenumber == 12) { 90 | Samplenumber = 0; 91 | return true; 92 | } 93 | return false; 94 | } 95 | 96 | /// 97 | /// * 98 | /// 99 | internal override bool PutNextSample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) { 100 | if (Allocation != 0 && channels != OutputChannels.RIGHT_CHANNEL) { 101 | float scaledSample = (Sample * Factor + Offset) * Scalefactor; 102 | filter1.AddSample(scaledSample, Subbandnumber); 103 | } 104 | return true; 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/OutputChannels.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * OutputChannels.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | 19 | namespace MP3Sharp.Decoding { 20 | /// 21 | /// A Type-safe representation of the the supported output channel 22 | /// constants. This class is immutable and, hence, is thread safe. 23 | /// 24 | /// 25 | /// Mat McGowan 26 | /// 27 | public class OutputChannels { 28 | /// 29 | /// Flag to indicate output should include both channels. 30 | /// 31 | internal const int BOTH_CHANNELS = 0; 32 | 33 | /// 34 | /// Flag to indicate output should include the left channel only. 35 | /// 36 | internal const int LEFT_CHANNEL = 1; 37 | 38 | /// 39 | /// Flag to indicate output should include the right channel only. 40 | /// 41 | internal const int RIGHT_CHANNEL = 2; 42 | 43 | /// 44 | /// Flag to indicate output is mono. 45 | /// 46 | internal const int DOWNMIX_CHANNELS = 3; 47 | 48 | internal static readonly OutputChannels Left = new OutputChannels(LEFT_CHANNEL); 49 | internal static readonly OutputChannels Right = new OutputChannels(RIGHT_CHANNEL); 50 | internal static readonly OutputChannels Both = new OutputChannels(BOTH_CHANNELS); 51 | internal static readonly OutputChannels DownMix = new OutputChannels(DOWNMIX_CHANNELS); 52 | private readonly int _OutputChannels; 53 | 54 | private OutputChannels(int channels) { 55 | _OutputChannels = channels; 56 | 57 | if (channels < 0 || channels > 3) { 58 | throw new ArgumentException("channels"); 59 | } 60 | } 61 | 62 | /// 63 | /// Retrieves the code representing the desired output channels. 64 | /// Will be one of LEFT_CHANNEL, RIGHT_CHANNEL, BOTH_CHANNELS 65 | /// or DOWNMIX_CHANNELS. 66 | /// 67 | /// 68 | /// the channel code represented by this instance. 69 | /// 70 | internal virtual int ChannelsOutputCode => _OutputChannels; 71 | 72 | /// 73 | /// Retrieves the number of output channels represented 74 | /// by this channel output type. 75 | /// 76 | /// 77 | /// The number of output channels for this channel output 78 | /// type. This will be 2 for BOTH_CHANNELS only, and 1 79 | /// for all other types. 80 | /// 81 | internal virtual int ChannelCount { 82 | get { 83 | int count = _OutputChannels == BOTH_CHANNELS ? 2 : 1; 84 | return count; 85 | } 86 | } 87 | 88 | /// 89 | /// Creates an OutputChannels instance 90 | /// corresponding to the given channel code. 91 | /// 92 | /// 93 | /// one of the OutputChannels channel code constants. 94 | /// @throws IllegalArgumentException if code is not a valid 95 | /// channel code. 96 | /// 97 | internal static OutputChannels FromInt(int code) { 98 | switch (code) { 99 | case (int)OutputChannelsEnum.LeftChannel: 100 | return Left; 101 | 102 | case (int)OutputChannelsEnum.RightChannel: 103 | return Right; 104 | 105 | case (int)OutputChannelsEnum.BothChannels: 106 | return Both; 107 | 108 | case (int)OutputChannelsEnum.DownmixChannels: 109 | return DownMix; 110 | 111 | default: 112 | throw new ArgumentException("Invalid channel code: " + code); 113 | } 114 | } 115 | 116 | public override bool Equals(object obj) { 117 | bool equals = false; 118 | 119 | if (obj is OutputChannels oc) { 120 | equals = oc._OutputChannels == _OutputChannels; 121 | } 122 | 123 | return equals; 124 | } 125 | 126 | public override int GetHashCode() => _OutputChannels; 127 | } 128 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerII/SubbandLayer2IntensityStereo.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * SubbandLayer2IntensityStereo.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerII { 18 | /// 19 | /// public class for layer II subbands in joint stereo mode. 20 | /// 21 | public class SubbandLayer2IntensityStereo : SubbandLayer2 { 22 | protected float Channel2Scalefactor1, Channel2Scalefactor2, Channel2Scalefactor3; 23 | protected int Channel2Scfsi; 24 | 25 | internal SubbandLayer2IntensityStereo(int subbandnumber) 26 | : base(subbandnumber) { } 27 | 28 | /// 29 | /// * 30 | /// 31 | internal override void ReadScaleFactorSelection(Bitstream stream, Crc16 crc) { 32 | if (Allocation != 0) { 33 | Scfsi = stream.GetBitsFromBuffer(2); 34 | Channel2Scfsi = stream.GetBitsFromBuffer(2); 35 | if (crc != null) { 36 | crc.AddBits(Scfsi, 2); 37 | crc.AddBits(Channel2Scfsi, 2); 38 | } 39 | } 40 | } 41 | 42 | /// 43 | /// * 44 | /// 45 | internal override void ReadScaleFactor(Bitstream stream, Header header) { 46 | if (Allocation != 0) { 47 | base.ReadScaleFactor(stream, header); 48 | switch (Channel2Scfsi) { 49 | case 0: 50 | Channel2Scalefactor1 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 51 | Channel2Scalefactor2 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 52 | Channel2Scalefactor3 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 53 | break; 54 | 55 | case 1: 56 | Channel2Scalefactor1 = Channel2Scalefactor2 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 57 | Channel2Scalefactor3 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 58 | break; 59 | 60 | case 2: 61 | Channel2Scalefactor1 = 62 | Channel2Scalefactor2 = Channel2Scalefactor3 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 63 | break; 64 | 65 | case 3: 66 | Channel2Scalefactor1 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 67 | Channel2Scalefactor2 = Channel2Scalefactor3 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 68 | break; 69 | } 70 | } 71 | } 72 | 73 | /// 74 | /// * 75 | /// 76 | internal override bool PutNextSample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) { 77 | if (Allocation != 0) { 78 | float sample = Samples[Samplenumber]; 79 | 80 | if (Groupingtable[0] == null) 81 | sample = (sample + D[0]) * CFactor[0]; 82 | if (channels == OutputChannels.BOTH_CHANNELS) { 83 | float sample2 = sample; 84 | if (Groupnumber <= 4) { 85 | sample *= Scalefactor1; 86 | sample2 *= Channel2Scalefactor1; 87 | } 88 | else if (Groupnumber <= 8) { 89 | sample *= Scalefactor2; 90 | sample2 *= Channel2Scalefactor2; 91 | } 92 | else { 93 | sample *= Scalefactor3; 94 | sample2 *= Channel2Scalefactor3; 95 | } 96 | filter1.AddSample(sample, Subbandnumber); 97 | filter2.AddSample(sample2, Subbandnumber); 98 | } 99 | else if (channels == OutputChannels.LEFT_CHANNEL) { 100 | if (Groupnumber <= 4) 101 | sample *= Scalefactor1; 102 | else if (Groupnumber <= 8) 103 | sample *= Scalefactor2; 104 | else 105 | sample *= Scalefactor3; 106 | filter1.AddSample(sample, Subbandnumber); 107 | } 108 | else { 109 | if (Groupnumber <= 4) 110 | sample *= Channel2Scalefactor1; 111 | else if (Groupnumber <= 8) 112 | sample *= Channel2Scalefactor2; 113 | else 114 | sample *= Channel2Scalefactor3; 115 | filter1.AddSample(sample, Subbandnumber); 116 | } 117 | } 118 | 119 | if (++Samplenumber == 3) 120 | return true; 121 | return false; 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /XNA4Sample/XNA4Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {78695BFC-A1B8-4A8D-97BE-3D75AF8E2778} 5 | {6D335F3A-9D43-41b4-9D22-F6F17C4BE596};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 6 | Debug 7 | x86 8 | Exe 9 | Properties 10 | XNA4Sample 11 | XNA4Sample 12 | v4.0 13 | Client 14 | v4.0 15 | Windows 16 | Reach 17 | cdcd8436-d04a-41f0-b287-276c7f64adf6 18 | Game 19 | 20 | 21 | 22 | 23 | publish\ 24 | true 25 | Disk 26 | false 27 | Foreground 28 | 7 29 | Days 30 | false 31 | false 32 | true 33 | 0 34 | 1.0.0.%2a 35 | false 36 | false 37 | true 38 | 39 | 40 | true 41 | full 42 | false 43 | bin\x86\Debug 44 | DEBUG;TRACE;WINDOWS 45 | prompt 46 | 4 47 | true 48 | false 49 | x86 50 | false 51 | 52 | 53 | pdbonly 54 | true 55 | bin\x86\Release 56 | TRACE;WINDOWS 57 | prompt 58 | 4 59 | true 60 | false 61 | x86 62 | true 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | Always 84 | 85 | 86 | 87 | 88 | False 89 | Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 90 | true 91 | 92 | 93 | False 94 | .NET Framework 3.5 SP1 Client Profile 95 | false 96 | 97 | 98 | False 99 | .NET Framework 3.5 SP1 100 | false 101 | 102 | 103 | False 104 | Windows Installer 4.5 105 | true 106 | 107 | 108 | 109 | 110 | {bf3b29f8-da04-4973-93db-144a5bbe2472} 111 | MP3Sharp 112 | 113 | 114 | 115 | 116 | 124 | -------------------------------------------------------------------------------- /MP3Sharp/Decoding/CircularByteBuffer.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * CircularByteBuffer.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | 19 | namespace MP3Sharp.Decoding { 20 | [Serializable] 21 | internal class CircularByteBuffer { 22 | private byte[] _Buffer; 23 | private int _Index; 24 | private int _Length; 25 | private int _NumValid; 26 | 27 | internal CircularByteBuffer(int size) { 28 | _Buffer = new byte[size]; 29 | _Length = size; 30 | } 31 | 32 | /// 33 | /// Initialize by copying the CircularByteBuffer passed in 34 | /// 35 | internal CircularByteBuffer(CircularByteBuffer cdb) { 36 | lock (cdb) { 37 | _Length = cdb._Length; 38 | _NumValid = cdb._NumValid; 39 | _Index = cdb._Index; 40 | _Buffer = new byte[_Length]; 41 | for (int c = 0; c < _Length; c++) { 42 | _Buffer[c] = cdb._Buffer[c]; 43 | } 44 | } 45 | } 46 | 47 | /// 48 | /// The physical size of the Buffer (read/write) 49 | /// 50 | internal int BufferSize { 51 | get => _Length; 52 | set { 53 | byte[] newDataArray = new byte[value]; 54 | 55 | int minLength = _Length > value ? value : _Length; 56 | for (int i = 0; i < minLength; i++) { 57 | newDataArray[i] = InternalGet(i - _Length + 1); 58 | } 59 | _Buffer = newDataArray; 60 | _Index = minLength - 1; 61 | _Length = value; 62 | } 63 | } 64 | 65 | /// 66 | /// e.g. Offset[0] is the current value 67 | /// 68 | internal byte this[int index] { 69 | get => InternalGet(-1 - index); 70 | set => InternalSet(-1 - index, value); 71 | } 72 | 73 | /// 74 | /// How far back it is safe to look (read/write). Write only to reduce NumValid. 75 | /// 76 | internal int NumValid { 77 | get => _NumValid; 78 | set { 79 | if (value > _NumValid) 80 | throw new Exception("Can't set NumValid to " + value + 81 | " which is greater than the current numValid value of " + _NumValid); 82 | _NumValid = value; 83 | } 84 | } 85 | 86 | internal CircularByteBuffer Copy() => new CircularByteBuffer(this); 87 | 88 | internal void Reset() { 89 | _Index = 0; 90 | _NumValid = 0; 91 | } 92 | 93 | /// 94 | /// Push a byte into the buffer. Returns the value of whatever comes off. 95 | /// 96 | internal byte Push(byte newValue) { 97 | byte ret; 98 | lock (this) { 99 | ret = InternalGet(_Length); 100 | _Buffer[_Index] = newValue; 101 | _NumValid++; 102 | if (_NumValid > _Length) _NumValid = _Length; 103 | _Index++; 104 | _Index %= _Length; 105 | } 106 | return ret; 107 | } 108 | 109 | /// 110 | /// Pop an integer off the start of the buffer. Throws an exception if the buffer is empty (NumValid == 0) 111 | /// 112 | internal byte Pop() { 113 | lock (this) { 114 | if (_NumValid == 0) throw new Exception("Can't pop off an empty CircularByteBuffer"); 115 | _NumValid--; 116 | return this[_NumValid]; 117 | } 118 | } 119 | 120 | /// 121 | /// Returns what would fall out of the buffer on a Push. NOT the same as what you'd get with a Pop(). 122 | /// 123 | internal byte Peek() { 124 | lock (this) { 125 | return InternalGet(_Length); 126 | } 127 | } 128 | 129 | private byte InternalGet(int offset) { 130 | int ind = _Index + offset; 131 | 132 | // Do thin modulo (should just drop through) 133 | for (; ind >= _Length; ind -= _Length) { } 134 | for (; ind < 0; ind += _Length) { } 135 | // Set value 136 | return _Buffer[ind]; 137 | } 138 | 139 | private void InternalSet(int offset, byte valueToSet) { 140 | int ind = _Index + offset; 141 | 142 | // Do thin modulo (should just drop through) 143 | for (; ind > _Length; ind -= _Length) { } 144 | 145 | for (; ind < 0; ind += _Length) { } 146 | // Set value 147 | _Buffer[ind] = valueToSet; 148 | } 149 | 150 | /// 151 | /// Returns a range (in terms of Offsets) in an int array in chronological (oldest-to-newest) order. e.g. (3, 0) 152 | /// returns the last four ints pushed, with result[3] being the most recent. 153 | /// 154 | internal byte[] GetRange(int str, int stp) { 155 | byte[] outByte = new byte[str - stp + 1]; 156 | 157 | for (int i = str, j = 0; i >= stp; i--, j++) { 158 | outByte[j] = this[i]; 159 | } 160 | 161 | return outByte; 162 | } 163 | 164 | public override string ToString() { 165 | string ret = ""; 166 | for (int i = 0; i < _Buffer.Length; i++) { 167 | ret += _Buffer[i] + " "; 168 | } 169 | ret += "\n index = " + _Index + " numValid = " + NumValid; 170 | return ret; 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /MP3Sharp/MP3Sharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {2C379A78-8A96-48A5-81E5-EA0AE696AA5B} 8 | Library 9 | Properties 10 | MP3Sharp 11 | MP3Sharp 12 | v4.6.2 13 | 512 14 | false 15 | 16 | 17 | true 18 | bin\x64\Debug\ 19 | DEBUG;TRACE 20 | full 21 | x64 22 | prompt 23 | MinimumRecommendedRules.ruleset 24 | false 25 | 26 | 27 | bin\x64\Release\ 28 | TRACE 29 | true 30 | x64 31 | prompt 32 | MinimumRecommendedRules.ruleset 33 | false 34 | 35 | 36 | true 37 | bin\x64\Debug-x64\ 38 | DEBUG;TRACE 39 | full 40 | x64 41 | prompt 42 | MinimumRecommendedRules.ruleset 43 | false 44 | 45 | 46 | true 47 | bin\Debug\ 48 | DEBUG;TRACE 49 | full 50 | AnyCPU 51 | prompt 52 | MinimumRecommendedRules.ruleset 53 | false 54 | 55 | 56 | bin\Release\ 57 | TRACE 58 | true 59 | AnyCPU 60 | prompt 61 | MinimumRecommendedRules.ruleset 62 | false 63 | 64 | 65 | true 66 | bin\Debug-x64\ 67 | DEBUG;TRACE 68 | full 69 | AnyCPU 70 | prompt 71 | MinimumRecommendedRules.ruleset 72 | false 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /MP3Sharp/Support/SupportClass.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * SupportClass.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using System.IO; 19 | 20 | namespace MP3Sharp.Support { 21 | public class SupportClass { 22 | internal static int URShift(int number, int bits) { 23 | if (number >= 0) 24 | return number >> bits; 25 | return (number >> bits) + (2 << ~bits); 26 | } 27 | 28 | internal static int URShift(int number, long bits) { 29 | return URShift(number, (int)bits); 30 | } 31 | 32 | internal static long URShift(long number, int bits) { 33 | if (number >= 0) 34 | return number >> bits; 35 | return (number >> bits) + (2L << ~bits); 36 | } 37 | 38 | internal static long URShift(long number, long bits) { 39 | return URShift(number, (int)bits); 40 | } 41 | 42 | internal static void WriteStackTrace(Exception throwable, TextWriter stream) { 43 | stream.Write(throwable.StackTrace); 44 | stream.Flush(); 45 | } 46 | 47 | /// 48 | /// This method is used as a dummy method to simulate VJ++ behavior 49 | /// 50 | /// The literal to return 51 | /// The received value 52 | internal static long Identity(long literal) { 53 | return literal; 54 | } 55 | 56 | /// 57 | /// This method is used as a dummy method to simulate VJ++ behavior 58 | /// 59 | /// The literal to return 60 | /// The received value 61 | internal static ulong Identity(ulong literal) { 62 | return literal; 63 | } 64 | 65 | /// 66 | /// This method is used as a dummy method to simulate VJ++ behavior 67 | /// 68 | /// The literal to return 69 | /// The received value 70 | internal static float Identity(float literal) { 71 | return literal; 72 | } 73 | 74 | /// 75 | /// This method is used as a dummy method to simulate VJ++ behavior 76 | /// 77 | /// The literal to return 78 | /// The received value 79 | internal static double Identity(double literal) { 80 | return literal; 81 | } 82 | 83 | /// 84 | /// Reads a number of characters from the current source Stream and writes the data to the target array at the 85 | /// specified index. 86 | /// 87 | /// The source Stream to read from 88 | /// Contains the array of characteres read from the source Stream. 89 | /// The starting index of the target array. 90 | /// The maximum number of characters to read from the source Stream. 91 | /// 92 | /// The number of characters read. The number will be less than or equal to count depending on the data available 93 | /// in the source Stream. 94 | /// 95 | internal static int ReadInput(Stream sourceStream, ref sbyte[] target, int start, int count) { 96 | byte[] receiver = new byte[target.Length]; 97 | int bytesRead = sourceStream.Read(receiver, start, count); 98 | 99 | for (int i = start; i < start + bytesRead; i++) 100 | target[i] = (sbyte)receiver[i]; 101 | 102 | return bytesRead; 103 | } 104 | 105 | /// 106 | /// Converts an array of sbytes to an array of bytes 107 | /// 108 | /// The array of sbytes to be converted 109 | /// The new array of bytes 110 | internal static byte[] ToByteArray(sbyte[] sbyteArray) { 111 | byte[] byteArray = new byte[sbyteArray.Length]; 112 | for (int index = 0; index < sbyteArray.Length; index++) 113 | byteArray[index] = (byte)sbyteArray[index]; 114 | return byteArray; 115 | } 116 | 117 | /// 118 | /// Converts a string to an array of bytes 119 | /// 120 | /// The string to be converted 121 | /// The new array of bytes 122 | internal static byte[] ToByteArray(string sourceString) { 123 | byte[] byteArray = new byte[sourceString.Length]; 124 | for (int index = 0; index < sourceString.Length; index++) 125 | byteArray[index] = (byte)sourceString[index]; 126 | return byteArray; 127 | } 128 | 129 | /// 130 | /// Method that copies an array of sbytes from a String to a received array. 131 | /// 132 | /// The String to get the sbytes. 133 | /// Position in the String to start getting sbytes. 134 | /// Position in the String to end getting sbytes. 135 | /// Array to store the bytes. 136 | /// Position in the destination array to start storing the sbytes. 137 | /// An array of sbytes 138 | internal static void GetSBytesFromString(string sourceString, int sourceStart, int sourceEnd, 139 | ref sbyte[] destinationArray, int destinationStart) { 140 | int sourceCounter; 141 | int destinationCounter; 142 | sourceCounter = sourceStart; 143 | destinationCounter = destinationStart; 144 | while (sourceCounter < sourceEnd) { 145 | destinationArray[destinationCounter] = (sbyte)sourceString[sourceCounter]; 146 | sourceCounter++; 147 | destinationCounter++; 148 | } 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /MP3Sharp/Buffer16BitStereo.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * Buffer16BitStereo.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using MP3Sharp.Decoding; 19 | 20 | namespace MP3Sharp { 21 | /// 22 | /// public class used to queue samples that are being obtained from an Mp3 stream. 23 | /// This class handles stereo 16-bit output, and can double 16-bit mono to stereo. 24 | /// 25 | public class Buffer16BitStereo : ABuffer { 26 | internal bool DoubleMonoToStereo = false; 27 | 28 | private const int OUTPUT_CHANNELS = 2; 29 | 30 | // Write offset used in append_bytes 31 | private readonly byte[] _Buffer = new byte[OBUFFERSIZE * 2]; // all channels interleaved 32 | private readonly int[] _BufferChannelOffsets = new int[MAXCHANNELS]; // contains write offset for each channel. 33 | 34 | // end marker, one past end of array. Same as bufferp[0], but 35 | // without the array bounds check. 36 | private int _End; 37 | 38 | // Read offset used to read from the stream, in bytes. 39 | private int _Offset; 40 | 41 | internal Buffer16BitStereo() { 42 | // Initialize the buffer pointers 43 | ClearBuffer(); 44 | } 45 | 46 | /// 47 | /// Gets the number of bytes remaining from the current position on the buffer. 48 | /// 49 | internal int BytesLeft => _End - _Offset; 50 | 51 | /// 52 | /// Reads a sequence of bytes from the buffer and advances the position of the 53 | /// buffer by the number of bytes read. 54 | /// 55 | /// 56 | /// The total number of bytes read in to the buffer. This can be less than the 57 | /// number of bytes requested if that many bytes are not currently available, or 58 | /// zero if th eend of the buffer has been reached. 59 | /// 60 | internal int Read(byte[] bufferOut, int offset, int count) { 61 | if (bufferOut == null) { 62 | throw new ArgumentNullException(nameof(bufferOut)); 63 | } 64 | if ((count + offset) > bufferOut.Length) { 65 | throw new ArgumentException("The sum of offset and count is larger than the buffer length"); 66 | } 67 | int remaining = BytesLeft; 68 | int copySize; 69 | if (count > remaining) { 70 | copySize = remaining; 71 | } 72 | else { 73 | // Copy an even number of sample frames 74 | int remainder = count % (2 * OUTPUT_CHANNELS); 75 | copySize = count - remainder; 76 | } 77 | Array.Copy(_Buffer, _Offset, bufferOut, offset, copySize); 78 | _Offset += copySize; 79 | return copySize; 80 | } 81 | 82 | /// 83 | /// Writes a single sample value to the buffer. 84 | /// 85 | /// The channel. 86 | /// The sample value. 87 | protected override void Append(int channel, short sampleValue) { 88 | _Buffer[_BufferChannelOffsets[channel]] = (byte)(sampleValue & 0xff); 89 | _Buffer[_BufferChannelOffsets[channel] + 1] = (byte)(sampleValue >> 8); 90 | _BufferChannelOffsets[channel] += OUTPUT_CHANNELS * 2; 91 | } 92 | 93 | /// 94 | /// Writes 32 samples to the buffer. 95 | /// 96 | /// The channel. 97 | /// An array of sample values. 98 | /// 99 | /// The parameter must have a length equal to 100 | /// or greater than 32. 101 | /// 102 | internal override void AppendSamples(int channel, float[] samples) { 103 | if (samples == null) { 104 | // samples is required. 105 | throw new ArgumentNullException(nameof(samples)); 106 | } 107 | if (samples.Length < 32) { 108 | throw new ArgumentException("samples must have 32 values"); 109 | } 110 | if (_BufferChannelOffsets == null || channel >= _BufferChannelOffsets.Length) { 111 | throw new Exception("Song is closing..."); 112 | } 113 | int pos = _BufferChannelOffsets[channel]; 114 | // Always, 32 samples are appended 115 | for (int i = 0; i < 32; i++) { 116 | float fs = samples[i]; 117 | // clamp values 118 | if (fs > 32767.0f) { 119 | fs = 32767.0f; 120 | } 121 | else if (fs < -32767.0f) { 122 | fs = -32767.0f; 123 | } 124 | int sample = (int)fs; 125 | _Buffer[pos] = (byte)(sample & 0xff); 126 | _Buffer[pos + 1] = (byte)(sample >> 8); 127 | if (DoubleMonoToStereo) { 128 | _Buffer[pos + 2] = (byte)(sample & 0xff); 129 | _Buffer[pos + 3] = (byte)(sample >> 8); 130 | } 131 | pos += OUTPUT_CHANNELS * 2; 132 | } 133 | _BufferChannelOffsets[channel] = pos; 134 | } 135 | 136 | /// 137 | /// This implementation does not clear the buffer. 138 | /// 139 | internal sealed override void ClearBuffer() { 140 | _Offset = 0; 141 | _End = 0; 142 | for (int i = 0; i < OUTPUT_CHANNELS; i++) 143 | _BufferChannelOffsets[i] = i * 2; // two bytes per channel 144 | } 145 | 146 | internal override void SetStopFlag() { } 147 | 148 | internal override void WriteBuffer(int val) { 149 | _Offset = 0; 150 | // speed optimization - save end marker, and avoid 151 | // array access at read time. Can you believe this saves 152 | // like 1-2% of the cpu on a PIII? I guess allocating 153 | // that temporary "new int(0)" is expensive, too. 154 | _End = _BufferChannelOffsets[0]; 155 | } 156 | 157 | internal override void Close() { } 158 | } 159 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Equalizer.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * Equalizer.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | 19 | namespace MP3Sharp.Decoding { 20 | /// 21 | /// The Equalizer class can be used to specify 22 | /// equalization settings for the MPEG audio decoder. 23 | /// The equalizer consists of 32 band-pass filters. 24 | /// Each band of the equalizer can take on a fractional value between 25 | /// -1.0 and +1.0. 26 | /// At -1.0, the input signal is attenuated by 6dB, at +1.0 the signal is 27 | /// amplified by 6dB. 28 | /// 29 | public class Equalizer { 30 | private const int BANDS = 32; 31 | 32 | /// 33 | /// Equalizer setting to denote that a given band will not be 34 | /// present in the output signal. 35 | /// 36 | internal const float BAND_NOT_PRESENT = float.NegativeInfinity; 37 | 38 | internal static readonly Equalizer PassThruEq = new Equalizer(); 39 | private float[] _Settings; 40 | 41 | /// 42 | /// Creates a new Equalizer instance. 43 | /// 44 | internal Equalizer() { 45 | InitBlock(); 46 | } 47 | 48 | // private Equalizer(float b1, float b2, float b3, float b4, float b5, 49 | // float b6, float b7, float b8, float b9, float b10, float b11, 50 | // float b12, float b13, float b14, float b15, float b16, 51 | // float b17, float b18, float b19, float b20); 52 | 53 | internal Equalizer(float[] settings) { 54 | InitBlock(); 55 | FromFloatArray = settings; 56 | } 57 | 58 | internal Equalizer(EQFunction eq) { 59 | InitBlock(); 60 | FromEQFunction = eq; 61 | } 62 | 63 | internal float[] FromFloatArray { 64 | set { 65 | Reset(); 66 | int max = value.Length > BANDS ? BANDS : value.Length; 67 | 68 | for (int i = 0; i < max; i++) { 69 | _Settings[i] = Limit(value[i]); 70 | } 71 | } 72 | } 73 | 74 | //UPGRADE_TODO: Method 'setFrom' was converted to a set modifier. This name conflicts with another property. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1137"' 75 | /// 76 | /// Sets the bands of this equalizer to the value the bands of 77 | /// another equalizer. Bands that are not present in both equalizers are ignored. 78 | /// 79 | internal virtual Equalizer FromEqualizer { 80 | set { 81 | if (value != this) { 82 | FromFloatArray = value._Settings; 83 | } 84 | } 85 | } 86 | 87 | //UPGRADE_TODO: Method 'setFrom' was converted to a set modifier. This name conflicts with another property. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1137"' 88 | internal EQFunction FromEQFunction { 89 | set { 90 | Reset(); 91 | int max = BANDS; 92 | 93 | for (int i = 0; i < max; i++) { 94 | _Settings[i] = Limit(value.GetBand(i)); 95 | } 96 | } 97 | } 98 | 99 | /// 100 | /// Retrieves the number of bands present in this equalizer. 101 | /// 102 | internal virtual int BandCount => _Settings.Length; 103 | 104 | /// 105 | /// Retrieves an array of floats whose values represent a 106 | /// scaling factor that can be applied to linear samples 107 | /// in each band to provide the equalization represented by 108 | /// this instance. 109 | /// 110 | /// 111 | /// an array of factors that can be applied to the 112 | /// subbands. 113 | /// 114 | internal virtual float[] BandFactors { 115 | get { 116 | float[] factors = new float[BANDS]; 117 | for (int i = 0; i < BANDS; i++) { 118 | factors[i] = GetBandFactor(_Settings[i]); 119 | } 120 | 121 | return factors; 122 | } 123 | } 124 | 125 | private void InitBlock() { 126 | _Settings = new float[BANDS]; 127 | } 128 | 129 | /// 130 | /// Sets all bands to 0.0 131 | /// 132 | internal void Reset() { 133 | for (int i = 0; i < BANDS; i++) { 134 | _Settings[i] = 0.0f; 135 | } 136 | } 137 | 138 | internal float SetBand(int band, float neweq) { 139 | float eq = 0.0f; 140 | 141 | if (band >= 0 && band < BANDS) { 142 | eq = _Settings[band]; 143 | _Settings[band] = Limit(neweq); 144 | } 145 | 146 | return eq; 147 | } 148 | 149 | /// 150 | /// Retrieves the eq setting for a given band. 151 | /// 152 | internal float GetBand(int band) { 153 | float eq = 0.0f; 154 | 155 | if (band >= 0 && band < BANDS) { 156 | eq = _Settings[band]; 157 | } 158 | 159 | return eq; 160 | } 161 | 162 | private float Limit(float eq) { 163 | if (eq == BAND_NOT_PRESENT) 164 | return eq; 165 | if (eq > 1.0f) 166 | return 1.0f; 167 | if (eq < -1.0f) 168 | return -1.0f; 169 | 170 | return eq; 171 | } 172 | 173 | /// 174 | /// Converts an equalizer band setting to a sample factor. 175 | /// The factor is determined by the function f = 2^n where 176 | /// n is the equalizer band setting in the range [-1.0,1.0]. 177 | /// 178 | internal float GetBandFactor(float eq) { 179 | if (eq == BAND_NOT_PRESENT) 180 | return 0.0f; 181 | 182 | float f = (float)Math.Pow(2.0, eq); 183 | return f; 184 | } 185 | 186 | internal abstract class EQFunction { 187 | /// 188 | /// Returns the setting of a band in the equalizer. 189 | /// 190 | /// 191 | /// The index of the band to retrieve the setting for. 192 | /// 193 | /// 194 | /// the setting of the specified band. This is a value between 195 | /// -1 and +1. 196 | /// 197 | internal virtual float GetBand(int band) => 0.0f; 198 | } 199 | } 200 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoders/LayerII/SubbandLayer2Stereo.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * SubbandLayer2Stereo.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | namespace MP3Sharp.Decoding.Decoders.LayerII { 18 | /// 19 | /// public class for layer II subbands in stereo mode. 20 | /// 21 | public class SubbandLayer2Stereo : SubbandLayer2 { 22 | protected int Channel2Allocation; 23 | protected readonly float[] Channel2C = {0}; 24 | protected readonly int[] Channel2Codelength = {0}; 25 | protected readonly float[] Channel2D = {0}; 26 | protected readonly float[] Channel2Factor = {0}; 27 | protected readonly float[] Channel2Samples; 28 | protected float Channel2Scalefactor1, Channel2Scalefactor2, Channel2Scalefactor3; 29 | protected int Channel2Scfsi; 30 | 31 | internal SubbandLayer2Stereo(int subbandnumber) 32 | : base(subbandnumber) { 33 | Channel2Samples = new float[3]; 34 | } 35 | 36 | /// 37 | /// * 38 | /// 39 | internal override void ReadAllocation(Bitstream stream, Header header, Crc16 crc) { 40 | int length = GetAllocationLength(header); 41 | Allocation = stream.GetBitsFromBuffer(length); 42 | Channel2Allocation = stream.GetBitsFromBuffer(length); 43 | if (crc != null) { 44 | crc.AddBits(Allocation, length); 45 | crc.AddBits(Channel2Allocation, length); 46 | } 47 | } 48 | 49 | /// 50 | /// * 51 | /// 52 | internal override void ReadScaleFactorSelection(Bitstream stream, Crc16 crc) { 53 | if (Allocation != 0) { 54 | Scfsi = stream.GetBitsFromBuffer(2); 55 | crc?.AddBits(Scfsi, 2); 56 | } 57 | if (Channel2Allocation != 0) { 58 | Channel2Scfsi = stream.GetBitsFromBuffer(2); 59 | crc?.AddBits(Channel2Scfsi, 2); 60 | } 61 | } 62 | 63 | /// 64 | /// * 65 | /// 66 | internal override void ReadScaleFactor(Bitstream stream, Header header) { 67 | base.ReadScaleFactor(stream, header); 68 | if (Channel2Allocation != 0) { 69 | switch (Channel2Scfsi) { 70 | case 0: 71 | Channel2Scalefactor1 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 72 | Channel2Scalefactor2 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 73 | Channel2Scalefactor3 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 74 | break; 75 | 76 | case 1: 77 | Channel2Scalefactor1 = Channel2Scalefactor2 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 78 | Channel2Scalefactor3 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 79 | break; 80 | 81 | case 2: 82 | Channel2Scalefactor1 = 83 | Channel2Scalefactor2 = Channel2Scalefactor3 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 84 | break; 85 | 86 | case 3: 87 | Channel2Scalefactor1 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 88 | Channel2Scalefactor2 = Channel2Scalefactor3 = ScaleFactors[stream.GetBitsFromBuffer(6)]; 89 | break; 90 | } 91 | PrepareForSampleRead(header, Channel2Allocation, 1, Channel2Factor, Channel2Codelength, 92 | Channel2C, Channel2D); 93 | } 94 | } 95 | 96 | /// 97 | /// * 98 | /// 99 | internal override bool ReadSampleData(Bitstream stream) { 100 | bool returnvalue = base.ReadSampleData(stream); 101 | 102 | if (Channel2Allocation != 0) 103 | if (Groupingtable[1] != null) { 104 | int samplecode = stream.GetBitsFromBuffer(Channel2Codelength[0]); 105 | // create requantized samples: 106 | samplecode += samplecode << 1; 107 | /* 108 | float[] target = channel2_samples; 109 | float[] source = channel2_groupingtable[0]; 110 | int tmp = 0; 111 | int temp = 0; 112 | target[tmp++] = source[samplecode + temp]; 113 | temp++; 114 | target[tmp++] = source[samplecode + temp]; 115 | temp++; 116 | target[tmp] = source[samplecode + temp]; 117 | // memcpy (channel2_samples, channel2_groupingtable + samplecode, 3 * sizeof (real)); 118 | */ 119 | float[] target = Channel2Samples; 120 | float[] source = Groupingtable[1]; 121 | int tmp = 0; 122 | int temp = samplecode; 123 | target[tmp] = source[temp]; 124 | temp++; 125 | tmp++; 126 | target[tmp] = source[temp]; 127 | temp++; 128 | tmp++; 129 | target[tmp] = source[temp]; 130 | } 131 | else { 132 | Channel2Samples[0] = 133 | (float)(stream.GetBitsFromBuffer(Channel2Codelength[0]) * Channel2Factor[0] - 1.0); 134 | Channel2Samples[1] = 135 | (float)(stream.GetBitsFromBuffer(Channel2Codelength[0]) * Channel2Factor[0] - 1.0); 136 | Channel2Samples[2] = 137 | (float)(stream.GetBitsFromBuffer(Channel2Codelength[0]) * Channel2Factor[0] - 1.0); 138 | } 139 | return returnvalue; 140 | } 141 | 142 | /// 143 | /// * 144 | /// 145 | internal override bool PutNextSample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) { 146 | bool returnvalue = base.PutNextSample(channels, filter1, filter2); 147 | if (Channel2Allocation != 0 && channels != OutputChannels.LEFT_CHANNEL) { 148 | float sample = Channel2Samples[Samplenumber - 1]; 149 | 150 | if (Groupingtable[1] == null) 151 | sample = (sample + Channel2D[0]) * Channel2C[0]; 152 | 153 | if (Groupnumber <= 4) 154 | sample *= Channel2Scalefactor1; 155 | else if (Groupnumber <= 8) 156 | sample *= Channel2Scalefactor2; 157 | else 158 | sample *= Channel2Scalefactor3; 159 | if (channels == OutputChannels.BOTH_CHANNELS) 160 | filter2.AddSample(sample, Subbandnumber); 161 | else 162 | filter1.AddSample(sample, Subbandnumber); 163 | } 164 | return returnvalue; 165 | } 166 | } 167 | } -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /MP3Sharp/IO/WaveFile.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * WaveFile.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System.IO; 18 | using MP3Sharp.Support; 19 | 20 | namespace MP3Sharp.IO { 21 | /// 22 | /// public class allowing WaveFormat Access 23 | /// 24 | public class WaveFile : RiffFile { 25 | internal const int MAX_WAVE_CHANNELS = 2; 26 | private readonly int _NumSamples; 27 | private readonly RiffChunkHeader _PcmData; 28 | private readonly WaveFormatChunk _WaveFormat; 29 | private bool _JustWriteLengthBytes; 30 | private long _PcmDataOffset; // offset of 'pc_data' in output file 31 | 32 | /// 33 | /// Creates a new WaveFile instance. 34 | /// 35 | internal WaveFile() { 36 | _PcmData = new RiffChunkHeader(this); 37 | _WaveFormat = new WaveFormatChunk(this); 38 | _PcmData.CkId = FourCC("data"); 39 | _PcmData.CkSize = 0; 40 | _NumSamples = 0; 41 | } 42 | 43 | /// 44 | /// Pass in either a FileName or a Stream. 45 | /// 46 | internal virtual int OpenForWrite(string filename, Stream stream, int samplingRate, short bitsPerSample, 47 | short numChannels) { 48 | // Verify parameters... 49 | if ((bitsPerSample != 8 && bitsPerSample != 16) || numChannels < 1 || numChannels > 2) { 50 | return DDC_INVALID_CALL; 51 | } 52 | 53 | _WaveFormat.Data.Config(samplingRate, bitsPerSample, numChannels); 54 | 55 | int retcode = DDC_SUCCESS; 56 | if (stream != null) 57 | Open(stream, RF_WRITE); 58 | else 59 | Open(filename, RF_WRITE); 60 | 61 | if (retcode == DDC_SUCCESS) { 62 | sbyte[] theWave = { 63 | (sbyte)SupportClass.Identity('W'), (sbyte)SupportClass.Identity('A'), 64 | (sbyte)SupportClass.Identity('V'), (sbyte)SupportClass.Identity('E') 65 | }; 66 | retcode = Write(theWave, 4); 67 | 68 | if (retcode == DDC_SUCCESS) { 69 | // Ecriture de wave_format 70 | retcode = Write(_WaveFormat.Header, 8); 71 | retcode = Write(_WaveFormat.Data.FormatTag, 2); 72 | retcode = Write(_WaveFormat.Data.NumChannels, 2); 73 | retcode = Write(_WaveFormat.Data.NumSamplesPerSec, 4); 74 | retcode = Write(_WaveFormat.Data.NumAvgBytesPerSec, 4); 75 | retcode = Write(_WaveFormat.Data.NumBlockAlign, 2); 76 | retcode = Write(_WaveFormat.Data.NumBitsPerSample, 2); 77 | 78 | if (retcode == DDC_SUCCESS) { 79 | _PcmDataOffset = CurrentFilePosition(); 80 | retcode = Write(_PcmData, 8); 81 | } 82 | } 83 | } 84 | 85 | return retcode; 86 | } 87 | 88 | /// 89 | /// Write 16-bit audio 90 | /// 91 | internal virtual int WriteData(short[] data, int numData) { 92 | int extraBytes = numData * 2; 93 | _PcmData.CkSize += extraBytes; 94 | return Write(data, extraBytes); 95 | } 96 | 97 | internal override int Close() { 98 | int rc = DDC_SUCCESS; 99 | 100 | if (Fmode == RF_WRITE) 101 | rc = Backpatch(_PcmDataOffset, _PcmData, 8); 102 | if (!_JustWriteLengthBytes) { 103 | if (rc == DDC_SUCCESS) 104 | rc = base.Close(); 105 | } 106 | return rc; 107 | } 108 | 109 | internal int Close(bool justWriteLengthBytes) { 110 | _JustWriteLengthBytes = justWriteLengthBytes; 111 | int ret = Close(); 112 | _JustWriteLengthBytes = false; 113 | return ret; 114 | } 115 | 116 | // [Hz] 117 | internal virtual int SamplingRate() { 118 | return _WaveFormat.Data.NumSamplesPerSec; 119 | } 120 | 121 | internal virtual short BitsPerSample() { 122 | return _WaveFormat.Data.NumBitsPerSample; 123 | } 124 | 125 | internal virtual short NumChannels() { 126 | return _WaveFormat.Data.NumChannels; 127 | } 128 | 129 | internal virtual int NumSamples() { 130 | return _NumSamples; 131 | } 132 | 133 | /// 134 | /// Open for write using another wave file's parameters... 135 | /// 136 | internal virtual int OpenForWrite(string filename, WaveFile otherWave) { 137 | return OpenForWrite(filename, null, otherWave.SamplingRate(), otherWave.BitsPerSample(), 138 | otherWave.NumChannels()); 139 | } 140 | 141 | internal sealed class WaveFormatChunkData { 142 | private WaveFile _EnclosingInstance; 143 | internal int NumAvgBytesPerSec; 144 | internal short NumBitsPerSample; 145 | internal short NumBlockAlign; 146 | internal short NumChannels; // Number of channels (mono=1, stereo=2) 147 | internal int NumSamplesPerSec; // Sampling rate [Hz] 148 | internal short FormatTag; // Format category (PCM=1) 149 | 150 | internal WaveFormatChunkData(WaveFile enclosingInstance) { 151 | InitBlock(enclosingInstance); 152 | FormatTag = 1; // PCM 153 | Config(44100, 16, 1); 154 | } 155 | 156 | internal WaveFile EnclosingInstance => _EnclosingInstance; 157 | 158 | private void InitBlock(WaveFile enclosingInstance) { 159 | _EnclosingInstance = enclosingInstance; 160 | } 161 | 162 | internal void Config(int newSamplingRate, short newBitsPerSample, short newNumChannels) { 163 | NumSamplesPerSec = newSamplingRate; 164 | NumChannels = newNumChannels; 165 | NumBitsPerSample = newBitsPerSample; 166 | NumAvgBytesPerSec = (NumChannels * NumSamplesPerSec * NumBitsPerSample) / 8; 167 | NumBlockAlign = (short)((NumChannels * NumBitsPerSample) / 8); 168 | } 169 | } 170 | 171 | public class WaveFormatChunk { 172 | internal WaveFormatChunkData Data; 173 | private WaveFile _EnclosingInstance; 174 | internal RiffChunkHeader Header; 175 | 176 | internal WaveFormatChunk(WaveFile enclosingInstance) { 177 | InitBlock(enclosingInstance); 178 | Header = new RiffChunkHeader(enclosingInstance); 179 | Data = new WaveFormatChunkData(enclosingInstance); 180 | Header.CkId = FourCC("fmt "); 181 | Header.CkSize = 16; 182 | } 183 | 184 | internal WaveFile EnclosingInstance => _EnclosingInstance; 185 | 186 | private void InitBlock(WaveFile enclosingInstance) { 187 | _EnclosingInstance = enclosingInstance; 188 | } 189 | 190 | internal virtual int VerifyValidity() { 191 | bool ret = Header.CkId == FourCC("fmt ") && (Data.NumChannels == 1 || Data.NumChannels == 2) && 192 | Data.NumAvgBytesPerSec == (Data.NumChannels * Data.NumSamplesPerSec * Data.NumBitsPerSample) / 8 && 193 | Data.NumBlockAlign == (Data.NumChannels * Data.NumBitsPerSample) / 8; 194 | return ret ? 1 : 0; 195 | } 196 | } 197 | 198 | public class WaveFileSample { 199 | internal short[] Chan; 200 | private WaveFile _EnclosingInstance; 201 | 202 | internal WaveFileSample(WaveFile enclosingInstance) { 203 | InitBlock(enclosingInstance); 204 | Chan = new short[MAX_WAVE_CHANNELS]; 205 | } 206 | 207 | internal WaveFile EnclosingInstance => _EnclosingInstance; 208 | 209 | private void InitBlock(WaveFile enclosingInstance) { 210 | _EnclosingInstance = enclosingInstance; 211 | } 212 | } 213 | } 214 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Decoder.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * Decoder.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using MP3Sharp.Decoding.Decoders; 19 | 20 | namespace MP3Sharp.Decoding { 21 | /// 22 | /// Encapsulates the details of decoding an MPEG audio frame. 23 | /// 24 | public class Decoder { 25 | private static readonly Params DecoderDefaultParams = new Params(); 26 | private Equalizer _Equalizer; 27 | 28 | private SynthesisFilter _LeftChannelFilter; 29 | private SynthesisFilter _RightChannelFilter; 30 | 31 | private bool _IsInitialized; 32 | private LayerIDecoder _L1Decoder; 33 | private LayerIIDecoder _L2Decoder; 34 | private LayerIIIDecoder _L3Decoder; 35 | 36 | private ABuffer _Output; 37 | 38 | private int _OutputChannels; 39 | private int _OutputFrequency; 40 | 41 | /// 42 | /// Creates a new Decoder instance with default parameters. 43 | /// 44 | internal Decoder() : this(null) { 45 | InitBlock(); 46 | } 47 | 48 | /// 49 | /// Creates a new Decoder instance with custom parameters. 50 | /// 51 | internal Decoder(Params params0) { 52 | InitBlock(); 53 | if (params0 == null) { 54 | params0 = DecoderDefaultParams; 55 | } 56 | Equalizer eq = params0.InitialEqualizerSettings; 57 | if (eq != null) { 58 | _Equalizer.FromEqualizer = eq; 59 | } 60 | } 61 | 62 | internal static Params DefaultParams => (Params)DecoderDefaultParams.Clone(); 63 | 64 | internal virtual Equalizer Equalizer { 65 | set { 66 | if (value == null) { 67 | value = Equalizer.PassThruEq; 68 | } 69 | _Equalizer.FromEqualizer = value; 70 | float[] factors = _Equalizer.BandFactors; 71 | if (_LeftChannelFilter != null) 72 | _LeftChannelFilter.Eq = factors; 73 | 74 | if (_RightChannelFilter != null) 75 | _RightChannelFilter.Eq = factors; 76 | } 77 | } 78 | 79 | /// 80 | /// Changes the output buffer. This will take effect the next time 81 | /// decodeFrame() is called. 82 | /// 83 | internal virtual ABuffer OutputBuffer { 84 | set => _Output = value; 85 | } 86 | 87 | /// 88 | /// Retrieves the sample frequency of the PCM samples output 89 | /// by this decoder. This typically corresponds to the sample 90 | /// rate encoded in the MPEG audio stream. 91 | /// 92 | internal virtual int OutputFrequency => _OutputFrequency; 93 | 94 | /// 95 | /// Retrieves the number of channels of PCM samples output by 96 | /// this decoder. This usually corresponds to the number of 97 | /// channels in the MPEG audio stream. 98 | /// 99 | internal virtual int OutputChannels => _OutputChannels; 100 | 101 | /// 102 | /// Retrieves the maximum number of samples that will be written to 103 | /// the output buffer when one frame is decoded. This can be used to 104 | /// help calculate the size of other buffers whose size is based upon 105 | /// the number of samples written to the output buffer. NB: this is 106 | /// an upper bound and fewer samples may actually be written, depending 107 | /// upon the sample rate and number of channels. 108 | /// 109 | internal virtual int OutputBlockSize => ABuffer.OBUFFERSIZE; 110 | 111 | private void InitBlock() { 112 | _Equalizer = new Equalizer(); 113 | } 114 | 115 | /// 116 | /// Decodes one frame from an MPEG audio bitstream. 117 | /// 118 | /// 119 | /// Header describing the frame to decode. 120 | /// 121 | /// 122 | /// Bistream that provides the bits for the body of the frame. 123 | /// 124 | /// 125 | /// A SampleBuffer containing the decoded samples. 126 | /// 127 | internal virtual ABuffer DecodeFrame(Header header, Bitstream stream) { 128 | if (!_IsInitialized) { 129 | Initialize(header); 130 | } 131 | int layer = header.Layer(); 132 | _Output.ClearBuffer(); 133 | IFrameDecoder decoder = RetrieveDecoder(header, stream, layer); 134 | decoder.DecodeFrame(); 135 | _Output.WriteBuffer(1); 136 | return _Output; 137 | } 138 | 139 | protected virtual DecoderException NewDecoderException(int errorcode) => new DecoderException(errorcode, null); 140 | 141 | protected virtual DecoderException NewDecoderException(int errorcode, Exception throwable) => new DecoderException(errorcode, throwable); 142 | 143 | protected virtual IFrameDecoder RetrieveDecoder(Header header, Bitstream stream, int layer) { 144 | IFrameDecoder decoder = null; 145 | 146 | // REVIEW: allow channel output selection type 147 | // (LEFT, RIGHT, BOTH, DOWNMIX) 148 | switch (layer) { 149 | case 3: 150 | if (_L3Decoder == null) { 151 | _L3Decoder = new LayerIIIDecoder(stream, header, _LeftChannelFilter, _RightChannelFilter, _Output, 152 | (int)OutputChannelsEnum.BothChannels); 153 | } 154 | 155 | decoder = _L3Decoder; 156 | break; 157 | 158 | case 2: 159 | if (_L2Decoder == null) { 160 | _L2Decoder = new LayerIIDecoder(); 161 | _L2Decoder.Create(stream, header, _LeftChannelFilter, _RightChannelFilter, _Output, 162 | (int)OutputChannelsEnum.BothChannels); 163 | } 164 | decoder = _L2Decoder; 165 | break; 166 | 167 | case 1: 168 | if (_L1Decoder == null) { 169 | _L1Decoder = new LayerIDecoder(); 170 | _L1Decoder.Create(stream, header, _LeftChannelFilter, _RightChannelFilter, _Output, 171 | (int)OutputChannelsEnum.BothChannels); 172 | } 173 | decoder = _L1Decoder; 174 | break; 175 | } 176 | 177 | if (decoder == null) { 178 | throw NewDecoderException(DecoderErrors.UNSUPPORTED_LAYER, null); 179 | } 180 | 181 | return decoder; 182 | } 183 | 184 | private void Initialize(Header header) { 185 | // REVIEW: allow customizable scale factor 186 | const float scalefactor = 32700.0f; 187 | int channels = header.Mode() == Header.SINGLE_CHANNEL ? 1 : 2; 188 | 189 | // set up output buffer if not set up by client. 190 | if (_Output == null) 191 | _Output = new SampleBuffer(header.Frequency(), channels); 192 | 193 | float[] factors = _Equalizer.BandFactors; 194 | _LeftChannelFilter = new SynthesisFilter(0, scalefactor, factors); 195 | if (channels == 2) 196 | _RightChannelFilter = new SynthesisFilter(1, scalefactor, factors); 197 | 198 | _OutputChannels = channels; 199 | _OutputFrequency = header.Frequency(); 200 | 201 | _IsInitialized = true; 202 | } 203 | 204 | /// 205 | /// The Params class presents the customizable 206 | /// aspects of the decoder. Instances of this class are not thread safe. 207 | /// 208 | public class Params : ICloneable { 209 | private OutputChannels _OutputChannels; 210 | 211 | internal virtual OutputChannels OutputChannels { 212 | get => _OutputChannels; 213 | 214 | set => _OutputChannels = value ?? throw new NullReferenceException("out"); 215 | } 216 | 217 | /// 218 | /// Retrieves the equalizer settings that the decoder's equalizer 219 | /// will be initialized from. 220 | /// The Equalizer instance returned 221 | /// cannot be changed in real time to affect the 222 | /// decoder output as it is used only to initialize the decoders 223 | /// EQ settings. To affect the decoder's output in realtime, 224 | /// use the Equalizer returned from the getEqualizer() method on 225 | /// the decoder. 226 | /// 227 | /// 228 | /// The Equalizer used to initialize the 229 | /// EQ settings of the decoder. 230 | /// 231 | private readonly Equalizer _Equalizer = null; 232 | 233 | internal virtual Equalizer InitialEqualizerSettings => _Equalizer; 234 | 235 | public object Clone() { 236 | try { 237 | return MemberwiseClone(); 238 | } 239 | catch (Exception ex) { 240 | throw new ApplicationException(this + ": " + ex); 241 | } 242 | } 243 | } 244 | } 245 | } -------------------------------------------------------------------------------- /MP3Sharp/MP3Stream.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * MP3Stream.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using System.IO; 19 | using MP3Sharp.Decoding; 20 | 21 | namespace MP3Sharp { 22 | /// 23 | /// Provides a view of the sequence of bytes that are produced during the conversion of an MP3 stream 24 | /// into a 16-bit PCM-encoded ("WAV" format) stream. 25 | /// 26 | public class MP3Stream : Stream { 27 | // Used to interface with JavaZoom code. 28 | private readonly Bitstream _BitStream; 29 | 30 | private readonly Decoder _Decoder = new Decoder(Decoder.DefaultParams); 31 | 32 | // local variables. 33 | private readonly Buffer16BitStereo _Buffer; 34 | private readonly Stream _SourceStream; 35 | private const int BACK_STREAM_BYTE_COUNT_REP = 0; 36 | private short _ChannelCountRep = -1; 37 | private readonly SoundFormat FormatRep; 38 | private int _FrequencyRep = -1; 39 | 40 | public bool IsEOF { get; protected set; } 41 | 42 | /// 43 | /// Creates a new stream instance using the provided filename, and the default chunk size of 4096 bytes. 44 | /// 45 | public MP3Stream(string fileName) 46 | : this(new FileStream(fileName, FileMode.Open, FileAccess.Read)) { } 47 | 48 | /// 49 | /// Creates a new stream instance using the provided filename and chunk size. 50 | /// 51 | public MP3Stream(string fileName, int chunkSize) 52 | : this(new FileStream(fileName, FileMode.Open, FileAccess.Read), chunkSize) { } 53 | 54 | /// 55 | /// Creates a new stream instance using the provided stream as a source, and the default chunk size of 4096 bytes. 56 | /// 57 | public MP3Stream(Stream sourceStream) : this(sourceStream, 4096) { } 58 | 59 | /// 60 | /// Creates a new stream instance using the provided stream as a source. 61 | /// Will also read the first frame of the MP3 into the internal buffer. 62 | /// 63 | public MP3Stream(Stream sourceStream, int chunkSize) { 64 | IsEOF = false; 65 | _SourceStream = sourceStream; 66 | _BitStream = new Bitstream(new PushbackStream(_SourceStream, chunkSize)); 67 | _Buffer = new Buffer16BitStereo(); 68 | _Decoder.OutputBuffer = _Buffer; 69 | // read the first frame. This will fill the initial buffer with data, and get our frequency! 70 | IsEOF |= !ReadFrame(); 71 | switch (_ChannelCountRep) { 72 | case 1: 73 | FormatRep = SoundFormat.Pcm16BitMono; 74 | break; 75 | case 2: 76 | FormatRep = SoundFormat.Pcm16BitStereo; 77 | break; 78 | default: 79 | throw new MP3SharpException($"Unhandled channel count rep: {_ChannelCountRep} (allowed values are 1-mono and 2-stereo)."); 80 | } 81 | if (FormatRep == SoundFormat.Pcm16BitMono) { 82 | _Buffer.DoubleMonoToStereo = true; 83 | } 84 | } 85 | 86 | /// 87 | /// Gets the chunk size. 88 | /// 89 | internal int ChunkSize => BACK_STREAM_BYTE_COUNT_REP; 90 | 91 | /// 92 | /// Gets a value indicating whether the current stream supports reading. 93 | /// 94 | public override bool CanRead => _SourceStream.CanRead; 95 | 96 | /// 97 | /// Gets a value indicating whether the current stream supports seeking. 98 | /// 99 | public override bool CanSeek => _SourceStream.CanSeek; 100 | 101 | /// 102 | /// Gets a value indicating whether the current stream supports writing. 103 | /// 104 | public override bool CanWrite => _SourceStream.CanWrite; 105 | 106 | /// 107 | /// Gets the length in bytes of the stream. 108 | /// 109 | public override long Length => _SourceStream.Length; 110 | 111 | /// 112 | /// Gets or sets the position of the source stream. This is relative to the number of bytes in the MP3 file, rather 113 | /// than the total number of PCM bytes (typically signicantly greater) contained in the Mp3Stream's output. 114 | /// 115 | public override long Position { 116 | get => _SourceStream.Position; 117 | set { 118 | if (value < 0) 119 | value = 0; 120 | if (value > _SourceStream.Length) 121 | value = _SourceStream.Length; 122 | _SourceStream.Position = value; 123 | IsEOF = false; 124 | IsEOF |= !ReadFrame(); 125 | } 126 | } 127 | 128 | /// 129 | /// Gets the frequency of the audio being decoded. Updated every call to Read() or DecodeFrames(), 130 | /// to reflect the most recent header information from the MP3 Stream. 131 | /// 132 | public int Frequency => _FrequencyRep; 133 | 134 | /// 135 | /// Gets the number of channels available in the audio being decoded. Updated every call to Read() or DecodeFrames(), 136 | /// to reflect the most recent header information from the MP3 Stream. 137 | /// 138 | internal short ChannelCount => _ChannelCountRep; 139 | 140 | /// 141 | /// Gets the PCM output format of this stream. 142 | /// 143 | internal SoundFormat Format => FormatRep; 144 | 145 | /// 146 | /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device. 147 | /// 148 | public override void Flush() { 149 | _SourceStream.Flush(); 150 | } 151 | 152 | /// 153 | /// Sets the position of the source stream. 154 | /// 155 | public override long Seek(long offset, SeekOrigin origin) { 156 | return _SourceStream.Seek(offset, origin); 157 | } 158 | 159 | /// 160 | /// This method is not valid for an Mp3Stream. 161 | /// 162 | public override void SetLength(long value) { 163 | throw new InvalidOperationException(); 164 | } 165 | 166 | /// 167 | /// This method is not valid for an Mp3Stream. 168 | /// 169 | public override void Write(byte[] buffer, int offset, int count) { 170 | throw new InvalidOperationException(); 171 | } 172 | 173 | /// 174 | /// Decodes the requested number of frames from the MP3 stream and caches their PCM-encoded bytes. 175 | /// These can subsequently be obtained using the Read method. 176 | /// Returns the number of frames that were successfully decoded. 177 | /// 178 | internal int DecodeFrames(int frameCount) { 179 | int framesDecoded = 0; 180 | bool aFrameWasRead = true; 181 | while (framesDecoded < frameCount && aFrameWasRead) { 182 | aFrameWasRead = ReadFrame(); 183 | if (aFrameWasRead) framesDecoded++; 184 | } 185 | return framesDecoded; 186 | } 187 | 188 | /// 189 | /// Reads the MP3 stream as PCM-encoded bytes. Decodes a portion of the stream if necessary. 190 | /// Returns the number of bytes read. 191 | /// 192 | public override int Read(byte[] buffer, int offset, int count) { 193 | // Copy from queue buffers, reading new ones as necessary, 194 | // until we can't read more or we have read "count" bytes 195 | if (IsEOF) 196 | return 0; 197 | 198 | int bytesRead = 0; 199 | while (true) { 200 | if (_Buffer.BytesLeft <= 0) { 201 | if (!ReadFrame()) // out of frames or end of stream? 202 | { 203 | IsEOF = true; 204 | _BitStream.CloseFrame(); 205 | break; 206 | } 207 | } 208 | 209 | // Copy as much as we can from the current buffer: 210 | bytesRead += _Buffer.Read(buffer, 211 | offset + bytesRead, 212 | count - bytesRead); 213 | 214 | if (bytesRead >= count) 215 | break; 216 | } 217 | return bytesRead; 218 | } 219 | 220 | /// 221 | /// Closes the source stream and releases any associated resources. 222 | /// If you don't call this, you may be leaking file descriptors. 223 | /// 224 | public override void Close() { 225 | _BitStream.Close(); // This should close SourceStream as well. 226 | } 227 | 228 | /// 229 | /// Reads a frame from the MP3 stream. Returns whether the operation was successful. If it wasn't, 230 | /// the source stream is probably at its end. 231 | /// 232 | private bool ReadFrame() { 233 | // Read a frame from the bitstream. 234 | Header header = _BitStream.ReadFrame(); 235 | if (header == null) 236 | return false; 237 | 238 | try { 239 | // Set the channel count and frequency values for the stream. 240 | if (header.Mode() == Header.SINGLE_CHANNEL) 241 | _ChannelCountRep = 1; 242 | else 243 | _ChannelCountRep = 2; 244 | _FrequencyRep = header.Frequency(); 245 | // Decode the frame. 246 | ABuffer decoderOutput = _Decoder.DecodeFrame(header, _BitStream); 247 | if (decoderOutput != _Buffer) { 248 | throw new ApplicationException("Output buffers are different."); 249 | } 250 | } 251 | finally { 252 | // No resource leaks please! 253 | _BitStream.CloseFrame(); 254 | } 255 | return true; 256 | } 257 | } 258 | } -------------------------------------------------------------------------------- /MP3Sharp/Decoding/Bitstream.cs: -------------------------------------------------------------------------------- 1 | // /*************************************************************************** 2 | // * Bitstream.cs 3 | // * Copyright (c) 2015, 2021 The Authors. 4 | // * 5 | // * All rights reserved. This program and the accompanying materials 6 | // * are made available under the terms of the GNU Lesser General Public License 7 | // * (LGPL) version 3 which accompanies this distribution, and is available at 8 | // * https://www.gnu.org/licenses/lgpl-3.0.en.html 9 | // * 10 | // * This library is distributed in the hope that it will be useful, 11 | // * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // * Lesser General Public License for more details. 14 | // * 15 | // ***************************************************************************/ 16 | 17 | using System; 18 | using System.IO; 19 | using MP3Sharp.Support; 20 | 21 | namespace MP3Sharp.Decoding { 22 | /// 23 | /// The Bistream class is responsible for parsing an MPEG audio bitstream. 24 | /// REVIEW: much of the parsing currently occurs in the various decoders. 25 | /// This should be moved into this class and associated inner classes. 26 | /// 27 | public sealed class Bitstream { 28 | /// 29 | /// Maximum size of the frame buffer: 30 | /// 1730 bytes per frame: 144 * 384kbit/s / 32000 Hz + 2 Bytes CRC 31 | /// 32 | private const int BUFFER_INT_SIZE = 433; 33 | 34 | /// 35 | /// Synchronization control constant for the initial 36 | /// synchronization to the start of a frame. 37 | /// 38 | internal const sbyte INITIAL_SYNC = 0; 39 | 40 | /// 41 | /// Synchronization control constant for non-inital frame 42 | /// synchronizations. 43 | /// 44 | internal const sbyte STRICT_SYNC = 1; 45 | 46 | private readonly int[] _Bitmask = { 47 | 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F, 48 | 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF, 49 | 0x0000FFFF, 0x0001FFFF 50 | }; 51 | 52 | private readonly PushbackStream _SourceStream; 53 | 54 | /// 55 | /// Number (0-31, from MSB to LSB) of next bit for get_bits() 56 | /// 57 | private int _BitIndex; 58 | 59 | private Crc16[] _CRC; 60 | 61 | /// 62 | /// The bytes read from the stream. 63 | /// 64 | private sbyte[] _FrameBytes; 65 | 66 | /// 67 | /// The frame buffer that holds the data for the current frame. 68 | /// 69 | private int[] _FrameBuffer; 70 | 71 | /// 72 | /// Number of valid bytes in the frame buffer. 73 | /// 74 | private int _FrameSize; 75 | 76 | private Header _Header; 77 | 78 | private bool _SingleChMode; 79 | 80 | private sbyte[] _SyncBuffer; 81 | 82 | /// 83 | /// The current specified syncword 84 | /// 85 | private int _SyncWord; 86 | 87 | /// 88 | /// Index into framebuffer where the next bits are retrieved. 89 | /// 90 | private int _WordPointer; 91 | 92 | /// 93 | /// Create a IBitstream that reads data from a given InputStream. 94 | /// 95 | internal Bitstream(PushbackStream stream) { 96 | InitBlock(); 97 | _SourceStream = stream ?? throw new NullReferenceException("in stream is null"); 98 | CloseFrame(); 99 | } 100 | 101 | private void InitBlock() { 102 | _CRC = new Crc16[1]; 103 | _SyncBuffer = new sbyte[4]; 104 | _FrameBytes = new sbyte[BUFFER_INT_SIZE * 4]; 105 | _FrameBuffer = new int[BUFFER_INT_SIZE]; 106 | _Header = new Header(); 107 | } 108 | 109 | internal void Close() { 110 | try { 111 | _SourceStream.Close(); 112 | } 113 | catch (IOException ex) { 114 | throw NewBitstreamException(BitstreamErrors.STREA_ERROR, ex); 115 | } 116 | } 117 | 118 | /// 119 | /// Reads and parses the next frame from the input source. 120 | /// 121 | /// 122 | /// The Header describing details of the frame read, 123 | /// or null if the end of the stream has been reached. 124 | /// 125 | internal Header ReadFrame() { 126 | Header result = null; 127 | try { 128 | result = ReadNextFrame(); 129 | } 130 | catch (BitstreamException ex) { 131 | if (ex.ErrorCode != BitstreamErrors.STREAM_EOF) { 132 | // wrap original exception so stack trace is maintained. 133 | throw NewBitstreamException(ex.ErrorCode, ex); 134 | } 135 | } 136 | return result; 137 | } 138 | 139 | private Header ReadNextFrame() { 140 | if (_FrameSize == -1) { 141 | // entire frame is read by the header class. 142 | _Header.read_header(this, _CRC); 143 | } 144 | 145 | return _Header; 146 | } 147 | 148 | /// 149 | /// Unreads the bytes read from the frame. 150 | /// Throws BitstreamException. 151 | /// REVIEW: add new error codes for this. 152 | /// 153 | internal void UnreadFrame() { 154 | if (_WordPointer == -1 && _BitIndex == -1 && _FrameSize > 0) { 155 | try { 156 | _SourceStream.UnRead(_FrameSize); 157 | } 158 | catch { 159 | throw NewBitstreamException(BitstreamErrors.STREA_ERROR); 160 | } 161 | } 162 | } 163 | 164 | internal void CloseFrame() { 165 | _FrameSize = -1; 166 | _WordPointer = -1; 167 | _BitIndex = -1; 168 | } 169 | 170 | /// 171 | /// Determines if the next 4 bytes of the stream represent a frame header. 172 | /// 173 | internal bool IsSyncCurrentPosition(int syncmode) { 174 | int read = ReadBytes(_SyncBuffer, 0, 4); 175 | int headerstring = ((_SyncBuffer[0] << 24) & (int)SupportClass.Identity(0xFF000000)) | 176 | ((_SyncBuffer[1] << 16) & 0x00FF0000) | ((_SyncBuffer[2] << 8) & 0x0000FF00) | 177 | ((_SyncBuffer[3] << 0) & 0x000000FF); 178 | 179 | try { 180 | _SourceStream.UnRead(read); 181 | } 182 | catch (Exception e) { 183 | throw new MP3SharpException("Could not restore file after reading frame header.", e); 184 | } 185 | 186 | bool sync = false; 187 | switch (read) { 188 | case 0: 189 | sync = true; 190 | break; 191 | 192 | case 4: 193 | sync = IsSyncMark(headerstring, syncmode, _SyncWord); 194 | break; 195 | } 196 | 197 | return sync; 198 | } 199 | 200 | // REVIEW: this class should provide inner classes to 201 | // parse the frame contents. Eventually, readBits will 202 | // be removed. 203 | internal int ReadBits(int n) => GetBitsFromBuffer(n); 204 | 205 | // REVIEW: implement CRC check. 206 | internal int ReadCheckedBits(int n) => GetBitsFromBuffer(n); 207 | 208 | internal BitstreamException NewBitstreamException(int errorcode) => new BitstreamException(errorcode, null); 209 | 210 | internal BitstreamException NewBitstreamException(int errorcode, Exception throwable) => new BitstreamException(errorcode, throwable); 211 | 212 | /// 213 | /// Get next 32 bits from bitstream. 214 | /// They are stored in the headerstring. 215 | /// syncmod allows Synchro flag ID 216 | /// The returned value is False at the end of stream. 217 | /// 218 | internal int SyncHeader(sbyte syncmode) { 219 | bool sync = false; 220 | // read additional 2 bytes 221 | int bytesRead = ReadBytes(_SyncBuffer, 0, 3); 222 | if (bytesRead != 3) { 223 | throw NewBitstreamException(BitstreamErrors.STREAM_EOF, null); 224 | } 225 | 226 | int headerstring = ((_SyncBuffer[0] << 16) & 0x00FF0000) | ((_SyncBuffer[1] << 8) & 0x0000FF00) | 227 | ((_SyncBuffer[2] << 0) & 0x000000FF); 228 | 229 | do { 230 | headerstring <<= 8; 231 | if (ReadBytes(_SyncBuffer, 3, 1) != 1) { 232 | throw NewBitstreamException(BitstreamErrors.STREAM_EOF, null); 233 | } 234 | headerstring |= _SyncBuffer[3] & 0x000000FF; 235 | if (CheckAndSkipId3Tag(headerstring)) { 236 | bytesRead = ReadBytes(_SyncBuffer, 0, 3); 237 | if (bytesRead != 3) { 238 | throw NewBitstreamException(BitstreamErrors.STREAM_EOF, null); 239 | } 240 | headerstring = ((_SyncBuffer[0] << 16) & 0x00FF0000) | ((_SyncBuffer[1] << 8) & 0x0000FF00) | 241 | ((_SyncBuffer[2] << 0) & 0x000000FF); 242 | continue; 243 | } 244 | sync = IsSyncMark(headerstring, syncmode, _SyncWord); 245 | } while (!sync); 246 | 247 | return headerstring; 248 | } 249 | /// 250 | /// check and skip the id3v2 tag. 251 | /// mp3 frame sync inside id3 tag may led false decodeing. 252 | /// id3 tag do have a flag for "unsynchronisation", indicate there are no 253 | /// frame sync inside tags, scence decoder don't care about tags, we just 254 | /// skip all tags. 255 | /// 256 | internal bool CheckAndSkipId3Tag(int headerstring) { 257 | bool id3 = (headerstring & 0xFFFFFF00) == 0x49443300; 258 | 259 | if (id3) { 260 | sbyte[] id3_header = new sbyte[6]; 261 | 262 | if (ReadBytes(id3_header, 0, 6) != 6) { 263 | throw NewBitstreamException(BitstreamErrors.STREAM_EOF, null); 264 | } 265 | // id3 header uses 4 bytes to store the size of all tags, 266 | // but only the low 7 bits of each byte is used, to avoid 267 | // mp3 frame sync. 268 | int id3_tag_size = 0; 269 | id3_tag_size |= id3_header[2] & 0x0000007F; id3_tag_size <<= 7; 270 | id3_tag_size |= id3_header[3] & 0x0000007F; id3_tag_size <<= 7; 271 | id3_tag_size |= id3_header[4] & 0x0000007F; id3_tag_size <<= 7; 272 | id3_tag_size |= id3_header[5] & 0x0000007F; 273 | 274 | sbyte[] id3_tag = new sbyte[id3_tag_size]; 275 | 276 | if (ReadBytes(id3_tag, 0, id3_tag_size) != id3_tag_size) { 277 | throw NewBitstreamException(BitstreamErrors.STREAM_EOF, null); 278 | } 279 | } 280 | return id3; 281 | } 282 | 283 | internal bool IsSyncMark(int headerstring, int syncmode, int word) { 284 | bool sync; 285 | if (syncmode == INITIAL_SYNC) { 286 | //sync = ((headerstring & 0xFFF00000) == 0xFFF00000); 287 | sync = (headerstring & 0xFFE00000) == 0xFFE00000; // SZD: MPEG 2.5 288 | } 289 | else { 290 | //sync = ((headerstring & 0xFFF80C00) == word) 291 | sync = (headerstring & 0xFFE00000) == 0xFFE00000 // ROB -- THIS IS PROBABLY WRONG. A WEAKER CHECK. 292 | && (headerstring & 0x000000C0) == 0x000000C0 == _SingleChMode; 293 | } 294 | 295 | // filter out invalid sample rate 296 | if (sync) { 297 | sync = (SupportClass.URShift(headerstring, 10) & 3) != 3; 298 | // if (!sync) Trace.WriteLine("INVALID SAMPLE RATE DETECTED", "Bitstream"); 299 | } 300 | // filter out invalid layer 301 | if (sync) { 302 | sync = (SupportClass.URShift(headerstring, 17) & 3) != 0; 303 | // if (!sync) Trace.WriteLine("INVALID LAYER DETECTED", "Bitstream"); 304 | } 305 | // filter out invalid version 306 | if (sync) { 307 | sync = (SupportClass.URShift(headerstring, 19) & 3) != 1; 308 | if (!sync) Console.WriteLine("INVALID VERSION DETECTED"); 309 | } 310 | return sync; 311 | } 312 | 313 | /// 314 | /// Reads the data for the next frame. The frame is not parsed 315 | /// until parse frame is called. 316 | /// 317 | internal void Read_frame_data(int bytesize) { 318 | ReadFully(_FrameBytes, 0, bytesize); 319 | _FrameSize = bytesize; 320 | _WordPointer = -1; 321 | _BitIndex = -1; 322 | } 323 | 324 | /// 325 | /// Parses the data previously read with read_frame_data(). 326 | /// 327 | internal void ParseFrame() { 328 | // Convert Bytes read to int 329 | int b = 0; 330 | sbyte[] byteread = _FrameBytes; 331 | int bytesize = _FrameSize; 332 | 333 | for (int k = 0; k < bytesize; k = k + 4) { 334 | sbyte b0 = byteread[k]; 335 | sbyte b1 = 0; 336 | sbyte b2 = 0; 337 | sbyte b3 = 0; 338 | if (k + 1 < bytesize) 339 | b1 = byteread[k + 1]; 340 | if (k + 2 < bytesize) 341 | b2 = byteread[k + 2]; 342 | if (k + 3 < bytesize) 343 | b3 = byteread[k + 3]; 344 | _FrameBuffer[b++] = ((b0 << 24) & (int)SupportClass.Identity(0xFF000000)) | ((b1 << 16) & 0x00FF0000) | 345 | ((b2 << 8) & 0x0000FF00) | (b3 & 0x000000FF); 346 | } 347 | 348 | _WordPointer = 0; 349 | _BitIndex = 0; 350 | } 351 | 352 | /// 353 | /// Read bits from buffer into the lower bits of an unsigned int. 354 | /// The LSB contains the latest read bit of the stream. 355 | /// (between 1 and 16, inclusive). 356 | /// 357 | internal int GetBitsFromBuffer(int countBits) { 358 | int returnvalue; 359 | int sum = _BitIndex + countBits; 360 | if (_WordPointer < 0) { 361 | _WordPointer = 0; 362 | } 363 | if (sum <= 32) { 364 | // all bits contained in *wordpointer 365 | returnvalue = SupportClass.URShift(_FrameBuffer[_WordPointer], 32 - sum) & _Bitmask[countBits]; 366 | if ((_BitIndex += countBits) == 32) { 367 | _BitIndex = 0; 368 | _WordPointer++; 369 | } 370 | return returnvalue; 371 | } 372 | int right = _FrameBuffer[_WordPointer] & 0x0000FFFF; 373 | _WordPointer++; 374 | int left = _FrameBuffer[_WordPointer] & (int)SupportClass.Identity(0xFFFF0000); 375 | returnvalue = ((right << 16) & (int)SupportClass.Identity(0xFFFF0000)) | (SupportClass.URShift(left, 16) & 0x0000FFFF); 376 | returnvalue = SupportClass.URShift(returnvalue, 48 - sum); 377 | returnvalue &= _Bitmask[countBits]; 378 | _BitIndex = sum - 32; 379 | return returnvalue; 380 | } 381 | 382 | /// 383 | /// Set the word we want to sync the header to. 384 | /// In Big-Endian byte order 385 | /// 386 | internal void SetSyncWord(int syncword0) { 387 | _SyncWord = syncword0 & unchecked((int)0xFFFFFF3F); 388 | _SingleChMode = (syncword0 & 0x000000C0) == 0x000000C0; 389 | } 390 | 391 | /// 392 | /// Reads the exact number of bytes from the source input stream into a byte array. 393 | /// 394 | private void ReadFully(sbyte[] b, int offs, int len) { 395 | try { 396 | while (len > 0) { 397 | int bytesread = _SourceStream.Read(b, offs, len); 398 | if (bytesread == -1 || bytesread == 0) // t/DD -- .NET returns 0 at end-of-stream! 399 | { 400 | // t/DD: this really SHOULD throw an exception here... 401 | // Trace.WriteLine("readFully -- returning success at EOF? (" + bytesread + ")", "Bitstream"); 402 | while (len-- > 0) { 403 | b[offs++] = 0; 404 | } 405 | break; 406 | //throw newBitstreamException(UNEXPECTED_EOF, new EOFException()); 407 | } 408 | 409 | offs += bytesread; 410 | len -= bytesread; 411 | } 412 | } 413 | catch (IOException ex) { 414 | throw NewBitstreamException(BitstreamErrors.STREA_ERROR, ex); 415 | } 416 | } 417 | 418 | /// 419 | /// Simlar to readFully, but doesn't throw exception when EOF is reached. 420 | /// 421 | private int ReadBytes(sbyte[] b, int offs, int len) { 422 | int totalBytesRead = 0; 423 | try { 424 | while (len > 0) { 425 | int bytesread = _SourceStream.Read(b, offs, len); 426 | // for (int i = 0; i < len; i++) b[i] = (sbyte)Temp[i]; 427 | if (bytesread == -1 || bytesread == 0) { 428 | break; 429 | } 430 | totalBytesRead += bytesread; 431 | offs += bytesread; 432 | len -= bytesread; 433 | } 434 | } 435 | catch (IOException ex) { 436 | throw NewBitstreamException(BitstreamErrors.STREA_ERROR, ex); 437 | } 438 | return totalBytesRead; 439 | } 440 | } 441 | } 442 | --------------------------------------------------------------------------------