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.IO;
using System.Linq;
using OpenRA.Primitives;
namespace OpenRA.Mods.Common.AudioLoaders
{
@@ -41,17 +42,17 @@ namespace OpenRA.Mods.Common.AudioLoaders
public int Channels { get { return 1; } }
public int SampleRate { get; private set; }
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(); }
int totalSamples = 0;
int samplePosition = 0;
readonly byte[] buffer = new byte[4096];
readonly Stream stream;
readonly VocBlock[] blocks;
readonly int totalSamples;
Stream stream;
List<VocBlock> blocks = new List<VocBlock>();
IEnumerator<VocBlock> currentBlock;
int samplesLeftInBlock = 0;
byte[] buffer = new byte[4096];
int samplesLeftInBlock;
int samplePosition;
struct VocFileHeader
{
@@ -95,11 +96,23 @@ namespace OpenRA.Mods.Common.AudioLoaders
{
this.stream = stream;
CheckVocHeader();
Preload();
CheckVocHeader(stream);
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);
@@ -114,7 +127,7 @@ namespace OpenRA.Mods.Common.AudioLoaders
(~vfh.Version + 0x1234).ToString("X") + " but value is : " + vfh.ID.ToString("X"));
}
int GetSampleRateFromVocRate(int vocSampleRate)
static int GetSampleRateFromVocRate(int vocSampleRate)
{
if (vocSampleRate == 256)
throw new InvalidDataException("Invalid frequency divisor 256 in voc file");
@@ -126,8 +139,12 @@ namespace OpenRA.Mods.Common.AudioLoaders
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)
{
VocBlock block = new VocBlock();
@@ -167,17 +184,17 @@ namespace OpenRA.Mods.Common.AudioLoaders
block.SampleBlock.Offset = stream.Position;
// 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)
{
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;
}
@@ -234,27 +251,27 @@ namespace OpenRA.Mods.Common.AudioLoaders
if (skip > 0)
stream.Seek(skip, SeekOrigin.Current);
blocks.Add(block);
blockList.Add(block);
}
// Check validity and calculated total number of samples
foreach (var b in blocks)
foreach (var b in blockList)
{
if (b.Code == 8)
throw new InvalidDataException("Unused block 8 in voc file");
if (b.Code != 1 && b.Code != 9)
continue;
if (b.SampleBlock.Rate != SampleRate)
if (b.SampleBlock.Rate != sampleRate)
throw new InvalidDataException("Voc file contains chunks with different sample rate");
totalSamples += b.SampleBlock.Samples;
}
Rewind();
blocks = blockList.ToArray();
}
void Rewind()
{
currentBlock = blocks.GetEnumerator();
currentBlock = (IEnumerator<VocBlock>)blocks.GetEnumerator();
samplesLeftInBlock = 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 void SetLength(long value) { 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);
}
}
}
}