├── 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 | /// -
29 | /// as an error-code describing the nature of the error
30 | ///
31 | ///
32 | /// -
33 | /// as the Throwable instance, if any, that was thrown
34 | /// indicating that an exceptional condition has occurred.
35 | ///
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 |
--------------------------------------------------------------------------------