Skip to content

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
dkorpel committed Aug 19, 2020
0 parents commit e99bc3b
Show file tree
Hide file tree
Showing 37 changed files with 15,059 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Compiled Object files
*.o
*.obj

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Compiled Static libraries
*.a
*.lib

# Executables
*.exe

# DUB
.dub
docs.json
__dummy.html
docs/

# Code coverage
*.lst

build/
dump/
dub.selections.json
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (Expat)

Copyright (c) 2015 Andrew Kelley

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
120 changes: 120 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# libsoundio-d
Translation from C to D of [libsoundio](https://github.com/andrewrk/libsoundio).

Libsoundio is a library for cross-platform real-time audio input and output.

It is licensed under the MIT License.
The translation is not affiliated with the original project.

Currently not all backends are translated.

| Backend | Translated | Used for |
|--------------------------------------------------------------------------|-----------------|--------------------------------------------|
| [Jack](https://jackaudio.org) | 🟠 Yes (untested)| See [JACK FAQ](https://jackaudio.org/faq/) |
| [Pulseaudio](https://en.wikipedia.org/wiki/PulseAudio) | ✔️ Yes | Linux (higher-level) |
| [Alsa](https://en.wikipedia.org/wiki/Advanced_Linux_Sound_Architecture) | ✔️ Yes | Linux (lower-level) |
| [WASAPI](https://docs.microsoft.com/en-us/windows/win32/coreaudio/wasapi)| ✔️ Yes | Windows |
| [Core Audio](https://en.wikipedia.org/wiki/Core_Audio) | ❌ No | macOS |
| Dummy | ✔️ Yes | Testing |

### Usage

Add this package as a dependency to your project.

dub.sdl:
```
dependency "libsoundio-d" version="~>1.0.0"
```

dub.json:
```
"dependencies": {
"libsoundio-d": "~>1.0.0"
}
```

And then use it:
```D
import soundio.api;
void main() {
SoundIo* soundio = soundio_create();
soundio_connect(soundio);
// your app
soundio_destroy(soundio);
}
```

The configuration should be automatically selected based on your platform, but you can also choose one explicitly:
- linux
- windows
- dummy

dub.sdl:
```
subConfiguration "libsoundio-d" "dummy"
```

dub.json:
```
"subConfigurations": {
"libsoundio-d": "dummy"
}
```

On Linux, you should have ALSA and PulseAudio installed (which you probably have by default, otherwise look up how to install it).

The following version identifiers are used:
- `SOUNDIO_HAVE_JACK`
- `SOUNDIO_HAVE_PULSEAUDIO`
- `SOUNDIO_HAVE_ALSA`
- `SOUNDIO_HAVE_COREAUDIO`
- `SOUNDIO_HAVE_WASAPI`

**Run the examples**

Assuming your current directory is the root of this repository:
```
dub run libsoundio-d:sine
dub run libsoundio-d:list-devices -- --short
dub run libsoundio-d:microphone -- --latency 0.05
dub run libsoundio-d:record -- output.bin
```

**Run the tests**
```
dub run libsoundio-d:backend-disconnect-recover
dub run libsoundio-d:latency
dub run libsoundio-d:overflow
dub run libsoundio-d:underflow
dub run libsoundio-d:unit-tests
```

### Translation events

The translation is closely converting C-syntax to D-syntax, no attempt to change the style to idiomatic D has been made.
There are a few exceptions where certain constructs had to be changed however.

- ALSA defines certain structs with an unknown size at compile time.
There are specific `alloca` macros that allocate these structs on the stack, and libsoundio uses these.
I translated these with malloc and free variants, because alloca has its own share of problems.

- Libsoundio has certain `static` functions with the same name across backends: both ALSA and Pulse have `probe_device` and `my_flush_events`.
Since D does not have C's notion of `static` functions (even `private` functions emit symbols), this introduces a name clash.
Worse, because DMD emits weak symbols, it gives no multiple definition error, but instead silently calls the wrong function:
The Pulse backend calls `probe_device` from the alsa backend instead of its own.
This is mitigated by making those functions `extern(D)` giving them unique names.

- D does not have C bindings of `stdatomic.h`, so I used equivalent functionality from `core.atomic`.
`core.atomic` has no direct equivalent of 'flag test and set'.
I initially translated as `cas` (compare and swap), but return value needed to be negated.
`atomicFetchAdd` was added in dmd 2.089 and is not supported in LDC as of 1.22, so I used `atomicOp!"+="` instead.

- On Windows `InterlockedIncrement` and `InterlockedDecrement` are not in the shipped import library "Kernel32.lib".
I replaced it with a corresponding `atomicOp!"+="` and `atomicOp!"-="`.

- On 32-bit Windows, 64-bit atomic operations are not supported.
The `SoundIoRingBuffer` uses `ulong` for its read and write offset, even on 32-bit.
I changed these to a `size_t` instead.

- Use of `fprintf(sderr, ...)` on Windows with `extern(C) main` triggers [issue 20532](https://issues.dlang.org/show_bug.cgi?id=20532). A custom `printf_stderr` function was made to work around this.
149 changes: 149 additions & 0 deletions dub.sdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
name "libsoundio-d"
description "D translation of libsoundio"
authors "dkorpel"
copyright "Copyright © 2020, dkorpel"
license "MIT"
targetName "libsoundio-d"
targetPath "build"
targetType "library"

buildOptions "betterC"
dflags "-preview=dip1000" "-preview=dip25"
dflags "-preview=fieldwise"
dflags "-preview=markdown"
dflags "-preview=fixAliasThis"
dflags "-preview=intpromote"
dflags "-preview=dtorfields"
dflags "-mixin=build/mixin.d"

sourcePaths // no default sourcepath
sourceFiles "source/soundio/api.d"
sourceFiles "source/soundio/atomics.d"
sourceFiles "source/soundio/channel_layout.d"
sourceFiles "source/soundio/config.d" // enums only
sourceFiles "source/soundio/list.d" // templates only
sourceFiles "source/soundio/dummy.d"
sourceFiles "source/soundio/os.d"
sourceFiles "source/soundio/package.d"
sourceFiles "source/soundio/ring_buffer.d"
sourceFiles "source/soundio/soundio.d"
sourceFiles "source/soundio/soundio_internal.d" // list template instantiations are in here sometimes
sourceFiles "source/soundio/soundio_private.d"
sourceFiles "source/soundio/util.d"

configuration "linux" {
platforms "linux"

libs "asound"
versions "SOUNDIO_HAVE_ALSA"
sourceFiles "source/soundio/alsa.d"

libs "pulse"
versions "SOUNDIO_HAVE_PULSEAUDIO"
sourceFiles "source/soundio/pulseaudio.d"
}

configuration "windows" {
platforms "windows"
versions "SOUNDIO_OS_WINDOWS"
versions "SOUNDIO_HAVE_WASAPI"
sourceFiles "source/soundio/wasapi.d"
sourceFiles "source/soundio/headers/wasapiheader.d"

libs "Ole32" // CoCreateInstance, CoTaskMemFree, PropVariantClear
}

configuration "dummy" {
sourceFiles "source/soundio/dummy.d" // redundant, but config can't be empty
}

configuration "jack" {
versions "SOUNDIO_HAVE_JACK"
sourceFiles "source/soundio/jack.d"
}

// Examples
subPackage {
name "sine"
targetPath "build"
targetType "executable"
sourcePaths
sourceFiles "examples/sio_sine.d"
dependency "libsoundio-d" version="*"
}

subPackage {
name "list-devices"
targetPath "build"
targetType "executable"
sourcePaths
sourceFiles "examples/sio_list_devices.d"
dependency "libsoundio-d" version="*"
}

subPackage {
name "record"
targetPath "build"
targetType "executable"
sourcePaths
sourceFiles "examples/sio_record.d"
dependency "libsoundio-d" version="*"
buildRequirements "allowWarnings" // statements after main-loop not reachable
}

subPackage {
name "microphone"
targetPath "build"
targetType "executable"
sourcePaths
sourceFiles "examples/sio_microphone.d"
dependency "libsoundio-d" version="*"
buildRequirements "allowWarnings" // statement after main-loop not reachable
}

// Tests
subPackage {
name "backend-disconnect-recover"
targetPath "build"
targetType "executable"
sourcePaths
sourceFiles "test/backend_disconnect_recover.d"
dependency "libsoundio-d" version="*"
}

subPackage {
name "latency"
targetPath "build"
targetType "executable"
sourcePaths
sourceFiles "test/latency.d"
dependency "libsoundio-d" version="*"
buildRequirements "allowWarnings" // statement after main-loop not reachable
}

subPackage {
name "overflow"
targetPath "build"
targetType "executable"
sourcePaths
sourceFiles "test/overflow.d"
dependency "libsoundio-d" version="*"
}

subPackage {
name "underflow"
targetPath "build"
targetType "executable"
sourcePaths
sourceFiles "test/underflow.d"
dependency "libsoundio-d" version="*"
}

subPackage {
name "unit-tests"
targetPath "build"
targetType "executable"
sourcePaths
sourceFiles "test/unit_tests.d"
dependency "libsoundio-d" version="*"
}
38 changes: 38 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

# Examples

These examples are translated from the original C examples, so they are not idiomatic D.

Note that the dub commands below should be executed from the root of the repository, not this examples folder.

### Sine

Plays a simple sine wave sound.
```
dub run libsoundio-d:sine
```

### List devices

Lists available input- and output devices.

Without the `--short` flag, it displays each device's id, which can be passed as an argument to the other examples to select an input/output device.
```
dub run libsoundio-d:list-devices
dub run libsoundio-d:list-devices -- --short
```

### Microphone

Reads from an input device (microphone) and pipe it to an output device (speaker / headphones).
Watch out that your microphone is not too close to the speaker or you might get a feedback loop.
```
dub run libsoundio-d:microphone -- --latency 0.05
```

### Record

Records sound from an input device and saves it as a binary file.
```
dub run libsoundio-d:record -- test.bin
```
Loading

0 comments on commit e99bc3b

Please sign in to comment.