Live Coding system in Kotlin for Ableton Live


Intro

k-Loops is a system for live-coding. It allows to use Kotlin as a tool for artistic expression.

k-Loops is free and open source although it relies on Ableton Live which is not free.

Principles

Use Powerful Language

k-Loops is developed in Kotlin - very powerful jvm-based programming language.

In you live coding you can you whole power of this language and supporting tools: you can abstract and reuse common functionality, you can use automatic refactoring, and code suggestions.

k-Loops is the only live-coding system developed in Kotlin and if you like this language you should give it a try.

Ableton Live as a Synth Backend

k-Loops is a system that allow algorithmically control Ableton Live: you can play any midi tracks and you can easily discover and change any controls in ableton

Ableton Live is a great backend for live coding system: it has hundreds of instruments and effects that are very high quality.

Vast majority of live coding systems integrate with SuperCollider synth, that is pretty outdated comparing with Live.

Focus on Midi Control

k-Loops's focus is control of midi instruments: i.e. working with samples is deprioritized.

Big reason for this is that Ableton Live itself is a great tool to work with samples: once sample is imported in simpler, sampler or drum rack it's easily available for k-loops

Focus on midi control allowed to make it really right.

Develop Right Abstractions

k-Loops is based on very few flexible and powerful low-level abstractions, such as triggers, playAsync, silence.

These abstraction are used as bricks to build more convinient high-level abstractions, such as patterns and sequences

Both types of abstractions are available to use you can use high-level abstraction to express very complex idea succinctly or you can use low-level abstraction to program music exactly how you want.

Examples

Synth-Pop

val runBackgroundTasks = startBackgroundTasks()

loop("main loop") {
    "c2 a2 c2 a2 e2 f2 c3 c3".toSeq().forEach { n ->
        if (n == "c3") triggerEvent("c3")
        else triggerEvent("c2")
        sequencer(_8th) {
            "k . sn . k k sn .".play(track("drums"), 1.0)
            "c3 g3 e3".play(track("keys 1"), 0.5)
            "$n . $n .".play(track("bass"), 1.0)
        }
    }
}

loop("hi hat") {
    silence(_8th)
    track("drums").play("ch", _4th, 0.5)
    triggerEvent("hat")
}

runWhenEvent("additional drums", listOf("hat")) {
    sequencer(_16th) {
        "co rm".play(track("drums"), 1.0)
    }
}

runWhenEvent("pads 1", listOf("c2")) {
    sequencer(_4th) {
        "e4  . . f4 ".play(track("pad"), velocity = 0.3, length = _q.dot())
    }
}

runWhenEvent("pads 2", listOf("c3")) {
    track("pad").playAsync("c4", _half, 0.1)
}
            
Polyrithmic Techno

val runBackgroundTasks = startBackgroundTasks()

loop("techno") {
    sequencer(_16th) {
        "k . co . cl . co co".play(track("drums"), velocity = 0.5)
        val bass2Length = listOf(2, 5, 7, 1, 3).look() o 64
        val velocity = listOf(0.2, 0.0, 0.1, 0.1).look()
        "a1 . . g1".play(track("bass"), velocity = velocity, length = bass2Length)
        val cutoff = triag(from = 0.01, to = 0.25, period = 12, t1 = 8)
        val mod = sine(from = 0.6, to = 0.7, period = 4, jitter = 0.1)
        val delay = trapezoid(from = 0.0, to = 1.0, period = 16 * 32, t1 = 7 * 16, t2 = 20 * 16)
        val midGain = rect(from = 0.5, to = 0.60, period = 8, phase = 0.5)
        master().device("master").parameter("mid gain").setValue(midGain)
        track("bass").parameter("mod").setValue(mod)
        track("bass").parameter("cutoff").setValue(cutoff)
        track("bass").sends("Delay").setValue(delay)
    }
}

loop("techno2") {
    sequencer(_16th) {
        setLoopVelocity(trapezoid(period = 16 * 16, t1 = 4 * 16))
        "k . . sn k . .".play(track("drums"), velocity = 0.7)
        ". . rd ch . .".play(track("drums"), velocity = 0.1, length = _32nd)
        "clave clave . . clave .".play(track("drums"), velocity = 0.5)
    }
}

loop("techno3") {
    sequencer(_16th) {
        setLoopVelocity(trapezoid(period = 16 * 16, t1 = 4 * 16, phase = 0.5))
        "mid . rm mid . .".play(track("drums"), velocity = 0.5)
        ". . sn sn . .".play(track("drums"), velocity = 0.5)
    }
}
            

More example can be found on Github!

Install

Install Ableton Live Trial and IntelliJ IDEA Community

Checkout k-Loops project from Github: https://github.com/Onuchin-Artem/k-Loops

In Ableton Live put k-loops_master on master track and k-loops_midi on every other track.

Open k-loops in IntelliJ. To launch kotlin REPL click ToolsKotlinKotlin REPL.

Run startBackgroundTasks(). You are ready to improvise!

Community