arrayscoscilloscope

How can I properly implement zero cross triggering for digital oscilloscope in C?


So I'm doing a simple oscilloscope in C. It reads audio data from the output buffer (and drops buffer write counter when called so the buffer is refreshed). I tried making simple zero-cross triggering since most of the time users will see simple (sine, pulse, saw, triangle) waves but the best result I got with the code below is a wave that jumps back and forth for half of its cycle. What is wrong?

Signal that is fed in goes from -32768 to 32767 so zero is where it should be.

If you didn't understand what I meant you can see the video: click

Upd: Removed the code unrelated to triggering so all function may be understood easier.

extern Mused mused;

void update_oscillscope_view(GfxDomain *dest, const SDL_Rect* area)
{
  if (mused.output_buffer_counter >= OSC_SIZE * 12) {
    mused.output_buffer_counter = 0;
  }

  for (int x = 0; x < area->h * 0.5; x++) {
    //drawing a black rect so bevel is hidden when it is under oscilloscope
    gfx_line(domain,
             area->x,               area->y + 2 * x,
             area->x + area->w - 1, area->y + 2 * x,
             colors[COLOR_WAVETABLE_BACKGROUND]);
  }

  Sint32 sample, last_sample, scaled_sample;

  for (int i = 0; i < 2048; i++) {
    if (mused.output_buffer[i] < 0 && mused.output_buffer[i - 1] > 0) {
      //here comes the part with triggering

      if (i < OSC_SIZE * 2) {
        for (int x = i; x < area->w + i; ++x) {
          last_sample = scaled_sample;
          sample = (mused.output_buffer[2 * x] + mused.output_buffer[2 * x + 1]) / 2;

          if (sample      >  OSC_MAX_CLAMP) { sample      =  OSC_MAX_CLAMP; }
          if (sample      < -OSC_MAX_CLAMP) { sample      = -OSC_MAX_CLAMP; }
          if (last_sample >  OSC_MAX_CLAMP) { last_sample =  OSC_MAX_CLAMP; }
          if (last_sample < -OSC_MAX_CLAMP) { last_sample = -OSC_MAX_CLAMP; }

          scaled_sample = (sample * OSC_SIZE) / 32768;

          if(x != i) {
            gfx_line(domain,
                     area->x + x - i - 1, area->h / 2 + area->y + last_sample,
                     area->x + x - i,     area->h / 2 + area->y + scaled_sample,
                     colors[COLOR_WAVETABLE_SAMPLE]);
          }
        }
      }

      return;
    }
  }
}

Solution

  • During debugging, I simplified the code until it started working. Thanks Clifford.

    I found a trigger index i (let's say it is array index 300). Modified it so that the oscilloscope was drawing lines from [(2 * i) + offset] to [(2 * i + 1) + offset], thus an incorrect picture was formed.

    I used (2 * i), because I wanted long waves to fit into oscilloscope. I replaced it with drawing from [i + offset] to [i + 1 + offset] and that solved a problem.

    Afterwards, I implemented "horizontal scale 0.5x properly.

    The output waveform still jumps a little, but overall it holds it in place.