Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method to obtain precise audio sample rate based on hardware clocks #629

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ndonald2
Copy link
Contributor

Background

Currently libDaisy's getter methods to obtain the current audio codec sample rate as a float return the target/idealized sample rate – e.g. 48000.0 for 48kHz – when in fact the actual codec sample rate will be slightly different from this due to hardware limitations.

The SAI peripheral clock must be divided by an integer (this is all initialized via the HAL) and thus the actual operating frame clock / LR clock (aka sample rate) for the I2S codec ends up being slightly off from the target sample rate. For example, at 48kHz target sample rate the actual operating sample rate comes out to ~48014.324.

In many DSP applications this error doesn't matter. Oscillator tuning will be off only by a cent or so usually, and delay times etc are off by a marginal amount. However, for certain specific applications, the exact value is important, and it's good to have the option anyway. One such application is a looping delay (100% feedback delay line) which will drift over time if not using the correct value.

Changes

This PR adds a new method GetPreciseSampleRate() to SAI handle (also accessible via callthrough from AudioHandle) which provides the exact operating sample rate derived from the corresponding SAI peripheral clock and the HAL-determined MCK divider – Mckdiv in the HAL init struct, as updated via the call to HAL_SAI_InitProtocol(...)

I also have my IDE setup to trim trailing whitespace and run clang-format (which uses the libDaisy configuration file) so there's a good amount of formatting changes here too.

Seeking Feedback:

  • Should this instead replace the implementation of the current GetSampleRate() methods? This would not be an API-breaking change but it may have slight impact to existing applications so I didn't go that route.
    • The most significant behavior change is probably that the current method returns hard-coded values so it works before audio system init, and this method does not.
  • Is optionally passing the sai_idx as an integer in the AudioHandle method reasonable? It would also be easy, albeit more verbose, to use SAIHandle::Config::Peripheral instead.

Example Usage

Typical usage:

// The exact sample rate is accessible from `AudioHandle`
// This must happen AFTER audio system is initialized
float sr_exact = seed.audio_handle.GetPreciseSampleRate();
osc.Init(sr_exact);

If the hardware is using an additional codec on the second SAI peripheral you can also specify this by passing 1 as an argument for sai_index.

float sr_exact = seed.audio_handle.GetPreciseSampleRate(1);

Actual LRClk I2S sample rate is not precisely
equal to the "ideal" sample rate due to
peripheral clock division requirements.

This adds a method to return a float
representing the "actual" hardware
audio sample rate for more precise DSP
Copy link

Test Results

151 tests  ±0   151 ✅ ±0   0s ⏱️ ±0s
 16 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 11b5b84. ± Comparison against base commit f7727ed.

@ndonald2
Copy link
Contributor Author

ndonald2 commented May 16, 2024

I don't know why clang-format in the github CI action always disagrees with my local run so I'm not going to try to fix the style check errors here for now. I would love to figure out why that happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant