• Audio
  • Serious audio output problems.

Hi all,

I'm having a pretty disappointing thing happen.

I had hooked up Bela to my external recorder to use a soft o-scope on my computer to grab some shots of waveforms I'm starting to make for my additive synth. They looked terrible and nothing like the waveforms I'd seen from my simulations and then in the Bela's own scope. I figured there was something wrong with my H2n or the scope software. Then I had the idea to hook Bela's input to its output. Exact same distortion. Asymmetrical, some weird DC offset, the distortion gets worse at lower frequencies. I even tried a software LPF, but it made no difference. I've tried adjusting every gain option on the Bela, but nothing is making this better. I've played different waveforms from my computer at different volumes and had none of these issues.

This means that something is borked on the output channels. I have tried every permutation of gain staging and of adjusting ADC + DAC + headphone + PGA level adjusting I can think of.

Any ideas? I've included screenshots.

http://imgur.com/a/aJhdu

Oh well that does not look right ( @andrew !!)
Can you tell us what each line is in the plots?
It would be helpful if you could send:
- the code
- a screenshot of the scope settings
- a screenshot of the project settings
- an explicit description of the wiring

thanks

The scope settings are the default. Nothing has changed.

The project settings were the default. I tried different gain options, but I've seen this problem before.

It's weird because sinewaves don't seem to be affected, just stuff with added harmonics, even if the harmonics are well below nyquist.

Wiring;

3,.5mm stereo cable from output to either H2n or Bela input.

The code:

output = (sinf_neon(gphase)>0)-(sinf_neon(gphase)<0). I've tried basically every output setting.

or output = (sinf_neon(gphasex))/x+(sinf_neon(gphasex*3))/3x ... (additive square wave)

I've tried to LPF the output to make sure it wasn't an aliasing thing, same issue.

I'll send the code shortly if you need it.

Oh, the lines are-blue is waveform on the o-scope output before it goes out of the bela, Red is the waveform as it comes back into Bela.

