diff --git a/interface/src/Oscilloscope.cpp b/interface/src/Oscilloscope.cpp index dc582d4c49..ec22b2165a 100644 --- a/interface/src/Oscilloscope.cpp +++ b/interface/src/Oscilloscope.cpp @@ -23,9 +23,11 @@ namespace { // everything in here only exists while compiling this .cpp file unsigned const N_SAMPLES_ALLOC = Oscilloscope::MAX_SAMPLES * Oscilloscope::MAX_CHANNELS; // adding an x-coordinate yields twice the amount of vertices - unsigned const MAX_COORDS = Oscilloscope::MAX_SAMPLES * 2; + unsigned const MAX_COORDS = Oscilloscope::MAX_SAMPLES * 2; + // allocated once for each channel unsigned const N_COORDS_ALLOC = MAX_COORDS * Oscilloscope::MAX_CHANNELS; - + + // total amount of memory to allocate (in 16-bit integers)` unsigned const N_ALLOC_TOTAL = N_SAMPLES_ALLOC + N_COORDS_ALLOC; } @@ -42,7 +44,7 @@ Oscilloscope::Oscilloscope(int w, int h, bool isEnabled) : memset(_arrSamples, 0, N_ALLOC_TOTAL * sizeof(short)); _arrVertices = _arrSamples + N_SAMPLES_ALLOC; - // initialize write positions + // initialize write positions to start of each channel's region for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) { _arrWritePos[ch] = MAX_SAMPLES * ch; } @@ -58,25 +60,31 @@ void Oscilloscope::addSamples(unsigned ch, short const* data, unsigned n) { if (! enabled || inputPaused) { return; } - + + // determine start/end offset of this channel's region unsigned baseOffs = MAX_SAMPLES * ch; unsigned endOffs = baseOffs + MAX_SAMPLES; - - unsigned writePos = _arrWritePos[ch]; - unsigned newWritePos = writePos + n; + // fetch write position for this channel + unsigned writePos = _arrWritePos[ch]; + + // determine write position after adding the samples + unsigned newWritePos = writePos + n; unsigned n2 = 0; if (newWritePos >= endOffs) { + // passed boundary of the circular buffer? -> we need to copy two blocks n2 = newWritePos - endOffs; newWritePos = baseOffs + n2; n -= n2; } - + + // copy data memcpy(_arrSamples + writePos, data, n * sizeof(short)); if (n2 > 0) { memcpy(_arrSamples + baseOffs, data + n, n2 * sizeof(short)); } - + + // set new write position for this channel _arrWritePos[ch] = newWritePos; } @@ -85,46 +93,58 @@ void Oscilloscope::render(int x, int y) { if (! enabled) { return; } - - // expand data to vertex data, now + + // determine lowpass / downsample factors int lowpass = -int(std::numeric_limits::min()) * _valLowpass; unsigned downsample = _valDownsample; // keep half of the buffer for writing and ensure an even vertex count unsigned usedWidth = min(_valWidth, MAX_SAMPLES / (downsample * 2)) & ~1u; unsigned usedSamples = usedWidth * downsample; + // expand samples to vertex data for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) { - + // for each channel: determine memory regions short const* basePtr = _arrSamples + MAX_SAMPLES * ch; short const* endPtr = basePtr + MAX_SAMPLES; short const* inPtr = _arrSamples + _arrWritePos[ch]; short* outPtr = _arrVertices + MAX_COORDS * ch; int sample = 0, x = usedWidth; for (int i = int(usedSamples); --i >= 0 ;) { - if (inPtr == basePtr) { + // handle boundary, reading the circular sample buffer inPtr = endPtr; } - sample += ((*--inPtr - sample) * lowpass) >> 15; + // read and (eventually) filter sample + sample += ((*--inPtr - sample) * lowpass) >> 15; + // write every nth as y with a corresponding x-coordinate if (i % downsample == 0) { *outPtr++ = short(--x); *outPtr++ = short(sample); } } } - - glLineWidth(2.0); + + // set up rendering state (vertex data lives at _arrVertices) glPushMatrix(); + glLineWidth(2.0); glTranslatef((float)x + 0.0f, (float)y + _valHeight / 2.0f, 0.0f); glScaled(1.0f, _valHeight / 32767.0f, 1.0f); glVertexPointer(2, GL_SHORT, 0, _arrVertices); glEnableClientState(GL_VERTEX_ARRAY); + + // batch channel 0 glColor3f(1.0f, 1.0f, 1.0f); glDrawArrays(GL_LINES, MAX_SAMPLES * 0, usedWidth); + + // batch channel 1 glColor3f(0.0f, 1.0f ,1.0f); glDrawArrays(GL_LINES, MAX_SAMPLES * 1, usedWidth); + + // batch channel 2 glColor3f(1.0f, 1.0f ,0.0f); glDrawArrays(GL_LINES, MAX_SAMPLES * 2, usedWidth); + + // reset rendering state glDisableClientState(GL_VERTEX_ARRAY); glPopMatrix(); }