Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Test
on:
pull_request:
push:
branches: [master]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
linux:
name: Linux tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '17'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Cache Kotlin/Native toolchain
uses: actions/cache@v4
with:
path: ~/.konan
key: konan-${{ runner.os }}-${{ hashFiles('gradle/libs.versions.toml') }}

# The shared tests (src/commonTest) built for linuxX64 and run natively: same TinySoundFont
# and stb_vorbis code as every other target, without an Android emulator.
- name: Run tests
run: ./gradlew :soundfont:linuxX64Test

- name: Upload test reports
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-reports
path: soundfont/build/reports/tests/
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![GitHub License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0)

Library for [sample-based synthesis](https://en.wikipedia.org/wiki/Sample-based_synthesis "Sample-based synthesis") to generate audio data.
The library allows to load `.sf2` files from memory. Is basically a KMP wrapper around [TinySoundFont](https://github.com/schellingb/TinySoundFont) library.
The library allows to load `.sf2` and `.sf3` files from memory. Is basically a KMP wrapper around [TinySoundFont](https://github.com/schellingb/TinySoundFont) library.

The goal of this library is to allow operations on .sf2 files and generating audio in Kotlin Multiplatform projects.
The library has `batteries-included` so no configuration is required.
Expand Down Expand Up @@ -35,7 +35,7 @@ mikrosoundfont = { module = "io.github.lemcoder.mikrosoundfont:soundfont", versi
___
### Usage
```
val sfBuffer // .sf2 file bytes
val sfBuffer // .sf2 or .sf3 file bytes

MikroSoundFont.load(sfBuffer).use { soundFont ->
// .. use soundFont to generate audio data
Expand All @@ -44,6 +44,19 @@ MikroSoundFont.load(sfBuffer).use { soundFont ->

A `SoundFont` holds its samples in native memory until `close()` is called, so close it (or load it in `use { }`) when you are done with it.

#### SF3 files
`.sf3` files store their samples compressed with Ogg Vorbis. `load` decodes all of them up front, so:
* loading takes noticeably longer than an `.sf2` of the same size (seconds for a large font on a phone), so load off the main thread;
* the loaded `SoundFont` takes several times the file size in memory, as the samples are kept decoded.

Decoding uses [stb_vorbis](https://github.com/nothings/stb), which is not hardened against malformed data, so only load `.sf3` files you trust.

## Testing

The tests in `soundfont/src/commonTest` load an `.sf2` and an `.sf3` font and render audio through the native library:
* `./gradlew :soundfont:linuxX64Test` or `:soundfont:macosArm64Test` runs them on the host (CI runs the Linux ones on every pull request);
* `./gradlew :soundfont:connectedAndroidDeviceTest` runs them on a connected Android device or emulator.

## License

This project is licensed under the Apache 2.0 License - see the [LICENSE.md](LICENSE.md) file for details
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ maven-publish = "0.37.0"
konanplugin = "2.0.0-alpha05"

[libraries]
androidx-test-runner = { module = "androidx.test:runner", version = "1.6.2" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }

[plugins]
Expand Down
Empty file modified gradlew
100644 → 100755
Empty file.
4 changes: 3 additions & 1 deletion native/include/tsf/tsfCInterop.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

LICENSE (MIT)

Copyright (C) 2017-2023 Bernhard Schelling
Copyright (C) 2017-2025 Bernhard Schelling
Based on SFZero, Copyright (C) 2012 Steve Folta (https://github.com/stevefolta/SFZero)

Permission is hereby granted, free of charge, to any person obtaining a copy of this
Expand Down Expand Up @@ -185,6 +185,7 @@ TSFDEF void tsf_render_float(tsf* f, float* buffer, int samples, int flag_mixing
// pitch_wheel: pitch wheel position 0 to 16383 (default 8192 unpitched)
// pitch_range: range of the pitch wheel in semitones (default 2.0, total +/- 2 semitones)
// tuning: tuning of all playing voices in semitones (default 0.0, standard (A440) tuning)
// flag_sustain: 0 to end notes that were held sustained and disable holding sustain otherwise enable it
// (tsf_set_preset_number and set_bank_preset return 0 if preset does not exist, otherwise 1)
// (tsf_channel_set_... return 0 if a new channel needed allocation and that failed, otherwise 1)
TSFDEF int tsf_channel_set_presetindex(tsf* f, int channel, int preset_index);
Expand All @@ -196,6 +197,7 @@ TSFDEF int tsf_channel_set_volume(tsf* f, int channel, float volume);
TSFDEF int tsf_channel_set_pitchwheel(tsf* f, int channel, int pitch_wheel);
TSFDEF int tsf_channel_set_pitchrange(tsf* f, int channel, float pitch_range);
TSFDEF int tsf_channel_set_tuning(tsf* f, int channel, float tuning);
TSFDEF int tsf_channel_set_sustain(tsf* f, int channel, int flag_sustain);

// Start or stop playing notes on a channel (needs channel preset to be set)
// channel: channel number
Expand Down
Loading
Loading