Hi Ben, what is the frequency of these waves you're generating? The plots to me look like what I'd expect to see based on the normal AC-coupling (high-pass filtering) of the audio I/Os. In general, don't read too much into the large-scale wave shapes on audio signals -- DC blocking can have a big effect on the visual appearance without any impact on the sound. On the other hand, if there is major spectral distortion that would be a big problem!

    I tried from ~20hz to about 5khz. The distortion gets worse in the lower frequencies, but again is only noticeable as you add harmonics. I'll do a series of FFT comparisons of output vs input. I've seen this happen before when the output cap values were too low.

    Could someone attempt to replicate this for me? IE: Loopback of output to input, FFT + oscope?

    Ok, yeah. Just ran a few FFTs. The overshooting is much less pronounced at higher frequencies and at low frequencies the FFT shows a pretty heavy DC signal. I think my bela might have a bad output cap.

    There is something funky going on with the headphone output. The following show the difference between output taken from headphone out and from the pin on the right hand side of j6.

    http://imgur.com/a/C3MDU

    Does the same thing happen on both left and right channels? If yes then the odds of a bad component are reduced. Also, try measuring the headphone output under load (e.g. a 100 ohm resistor), and/or measuring the signal at J9.

    A small DC offset at the input, even after the input filter caps, is not necessarily impossible. I would expect it to be in the region of .05 or less at rest, and probably much smaller (.01 or less). Anything bigger than 0.1, or anything substantially different between left and right channels, might indicate a component problem. The measure_noisefloor example will show you the DC level of each pin calculated over a window.

    Don't necessarily trust the FFT to tell you a DC offset though. For any short-time window, the lowest bin will encompass a range of very low frequencies, and because of windowing I would expect it to show some energy in that bin even if there isn't a "real" DC offset. The best way to measure the actual DC offset is to take a mean over several seconds, ideally with no signal at all.

    [1;1H[2JAudio In L: Noise -76.9dB DC offset 0.0363 ( -28.8d😎 window size: 8192
    Audio In R: Noise -81.1dB DC offset 0.0252 ( -32.0d😎 window size: 8192
    Analog In 0: Noise -59.3dB DC offset 0.0011 ( -58.9d😎 window size: 4096
    Analog In 1: Noise -60.8dB DC offset 0.0008 ( -61.9d😎 window size: 4096
    Analog In 2: Noise -60.6dB DC offset 0.0009 ( -61.1d😎 window size: 4096
    Analog In 3: Noise -62.7dB DC offset 0.0006 ( -65.0d😎 window size: 4096
    Analog In 4: Noise -58.6dB DC offset 0.0011 ( -58.8d😎 window size: 4096
    Analog In 5: Noise -60.2dB DC offset 0.0009 ( -60.7d😎 window size: 4096
    Analog In 6: Noise -66.7dB DC offset 0.0004 ( -69.1d😎 window size: 4096
    Analog In 7: Noise -63.2dB DC offset 0.0006 ( -64.2d😎 window size: 4096

    I let this run for about 10 minutes.

    I'll take this down to my office and do some stuff there later with proper equipment.

    Yeah, both channels show the same issue. I'll check in. Right now the line out is decent enough that I can keep going-ultimately I need to assume the output of this is going to be hooked up to a scope semipermanently, so it needs to look reasonably pretty. I think I can work with what I'm seeing here.

    Thanks again!

    OK that looks pretty normal for unconnected inputs. Another thought on the headphone output is that there may be some kind of extra filtering going on in the codec which is emphasising the high frequencies. There are quite a few options that can be flipped on or off via I2C. It's beyond what I have time to dig into right now, but you can find the datasheet here: http://www.ti.com/lit/ds/slas510d/slas510d.pdf

    ben_wizards

    If you add this at the top of render.cpp

    #include <I2c_Codec.h>
    extern I2c_Codec *gAudioCodec;

    then you should be able to write to the audio codec with

    gAudioCodec->writeRegister(register, value)

    (see some examples in core/I2c_Codec.cpp)

    Unfortunately anything you would do during setup would be overwritten by the actual codec initialization, so you should try to run it in an auxiliary task (which is scheduled from render()), or do it at the first call to render(), something like

    static bool init = false;
    if(init == false){
      gAudioCodec->writeRegister(register, value);
      init = true;
    }

    Also, a couple of notes on the snippets of code you posted above:
    1) I am not sure what degree of precision you can expect from sinf_neon(rad) when rad is outside the range of 0 to 2*M_PI. Even if the precision of the function is not an issue, you should always make sure you wrap the phase in order to avoid troubles with the finite precision of float (e.g.: after a few seconds or minutes that your project is running, the frequency of the sinewave will change and eventually degrade to a DC signal).
    2) in case you already are wrapping the phase between 0 and 2*M_PI, then (sinf_neon(gphasex*3))/3*x is NOT going to give you a sine wave, because gphasex*3 would be affected by the wrapping. The resulting wave will probably contain lots of high frequency and potentially cause aliasing.

    Also, applying a filter in the digital domain is not likely to help much with aliasing, unless aliasing is concentrated in a band where you have no signal.

    One last thing, the forum engine understands markdown, so when pasting your code you are encouraged to use backticks ( ` ) around it, so that it is displayed in a monospace character. For blocks of code, use three backticks ( ``` ) before and after, this also gives some sort of syntax highlighting and different background color.

      Thanks for all that. I am actually doing a phase incrementer for each multiple, so it is ghase[x] inside. I used a filter in software to avoid any aliasing on the output just to make sure i wasnt getting some weird foldback from the high harmonics of a signum wave.

      giuliomoro

      The examples all have gPhase looping back to zero rather than -2*pi,

      gPhase += 2.0 M_PI gFrequency gInverseSampleRate;
      if(gPhase > 2.0
      M_PI)
      gPhase -= 2.0 * M_PI;

      instead of

      gPhase += 2.0 M_PI gFrequency gInverseSampleRate;
      if(gPhase >
      M_PI)
      gPhase -= 2.0 * M_PI;

      Which for standard sinf isn't much of a problem, but the error blows up for lower precision approximations.

      Before the Neon library, the sin approximation I used would make very glitchy sinewaves with lots of error unless I wrapped the phase that way. I'm not sure how precise Neon's sinf is, but wrapping it that way helped tremendously for the earlier implementation I was using and has allowed me to shaped aliasing/glitching artifacts like I was doing with the stock sinf function.

      Good point, each approximated implementation will have their constraints about phase range, this needs to be checked before use

      a month later

      As andrew pointed out, the time-domain representation of a waveform can be distorted by a simple high-pass filter, without that impacting the resulting sound. Also, at is common in many amplifying stages, depending on their design, the output of the headphone amp is inverted with respect to its input, again with no audible difference.

      So I made a Matlab simulation to see what happens to a bandlimited complex waveform when it is delayed, slightly offset, inverted and high pass filtered.
      I used a Butterworth second order high pass, cutoff 50Hz, the waveforms have fundamental frequency of 200Hz.

      You can see the results here Square wave sawtooth (matlab code is embedded in the image description, should run fine also on GNU/octave which is free ).
      They seem pretty close to the ones you posted above, from which I'd conclude: what you see is not distortion, it is just the effect of linear filtering. I actually did not realize it immediately myself, as you'll have realized from my first answer above, but as Andrew pointed out in his first post, there seems to be no issue with your board.

      Have you heard any audible distortion (when using reasonable gain settings) by any chance?

      Incidentally, as mentioned briefly above, I do not think that "software filters" would help you get rid of aliasing and using a signum() function (or anything with sharp corners) is likely to cause aliasing. Aliasing sounds great some times but the time-domain representation of a non-bandlimited waveform may be affected in even more unexpected ways when it goes through a lowpass filter like the one built into the audio DAC.

      The signum portion of the synth is part of a purposefully noisy thing that is only incidental to the main additive synth. The traditional functions are all bandlimited in code, so I'm not worried about that.

      About the output-I have literally dozens of synths, function generators, audio interfaces, cell phones...so on. I haven't seen anything like this before on any of them. " It's not a bug, it's a feature" doesn't fly when it's easy to reproduce the anticipated waveshape on anything but your platform. I have heard output sounding unlike what it should sound like-but I haven't had time to properly measure. Having a software 50hz HPF seems to be a pretty darned high frequency for an audio device which could reasonably be used as a synth! If it's in software, how can I shut it off? If it's in hardware, I guess I could put a pair of caps in parallel with the output caps to lower the 6db point to something more useable.

      I forgot to mention I am not sure what the high pass filter is on the headphones output, the numbers I used in the simulation (200Hz tone, 50Hz high pass) are arbitrary because I did not know what frequency you used in your screenshots and I was trying to match them visually. Multiplying these frequency values by the same constant would not change the visual result (say 100Hz tone, 25Hz high-pass) .

      As you have seen from your previous measurements, the line-level output does not show this effect, so it probably has a much lower cutoff.
      When designing the board we had to decide whether to make the headphone output or the line output available on on the header. We eventually settled for the headphone output as that is surely more useful in most situations for rapid prototyping. We expected that anyone requiring the improved performances of the line out (e.g: for a finished instrument) will have no trouble soldering the three pins on the cape as part of the larger instrument building process).

      See if you find anything that is programmable via software for the audio codec in its datasheet. I had a quick look and could not find much.

        giuliomoro You're right. I had actually forgotten that I'm still using the headphone out.

        I'll go through the datasheet, thanks.