Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions MP3Sharp/Buffer16BitMono.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// /***************************************************************************
// * Buffer16BitMono.cs
// * Copyright (c) 2024 the authors.
// *
// * All rights reserved. This program and the accompanying materials
// * are made available under the terms of the GNU Lesser General Public License
// * (LGPL) version 3 which accompanies this distribution, and is available at
// * https://www.gnu.org/licenses/lgpl-3.0.en.html
// *
// * This library is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// * Lesser General Public License for more details.
// *
// ***************************************************************************/

using System;
using MP3Sharp.Decoding;

namespace MP3Sharp
{
/// <summary>
/// Internal class used to queue samples that are being obtained from an Mp3 stream.
/// </summary>
internal class Buffer16BitMono : IStreamBuffer
{
// Write offset used in append_bytes
private readonly byte[] m_Buffer = new byte[ABufferUtil.OBUFFERSIZE]; // all channels interleaved

private int m_Bufferp;

// end marker, one past end of array. Same as bufferp[0], but
// without the array bounds check.
private int m_End;

// Read offset used to read from the stream, in bytes.
private int m_Offset;

public Buffer16BitMono()
{
// Initialize the buffer pointers
ClearBuffer();
}

/// <summary>
/// Gets the number of bytes remaining from the current position on the buffer.
/// </summary>
public int BytesLeft => m_End - m_Offset;

/// <summary>
/// Reads a sequence of bytes from the buffer and advances the position of the
/// buffer by the number of bytes read.
/// </summary>
/// <returns>
/// The total number of bytes read in to the buffer. This can be less than the
/// number of bytes requested if that many bytes are not currently available, or
/// zero if th eend of the buffer has been reached.
/// </returns>
public int Read(byte[] bufferOut, int offset, int count)
{
if (bufferOut == null)
{
throw new ArgumentNullException("bufferOut");
}
if ((count + offset) > bufferOut.Length)
{
throw new ArgumentException("The sum of offset and count is larger than the buffer length");
}
int remaining = BytesLeft;
int copySize;
if (count > remaining)
{
copySize = remaining;
}
else
{
// Copy an even number of sample frames
int remainder = count % 2;
copySize = count - remainder;
}

Array.Copy(m_Buffer, m_Offset, bufferOut, offset, copySize);

m_Offset += copySize;
return copySize;
}

/// <summary>
/// Writes a single sample value to the buffer.
/// </summary>
/// <param name="channel">The channel.</param>
/// <param name="sampleValue">The sample value.</param>
public void Append(int channel, short sampleValue)
{
m_Buffer[m_Bufferp] = (byte)(sampleValue & 0xff);
m_Buffer[m_Bufferp + 1] = (byte)(sampleValue >> 8);

m_Bufferp += 2;
}

/// <summary>
/// Writes 32 samples to the buffer.
/// </summary>
/// <param name="channel">The channel.</param>
/// <param name="samples">An array of sample values.</param>
/// <remarks>
/// The <paramref name="samples"/> parameter must have a length equal to
/// or greater than 32.
/// </remarks>
public void AppendSamples(int channel, float[] samples)
{
if (samples == null)
{
// samples is required.
throw new ArgumentNullException(nameof(samples));
}
if (samples.Length < 32)
{
throw new ArgumentException("samples must have 32 values");
}
// Always, 32 samples are appended
int pos = m_Bufferp;

for (int i = 0; i < 32; i++)
{
float fs = samples[i];
if (fs > 32767.0f) // can this happen?
fs = 32767.0f;
else if (fs < -32767.0f)
fs = -32767.0f;

int sample = (int)fs;
m_Buffer[pos] = (byte)(sample & 0xff);
m_Buffer[pos + 1] = (byte)(sample >> 8);

pos += 2;
}

m_Bufferp = pos;
}

public void ClearBuffer()
{
m_Offset = 0;
m_End = 0;
m_Bufferp = 0;
}

public void SetStopFlag()
{
}

public void WriteBuffer(int val)
{
m_Offset = 0;
m_End = m_Bufferp;
}

public void Close()
{
}
}
}
18 changes: 9 additions & 9 deletions MP3Sharp/Buffer16BitStereo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ namespace MP3Sharp
/// Internal class used to queue samples that are being obtained from an Mp3 stream.
/// This class handles stereo 16-bit data! Switch it out if you want mono or something.
/// </summary>
internal class Buffer16BitStereo : ABuffer
internal class Buffer16BitStereo : IStreamBuffer
{
// This is stereo!
private static readonly int CHANNELS = 2;
// Write offset used in append_bytes
private readonly byte[] m_Buffer = new byte[OBUFFERSIZE * 2]; // all channels interleaved
private readonly int[] m_Bufferp = new int[MAXCHANNELS]; // offset in each channel not same!
private readonly byte[] m_Buffer = new byte[ABufferUtil.OBUFFERSIZE * 2]; // all channels interleaved
private readonly int[] m_Bufferp = new int[ABufferUtil.MAXCHANNELS]; // offset in each channel not same!
// end marker, one past end of array. Same as bufferp[0], but
// without the array bounds check.
private int m_End;
Expand Down Expand Up @@ -90,7 +90,7 @@ public int Read(byte[] bufferOut, int offset, int count)
/// </summary>
/// <param name="channel">The channel.</param>
/// <param name="sampleValue">The sample value.</param>
public override void Append(int channel, short sampleValue)
public void Append(int channel, short sampleValue)
{
m_Buffer[m_Bufferp[channel]] = (byte)(sampleValue & 0xff);
m_Buffer[m_Bufferp[channel] + 1] = (byte)(sampleValue >> 8);
Expand All @@ -107,7 +107,7 @@ public override void Append(int channel, short sampleValue)
/// The <paramref name="samples"/> parameter must have a length equal to
/// or greater than 32.
/// </remarks>
public override void AppendSamples(int channel, float[] samples)
public void AppendSamples(int channel, float[] samples)
{
if (samples == null)
{
Expand Down Expand Up @@ -142,7 +142,7 @@ public override void AppendSamples(int channel, float[] samples)
/// <summary>
/// This implementation does not clear the buffer.
/// </summary>
public override sealed void ClearBuffer()
public void ClearBuffer()
{
m_Offset = 0;
m_End = 0;
Expand All @@ -151,11 +151,11 @@ public override sealed void ClearBuffer()
m_Bufferp[i] = i * 2; // two bytes per channel
}

public override void SetStopFlag()
public void SetStopFlag()
{
}

public override void WriteBuffer(int val)
public void WriteBuffer(int val)
{
m_Offset = 0;

Expand All @@ -166,7 +166,7 @@ public override void WriteBuffer(int val)
m_End = m_Bufferp[0];
}

public override void Close()
public void Close()
{
}
}
Expand Down
60 changes: 34 additions & 26 deletions MP3Sharp/Decoding/ABuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,52 +16,60 @@
namespace MP3Sharp.Decoding
{
/// <summary>
/// Base Class for audio output.
/// A buffer that a <see cref="Decoder"/> can output to.
/// </summary>
internal abstract class ABuffer
internal interface ABuffer
{
public const int OBUFFERSIZE = 2*1152; // max. 2 * 1152 samples per frame
public const int MAXCHANNELS = 2; // max. number of channels

/// <summary>
/// Takes a 16 Bit PCM sample.
/// </summary>
public abstract void Append(int channel, short valueRenamed);
void Append(int channel, short valueRenamed);

/// <summary>
/// Accepts 32 new PCM samples.
/// </summary>
public virtual void AppendSamples(int channel, float[] f)
{
for (int i = 0; i < 32; i++)
{
Append(channel, Clip((f[i])));
}
}

/// <summary>
/// Clip Sample to 16 Bits
/// </summary>
private static short Clip(float sample)
{
return ((sample > 32767.0f) ? (short) 32767 : ((sample < -32768.0f) ? (short) -32768 : (short) sample));
}

void AppendSamples(int channel, float[] f);

/// <summary>
/// Write the samples to the file or directly to the audio hardware.
/// </summary>
public abstract void WriteBuffer(int val);
void WriteBuffer(int val);

public abstract void Close();
void Close();

/// <summary>
/// Clears all data in the buffer (for seeking).
/// </summary>
public abstract void ClearBuffer();
void ClearBuffer();

/// <summary>
/// Notify the buffer that the user has stopped the stream.
/// </summary>
public abstract void SetStopFlag();
void SetStopFlag();
}

internal static class ABufferUtil
{
public const int OBUFFERSIZE = 2*1152; // max. 2 * 1152 samples per frame
public const int MAXCHANNELS = 2; // max. number of channels

/// <summary>
/// Accepts 32 new PCM samples.
/// </summary>
internal static void DefaultAppendSamples(this ABuffer buffer, int channel, float[] f)
{
for (int i = 0; i < 32; i++)
{
buffer.Append(channel, Clip((f[i])));
}
}

/// <summary>
/// Clip Sample to 16 Bits
/// </summary>
private static short Clip(float sample)
{
return ((sample > 32767.0f) ? (short) 32767 : ((sample < -32768.0f) ? (short) -32768 : (short) sample));
}
}
}
2 changes: 1 addition & 1 deletion MP3Sharp/Decoding/Decoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public virtual ABuffer OutputBuffer
/// an upper bound and fewer samples may actually be written, depending
/// upon the sample rate and number of channels.
/// </summary>
public virtual int OutputBlockSize => ABuffer.OBUFFERSIZE;
public virtual int OutputBlockSize => ABufferUtil.OBUFFERSIZE;

private void InitBlock()
{
Expand Down
16 changes: 8 additions & 8 deletions MP3Sharp/Decoding/SampleBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ internal class SampleBuffer : ABuffer
/// </summary>
public SampleBuffer(int sample_frequency, int number_of_channels)
{
buffer = new short[OBUFFERSIZE];
bufferp = new int[MAXCHANNELS];
buffer = new short[ABufferUtil.OBUFFERSIZE];
bufferp = new int[ABufferUtil.MAXCHANNELS];
channels = number_of_channels;
frequency = sample_frequency;

Expand All @@ -51,13 +51,13 @@ public SampleBuffer(int sample_frequency, int number_of_channels)
/// <summary>
/// Takes a 16 Bit PCM sample.
/// </summary>
public override void Append(int channel, short valueRenamed)
public void Append(int channel, short valueRenamed)
{
buffer[bufferp[channel]] = valueRenamed;
bufferp[channel] += channels;
}

public override void AppendSamples(int channel, float[] f)
public void AppendSamples(int channel, float[] f)
{
int pos = bufferp[channel];

Expand All @@ -80,20 +80,20 @@ public override void AppendSamples(int channel, float[] f)
/// <summary>
/// Write the samples to the file (Random Acces).
/// </summary>
public override void WriteBuffer(int val)
public void WriteBuffer(int val)
{
//for (int i = 0; i < channels; ++i)
// bufferp[i] = (short)i;
}

public override void Close()
public void Close()
{
}

/// <summary>
/// *
/// </summary>
public override void ClearBuffer()
public void ClearBuffer()
{
for (int i = 0; i < channels; ++i)
bufferp[i] = (short) i;
Expand All @@ -102,7 +102,7 @@ public override void ClearBuffer()
/// <summary>
/// *
/// </summary>
public override void SetStopFlag()
public void SetStopFlag()
{

}
Expand Down
Loading