Try to fix resampler to be thread-safe.

This commit is contained in:
BearOso 2023-06-27 15:33:52 -05:00
parent 376e6de81c
commit c13e4d8330
2 changed files with 31 additions and 27 deletions

View File

@ -9,19 +9,15 @@
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#if __cplusplus >= 201103L
#include <cstdint> #include <cstdint>
#else
#include <stdint.h>
#endif
#include <cmath> #include <cmath>
class Resampler class Resampler
{ {
public: public:
int size; volatile int end;
int buffer_size; int buffer_size;
int start; volatile int start;
int16_t *buffer; int16_t *buffer;
float r_step; float r_step;
@ -87,7 +83,7 @@ class Resampler
return; return;
start = 0; start = 0;
size = 0; end = 0;
memset(buffer, 0, buffer_size * 2); memset(buffer, 0, buffer_size * 2);
r_frac = 0.0; r_frac = 0.0;
@ -100,13 +96,14 @@ class Resampler
if (space_filled() < num_samples) if (space_filled() < num_samples)
return false; return false;
memcpy(dst, buffer + start, min(num_samples, buffer_size - start) * 2); int first_block_size = buffer_size - start;
if (num_samples > (buffer_size - start)) memcpy(dst, buffer + start, min(num_samples, first_block_size) * 2);
memcpy(dst + (buffer_size - start), buffer, (num_samples - (buffer_size - start)) * 2);
if (num_samples > first_block_size)
memcpy(dst + first_block_size, buffer, (num_samples - first_block_size) * 2);
start = (start + num_samples) % buffer_size; start = (start + num_samples) % buffer_size;
size -= num_samples;
return true; return true;
} }
@ -115,12 +112,9 @@ class Resampler
{ {
if (space_empty() >= 2) if (space_empty() >= 2)
{ {
int end = start + size;
if (end >= buffer_size)
end -= buffer_size;
buffer[end] = l; buffer[end] = l;
buffer[end + 1] = r; buffer[end + 1] = r;
size += 2; end = (end + 2) % buffer_size;
} }
} }
@ -129,17 +123,14 @@ class Resampler
if (space_empty() < num_samples) if (space_empty() < num_samples)
return false; return false;
int end = start + size; int first_block_size = min(num_samples, buffer_size - end);
if (end > buffer_size)
end -= buffer_size;
int first_write_size = min(num_samples, buffer_size - end);
memcpy(buffer + end, src, first_write_size * 2); memcpy(buffer + end, src, first_block_size * 2);
if (num_samples > first_write_size) if (num_samples > first_block_size)
memcpy(buffer, src + first_write_size, (num_samples - first_write_size) * 2); memcpy(buffer, src + first_block_size, (num_samples - first_block_size) * 2);
size += num_samples; end = (end + num_samples) % buffer_size;
return true; return true;
} }
@ -156,7 +147,7 @@ class Resampler
assert((num_samples & 1) == 0); // resampler always processes both stereo samples assert((num_samples & 1) == 0); // resampler always processes both stereo samples
int o_position = 0; int o_position = 0;
while (o_position < num_samples && size > 0) while (o_position < num_samples && space_filled() >= 2)
{ {
int s_left = buffer[start]; int s_left = buffer[start];
int s_right = buffer[start + 1]; int s_right = buffer[start + 1];
@ -191,23 +182,26 @@ class Resampler
start += 2; start += 2;
if (start >= buffer_size) if (start >= buffer_size)
start -= buffer_size; start -= buffer_size;
size -= 2;
} }
} }
} }
inline int space_empty(void) const inline int space_empty(void) const
{ {
return buffer_size - size; return buffer_size - 2 - space_filled();
} }
inline int space_filled(void) const inline int space_filled(void) const
{ {
int size = end - start;
if (size < 0)
size += buffer_size;
return size; return size;
} }
inline int avail(void) inline int avail(void)
{ {
int size = space_filled();
//If we are outputting the exact same ratio as the input, find out directly from the input buffer //If we are outputting the exact same ratio as the input, find out directly from the input buffer
if (r_step == 1.0) if (r_step == 1.0)
return size; return size;

View File

@ -71,7 +71,17 @@ long data_callback(cubeb_stream *stream, void *user_ptr,
long S9xCubebSoundDriver::data_callback(cubeb_stream *stream, void const *input_buffer, void *output_buffer, long nframes) long S9xCubebSoundDriver::data_callback(cubeb_stream *stream, void const *input_buffer, void *output_buffer, long nframes)
{ {
buffer.read((int16_t *)output_buffer, nframes * 2); auto avail = buffer.avail();
if (avail < nframes * 2)
{
auto zeroed_samples = nframes * 2 - avail;
memset(output_buffer, 0, zeroed_samples);
buffer.read((int16_t *)output_buffer + zeroed_samples, nframes * 2 - zeroed_samples);
}
else
{
buffer.read((int16_t *)output_buffer, nframes * 2);
}
return nframes; return nframes;
} }