Skip to content

Commit f0ac812

Browse files
committed
Allow circular buffer to report disjoint buffer
This allows to avoid memmove after each consume_cbuff_data. Some extra care was necessary to round queue transactions to a multiple of the sample size. I also did some refactoring on the cbuff to allow it to grow and on the resamplers to allw them to report not only how many bytes were consumed, but also how many bytes were produced, so we can move cbuff pointers accordingly. tail/head methods reports the available sizes in 2 parameters : "available" for the first chunk size, and "extra" for the optional second chunk (which starts at the buffer beginning). It's up to the caller to split it's contiguous accesses around these two chunks. Another method that I initially wanted to try was the virtual memory trick to mirror the beggining of the buffer at the end of itself. But this trick requires some code specific platform and can be tricky when we need to grow the buffer. So I went this explicit 2 chunk approach which is simpler and doesn't require platform specific code.
1 parent af6af5b commit f0ac812

File tree

9 files changed

+163
-90
lines changed

9 files changed

+163
-90
lines changed

src/circular_buffer.c

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,36 +48,83 @@ void release_cbuff(struct circular_buffer* cbuff)
4848
memset(cbuff, 0, sizeof(*cbuff));
4949
}
5050

51+
void grow_cbuff(struct circular_buffer* cbuff, size_t new_size)
52+
{
53+
if (new_size >= cbuff->size) {
54+
55+
cbuff->data = realloc(cbuff->data, new_size);
56+
57+
size_t delta = new_size - cbuff->size;
58+
size_t delta_max = (cbuff->head >= cbuff->tail) ? cbuff->tail : cbuff->head;
5159

52-
void* cbuff_head(const struct circular_buffer* cbuff, size_t* available)
60+
if (delta_max <= delta) {
61+
memcpy((unsigned char*)cbuff->data + cbuff->size, cbuff->data, delta_max);
62+
memset((unsigned char*)cbuff->data + cbuff->size + delta_max, 0, delta - delta_max);
63+
}
64+
else {
65+
memcpy((unsigned char*)cbuff->data + cbuff->size, cbuff->data, delta);
66+
memmove(cbuff->data, (const unsigned char*)cbuff->data + delta, delta_max - delta);
67+
}
68+
69+
cbuff->size = new_size;
70+
}
71+
}
72+
73+
74+
void* cbuff_head(const struct circular_buffer* cbuff, size_t* available, size_t* extra)
5375
{
5476
assert(cbuff->head <= cbuff->size);
77+
assert(cbuff->tail <= cbuff->size);
78+
79+
if (cbuff->head >= cbuff->tail) {
80+
*available = cbuff->size - cbuff->head;
81+
*extra = cbuff->tail;
82+
}
83+
else {
84+
*available = cbuff->tail - cbuff->head;
85+
*extra = 0;
86+
}
5587

56-
*available = cbuff->size - cbuff->head;
5788
return (unsigned char*)cbuff->data + cbuff->head;
5889
}
5990

6091

61-
void* cbuff_tail(const struct circular_buffer* cbuff, size_t* available)
92+
void* cbuff_tail(const struct circular_buffer* cbuff, size_t* available, size_t* extra)
6293
{
63-
*available = cbuff->head;
64-
return cbuff->data;
94+
assert(cbuff->head <= cbuff->size);
95+
assert(cbuff->tail <= cbuff->size);
96+
97+
if (cbuff->head >= cbuff->tail) {
98+
*available = cbuff->head - cbuff->tail;
99+
*extra = 0;
100+
}
101+
else {
102+
*available = cbuff->size - cbuff->tail;
103+
*extra = cbuff->head;
104+
}
105+
106+
return (unsigned char*)cbuff->data + cbuff->tail;
65107
}
66108

67109

68110
void produce_cbuff_data(struct circular_buffer* cbuff, size_t amount)
69111
{
70-
assert(cbuff->head + amount <= cbuff->size);
112+
//assert((cbuff->head + amount) % cbuff->size <= cbuff->tail);
71113

72114
cbuff->head += amount;
115+
if (cbuff->head > cbuff->size) {
116+
cbuff->head -= cbuff->size;
117+
}
73118
}
74119

75120

