mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-18 20:15:35 -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;
|
disposingMusic = false;
|
||||||
musicOut = GetPlatformOut();
|
musicOut = GetPlatformOut();
|
||||||
musicOut.Create(10);
|
musicOut.Create(4);
|
||||||
musicThread = MakeThread(DoMusicThread, "ClassicalSharp.DoMusic");
|
musicThread = MakeThread(DoMusicThread, "ClassicalSharp.DoMusic");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,31 +33,49 @@ namespace SharpWave {
|
|||||||
|
|
||||||
public int NumBuffers;
|
public int NumBuffers;
|
||||||
public bool pendingStop;
|
public bool pendingStop;
|
||||||
public void PlayStreaming(Stream src) {
|
public void PlayStreaming(Stream stream) {
|
||||||
VorbisCodec codec = new VorbisCodec();
|
VorbisCodec codec = new VorbisCodec();
|
||||||
AudioFormat format = codec.ReadHeader(src);
|
AudioFormat fmt = codec.ReadHeader(stream);
|
||||||
|
|
||||||
SetFormat(format);
|
SetFormat(fmt);
|
||||||
IEnumerator<AudioChunk> chunks = codec.StreamData(src).GetEnumerator();
|
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 (;;) {
|
for (;;) {
|
||||||
// Have any of the buffers finished playing
|
|
||||||
if (reachedEnd && IsFinished()) return;
|
|
||||||
|
|
||||||
int next = -1;
|
int next = -1;
|
||||||
for (int i = 0; i < NumBuffers; i++) {
|
for (int i = 0; i < NumBuffers; i++) {
|
||||||
if (IsCompleted(i)) { next = i; break; }
|
if (IsCompleted(i)) { next = i; break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next == -1) {
|
if (next == -1) { Thread.Sleep(10); continue; }
|
||||||
} else if (pendingStop || !chunks.MoveNext()) {
|
if (pendingStop) break;
|
||||||
reachedEnd = true;
|
|
||||||
} else {
|
// decode up to around a second
|
||||||
PlayData(next, chunks.Current);
|
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); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -118,45 +118,6 @@ namespace SharpWave {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<AudioChunk> StreamData( Stream source ) {
|
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;
|
input = source;
|
||||||
int convsize = 4096 * 2;
|
int convsize = 4096 * 2;
|
||||||
byte[] convbuffer = new byte[convsize]; // take 8k out of the data segment, not the stack
|
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);
|
Mutex_Lock(async_pendingMutex);
|
||||||
{
|
{
|
||||||
if (async_terminate) return;
|
if (async_terminate) return;
|
||||||
if (async_pending.Count > 0) {
|
if (async_pending.Count) {
|
||||||
request = async_pending.Requests[0];
|
request = async_pending.Requests[0];
|
||||||
hasRequest = true;
|
hasRequest = true;
|
||||||
AsyncRequestList_RemoveAt(&async_pending, 0);
|
AsyncRequestList_RemoveAt(&async_pending, 0);
|
||||||
|
@ -281,45 +281,39 @@ static ReturnCode Music_PlayOgg(struct Stream* source) {
|
|||||||
fmt.BitsPerSample = 16;
|
fmt.BitsPerSample = 16;
|
||||||
Audio_SetFormat(music_out, &fmt);
|
Audio_SetFormat(music_out, &fmt);
|
||||||
|
|
||||||
/* max possible result of a vorbis decode is blocksize1 */
|
/* largest possible vorbis frame decodes to blocksize1 samples */
|
||||||
/* so we decode a bit over a second of audio each time */
|
/* so we may end up decoding slightly over a second of audio */
|
||||||
Int32 offset = 0, size = (Math_CeilDiv(fmt.SampleRate, vorbis.BlockSizes[1]) + 1) * vorbis.BlockSizes[1];
|
Int32 chunkSize = (fmt.SampleRate + vorbis.BlockSizes[1]) * fmt.Channels;
|
||||||
Int16* data = Mem_Alloc((size * fmt.Channels) * AUDIO_MAX_CHUNKS, sizeof(Int16), "Ogg - final PCM output");
|
Int16* data = Mem_Alloc(chunkSize * AUDIO_MAX_CHUNKS, sizeof(Int16), "Ogg - final PCM output");
|
||||||
|
|
||||||
Int32 i, next;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
next = -1;
|
Int32 i, next = -1;
|
||||||
for (i = 0; i < AUDIO_MAX_CHUNKS; i++) {
|
for (i = 0; i < AUDIO_MAX_CHUNKS; i++) {
|
||||||
if (Audio_IsCompleted(music_out, i)) { next = i; break; }
|
if (Audio_IsCompleted(music_out, i)) { next = i; break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next == -1) {
|
if (next == -1) { Thread_Sleep(10); continue; }
|
||||||
} else if (music_pendingStop) {
|
if (music_pendingStop) break;
|
||||||
goto finished;
|
|
||||||
} else {
|
|
||||||
/* decode up to around a second */
|
/* decode up to around a second */
|
||||||
Int16* base = data + (size * fmt.Channels) * next;
|
Int16* base = data + (chunkSize * next);
|
||||||
|
Int32 samples = 0;
|
||||||
|
|
||||||
while (offset + vorbis.BlockSizes[1] < size) {
|
while (samples < fmt.SampleRate) {
|
||||||
result = Vorbis_DecodeFrame(&vorbis);
|
result = Vorbis_DecodeFrame(&vorbis);
|
||||||
if (result == ERR_END_OF_STREAM) break;
|
if (result) break;
|
||||||
if (result) goto finished;
|
|
||||||
|
|
||||||
Int16* cur = &base[offset * fmt.Channels];
|
Int16* cur = &base[samples * fmt.Channels];
|
||||||
offset += Vorbis_OutputFrame(&vorbis, cur);
|
samples += Vorbis_OutputFrame(&vorbis, cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
Audio_PlayData(music_out, next, base, offset * fmt.Channels * sizeof(Int16));
|
Audio_PlayData(music_out, next, base, samples * fmt.Channels * sizeof(Int16));
|
||||||
offset = 0;
|
|
||||||
/* need to specially handle last bit of audio */
|
/* need to specially handle last bit of audio */
|
||||||
if (result == ERR_END_OF_STREAM) goto finished;
|
if (result) break;
|
||||||
}
|
|
||||||
Thread_Sleep(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finished:
|
|
||||||
/* Wait until the buffers finished playing */
|
/* 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);
|
Mem_Free(&data);
|
||||||
Vorbis_Free(&vorbis);
|
Vorbis_Free(&vorbis);
|
||||||
|
@ -503,7 +503,7 @@ void EnvRenderer_RenderBorders(BlockID block, GfxResourceID vb, GfxResourceID te
|
|||||||
Gfx_BindTexture(tex);
|
Gfx_BindTexture(tex);
|
||||||
Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B);
|
Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B);
|
||||||
Gfx_BindVb(vb);
|
Gfx_BindVb(vb);
|
||||||
if (count > 0) Gfx_DrawVb_IndexedTris(count);
|
if (count) Gfx_DrawVb_IndexedTris(count);
|
||||||
|
|
||||||
Gfx_DisableMipmaps();
|
Gfx_DisableMipmaps();
|
||||||
GfxCommon_RestoreAlphaState(Block_Draw[block]);
|
GfxCommon_RestoreAlphaState(Block_Draw[block]);
|
||||||
|
@ -130,7 +130,7 @@ void Gui_MakeComponent(struct IGameComponent* comp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Screen* Gui_GetActiveScreen(void) {
|
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) {
|
struct Screen* Gui_GetUnderlyingScreen(void) {
|
||||||
@ -207,7 +207,7 @@ void Gui_RenderGui(Real64 delta) {
|
|||||||
if (Gui_Active) { Elem_Render(Gui_Active, delta); }
|
if (Gui_Active) { Elem_Render(Gui_Active, delta); }
|
||||||
if (showHUD && !hudBefore) { Elem_Render(Gui_HUD, 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();
|
GfxCommon_Mode3D();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ static bool InputHandler_HandleNonClassicKey(Key key) {
|
|||||||
Event_RaiseVoid(&UserEvents_HeldBlockChanged);
|
Event_RaiseVoid(&UserEvents_HeldBlockChanged);
|
||||||
}
|
}
|
||||||
} else if (key == KeyBind_Get(KeyBind_IDOverlay)) {
|
} else if (key == KeyBind_Get(KeyBind_IDOverlay)) {
|
||||||
if (Gui_OverlaysCount > 0) return true;
|
if (Gui_OverlaysCount) return true;
|
||||||
struct Screen* overlay = TexIdsOverlay_MakeInstance();
|
struct Screen* overlay = TexIdsOverlay_MakeInstance();
|
||||||
Gui_ShowOverlay(overlay, false);
|
Gui_ShowOverlay(overlay, false);
|
||||||
} else if (key == KeyBind_Get(KeyBind_BreakableLiquids)) {
|
} else if (key == KeyBind_Get(KeyBind_BreakableLiquids)) {
|
||||||
|
@ -1463,7 +1463,7 @@ struct Screen* TexturePackScreen_MakeInstance(void) {
|
|||||||
|
|
||||||
String path = String_FromConst("texpacks");
|
String path = String_FromConst("texpacks");
|
||||||
Directory_Enum(&path, &screen->Entries, TexturePackScreen_SelectEntry);
|
Directory_Enum(&path, &screen->Entries, TexturePackScreen_SelectEntry);
|
||||||
if (screen->Entries.Count > 0) {
|
if (screen->Entries.Count) {
|
||||||
ListScreen_QuickSort(0, screen->Entries.Count - 1);
|
ListScreen_QuickSort(0, screen->Entries.Count - 1);
|
||||||
}
|
}
|
||||||
return (struct Screen*)screen;
|
return (struct Screen*)screen;
|
||||||
@ -1665,7 +1665,7 @@ struct Screen* LoadLevelScreen_MakeInstance(void) {
|
|||||||
|
|
||||||
String path = String_FromConst("maps");
|
String path = String_FromConst("maps");
|
||||||
Directory_Enum(&path, &screen->Entries, LoadLevelScreen_SelectEntry);
|
Directory_Enum(&path, &screen->Entries, LoadLevelScreen_SelectEntry);
|
||||||
if (screen->Entries.Count > 0) {
|
if (screen->Entries.Count) {
|
||||||
ListScreen_QuickSort(0, screen->Entries.Count - 1);
|
ListScreen_QuickSort(0, screen->Entries.Count - 1);
|
||||||
}
|
}
|
||||||
return (struct Screen*)screen;
|
return (struct Screen*)screen;
|
||||||
|
@ -716,7 +716,7 @@ static void CPE_WriteTwoWayPing(struct Stream* stream, bool serverToClient, UInt
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void CPE_SendCpeExtInfoReply(void) {
|
static void CPE_SendCpeExtInfoReply(void) {
|
||||||
if (cpe_serverExtensionsCount != 0) return;
|
if (cpe_serverExtensionsCount) return;
|
||||||
Int32 count = Array_Elems(cpe_clientExtensions);
|
Int32 count = Array_Elems(cpe_clientExtensions);
|
||||||
if (!Game_AllowCustomBlocks) count -= 2;
|
if (!Game_AllowCustomBlocks) count -= 2;
|
||||||
struct Stream* stream = ServerConnection_WriteStream();
|
struct Stream* stream = ServerConnection_WriteStream();
|
||||||
|
@ -197,7 +197,7 @@ Int32 Searcher_FindReachableBlocks(struct Entity* entity, struct AABB* entityBB,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Int32 count = (Int32)(curState - Searcher_States);
|
Int32 count = (Int32)(curState - Searcher_States);
|
||||||
if (count > 0) Searcher_QuickSort(0, count - 1);
|
if (count) Searcher_QuickSort(0, count - 1);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,7 +422,7 @@ static void MPConnection_Tick(struct ScheduledTask* task) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (net_readStream.Meta.Mem.Left > 0) {
|
while (net_readStream.Meta.Mem.Left) {
|
||||||
UInt8 opcode = net_readStream.Meta.Mem.Cur[0];
|
UInt8 opcode = net_readStream.Meta.Mem.Cur[0];
|
||||||
/* Workaround for older D3 servers which wrote one byte too many for HackControl packets */
|
/* 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)) {
|
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) {
|
void Net_SendPacket(void) {
|
||||||
if (!ServerConnection_Disconnected) {
|
if (!ServerConnection_Disconnected) {
|
||||||
/* NOTE: Not immediately disconnecting here, as otherwise we sometimes miss out on kick messages */
|
/* 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) {
|
while (count) {
|
||||||
ReturnCode result = Socket_Write(net_socket, net_writeBuffer, count, &modified);
|
ReturnCode result = Socket_Write(net_socket, net_writeBuffer, count, &wrote);
|
||||||
if (result != 0 || modified == 0) { net_writeFailed = true; break; }
|
if (result || !wrote) { net_writeFailed = true; break; }
|
||||||
count -= modified;
|
count -= wrote;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user