You are browsing as a guest. Sign up (or log in) to start making projects!

hatya-mouse

@hatya-mouse

Joined May 31st, 2026

  • 30Devlogs
  • 7Projects
  • 3Ships
  • 48Votes
16yo Japanese Kosen student fascinated with Rust.
Ship Changes requested

Kadent

Kadent is a cross-platform DAW featuring KASL, a domain-specific audio language, and node-graph processing system.

Features

  • Create music with familiar track-based UI
  • Two track types: Note Track & Audio Track
  • Node graph for every track
  • KASL language with syntax similar to Swift
    The node graph allows you to combine multiple KASL programs to perform much more complex processing.

What Is a Node Graph?

Kadent uses node graph for track processing.

A Node is a processing unit that calculates the output. In node graph, an output of one node can be connected to an input of another node. This allows you to connect multiple inputs and outputs freely to other nodes to create sound.

Then, why did I adopt node graph? KASL programs can have multiple inputs and outputs, and their types may also vary. So placing them in order does not work because the DAW cannot know which output is connected to the specific input. That’s why Kadent uses node graph.

Characteristics of KASL

  • Utilizes Cranelift as a backend for quicker JIT compilation
  • Specialized type of variables such as input, output and state
  • Supports fixed-length arrays and structs
  • Fixed-count loop syntax for predictable execution time
  • Module system influenced by Python
  • Custom infix/prefix/postfix operators (even normal arithmetic operators are defined and provided by std)

KASL Sample Program

audio module is built-in module provided by Kadent. Note that these programs below won’t work outside the DAW.

Gain Node

import audio
import std

input in = audio.zero_sample()
input gain = 0.0
output out = audio.zero_sample()

func main() {
    out = in * [gain; audio.max_channels]
}

Mix Node

import std
import std/math/float as f
import audio

input input_1 = audio.zero_sample()
input input_2 = audio.zero_sample()
input factor = 0.0
output out = audio.zero_sample()

func main() {
    let clamped_factor = f.clamp(factor, 0.0, 1.0)
    let multiplied_input_1: audio.Sample = input_1 * [clamped_factor; audio.max_channels]
    let multiplied_input_2: audio.Sample = input_2 * [1.0 - clamped_factor; audio.max_channels]
    out = multiplied_input_1 + multiplied_input_2
}

Sawtooth Wave Synthesizer

import audio as a
import std
import std/math/float as f

input notes = a.EventSlot()
input pitch = 1.0
output out = a.zero_sample()
state allocator = a.Allocator()

let base_freq = 440.0
let volume = 0.1

func main() {
    allocator.update(notes)

    var i = 0
    loop a.max_voices {
        let voice = allocator.voices[i]
        let freq = pitch * base_freq * f.pow(2.0, (voice.pitch - 69.0) / 12.0)

        if voice.is_active {
            let t = voice.age

            let sample = saw(freq: freq, time: t)
            out = out + [sample * volume; a.max_channels]
        }
        i = i + 1
    }
}

func saw(freq f = 440.0, time t: Float) -> Float {
    return 2.0 * (t * f) % 1.0 - 1.0
}

Installation

Go to the Releases page of my GitHub repository to download the latest precompiled binary, or compile the binary yourself. Detailed installation steps are described in README.

  • 23 devlogs
  • 229h
Try project → See source code →
Open comments for this post

17h 10m 49s logged

Added License Browser

It’s been a while since my last devlog!
During this time I’ve added an Acknowledgements view where you can look at license text and other informations of the Fonts and Crates that I’ve used.
It was a bit difficult to implement because there are so many crates, but I’m satisfied with the result.

0
0
36
Open comments for this post

41h 27m 13s logged

Improved code editor

I’ve implemented error highlighting in the code editor. I also added a list of errors at the bottom of the code editor, and I can jump to the position of the error by clicking the error.

TextEdit in egui does not support highlighting character by character and instead it only highlighting by each sections, so red underlined part may be bigger than the actual error range, but I guess it still looks nice.

0
0
6
Open comments for this post

10h 56m 7s logged

sode

I’ve created a simple binary serialization crate called “sode” for Kadent. This guarantees that the output binary won’t change even if the struct is modified so I thought it would be better than serde or that sort of serialization library.

impl Encode for Note {
    fn encode(&self, e: &mut Encoder) -> Result<(), EncodeError> {
        e.field(0, &self.start)?;
        e.field(1, &self.duration)?;
        e.field(2, &self.pitch)?;
        e.field(3, &self.velocity)?;
        Ok(())
    }
}

impl Decode for Note {
    fn decode(d: &mut ValueDecoder) -> Result<Self, DecodeError> {
        let d = d.to_field_decoder()?;
        Ok(Note::new(
            d.field(0)?.ok_or(DecodeError::InvalidData)?,
            d.field(1)?.ok_or(DecodeError::InvalidData)?,
            d.field(2)?.ok_or(DecodeError::InvalidData)?,
            d.field(3)?.ok_or(DecodeError::InvalidData)?,
        ))
    }
}
0
0
9
Open comments for this post

4h 21m 24s logged

Curve type selection

I’ve implemented a selection dropdown for three curve types: linear, step, and smooth. Next thing to do is to add a text field to adjust the curve tension

0
0
4
Open comments for this post

8h 42m 10s logged

Automation

Automation is here.
I’ve implemented an automation node, which is associated with an automation track that you can add keyframes to value that changes over time.
You can even connect automation nodes to KASL Node to use the value for calculation!

0
0
7
Open comments for this post

4h 53m 20s logged

Refactored codebase

