diff options
Diffstat (limited to 'src/buffer')
| -rw-r--r-- | src/buffer/audio.c | 69 | ||||
| -rw-r--r-- | src/buffer/audio.h | 15 | ||||
| -rw-r--r-- | src/buffer/video.c | 6 | ||||
| -rw-r--r-- | src/buffer/volume.h | 30 |
4 files changed, 78 insertions, 42 deletions
diff --git a/src/buffer/audio.c b/src/buffer/audio.c index 8d33f79..3abae42 100644 --- a/src/buffer/audio.c +++ b/src/buffer/audio.c @@ -9,12 +9,12 @@ #include "common_internal.h" #include "volume.h" -#define BUFFER_SIZE (6 * 1000000L) -#define BUFFER_MARK_MIN (2.6 * 1000000L) // Must be a most half of the buffer size. -#define BUFFER_MARK_BUFFERED (2.5 * 1000000L) +#define BUFFER_SIZE (9 * 1000000L) +#define BUFFER_MARK_MIN (4.3 * 1000000L) // Must be a most half of the buffer size. +#define BUFFER_MARK_BUFFERED (4.0 * 1000000L) #ifdef CAMU_AUDIO_BUFFER_FADE -#define FADE_STEP(fmt) (1.1f / (fmt)->sample_rate) +#define FADE_STEP(fmt) (1.f / (fmt)->sample_rate) #endif enum { @@ -29,10 +29,11 @@ static void reset_buffer_state(struct camu_audio_buffer *buf) { buf->pts = -1.0; buf->pause = PAUSE_PAUSED; - al_atomic_store(u8)(&buf->unpause, 0, AL_ATOMIC_RELAXED); - buf->volume = 1.f; + al_atomic_store(s32)(&buf->unpause, 0, AL_ATOMIC_RELAXED); + al_atomic_store(s32)(&buf->volume.set, 0, AL_ATOMIC_RELAXED); #ifdef CAMU_AUDIO_BUFFER_FADE - buf->fade_offset = 0; + buf->fade.offset = 0; + buf->fade.volume = 1.f; #endif buf->buffered = false; al_atomic_store(u8)(&buf->flow, FLOWING, AL_ATOMIC_RELAXED); @@ -88,6 +89,12 @@ bool camu_audio_buffer_configure(struct camu_audio_buffer *buf, struct camu_code return true; } +void camu_audio_buffer_set_volume(struct camu_audio_buffer *buf, f32 volume) +{ + al_atomic_store(f32)(&buf->volume.queued, volume, AL_ATOMIC_RELAXED); + al_atomic_add(s32)(&buf->volume.set, 1, AL_ATOMIC_RELAXED); +} + void camu_audio_buffer_set_latency(struct camu_audio_buffer *buf, f64 latency) { buf->latency = latency; @@ -191,7 +198,7 @@ void camu_audio_buffer_push(struct camu_audio_buffer *buf, struct camu_codec_fra void camu_audio_buffer_unpause(struct camu_audio_buffer *buf) { - al_atomic_store(u8)(&buf->unpause, 1, AL_ATOMIC_RELAXED); + al_atomic_add(s32)(&buf->unpause, 1, AL_ATOMIC_RELAXED); } // Not thread-safe, must be called while the buffer is not being read from or written to. @@ -238,12 +245,23 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re return 0; } + if (al_atomic_load(s32)(&buf->volume.set, AL_ATOMIC_ACQUIRE) > 0) { + buf->volume.user = al_atomic_load(f32)(&buf->volume.queued, AL_ATOMIC_RELAXED); +#ifdef CAMU_AUDIO_BUFFER_FADE + if (buf->fade.volume == -1.f) { + buf->fade.volume = buf->volume.user; + } +#endif + al_atomic_sub(s32)(&buf->volume.set, 1, AL_ATOMIC_RELEASE); + } + if (camu_clock_is_paused(buf->clock)) { #ifdef CAMU_AUDIO_BUFFER_FADE if (buf->pause == PAUSE_PLAYING) { buf->pause = PAUSE_FADING; - buf->fade_offset = 0; - } else if (buf->volume == 0.f || buf->pause == PAUSE_PAUSED) { + buf->fade.offset = 0; + } else if (buf->fade.volume == 0.f || buf->pause == PAUSE_PAUSED) { + buf->fade.offset = 0; al_memset(data, 0, req); if (NOT_PAUSED(buf->pause)) { buf->pause = PAUSE_PAUSED; @@ -263,10 +281,10 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re #endif } - if (al_atomic_load(u8)(&buf->unpause, AL_ATOMIC_ACQUIRE)) { + if (al_atomic_load(s32)(&buf->unpause, AL_ATOMIC_ACQUIRE) > 0) { // If pause != PLAYING here, this will cause unexpected behavior. buf->pause = PAUSE_PAUSED; - al_atomic_store(u8)(&buf->unpause, 0, AL_ATOMIC_RELEASE); + al_atomic_sub(s32)(&buf->unpause, 1, AL_ATOMIC_RELEASE); } f64 pts = camu_clock_get_pts(buf->clock, buf->latency); @@ -274,8 +292,8 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re size_t have = al_ring_buffer_occupied(&buf->rb); #ifdef CAMU_AUDIO_BUFFER_FADE // Cut off fade if it's reaching too far. - if (have < buf->fade_offset) have = 0; - else have -= buf->fade_offset; + if (have < buf->fade.offset) have = 0; + else have -= buf->fade.offset; if (buf->pause != PAUSE_FADING && buf->pause != PAUSE_PLAYING) { #endif pts -= buf->pts; @@ -350,8 +368,8 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re if (buf->pause == PAUSE_FADING) { // Peek into the ring buffer. This won't consume the data, so when // we resume it will fade in from the same position the fade out started. - ret = al_ring_buffer_peek(&buf->rb, data, buf->fade_offset, req); - buf->fade_offset += ret; + ret = al_ring_buffer_peek(&buf->rb, data, buf->fade.offset, req); + buf->fade.offset += ret; } else { #endif // Read as much as we determined we can. @@ -361,19 +379,30 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re #ifdef CAMU_AUDIO_BUFFER_FADE } f32 step = 0.f; - if (buf->pause == PAUSE_FADING) { + if (buf->pause == PAUSE_FADING || buf->fade.volume > buf->volume.user) { step = -FADE_STEP(&buf->fmt.req); - } else if (buf->volume < 1.f) { + } else if (buf->fade.volume < buf->volume.user) { step = FADE_STEP(&buf->fmt.req); } - if (step != 0.f || buf->volume != 1.f) { - buf->volume = apply_volume(data, req, &buf->fmt.req, buf->volume, step); + if (step != 0.f || buf->fade.volume != 1.f) { + if (buf->volume.user > 1.f) { + step *= buf->volume.user; + } + buf->fade.volume = apply_volume(data, req, &buf->fmt.req, buf->fade.volume, buf->volume.user, step); + } +#else + if (buf->volume.user != 1.f) { + apply_volume(data, req, &buf->fmt.req, buf->volume.user, 0.f, 0.f); } #endif } // Check if we should request to uncork. +#ifdef CAMU_AUDIO_BUFFER_FADE + if (flow == FLOWING && buf->pause != PAUSE_FADING) { +#else if (flow == FLOWING) { +#endif ret = al_atomic_load(size_t)(&buf->uncork_at, AL_ATOMIC_RELAXED); if (ret && have - req <= ret) { buf->callback(buf->userdata, CAMU_BUFFER_UNCORK); diff --git a/src/buffer/audio.h b/src/buffer/audio.h index 0f84d5a..1d49448 100644 --- a/src/buffer/audio.h +++ b/src/buffer/audio.h @@ -17,7 +17,7 @@ struct camu_audio_buffer { f64 pts; u8 pause; - atomic(u8) unpause; + atomic(s32) unpause; struct camu_clock *clock; bool ignore_desync; f64 latency; @@ -36,9 +36,17 @@ struct camu_audio_buffer { struct camu_peak_buffer peak; atomic(size_t) uncork_at; - f32 volume; + struct { + f32 user; + atomic(f32) queued; + atomic(s32) set; + } volume; + #ifdef CAMU_AUDIO_BUFFER_FADE - size_t fade_offset; + struct { + f32 volume; + size_t offset; + } fade; #endif #ifdef CAMU_MIXER_THREADED @@ -51,6 +59,7 @@ struct camu_audio_buffer { bool camu_audio_buffer_init(struct camu_audio_buffer *buf, struct camu_clock *clock, struct camu_mixer *mixer); bool camu_audio_buffer_configure(struct camu_audio_buffer *buf, struct camu_codec_stream *stream); +void camu_audio_buffer_set_volume(struct camu_audio_buffer *buf, f32 volume); void camu_audio_buffer_set_latency(struct camu_audio_buffer *buf, f64 latency); void camu_audio_buffer_push(struct camu_audio_buffer *buf, struct camu_codec_frame *frame); void camu_audio_buffer_unpause(struct camu_audio_buffer *buf); diff --git a/src/buffer/video.c b/src/buffer/video.c index 91c3687..a8b35c6 100644 --- a/src/buffer/video.c +++ b/src/buffer/video.c @@ -10,9 +10,9 @@ #endif #endif -#define BUFFER_MARK_LOW 0.199998 -#define BUFFER_MARK_BUFFERED 0.133332 -#define BUFFER_MARK_HIGH 0.33333 +#define BUFFER_MARK_LOW ((1.0 / 30.0) * 6) +#define BUFFER_MARK_BUFFERED ((1.0 / 30.0) * 8) +#define BUFFER_MARK_HIGH ((1.0 / 30.0) * 12) #define BUFFER_MARK_RESET (BUFFER_MARK_HIGH * 2.0) bool camu_video_buffer_init(struct camu_video_buffer *buf, struct camu_clock *clock, struct camu_renderer *renderer) diff --git a/src/buffer/volume.h b/src/buffer/volume.h index 0cad8d3..d39affc 100644 --- a/src/buffer/volume.h +++ b/src/buffer/volume.h @@ -2,26 +2,24 @@ AL_UNUSED_FUNCTION_PUSH -// https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1AB9U8lJL6yAngGVG6AMKpaAVxYMQ0hwBk8DTAA5dwAjTGIvAFZSAAdUBUJbBmc3Dy9Y%2BMSBPwDgljCIyWjLTGskoQImYgIU909pErKBCqqCHKDQ8KiLSuratIbetv8O/K6igEoLVFdiZHYOAFIAJgBmf2Q3LABqRdXHBQJ8QQA6BD3sRY0AQRX1hk3XHb2Do6wqM4ur27WNrcxdvsqLRUEwCJ9Vpcbt87u8Rttrj5jABZa4ADQgTFI2xCE22%2BIJu0ijm%2BEEWAHYAEKEmm0ukExbE76E0wEACeMUwqCopkxeOMTEBABFtkw9tSiSSbizjOzOdzebjtsYQsKceL8YypdcWYKLsrVXsAGLKwUgA0awlamHkoUTGFrOEBBFI5EASUCmOxStp1puZKp9KD9L9OoJrI5XJ5xj5prVYtWEtDMrlUcV/MNqxFIUtyfDev2BsBJoF23NKstDKZ0Nt9uhjswNGdiOMjh812RyggDGxIOxCDweJb7s9A%2Bxw/RED72wYEzrtxuqfe238BAAHLLtgo1%2BLvkvG9tXKuNwRDzvE3vI8vV1wAGybhR33eLq8Ho%2BCO%2Bb1xPi8vznXwRVmWB8gOfa59yoQ9VyAr9QN/cDX0g1db0kB8ULAiCoMEFCv3Q%2BDL3/A9gVBU8qDgykCMwZd0BmEJ6G2Kg8Io6EbkOME8GQBigOVAUCAIYg8BCVwCEwUxtigBhUH8WgRjnUUYhiWg2WMAA3Fx3FEsjlmobiACp0DBLEtzwAAvUTTwUVhFNEtBXEEbEFG45AEEMAJaGMWz7K45ZtjU1JMGxLStxEmJ5wpZiw3xfhiHE1xuLwNUNA1BKXi3Kz6A8mZBGSlYKOWSk8XC5k6TwSCIBS5ZIm2ZzXMwdzPNPPYhSa7YNEKqliuDPyNLVFs2w7LturYXZ8uCzAYmxDQTiobEuGm%2B14JDW1OppRjJDSlhrLVagUImAzKkZSk8EZZrFrpSzNvo3SWqGzAwPpfaxUiI6Tu2rSJj69tOwgC7rOxI0fAAFRRD1/qBlF0QWiKVopZrpQJYhMAIWYGF89S2DA2GYRuVdthYJh/AgNS8HQMKOvhqLuMew6uGWSRlhO%2B6CSC261TmpKzvxVmWqYBSlNU9HNKAiBHtmunlmxCW0f8yaTg0LguCoKGVsR5HiFRjnodtDgploThIl4TxuF4VBOEcLcZjmAE7h4UgCE0HWpgAaxASJVhOLgAE5PbXenPciOnPdWLhoj1jhJENh3SFNjheAUEANDth2pjgWAkDQTa6HCchKAzmIs4iZBNkMYAuFWeW%2BDoETiHjiAQijkJ/CqNlOFtxvmGINkAHkQm0Up7eN0gM7YQQu4YJSo6wITgEcMRaHjwesHxoxxA4LRSHwRGyhUzAF/XzBVFKYSFlt1c6qjmSQmIZvnCwKP%2BLwFhW94HfiBCeJMCFTBl%2BAGSjGTvgBhgAKAAGp4EwAAdy7pyI2tt%2BCCBEGIdgUgZCCEUCodQa8dAgAlgYf%2BpgPL6EEvHSAUxUAxBsAIBeABaQ46AmrIG9tsahXcfLUPxnMc4WYTIMFfmwlgyMAhNR4Xwk2r8BJYBIRAKYjRKGeAgA4fonguCkF8CMPIBQ9BxASHIpRWjMhyPaBoroKjZHlCGHo0xdV%2B7mNaEYzoERTEWPRsonodj1EOIkDIy28wvH6H1pHLB0dODbFUGuW81CULVTwcAbYZc5Ye3ErgQgJARrBwmLwAeWg5ykBdpIW8Jw1waHlpEckGhJDkkiBoW8a5yT%2BPDoE9eMc44JyTlgnJYdliNJNpwTJycpivwSHYSQQA - -static inline f32 apply_volume_f32(f32 *data, size_t sample_count, s32 channel_count, f32 volume, f32 step) +static inline f32 apply_volume_f32(f32 *data, size_t sample_count, s32 channel_count, f32 volume, f32 user, f32 step) { for (u32 i = 0; i < sample_count; i++) { - if (i % channel_count == 0) { - volume = AL_CLAMP(volume + step, 0.f, 1.f); + if (step != 0.f && i % channel_count == 0) { + volume = AL_CLAMP(volume + step, 0.f, user); } f64 sample = (f64)data[i]; sample *= volume; - data[i] = (f32)AL_CLAMP(sample, FLT_MIN, FLT_MAX); + data[i] = (f32)AL_CLAMP(sample, -1.0, 1.0); } return volume; } -static inline f32 apply_volume_s32(s32 *data, size_t sample_count, s32 channel_count, f32 volume, f32 step) +static inline f32 apply_volume_s32(s32 *data, size_t sample_count, s32 channel_count, f32 volume, f32 user, f32 step) { for (u32 i = 0; i < sample_count; i++) { - if (i % channel_count == 0) { - volume = AL_CLAMP(volume + step, 0.f, 1.f); + if (step != 0.f && i % channel_count == 0) { + volume = AL_CLAMP(volume + step, 0.f, user); } f64 sample = (f64)data[i]; sample *= volume; @@ -30,11 +28,11 @@ static inline f32 apply_volume_s32(s32 *data, size_t sample_count, s32 channel_c return volume; } -static inline f32 apply_volume_s16(s16 *data, size_t sample_count, s32 channel_count, f32 volume, f32 step) +static inline f32 apply_volume_s16(s16 *data, size_t sample_count, s32 channel_count, f32 volume, f32 user, f32 step) { for (u32 i = 0; i < sample_count; i++) { - if (i % channel_count == 0) { - volume = AL_CLAMP(volume + step, 0.f, 1.f); + if (step != 0.f && i % channel_count == 0) { + volume = AL_CLAMP(volume + step, 0.f, user); } f64 sample = (f64)data[i]; sample *= volume; @@ -43,22 +41,22 @@ static inline f32 apply_volume_s16(s16 *data, size_t sample_count, s32 channel_c return volume; } -static inline f32 apply_volume(u8 *data, size_t size, struct camu_audio_format *fmt, f32 volume, f32 step) +static inline f32 apply_volume(u8 *data, size_t size, struct camu_audio_format *fmt, f32 volume, f32 user, f32 step) { size_t sample_count; switch (camu_audio_format_bytes_per_sample(fmt)) { case 4: sample_count = size / 4; if (fmt->format == CAMU_SAMPLE_FORMAT_S32) { - return apply_volume_s32((s32 *)data, sample_count, fmt->channel_count, volume, step); + return apply_volume_s32((s32 *)data, sample_count, fmt->channel_count, volume, user, step); } else if (fmt->format == CAMU_SAMPLE_FORMAT_FLT) { - return apply_volume_f32((f32 *)data, sample_count, fmt->channel_count, volume, step); + return apply_volume_f32((f32 *)data, sample_count, fmt->channel_count, volume, user, step); } break; case 2: sample_count = size / 2; if (fmt->format == CAMU_SAMPLE_FORMAT_S16) { - return apply_volume_s16((s16 *)data, sample_count, fmt->channel_count, volume, step); + return apply_volume_s16((s16 *)data, sample_count, fmt->channel_count, volume, user, step); } break; } |