Fix most of sound issues with OpenAL backend

This commit is contained in:
UnknownShadow200 2018-08-14 22:20:37 +10:00
parent 259128e133
commit 0139788fee
13 changed files with 70 additions and 97 deletions

View File

@ -64,7 +64,7 @@ namespace ClassicalSharp.Audio {
disposingMusic = false;
musicOut = GetPlatformOut();
musicOut.Create(10);
musicOut.Create(4);
musicThread = MakeThread(DoMusicThread, "ClassicalSharp.DoMusic");
}

View File

@ -5,7 +5,7 @@ using System.Threading;
namespace SharpWave {
public struct AudioFormat {
public struct AudioFormat {
public int Channels, BitsPerSample, SampleRate;
public bool Equals(AudioFormat a) {
@ -33,31 +33,49 @@ namespace SharpWave {
public int NumBuffers;
public bool pendingStop;
public void PlayStreaming(Stream src) {
public void PlayStreaming(Stream stream) {
VorbisCodec codec = new VorbisCodec();
AudioFormat format = codec.ReadHeader(src);
AudioFormat fmt = codec.ReadHeader(stream);
SetFormat(format);
IEnumerator<AudioChunk> chunks = codec.StreamData(src).GetEnumerator();
SetFormat(fmt);
IEnumerator<AudioChunk> chunks = codec.StreamData(stream).GetEnumerator();
AudioChunk tmp = new AudioChunk();
// 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]; }
bool reachedEnd = false;
for (;;) {
// Have any of the buffers finished playing
if (reachedEnd && IsFinished()) return;
int next = -1;
for (int i = 0; i < NumBuffers; i++) {
if (IsCompleted(i)) { next = i; break; }
}
if (next == -1) {
} else if (pendingStop || !chunks.MoveNext()) {
reachedEnd = true;
} else {
PlayData(next, chunks.Current);
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;
}
Thread.Sleep(1);
PlayData(next, tmp);
// need to specially handle last bit of audio
if (reachedEnd) break;
}
while (!IsFinished()) { Thread.Sleep(10); }
}
}
}

View File

@ -70,7 +70,7 @@ namespace SharpWave {
CheckError(result, "Open");
}
public override void PlayData(int index, AudioChunk chunk) {
public override void PlayData(int index, AudioChunk chunk) {
if (chunk.Length > dataSizes[index]) {
IntPtr ptr = dataHandles[index];
if (ptr != IntPtr.Zero) Marshal.FreeHGlobal(ptr);

View File

@ -118,45 +118,6 @@ namespace SharpWave {
}
public IEnumerable<AudioChunk> StreamData( Stream source ) {
// the original iterator may not always return enough samples,
// so we will do our own buffering here.
rawChunk = new AudioChunk();
foreach( AudioChunk chunk in StreamDataCore( source ) ) {
if( rawPcm == null )
InitRaw( chunk );
if( rawIndex + chunk.Length > rawPcm.Length )
ResizeRaw( rawIndex + chunk.Length );
Buffer.BlockCopy( chunk.Data, 0, rawPcm, rawIndex, chunk.Length );
rawIndex += chunk.Length;
if( rawIndex >= (vi.rate / 4) ) {
rawChunk.Length = rawIndex;
rawIndex = 0;
yield return rawChunk;
}
}
rawChunk.Length = rawIndex;
yield return rawChunk;
yield break;
}
void InitRaw(AudioChunk chunk) {
rawPcm = new byte[vi.rate / 4];
rawChunk.Data = rawPcm;
rawChunk.Length = rawPcm.Length;
}
void ResizeRaw(int newLen) {
byte[] oldPcm = rawPcm;
rawPcm = new byte[rawIndex + chunk.Length];
Buffer.BlockCopy( oldPcm, 0, rawPcm, 0, rawIndex );
rawChunk.Data = rawPcm;
rawChunk.Length = rawPcm.Length;
}
IEnumerable<AudioChunk> StreamDataCore( Stream source ) {
input = source;
int convsize = 4096 * 2;
byte[] convbuffer = new byte[convsize]; // take 8k out of the data segment, not the stack

View File

@ -261,7 +261,7 @@ static void AsyncDownloader_WorkerFunc(void) {
Mutex_Lock(async_pendingMutex);
{
if (async_terminate) return;
if (async_pending.Count > 0) {
if (async_pending.Count) {
request = async_pending.Requests[0];
hasRequest = true;
AsyncRequestList_RemoveAt(&async_pending, 0);

View File

@ -281,45 +281,39 @@ static ReturnCode Music_PlayOgg(struct Stream* source) {
fmt.BitsPerSample = 16;
Audio_SetFormat(music_out, &fmt);
/* max possible result of a vorbis decode is blocksize1 */
/* so we decode a bit over a second of audio each time */
Int32 offset = 0, size = (Math_CeilDiv(fmt.SampleRate, vorbis.BlockSizes[1]) + 1) * vorbis.BlockSizes[1];
Int16* data = Mem_Alloc((size * fmt.Channels) * AUDIO_MAX_CHUNKS, sizeof(Int16), "Ogg - final PCM output");
/* largest possible vorbis frame decodes to blocksize1 samples */
/* so we may end up decoding slightly over a second of audio */
Int32 chunkSize = (fmt.SampleRate + vorbis.BlockSizes[1]) * fmt.Channels;
Int16* data = Mem_Alloc(chunkSize * AUDIO_MAX_CHUNKS, sizeof(Int16), "Ogg - final PCM output");
Int32 i, next;
for (;;) {
next = -1;
Int32 i, next = -1;
for (i = 0; i < AUDIO_MAX_CHUNKS; i++) {
if (Audio_IsCompleted(music_out, i)) { next = i; break; }
}
if (next == -1) {
} else if (music_pendingStop) {
goto finished;
} else {
/* decode up to around a second */
Int16* base = data + (size * fmt.Channels) * next;
if (next == -1) { Thread_Sleep(10); continue; }
if (music_pendingStop) break;
while (offset + vorbis.BlockSizes[1] < size) {
result = Vorbis_DecodeFrame(&vorbis);
if (result == ERR_END_OF_STREAM) break;
if (result) goto finished;
/* decode up to around a second */
Int16* base = data + (chunkSize * next);
Int32 samples = 0;
Int16* cur = &base[offset * fmt.Channels];
offset += Vorbis_OutputFrame(&vorbis, cur);
}
while (samples < fmt.SampleRate) {
result = Vorbis_DecodeFrame(&vorbis);
if (result) break;
Audio_PlayData(music_out, next, base, offset * fmt.Channels * sizeof(Int16));
offset = 0;
/* need to specially handle last bit of audio */
if (result == ERR_END_OF_STREAM) goto finished;
Int16* cur = &base[samples * fmt.Channels];
samples += Vorbis_OutputFrame(&vorbis, cur);
}
Thread_Sleep(1);
Audio_PlayData(music_out, next, base, samples * fmt.Channels * sizeof(Int16));
/* need to specially handle last bit of audio */
if (result) break;
}
finished:
/* Wait until the buffers finished playing */
while (!Audio_IsFinished(music_out)) { Thread_Sleep(1); }
while (!Audio_IsFinished(music_out)) { Thread_Sleep(10); }
Mem_Free(&data);
Vorbis_Free(&vorbis);

View File

@ -503,7 +503,7 @@ void EnvRenderer_RenderBorders(BlockID block, GfxResourceID vb, GfxResourceID te
Gfx_BindTexture(tex);
Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B);
Gfx_BindVb(vb);
if (count > 0) Gfx_DrawVb_IndexedTris(count);
if (count) Gfx_DrawVb_IndexedTris(count);
Gfx_DisableMipmaps();
GfxCommon_RestoreAlphaState(Block_Draw[block]);

View File

@ -130,7 +130,7 @@ void Gui_MakeComponent(struct IGameComponent* comp) {
}
struct Screen* Gui_GetActiveScreen(void) {
return Gui_OverlaysCount > 0 ? Gui_Overlays[0] : Gui_GetUnderlyingScreen();
return Gui_OverlaysCount ? Gui_Overlays[0] : Gui_GetUnderlyingScreen();
}
struct Screen* Gui_GetUnderlyingScreen(void) {
@ -207,7 +207,7 @@ void Gui_RenderGui(Real64 delta) {
if (Gui_Active) { Elem_Render(Gui_Active, delta); }
if (showHUD && !hudBefore) { Elem_Render(Gui_HUD, delta); }
if (Gui_OverlaysCount > 0) { Elem_Render(Gui_Overlays[0], delta); }
if (Gui_OverlaysCount) { Elem_Render(Gui_Overlays[0], delta); }
GfxCommon_Mode3D();
}

View File

@ -164,7 +164,7 @@ static bool InputHandler_HandleNonClassicKey(Key key) {
Event_RaiseVoid(&UserEvents_HeldBlockChanged);
}
} else if (key == KeyBind_Get(KeyBind_IDOverlay)) {
if (Gui_OverlaysCount > 0) return true;
if (Gui_OverlaysCount) return true;
struct Screen* overlay = TexIdsOverlay_MakeInstance();
Gui_ShowOverlay(overlay, false);
} else if (key == KeyBind_Get(KeyBind_BreakableLiquids)) {

View File

@ -1463,7 +1463,7 @@ struct Screen* TexturePackScreen_MakeInstance(void) {
String path = String_FromConst("texpacks");
Directory_Enum(&path, &screen->Entries, TexturePackScreen_SelectEntry);
if (screen->Entries.Count > 0) {
if (screen->Entries.Count) {
ListScreen_QuickSort(0, screen->Entries.Count - 1);
}
return (struct Screen*)screen;
@ -1665,7 +1665,7 @@ struct Screen* LoadLevelScreen_MakeInstance(void) {
String path = String_FromConst("maps");
Directory_Enum(&path, &screen->Entries, LoadLevelScreen_SelectEntry);
if (screen->Entries.Count > 0) {
if (screen->Entries.Count) {
ListScreen_QuickSort(0, screen->Entries.Count - 1);
}
return (struct Screen*)screen;

View File

@ -716,7 +716,7 @@ static void CPE_WriteTwoWayPing(struct Stream* stream, bool serverToClient, UInt
}
static void CPE_SendCpeExtInfoReply(void) {
if (cpe_serverExtensionsCount != 0) return;
if (cpe_serverExtensionsCount) return;
Int32 count = Array_Elems(cpe_clientExtensions);
if (!Game_AllowCustomBlocks) count -= 2;
struct Stream* stream = ServerConnection_WriteStream();

View File

@ -197,7 +197,7 @@ Int32 Searcher_FindReachableBlocks(struct Entity* entity, struct AABB* entityBB,
}
Int32 count = (Int32)(curState - Searcher_States);
if (count > 0) Searcher_QuickSort(0, count - 1);
if (count) Searcher_QuickSort(0, count - 1);
return count;
}

View File

@ -422,7 +422,7 @@ static void MPConnection_Tick(struct ScheduledTask* task) {
return;
}
while (net_readStream.Meta.Mem.Left > 0) {
while (net_readStream.Meta.Mem.Left) {
UInt8 opcode = net_readStream.Meta.Mem.Cur[0];
/* Workaround for older D3 servers which wrote one byte too many for HackControl packets */
if (cpe_needD3Fix && net_lastOpcode == OPCODE_CPE_HACK_CONTROL && (opcode == 0x00 || opcode == 0xFF)) {
@ -476,12 +476,12 @@ void Net_Set(UInt8 opcode, Net_Handler handler, UInt16 packetSize) {
void Net_SendPacket(void) {
if (!ServerConnection_Disconnected) {
/* NOTE: Not immediately disconnecting here, as otherwise we sometimes miss out on kick messages */
UInt32 count = (UInt32)(net_writeStream.Meta.Mem.Cur - net_writeStream.Meta.Mem.Base), modified = 0;
UInt32 count = (UInt32)(net_writeStream.Meta.Mem.Cur - net_writeStream.Meta.Mem.Base), wrote = 0;
while (count > 0) {
ReturnCode result = Socket_Write(net_socket, net_writeBuffer, count, &modified);
if (result != 0 || modified == 0) { net_writeFailed = true; break; }
count -= modified;
while (count) {
ReturnCode result = Socket_Write(net_socket, net_writeBuffer, count, &wrote);
if (result || !wrote) { net_writeFailed = true; break; }
count -= wrote;
}
}