annotate src/Modules/Output/Graphics/GraphicsView.cc @ 121:3cdaa81c3aca

- Massive refactoring to make module tree stuff work. In theory we now support configuration files again. The graphics stuff is untested as yet.
author tomwalters
date Mon, 18 Oct 2010 04:42:28 +0000
parents 18237d55e346
children bf1417b5d83e
rev   line source
tomwalters@116 1 // Copyright 2006, Willem van Engen
tomwalters@116 2 //
tomwalters@116 3 // AIM-C: A C++ implementation of the Auditory Image Model
tomwalters@116 4 // http://www.acousticscale.org/AIMC
tomwalters@116 5 //
tomwalters@116 6 // Licensed under the Apache License, Version 2.0 (the "License");
tomwalters@116 7 // you may not use this file except in compliance with the License.
tomwalters@116 8 // You may obtain a copy of the License at
tomwalters@116 9 //
tomwalters@116 10 // http://www.apache.org/licenses/LICENSE-2.0
tomwalters@116 11 //
tomwalters@116 12 // Unless required by applicable law or agreed to in writing, software
tomwalters@116 13 // distributed under the License is distributed on an "AS IS" BASIS,
tomwalters@116 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
tomwalters@116 15 // See the License for the specific language governing permissions and
tomwalters@116 16 // limitations under the License.
tomwalters@116 17
tom@118 18 #include <algorithm>
tom@118 19
tomwalters@116 20 #include "Support/Common.h"
tomwalters@116 21
tom@118 22 #include "Modules/Output/Graphics/GraphicsView.h"
tom@118 23 #include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h"
tom@118 24
tom@118 25 namespace aimc {
tomwalters@116 26
tomwalters@116 27 GraphicsView::GraphicsView(Parameters *parameters) : Module(parameters) {
tomwalters@121 28 module_description_ = "Graphics output.";
tomwalters@116 29 module_identifier_ = "graphics";
tomwalters@116 30 module_type_ = "output";
tomwalters@116 31 module_version_ = "$Id: $";
tomwalters@116 32
tomwalters@117 33 m_pDev = NULL;
tomwalters@117 34 m_bPlotLabels = false;
tomwalters@117 35 m_pAxisX = new GraphAxisSpec();
tomwalters@117 36 AIM_ASSERT(m_pAxisX);
tomwalters@117 37 m_pAxisY = new GraphAxisSpec();
tomwalters@117 38 AIM_ASSERT(m_pAxisY);
tomwalters@117 39 m_pAxisFreq = new GraphAxisSpec();
tomwalters@117 40 AIM_ASSERT(m_pAxisFreq);
tom@118 41 initialized_ = true;
tomwalters@116 42
tom@118 43 if (!m_pAxisY->Initialize(m_pParam,
tom@118 44 _S("graph.y"),
tom@118 45 -1,
tom@118 46 1,
tom@118 47 Scale::SCALE_LINEAR)) {
tom@118 48 LOG_ERROR("Axis initialization failed");
tom@118 49 initialized_ = false;
tom@118 50 }
tomwalters@117 51 m_fMarginLeft = m_pParam->GetFloat(_S("graph.margin.left"));
tomwalters@117 52 m_fMarginRight = m_pParam->GetFloat(_S("graph.margin.right"));
tomwalters@117 53 m_fMarginTop = m_pParam->GetFloat(_S("graph.margin.top"));
tomwalters@117 54 m_fMarginBottom = m_pParam->GetFloat(_S("graph.margin.bottom"));
tomwalters@117 55 m_bPlotLabels = m_pParam->GetBool(_S("graph.plotlabels"));
tomwalters@116 56
tomwalters@117 57 const char *sGraphType = m_pParam->GetString(_S("graph.type"));
tomwalters@117 58 if (strcmp(sGraphType, _S("line"))==0)
tomwalters@117 59 m_iGraphType = GraphTypeLine;
tomwalters@117 60 else if (strcmp(sGraphType, _S("colormap"))==0)
tomwalters@117 61 m_iGraphType = GraphTypeColormap;
tomwalters@117 62 else if (strcmp(sGraphType, _S("none"))==0)
tomwalters@117 63 m_iGraphType = GraphTypeNone;
tomwalters@117 64 else {
tom@118 65 LOG_ERROR(_T("Unrecognized graph type: '%s'"), sGraphType);
tom@118 66 initialized_ = false;
tomwalters@117 67 }
tomwalters@116 68
tomwalters@117 69 if (strcmp(m_pParam->GetString(_S("graph.mindistance")),"auto") == 0)
tomwalters@117 70 // -1 means detect later, based on type and Fire() argument
tomwalters@117 71 m_fMinPlotDistance = -1;
tomwalters@117 72 else
tomwalters@117 73 m_fMinPlotDistance = m_pParam->GetFloat(_S("graph.mindistance"));
tomwalters@116 74 }
tomwalters@116 75
tomwalters@116 76 GraphicsView::~GraphicsView() {
tomwalters@117 77 DELETE_IF_NONNULL(m_pAxisX);
tomwalters@117 78 DELETE_IF_NONNULL(m_pAxisY);
tomwalters@117 79 DELETE_IF_NONNULL(m_pAxisFreq);
tomwalters@116 80 }
tomwalters@116 81
tom@118 82 void GraphicsView::ResetInternal() {
tom@118 83 }
tomwalters@116 84
tomwalters@116 85 bool GraphicsView::InitializeInternal(const SignalBank &bank) {
tomwalters@117 86 if (!m_pDev) {
tomwalters@117 87 LOG_ERROR("Output device not connected");
tomwalters@117 88 return false;
tomwalters@117 89 }
tomwalters@116 90
tomwalters@116 91 float y_min = bank.centre_frequency(0);
tomwalters@116 92 float y_max = bank.centre_frequency(bank.channel_count() - 1);
tomwalters@117 93 if (!m_pAxisFreq->Initialize(m_pParam,
tomwalters@116 94 "graph.freq",
tomwalters@117 95 y_min,
tomwalters@117 96 y_max,
tomwalters@117 97 Scale::SCALE_ERB)) {
tomwalters@116 98 LOG_ERROR("");
tomwalters@116 99 return false;
tomwalters@116 100 }
tomwalters@116 101
tomwalters@116 102 float x_min = 0.0;
tomwalters@116 103 float x_max = 1000.0 * bank.buffer_length() / bank.sample_rate();
tomwalters@117 104 if (!m_pAxisX->Initialize(m_pParam,
tomwalters@116 105 "graph.x",
tomwalters@117 106 x_min,
tomwalters@116 107 x_max,
tomwalters@117 108 Scale::SCALE_LINEAR)) {
tomwalters@116 109 LOG_ERROR("");
tomwalters@116 110 return false;
tomwalters@116 111 }
tomwalters@116 112
tomwalters@117 113 /* Inform graphics output of maximum number of vertices between
tomwalters@117 114 * gBegin*() and gEnd(), for any type of plot. Colormap needs most.
tomwalters@117 115 */
tom@118 116 if (!m_pDev->Initialize(std::max<int>(10, bank.buffer_length() * 2 + 2))) {
tomwalters@116 117 LOG_ERROR("");
tomwalters@116 118 return false;
tomwalters@116 119 }
tom@118 120 return true;
tomwalters@116 121 }
tomwalters@116 122
tomwalters@116 123 void GraphicsView::Process(const SignalBank &bank) {
tomwalters@117 124 float height = 1.0 / bank.channel_count();
tomwalters@117 125 float heightMinMargin = height * (1.0f - m_fMarginBottom - m_fMarginTop);
tomwalters@117 126 float xScaling = 1.0f;
tomwalters@116 127
tomwalters@117 128 m_pDev->gGrab();
tomwalters@117 129 PlotAxes(bank);
tomwalters@117 130 m_pDev->gColor3f(1.0f, 1.0f, 0.8f);
tomwalters@117 131 for (int i = 0; i < bank.channel_count(); i++) {
tomwalters@117 132 float yOffs = bank.centre_frequency(i);
tomwalters@117 133 yOffs = m_pAxisFreq->m_pScale->FromLinearScaled(yOffs) + 0.5f;
tomwalters@117 134 /* Don't plot below zero and stop when above 1, since yOffs is
tomwalters@116 135 * monotonically increasing. Because of rounding errors, we need
tomwalters@116 136 * to check for yOffs < -1e-6 instead of yOffs < 0. */
tomwalters@117 137 if (yOffs < -1e-6)
tomwalters@116 138 continue;
tomwalters@117 139 if (yOffs > 1)
tomwalters@116 140 break;
tomwalters@116 141
tomwalters@116 142 // Scale to single channel graphing.
tomwalters@117 143 yOffs = yOffs * (1.0f - height) + height / 2.0;
tomwalters@117 144 yOffs = yOffs * (1.0f - m_fMarginTop - m_fMarginBottom) + m_fMarginBottom;
tom@118 145 PlotData(bank[i], bank.sample_rate(), yOffs, heightMinMargin, xScaling);
tomwalters@117 146 }
tomwalters@117 147 m_pDev->gRelease();
tomwalters@116 148 }
tomwalters@116 149
tomwalters@116 150 void GraphicsView::SetAxisScale(Scale::ScaleType iHori,
tomwalters@116 151 Scale::ScaleType iVert,
tomwalters@116 152 Scale::ScaleType iFreq) {
tomwalters@117 153 AIM_ASSERT(m_pAxisX);
tomwalters@117 154 AIM_ASSERT(m_pAxisY);
tomwalters@117 155 AIM_ASSERT(m_pAxisFreq);
tomwalters@117 156 m_pAxisX->SetDisplayScale(iHori);
tomwalters@117 157 m_pAxisY->SetDisplayScale(iVert);
tomwalters@117 158 m_pAxisFreq->SetDisplayScale(iFreq);
tomwalters@116 159 }
tomwalters@116 160
tomwalters@116 161 void GraphicsView::BeginDataStrip() {
tomwalters@117 162 m_iPrevValEqual=0;
tomwalters@117 163 m_bFirstPoint=true;
tomwalters@117 164 switch(m_iGraphType) {
tomwalters@117 165 case GraphTypeLine:
tomwalters@117 166 m_pDev->gBeginLineStrip();
tomwalters@117 167 break;
tomwalters@117 168 case GraphTypeColormap:
tomwalters@117 169 m_pDev->gBeginQuadStrip();
tomwalters@117 170 break;
tomwalters@117 171 case GraphTypeNone:
tomwalters@117 172 // Nothing: just for testing computation overhead of graphing
tomwalters@117 173 break;
tomwalters@117 174 }
tomwalters@116 175 }
tomwalters@116 176
tomwalters@116 177 void GraphicsView::PlotDataPoint(float x,
tomwalters@116 178 float y,
tomwalters@116 179 float val,
tomwalters@116 180 float height,
tomwalters@116 181 bool isLast) {
tomwalters@117 182 AIM_ASSERT(m_pDev);
tomwalters@116 183
tomwalters@117 184 /* Reduce the number of points plotted by eliminating duplicate values:
tomwalters@117 185 *
tomwalters@117 186 * oooo o--o
tomwalters@117 187 * o / o
tomwalters@117 188 * oooo ooo => o--o o--o
tomwalters@117 189 * oooo ooo o--o o-o
tomwalters@117 190 *
tomwalters@117 191 * with 'o' points that are plotted, and '-' by the graphics output
tomwalters@117 192 * device interpolated points. We could be smarter and include
tomwalters@117 193 * first-order interpolation, but we leave that as an exercise for
tomwalters@117 194 * the reader. Please send your patches :)
tomwalters@117 195 *
tomwalters@117 196 * So, we don't draw points that are too close to the previous value.
tomwalters@117 197 * But if the value changes (or it's the last point), we must draw the
tomwalters@117 198 * previous point too.
tomwalters@117 199 */
tomwalters@117 200 if (!m_bFirstPoint
tomwalters@116 201 && !isLast
tom@118 202 && abs(m_fPrevVal-val) < m_fMinPlotDistance) {
tomwalters@117 203 m_iPrevValEqual++;
tomwalters@117 204 // Don't set m_fPrevVal to avoid not catching slow changes
tomwalters@117 205 m_fPrevX = x;
tomwalters@117 206 m_fPrevY = y;
tomwalters@117 207 m_fPrevHeight = height;
tomwalters@117 208 return;
tomwalters@117 209 } else {
tomwalters@117 210 if (m_iPrevValEqual > 0) {
tomwalters@117 211 // Draw previous point
tomwalters@117 212 PlotDataPointDirect(m_fPrevX, m_fPrevY, m_fPrevVal, m_fPrevHeight);
tomwalters@117 213 }
tomwalters@117 214 m_iPrevValEqual = 0;
tomwalters@117 215 m_fPrevVal = val;
tomwalters@117 216 m_bFirstPoint = false;
tomwalters@117 217 }
tomwalters@117 218 PlotDataPointDirect(x, y, val, height);
tomwalters@116 219 }
tomwalters@116 220
tomwalters@116 221 void GraphicsView::PlotDataPointDirect(float x,
tomwalters@116 222 float y,
tomwalters@116 223 float val,
tomwalters@116 224 float height) {
tomwalters@117 225 // Draw it in the right way
tomwalters@117 226 switch(m_iGraphType) {
tomwalters@117 227 case GraphTypeLine:
tomwalters@117 228 m_pDev->gVertex2f(x, y + val * height);
tomwalters@117 229 break;
tomwalters@117 230 case GraphTypeColormap:
tomwalters@117 231 //! \todo make it a real colormap instead of grayscale
tomwalters@117 232 m_pDev->gColor3f(val + 0.5, val + 0.5, val + 0.5);
tomwalters@117 233 m_pDev->gVertex2f(x, y - height / 2);
tomwalters@117 234 m_pDev->gVertex2f(x, y + height / 2);
tomwalters@117 235 break;
tomwalters@117 236 case GraphTypeNone:
tomwalters@117 237 // Nothing: just for testing computation overhead of graphing
tomwalters@117 238 break;
tomwalters@117 239 default:
tomwalters@117 240 // Shouldn't happen
tomwalters@117 241 AIM_ASSERT(0);
tomwalters@117 242 }
tomwalters@116 243 }
tom@118 244 } // namespace aimc