76121
void consume_cbuff_data(struct circular_buffer* cbuff, size_t amount)
77122
{
78-
assert(cbuff->head >= amount);
123+
//assert((cbuff->tail + amount) % cbuff->size <= cbuff->tail);
79124

80-
memmove(cbuff->data, (unsigned char*)cbuff->data + amount, cbuff->head - amount);
81-
cbuff->head -= amount;
125+
cbuff->tail += amount;
126+
if (cbuff->tail > cbuff->size) {
127+
cbuff->tail -= cbuff->size;
128+
}
82129
}
83130

src/circular_buffer.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,18 @@ struct circular_buffer
2929
void* data;
3030
size_t size;
3131
size_t head;
32+
size_t tail;
3233
};
3334

3435
int init_cbuff(struct circular_buffer* cbuff, size_t capacity);
3536

3637
void release_cbuff(struct circular_buffer* cbuff);
3738

38-
void* cbuff_head(const struct circular_buffer* cbuff, size_t* available);
39+
void grow_cbuff(struct circular_buffer* cbuff, size_t new_size);
3940

40-
void* cbuff_tail(const struct circular_buffer* cbuff, size_t* available);
41+
void* cbuff_head(const struct circular_buffer* cbuff, size_t* available, size_t* extra);
42+
43+
void* cbuff_tail(const struct circular_buffer* cbuff, size_t* available, size_t* extra);
4144

4245
void produce_cbuff_data(struct circular_buffer* cbuff, size_t amount);
4346

src/main.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -381,27 +381,23 @@ EXPORT void CALL SetSpeedFactor(int percentage)
381381
sdl_set_speed_factor(l_sdl_backend, percentage);
382382
}
383383

384-
size_t ResampleAndMix(void* resampler, const struct resampler_interface* iresampler,
385-
void* mix_buffer,
386-
const void* src, size_t src_size, unsigned int src_freq,
387-
void* dst, size_t dst_size, unsigned int dst_freq)
384+
void ResampleAndMix(void* resampler, const struct resampler_interface* iresampler,
385+
void* mix_buffer,
386+
const void* src, size_t src_size, unsigned int src_freq, size_t* consumed,
387+
void* dst, size_t dst_size, unsigned int dst_freq, size_t* produced)
388388
{
389-
size_t consumed;
390-
391389
#if defined(HAS_OSS_SUPPORT)
392390
if (VolumeControlType == VOLUME_TYPE_OSS)
393391
{
394-
consumed = iresampler->resample(resampler, src, src_size, src_freq, dst, dst_size, dst_freq);
392+
iresampler->resample(resampler, src, src_size, src_freq, consumed, dst, dst_size, dst_freq, produced);
395393
}
396394
else
397395
#endif
398396
{
399-
consumed = iresampler->resample(resampler, src, src_size, src_freq, mix_buffer, dst_size, dst_freq);
397+
iresampler->resample(resampler, src, src_size, src_freq, consumed, mix_buffer, dst_size, dst_freq, produced);
400398
memset(dst, 0, dst_size);
401399
SDL_MixAudio(dst, mix_buffer, dst_size, VolSDL);
402400
}
403-
404-
return consumed;
405401
}
406402

407403
void SetPlaybackVolume(void)

src/main.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ enum {
4040

4141
void SetPlaybackVolume(void);
4242

43-
size_t ResampleAndMix(void* resampler, const struct resampler_interface* iresampler,
44-
void* mix_buffer,
45-
const void* src, size_t src_size, unsigned int src_freq,
46-
void* dst, size_t dst_size, unsigned int dst_freq);
43+
void ResampleAndMix(void* resampler, const struct resampler_interface* iresampler,
44+
void* mix_buffer,
45+
const void* src, size_t src_size, unsigned int src_freq, size_t* consumed,
46+
void* dst, size_t dst_size, unsigned int dst_freq, size_t* produced);
4747

4848
/* declarations of pointers to Core config functions */
4949
extern ptr_ConfigListSections ConfigListSections;

src/resamplers/resamplers.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ struct resampler_interface
3232

3333
void (*release)(void* resampler);
3434

35-
size_t (*resample)(void* resampler,
36-
const void* src, size_t src_size, unsigned int src_freq,
37-
void* dst, size_t dst_size, unsigned int dst_freq);
35+
void (*resample)(void* resampler,
36+
const void* src, size_t src_size, unsigned int src_freq, size_t* consumed,
37+
void* dst, size_t dst_size, unsigned int dst_freq, size_t* produced);
3838
};
3939

4040
const struct resampler_interface* get_iresampler(const char* resampler_id, void** resampler);

