mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Decode ogg files as shorts instead of floats (#4715)
This commit is contained in:
committed by
GitHub
parent
438fed2f0e
commit
3f83733a03
@@ -97,11 +97,11 @@ internal partial class AudioManager
|
||||
// check the git history, I originally used libvorbisfile which worked and loaded 16 bit LPCM.
|
||||
if (vorbis.Channels == 1)
|
||||
{
|
||||
format = ALFormat.MonoFloat32Ext;
|
||||
format = ALFormat.Mono16;
|
||||
}
|
||||
else if (vorbis.Channels == 2)
|
||||
{
|
||||
format = ALFormat.StereoFloat32Ext;
|
||||
format = ALFormat.Stereo16;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -110,9 +110,9 @@ internal partial class AudioManager
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (float* ptr = vorbis.Data.Span)
|
||||
fixed (short* ptr = vorbis.Data.Span)
|
||||
{
|
||||
AL.BufferData(buffer, format, (IntPtr) ptr, vorbis.Data.Length * sizeof(float),
|
||||
AL.BufferData(buffer, format, (IntPtr) ptr, vorbis.Data.Length * sizeof(short),
|
||||
(int) vorbis.SampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using NVorbis;
|
||||
|
||||
namespace Robust.Shared.Audio.AudioLoading;
|
||||
@@ -16,7 +17,8 @@ internal static class AudioLoaderOgg
|
||||
/// <param name="stream">Audio file stream to load.</param>
|
||||
public static AudioMetadata LoadAudioMetadata(Stream stream)
|
||||
{
|
||||
using var reader = new VorbisReader(stream);
|
||||
using var reader = new VorbisReader(stream, false);
|
||||
reader.Initialize();
|
||||
return new AudioMetadata(reader.TotalTime, reader.Channels, reader.Tags.Title, reader.Tags.Artist);
|
||||
}
|
||||
|
||||
@@ -26,39 +28,88 @@ internal static class AudioLoaderOgg
|
||||
/// <param name="stream">Audio file stream to load.</param>
|
||||
public static OggVorbisData LoadAudioData(Stream stream)
|
||||
{
|
||||
using var vorbis = new NVorbis.VorbisReader(stream, false);
|
||||
using var vorbis = new VorbisReader(stream, false);
|
||||
vorbis.Initialize();
|
||||
|
||||
var sampleRate = vorbis.SampleRate;
|
||||
var channels = vorbis.Channels;
|
||||
var totalSamples = vorbis.TotalSamples;
|
||||
|
||||
var readSamples = 0;
|
||||
var buffer = new float[totalSamples * channels];
|
||||
var totalValues = totalSamples * channels;
|
||||
var readValues = 0;
|
||||
var buffer = new short[totalSamples * channels];
|
||||
Span<float> readBuffer = stackalloc float[32768];
|
||||
|
||||
while (readSamples < totalSamples)
|
||||
while (readValues < totalValues)
|
||||
{
|
||||
var read = vorbis.ReadSamples(buffer, readSamples * channels, buffer.Length - readSamples);
|
||||
var read = ReadSamples(buffer.AsSpan(readValues), readBuffer, channels, vorbis);
|
||||
if (read == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
readSamples += read;
|
||||
readValues += read;
|
||||
}
|
||||
|
||||
return new OggVorbisData(totalSamples, sampleRate, channels, buffer, vorbis.Tags.Title, vorbis.Tags.Artist);
|
||||
}
|
||||
|
||||
private static int ReadSamples(Span<short> dest, Span<float> readBuffer, int channels, VorbisReader reader)
|
||||
{
|
||||
var read = reader.ReadSamples(readBuffer);
|
||||
read *= channels;
|
||||
|
||||
ConvertToShort(readBuffer[..read], dest[..read]);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
private static void ConvertToShort(ReadOnlySpan<float> src, Span<short> dst)
|
||||
{
|
||||
if (src.Length != dst.Length)
|
||||
throw new InvalidOperationException("Invalid lengths!");
|
||||
|
||||
var simdSamples = (src.Length / Vector<short>.Count) * Vector<short>.Count;
|
||||
|
||||
// Note: I think according to spec we'd actually need to multiply negative values with 2^15 instead of 2^15-1.
|
||||
// because it's -32768 -> 32767
|
||||
// Can't be arsed though
|
||||
var factor = new Vector<float>(short.MaxValue);
|
||||
|
||||
ref readonly var srcBase = ref src[0];
|
||||
ref var dstBase = ref dst[0];
|
||||
|
||||
for (var i = 0; i < simdSamples; i += Vector<short>.Count)
|
||||
{
|
||||
var lower = Vector.LoadUnsafe(in srcBase, (nuint) i);
|
||||
var upper = Vector.LoadUnsafe(in srcBase, (nuint) (i + Vector<float>.Count));
|
||||
|
||||
lower *= factor;
|
||||
upper *= factor;
|
||||
|
||||
var lowerInt = Vector.ConvertToInt32(lower);
|
||||
var upperInt = Vector.ConvertToInt32(upper);
|
||||
|
||||
var merged = Vector.Narrow(lowerInt, upperInt);
|
||||
|
||||
merged.StoreUnsafe(ref dstBase, (nuint) i);
|
||||
}
|
||||
|
||||
for (var i = simdSamples; i < src.Length; i++)
|
||||
{
|
||||
dst[i] = (short)(src[i] * short.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly struct OggVorbisData
|
||||
{
|
||||
public readonly long TotalSamples;
|
||||
public readonly long SampleRate;
|
||||
public readonly long Channels;
|
||||
public readonly ReadOnlyMemory<float> Data;
|
||||
public readonly ReadOnlyMemory<short> Data;
|
||||
public readonly string Title;
|
||||
public readonly string Artist;
|
||||
|
||||
public OggVorbisData(long totalSamples, long sampleRate, long channels, ReadOnlyMemory<float> data, string title, string artist)
|
||||
public OggVorbisData(long totalSamples, long sampleRate, long channels, ReadOnlyMemory<short> data,
|
||||
string title, string artist)
|
||||
{
|
||||
TotalSamples = totalSamples;
|
||||
SampleRate = sampleRate;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<PackageReference Include="Microsoft.ILVerification" Version="6.0.0" PrivateAssets="compile" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageReference Include="Nett" Version="0.15.0" PrivateAssets="compile" />
|
||||
<PackageReference Include="NVorbis" Version="0.10.1" PrivateAssets="compile" />
|
||||
<PackageReference Include="VorbisPizza" Version="1.3.0" PrivateAssets="compile" />
|
||||
<PackageReference Include="Pidgin" Version="2.5.0" />
|
||||
<PackageReference Include="prometheus-net" Version="4.1.1" />
|
||||
<PackageReference Include="Robust.Shared.AuthLib" Version="0.1.2" />
|
||||
|
||||
Reference in New Issue
Block a user