annotate src/Modules/Output/Graphics/GraphicsView.cc @ 126:a9cb396529c2

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