Create "trio" demo
task id: demo-trio2024-07-12 08:58: This concept feels pretty fleshed out #concept-concerto #demo-trio
2024-07-12 08:59: First step in trio: get instantaneous chords #demo-trio
2024-07-12 12:21: Initial boilerplate code, maybe some chords #demo-trio #timelog:01:33:13
2024-07-12 12:22: make copy of the singer test. #demo-trio
2024-07-12 12:36: getting the pitch control happening in rust instead of C #demo-trio
2024-07-12 12:51: time for initial chord logic? #demo-trio
For now: given a pitch (octave-wrapped, 0-11), find the corresponding triad. Use a lookup table (vector, probably).
2024-07-12 12:54: consolidate voice into struct #demo-trio
2024-07-12 13:05: two intial instances #demo-trio
2024-07-12 13:16: initial chord look-up table #demo-trio
2024-07-12 13:51: initial chord logic works! #demo-trio
I'm going to need to rework this to make it work with gesture and chords, but this is a good start.
2024-07-12 13:56: changing the smooth times makes a HUGE difference wow #demo-trio
2024-07-18 08:39: complete in theory. time to test in trio demo. #event-driven-gesture #demo-trio
Attempt voice staggering using event-driven gesture algorithm, see what goes wrong.
2024-07-18 12:35: Time to revisit the trio. #demo-trio #timelog:03:01:06
Now that I supposedly have an event-driven gesture, I need to begin work incorporating those mechanics into the existing demo.
2024-07-18 12:36: refamiliarizing myself with the work. #demo-trio
2024-07-18 13:00: light refactoring. main clock added. #demo-trio
Now, for the initial process of introducing these eventful gestures.
Before any events can be added to any gestures, we need to be able to simulate adding events. Events should only be added after the lead has held onto a pitch for one period.
The easiest way to do this using a global timer that keeps track the phasor ticks, which occur once a second. If a u32 is used, how many seconds is that?
Okay, so that's about a millenium short of 50k years. I think there's no general risk of things overflowing. I will be long dead and forgotten before that happens to a potential user.
Is this enough granularity though if I want to detect pitch changes? Maybe not actually.
2024-07-18 13:11: How to tell if pitch has lasted for a period. #demo-trio
Might need to ink this one out.
2024-07-18 13:27: Inked out an idea #demo-trio
First, implement things so that it detects changes in pitch. Then, build a sample and hold with along with a global monotonically increasing clock that increments at the start of every tick.
Now, any time a pitch change occurs in the lead, it can be compared against the sampled pitch. If the pitch is different, but the timestamps aren't, the whole period is marked as having been changed for the rest of the period.
The "dirty bit" trick is used in situations where the pitch changes quickly inside a period.
2024-07-18 13:32: Implementing pitch changes, alert on change. #demo-trio
2024-07-18 13:37: implementing clock and sample and hold #demo-trio
2024-07-18 13:50: shoot. I'm actually unable to articulate when a change *should* happen #demo-trio
I think there may be another state required.
How about this: If there has been a requested pitch change from the current lead pitch, and this request has been held for a period, apply this changed pitch to the current lead.
This should happen at the start of every period.
2024-07-18 14:05: well, now my logic isn't working at all. #demo-trio
I was setting things to be negative oops.
2024-07-18 14:11: this timing logic is trickier than I expected #demo-trio
2024-07-18 14:15: Going to try caching the lead value between takes. #demo-trio
Caching the lead value and also storing the last changed value may be what I'm looking for.
Essentially, this lead value needs ot be updated regardeless, but the other two voices need to be delayed.
2024-07-18 14:19: Okay, the complexity comes from the lead value needing to be updated #demo-trio
I can't simply cache the last lead pitch every time because I'm setting it every time.
2024-07-18 14:23: The delayed behavior works as expected now. #demo-trio
Now I am looking to delay chord changes on the upper/lower voices.
2024-07-18 14:28: I think I might be able to work staggering without gesture #demo-trio
I think I'm going to have to do this anyways because the event scheduler in the eventful gesture is so small, and can really only take one vertice at a time.
2024-07-18 14:34: reworking things for variable stagger times #demo-trio
The logic would need to be: lower gets set first, then upper.
Initially I had it so that the chord would be determined, and then you'd send off the events with delays. Rethinking this a bit.
I want it so that the upper pitch only changes if it waits 2 beats, and the lower pitch changes if it waits 1 beat.
2024-07-18 14:48: I'm going to try having another state variable #demo-trio
I want to have a state when the lower changed, but the upper hasn't. When the upper gets changed, the lower changed gets setup.
2024-07-18 15:01: Now I want the voices to be staggered on too #demo-trio
2024-07-18 15:08: Weird timing bugs #demo-trio
2024-07-18 15:14: Try to reset clock on new voice. #demo-trio
2024-07-18 15:34: Clock works, but the voices aren't resetting pitches #demo-trio
This causes some very rude sounding glisses sometimes.
2024-07-18 15:45: it works. clocking out. #demo-trio
2024-07-19 08:19: Clock resets are going to throw off gesture algorithm #demo-trio
One of the things I am doing in Trio is forcing a phase reset on pen down so the voices always stagger the same way. The funderlying rephasor in the gesture signal generator does not have a way of handling phase resets, so it'll assume a faster tempo change and cause unwanted jumps in time. The rephasor needs a way to be told that there has been a phase reset, which would cause it to skip calculating the delta time in the next sample tick.
I wonder if we can build a test around this?
2024-07-19 08:26: Task created for gesture reset #gesture-reset #demo-trio
I want to not only do the fix, but create a test in the test suite that showcases the problem before the fix is created, just so I know that I properly understand the problem that I am trying to solve.
2024-07-19 14:31: Time to actually hook up gesture to trio #demo-trio #timelog:00:36:25
2024-07-19 15:04: Things sound better than expected. #demo-trio
It did not crash. Not one crash. Thanks, Rust.
2024-07-19 15:07: A quick break. #demo-trio
2024-07-19 15:25: More trio tweaks #demo-trio #timelog:00:50:22
2024-07-19 15:26: Need a way to instantaneously set value of gesture. #demo-trio
This can be like a method or something like immediate()
. Setting the next/prev values to be some scalar value should work for the most part. The event queue should also be cleared as well.
2024-07-19 15:53: Weird bug: playing the same note twice doesn't trigger events #demo-trio
2024-07-19 16:04: A rewrite might be in order for this voice state management #demo-trio
There's too much spaghetti right now. I think I need to actually attempt to model this as a state machine and add some tests. Otherwise, I'm never going to figure out the issue, and this code will become too unwieldy to maintain.
2024-07-19 16:13: Gesture is unpredictable. #demo-trio
Not sure if this is my scheduling logic, or some subtle bug with the gesture event queue, or a mix of both.
Testing is definitely in order. But like, not today. I'm pretty drained.
Yeah, considering I want to change the chord selection logic, it's going to be even worse. This needs a rewrite.
I have built what is essentially a concurrent event system. So yeah, this is tough one to do correctly.
2024-07-20 21:00: Some impromptu showings of trio demo prototype #demo-trio
I turned on gesture again, and I think the wrong notes are caused by the event graph not removing events at the right time. I think. Anyways, this needs to be rebuilt for sure because I don't want to live life doing guess and check.
2024-07-22 09:03: good time to figure out pikchr? #demo-trio
I'm trying to more formally establish a way to manage how the voice scheduling works for trio.
2024-07-24 10:11: A more sophisticated chord selection algorithm is required #demo-trio-chords #demo-trio
The issue is there is no sense of resolution anywhere. It still kinda meanders.
2024-07-25 15:53: Initial chord structure, now to think about querying #demo-trio
We want to make a query: given some pitch (0-11), and a current chord, provide a range of potential candidates for the next chord.
Since this is going to be used in a realtime situation. My thinking is to populate with a pre-allocated fixed size array that is managed internally.
2024-07-28 20:04: More reverb, predelay too. #demo-trio #timelog:00:14:42
2024-07-28 21:02: Some expression control #demo-trio #timelog:00:43:36
2024-07-29 09:40: How does this sound today? #demo-trio #timelog:00:40:00
Added a new shape. Really expressive now. Vibrato not as bad as I remembered (with headphones on now instead of speakers).
Should resolve to tonic more often. There should be a built in bias to choose tonic.
I'm desiring the instantaneous mode again.
The chord changes are happening too quickly. If I select a pitch, go down quickly, and og back up, the chord shouldn't change. But it does.
2024-07-29 10:11: Sounding chords are different from hypothetical ones #demo-trio
Right now, a changing pitch triggers a set of chord progressions. But if they move too quickly, only the last one is heard. Which means effectively an arbitrary chord transition.
How to prevent this? A chord isn't a chord until all 3 voices commit. If the lead changes pitch, it uses the stored chord as a reference point. As it continues to change, this chord will continue to be used. The upper voice is the last person to commit to a chord, so only then should the reference chord be updated.
When the chord is officially committed for selection, only then does that chord get registered in the chord frequency table.
Oh my god this is consensus in a distributed system.
2024-07-29 14:30: Working out the "chord committing" idea on paper. #demo-trio #timelog:00:40:08
2024-07-31 09:52: Tweaked the tract lengths too #demo-trio
2024-07-31 09:55: revisit mobile, add smoothing, and other things. publish #demo-trio #timelog:01:15:28
2024-07-31 10:02: shoot I am having too much fun with this thing it's working it's really working #demo-trio
That's how I know this is close.
2024-07-31 10:04: Okay for real, smoothing. #demo-trio
2024-07-31 10:18: My phone is almost definitely running at a higher sampling rate #demo-trio
I want to see if I can get the webaudio API to request a sampling rate (44.1kHz) because the voices are just going to sound better.
I am now coming to understand why gnuspeech decided to go the route of resampling from 16kHz to the host sampling rate. It's just going to sound better that way. The changes sound too weird.
2024-07-31 10:46: Getting caught up in tweaking the "ooo" vocal shape #demo-trio
I'm finding it's very hard to find in my interface, because the sliders end up being very close to zero. I almost feel the urge to have a min/max slider too to be able to "zoom in".
2024-07-31 11:04: Reqeusted sample rate of 44.khz. Sounds better now #demo-trio
2024-07-31 11:08: Time to upload this thing. #demo-trio
2024-07-31 11:14: Uploaded. #demo-trio
2024-07-31 12:55: Safari troubleshooting. #demo-trio #timelog:00:11:13
I think I might call it "trio", and the elevator pitch is that you control one voice in a trio, and there is an algorithm that controls the other two pitches to form 3 part harmony.
Follow-up task created: demo-trio.