src/resamplers/speex.c

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ static void speex_release(void* resampler)
9393
speex_resampler_destroy(spx_state);
9494
}
9595

96-
static size_t speex_resample(void* resampler,
97-
const void* src, size_t src_size, unsigned int src_freq,
98-
void* dst, size_t dst_size, unsigned int dst_freq)
96+
static void speex_resample(void* resampler,
97+
const void* src, size_t src_size, unsigned int src_freq, size_t* consumed,
98+
void* dst, size_t dst_size, unsigned int dst_freq, size_t* produced)
9999
{
100100
SpeexResamplerState* spx_state = (SpeexResamplerState*)resampler;
101101

@@ -111,17 +111,14 @@ static size_t speex_resample(void* resampler,
111111
if (error != RESAMPLER_ERR_SUCCESS)
112112
{
113113
DebugMessage(M64MSG_ERROR, "Speex error: %s", speex_resampler_strerror(error));
114+
*consumed = src_size;
115+
*produced = dst_size;
114116
memset(dst, 0, dst_size);
115-
return src_size;
116-
}
117-
118-
if (dst_size != out_len * BYTES_PER_SAMPLE) {
119-
DebugMessage(M64MSG_WARNING, "dst_size = %u != outlen*4 = %u",
120-
(uint32_t) dst_size, out_len * BYTES_PER_SAMPLE);
117+
return;
121118
}
122-
memset((char*)dst + out_len * BYTES_PER_SAMPLE, 0, dst_size - out_len * BYTES_PER_SAMPLE);
123119

124-
return in_len * BYTES_PER_SAMPLE;
120+
*consumed = in_len * BYTES_PER_SAMPLE;
121+
*produced = out_len * BYTES_PER_SAMPLE;
125122
}
126123

127124

src/resamplers/src.c

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,9 @@ static void src_release(void* resampler)
133133
}
134134
}
135135

136-
static size_t src_resample(void* resampler,
137-
const void* src, size_t src_size, unsigned int src_freq,
138-
void* dst, size_t dst_size, unsigned int dst_freq)
136+
static void src_resample(void* resampler,
137+
const void* src, size_t src_size, unsigned int src_freq, size_t* consumed,
138+
void* dst, size_t dst_size, unsigned int dst_freq, size_t* produced)
139139
{
140140
struct src_resampler* src_resampler = (struct src_resampler*)resampler;
141141

@@ -176,19 +176,16 @@ static size_t src_resample(void* resampler,
176176
if (error)
177177
{
178178
DebugMessage(M64MSG_ERROR, "SRC error: %s", src_strerror(error));
179+
*consumed = src_size;
180+
*produced = dst_size;
179181
memset(dst, 0, dst_size);
180-
return src_size;
181-
}
182-
183-
if (dst_size != src_data.output_frames_gen*4) {
184-
DebugMessage(M64MSG_WARNING, "dst_size = %u != output_frames_gen*4 = %u",
185-
(uint32_t) dst_size, (uint32_t) src_data.output_frames_gen*4);
182+
return;
186183
}
187184

188185
src_float_to_short_array(src_resampler->fbuffers[1].data, (short*)dst, src_data.output_frames_gen*2);
189-
memset((char*)dst + src_data.output_frames_gen*4, 0, dst_size - src_data.output_frames_gen*4);
190186

191-
return src_data.input_frames_used * 4;
187+
*consumed = src_data.input_frames_used * 4;
188+
*produced = src_data.output_frames_gen * 4;
192189
}
193190

194191

src/resamplers/trivial.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ static void trivial_release(void* resampler)
3535
/* nothing to do */
3636
}
3737

38-
static size_t trivial_resample(void* resampler,
39-
const void* src, size_t src_size, unsigned int src_freq,
40-
void* dst, size_t dst_size, unsigned int dst_freq)
38+
static void trivial_resample(void* resampler,
39+
const void* src, size_t src_size, unsigned int src_freq, size_t* consumed,
40+
void* dst, size_t dst_size, unsigned int dst_freq, size_t* produced)
4141
{
4242
enum { BYTES_PER_SAMPLE = 4 };
4343
size_t i;
@@ -71,7 +71,8 @@ static size_t trivial_resample(void* resampler,
7171
}
7272
}
7373

74-
return j * 4;
74+
*consumed = j * 4;
75+
*produced = i * 4;
7576
}
7677

7778

0 commit comments

Comments
 (0)