diff --git a/src/soundio.cpp b/src/soundio.cpp index e06c2d8..d6c017a 100644 --- a/src/soundio.cpp +++ b/src/soundio.cpp @@ -763,21 +763,29 @@ bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, int sampl return false; } +static int abs_diff_int(int a, int b) { + int x = a - b; + return (x >= 0) ? x : -x; +} + int soundio_device_nearest_sample_rate(struct SoundIoDevice *device, int sample_rate) { int best_rate = -1; int best_delta = -1; for (int i = 0; i < device->sample_rate_count; i += 1) { SoundIoSampleRateRange *range = &device->sample_rates[i]; - if (sample_rate < range->min) { - int delta = range->min - sample_rate; - if (best_delta == -1 || delta < best_delta) { - best_delta = delta; - best_rate = range->min; - } - } else if (best_rate == -1 && sample_rate > range->max) { - best_rate = range->max; - } else { - return sample_rate; + int candidate_rate = clamp(range->min, sample_rate, range->max); + if (candidate_rate == sample_rate) + return candidate_rate; + + int delta = abs_diff_int(candidate_rate, sample_rate); + bool best_rate_too_small = best_rate < sample_rate; + bool candidate_rate_too_small = candidate_rate < sample_rate; + if (best_rate == -1 || + (best_rate_too_small && !candidate_rate_too_small) || + ((best_rate_too_small || !candidate_rate_too_small) && delta < best_delta)) + { + best_rate = candidate_rate; + best_delta = delta; } } return best_rate; diff --git a/test/unit_tests.cpp b/test/unit_tests.cpp index 742df29..3a25255 100644 --- a/test/unit_tests.cpp +++ b/test/unit_tests.cpp @@ -183,6 +183,33 @@ static void test_mirrored_memory(void) { soundio_os_deinit_mirrored_memory(&mem); } +static void test_nearest_sample_rate(void) { + struct SoundIoDevice device; + struct SoundIoSampleRateRange sample_rates[2] = { + { + 44100, + 48000 + }, + { + 96000, + 96000, + }, + }; + + device.sample_rate_count = 2; + device.sample_rates = sample_rates; + + assert(soundio_device_nearest_sample_rate(&device, 100) == 44100); + assert(soundio_device_nearest_sample_rate(&device, 44099) == 44100); + assert(soundio_device_nearest_sample_rate(&device, 44100) == 44100); + assert(soundio_device_nearest_sample_rate(&device, 45000) == 45000); + assert(soundio_device_nearest_sample_rate(&device, 48000) == 48000); + assert(soundio_device_nearest_sample_rate(&device, 48001) == 96000); + assert(soundio_device_nearest_sample_rate(&device, 90000) == 96000); + assert(soundio_device_nearest_sample_rate(&device, 96001) == 96000); + assert(soundio_device_nearest_sample_rate(&device, 9999999) == 96000); +} + struct Test { const char *name; void (*fn)(void); @@ -194,6 +221,7 @@ static struct Test tests[] = { {"ring buffer basic", test_ring_buffer_basic}, {"ring buffer threaded", test_ring_buffer_threaded}, {"mirrored memory", test_mirrored_memory}, + {"soundio_device_nearest_sample_rate", test_nearest_sample_rate}, {NULL, NULL}, };