Skip to content

Commit

Permalink
switched to alsa-javacpp and bring in alsakt here.
Browse files Browse the repository at this point in the history
alsa-javacpp strips out Kotlin deps.
Maybe we can even remove dependency on Gradle. Less Gradle, more happiness.

alsakt OO wrapper now resides in this repo instead. It would also be easier
to bring in UMP based stuff without dealing with frequent versioning hassle.

Brought back swing coroutines backend, desktop on linux crashes without it.
No idea why it was working on mac though - ran on stale dep file?
  • Loading branch information
atsushieno committed Jun 5, 2024
1 parent 2590dd6 commit 200c812
Show file tree
Hide file tree
Showing 12 changed files with 1,104 additions and 3 deletions.
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ ktor-io = "2.3.11"
mpfilepicker = "3.1.0"
gradle-javacpp = "1.5.10"

alsakt = "0.3.5"
alsa-javacpp = "0.1.0"
rtmidi-javacpp = "0.1.5"

[libraries]
Expand All @@ -42,7 +42,7 @@ compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }

alsakt = { module = "dev.atsushieno:alsakt", version.ref = "alsakt" }
alsa-javacpp = { module = "dev.atsushieno:alsa-javacpp", version.ref = "alsa-javacpp" }
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit-jupiter-api" }
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter-api" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
Expand Down
1 change: 1 addition & 0 deletions ktmidi-ci-tool/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ kotlin {
implementation(libs.mpfilepicker)
// without this, jnirtmidi.so will not be found at runtime.
api(libs.rtmidi.javacpp.platform)
implementation(libs.kotlinx.coroutines.swing)
}

