mirror of https://github.com/bjornbytes/lovr.git
Fix mixer bug; Refactor mixer;
- Sources without converters always read into the beginning of the raw buffer, overwriting previous frames if the source was rewound due to looping. This resulted in an audible click whenever the source was rewound. - After looping, Sources without converters would try to read too many frames -- they would read a full buffer instead of only the necessary number of frames.
This commit is contained in:
parent
69b5c51388
commit
4469fc99e8
|
@ -92,7 +92,7 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
|
||||||
|
|
||||||
do {
|
do {
|
||||||
float* dst = count >= BUFFER_SIZE ? output : state.leftovers;
|
float* dst = count >= BUFFER_SIZE ? output : state.leftovers;
|
||||||
float* src = NULL; // The "current" buffer (used for fast paths)
|
float* buf = NULL; // The "current" buffer (used for fast paths)
|
||||||
|
|
||||||
if (dst == state.leftovers) {
|
if (dst == state.leftovers) {
|
||||||
memset(dst, 0, sizeof(state.leftovers));
|
memset(dst, 0, sizeof(state.leftovers));
|
||||||
|
@ -110,16 +110,25 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and convert raw frames until there's BUFFER_SIZE converted frames
|
// Read and convert raw frames until there's BUFFER_SIZE converted frames
|
||||||
uint32_t channels = lovrSourceUsesSpatializer(source) ? 1 : 2; // If spatializer isn't converting to stereo, converter must do it
|
// - No converter: just read frames into raw (it has enough space for BUFFER_SIZE frames).
|
||||||
uint64_t frameLimit = sizeof(raw) / lovrSoundGetChannelCount(source->sound) / sizeof(float);
|
// - Converter: keep reading as many frames as possible/needed into raw and convert into aux.
|
||||||
uint32_t framesToConvert = BUFFER_SIZE;
|
// - If EOF is reached, rewind and continue for looping sources, otherwise pad end with zero.
|
||||||
uint32_t framesConverted = 0;
|
buf = source->converter ? aux : raw;
|
||||||
while (framesToConvert > 0) {
|
float* cursor = buf; // Edge of processed frames
|
||||||
src = raw;
|
uint32_t channelsOut = lovrSourceUsesSpatializer(source) ? 1 : 2; // If spatializer isn't converting to stereo, converter must do it
|
||||||
uint64_t framesToRead = source->converter ? MIN(ma_data_converter_get_required_input_frame_count(source->converter, framesToConvert), frameLimit) : framesToConvert;
|
uint32_t framesRemaining = BUFFER_SIZE;
|
||||||
uint64_t framesRead = lovrSoundRead(source->sound, source->offset, framesToRead, src);
|
uint32_t framesProcessed = 0;
|
||||||
ma_uint64 framesIn = framesRead;
|
while (framesRemaining > 0) {
|
||||||
ma_uint64 framesOut = framesToConvert;
|
uint32_t framesRead;
|
||||||
|
|
||||||
|
if (source->converter) {
|
||||||
|
uint32_t channelsIn = lovrSoundGetChannelCount(source->sound);
|
||||||
|
uint32_t capacity = sizeof(raw) / (channelsIn * sizeof(float));
|
||||||
|
uint32_t chunk = MIN(ma_data_converter_get_required_input_frame_count(source->converter, framesRemaining), capacity);
|
||||||
|
framesRead = lovrSoundRead(source->sound, source->offset, chunk, raw);
|
||||||
|
} else {
|
||||||
|
framesRead = lovrSoundRead(source->sound, source->offset, framesRemaining, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
if (framesRead == 0) {
|
if (framesRead == 0) {
|
||||||
if (source->looping) {
|
if (source->looping) {
|
||||||
|
@ -128,32 +137,37 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
|
||||||
} else {
|
} else {
|
||||||
source->offset = 0;
|
source->offset = 0;
|
||||||
source->playing = false;
|
source->playing = false;
|
||||||
src = source->converter ? aux : raw;
|
memset(cursor, 0, framesRemaining * channelsOut * sizeof(float));
|
||||||
memset(src + framesConverted * channels, 0, framesToConvert * channels * sizeof(float));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
source->offset += framesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source->converter) {
|
if (source->converter) {
|
||||||
ma_data_converter_process_pcm_frames(source->converter, src, &framesIn, aux + framesConverted * channels, &framesOut);
|
ma_uint64 framesIn = framesRead;
|
||||||
src = aux;
|
ma_uint64 framesOut = framesRemaining;
|
||||||
|
ma_data_converter_process_pcm_frames(source->converter, raw, &framesIn, cursor, &framesOut);
|
||||||
|
cursor += framesOut * channelsOut;
|
||||||
|
framesProcessed += framesOut;
|
||||||
|
framesRemaining -= framesOut;
|
||||||
|
} else {
|
||||||
|
cursor += framesRead * channelsOut;
|
||||||
|
framesProcessed += framesRead;
|
||||||
|
framesRemaining -= framesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
framesToConvert -= framesOut;
|
|
||||||
framesConverted += framesOut;
|
|
||||||
source->offset += framesRead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spatialize
|
// Spatialize
|
||||||
if (lovrSourceUsesSpatializer(source)) {
|
if (lovrSourceUsesSpatializer(source)) {
|
||||||
state.spatializer->apply(source, src, mix, BUFFER_SIZE, BUFFER_SIZE);
|
state.spatializer->apply(source, buf, mix, BUFFER_SIZE, BUFFER_SIZE);
|
||||||
src = mix;
|
buf = mix;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mix
|
// Mix
|
||||||
float volume = source->volume;
|
float volume = source->volume;
|
||||||
for (uint32_t i = 0; i < OUTPUT_CHANNELS * BUFFER_SIZE; i++) {
|
for (uint32_t i = 0; i < OUTPUT_CHANNELS * BUFFER_SIZE; i++) {
|
||||||
dst[i] += src[i] * volume;
|
dst[i] += buf[i] * volume;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue