fix crackling/popping when playing music on openal backend

This commit is contained in:
UnknownShadow200 2018-08-19 17:29:40 +10:00
parent de3bce77a6
commit 9399d5b384
5 changed files with 54 additions and 32 deletions

View file

@ -27,12 +27,33 @@ namespace SharpWave {
public AudioFormat Format;
public abstract void SetFormat(AudioFormat format);
public abstract void PlayData(int index, AudioChunk chunk);
public abstract void BufferData(int index, AudioChunk chunk);
public abstract void Play();
public abstract bool IsCompleted(int index);
public abstract bool IsFinished();
public int NumBuffers;
public bool pendingStop;
public void PlayData(int index, AudioChunk chunk) {
BufferData(index, chunk);
Play();
}
bool BufferBlock(AudioChunk tmp, AudioFormat fmt, IEnumerator<AudioChunk> chunks) {
// decode up to around a second
int secondSize = fmt.SampleRate * fmt.Channels * sizeof(short);
tmp.Length = 0;
while (tmp.Length < secondSize) {
if (!chunks.MoveNext()) return true;
AudioChunk src = chunks.Current;
Buffer.BlockCopy(src.Data, 0, tmp.Data, tmp.Length, src.Length);
tmp.Length += src.Length;
}
return false;
}
public void PlayStreaming(Stream stream) {
VorbisCodec codec = new VorbisCodec();
AudioFormat fmt = codec.ReadHeader(stream);
@ -43,12 +64,19 @@ namespace SharpWave {
// largest possible vorbis frame decodes to blocksize1 samples
// so we may end up decoding slightly over a second of audio
int secondSize = fmt.SampleRate * fmt.Channels * sizeof(short);
int chunkSize = (fmt.SampleRate + 8192) * fmt.Channels * sizeof(short);
byte[][] data = new byte[NumBuffers][];
for (int i = 0; i < NumBuffers; i++) { data[i] = new byte[chunkSize]; }
for (int i = 0; i < NumBuffers; i++) { data[i] = new byte[chunkSize]; }
for (;;) {
bool reachedEnd = false;
for (int i = 0; i < NumBuffers && !reachedEnd; i++) {
tmp.Data = data[i];
reachedEnd = BufferBlock(tmp, fmt, chunks);
BufferData(i, tmp);
}
Play();
for (; !reachedEnd;) {
int next = -1;
for (int i = 0; i < NumBuffers; i++) {
if (IsCompleted(i)) { next = i; break; }
@ -56,23 +84,10 @@ namespace SharpWave {
if (next == -1) { Thread.Sleep(10); continue; }
if (pendingStop) break;
// decode up to around a second
tmp.Data = data[next];
tmp.Length = 0;
bool reachedEnd = false;
while (tmp.Length < secondSize) {
if (!chunks.MoveNext()) { reachedEnd = true; break; }
AudioChunk src = chunks.Current;
Buffer.BlockCopy(src.Data, 0, tmp.Data, tmp.Length, src.Length);
tmp.Length += src.Length;
}
PlayData(next, tmp);
// need to specially handle last bit of audio
if (reachedEnd) break;
reachedEnd = BufferBlock(tmp, fmt, chunks);
BufferData(next, tmp);
}
while (!IsFinished()) { Thread.Sleep(10); }

View file

@ -48,12 +48,12 @@ namespace SharpWave {
public override bool IsCompleted(int index) {
int processed = 0;
uint buffer = 0;
uint buffer = 0;
lock (contextLock) {
MakeContextCurrent();
AL.alGetSourcei(source, ALGetSourcei.BuffersProcessed, &processed);
CheckError("GetSources");
CheckError("GetSources");
if (processed == 0) return completed[index];
AL.alSourceUnqueueBuffers(source, 1, &buffer);
@ -80,7 +80,7 @@ namespace SharpWave {
}
}
public override void PlayData(int index, AudioChunk chunk) {
public override void BufferData(int index, AudioChunk chunk) {
fixed (byte* data = chunk.Data) {
uint buffer = bufferIDs[index];
completed[index] = false;
@ -88,17 +88,23 @@ namespace SharpWave {
lock (contextLock) {
MakeContextCurrent();
AL.alBufferData(buffer, dataFormat, (IntPtr)data,
chunk.Length, Format.SampleRate);
chunk.Length, Format.SampleRate);
CheckError("BufferData");
AL.alSourceQueueBuffers(source, 1, &buffer);
CheckError("QueueBuffers");
AL.alSourcePlay(source);
CheckError("SourcePlay");
CheckError("QueueBuffers");
}
}
}
public override void Play() {
lock (contextLock) {
MakeContextCurrent();
AL.alSourcePlay(source);
CheckError("SourcePlay");
}
}
void CheckError(string location) {
ALError error = AL.alGetError();
if (error != ALError.NoError) {

View file

@ -70,7 +70,7 @@ namespace SharpWave {
CheckError(result, "Open");
}
public override void PlayData(int index, AudioChunk chunk) {
public override void BufferData(int index, AudioChunk chunk) {
if (chunk.Length > dataSizes[index]) {
IntPtr ptr = dataHandles[index];
if (ptr != IntPtr.Zero) Marshal.FreeHGlobal(ptr);
@ -97,6 +97,8 @@ namespace SharpWave {
CheckError(result, "Write");
}
public override void Play() { }
void ApplyVolume(IntPtr handle, AudioChunk chunk) {
if (volumePercent == 100) return;

View file

@ -11,11 +11,9 @@ namespace SharpWave {
chunk = new AudioChunk();
}
AudioChunk chunk, rawChunk;
AudioChunk chunk;
Stream input;
byte[] rawPcm;
int rawIndex;
SyncState oy = new SyncState(); // sync and verify incoming physical bitstream
StreamState os = new StreamState(); // take physical pages, weld into a logical stream of packets
Page og = new Page(); // one Ogg bitstream page. Vorbis packets are inside

View file

@ -932,6 +932,7 @@ static void CPE_MakeSelection(UInt8* data) {
p2.Z = (Int16)Stream_GetU16_BE(&data[4]);
PackedCol c; data += 6;
/* R,G,B,A are actually 16 bit unsigned integers */
c.R = data[1]; c.G = data[3]; c.B = data[5]; c.A = data[7];
Selections_Add(selectionId, p1, p2, c);
}