+#ifdef WITH_ASIO
+bool
+PortAudioIO::get_asio_buffer_properties (int device_id,
+ long& min_size_frames,
+ long& max_size_frames,
+ long& preferred_size_frames,
+ long& granularity)
+{
+ // we shouldn't really need all these checks but it shouldn't hurt
+ const PaDeviceInfo* device_info = Pa_GetDeviceInfo(device_id);
+
+ if (!device_info) {
+ DEBUG_AUDIO (string_compose (
+ "Unable to get device info from device index %1\n", device_id));
+ return false;
+ }
+
+ if (get_current_host_api_type() != paASIO) {
+ DEBUG_AUDIO (string_compose (
+ "ERROR device_id %1 is not an ASIO device\n", device_id));
+ return false;
+ }
+
+ PaError err = PaAsio_GetAvailableBufferSizes (device_id,
+ &min_size_frames,
+ &max_size_frames,
+ &preferred_size_frames,
+ &granularity);
+
+ if (err != paNoError) {
+ DEBUG_AUDIO (string_compose (
+ "Unable to determine available buffer sizes for device %1\n", device_id));
+ return false;
+ }
+ return true;
+}
+
+static
+bool
+is_power_of_two (uint32_t v)
+{
+ return ((v != 0) && !(v & (v - 1)));
+}
+
+bool
+PortAudioIO::get_asio_buffer_sizes(int device_id,
+ std::vector<uint32_t>& buffer_sizes,
+ bool preferred_only)
+{
+ long min_size_frames = 0;
+ long max_size_frames = 0;
+ long preferred_size_frames = 0;
+ long granularity = 0;
+
+ if (!get_asio_buffer_properties (device_id,
+ min_size_frames,
+ max_size_frames,
+ preferred_size_frames,
+ granularity)) {
+ DEBUG_AUDIO (string_compose (
+ "Unable to get device buffer properties from device index %1\n", device_id));
+ return false;
+ }
+
+ DEBUG_AUDIO (string_compose ("ASIO buffer properties for device %1, "
+ "min_size_frames: %2, max_size_frames: %3, "
+ "preferred_size_frames: %4, granularity: %5\n",
+ device_id,
+ min_size_frames,
+ max_size_frames,
+ preferred_size_frames,
+ granularity));
+
+ bool driver_returns_one_size = (min_size_frames == max_size_frames) &&
+ (min_size_frames == preferred_size_frames);
+
+ if (preferred_only || driver_returns_one_size) {
+ buffer_sizes.push_back(preferred_size_frames);
+ return true;
+ }
+
+ long buffer_size = min_size_frames;
+
+ // If min size and granularity are power of two then just use values that
+ // are power of 2 even if the granularity allows for more values
+ bool use_power_of_two =
+ is_power_of_two(min_size_frames) && is_power_of_two(granularity);
+
+ if (granularity <= 0 || use_power_of_two) {
+ // driver uses buffer sizes that are power of 2
+ while (buffer_size <= max_size_frames) {
+ buffer_sizes.push_back(buffer_size);
+ buffer_size *= 2;
+ }
+ } else {
+ if (min_size_frames == max_size_frames) {
+ // The devices I have tested either return the same values for
+ // min/max/preferred and changing buffer size is intended to only be
+ // done via the control dialog or they return a range where min != max
+ // but I guess min == max could happen if a driver only supports a single
+ // buffer size
+ buffer_sizes.push_back(min_size_frames);
+ return true;
+ }
+
+ // If min_size_frames is not power of 2 use at most 8 of the possible
+ // buffer sizes spread evenly between min and max
+ long max_values = 8;
+ while (((max_size_frames - min_size_frames) / granularity) > max_values) {
+ granularity *= 2;
+ }
+
+ while (buffer_size < max_size_frames) {
+ buffer_sizes.push_back(buffer_size);
+ buffer_size += granularity;
+ }
+ buffer_sizes.push_back(max_size_frames);
+ }
+ return true;
+}
+#endif
+
+void
+PortAudioIO::get_default_buffer_sizes(std::vector<uint32_t>& buffer_sizes)
+{
+ buffer_sizes.push_back(64);
+ buffer_sizes.push_back(128);
+ buffer_sizes.push_back(256);
+ buffer_sizes.push_back(512);
+ buffer_sizes.push_back(1024);
+ buffer_sizes.push_back(2048);
+ buffer_sizes.push_back(4096);
+}
+