You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tderadio/plugins/recording/recording-datamonitor.cpp

279 lines
8.7 KiB

/***************************************************************************
recording-monitor-widget.cpp - description
-------------------
begin : So Sep 7 2003
copyright : (C) 2003 by Martin Witte
email : witte@kawo1.rwth-aachen.de
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "recording-datamonitor.h"
//#include "recording-context.h"
#include <math.h>
#include <tqpainter.h>
#include <tqimage.h>
#include <tqpixmap.h>
#include <kimageeffect.h> // fading, blending, ...
#include <kpixmapio.h> // fast conversion between TQPixmap/TQImage
#include <limits.h>
#include <stdlib.h>
#include <tdelocale.h>
#define CHANNEL_H_MIN 20
#define BLOCK_W_MIN 10
#define W_MIN (20 * (BLOCK_W_MIN))
RecordingDataMonitor::RecordingDataMonitor(TQWidget *parent, const char *name)
: TQFrame(parent, name),
m_channelsMax(NULL),
m_channelsAvg(NULL),
m_maxValue(INT_MAX),
m_channels(0),
m_pActiveBlocks(NULL)
{
setFrameStyle(Box | Sunken);
setLineWidth(1);
setMidLineWidth(1);
setChannels(2);
setColors(TQColor(20, 244, 20),
TQColor(10, 117, 10));
setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding));
}
RecordingDataMonitor::~RecordingDataMonitor()
{
if (m_channelsMax) delete[] m_channelsMax;
if (m_channelsAvg) delete[] m_channelsAvg;
if (m_pActiveBlocks) delete[] m_pActiveBlocks;
}
// own stuff
void RecordingDataMonitor::setChannels(int n)
{
if (n != m_channels) {
if (m_channelsMax) delete[] m_channelsMax;
if (m_channelsAvg) delete[] m_channelsAvg;
if (m_pActiveBlocks) delete[] m_pActiveBlocks;
m_channels = n > 0 ? n : 0;
if (m_channels > 0) {
m_channelsMax = new int[m_channels];
m_channelsAvg = new double[m_channels];
m_pActiveBlocks = new int[m_channels];
for (int i = 0; i < m_channels; ++i) {
m_pActiveBlocks[i] = 0;
}
} else {
m_channelsMax = NULL;
m_channelsAvg = NULL;
m_pActiveBlocks = NULL;
}
}
for (int i = 0; i < m_channels; ++i) {
m_channelsMax[i] = 0;
m_channelsAvg[i] = 0;
}
setMinimumSize(TQSize(W_MIN, (m_channels + 1 )* CHANNEL_H_MIN));
}
// QT/KDE ...
void RecordingDataMonitor::drawContents(TQPainter *painter)
{
if (painter)
internalDrawContents(*painter, true);
}
void RecordingDataMonitor::internalDrawContents(TQPainter &painter, bool repaintAll)
{
if (m_channels <= 0) return;
TQRect r = contentsRect();
TQPen activePen (colorGroup().color(TQColorGroup::Text), 1);
TQPen inactivePen (colorGroup().color(TQColorGroup::Mid), 1);
TQBrush activeBrush = colorGroup().brush(TQColorGroup::Text);
TQBrush inactiveBrush = colorGroup().brush(TQColorGroup::Mid);
TQBrush yellowBrush(TQColor(255,255,0));
TQBrush orangeBrush(TQColor(255,192,0));
TQBrush redBrush (TQColor(255,0, 0));
double ranges [5] = { 0.75, 0.83, 0.91, 1.0, 999 };
TQBrush *brushes[5] = { &activeBrush, &yellowBrush, &orangeBrush, &redBrush, &redBrush };
painter.setBrush( isEnabled() ? activeBrush : inactiveBrush);
int nBlocks = (r.width()-1) / BLOCK_W_MIN;
int xoffs = (r.width()-1) % BLOCK_W_MIN;
int chHeight = (r.height()-1-CHANNEL_H_MIN) / m_channels;
int yoffs = (r.height()-1) % m_channels;
double min_dB = 20*log10(1 / (double)m_maxValue );
int x0 = xoffs/2 + r.top();
int y = yoffs/2 + r.left();
for (int c = 0; c < m_channels; ++c) {
int x = x0;
int startBlock = 0;
int endBlock = nBlocks - 1;
int oldActiveBlocks = m_pActiveBlocks[c];
double dBMax = isEnabled() ? 20*log10(m_channelsMax[c] / (double)m_maxValue ) : min_dB;
m_pActiveBlocks[c] = m_channelsMax[c] ? (int)rint(nBlocks * (min_dB - dBMax) / min_dB) : 0;
if (!repaintAll) {
if (oldActiveBlocks > m_pActiveBlocks[c]) {
startBlock = m_pActiveBlocks[c];
endBlock = oldActiveBlocks - 1;
} else {
startBlock = oldActiveBlocks;
endBlock = m_pActiveBlocks[c]-1;
}
}
int range = 0;
x += BLOCK_W_MIN * startBlock;
for (int b = startBlock; b <= endBlock; ++b) {
while (b >= nBlocks * ranges[range]) ++range;
painter.fillRect(x+1, y+1, BLOCK_W_MIN-1, chHeight-1,
b < m_pActiveBlocks[c] ? *brushes[range] : inactiveBrush);
x += BLOCK_W_MIN;
}
y += chHeight;
}
if (repaintAll) {
TQFont f("Helvetica");
painter.setPen (activePen);
f.setPixelSize(CHANNEL_H_MIN);
painter.setFont(f);
int maxW = TQFontMetrics(f).width(i18n("%1 dB").arg((int)min_dB));
int delta_dB = 5;
while (abs((long)min_dB) / delta_dB * maxW * 2 > r.width()) delta_dB *= 2;
for (int dB = 0; dB >= min_dB; dB -= delta_dB) {
TQString txt = i18n("%1 dB").arg(dB);
int w = TQFontMetrics(f).width(txt);
int x = x0 + (int)(nBlocks * BLOCK_W_MIN * (min_dB - dB) / min_dB) - w;
if (x < x0) continue;
painter.drawText(x, y + CHANNEL_H_MIN, txt);
}
}
}
bool RecordingDataMonitor::setColors(const TQColor &activeText,
const TQColor &button)
{
m_colorActiveText = activeText;
m_colorButton = button;
TQPalette pl = palette();
TQColorGroup cg = pl.inactive();
TQBrush fg = cg.brush(TQColorGroup::Foreground),
btn = cg.brush(TQColorGroup::Button),
lgt = cg.brush(TQColorGroup::Light),
drk = cg.brush(TQColorGroup::Dark),
mid = cg.brush(TQColorGroup::Mid),
txt = cg.brush(TQColorGroup::Text),
btx = cg.brush(TQColorGroup::BrightText),
bas = cg.brush(TQColorGroup::Base),
bg = cg.brush(TQColorGroup::Background);
fg.setColor (m_colorActiveText);
btn.setColor(m_colorButton);
lgt.setColor(m_colorButton.light(180));
drk.setColor(m_colorButton.light( 50));
mid.setColor(m_colorButton.light( 75));
txt.setColor(m_colorActiveText);
btx.setColor(m_colorActiveText);
bas.setColor(m_colorButton);
bg.setColor (m_colorButton);
TQColorGroup ncg(fg, btn, lgt, drk, mid, txt, btx, bas, bg);
pl.setInactive(ncg);
pl.setActive(ncg);
setPalette(pl);
if (parentWidget() && parentWidget()->backgroundPixmap() ){
KPixmapIO io;
TQImage i = io.convertToImage(*parentWidget()->backgroundPixmap());
KImageEffect::fade(i, 0.5, colorGroup().color(TQColorGroup::Dark));
setPaletteBackgroundPixmap(io.convertToPixmap(i));
setBackgroundOrigin(WindowOrigin);
} else {
setBackgroundColor(colorGroup().color(TQColorGroup::Button));
}
return true;
}
bool RecordingDataMonitor::noticeSoundStreamData(SoundStreamID /*id*/,
const SoundFormat &sf, const char *data, size_t size, size_t &/*consumed_size*/,
const SoundMetaData &/*md*/
)
{
if (!isEnabled())
return false;
int nSamples = size / sf.frameSize();
int sample_size = sf.sampleSize();
int bias = 0;
setChannels(sf.m_Channels);
int old_max = m_maxValue;
m_maxValue = sf.maxValue();
if (!sf.m_IsSigned) {
m_maxValue /= 2;
bias = -m_maxValue;
}
int c = 0;
for (int s = 0; s < nSamples; ++s, ++c, data += sample_size) {
if (c >= m_channels) c -= m_channels; // avoid slow c = s % m_channels
int &m = m_channelsMax[c];
int x = abs(sf.convertSampleToInt(data, false) + bias);
if (m < x) m = x;
m_channelsAvg[c] += x;
}
for (int i = 0; i < m_channels; ++i)
m_channelsAvg[i] /= nSamples;
TQPainter paint(this);
if (m_maxValue != old_max) {
repaint(true);
} else {
internalDrawContents(paint, false);
}
return true;
}
#include "recording-datamonitor.moc"