1 /// Translated from C to D 2 module soundio.soundio; 3 4 @nogc nothrow: 5 extern(C): __gshared: 6 7 8 import soundio.atomics; 9 import soundio.soundio_private; 10 import soundio.util; 11 import soundio.os; 12 import soundio.config; 13 import core.stdc.string; 14 import core.stdc.assert_; 15 import core.stdc.stdio; 16 import core.stdc.stdlib: qsort, free; 17 18 package: 19 20 private extern(D) immutable SoundIoBackend[] available_backends = () { 21 SoundIoBackend[] result; 22 version(SOUNDIO_HAVE_JACK) result ~= SoundIoBackend.Jack; 23 version(SOUNDIO_HAVE_PULSEAUDIO) result ~= SoundIoBackend.PulseAudio; 24 version(SOUNDIO_HAVE_ALSA) result ~= SoundIoBackend.Alsa; 25 version(SOUNDIO_HAVE_COREAUDIO) result ~= SoundIoBackend.CoreAudio; 26 version(SOUNDIO_HAVE_WASAPI) result ~= SoundIoBackend.Wasapi; 27 return result; 28 } (); 29 30 alias backend_init_t = int function(SoundIoPrivate*); 31 32 immutable backend_init_t[7] backend_init_fns = () { 33 backend_init_t[7] result = null; 34 result[0] = null; // None backend 35 version(SOUNDIO_HAVE_JACK) result[1] = &soundio_jack_init; 36 version(SOUNDIO_HAVE_PULSEAUDIO) result[2] = &soundio_pulseaudio_init; 37 version(SOUNDIO_HAVE_ALSA) result[3] = &soundio_alsa_init; 38 version(SOUNDIO_HAVE_COREAUDIO) result[4] = &soundio_coreaudio_init; 39 version(SOUNDIO_HAVE_WASAPI) result[5] = &soundio_wasapi_init; 40 result[6] = &soundio_dummy_init; 41 return result; 42 } (); 43 44 const(char)* soundio_strerror(int error) { 45 switch (cast(SoundIoError)error) { 46 case SoundIoError.None: return "(no error)"; 47 case SoundIoError.NoMem: return "out of memory"; 48 case SoundIoError.InitAudioBackend: return "unable to initialize audio backend"; 49 case SoundIoError.SystemResources: return "system resource not available"; 50 case SoundIoError.OpeningDevice: return "unable to open device"; 51 case SoundIoError.NoSuchDevice: return "no such device"; 52 case SoundIoError.Invalid: return "invalid value"; 53 case SoundIoError.BackendUnavailable: return "backend unavailable"; 54 case SoundIoError.Streaming: return "unrecoverable streaming failure"; 55 case SoundIoError.IncompatibleDevice: return "incompatible device"; 56 case SoundIoError.NoSuchClient: return "no such client"; 57 case SoundIoError.IncompatibleBackend: return "incompatible backend"; 58 case SoundIoError.BackendDisconnected: return "backend disconnected"; 59 case SoundIoError.Interrupted: return "interrupted; try again"; 60 case SoundIoError.Underflow: return "buffer underflow"; 61 case SoundIoError.EncodingString: return "failed to encode string"; 62 default: return "(invalid error)"; 63 } 64 } 65 66 int soundio_get_bytes_per_sample(SoundIoFormat format) { 67 switch (format) { 68 case SoundIoFormat.U8: return 1; 69 case SoundIoFormat.S8: return 1; 70 case SoundIoFormat.S16LE: return 2; 71 case SoundIoFormat.S16BE: return 2; 72 case SoundIoFormat.U16LE: return 2; 73 case SoundIoFormat.U16BE: return 2; 74 case SoundIoFormat.S24LE: return 4; 75 case SoundIoFormat.S24BE: return 4; 76 case SoundIoFormat.U24LE: return 4; 77 case SoundIoFormat.U24BE: return 4; 78 case SoundIoFormat.S32LE: return 4; 79 case SoundIoFormat.S32BE: return 4; 80 case SoundIoFormat.U32LE: return 4; 81 case SoundIoFormat.U32BE: return 4; 82 case SoundIoFormat.Float32LE: return 4; 83 case SoundIoFormat.Float32BE: return 4; 84 case SoundIoFormat.Float64LE: return 8; 85 case SoundIoFormat.Float64BE: return 8; 86 87 case SoundIoFormat.Invalid: return -1; 88 default: break; 89 } 90 return -1; 91 } 92 93 const(char)* soundio_format_string(SoundIoFormat format) { 94 switch (format) { 95 case SoundIoFormat.S8: return "signed 8-bit"; 96 case SoundIoFormat.U8: return "unsigned 8-bit"; 97 case SoundIoFormat.S16LE: return "signed 16-bit LE"; 98 case SoundIoFormat.S16BE: return "signed 16-bit BE"; 99 case SoundIoFormat.U16LE: return "unsigned 16-bit LE"; 100 case SoundIoFormat.U16BE: return "unsigned 16-bit LE"; 101 case SoundIoFormat.S24LE: return "signed 24-bit LE"; 102 case SoundIoFormat.S24BE: return "signed 24-bit BE"; 103 case SoundIoFormat.U24LE: return "unsigned 24-bit LE"; 104 case SoundIoFormat.U24BE: return "unsigned 24-bit BE"; 105 case SoundIoFormat.S32LE: return "signed 32-bit LE"; 106 case SoundIoFormat.S32BE: return "signed 32-bit BE"; 107 case SoundIoFormat.U32LE: return "unsigned 32-bit LE"; 108 case SoundIoFormat.U32BE: return "unsigned 32-bit BE"; 109 case SoundIoFormat.Float32LE: return "float 32-bit LE"; 110 case SoundIoFormat.Float32BE: return "float 32-bit BE"; 111 case SoundIoFormat.Float64LE: return "float 64-bit LE"; 112 case SoundIoFormat.Float64BE: return "float 64-bit BE"; 113 case SoundIoFormat.Invalid: 114 default: break; 115 } 116 return "(invalid sample format)"; 117 } 118 119 120 const(char)* soundio_backend_name(SoundIoBackend backend) { 121 switch (backend) { 122 case SoundIoBackend.None: return "(none)"; 123 case SoundIoBackend.Jack: return "JACK"; 124 case SoundIoBackend.PulseAudio: return "PulseAudio"; 125 case SoundIoBackend.Alsa: return "ALSA"; 126 case SoundIoBackend.CoreAudio: return "CoreAudio"; 127 case SoundIoBackend.Wasapi: return "WASAPI"; 128 case SoundIoBackend.Dummy: return "Dummy"; 129 default: break; 130 } 131 return "(invalid backend)"; 132 } 133 134 void soundio_destroy(SoundIo* soundio) { 135 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 136 137 soundio_disconnect(soundio); 138 139 free(si); 140 } 141 142 static void do_nothing_cb(SoundIo* soundio) { } 143 static void default_msg_callback(const(char)* msg) { } 144 145 static void default_backend_disconnect_cb(SoundIo* soundio, int err) { 146 soundio_panic("libsoundio: backend disconnected: %s", soundio_strerror(err)); 147 } 148 149 static SoundIoAtomicFlag rtprio_seen = SoundIoAtomicFlag.init; 150 static void default_emit_rtprio_warning() { 151 if (!SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(rtprio_seen)) { 152 printf_stderr("warning: unable to set high priority thread: Operation not permitted\n"); 153 printf_stderr("See " 154 ~ "https://github.com/andrewrk/genesis/wiki/warning:-unable-to-set-high-priority-thread:-Operation-not-permitted\n"); 155 } 156 } 157 158 SoundIo* soundio_create() { 159 if (auto err = soundio_os_init()) 160 return null; 161 SoundIoPrivate* si = ALLOCATE!SoundIoPrivate(1); 162 if (!si) 163 return null; 164 SoundIo* soundio = &si.pub; 165 soundio.on_devices_change = &do_nothing_cb; 166 soundio.on_backend_disconnect = &default_backend_disconnect_cb; 167 soundio.on_events_signal = &do_nothing_cb; 168 soundio.app_name = "SoundIo"; 169 soundio.emit_rtprio_warning = &default_emit_rtprio_warning; 170 soundio.jack_info_callback = &default_msg_callback; 171 soundio.jack_error_callback = &default_msg_callback; 172 return soundio; 173 } 174 175 int soundio_connect(SoundIo* soundio) { 176 int err = 0; 177 178 for (int i = 0; i < available_backends.length; i += 1) { 179 SoundIoBackend backend = available_backends[i]; 180 err = soundio_connect_backend(soundio, backend); 181 if (!err) 182 return 0; 183 if (err != SoundIoError.InitAudioBackend) 184 return err; 185 } 186 187 return err; 188 } 189 190 int soundio_connect_backend(SoundIo* soundio, SoundIoBackend backend) { 191 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 192 193 if (soundio.current_backend) 194 return SoundIoError.Invalid; 195 196 if (backend <= 0 || backend > SoundIoBackend.Dummy) 197 return SoundIoError.Invalid; 198 199 extern(C) int function(SoundIoPrivate*) fn = backend_init_fns[backend]; 200 201 if (!fn) 202 return SoundIoError.BackendUnavailable; 203 204 if (auto err = backend_init_fns[backend](si)) { 205 soundio_disconnect(soundio); 206 return err; 207 } 208 soundio.current_backend = backend; 209 210 return 0; 211 } 212 213 void soundio_disconnect(SoundIo* soundio) { 214 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 215 216 if (!si) 217 return; 218 219 if (si.destroy) 220 si.destroy(si); 221 memset(&si.backend_data, 0, SoundIoBackendData.sizeof); 222 223 soundio.current_backend = SoundIoBackend.None; 224 225 soundio_destroy_devices_info(si.safe_devices_info); 226 si.safe_devices_info = null; 227 228 si.destroy = null; 229 si.flush_events = null; 230 si.wait_events = null; 231 si.wakeup = null; 232 si.force_device_scan = null; 233 234 si.outstream_open = null; 235 si.outstream_destroy = null; 236 si.outstream_start = null; 237 si.outstream_begin_write = null; 238 si.outstream_end_write = null; 239 si.outstream_clear_buffer = null; 240 si.outstream_pause = null; 241 si.outstream_get_latency = null; 242 si.outstream_set_volume = null; 243 244 si.instream_open = null; 245 si.instream_destroy = null; 246 si.instream_start = null; 247 si.instream_begin_read = null; 248 si.instream_end_read = null; 249 si.instream_pause = null; 250 si.instream_get_latency = null; 251 } 252 253 void soundio_flush_events(SoundIo* soundio) { 254 assert(soundio.current_backend != SoundIoBackend.None); 255 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 256 si.flush_events(si); 257 } 258 259 int soundio_input_device_count(SoundIo* soundio) { 260 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 261 262 assert(si.safe_devices_info); 263 if (!si.safe_devices_info) 264 return -1; 265 266 assert(soundio.current_backend != SoundIoBackend.None); 267 if (soundio.current_backend == SoundIoBackend.None) 268 return -1; 269 270 return si.safe_devices_info.input_devices.length; 271 } 272 273 int soundio_output_device_count(SoundIo* soundio) { 274 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 275 276 assert(si.safe_devices_info); 277 if (!si.safe_devices_info) 278 return -1; 279 280 assert(soundio.current_backend != SoundIoBackend.None); 281 if (soundio.current_backend == SoundIoBackend.None) 282 return -1; 283 284 return si.safe_devices_info.output_devices.length; 285 } 286 287 int soundio_default_input_device_index(SoundIo* soundio) { 288 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 289 290 assert(si.safe_devices_info); 291 if (!si.safe_devices_info) 292 return -1; 293 294 assert(soundio.current_backend != SoundIoBackend.None); 295 if (soundio.current_backend == SoundIoBackend.None) 296 return -1; 297 298 return si.safe_devices_info.default_input_index; 299 } 300 301 int soundio_default_output_device_index(SoundIo* soundio) { 302 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 303 304 assert(si.safe_devices_info); 305 if (!si.safe_devices_info) 306 return -1; 307 308 assert(soundio.current_backend != SoundIoBackend.None); 309 if (soundio.current_backend == SoundIoBackend.None) 310 return -1; 311 312 return si.safe_devices_info.default_output_index; 313 } 314 315 SoundIoDevice* soundio_get_input_device(SoundIo* soundio, int index) { 316 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 317 318 assert(soundio.current_backend != SoundIoBackend.None); 319 if (soundio.current_backend == SoundIoBackend.None) 320 return null; 321 322 assert(si.safe_devices_info); 323 if (!si.safe_devices_info) 324 return null; 325 326 assert(index >= 0); 327 assert(index < si.safe_devices_info.input_devices.length); 328 if (index < 0 || index >= si.safe_devices_info.input_devices.length) 329 return null; 330 331 SoundIoDevice* device = si.safe_devices_info.input_devices.val_at(index); 332 soundio_device_ref(device); 333 return device; 334 } 335 336 SoundIoDevice* soundio_get_output_device(SoundIo* soundio, int index) { 337 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 338 339 assert(soundio.current_backend != SoundIoBackend.None); 340 if (soundio.current_backend == SoundIoBackend.None) 341 return null; 342 343 assert(si.safe_devices_info); 344 if (!si.safe_devices_info) 345 return null; 346 347 assert(index >= 0); 348 assert(index < si.safe_devices_info.output_devices.length); 349 if (index < 0 || index >= si.safe_devices_info.output_devices.length) 350 return null; 351 352 SoundIoDevice* device = si.safe_devices_info.output_devices.val_at(index); 353 soundio_device_ref(device); 354 return device; 355 } 356 357 void soundio_device_unref(SoundIoDevice* device) { 358 if (!device) 359 return; 360 361 device.ref_count -= 1; 362 assert(device.ref_count >= 0); 363 364 if (device.ref_count == 0) { 365 SoundIoDevicePrivate* dev = cast(SoundIoDevicePrivate*)device; 366 if (dev.destruct) 367 dev.destruct(dev); 368 369 free(device.id); 370 free(device.name); 371 372 if (device.sample_rates != &dev.prealloc_sample_rate_range && 373 device.sample_rates != dev.sample_rates.items) 374 { 375 free(device.sample_rates); 376 } 377 dev.sample_rates.deinit(); 378 379 if (device.formats != &dev.prealloc_format) 380 free(device.formats); 381 382 if (device.layouts != &device.current_layout) 383 free(device.layouts); 384 385 free(dev); 386 } 387 } 388 389 void soundio_device_ref(SoundIoDevice* device) { 390 assert(device); 391 device.ref_count += 1; 392 } 393 394 void soundio_wait_events(SoundIo* soundio) { 395 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 396 si.wait_events(si); 397 } 398 399 void soundio_wakeup(SoundIo* soundio) { 400 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 401 si.wakeup(si); 402 } 403 404 void soundio_force_device_scan(SoundIo* soundio) { 405 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 406 si.force_device_scan(si); 407 } 408 409 int soundio_outstream_begin_write(SoundIoOutStream* outstream, SoundIoChannelArea** areas, int* frame_count) { 410 SoundIo* soundio = outstream.device.soundio; 411 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 412 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)outstream; 413 if (*frame_count <= 0) 414 return SoundIoError.Invalid; 415 return si.outstream_begin_write(si, os, areas, frame_count); 416 } 417 418 int soundio_outstream_end_write(SoundIoOutStream* outstream) { 419 SoundIo* soundio = outstream.device.soundio; 420 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 421 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)outstream; 422 return si.outstream_end_write(si, os); 423 } 424 425 static void default_outstream_error_callback(SoundIoOutStream* os, int err) { 426 soundio_panic("libsoundio: %s", soundio_strerror(err)); 427 } 428 429 static void default_underflow_callback(SoundIoOutStream* outstream) { } 430 431 SoundIoOutStream* soundio_outstream_create(SoundIoDevice* device) { 432 SoundIoOutStreamPrivate* os = ALLOCATE!SoundIoOutStreamPrivate(1); 433 SoundIoOutStream* outstream = &os.pub; 434 435 if (!os) 436 return null; 437 if (!device) 438 return null; 439 440 outstream.device = device; 441 soundio_device_ref(device); 442 443 outstream.error_callback = &default_outstream_error_callback; 444 outstream.underflow_callback = &default_underflow_callback; 445 446 return outstream; 447 } 448 449 int soundio_outstream_open(SoundIoOutStream* outstream) { 450 SoundIoDevice* device = outstream.device; 451 452 if (device.aim != SoundIoDeviceAim.Output) 453 return SoundIoError.Invalid; 454 455 if (device.probe_error) 456 return device.probe_error; 457 458 if (outstream.layout.channel_count > SOUNDIO_MAX_CHANNELS) 459 return SoundIoError.Invalid; 460 461 if (outstream.format == SoundIoFormat.Invalid) { 462 outstream.format = soundio_device_supports_format(device, SoundIoFormatFloat32NE) ? 463 SoundIoFormatFloat32NE : device.formats[0]; 464 } 465 466 if (outstream.format <= SoundIoFormat.Invalid) 467 return SoundIoError.Invalid; 468 469 if (!outstream.layout.channel_count) { 470 const(SoundIoChannelLayout)* stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutId.Stereo); 471 outstream.layout = soundio_device_supports_layout(device, stereo) ? *stereo : device.layouts[0]; 472 } 473 474 if (!outstream.sample_rate) 475 outstream.sample_rate = soundio_device_nearest_sample_rate(device, 48000); 476 477 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)outstream; 478 outstream.bytes_per_frame = soundio_get_bytes_per_frame(outstream.format, outstream.layout.channel_count); 479 outstream.bytes_per_sample = soundio_get_bytes_per_sample(outstream.format); 480 481 SoundIo* soundio = device.soundio; 482 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 483 return si.outstream_open(si, os); 484 } 485 486 void soundio_outstream_destroy(SoundIoOutStream* outstream) { 487 if (!outstream) 488 return; 489 490 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)outstream; 491 SoundIo* soundio = outstream.device.soundio; 492 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 493 494 if (si.outstream_destroy) 495 si.outstream_destroy(si, os); 496 497 soundio_device_unref(outstream.device); 498 free(os); 499 } 500 501 int soundio_outstream_start(SoundIoOutStream* outstream) { 502 SoundIo* soundio = outstream.device.soundio; 503 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 504 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)outstream; 505 return si.outstream_start(si, os); 506 } 507 508 int soundio_outstream_pause(SoundIoOutStream* outstream, bool pause) { 509 SoundIo* soundio = outstream.device.soundio; 510 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 511 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)outstream; 512 return si.outstream_pause(si, os, pause); 513 } 514 515 int soundio_outstream_clear_buffer(SoundIoOutStream* outstream) { 516 SoundIo* soundio = outstream.device.soundio; 517 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 518 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)outstream; 519 return si.outstream_clear_buffer(si, os); 520 } 521 522 int soundio_outstream_get_latency(SoundIoOutStream* outstream, double* out_latency) { 523 SoundIo* soundio = outstream.device.soundio; 524 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 525 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)outstream; 526 return si.outstream_get_latency(si, os, out_latency); 527 } 528 529 int soundio_outstream_set_volume(SoundIoOutStream* outstream, double volume) { 530 SoundIo* soundio = outstream.device.soundio; 531 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 532 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)outstream; 533 return si.outstream_set_volume(si, os, volume); 534 } 535 536 static void default_instream_error_callback(SoundIoInStream* is_, int err) { 537 soundio_panic("libsoundio: %s", soundio_strerror(err)); 538 } 539 540 static void default_overflow_callback(SoundIoInStream* instream) { } 541 542 SoundIoInStream* soundio_instream_create(SoundIoDevice* device) { 543 SoundIoInStreamPrivate* is_ = ALLOCATE!SoundIoInStreamPrivate(1); 544 SoundIoInStream* instream = &is_.pub; 545 546 if (!is_) 547 return null; 548 if (!device) 549 return null; 550 551 instream.device = device; 552 soundio_device_ref(device); 553 554 instream.error_callback = &default_instream_error_callback; 555 instream.overflow_callback = &default_overflow_callback; 556 557 return instream; 558 } 559 560 int soundio_instream_open(SoundIoInStream* instream) { 561 SoundIoDevice* device = instream.device; 562 if (device.aim != SoundIoDeviceAim.Input) 563 return SoundIoError.Invalid; 564 565 if (instream.format <= SoundIoFormat.Invalid) 566 return SoundIoError.Invalid; 567 568 if (instream.layout.channel_count > SOUNDIO_MAX_CHANNELS) 569 return SoundIoError.Invalid; 570 571 if (device.probe_error) 572 return device.probe_error; 573 574 if (instream.format == SoundIoFormat.Invalid) { 575 instream.format = soundio_device_supports_format(device, SoundIoFormat.Float32NE) ? 576 SoundIoFormat.Float32NE : device.formats[0]; 577 } 578 579 if (!instream.layout.channel_count) { 580 const(SoundIoChannelLayout)* stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutId.Stereo); 581 instream.layout = soundio_device_supports_layout(device, stereo) ? *stereo : device.layouts[0]; 582 } 583 584 if (!instream.sample_rate) 585 instream.sample_rate = soundio_device_nearest_sample_rate(device, 48000); 586 587 588 instream.bytes_per_frame = soundio_get_bytes_per_frame(instream.format, instream.layout.channel_count); 589 instream.bytes_per_sample = soundio_get_bytes_per_sample(instream.format); 590 SoundIo* soundio = device.soundio; 591 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 592 SoundIoInStreamPrivate* is_ = cast(SoundIoInStreamPrivate*)instream; 593 return si.instream_open(si, is_); 594 } 595 596 int soundio_instream_start(SoundIoInStream* instream) { 597 SoundIo* soundio = instream.device.soundio; 598 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 599 SoundIoInStreamPrivate* is_ = cast(SoundIoInStreamPrivate*)instream; 600 return si.instream_start(si, is_); 601 } 602 603 void soundio_instream_destroy(SoundIoInStream* instream) { 604 if (!instream) 605 return; 606 607 SoundIoInStreamPrivate* is_ = cast(SoundIoInStreamPrivate*)instream; 608 SoundIo* soundio = instream.device.soundio; 609 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 610 611 if (si.instream_destroy) 612 si.instream_destroy(si, is_); 613 614 soundio_device_unref(instream.device); 615 free(is_); 616 } 617 618 int soundio_instream_pause(SoundIoInStream* instream, bool pause) { 619 SoundIo* soundio = instream.device.soundio; 620 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 621 SoundIoInStreamPrivate* is_ = cast(SoundIoInStreamPrivate*)instream; 622 return si.instream_pause(si, is_, pause); 623 } 624 625 int soundio_instream_begin_read(SoundIoInStream* instream, SoundIoChannelArea** areas, int* frame_count) { 626 SoundIo* soundio = instream.device.soundio; 627 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 628 SoundIoInStreamPrivate* is_ = cast(SoundIoInStreamPrivate*)instream; 629 return si.instream_begin_read(si, is_, areas, frame_count); 630 } 631 632 int soundio_instream_end_read(SoundIoInStream* instream) { 633 SoundIo* soundio = instream.device.soundio; 634 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 635 SoundIoInStreamPrivate* is_ = cast(SoundIoInStreamPrivate*)instream; 636 return si.instream_end_read(si, is_); 637 } 638 639 int soundio_instream_get_latency(SoundIoInStream* instream, double* out_latency) { 640 SoundIo* soundio = instream.device.soundio; 641 SoundIoPrivate* si = cast(SoundIoPrivate*)soundio; 642 SoundIoInStreamPrivate* is_ = cast(SoundIoInStreamPrivate*)instream; 643 return si.instream_get_latency(si, is_, out_latency); 644 } 645 646 void soundio_destroy_devices_info(SoundIoDevicesInfo* devices_info) { 647 if (!devices_info) 648 return; 649 650 for (int i = 0; i < devices_info.input_devices.length; i += 1) 651 soundio_device_unref(devices_info.input_devices.val_at(i)); 652 for (int i = 0; i < devices_info.output_devices.length; i += 1) 653 soundio_device_unref(devices_info.output_devices.val_at(i)); 654 655 devices_info.input_devices.deinit(); 656 devices_info.output_devices.deinit(); 657 658 free(devices_info); 659 } 660 661 bool soundio_have_backend(SoundIoBackend backend) { 662 assert(backend > 0); 663 assert(backend <= SoundIoBackend.max); 664 return cast(bool) backend_init_fns[backend]; 665 } 666 667 int soundio_backend_count(SoundIo* soundio) { 668 return cast(int) available_backends.length; 669 } 670 671 SoundIoBackend soundio_get_backend(SoundIo* soundio, int index) { 672 return available_backends[index]; 673 } 674 675 static bool layout_contains(const(SoundIoChannelLayout)* available_layouts, int available_layouts_count, const(SoundIoChannelLayout)* target_layout) { 676 for (int i = 0; i < available_layouts_count; i += 1) { 677 const(SoundIoChannelLayout)* available_layout = &available_layouts[i]; 678 if (soundio_channel_layout_equal(target_layout, available_layout)) 679 return true; 680 } 681 return false; 682 } 683 684 const(SoundIoChannelLayout)* soundio_best_matching_channel_layout(const(SoundIoChannelLayout)* preferred_layouts, int preferred_layouts_count, const(SoundIoChannelLayout)* available_layouts, int available_layouts_count) { 685 for (int i = 0; i < preferred_layouts_count; i += 1) { 686 const(SoundIoChannelLayout)* preferred_layout = &preferred_layouts[i]; 687 if (layout_contains(available_layouts, available_layouts_count, preferred_layout)) 688 return preferred_layout; 689 } 690 return null; 691 } 692 693 static int compare_layouts(const(void)* a, const(void)* b) { 694 const(SoundIoChannelLayout)* layout_a = cast(const(SoundIoChannelLayout)*)a; 695 const(SoundIoChannelLayout)* layout_b = cast(const(SoundIoChannelLayout)*)b; 696 if (layout_a.channel_count > layout_b.channel_count) 697 return -1; 698 else if (layout_a.channel_count < layout_b.channel_count) 699 return 1; 700 else 701 return 0; 702 } 703 704 void soundio_sort_channel_layouts(SoundIoChannelLayout* layouts, int layouts_count) { 705 if (!layouts) 706 return; 707 708 qsort(layouts, layouts_count, SoundIoChannelLayout.sizeof, &compare_layouts); 709 } 710 711 void soundio_device_sort_channel_layouts(SoundIoDevice* device) { 712 soundio_sort_channel_layouts(device.layouts, device.layout_count); 713 } 714 715 bool soundio_device_supports_format(SoundIoDevice* device, SoundIoFormat format) { 716 for (int i = 0; i < device.format_count; i += 1) { 717 if (device.formats[i] == format) 718 return true; 719 } 720 return false; 721 } 722 723 bool soundio_device_supports_layout(SoundIoDevice* device, const(SoundIoChannelLayout)* layout) { 724 for (int i = 0; i < device.layout_count; i += 1) { 725 if (soundio_channel_layout_equal(&device.layouts[i], layout)) 726 return true; 727 } 728 return false; 729 } 730 731 bool soundio_device_supports_sample_rate(SoundIoDevice* device, int sample_rate) { 732 for (int i = 0; i < device.sample_rate_count; i += 1) { 733 SoundIoSampleRateRange* range = &device.sample_rates[i]; 734 if (sample_rate >= range.min && sample_rate <= range.max) 735 return true; 736 } 737 return false; 738 } 739 740 static int abs_diff_int(int a, int b) { 741 int x = a - b; 742 return (x >= 0) ? x : -x; 743 } 744 745 int soundio_device_nearest_sample_rate(SoundIoDevice* device, int sample_rate) { 746 int best_rate = -1; 747 int best_delta = -1; 748 for (int i = 0; i < device.sample_rate_count; i += 1) { 749 SoundIoSampleRateRange* range = &device.sample_rates[i]; 750 int candidate_rate = soundio_int_clamp(range.min, sample_rate, range.max); 751 if (candidate_rate == sample_rate) 752 return candidate_rate; 753 754 int delta = abs_diff_int(candidate_rate, sample_rate); 755 bool best_rate_too_small = best_rate < sample_rate; 756 bool candidate_rate_too_small = candidate_rate < sample_rate; 757 if (best_rate == -1 || 758 (best_rate_too_small && !candidate_rate_too_small) || 759 ((best_rate_too_small || !candidate_rate_too_small) && delta < best_delta)) 760 { 761 best_rate = candidate_rate; 762 best_delta = delta; 763 } 764 } 765 return best_rate; 766 } 767 768 bool soundio_device_equal(const(SoundIoDevice)* a, const(SoundIoDevice)* b) { 769 return a.is_raw == b.is_raw && a.aim == b.aim && strcmp(a.id, b.id) == 0; 770 } 771 772 const(char)* soundio_version_string() { 773 return SOUNDIO_VERSION_STRING; 774 } 775 776 int soundio_version_major() { 777 return SOUNDIO_VERSION_MAJOR; 778 } 779 780 int soundio_version_minor() { 781 return SOUNDIO_VERSION_MINOR; 782 } 783 784 int soundio_version_patch() { 785 return SOUNDIO_VERSION_PATCH; 786 }