Last active
August 29, 2015 14:02
-
-
Save ArcticEcho/185ee36167d89bcdc55b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Read32BitSamples is called first. | |
private float[] Read32BitSamples(FileStream stream, int sampleStartIndex, int sampleEndIndex) | |
{ | |
var bytesLength = 0; | |
var allocation = ReadBytes(stream, sampleStartIndex, sampleEndIndex, out bytesLength); | |
var bytes = (byte*)allocation.Allocation; | |
var samples = new float[bytesLength / 4]; | |
if (audioFormat == WavFormat.PCM) | |
{ | |
for (var i = 0; i < bytesLength; i += 4) | |
{ | |
samples[i / 4] = (bytes[i] | bytes[i + 1] << 8 | bytes[i + 2] << 16 | bytes[i + 3] << 24) / 2147483648f; | |
} | |
} | |
else | |
{ | |
for (var i = 0; i < bytesLength; i += 4) | |
{ | |
var temp = bytes[i] | bytes[i + 1] << 8 | bytes[i + 2] << 16 | bytes[i + 3] << 24; | |
samples[i / 4] = *(float*)&temp; | |
} | |
} | |
allocation.Dispose(); | |
return samples; | |
} | |
private StackAllocation ReadBytes(FileStream stream, int startIndex, int endIndex, out int outputBytesCount) | |
{ | |
var ch = ChannelPosition.GetChannelNumber(); | |
var byteDepth = bitDepth / 8; | |
var a = startIndex + ch; | |
var b = (endIndex * channels * byteDepth) + ch; | |
outputBytesCount = b - a; | |
var c = byteDepth * channels; | |
var temp = new byte[outputBytesCount * channels + byteDepth]; | |
var selectedBytes = (byte*)allocator.AllocateBytes(outputBytesCount).Allocation; | |
stream.Position = headerSize; | |
stream.Read(temp, 0, outputBytesCount * channels); | |
if (audioFormat == WavFormat.PCM) | |
{ | |
for (; a < b; a += c) | |
{ | |
for (var ii = byteDepth + a; ii > a; ii--) | |
{ | |
selectedBytes[ii] = temp[ii]; | |
} | |
} | |
} | |
else | |
{ | |
for (; a < b; a += c) | |
{ | |
for (var ii = a; ii < byteDepth + a; ii++) | |
{ | |
selectedBytes[ii] = temp[ii]; | |
} | |
} | |
} | |
return allocator.Allocations[0]; | |
} | |
public unsafe class StackAllocation : IDisposable | |
{ | |
private bool dispose; | |
public IntPtr Allocation { get; private set; } | |
public int Size { get; private set; } | |
public Thread Allocator { get; private set; } | |
public bool IsDisposing | |
{ | |
get | |
{ | |
return dispose; | |
} | |
} | |
public StackAllocation(IntPtr allocation, int allocationSize, Thread allocator) | |
{ | |
Allocator = allocator; | |
Allocation = allocation; | |
Size = allocationSize; | |
} | |
public void Dispose() | |
{ | |
dispose = true; // Buffer overrun caused | |
} | |
} | |
public StackAllocation AllocateBytes(int count) | |
{ | |
if ((ulong)(count + totalAllocated) > new Microsoft.VisualBasic.Devices.ComputerInfo().AvailablePhysicalMemory) { throw new OutOfMemoryException(); } | |
var ptr = IntPtr.Zero; | |
Thread t = null; | |
StackAllocation allocation = null; | |
t = new Thread(() => | |
{ | |
try | |
{ | |
var p = stackalloc byte[count]; | |
ptr = (IntPtr)p; | |
t.Priority = ThreadPriority.Lowest; | |
while (allocation == null) { Thread.Sleep(0); } // Wait for allocation to be instantiated. | |
while (!allocation.IsDisposing) { Thread.Sleep(0); } // Wait for Dispose to be called from either variable "allocation" or from the allocator (this). | |
} | |
finally | |
{ | |
totalAllocated -= count; | |
if (allocations.Contains(allocation)) allocations.Remove(allocation); | |
allocation = null; | |
} | |
}, count) { Priority = ThreadPriority.AboveNormal }; | |
t.Start(); | |
while (ptr == IntPtr.Zero) { Thread.Sleep(0); } // Wait for memory to be allocated. | |
allocation = new StackAllocation(ptr, count, t); | |
allocations.Add(allocation); | |
totalAllocated += count; | |
return allocation; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment