implement glot algorithm to voxbox

implement glot algorithm to voxbox

task id: implement-glot

2024-05-28 09:57: Hoping to start the glottis port today. #implement-glot

This is the algorithm I'd like to use: https://git.sr.ht/~pbatch/mnodes/tree/master/item/glot/glot.c.

2024-05-28 15:16: glot pre-setup: import wavwrite #implement-glot

This is hard for me because I don't actually know what the best practice is for organizing library code.

Found this: https://rust-classes.com/chapter_4_3

2024-05-29 09:43: Some initial work on glottis scaffolding #implement-glot

2024-05-30 09:25: Didn't complete this yesterday. Completing today. #implement-glot

2024-05-30 09:32: Building glot initializer #implement-glot

Struct initialization feels like a pain point to me.

2024-05-30 09:55: HP/LP filter uses similar struct, how to do inheritance like things? #implement-glot

Using this as a learning opportunity.

Okay, looks like I want to implement a filter as a trait. See: <<rust/books/rust_by_example/traits>> and <<rust/books/rust_book/traits>>.

2024-05-30 10:12: Trying to get traits to work is premature optimization and too much time, making a new task for it. #implement-glot #refactor-glotfilt-traits

I want to set aside some time to actually do this right. It's not quite fitting in my head at the moment, and I need to keep moving forward. Ultimately, what we want is to be able to have a nice way to define two two types: highpass and lowpass, which are two types that use identical data structs but slightly different methods.

I imagine it'll be pretty trivial to return and refactor. So far, this has been my experience with Rust.

2024-05-30 10:16: Back to Butterworth porting #implement-glot

These are needed to filter the noise source in the glottal model.

2024-05-30 10:18: Oh wait, I implemented the butterworth filter in boing^3 #implement-glot

I'll just copy that over. duh.

2024-05-30 10:23: Ugh, how do I use modules locally? need a refresher. #implement-glot

Revisiting <<rust/organizing_code_project_structure>>.

Here is the winning code block for imports.

use crate::butterworth::{ButterworthLowPass, ButterworthHighPass};

Also needed to make sure that lib.rs had butterworth imported too.

2024-05-30 10:36: Back to filling out rest of the glot struct #implement-glot

I will need to return to implement the highpass filter.

2024-05-30 10:45: implement setup_waveform #implement-glot

2024-05-30 11:02: implement hanning table #implement-glot

2024-05-30 11:06: implement highpass #implement-glot

2024-05-30 11:09: initializer done. now some of the smaller methods #implement-glot

2024-05-30 11:15: Port tick function. #implement-glot

2024-05-30 11:30: I think there's enough in place for some initial sound #implement-glot

2024-05-30 11:37: Uh oh, it panicked. #implement-glot

There was an attempt to multiply with overflow. It seems to be a problem with the RNG.

disabling noise source for now.

2024-05-30 11:40: No sound. Debugging in my future. #implement-glot

2024-05-30 11:55: troubleshooting: why isn't there any sound? #implement-glot

Here is the debug script:

rm -f glot_simple.wav
cargo run --example glot_simple
mnolth wavdraw glot_simple.wav glot_simple.pbm

ah. I didn't finish setup_waveform()

2024-05-30 13:11: Line by line checking with reference #implement-glot

I will log as I go.

setup_waveform: found multiply that should have been add. otherwise, it looks okay.

settuptable looks good. -- rest of initializer looks good. -- tick(): I messed up most of the exp function translations. Rust has a weird notation for this. instead of exp(x), rust does x.exp().

2024-05-30 14:00: final thoughts #implement-glot

I have finished porting the glottal source component of my singing synthesizer from C to Rust. It was a bit of a tedious effort, but luckily the setbacks were small.

The port can be found here: https://github.com/PaulBatchelor/voxbox/blob/main/src/glot.rs.

Sample code writing to WAV file: https://github.com/PaulBatchelor/voxbox/blob/main/examples/glot_simple.rs.

This implements a glottal source model based on the one described by Hui-Ling Lu in their dissertation. It includes a version of the LF glottal flow derivative waveform model (based off an implementation by Neil Thapen of Pink Trombone), as well as a synchronous pulsed noise component for breathiness and aspiration.

On the first pass manually translating C to Rust, I ran into some issues. Most of the issues ended up being related to the way Rust handles math functions. Instead of doing something like exp(x) like you'd expect, Rust tends to use notation like x.exp(), and I messed up the notation.

By itself, the glottal source component sounds pretty unremarkable. It will need a tract filter before it starts to sound talky.