Browse Source

Now supports all of SDL's audio formats.

improved_timing
Ian Burgmyer 7 years ago
parent
commit
0ee62dfa6b
  1. 110
      DotSDL/Audio/FormatConverter.cs
  2. 12
      DotSDL/Audio/Playback.cs
  3. 6
      Samples/Sample.Audio/Window.cs

110
DotSDL/Audio/FormatConverter.cs

@ -2,6 +2,9 @@
using SdlAudio = DotSDL.Sdl.Audio;
namespace DotSDL.Audio {
/// <summary>
/// Converts between the audio formats supported by SDL.
/// </summary>
internal static class FormatConverter {
/// <summary>
/// Converts a DotSDL <see cref="AudioBuffer"/> to an SDL-compatible byte array.
@ -11,8 +14,29 @@ namespace DotSDL.Audio {
/// <param name="format">The SDL <see cref="AudioFormat"/> to convert to.</param>
internal static void ConvertFormat(AudioBuffer buffer, ref byte[] stream, SdlAudio.AudioFormat format) {
switch(format) {
case SdlAudio.AudioFormat.SignedByte:
case SdlAudio.AudioFormat.UnsignedByte:
ToInt8(buffer, ref stream);
break;
case SdlAudio.AudioFormat.SignedShortLittleEndian:
ToSint16Lsb(buffer, ref stream);
case SdlAudio.AudioFormat.UnsignedShortLittleEndian:
ToInt16(buffer, ref stream, true);
break;
case SdlAudio.AudioFormat.SignedShortBigEndian:
case SdlAudio.AudioFormat.UnsignedShortBigEndian:
ToInt16(buffer, ref stream, false);
break;
case SdlAudio.AudioFormat.SignedIntLittleEndian:
ToInt32(buffer, ref stream, true);
break;
case SdlAudio.AudioFormat.SignedIntBigEndian:
ToInt32(buffer, ref stream, false);
break;
case SdlAudio.AudioFormat.FloatLittleEndian:
ToFloat32(buffer, ref stream, true);
break;
case SdlAudio.AudioFormat.FloatBigEndian:
ToFloat32(buffer, ref stream, false);
break;
default:
throw new NotImplementedException();
@ -20,26 +44,94 @@ namespace DotSDL.Audio {
}
/// <summary>
/// Converts an audio buffer to a byte array with little-endian signed shorts.
/// Converts an audio buffer to a byte array with 8-bit samples.
/// </summary>
/// <param name="buffer">A DotSDL <see cref="AudioBuffer"/>.</param>
/// <param name="stream">The byte array to write the converted data to.</param>
private static void ToInt8(AudioBuffer buffer, ref byte[] stream) {
for(var i = 0; i < buffer.Samples.Length; i++) {
var sample = buffer.Samples[i];
var newSample = (sbyte)(sample * sbyte.MaxValue);
stream[i] = (byte)newSample;
}
}
/// <summary>
/// Converts an audio buffer to a byte array with 16-bit samples.
/// </summary>
/// <param name="buffer">A DotSDL <see cref="AudioBuffer"/>.</param>
/// <param name="stream">The byte array to write the converted data to.</param>
private static void ToSint16Lsb(AudioBuffer buffer, ref byte[] stream) {
if(BitConverter.IsLittleEndian) {
// Little-endian architecture.
/// <param name="littleEndian">Indicates whether the target byte stream should be little endian.</param>
private static void ToInt16(AudioBuffer buffer, ref byte[] stream, bool littleEndian) {
if((BitConverter.IsLittleEndian && littleEndian) || (!BitConverter.IsLittleEndian && !littleEndian)) {
// Sample endian == system endian.
for(var i = 0; i < buffer.Samples.Length; i++) {
var sample = buffer.Samples[i];
var newSample = (short)(sample * short.MaxValue);
stream[i * 2 + 1] = (byte)(newSample >> 8);
stream[i * 2] = (byte)newSample;
stream[i * 2 + 1] = (byte)(newSample >> 8);
}
} else {
// Big-endian architecture.
// Sample endian != system endian. Flip bytes.
for(var i = 0; i < buffer.Samples.Length; i++) {
var sample = buffer.Samples[i];
var newSample = (short)(sample * short.MaxValue);
stream[i * 2] = (byte)newSample;
stream[i * 2 + 1] = (byte)(newSample >> 8);
stream[i * 2] = (byte)(newSample >> 8);
stream[i * 2 + 1] = (byte)newSample;
}
}
}
/// <summary>
/// Converts an audio buffer to a byte array with little-endian 32-bit samples.
/// </summary>
/// <param name="buffer">A DotSDL <see cref="AudioBuffer"/>.</param>
/// <param name="stream">The byte array to write the converted data to.</param>
/// <param name="littleEndian">Indicates whether the target byte stream should be little endian.</param>
private static void ToInt32(AudioBuffer buffer, ref byte[] stream, bool littleEndian) {
if((BitConverter.IsLittleEndian && littleEndian) || (!BitConverter.IsLittleEndian && !littleEndian)) {
// Sample endian == system endian.
for(var i = 0; i < buffer.Samples.Length; i++) {
var sample = buffer.Samples[i];
var newSample = (int)(sample * int.MaxValue);
stream[i * 4] = (byte)newSample;
stream[i * 4 + 1] = (byte)(newSample >> 8);
stream[i * 4 + 2] = (byte)(newSample >> 16);
stream[i * 4 + 3] = (byte)(newSample >> 24);
}
} else {
// Sample endian != system endian. Flip bytes.
for(var i = 0; i < buffer.Samples.Length; i++) {
var sample = buffer.Samples[i];
var newSample = (int)(sample * int.MaxValue);
stream[i * 4] = (byte)(newSample >> 24);
stream[i * 4 + 1] = (byte)(newSample >> 16);
stream[i * 4 + 2] = (byte)(newSample >> 8);
stream[i * 4 + 3] = (byte)newSample;
}
}
}
private static void ToFloat32(AudioBuffer buffer, ref byte[] stream, bool littleEndian) {
if((BitConverter.IsLittleEndian && littleEndian) || (!BitConverter.IsLittleEndian && !littleEndian)) {
// Sample endian == system endian.
for(var i = 0; i < buffer.Samples.Length; i++) {
var sample = (float)buffer.Samples[i];
var newSample = BitConverter.GetBytes(sample);
stream[i * 4] = newSample[0];
stream[i * 4 + 1] = newSample[1];
stream[i * 4 + 2] = newSample[2];
stream[i * 4 + 3] = newSample[3];
}
} else {
// Sample endian != system endian. Flip bytes.
for(var i = 0; i < buffer.Samples.Length; i++) {
var sample = (float)buffer.Samples[i];
var newSample = BitConverter.GetBytes(sample);
stream[i * 4] = newSample[3];
stream[i * 4 + 1] = newSample[2];
stream[i * 4 + 2] = newSample[1];
stream[i * 4 + 3] = newSample[0];
}
}
}

12
DotSDL/Audio/Playback.cs

@ -43,6 +43,16 @@ namespace DotSDL.Audio {
/// </summary>
public ushort BufferSizeSamples { get; }
/// <summary>
/// <c>true</c> if the audio format is floating-point, otherwise <c>false</c>.
/// </summary>
public bool FloatingPoint { get; }
/// <summary>
/// <c>true</c> if the audio format is little-endian, otherwise <c>false</c>.
/// </summary>
public bool LittleEndian { get; }
/// <summary>
/// Fired when the audio device is requesting more data.
/// </summary>
@ -88,6 +98,8 @@ namespace DotSDL.Audio {
BufferSizeSamples = actual.Samples;
BufferSizeBytes = actual.Size;
BitSize = SdlAudio.BitSize((ushort)actual.Format);
FloatingPoint = SdlAudio.IsFloat((ushort)actual.Format);
LittleEndian = !SdlAudio.IsBigEndian((ushort)actual.Format);
_sdlAudioSpec = actual;
}

6
Samples/Sample.Audio/Window.cs

@ -32,10 +32,12 @@ namespace Sample.Audio {
KeyPressed += Window_KeyPressed;
KeyReleased += Window_KeyReleased;
_audio = new Playback(44100, AudioFormat.Integer16, 1);
_audio = new Playback(48000, AudioFormat.Integer16, 1);
_audioFreq = _audio.Frequency;
Console.WriteLine($"Audio opened: {_audioFreq}hz, {_audio.BitSize}-bit, {_audio.Channels} channels, {_audio.BufferSizeSamples} sample buffer, {_audio.BufferSizeBytes} byte buffer");
var floatingPointText = _audio.FloatingPoint ? "floating-point, " : "";
var endianText = _audio.LittleEndian ? "little-endian" : "big-endian";
Console.WriteLine($"Audio opened: {_audioFreq}hz, {_audio.BitSize}-bit ({floatingPointText}{endianText}), {_audio.Channels} channels, {_audio.BufferSizeSamples} sample buffer, {_audio.BufferSizeBytes} byte buffer.");
_audio.BufferEmpty += Audio_BufferEmpty;
_maxFreq = _audioFreq / 2;

Loading…
Cancel
Save