Questions about digital noise and grounding

“A bandaid that works when doing fairly trivial DSP is to increase the callback frequency to something outside of, or at the upper limits of human hearing. Obviously this is not always possible.”

Actually this is what I always do on other processors - I calculate the latest DAC samples at 96kHz and have a counter that increments by one to choose what else to do during the sample. Divide by 8 and a Case statement usually works fine.

And I was wondering for a second why this code looks so familiar…
It’s surreal bumping into you here. I’m still using your FFT anytime I need one, it’s the most usable implementation out there.
Looking forward to trying your noise gate.

2 Likes

To try and move the 1kHz noise (from 48kHz sampling and blocksize = 48) above audible frequencies it is pretty easy to lower the blocksize. Is anything bad going to happen or degrade if I make the blocksize 1 of 2 or something super low? Maybe processing will just go up? How was 48 chosen to be a good blocksize to start with?

The 48 blocksize was chosen as a way to have an easily understood callback rate (48000Hz / 48 = 1000Hz – or 1ms), that can still benefit from block processing while maintaining minimal latency.

Any effects from reducing blocksize would largely depend on how busy your process loop is, as well as how much stuff you need to do outside of the callback. Whatever is happening in other interrupts, or in the main infinite loop will be getting interrupted more frequently. This most likely would have a negative effect on stuff like USB or SD Cards more than anything else.

But if all you’re doing is generating audio then there may not be any issue.

3 Likes

I’m having some trouble with the noise issue as well. I’ve designed a eurorack module around the Seed, and have incorporated the isolator and caps in almost exactly the same configuration as the Patch. I was also able to reduce the block size down to 10 in my code without problems, but that still puts the whistling noise at 4.8kHz. Both of these things helped a lot, but I still find that I need to apply a 10dB cut with a Q of 18 in Ableton to make the noise inaudible.
Does the problem stem from the fact that the audio codec uses the same VCC and ground pins as the MCU? I wonder if using an external codec with better supply trace routing might solve the issue?

That’s one solution. Other is to try to get the block size down to 1 by dividing your code up into segments that are spread over 8 or 16 callbacks.

1 Like

oh that’s interesting, I didn’t think of that. My code has a combination of delay lines (reading from the SDRAM), filters, cross fades, ADC reads, digital outputs etc, so if I spread those around a number of callbacks the processor might be able to keep up? Presumably I would need to read the audio input on the first callback, and then end up writing the output on the last?

Yes it’s almost the same amount of code, you just add a counter from 0 to 7 or 15, increment it each callback and then test it and run that portion of the code. Just divide it up into 8 or 16 functions. If you can keep each function of similar time - the better you do this the quieter it will be.

You still read the audio in and write the audio out every callback. You get rid of the buffer (set it to 1)

I’m not quite sure how that would work - if I read and write the audio every callback it won’t have calculated all the data for the output? I mean it’s ok for dry signal, but for the wet signal (my code is a delay effect) won’t it run in to problems?

You’ll still have to buffer data. Say you decomposed your processing function into 16 balanced sub-functions. The time can be divided in cycles of 16 samples:

Time 0 — the ADC provides the 16th sample (index 15) of a nearly full buffer, let’s call it A. Then you can start the processing calling function 0 on this 16-sample buffer. On the output, you’ll pass the sample at the index 1 of the previous output buffer, let’s call it B.
Time 1 — start filling a fresh input buffer (let’s call it C) with the input, index 0. Process the buffer A with function 1. Send index 2 of the buffer B to the DAC.
Time 2 — add the input to the buffer C, index 1. Process the buffer A with function 2, send buffer B index 3.
Time …
Time 14 — add the input to the buffer C, index 13. Process the buffer A with function 14, send the last sample of the buffer B, index 15.
Time 15 — add the input to the buffer C, index 14. Process the buffer A with function 15, and now it is ready for the output. Send index 0 of this buffer to the DAC.

Then repeat this cycle, rotating the buffers.

2 Likes

If you think of it you have to calculate 48000 samples per second no matter how you do it, whether in blocks of 1 or blocks of 16. So the real time stuff should be done every callback, calculating just the latest value. But you also have non-critical stuff which isn’t updated that often - reading controls, USB, display, etc. This is the code you should do a little of every callback using a counter.

Alternatively it is often slightly faster to calculate say 8 samples at a time into an array as it saves on loading pointers, etc, using one or more of these callback routines for this.

But you should just load in one sample from a saved array at a time into the buffer so as to avoid any repetitive burst of noise.

In fact you can load two samples at a time as noise will be at 24kHz if you prefer, but that often makes the code more complicated, not less.

3 Likes

Ok just as a quick update - I did as MikeDB suggested and spread the non-realtime processes out. I put them into 7 different functions in the end, and used a switch statement and counter to select one per callback. I left all the audio processing code alone, and set the block size to 1. Everything functions as it did before (well I had some LPF’s on the control inputs so these need to be tweaked), with zero whistling in the audible spectrum. Worked like a charm! Thanks for the help guys!

2 Likes

ok slight edit - the whistling is still in the audible spectrum, but at a much lower level. I tweaked it to be in 4 functions, and the whistling is now at 12kHz, but it’s not audible over the hiss from the opamps / codec etc.

3 Likes

Glad you got it working. It’s a common problem all these programmable audio platforms. Linux is even worse as you can’t make ALSA work with a block size of less than 10 so even sampling at 96kHz it’s audible.

However you shouldn’t be getting much hiss from the CODEC and op-amps. How loud are we talking about ?

Oh the hiss is pretty quiet, I had to boost the already healthy signal level by 24dB in Ableton to be able to hear it! Some of that will be my interface as well.

Okay that’s great.

BTW if you (or anybody else doing the same) have any spare time left after any of the non-realtime functions in that 1/12 mS timeslot, you can measure it and put a random delay at the start of the function with 0 as minimum and just under that spare time as maximum, changing the wait every cycle. This dithering spreads the noise out rather than being a repetitive 12kHz tone.

oh neat, yeah I’d like to try that. How would I go about measuring the time taken for the functions to execute?

I run counters at the end of all my functions when they are waiting for the next callback, then the callback records those values and zeroes them.

while {} timefunc1++;

And in the callback :
savetimefunc1 = (timefunc1 + 1023 * savetimefunc1) >> 10;
// this converges to the average wait time pretty quickly
// also good to record the maximum
if (savetimefunc1max < timefunc1)
savetimefunc1max = timefunc1
timefunc1 = 0;

Of course this depends on the callback being interrupt driven - you’d need to check that is how Electrosmith have done it. If it’s a round-robin scheduler it will just hang up.

I use the Arduino environment and i get some digital noise when connected to the PC (you know the kind of noise you get when you can hear the mouse when you move it).

When the Daisy Seed is connected to a power bank i do not get any digital noise.

Is there something special in the Arduino implementation that makes this noise disappear ? (constant charge of cpu ?..)


my test consists of a filtered osc with osc.SetAmp(0.0003f) with svf → EIEpro soundinterface with input gain set to max for line input (~50dB).


[EDIT]

  • I added a “USB silencer” (galvanic isolator) and connected the daisy through it to the PC.
    Now i have the 1kHz and its harmonics (it’s not drown/hidden by the PC digital noise) as described in this thread. It is at about -80dB (compared to a full scale sine)
  • The noise still disappears when connected to a powerbank

It would be interesting to see how other power sources can affect this noise.