It looks exactly the same as the previous devlog, but I refactored the codebase, primarily the EditorUiState. I separated many members of EditorUiState to multiple small structs for better readability

0
0
4
Open comments for this post

7h 9m 51s logged

Added ruler to piano roll

I’ve added the ruler to the piano roll. This will make note placement easier and more intuitive than before.

Also I refactored the codebase a little bit, but honestly I thought the previous implementation would be better so I may be putting it back soon.

0
0
7
Open comments for this post

11h 52m 17s logged

Add seconds support for region placement

I’ve added TimePosition and TimeBounds to store the position of the region. They have two modes: one stores the position in Ticks, and another one stores it in seconds. Ticks and seconds can be calculated from each other using TempoMap.

0
0
17
Open comments for this post

11h 30m 28s logged

On-demamd resampling for audio tracks

Audio regions require resampling because the sample rate of the source data may differ from the required sample rate.
So far, the audio engine for Kadent has been resampling the entire audio data before playback or exporting. However, resampling audio data in advance takes a lot of CPU and increases the time it takes to prepare for playback.
This time I made it resample the audio data on demand during playback. This makes audio thread not to store the massive resampled audio data.

*sample rate: a value that indicates how many samples are in a single second
*sample: a value that represents the sound wave’s loudness at a specific moment in time

0
0
22
Open comments for this post

49h 7m 14s logged

Waveform Rendering & Scroll Bar

This time, I’ve mainly implemented two features: waveform rendering and timeline scroll bar.

Waveform

I’ve added a waveform rendering logic to the timeline. I handled it by generating peak value data to render it quicker than calculating the peak value while rendering.
After all, it looks pretty nice and scales perfectly when zooming with my trackpad.

Timeline Scroll Bar

Another feature I’ve added is a timeline scroll bar. It may not look appealing, but its calculation was quite hard actually. I had to calculate the ratio of the visible area and the entire timeline to get the width of the scroll bar. I think it is lot better than egui’s builtin scroll bar, so I’m quite satisfied with the outcome!

0
0
7
Open comments for this post

12h 5m 5s logged

Quantum Learning JP

I started translating the IBM Quantum Learning resource into Japanese. Because the resources are licensed under CC BY-SA 4.0, I can translate them and publish as long as I license the translation under CC BY-SA 4.0.

Some Improvements

Not only I translated the documents, but also I added some interactive Python exercises so that they can learn without friction.

0
0
10
Open comments for this post

1h 59m 17s logged

Ability to adjust project range

I’ve implemented a feature that the user can adjust the project’s export range just by dragging the handle in the ruler.

Also the actual number is shown in the status bar while the handle is being dragged so the user can know the exact beat where is going to be exported.

0
0
1
Open comments for this post

23h 45m 8s logged

Refactored the audio engine

I’ve streamlined the note processing logic in the audio engine. So far, the audio engine handled sequenced notes (notes that you can see in the editor) and the realtime MIDI notes that you can play using some MIDI controllers differently. It also lacked maintainability.

That’s why I’ve completely rebuilt the logic to unify the process. It also contributed to reduce the amount of code, and I’m happy with that.

0
0
1
Open comments for this post

3h 1m 50s logged

Added Status Bar

I’ve added a new status bar, which shows some informations such as sample rate, buffer size and the selected content, at the bottom of the window.

Fixed Node Graph Rendering Bug

The node graph used to be rendered on the front of the header, but I finally fixed this by using Panel to limit the area where painter can draw the graph.

0
0
3
Open comments for this post

7h 7m 57s logged

Improved menu design

I’ve improved the design of the menu by adjusting the button style. It took quite a long time because of egui’s a little bit confusing styling API.

Refactor and optimize the audio engine

I’ve refactored the audio engine by using integer ticks to manage time instead of f32 beats. By using integer ticks, it can be calculated even faster and more accurately.

0
0
4
Open comments for this post

1h 11m 26s logged

Nested dropdown menu for device selection

I’ve improved a device selection feature by nesting the menu. Thanks to this, users can click a single headphones button to change the MIDI ports and output devices.
Also I added some icons for these.

0
0
2
Open comments for this post

1h 12m 42s logged

Selectable audio output

I’ve added a feature to select audio output! It may seem simple but it actually needed refactoring the audio engine and it took a lot of time.

0
0
2
Open comments for this post

2h 26m logged

Replacing audio stream when switching devices

I’ve implemented a logic in the audio engine, that allows the Kadent DAW to switch the output device.
It was challenging because Mixer and MPSC consumers cannot be cloned. Finally I used Arc and Mutex in order to share the context with multiple threads.

let callback_ctx = Arc::new(Mutex::new(OutputCallbackContext {
        mixer,
        command_cons,
        midi_cons,
        vu_prod,
        pending_project: pending_arc,
    }));

I used try_lock instead of normal lock, which may block the thread, as you can see in the screenshot.

0
0
1
Open comments for this post

5h 39m 19s logged

KASL module system improvement

So far, KASL compiler didn’t allow us to import external programs with the same name, because the name of the namespace conflicts. Today I have added new alias feature, which can be used like this:

import foo as bar

With this syntax, you can import a program named foo.kasl and refer to it with bar.
This can also improve readability when importing a file with a long name!

Streamline compilation

I wanted to try compiling Kadent to application that can be installed using an installer, instead of a simple executable binary. I found Taskfile, which is a build tool similar to make but uses a yaml file to define workflows. I found it very useful so I adopted it and it worked very well! Currently I only have workflow for macOS compilation but I want to add Windows and Linux support soon!

0
0
1
Loading more…

Followers

Loading…