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