mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-15 02:25:32 -04:00
Audio: Now pass chunks in QueueChunk too
This commit is contained in:
parent
e7a0619e47
commit
6dcc9ec7e3
13
src/Audio.c
13
src/Audio.c
@ -183,8 +183,7 @@ static void Sounds_Play(cc_uint8 type, struct Soundboard* board) {
|
||||
snd = Soundboard_PickRandom(board, type);
|
||||
if (!snd) return;
|
||||
|
||||
data.data = snd->chunk.data;
|
||||
data.size = snd->chunk.size;
|
||||
data.chunk = snd->chunk;
|
||||
data.channels = snd->channels;
|
||||
data.sampleRate = snd->sampleRate;
|
||||
data.rate = 100;
|
||||
@ -331,10 +330,11 @@ static void* music_waitable;
|
||||
static volatile cc_bool music_stopping, music_joining;
|
||||
static int music_minDelay, music_maxDelay;
|
||||
|
||||
static cc_result Music_Buffer(cc_int16* data, int maxSamples, struct VorbisState* ctx) {
|
||||
static cc_result Music_Buffer(struct AudioChunk* chunk, int maxSamples, struct VorbisState* ctx) {
|
||||
int samples = 0;
|
||||
cc_int16* cur;
|
||||
cc_result res = 0, res2;
|
||||
cc_int16* data = chunk->data;
|
||||
|
||||
while (samples < maxSamples) {
|
||||
if ((res = Vorbis_DecodeFrame(ctx))) break;
|
||||
@ -343,7 +343,8 @@ static cc_result Music_Buffer(cc_int16* data, int maxSamples, struct VorbisState
|
||||
samples += Vorbis_OutputFrame(ctx, cur);
|
||||
}
|
||||
|
||||
res2 = Audio_QueueChunk(&music_ctx, data, samples * 2);
|
||||
chunk->size = samples * 2;
|
||||
res2 = Audio_QueueChunk(&music_ctx, chunk);
|
||||
if (res2) { music_stopping = true; return res2; }
|
||||
return res;
|
||||
}
|
||||
@ -379,7 +380,7 @@ static cc_result Music_PlayOgg(struct Stream* source) {
|
||||
/* fill up with some samples before playing */
|
||||
for (i = 0; i < AUDIO_MAX_BUFFERS && !res; i++)
|
||||
{
|
||||
res = Music_Buffer((cc_int16*)chunks[i].data, samplesPerSecond, &vorbis);
|
||||
res = Music_Buffer(&chunks[i], samplesPerSecond, &vorbis);
|
||||
}
|
||||
if (music_stopping) goto cleanup;
|
||||
|
||||
@ -411,7 +412,7 @@ static cc_result Music_PlayOgg(struct Stream* source) {
|
||||
Thread_Sleep(10); continue;
|
||||
}
|
||||
|
||||
res = Music_Buffer((cc_int16*)chunks[cur].data, samplesPerSecond, &vorbis);
|
||||
res = Music_Buffer(&chunks[cur], samplesPerSecond, &vorbis);
|
||||
cur = (cur + 1) % AUDIO_MAX_BUFFERS;
|
||||
|
||||
/* need to specially handle last bit of audio */
|
||||
|
20
src/Audio.h
20
src/Audio.h
@ -20,8 +20,15 @@ struct AudioContext;
|
||||
#define DEFAULT_MUSIC_VOLUME 100
|
||||
#endif
|
||||
|
||||
union AudioChunkMeta { void* ptr; cc_uintptr val; };
|
||||
struct AudioChunk {
|
||||
void* data; /* the raw 16 bit integer samples */
|
||||
cc_uint32 size;
|
||||
union AudioChunkMeta meta;
|
||||
};
|
||||
|
||||
struct AudioData {
|
||||
void* data; cc_uint32 size; /* the raw 16 bit integer samples */
|
||||
struct AudioChunk chunk;
|
||||
int channels;
|
||||
int sampleRate; /* frequency / sample rate */
|
||||
int volume; /* volume data played at (100 = normal volume) */
|
||||
@ -47,13 +54,6 @@ cc_bool AudioBackend_Init(void);
|
||||
void AudioBackend_Tick(void);
|
||||
void AudioBackend_Free(void);
|
||||
|
||||
union AudioChunkMeta { void* ptr; cc_uintptr val; };
|
||||
struct AudioChunk {
|
||||
void* data;
|
||||
cc_uint32 size;
|
||||
union AudioChunkMeta meta;
|
||||
};
|
||||
|
||||
/* Initialises an audio context. */
|
||||
cc_result Audio_Init(struct AudioContext* ctx, int buffers);
|
||||
/* Stops any playing audio and then frees the audio context. */
|
||||
@ -65,8 +65,8 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate
|
||||
void Audio_SetVolume(struct AudioContext* ctx, int volume);
|
||||
/* Queues the given audio chunk for playing. */
|
||||
/* NOTE: You MUST ensure Audio_Poll indicates a buffer is free before calling this. */
|
||||
/* NOTE: Some backends directly read from the data - therefore you MUST NOT modify it */
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size);
|
||||
/* NOTE: Some backends directly read from the chunk data - therefore you MUST NOT modify it */
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk);
|
||||
/* Begins playing audio. Audio_QueueChunk must have been used before this. */
|
||||
cc_result Audio_Play(struct AudioContext* ctx);
|
||||
/* Polls the audio context and then potentially unqueues buffer */
|
||||
|
@ -15,7 +15,7 @@ static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data);
|
||||
|
||||
/* Common/Base methods */
|
||||
static void AudioBase_Clear(struct AudioContext* ctx);
|
||||
static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, int i, void** data, cc_uint32* size);
|
||||
static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, int i, struct AudioChunk* chunk);
|
||||
static cc_result AudioBase_AllocChunks(int size, struct AudioChunk* chunks, int numChunks);
|
||||
static void AudioBase_FreeChunks(struct AudioChunk* chunks, int numChunks);
|
||||
|
||||
@ -226,7 +226,7 @@ void Audio_SetVolume(struct AudioContext* ctx, int volume) {
|
||||
_alGetError(); /* Reset error state */
|
||||
}
|
||||
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) {
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
|
||||
ALuint buffer;
|
||||
ALenum err;
|
||||
|
||||
@ -234,7 +234,7 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size
|
||||
buffer = ctx->freeIDs[--ctx->free];
|
||||
_alGetError(); /* Reset error state */
|
||||
|
||||
_alBufferData(buffer, ctx->format, chunk, size, ctx->sampleRate);
|
||||
_alBufferData(buffer, ctx->format, chunk->data, chunk->size, ctx->sampleRate);
|
||||
if ((err = _alGetError())) return err;
|
||||
_alSourceQueueBuffers(ctx->source, 1, &buffer);
|
||||
if ((err = _alGetError())) return err;
|
||||
@ -433,22 +433,23 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate
|
||||
|
||||
void Audio_SetVolume(struct AudioContext* ctx, int volume) { ctx->volume = volume; }
|
||||
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) {
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
|
||||
cc_result res;
|
||||
WAVEHDR* hdr;
|
||||
cc_bool ok;
|
||||
int i;
|
||||
struct AudioChunk tmp = *chunk;
|
||||
|
||||
for (i = 0; i < ctx->count; i++) {
|
||||
hdr = &ctx->headers[i];
|
||||
if (!(hdr->dwFlags & WHDR_DONE)) continue;
|
||||
|
||||
ok = AudioBase_AdjustSound(ctx, i, &chunk, &dataSize);
|
||||
ok = AudioBase_AdjustSound(ctx, i, &tmp);
|
||||
if (!ok) return ERR_OUT_OF_MEMORY;
|
||||
|
||||
Mem_Set(hdr, 0, sizeof(WAVEHDR));
|
||||
hdr->lpData = (LPSTR)chunk;
|
||||
hdr->dwBufferLength = dataSize;
|
||||
hdr->lpData = (LPSTR)tmp.data;
|
||||
hdr->dwBufferLength = tmp.size;
|
||||
hdr->dwLoops = 1;
|
||||
|
||||
if ((res = waveOutPrepareHeader(ctx->handle, hdr, sizeof(WAVEHDR)))) return res;
|
||||
@ -703,8 +704,8 @@ void Audio_SetVolume(struct AudioContext* ctx, int volume) {
|
||||
UpdateVolume(ctx);
|
||||
}
|
||||
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) {
|
||||
return (*ctx->playerQueue)->Enqueue(ctx->playerQueue, chunk, size);
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
|
||||
return (*ctx->playerQueue)->Enqueue(ctx->playerQueue, chunk->data, chunk->size);
|
||||
}
|
||||
|
||||
cc_result Audio_Pause(struct AudioContext* ctx) {
|
||||
@ -845,15 +846,15 @@ void Audio_SetVolume(struct AudioContext* ctx, int volume) {
|
||||
ndspChnSetMix(ctx->chanID, mix);
|
||||
}
|
||||
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) {
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
|
||||
ndspWaveBuf* buf;
|
||||
|
||||
// DSP audio buffers must be aligned to a multiple of 0x80, according to the example code I could find.
|
||||
if (((uintptr_t)chunk & 0x7F) != 0) {
|
||||
Platform_Log1("Audio_QueueData: tried to queue buffer with non-aligned audio buffer 0x%x\n", &chunk);
|
||||
if (((uintptr_t)chunk->data & 0x7F) != 0) {
|
||||
Platform_Log1("Audio_QueueData: tried to queue buffer with non-aligned audio buffer 0x%x\n", &chunk>data);
|
||||
}
|
||||
if ((dataSize & 0x7F) != 0) {
|
||||
Platform_Log1("Audio_QueueData: unaligned audio data size 0x%x\n", &dataSize);
|
||||
if ((chunk->size & 0x7F) != 0) {
|
||||
Platform_Log1("Audio_QueueData: unaligned audio data size 0x%x\n", &chunk->size);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ctx->count; i++)
|
||||
@ -862,9 +863,9 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data
|
||||
if (buf->status == NDSP_WBUF_QUEUED || buf->status == NDSP_WBUF_PLAYING)
|
||||
continue;
|
||||
|
||||
buf->data_pcm16 = chunk;
|
||||
buf->nsamples = dataSize / (sizeof(cc_int16) * (ctx->stereo ? 2 : 1));
|
||||
DSP_FlushDataCache(buf->data_pcm16, dataSize);
|
||||
buf->data_pcm16 = chunk>data;
|
||||
buf->nsamples = chunk->size / (sizeof(cc_int16) * (ctx->stereo ? 2 : 1));
|
||||
DSP_FlushDataCache(buf->data_pcm16, chunk->size);
|
||||
ndspChnWaveBufAdd(ctx->chanID, buf);
|
||||
return 0;
|
||||
}
|
||||
@ -1030,15 +1031,15 @@ void Audio_SetVolume(struct AudioContext* ctx, int volume) {
|
||||
audrvVoiceSetVolume(&drv, ctx->chanID, volume / 100.0f);
|
||||
}
|
||||
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) {
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
|
||||
AudioDriverWaveBuf* buf;
|
||||
|
||||
// Audio buffers must be aligned to a multiple of 0x1000, according to libnx example code
|
||||
if (((uintptr_t)chunk & 0xFFF) != 0) {
|
||||
Platform_Log1("Audio_QueueData: tried to queue buffer with non-aligned audio buffer 0x%x\n", &chunk);
|
||||
if (((uintptr_t)chunk->data & 0xFFF) != 0) {
|
||||
Platform_Log1("Audio_QueueData: tried to queue buffer with non-aligned audio buffer 0x%x\n", &chunk->data);
|
||||
}
|
||||
if ((dataSize & 0xFFF) != 0) {
|
||||
Platform_Log1("Audio_QueueData: unaligned audio data size 0x%x\n", &dataSize);
|
||||
if ((chunk->size & 0xFFF) != 0) {
|
||||
Platform_Log1("Audio_QueueData: unaligned audio data size 0x%x\n", &chunk->size);
|
||||
}
|
||||
|
||||
|
||||
@ -1046,14 +1047,13 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data
|
||||
{
|
||||
buf = &ctx->bufs[i];
|
||||
int state = buf->state;
|
||||
cc_uint32 size = dataSize;
|
||||
cc_uint32 endOffset = dataSize / (sizeof(cc_int16) * ((ctx->channels == 2) ? 2 : 1));
|
||||
cc_uint32 endOffset = chunk->size / (sizeof(cc_int16) * ((ctx->channels == 2) ? 2 : 1));
|
||||
|
||||
if (state == AudioDriverWaveBufState_Queued || state == AudioDriverWaveBufState_Playing || state == AudioDriverWaveBufState_Waiting)
|
||||
continue;
|
||||
|
||||
buf->data_pcm16 = chunk;
|
||||
buf->size = size;
|
||||
buf->data_pcm16 = chunk->data;
|
||||
buf->size = chunk->size;
|
||||
buf->start_sample_offset = 0;
|
||||
buf->end_sample_offset = endOffset;
|
||||
|
||||
@ -1218,10 +1218,10 @@ void Audio_SetVolume(struct AudioContext* ctx, int volume) {
|
||||
ctx->volume = (volume / 100.0f) * 255;
|
||||
}
|
||||
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) {
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
|
||||
// Audio buffers must be aligned and padded to a multiple of 32 bytes
|
||||
if (((uintptr_t)chunk & 0x1F) != 0) {
|
||||
Platform_Log1("Audio_QueueData: tried to queue buffer with non-aligned audio buffer 0x%x\n", &chunk);
|
||||
if (((uintptr_t)chunk->data & 0x1F) != 0) {
|
||||
Platform_Log1("Audio_QueueData: tried to queue buffer with non-aligned audio buffer 0x%x\n", &chunk->data);
|
||||
}
|
||||
|
||||
struct AudioBuffer* buf;
|
||||
@ -1231,8 +1231,8 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data
|
||||
buf = &ctx->bufs[i];
|
||||
if (!buf->available) continue;
|
||||
|
||||
buf->samples = chunk;
|
||||
buf->size = dataSize;
|
||||
buf->samples = chunk->data;
|
||||
buf->size = chunk->size;
|
||||
buf->available = false;
|
||||
|
||||
return 0;
|
||||
@ -1385,7 +1385,7 @@ void Audio_SetVolume(struct AudioContext* ctx, int volume) {
|
||||
snd_stream_volume(ctx->hnd, volume);
|
||||
}
|
||||
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) {
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
|
||||
struct AudioBuffer* buf;
|
||||
|
||||
for (int i = 0; i < ctx->count; i++)
|
||||
@ -1393,8 +1393,8 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data
|
||||
buf = &ctx->bufs[i];
|
||||
if (!buf->available) continue;
|
||||
|
||||
buf->samples = chunk;
|
||||
buf->bytesLeft = dataSize;
|
||||
buf->samples = chunk->data;
|
||||
buf->bytesLeft = chunk->size;
|
||||
buf->available = false;
|
||||
return 0;
|
||||
}
|
||||
@ -1492,8 +1492,8 @@ void Audio_SetVolume(struct AudioContext* ctx, int volume) {
|
||||
interop_AudioVolume(ctx->contextID, volume);
|
||||
}
|
||||
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) {
|
||||
ctx->data = chunk; return 0;
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
|
||||
ctx->data = chunk->data; return 0;
|
||||
}
|
||||
|
||||
cc_result Audio_Play(struct AudioContext* ctx) {
|
||||
@ -1546,7 +1546,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate
|
||||
|
||||
void Audio_SetVolume(struct AudioContext* ctx, int volume) { }
|
||||
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) {
|
||||
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@ -1609,9 +1609,9 @@ static void AudioBase_Clear(struct AudioContext* ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, int i, void** data, cc_uint32* size) {
|
||||
static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, int i, struct AudioChunk* chunk) {
|
||||
void* audio;
|
||||
cc_uint32 src_size = *size;
|
||||
cc_uint32 src_size = chunk->size;
|
||||
if (ctx->volume >= 100) return true;
|
||||
|
||||
/* copy to temp buffer to apply volume */
|
||||
@ -1623,17 +1623,16 @@ static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, int i, void** dat
|
||||
audio = Mem_TryAlloc(src_size, 1);
|
||||
}
|
||||
|
||||
if (!data) return false;
|
||||
if (!audio) return false;
|
||||
ctx->_tmpData[i] = audio;
|
||||
ctx->_tmpSize[i] = src_size;
|
||||
}
|
||||
|
||||
audio = ctx->_tmpData[i];
|
||||
Mem_Copy(audio, *data, src_size);
|
||||
Mem_Copy(audio, chunk->data, src_size);
|
||||
ApplyVolume((cc_int16*)audio, src_size / 2, ctx->volume);
|
||||
|
||||
*data = audio;
|
||||
*size = src_size;
|
||||
chunk->data = audio;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@ -1671,7 +1670,7 @@ static cc_result PlayAudio(struct AudioContext* ctx, struct AudioData* data) {
|
||||
Audio_SetVolume(ctx, data->volume);
|
||||
|
||||
if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate, data->rate))) return res;
|
||||
if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res;
|
||||
if ((res = Audio_QueueChunk(ctx, &data->chunk))) return res;
|
||||
if ((res = Audio_Play(ctx))) return res;
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user