val iosMain by creating {
Expand Down
2 changes: 1 addition & 1 deletion ktmidi-jvm-desktop/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ kotlin {
val commonMain by getting {
dependencies {
implementation(project(":ktmidi"))
implementation(libs.alsakt)
implementation(libs.alsa.javacpp)
api(libs.rtmidi.javacpp)

implementation(libs.kotlinx.coroutines.core)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
@file:Suppress("unused")

package dev.atsushieno.alsakt

import dev.atsushieno.alsa.javacpp.global.Alsa
import dev.atsushieno.alsa.javacpp.snd_seq_client_info_t
import org.bytedeco.javacpp.BytePointer

class AlsaClientInfo : AutoCloseable {
companion object {
private fun malloc(): snd_seq_client_info_t? {
val outHandle = snd_seq_client_info_t()
Alsa.snd_seq_client_info_malloc(outHandle)
return outHandle
}

private fun free(handle: snd_seq_client_info_t?) {
if (handle != null)
Alsa.snd_seq_client_info_free(handle)
}

}

constructor () : this (malloc (), { handle -> free(handle) })

constructor (handle: snd_seq_client_info_t?, free: (snd_seq_client_info_t?) -> Unit) {
this.handle = handle
this.freeFunc = free
}

internal var handle: snd_seq_client_info_t?//Pointer<snd_seq_client_info_t>
private val freeFunc: (snd_seq_client_info_t?) -> Unit

override fun close () {
namePtr?.deallocate()
namePtr = null
if (handle != null) {
freeFunc(handle)
handle = null
}
}

var client: Int
get() = Alsa.snd_seq_client_info_get_client (handle)
set(value) = Alsa.snd_seq_client_info_set_client (handle, value)

val clientType: Int
get () = Alsa.snd_seq_client_info_get_type (handle)

private var namePtr: BytePointer? = null
var name: String
get() = Alsa.snd_seq_client_info_get_name (handle).string
set(value) {
namePtr?.deallocate()
namePtr = BytePointer(value)
Alsa.snd_seq_client_info_set_name(handle, namePtr)
}

var broadcastFilter: Int
get() = Alsa.snd_seq_client_info_get_broadcast_filter (handle)
set(value) = Alsa.snd_seq_client_info_set_broadcast_filter (handle, value)

var errorBounce: Int
get() = Alsa.snd_seq_client_info_get_error_bounce (handle)
set(value) = Alsa.snd_seq_client_info_set_error_bounce (handle, value)

val card : Int
get() = Alsa.snd_seq_client_info_get_card (handle)
val pid :Int
get() = Alsa.snd_seq_client_info_get_pid (handle)
val portCount: Int
get() = Alsa.snd_seq_client_info_get_num_ports (handle)
val eventLostCount : Int
get() = Alsa.snd_seq_client_info_get_event_lost (handle)

private val midiVersionAvailable =
AlsaVersion.major >=1 &&
AlsaVersion.minor >=2 &&
AlsaVersion.revision >= 10
var midiVersion : Int
get() = if (midiVersionAvailable) Alsa.snd_seq_client_info_get_midi_version(handle) else 0
set(value) {
if (midiVersionAvailable)
Alsa.snd_seq_client_info_set_midi_version(handle, value)
}

val umpConversion : Int
get() = Alsa.snd_seq_client_info_get_ump_conversion(handle)

var isUmpGrouplessEnabled : Boolean
get() = Alsa.snd_seq_client_info_get_ump_groupless_enabled(handle) != 0
set(value) = Alsa.snd_seq_client_info_set_ump_groupless_enabled(handle, if (value) 1 else 0)

fun clearEventFilter () = Alsa.snd_seq_client_info_event_filter_clear (handle)
fun addEventFilter ( eventType: Int) = Alsa.snd_seq_client_info_event_filter_add (handle, eventType)
fun deleteEventFilter ( eventType: Int) = Alsa.snd_seq_client_info_event_filter_del (handle, eventType)
fun isEventFiltered ( eventType: Int) = Alsa.snd_seq_client_info_event_filter_check (handle, eventType) > 0
fun isUmpGroupEnabled(group: Int) = Alsa.snd_seq_client_info_get_ump_group_enabled(handle, group) != 0
fun setUmpGroupEnabled(group: Int, enabled: Boolean) = Alsa.snd_seq_client_info_set_ump_group_enabled(handle, group, if (enabled) 1 else 0)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.atsushieno.alsakt

import dev.atsushieno.alsa.javacpp.global.Alsa

class AlsaException : Exception {
constructor() : super("ALSA error")
constructor(errorCode: Int) : super("ALSA error: ${Alsa.snd_strerror(errorCode).string} (error code $errorCode)")
constructor(msg: String?) : super(msg)

constructor(msg: String?, innerException: Exception?) : super(msg, innerException)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
@file:Suppress("unused")

package dev.atsushieno.alsakt
import dev.atsushieno.alsa.javacpp.global.Alsa
import dev.atsushieno.alsa.javacpp.snd_seq_port_info_t
import org.bytedeco.javacpp.BytePointer

class AlsaPortInfo : AutoCloseable {
companion object {
const val PortSystemTimer = 0
const val PortSystemAnnouncement = 1

private fun malloc(): snd_seq_port_info_t? {
val outHandle = snd_seq_port_info_t()
Alsa.snd_seq_port_info_malloc(outHandle)
return outHandle
}

private fun free(handle: snd_seq_port_info_t?) {
if (handle != null)
Alsa.snd_seq_port_info_free(handle)
}
}

constructor () : this(malloc(), { handle -> free(handle) })

constructor (handle: snd_seq_port_info_t?, port: Int) {
this.handle = handle
this.freeFunc = {}
}

constructor (handle: snd_seq_port_info_t?, free: (snd_seq_port_info_t?) -> Unit) {
this.handle = handle
this.freeFunc = free
}

internal var handle: snd_seq_port_info_t?//Pointer<snd_seq_port_info_t>
private val freeFunc: (snd_seq_port_info_t?) -> Unit

override fun close() {
namePtr?.deallocate()
namePtr = null
if (handle != null)
freeFunc(handle)
handle = null
}

fun clone(): AlsaPortInfo {
val ret = AlsaPortInfo()
Alsa.snd_seq_port_info_copy(ret.handle, handle)
return ret
}

var client: Int
get() = Alsa.snd_seq_port_info_get_client(handle)
set(value) = Alsa.snd_seq_port_info_set_client(handle, value)

var port: Int
get() = Alsa.snd_seq_port_info_get_port(handle)
set(value) = Alsa.snd_seq_port_info_set_port(handle, value)

private var namePtr: BytePointer? = null
var name: String
get() = Alsa.snd_seq_port_info_get_name(handle).string
set(value) {
namePtr?.deallocate()
namePtr = BytePointer(value)
Alsa.snd_seq_port_info_set_name(handle, namePtr)
}

var capabilities: Int
get() = Alsa.snd_seq_port_info_get_capability (handle)
set(value) = Alsa.snd_seq_port_info_set_capability(handle, value)

var portType: Int
get() = Alsa.snd_seq_port_info_get_type (handle)
set(value) = Alsa.snd_seq_port_info_set_type(handle, value)

var midiChannels: Int
get() = Alsa.snd_seq_port_info_get_midi_channels(handle)
set(value) = Alsa.snd_seq_port_info_set_midi_channels(handle, value)

var midiVoices: Int
get() = Alsa.snd_seq_port_info_get_midi_voices(handle)
set(value) = Alsa.snd_seq_port_info_set_midi_voices(handle, value)

var synthVoices: Int
get() = Alsa.snd_seq_port_info_get_synth_voices(handle)
set(value) = Alsa.snd_seq_port_info_set_synth_voices(handle, value)

val readSubscriptions
get() = Alsa.snd_seq_port_info_get_read_use(handle)

val writeSubscriptions
get() = Alsa.snd_seq_port_info_get_write_use(handle)

var portSpecified
get() = Alsa.snd_seq_port_info_get_port_specified(handle) > 0
set(value) = Alsa.snd_seq_port_info_set_port_specified(handle, if (value) 1 else 0)

var timestampQueue: Int
get() = Alsa.snd_seq_port_info_get_timestamp_queue(handle)
set(value) = Alsa.snd_seq_port_info_set_timestamp_queue(handle, value)

var timestampReal: Int
get() = Alsa.snd_seq_port_info_get_timestamp_real(handle)
set(value) = Alsa.snd_seq_port_info_set_timestamp_real(handle, value)

var timestamping: Boolean
get() = Alsa.snd_seq_port_info_get_timestamping(handle) != 0
set(value) = Alsa.snd_seq_port_info_set_timestamping(handle, if (value) 1 else 0)

val id: String
get() = "${client}_${port}"

val manufacturer = "" // FIXME: implement

val version = "" // FIXME: implement

var direction: Int
get() = Alsa.snd_seq_port_info_get_direction(handle)
set(value) = Alsa.snd_seq_port_info_set_direction(handle, value)

var umpGroup: Int
get() = Alsa.snd_seq_port_info_get_ump_group(handle)
set(value) = Alsa.snd_seq_port_info_set_ump_group(handle, value)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package dev.atsushieno.alsakt
import dev.atsushieno.alsa.javacpp.global.Alsa
import dev.atsushieno.alsa.javacpp.snd_seq_addr_t
import dev.atsushieno.alsa.javacpp.snd_seq_port_subscribe_t

class AlsaPortSubscription {
class Address(val handle: snd_seq_addr_t?) {

var client: Byte
get() = handle?.asByteBuffer()?.get(0) ?: 0
set(value) {
handle?.asByteBuffer()?.put(value)
}


var port: Byte
get() = handle?.asByteBuffer()?.get(1) ?: 0
set(value) {
handle?.asByteBuffer()?.put(1, value)
}


override fun toString(): String {
return "ch${client}_port${port}"
}
}

companion object {
fun malloc(): snd_seq_port_subscribe_t? {
val outHandle = snd_seq_port_subscribe_t()
Alsa.snd_seq_port_subscribe_malloc(outHandle)
return outHandle
}

fun free(handle: snd_seq_port_subscribe_t?) {
if (handle != null)
Alsa.snd_seq_port_subscribe_free(handle)
}
}


constructor () : this(malloc(), { handle -> free(handle) })

constructor (handle: snd_seq_port_subscribe_t?, free: (snd_seq_port_subscribe_t?) -> Unit) {
this.handle = handle
this.freeFunc = free
}

var handle: snd_seq_port_subscribe_t? // Pointer<snd_seq_port_subscribe_t>
private val freeFunc: (snd_seq_port_subscribe_t?) -> Unit

fun close() {
if (handle != null)
freeFunc(handle)
handle = null
}

var sender: Address
get() = Address(Alsa.snd_seq_port_subscribe_get_sender(handle))
set(value) = Alsa.snd_seq_port_subscribe_set_sender(handle, value.handle)

var destination: Address
get() = Address(Alsa.snd_seq_port_subscribe_get_dest(handle))
set(value) = Alsa.snd_seq_port_subscribe_set_dest(handle, value.handle)


var queue: Int
get() = Alsa.snd_seq_port_subscribe_get_queue(handle)
set(value) = Alsa.snd_seq_port_subscribe_set_queue(handle, value)

var exclusive: Boolean
get() = Alsa.snd_seq_port_subscribe_get_exclusive(handle) != 0
set(value) = Alsa.snd_seq_port_subscribe_set_exclusive(handle, if (value) 1 else 0)

var updateTime: Boolean
get() = Alsa.snd_seq_port_subscribe_get_time_update(handle) != 0
set(value) = Alsa.snd_seq_port_subscribe_set_time_update(handle, if (value) 1 else 0)

var isRealTimeUpdateMode: Boolean
get() = Alsa.snd_seq_port_subscribe_get_time_real(handle) != 0
set(value) = Alsa.snd_seq_port_subscribe_set_time_real(handle, if (value) 1 else 0)
}
Loading

0 comments on commit 200c812

Please sign in to comment.