mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-16 02:56:09 -04:00
Fix most of sound issues with OpenAL backend
This commit is contained in:
parent
259128e133
commit
0139788fee
@ -64,7 +64,7 @@ namespace ClassicalSharp.Audio {
|
||||
|
||||
disposingMusic = false;
|
||||
musicOut = GetPlatformOut();
|
||||
musicOut.Create(10);
|
||||
musicOut.Create(4);
|
||||
musicThread = MakeThread(DoMusicThread, "ClassicalSharp.DoMusic");
|
||||
}
|
||||
|
||||
|
@ -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); }
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user