1 /************************************************************************
3 * Copyright 2010-2011 Jakob Leben (jakob.leben@gmail.com)
5 * This file is part of Qt GUI for SuperCollider.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ************************************************************************/
22 #include "QcScopeShm.h"
23 #include "scope_shm_interface.hpp"
24 #include "../QcWidgetFactory.h"
29 #include <QResizeEvent>
31 static QcWidgetFactory
<QcScopeShm
> factory
;
33 QcScopeShm::QcScopeShm() :
36 _shm(new ScopeShm(this)),
47 setAttribute( Qt::WA_OpaquePaintEvent
, true );
48 setAutoFillBackground(false);
50 setSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Expanding
);
52 timer
= new QTimer( this );
53 timer
->setInterval( 50 );
54 connect( timer
, SIGNAL( timeout() ), this, SLOT( updateScope() ) );
57 QcScopeShm::~QcScopeShm()
62 void QcScopeShm::setServerPort( int port
)
65 qcWarningMsg( "QScope: Can not change server port while running!" );
72 void QcScopeShm::setBufferNumber( int n
)
75 // TODO: release used reader?
76 initScopeReader( _shm
, n
);
81 void QcScopeShm::setWaveColors( const VariantList
& newColors
)
84 Q_FOREACH( QVariant var
, newColors
.data
) {
85 QColor color
= var
.value
<QColor
>();
86 if( !color
.isValid() )
87 colors
.append( QColor( 0,0,0 ) );
89 colors
.append( color
);
93 int QcScopeShm::updateInterval() const {
94 return timer
->interval();
97 void QcScopeShm::setUpdateInterval( int interval
) {
98 timer
->setInterval( qMax(0, interval
) );
101 void QcScopeShm::start()
103 if( _running
) return;
104 if( _srvPort
< 0 || _scopeIndex
< 0 ) return;
106 connectSharedMemory( _srvPort
);
107 if( !_shm
->client
) {
112 initScopeReader( _shm
, _scopeIndex
);
119 void QcScopeShm::stop()
121 // TODO: release used reader?
131 void QcScopeShm::updateScope()
133 bool valid
= _shm
->reader
.valid();
134 //qcDebugMsg(1, tr("valid = %1").arg(valid));
137 bool ok
= _shm
->reader
.pull( _availableFrames
);
138 //qcDebugMsg(1, tr("Got %1 frames").arg(_availableFrames) );
140 _data
= _shm
->reader
.data();
145 void QcScopeShm::resizeEvent ( QResizeEvent
* ev
)
147 _pixmap
= QPixmap(ev
->size());
150 void QcScopeShm::paintEvent ( QPaintEvent
* event
)
156 _pixmap
.fill( _bkg
);
158 if( _running
&& _availableFrames
) {
160 int chanCount
= _shm
->reader
.channels();
161 int maxFrames
= _shm
->reader
.max_frames();
162 QRect
area (_pixmap
.rect());
167 paint1D( false, chanCount
, maxFrames
, _availableFrames
, area
, p
);
170 paint1D( true, chanCount
, maxFrames
, _availableFrames
, area
, p
);
173 paint2D( chanCount
, maxFrames
, _availableFrames
, area
, p
);
181 p
.drawPixmap(0, 0, _pixmap
);
184 void QcScopeShm::paint1D( bool overlapped
, int chanCount
, int maxFrames
, int frameCount
,
185 const QRect
&area
, QPainter
& painter
)
187 //qcDebugMsg( 0, tr("Drawing: data %1 / channels %2 / max-size %3").arg(_data!=0).arg(chanCount).arg(maxFrames) );
189 if( frameCount
< 2 || area
.width() < 1 || area
.height() < 1 ) return;
191 float yRatio
= - yZoom
* area
.height() * 0.5;
192 if( !overlapped
) yRatio
/= chanCount
;
193 float yHeight
= area
.height();
194 if( !overlapped
) yHeight
/= chanCount
;
196 if( frameCount
< area
.width() )
198 float xRatio
= xZoom
* area
.width() / (frameCount
-1);
200 for( int ch
= 0; ch
< chanCount
; ch
++ ) {
201 float *frameData
= _data
+ (ch
* maxFrames
); //frame vector
202 float yOrigin
= yHeight
* (overlapped
? 0.5 : ch
+ 0.5);
203 QColor color
= ( ch
< colors
.count() ? colors
[ch
] : QColor(255,255,255) );
206 painter
.translate( area
.x(), area
.y() + yOrigin
);
207 painter
.scale( xRatio
, yRatio
);
208 painter
.setPen(color
);
211 path
.moveTo( xOffset
, frameData
[0] );
212 for( int f
= 1; f
< frameCount
; ++f
)
213 path
.lineTo( xOffset
+ f
, frameData
[f
] );
215 painter
.drawPath(path
);
222 int w
= area
.width();
223 float fpp
= frameCount
/ (float) w
; // frames per x pixel
224 float ypix
= yRatio
!= 0.f
? -1/yRatio
: 0.f
; // value per y pixel;
226 for( int ch
= 0; ch
< chanCount
; ch
++ )
228 float *frameData
= _data
+ (ch
* maxFrames
); //frame vector
229 float yOrigin
= yHeight
* (overlapped
? 0.5 : ch
+ 0.5);
230 QColor color
= ( ch
< colors
.count() ? colors
[ch
] : QColor(255,255,255) );
233 painter
.translate( area
.x(), area
.y() + yOrigin
);
235 pen
.setCapStyle( Qt::FlatCap
);
240 int p
=0, f
=1; // pixel, frame
242 min
= max
= frameData
[0];
248 for(; f
< f_max
; ++f
)
250 float d
= frameData
[f
];
251 if( d
< min
) min
= d
;
252 if( d
> max
) max
= d
;
256 float y
= max
* yRatio
;
258 y
= qMax( min
* yRatio
, y
+1 );
261 // flip min/max to ensure continuity
267 painter
.drawPath(path
);
274 void QcScopeShm::paint2D( int chanCount
, int maxFrames
, int frameCount
,
275 const QRect
&area
, QPainter
& painter
)
277 QColor color
= colors
.count() ? colors
[0] : QColor(255,255,255);
279 int minSize
= qMin( area
.width(), area
.height() );
280 // NOTE: use yZoom for both axis, since both represent value, as opposed to index
281 float xRatio
= yZoom
* minSize
* 0.5;
282 float yRatio
= -yZoom
* minSize
* 0.5;
283 QPoint center
= area
.center();
285 painter
.setPen(color
);
286 painter
.translate( center
.x(), center
.y() );
287 painter
.scale( xRatio
, yRatio
);
293 float *data1
= _data
;
294 float *data2
= _data
+ maxFrames
;
296 path
.moveTo( data1
[0], data2
[0] );
297 for( int f
= 1; f
< frameCount
; ++f
)
298 path
.lineTo( data1
[f
], data2
[f
] );
302 float *data1
= _data
;
303 path
.moveTo( data1
[0], 0.f
);
304 for( int f
= 1; f
< frameCount
; ++f
)
305 path
.lineTo( data1
[f
], 0.f
);
308 painter
.drawPath(path
);
311 void QcScopeShm::connectSharedMemory( int port
)
314 server_shared_memory_client
* client
= new server_shared_memory_client(port
);
315 _shm
->client
= client
;
316 qcDebugMsg(1,"Shared memory connected");
317 } catch (std::exception
& e
) {
319 qcErrorMsg(QString("Cannot connect to shared memory: %1").arg(e
.what()) );
323 void QcScopeShm::initScopeReader( ScopeShm
*shm
, int index
)
325 shm
->reader
= shm
->client
->get_scope_buffer_reader( index
);
326 qcDebugMsg(1,QString("Initialized scope buffer reader for index %1.").arg(index
));