This is the seventh of a series of posts about SQA, my pet audio project. I’m rebuilding it from the ground up, for reasons explained here.

I’m pretty sure this is going to become a fortnightly publication. I think it really depends on whether any significant progress was made - it’s not very interesting to publish a ‘this week in SQA’ when there were no noticeable changes!

Commit log

  • 83e9866 on 2017-04-01: ffmpeg, jack: fix Cargo.toml metadata
  • 672628f on 2017-04-01: jack: publish version 0.5.0
  • 72f599e on 2017-04-01: backend: add spooler functionality
  • 6955df6 on 2017-04-01: engine: fix empty/half notifications to work (!)
  • 277d2f7 on 2017-04-01: ffmpeg: change iterator to yield (ch, smpl) pairs, add more methods
  • 9db76a4 on 2017-03-28: backend, engine, jack: add mixer, fix action FSM
  • e929713 on 2017-03-24: backend: add better OSC error messages
  • 02d52d9 on 2017-03-24: backend: add subscription and notification system
  • aee7690 on 2017-03-23: backend: quick’n’dirty playback demo!
  • 190ba6f on 2017-03-19: backend: add /action/update, /action/delete, /action methods
  • 4735e5c on 2017-03-18: *: update rosc to unborked version
  • 0c022cb on 2017-03-18: backend: move to new parameters abstraction
  • 0f182f7 on 2017-03-18: backend: replace protocol with OSC, decruftify
  • 46532dc on 2017-03-18: add rosc submodule

Changes in detail

SQA Backend has made quite a bit of progress since the last time I did a writeup! Instead of using some custom homebrew protocol, it now uses the well-established Open Sound Control (OSC) standard, so it can talk to other OSC-enabled things. (This also means that I don’t need to write a client just yet - I’ve been doing my testing with a command-line OSC utility called oscchief).

SQA Backend now uses an enum to list the different types of Action, rather than using trait objects. This makes things a lot easier, because we can do non-object safe things! Parameters are vastly simplified: instead of having some weird abstraction where you have to get and set them with methods, you just provide an associated type, like so:

pub trait ActionController {
    type Parameters: Serialize + Deserialize + Clone + Debug;

    fn desc(&self) -> String;
    fn get_params(&self) -> &Self::Parameters;
    fn set_params(&mut self, Self::Parameters);
    fn verify_params(&self, ctx: &mut ActionContext) -> Vec<ParameterError>;
    fn load(&mut self, _ctx: ControllerParams) -> BackendResult<bool> {
        Ok(true)
    }
    fn accept_load(&mut self, _ctx: ControllerParams, data: Box<Any>) -> BackendResult<()> {
        Ok(())
    }
    fn execute(&mut self, time: u64, ctx: ControllerParams) -> BackendResult<bool>;
    fn duration(&self) -> Option<Duration> {
        None
    }
    fn accept_audio_message(&mut self, _msg: &AudioThreadMessage, ctx: ControllerParams) -> bool {
        false
    }
}

The Parameters type provides a strongly-typed way to define the parameters of an action. This is then serialised using the wonderful serde library, so it can be get/set via OSC! Calling /action/{uuid}/update with a JSON string facilitates this.

We also now have a dedicated mixer subsystem that wrangles sqa-engine and takes care of updating JACK ports and connections - via the /mixer/config/set OSC method, a client can completely rewire the system in one OSC call.

In more recent news, we can now actually play audio through SQA Backend in a performant fashion! (Doing so required fixing up a few bugs that were found in the other SQA libraries, for which fixes were released and pushed to crates.io.) Check out the screenshot below!

Screenshot of the week

This screenshot shows the OSC replies from sqa-backend at the top, my OSC commands in the middle, htop at the bottom (showing the wonderfully low CPU usage!), and a volume display on the left (to show that stuff is actually playing).

screenshot


That’s it for this week; tune in in a few week’s time for the next edition!