131 lines · 3.9 KB · C++
RawDownload
////  Oscilloscope.cpp//  interface////  Created by Philip on 1/28/13.//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.// #include "Oscilloscope.h" #include "InterfaceConfig.h"#include <limits>#include <cstring>#include <algorithm> //  Reimplemented 4/26/13 (tosh) - don't blame Philip for bugs using namespace std; namespace { // everything in here only exists while compiling this .cpp file     // one sample buffer per channel    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 N_COORDS_ALLOC = MAX_COORDS * Oscilloscope::MAX_CHANNELS;        unsigned const N_ALLOC_TOTAL = N_SAMPLES_ALLOC + N_COORDS_ALLOC;}  Oscilloscope::Oscilloscope(int w, int h, bool isEnabled) :     _valWidth(w), _valHeight(h),     _arrSamples(0l), _arrVertices(0l),     _valLowpass(0.4f), _valDownsample(3),    enabled(isEnabled), inputPaused(false) {        // allocate enough space for the sample data and to turn it into    // vertices and since they're all 'short', do so in one shot    _arrSamples = new short[N_ALLOC_TOTAL];    memset(_arrSamples, 0, N_ALLOC_TOTAL * sizeof(short));    _arrVertices = _arrSamples + N_SAMPLES_ALLOC;     // initialize write positions    for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) {        _arrWritePos[ch] = MAX_SAMPLES * ch;    }} Oscilloscope::~Oscilloscope() {     delete[] _arrSamples;} void Oscilloscope::addSamples(unsigned ch, short const* data, unsigned n) {     if (! enabled || inputPaused) {        return;    }        unsigned baseOffs = MAX_SAMPLES * ch;    unsigned endOffs = baseOffs + MAX_SAMPLES;            unsigned writePos = _arrWritePos[ch];    unsigned newWritePos = writePos + n;     unsigned n2 = 0;    if (newWritePos >= endOffs) {        n2 = newWritePos - endOffs;        newWritePos = baseOffs + n2;        n -= n2;    }            memcpy(_arrSamples + writePos, data, n * sizeof(short));    if (n2 > 0) {        memcpy(_arrSamples + baseOffs, data + n, n2 * sizeof(short));    }        _arrWritePos[ch] = newWritePos;}        void Oscilloscope::render(int x, int y) {     if (! enabled) {        return;    }        // expand data to vertex data, now    int lowpass = -int(std::numeric_limits<short>::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;        for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) {         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) {                inPtr = endPtr;            }            sample += ((*--inPtr - sample) * lowpass) >> 15;                                if (i % downsample == 0) {                *outPtr++ = short(--x);                *outPtr++ = short(sample);            }        }    }         glLineWidth(2.0);    glPushMatrix();    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);    glColor3f(1.0f, 1.0f, 1.0f);    glDrawArrays(GL_LINES, MAX_SAMPLES * 0, usedWidth);    glColor3f(0.0f, 1.0f ,1.0f);    glDrawArrays(GL_LINES, MAX_SAMPLES * 1, usedWidth);    glColor3f(1.0f, 1.0f ,0.0f);    glDrawArrays(GL_LINES, MAX_SAMPLES * 2, usedWidth);    glDisableClientState(GL_VERTEX_ARRAY);    glPopMatrix();}