annotate trunk/src/Modules/Output/Graphics/GraphicsView.cc @ 706:f8e90b5d85fd tip

Delete CARFAC code from this repository. It has been moved to https://github.com/google/carfac Please email me with your github username to get access. I've also created a new mailing list to discuss CARFAC development: https://groups.google.com/forum/#!forum/carfac-dev
author ronw@google.com
date Thu, 18 Jul 2013 20:56:51 +0000
parents 16a590fbc0ba
children
rev   line source
tomwalters@397 1 // Copyright 2006, Willem van Engen
tomwalters@397 2 //
tomwalters@397 3 // AIM-C: A C++ implementation of the Auditory Image Model
tomwalters@397 4 // http://www.acousticscale.org/AIMC
tomwalters@397 5 //
tomwalters@397 6 // Licensed under the Apache License, Version 2.0 (the "License");
tomwalters@397 7 // you may not use this file except in compliance with the License.
tomwalters@397 8 // You may obtain a copy of the License at
tomwalters@397 9 //
tomwalters@397 10 // http://www.apache.org/licenses/LICENSE-2.0
tomwalters@397 11 //
tomwalters@397 12 // Unless required by applicable law or agreed to in writing, software
tomwalters@397 13 // distributed under the License is distributed on an "AS IS" BASIS,
tomwalters@397 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
tomwalters@397 15 // See the License for the specific language governing permissions and
tomwalters@397 16 // limitations under the License.
tomwalters@397 17
tom@399 18 #include <algorithm>
tom@399 19
tomwalters@397 20 #include "Support/Common.h"
tomwalters@397 21
tom@399 22 #include "Modules/Output/Graphics/GraphicsView.h"
tom@399 23 #include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h"
tomwalters@411 24 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h"
tom@399 25
tom@399 26 namespace aimc {
tomwalters@397 27
tomwalters@397 28 GraphicsView::GraphicsView(Parameters *parameters) : Module(parameters) {
tomwalters@402 29 module_description_ = "Graphics output.";
tomwalters@397 30 module_identifier_ = "graphics";
tomwalters@397 31 module_type_ = "output";
tomwalters@397 32 module_version_ = "$Id: $";
tomwalters@443 33
tomwalters@443 34 if (parameters_->DefaultBool("output.images", false)) {
tomwalters@443 35 m_pDev = new GraphicsOutputDeviceCairo(parameters_);
tomwalters@443 36 } else {
tomwalters@443 37 m_pDev = new GraphicsOutputDeviceMovie(parameters_);
tomwalters@443 38 }
tomwalters@398 39 m_bPlotLabels = false;
tomwalters@398 40 m_pAxisX = new GraphAxisSpec();
tomwalters@398 41 AIM_ASSERT(m_pAxisX);
tomwalters@398 42 m_pAxisY = new GraphAxisSpec();
tomwalters@398 43 AIM_ASSERT(m_pAxisY);
tomwalters@398 44 m_pAxisFreq = new GraphAxisSpec();
tomwalters@398 45 AIM_ASSERT(m_pAxisFreq);
tom@399 46 initialized_ = true;
tomwalters@397 47
tomwalters@410 48 if (!m_pAxisY->Initialize(parameters_,
tom@399 49 _S("graph.y"),
tom@399 50 -1,
tom@399 51 1,
tom@399 52 Scale::SCALE_LINEAR)) {
tom@399 53 LOG_ERROR("Axis initialization failed");
tom@399 54 initialized_ = false;
tom@399 55 }
tomwalters@411 56 m_fMarginLeft = parameters_->DefaultFloat(_S("graph.margin.left"), 0.05);
tomwalters@411 57 m_fMarginRight = parameters_->DefaultFloat(_S("graph.margin.right"), 0.005);
tomwalters@411 58 m_fMarginTop = parameters_->DefaultFloat(_S("graph.margin.top"), 0.005);
tomwalters@411 59 m_fMarginBottom = parameters_->DefaultFloat(_S("graph.margin.bottom"), 0.05);
tomwalters@411 60 m_bPlotLabels = parameters_->DefaultBool(_S("graph.plotlabels"), true);
tomwalters@569 61 plotting_strobes_ = parameters_->DefaultBool(_S("graph.plot_strobes"), false);
tomwalters@397 62
tomwalters@411 63 const char *sGraphType = parameters_->DefaultString(_S("graph.type"), "line");
tomwalters@398 64 if (strcmp(sGraphType, _S("line"))==0)
tomwalters@398 65 m_iGraphType = GraphTypeLine;
tomwalters@398 66 else if (strcmp(sGraphType, _S("colormap"))==0)
tomwalters@398 67 m_iGraphType = GraphTypeColormap;
tomwalters@398 68 else if (strcmp(sGraphType, _S("none"))==0)
tomwalters@398 69 m_iGraphType = GraphTypeNone;
tomwalters@398 70 else {
tom@399 71 LOG_ERROR(_T("Unrecognized graph type: '%s'"), sGraphType);
tom@399 72 initialized_ = false;
tomwalters@398 73 }
tomwalters@397 74
tomwalters@411 75 if (strcmp(parameters_->DefaultString(_S("graph.mindistance"), "auto"),"auto") == 0)
tomwalters@398 76 // -1 means detect later, based on type and Fire() argument
tomwalters@398 77 m_fMinPlotDistance = -1;
tomwalters@398 78 else
tomwalters@410 79 m_fMinPlotDistance = parameters_->GetFloat(_S("graph.mindistance"));
tomwalters@397 80 }
tomwalters@397 81
tomwalters@397 82 GraphicsView::~GraphicsView() {
tomwalters@398 83 DELETE_IF_NONNULL(m_pAxisX);
tomwalters@398 84 DELETE_IF_NONNULL(m_pAxisY);
tomwalters@398 85 DELETE_IF_NONNULL(m_pAxisFreq);
tomwalters@397 86 }
tomwalters@397 87
tom@399 88 void GraphicsView::ResetInternal() {
tomwalters@411 89 if (m_pDev != NULL) {
tomwalters@418 90 m_pDev->Reset(global_parameters_);
tomwalters@411 91 }
tom@399 92 }
tomwalters@397 93
tomwalters@397 94 bool GraphicsView::InitializeInternal(const SignalBank &bank) {
tomwalters@398 95 if (!m_pDev) {
tomwalters@398 96 LOG_ERROR("Output device not connected");
tomwalters@398 97 return false;
tomwalters@398 98 }
tomwalters@397 99
tomwalters@397 100 float y_min = bank.centre_frequency(0);
tomwalters@397 101 float y_max = bank.centre_frequency(bank.channel_count() - 1);
tomwalters@410 102 if (!m_pAxisFreq->Initialize(parameters_,
tomwalters@397 103 "graph.freq",
tomwalters@398 104 y_min,
tomwalters@398 105 y_max,
tomwalters@398 106 Scale::SCALE_ERB)) {
tomwalters@411 107 LOG_ERROR("Frequency axis init failed.");
tomwalters@397 108 return false;
tomwalters@397 109 }
tomwalters@397 110
tomwalters@397 111 float x_min = 0.0;
tomwalters@397 112 float x_max = 1000.0 * bank.buffer_length() / bank.sample_rate();
tomwalters@410 113 if (!m_pAxisX->Initialize(parameters_,
tomwalters@397 114 "graph.x",
tomwalters@398 115 x_min,
tomwalters@397 116 x_max,
tomwalters@398 117 Scale::SCALE_LINEAR)) {
tomwalters@411 118 LOG_ERROR("Time axis init failed.");
tomwalters@397 119 return false;
tomwalters@397 120 }
tomwalters@397 121
tomwalters@398 122 /* Inform graphics output of maximum number of vertices between
tomwalters@398 123 * gBegin*() and gEnd(), for any type of plot. Colormap needs most.
tomwalters@398 124 */
tomwalters@411 125 LOG_INFO("Initializing graphics output device.");
tomwalters@411 126
tomwalters@411 127 if (!m_pDev->Initialize(global_parameters_)) {
tomwalters@411 128 LOG_ERROR("Graphics output device init failed.");
tomwalters@397 129 return false;
tomwalters@397 130 }
tomwalters@411 131 m_pDev->Start();
tomwalters@411 132 previous_start_time_ = 0;
tom@399 133 return true;
tomwalters@397 134 }
tomwalters@397 135
tomwalters@397 136 void GraphicsView::Process(const SignalBank &bank) {
tomwalters@398 137 float height = 1.0 / bank.channel_count();
tomwalters@398 138 float heightMinMargin = height * (1.0f - m_fMarginBottom - m_fMarginTop);
tomwalters@398 139 float xScaling = 1.0f;
tomwalters@569 140 float diameter = height / 5.0;
tomwalters@397 141
tomwalters@398 142 m_pDev->gGrab();
tomwalters@398 143 PlotAxes(bank);
tomwalters@398 144 m_pDev->gColor3f(1.0f, 1.0f, 0.8f);
tomwalters@398 145 for (int i = 0; i < bank.channel_count(); i++) {
tomwalters@398 146 float yOffs = bank.centre_frequency(i);
tomwalters@398 147 yOffs = m_pAxisFreq->m_pScale->FromLinearScaled(yOffs) + 0.5f;
tomwalters@398 148 /* Don't plot below zero and stop when above 1, since yOffs is
tomwalters@397 149 * monotonically increasing. Because of rounding errors, we need
tomwalters@397 150 * to check for yOffs < -1e-6 instead of yOffs < 0. */
tomwalters@398 151 if (yOffs < -1e-6)
tomwalters@397 152 continue;
tomwalters@398 153 if (yOffs > 1)
tomwalters@397 154 break;
tomwalters@397 155
tomwalters@397 156 // Scale to single channel graphing.
tomwalters@398 157 yOffs = yOffs * (1.0f - height) + height / 2.0;
tomwalters@398 158 yOffs = yOffs * (1.0f - m_fMarginTop - m_fMarginBottom) + m_fMarginBottom;
tom@399 159 PlotData(bank[i], bank.sample_rate(), yOffs, heightMinMargin, xScaling);
tomwalters@569 160 if (plotting_strobes_) {
tomwalters@569 161 PlotStrobes(bank[i], bank.get_strobes(i), bank.sample_rate(),
tomwalters@569 162 yOffs, heightMinMargin ,xScaling, diameter);
tomwalters@569 163 }
tomwalters@398 164 }
tomwalters@398 165 m_pDev->gRelease();
tomwalters@411 166
tomwalters@411 167 frame_rate_ = bank.sample_rate()
tomwalters@411 168 / (bank.start_time() - previous_start_time_);
tomwalters@411 169 previous_start_time_ = bank.start_time();
tomwalters@411 170 global_parameters_->SetFloat("frame_rate", frame_rate_);
tomwalters@397 171 }
tomwalters@397 172
tomwalters@397 173 void GraphicsView::SetAxisScale(Scale::ScaleType iHori,
tomwalters@397 174 Scale::ScaleType iVert,
tomwalters@397 175 Scale::ScaleType iFreq) {
tomwalters@398 176 AIM_ASSERT(m_pAxisX);
tomwalters@398 177 AIM_ASSERT(m_pAxisY);
tomwalters@398 178 AIM_ASSERT(m_pAxisFreq);
tomwalters@398 179 m_pAxisX->SetDisplayScale(iHori);
tomwalters@398 180 m_pAxisY->SetDisplayScale(iVert);
tomwalters@398 181 m_pAxisFreq->SetDisplayScale(iFreq);
tomwalters@397 182 }
tomwalters@397 183
tomwalters@397 184 void GraphicsView::BeginDataStrip() {
tomwalters@398 185 m_iPrevValEqual=0;
tomwalters@398 186 m_bFirstPoint=true;
tomwalters@398 187 switch(m_iGraphType) {
tomwalters@398 188 case GraphTypeLine:
tomwalters@398 189 m_pDev->gBeginLineStrip();
tomwalters@398 190 break;
tomwalters@398 191 case GraphTypeColormap:
tomwalters@398 192 m_pDev->gBeginQuadStrip();
tomwalters@398 193 break;
tomwalters@398 194 case GraphTypeNone:
tomwalters@398 195 // Nothing: just for testing computation overhead of graphing
tomwalters@398 196 break;
tomwalters@398 197 }
tomwalters@397 198 }
tomwalters@397 199
tomwalters@397 200 void GraphicsView::PlotDataPoint(float x,
tomwalters@397 201 float y,
tomwalters@397 202 float val,
tomwalters@397 203 float height,
tomwalters@397 204 bool isLast) {
tomwalters@398 205 AIM_ASSERT(m_pDev);
tomwalters@397 206
tomwalters@398 207 /* Reduce the number of points plotted by eliminating duplicate values:
tomwalters@398 208 *
tomwalters@398 209 * oooo o--o
tomwalters@398 210 * o / o
tomwalters@398 211 * oooo ooo => o--o o--o
tomwalters@398 212 * oooo ooo o--o o-o
tomwalters@398 213 *
tomwalters@398 214 * with 'o' points that are plotted, and '-' by the graphics output
tomwalters@398 215 * device interpolated points. We could be smarter and include
tomwalters@398 216 * first-order interpolation, but we leave that as an exercise for
tomwalters@398 217 * the reader. Please send your patches :)
tomwalters@398 218 *
tomwalters@398 219 * So, we don't draw points that are too close to the previous value.
tomwalters@398 220 * But if the value changes (or it's the last point), we must draw the
tomwalters@398 221 * previous point too.
tomwalters@398 222 */
tomwalters@398 223 if (!m_bFirstPoint
tomwalters@397 224 && !isLast
tom@399 225 && abs(m_fPrevVal-val) < m_fMinPlotDistance) {
tomwalters@398 226 m_iPrevValEqual++;
tomwalters@398 227 // Don't set m_fPrevVal to avoid not catching slow changes
tomwalters@398 228 m_fPrevX = x;
tomwalters@398 229 m_fPrevY = y;
tomwalters@398 230 m_fPrevHeight = height;
tomwalters@398 231 return;
tomwalters@398 232 } else {
tomwalters@398 233 if (m_iPrevValEqual > 0) {
tomwalters@398 234 // Draw previous point
tomwalters@398 235 PlotDataPointDirect(m_fPrevX, m_fPrevY, m_fPrevVal, m_fPrevHeight);
tomwalters@398 236 }
tomwalters@398 237 m_iPrevValEqual = 0;
tomwalters@398 238 m_fPrevVal = val;
tomwalters@398 239 m_bFirstPoint = false;
tomwalters@398 240 }
tomwalters@398 241 PlotDataPointDirect(x, y, val, height);
tomwalters@397 242 }
tomwalters@397 243
tomwalters@569 244 void GraphicsView::PlotStrobe(float x, float y, float val,
tomwalters@569 245 float height,
tomwalters@569 246 float diameter) {
tomwalters@569 247 switch(m_iGraphType) {
tomwalters@569 248 case GraphTypeLine:
tomwalters@569 249 m_pDev->gBeginQuadStrip();
tomwalters@569 250 m_pDev->gVertex2f(x + diameter, y + val * height + diameter);
tomwalters@569 251 m_pDev->gVertex2f(x + diameter, y + val * height - diameter);
tomwalters@569 252 m_pDev->gVertex2f(x - diameter, y + val * height - diameter);
tomwalters@569 253 m_pDev->gVertex2f(x - diameter, y + val * height + diameter);
tomwalters@569 254 m_pDev->gEnd();
tomwalters@569 255 break;
tomwalters@569 256 case GraphTypeColormap:
tomwalters@569 257 m_pDev->gBeginQuadStrip();
tomwalters@569 258 m_pDev->gVertex2f(x + diameter, y + diameter);
tomwalters@569 259 m_pDev->gVertex2f(x + diameter, y - diameter);
tomwalters@569 260 m_pDev->gVertex2f(x - diameter, y - diameter);
tomwalters@569 261 m_pDev->gVertex2f(x - diameter, y + diameter);
tomwalters@569 262 m_pDev->gEnd();
tomwalters@569 263 break;
tomwalters@569 264 case GraphTypeNone:
tomwalters@569 265 // Nothing: just for testing computation overhead of graphing
tomwalters@569 266 break;
tomwalters@569 267 default:
tomwalters@569 268 // Shouldn't happen
tomwalters@569 269 AIM_ASSERT(0);
tomwalters@569 270 }
tomwalters@569 271 }
tomwalters@569 272
tomwalters@397 273 void GraphicsView::PlotDataPointDirect(float x,
tomwalters@397 274 float y,
tomwalters@397 275 float val,
tomwalters@397 276 float height) {
tomwalters@398 277 // Draw it in the right way
tomwalters@398 278 switch(m_iGraphType) {
tomwalters@398 279 case GraphTypeLine:
tomwalters@398 280 m_pDev->gVertex2f(x, y + val * height);
tomwalters@398 281 break;
tomwalters@398 282 case GraphTypeColormap:
tomwalters@398 283 //! \todo make it a real colormap instead of grayscale
tomwalters@398 284 m_pDev->gColor3f(val + 0.5, val + 0.5, val + 0.5);
tomwalters@398 285 m_pDev->gVertex2f(x, y - height / 2);
tomwalters@398 286 m_pDev->gVertex2f(x, y + height / 2);
tomwalters@398 287 break;
tomwalters@398 288 case GraphTypeNone:
tomwalters@398 289 // Nothing: just for testing computation overhead of graphing
tomwalters@398 290 break;
tomwalters@398 291 default:
tomwalters@398 292 // Shouldn't happen
tomwalters@398 293 AIM_ASSERT(0);
tomwalters@398 294 }
tomwalters@397 295 }
tom@399 296 } // namespace aimc