Allow multiple VocFormat streams.

VocFormat.GetPCMInputStream now returns independent streams, allowing multiple instances of the same source to be streamed.
This commit is contained in:
RoosterDragon
2017-07-08 10:28:28 +01:00
committed by Paul Chote
parent 7ed769421e
commit 7160c8a1a9

View File

@@ -13,6 +13,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using OpenRA.Primitives;
namespace OpenRA.Mods.Common.AudioLoaders namespace OpenRA.Mods.Common.AudioLoaders
{ {
@@ -41,17 +42,17 @@ namespace OpenRA.Mods.Common.AudioLoaders
public int Channels { get { return 1; } } public int Channels { get { return 1; } }
public int SampleRate { get; private set; } public int SampleRate { get; private set; }
public float LengthInSeconds { get { return (float)totalSamples / SampleRate; } } public float LengthInSeconds { get { return (float)totalSamples / SampleRate; } }
public Stream GetPCMInputStream() { return new VocStream(this); } public Stream GetPCMInputStream() { return new VocStream(new VocFormat(this)); }
public void Dispose() { stream.Dispose(); } public void Dispose() { stream.Dispose(); }
int totalSamples = 0; readonly byte[] buffer = new byte[4096];
int samplePosition = 0; readonly Stream stream;
readonly VocBlock[] blocks;
readonly int totalSamples;
Stream stream;
List<VocBlock> blocks = new List<VocBlock>();
IEnumerator<VocBlock> currentBlock; IEnumerator<VocBlock> currentBlock;
int samplesLeftInBlock = 0; int samplesLeftInBlock;
byte[] buffer = new byte[4096]; int samplePosition;
struct VocFileHeader struct VocFileHeader
{ {
@@ -95,11 +96,23 @@ namespace OpenRA.Mods.Common.AudioLoaders
{ {
this.stream = stream; this.stream = stream;
CheckVocHeader(); CheckVocHeader(stream);
Preload(); int sampleRate;
Preload(stream, out blocks, out totalSamples, out sampleRate);
SampleRate = sampleRate;
Rewind();
} }
void CheckVocHeader() VocFormat(VocFormat cloneFrom)
{
SampleRate = cloneFrom.SampleRate;
stream = SegmentStream.CreateWithoutOwningStream(cloneFrom.stream, 0, (int)cloneFrom.stream.Length);
blocks = cloneFrom.blocks;
totalSamples = cloneFrom.totalSamples;
Rewind();
}
static void CheckVocHeader(Stream stream)
{ {
var vfh = VocFileHeader.Read(stream); var vfh = VocFileHeader.Read(stream);
@@ -114,7 +127,7 @@ namespace OpenRA.Mods.Common.AudioLoaders
(~vfh.Version + 0x1234).ToString("X") + " but value is : " + vfh.ID.ToString("X")); (~vfh.Version + 0x1234).ToString("X") + " but value is : " + vfh.ID.ToString("X"));
} }
int GetSampleRateFromVocRate(int vocSampleRate) static int GetSampleRateFromVocRate(int vocSampleRate)
{ {
if (vocSampleRate == 256) if (vocSampleRate == 256)
throw new InvalidDataException("Invalid frequency divisor 256 in voc file"); throw new InvalidDataException("Invalid frequency divisor 256 in voc file");
@@ -126,8 +139,12 @@ namespace OpenRA.Mods.Common.AudioLoaders
return (int)(1000000L / (256L - vocSampleRate)); return (int)(1000000L / (256L - vocSampleRate));
} }
void Preload() static void Preload(Stream stream, out VocBlock[] blocks, out int totalSamples, out int sampleRate)
{ {
var blockList = new List<VocBlock>();
totalSamples = 0;
sampleRate = 0;
while (true) while (true)
{ {
VocBlock block = new VocBlock(); VocBlock block = new VocBlock();
@@ -167,17 +184,17 @@ namespace OpenRA.Mods.Common.AudioLoaders
block.SampleBlock.Offset = stream.Position; block.SampleBlock.Offset = stream.Position;
// See if last block contained additional information // See if last block contained additional information
if (blocks.Count > 0) if (blockList.Count > 0)
{ {
var b = blocks.Last(); var b = blockList.Last();
if (b.Code == 8) if (b.Code == 8)
{ {
block.SampleBlock.Rate = b.SampleBlock.Rate; block.SampleBlock.Rate = b.SampleBlock.Rate;
blocks.Remove(b); blockList.Remove(b);
} }
} }
SampleRate = Math.Max(SampleRate, block.SampleBlock.Rate); sampleRate = Math.Max(sampleRate, block.SampleBlock.Rate);
break; break;
} }
@@ -234,27 +251,27 @@ namespace OpenRA.Mods.Common.AudioLoaders
if (skip > 0) if (skip > 0)
stream.Seek(skip, SeekOrigin.Current); stream.Seek(skip, SeekOrigin.Current);
blocks.Add(block); blockList.Add(block);
} }
// Check validity and calculated total number of samples // Check validity and calculated total number of samples
foreach (var b in blocks) foreach (var b in blockList)
{ {
if (b.Code == 8) if (b.Code == 8)
throw new InvalidDataException("Unused block 8 in voc file"); throw new InvalidDataException("Unused block 8 in voc file");
if (b.Code != 1 && b.Code != 9) if (b.Code != 1 && b.Code != 9)
continue; continue;
if (b.SampleBlock.Rate != SampleRate) if (b.SampleBlock.Rate != sampleRate)
throw new InvalidDataException("Voc file contains chunks with different sample rate"); throw new InvalidDataException("Voc file contains chunks with different sample rate");
totalSamples += b.SampleBlock.Samples; totalSamples += b.SampleBlock.Samples;
} }
Rewind(); blocks = blockList.ToArray();
} }
void Rewind() void Rewind()
{ {
currentBlock = blocks.GetEnumerator(); currentBlock = (IEnumerator<VocBlock>)blocks.GetEnumerator();
samplesLeftInBlock = 0; samplesLeftInBlock = 0;
samplePosition = 0; samplePosition = 0;
@@ -356,6 +373,13 @@ namespace OpenRA.Mods.Common.AudioLoaders
public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); }
public override void SetLength(long value) { throw new NotImplementedException(); } public override void SetLength(long value) { throw new NotImplementedException(); }
public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); }
protected override void Dispose(bool disposing)
{
if (disposing)
format.Dispose();
base.Dispose(disposing);
}
} }
} }
} }