annotate src/Modules/Output/Graphics/GraphicsView.cc @ 611:0fbaf443ec82

Carfac C++ revision 3, indluding more style improvements. The output structs are now classes again, and have separate storage methods for each output structure along with flags in the Run and RunSegment methods to allow for only storing NAPs if desired.
author alexbrandmeyer
date Fri, 17 May 2013 19:52:45 +0000
parents d609725e568a
children
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@229 18 #include <algorithm>
tom@229 19
tomwalters@116 20 #include "Support/Common.h"
tomwalters@116 21
tom@229 22 #include "Modules/Output/Graphics/GraphicsView.h"
tom@229 23 #include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h"
tomwalters@237 24 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h"
tom@229 25
tom@229 26 namespace aimc {
tomwalters@116 27
tomwalters@116 28 GraphicsView::GraphicsView(Parameters *parameters) : Module(parameters) {
tomwalters@232 29 module_description_ = "Graphics output.";
tomwalters@116 30 module_identifier_ = "graphics";
tomwalters@116 31 module_type_ = "output";
tomwalters@116 32 module_version_ = "$Id: $";
tomwalters@256 33
tomwalters@256 34 if (parameters_->DefaultBool("output.images", false)) {
tomwalters@256 35 m_pDev = new GraphicsOutputDeviceCairo(parameters_);
tomwalters@256 36 } else {
tomwalters@256 37 m_pDev = new GraphicsOutputDeviceMovie(parameters_);
tomwalters@256 38 }
tomwalters@228 39 m_bPlotLabels = false;
tomwalters@228 40 m_pAxisX = new GraphAxisSpec();
tomwalters@228 41 AIM_ASSERT(m_pAxisX);
tomwalters@228 42 m_pAxisY = new GraphAxisSpec();
tomwalters@228 43 AIM_ASSERT(m_pAxisY);
tomwalters@228 44 m_pAxisFreq = new GraphAxisSpec();
tomwalters@228 45 AIM_ASSERT(m_pAxisFreq);
tom@229 46 initialized_ = true;
tomwalters@145 47
tomwalters@236 48 if (!m_pAxisY->Initialize(parameters_,
tom@229 49 _S("graph.y"),
tom@229 50 -1,
tom@229 51 1,
tom@229 52 Scale::SCALE_LINEAR)) {
tom@229 53 LOG_ERROR("Axis initialization failed");
tom@229 54 initialized_ = false;
tom@229 55 }
tomwalters@237 56 m_fMarginLeft = parameters_->DefaultFloat(_S("graph.margin.left"), 0.05);
tomwalters@237 57 m_fMarginRight = parameters_->DefaultFloat(_S("graph.margin.right"), 0.005);
tomwalters@237 58 m_fMarginTop = parameters_->DefaultFloat(_S("graph.margin.top"), 0.005);
tomwalters@237 59 m_fMarginBottom = parameters_->DefaultFloat(_S("graph.margin.bottom"), 0.05);
tomwalters@237 60 m_bPlotLabels = parameters_->DefaultBool(_S("graph.plotlabels"), true);
tomwalters@508 61 plotting_strobes_ = parameters_->DefaultBool(_S("graph.plot_strobes"), false);
tomwalters@116 62
tomwalters@237 63 const char *sGraphType = parameters_->DefaultString(_S("graph.type"), "line");
tomwalters@228 64 if (strcmp(sGraphType, _S("line"))==0)
tomwalters@228 65 m_iGraphType = GraphTypeLine;
tomwalters@228 66 else if (strcmp(sGraphType, _S("colormap"))==0)
tomwalters@228 67 m_iGraphType = GraphTypeColormap;
tomwalters@228 68 else if (strcmp(sGraphType, _S("none"))==0)
tomwalters@228 69 m_iGraphType = GraphTypeNone;
tomwalters@228 70 else {
tom@229 71 LOG_ERROR(_T("Unrecognized graph type: '%s'"), sGraphType);
tom@229 72 initialized_ = false;
tomwalters@228 73 }
tomwalters@116 74
tomwalters@237 75 if (strcmp(parameters_->DefaultString(_S("graph.mindistance"), "auto"),"auto") == 0)
tomwalters@228 76 // -1 means detect later, based on type and Fire() argument
tomwalters@228 77 m_fMinPlotDistance = -1;
tomwalters@228 78 else
tomwalters@236 79 m_fMinPlotDistance = parameters_->GetFloat(_S("graph.mindistance"));
tomwalters@116 80 }
tomwalters@116 81
tomwalters@116 82 GraphicsView::~GraphicsView() {
tomwalters@228 83 DELETE_IF_NONNULL(m_pAxisX);
tomwalters@228 84 DELETE_IF_NONNULL(m_pAxisY);
tomwalters@228 85 DELETE_IF_NONNULL(m_pAxisFreq);
tomwalters@116 86 }
tomwalters@116 87
tom@229 88 void GraphicsView::ResetInternal() {
tomwalters@237 89 if (m_pDev != NULL) {
tomwalters@244 90 m_pDev->Reset(global_parameters_);
tomwalters@237 91 }
tom@229 92 }
tomwalters@116 93
tomwalters@116 94 bool GraphicsView::InitializeInternal(const SignalBank &bank) {
tomwalters@228 95 if (!m_pDev) {
tomwalters@228 96 LOG_ERROR("Output device not connected");
tomwalters@228 97 return false;
tomwalters@228 98 }
tomwalters@116 99
tomwalters@116 100 float y_min = bank.centre_frequency(0);
tomwalters@116 101 float y_max = bank.centre_frequency(bank.channel_count() - 1);
tomwalters@236 102 if (!m_pAxisFreq->Initialize(parameters_,
tomwalters@116 103 "graph.freq",
tomwalters@228 104 y_min,
tomwalters@228 105 y_max,
tomwalters@228 106 Scale::SCALE_ERB)) {
tomwalters@237 107 LOG_ERROR("Frequency axis init failed.");
tomwalters@116 108 return false;
tomwalters@116 109 }
tomwalters@116 110
tomwalters@116 111 float x_min = 0.0;
tomwalters@116 112 float x_max = 1000.0 * bank.buffer_length() / bank.sample_rate();
tomwalters@236 113 if (!m_pAxisX->Initialize(parameters_,
tomwalters@116 114 "graph.x",
tomwalters@228 115 x_min,
tomwalters@116 116 x_max,
tomwalters@228 117 Scale::SCALE_LINEAR)) {
tomwalters@237 118 LOG_ERROR("Time axis init failed.");
tomwalters@116 119 return false;
tomwalters@116 120 }
tomwalters@116 121
tomwalters@228 122 /* Inform graphics output of maximum number of vertices between
tomwalters@228 123 * gBegin*() and gEnd(), for any type of plot. Colormap needs most.
tomwalters@228 124 */
tomwalters@237 125 LOG_INFO("Initializing graphics output device.");
tomwalters@237 126
tomwalters@237 127 if (!m_pDev->Initialize(global_parameters_)) {
tomwalters@237 128 LOG_ERROR("Graphics output device init failed.");
tomwalters@116 129 return false;
tomwalters@116 130 }
tomwalters@237 131 m_pDev->Start();
tomwalters@237 132 previous_start_time_ = 0;
tom@229 133 return true;
tomwalters@116 134 }
tomwalters@116 135
tomwalters@116 136 void GraphicsView::Process(const SignalBank &bank) {
tomwalters@228 137 float height = 1.0 / bank.channel_count();
tomwalters@228 138 float heightMinMargin = height * (1.0f - m_fMarginBottom - m_fMarginTop);
tomwalters@228 139 float xScaling = 1.0f;
tomwalters@508 140 float diameter = height / 5.0;
tomwalters@116 141
tomwalters@228 142 m_pDev->gGrab();
tomwalters@228 143 PlotAxes(bank);
tomwalters@228 144 m_pDev->gColor3f(1.0f, 1.0f, 0.8f);
tomwalters@228 145 for (int i = 0; i < bank.channel_count(); i++) {
tomwalters@228 146 float yOffs = bank.centre_frequency(i);
tomwalters@228 147 yOffs = m_pAxisFreq->m_pScale->FromLinearScaled(yOffs) + 0.5f;
tomwalters@228 148 /* Don't plot below zero and stop when above 1, since yOffs is
tomwalters@116 149 * monotonically increasing. Because of rounding errors, we need
tomwalters@116 150 * to check for yOffs < -1e-6 instead of yOffs < 0. */
tomwalters@228 151 if (yOffs < -1e-6)
tomwalters@116 152 continue;
tomwalters@228 153 if (yOffs > 1)
tomwalters@116 154 break;
tomwalters@116 155
tomwalters@116 156 // Scale to single channel graphing.
tomwalters@228 157 yOffs = yOffs * (1.0f - height) + height / 2.0;
tomwalters@228 158 yOffs = yOffs * (1.0f - m_fMarginTop - m_fMarginBottom) + m_fMarginBottom;
tom@229 159 PlotData(bank[i], bank.sample_rate(), yOffs, heightMinMargin, xScaling);
tomwalters@508 160 if (plotting_strobes_) {
tomwalters@508 161 PlotStrobes(bank[i], bank.get_strobes(i), bank.sample_rate(),
tomwalters@508 162 yOffs, heightMinMargin ,xScaling, diameter);
tomwalters@508 163 }
tomwalters@228 164 }
tomwalters@228 165 m_pDev->gRelease();
tomwalters@237 166
tomwalters@237 167 frame_rate_ = bank.sample_rate()
tomwalters@237 168 / (bank.start_time() - previous_start_time_);
tomwalters@237 169 previous_start_time_ = bank.start_time();
tomwalters@237 170 global_parameters_->SetFloat("frame_rate", frame_rate_);
tomwalters@116 171 }
tomwalters@116 172
tomwalters@116 173 void GraphicsView::SetAxisScale(Scale::ScaleType iHori,
tomwalters@116 174 Scale::ScaleType iVert,
tomwalters@116 175 Scale::ScaleType iFreq) {
tomwalters@228 176 AIM_ASSERT(m_pAxisX);
tomwalters@228 177 AIM_ASSERT(m_pAxisY);
tomwalters@228 178 AIM_ASSERT(m_pAxisFreq);
tomwalters@228 179 m_pAxisX->SetDisplayScale(iHori);
tomwalters@228 180 m_pAxisY->SetDisplayScale(iVert);
tomwalters@228 181 m_pAxisFreq->SetDisplayScale(iFreq);
tomwalters@116 182 }
tomwalters@116 183
tomwalters@116 184 void GraphicsView::BeginDataStrip() {
tomwalters@228 185 m_iPrevValEqual=0;
tomwalters@228 186 m_bFirstPoint=true;
tomwalters@228 187 switch(m_iGraphType) {
tomwalters@228 188 case GraphTypeLine:
tomwalters@228 189 m_pDev->gBeginLineStrip();
tomwalters@228 190 break;
tomwalters@228 191 case GraphTypeColormap:
tomwalters@228 192 m_pDev->gBeginQuadStrip();
tomwalters@228 193 break;
tomwalters@228 194 case GraphTypeNone:
tomwalters@228 195 // Nothing: just for testing computation overhead of graphing
tomwalters@228 196 break;
tomwalters@228 197 }
tomwalters@116 198 }
tomwalters@116 199
tomwalters@116 200 void GraphicsView::PlotDataPoint(float x,
tomwalters@116 201 float y,
tomwalters@116 202 float val,
tomwalters@116 203 float height,
tomwalters@116 204 bool isLast) {
tomwalters@228 205 AIM_ASSERT(m_pDev);
tomwalters@116 206
tomwalters@228 207 /* Reduce the number of points plotted by eliminating duplicate values:
tomwalters@228 208 *
tomwalters@228 209 * oooo o--o
tomwalters@228 210 * o / o
tomwalters@228 211 * oooo ooo => o--o o--o
tomwalters@228 212 * oooo ooo o--o o-o
tomwalters@228 213 *
tomwalters@228 214 * with 'o' points that are plotted, and '-' by the graphics output
tomwalters@228 215 * device interpolated points. We could be smarter and include
tomwalters@228 216 * first-order interpolation, but we leave that as an exercise for
tomwalters@228 217 * the reader. Please send your patches :)
tomwalters@228 218 *
tomwalters@228 219 * So, we don't draw points that are too close to the previous value.
tomwalters@228 220 * But if the value changes (or it's the last point), we must draw the
tomwalters@228 221 * previous point too.
tomwalters@228 222 */
tomwalters@228 223 if (!m_bFirstPoint
tomwalters@116 224 && !isLast
tom@229 225 && abs(m_fPrevVal-val) < m_fMinPlotDistance) {
tomwalters@228 226 m_iPrevValEqual++;
tomwalters@228 227 // Don't set m_fPrevVal to avoid not catching slow changes
tomwalters@228 228 m_fPrevX = x;
tomwalters@228 229 m_fPrevY = y;
tomwalters@228 230 m_fPrevHeight = height;
tomwalters@228 231 return;
tomwalters@228 232 } else {
tomwalters@228 233 if (m_iPrevValEqual > 0) {
tomwalters@228 234 // Draw previous point
tomwalters@228 235 PlotDataPointDirect(m_fPrevX, m_fPrevY, m_fPrevVal, m_fPrevHeight);
tomwalters@228 236 }
tomwalters@228 237 m_iPrevValEqual = 0;
tomwalters@228 238 m_fPrevVal = val;
tomwalters@228 239 m_bFirstPoint = false;
tomwalters@228 240 }
tomwalters@228 241 PlotDataPointDirect(x, y, val, height);
tomwalters@116 242 }
tomwalters@116 243
tomwalters@508 244 void GraphicsView::PlotStrobe(float x, float y, float val,
tomwalters@508 245 float height,
tomwalters@508 246 float diameter) {
tomwalters@508 247 switch(m_iGraphType) {
tomwalters@508 248 case GraphTypeLine:
tomwalters@508 249 m_pDev->gBeginQuadStrip();
tomwalters@508 250 m_pDev->gVertex2f(x + diameter, y + val * height + diameter);
tomwalters@508 251 m_pDev->gVertex2f(x + diameter, y + val * height - diameter);
tomwalters@508 252 m_pDev->gVertex2f(x - diameter, y + val * height - diameter);
tomwalters@508 253 m_pDev->gVertex2f(x - diameter, y + val * height + diameter);
tomwalters@508 254 m_pDev->gEnd();
tomwalters@508 255 break;
tomwalters@508 256 case GraphTypeColormap:
tomwalters@508 257 m_pDev->gBeginQuadStrip();
tomwalters@508 258 m_pDev->gVertex2f(x + diameter, y + diameter);
tomwalters@508 259 m_pDev->gVertex2f(x + diameter, y - diameter);
tomwalters@508 260 m_pDev->gVertex2f(x - diameter, y - diameter);
tomwalters@508 261 m_pDev->gVertex2f(x - diameter, y + diameter);
tomwalters@508 262 m_pDev->gEnd();
tomwalters@508 263 break;
tomwalters@508 264 case GraphTypeNone:
tomwalters@508 265 // Nothing: just for testing computation overhead of graphing
tomwalters@508 266 break;
tomwalters@508 267 default:
tomwalters@508 268 // Shouldn't happen
tomwalters@508 269 AIM_ASSERT(0);
tomwalters@508 270 }
tomwalters@508 271 }
tomwalters@508 272
tomwalters@116 273 void GraphicsView::PlotDataPointDirect(float x,
tomwalters@116 274 float y,
tomwalters@116 275 float val,
tomwalters@116 276 float height) {
tomwalters@228 277 // Draw it in the right way
tomwalters@228 278 switch(m_iGraphType) {
tomwalters@228 279 case GraphTypeLine:
tomwalters@228 280 m_pDev->gVertex2f(x, y + val * height);
tomwalters@228 281 break;
tomwalters@228 282 case GraphTypeColormap:
tomwalters@228 283 //! \todo make it a real colormap instead of grayscale
tomwalters@228 284 m_pDev->gColor3f(val + 0.5, val + 0.5, val + 0.5);
tomwalters@228 285 m_pDev->gVertex2f(x, y - height / 2);
tomwalters@228 286 m_pDev->gVertex2f(x, y + height / 2);
tomwalters@228 287 break;
tomwalters@228 288 case GraphTypeNone:
tomwalters@228 289 // Nothing: just for testing computation overhead of graphing
tomwalters@228 290 break;
tomwalters@228 291 default:
tomwalters@228 292 // Shouldn't happen
tomwalters@228 293 AIM_ASSERT(0);
tomwalters@228 294 }
tomwalters@116 295 }
tom@229 296 } // namespace aimc