Made the PeakView multi-channel capable.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38489 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2010-09-01 11:37:52 +00:00
parent b006bbe130
commit 389cd87bcb
2 changed files with 146 additions and 105 deletions
+133 -96
View File
@@ -1,10 +1,12 @@
/* /*
* Copyright (C) 2001-2010 Stephan Aßmus. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Copyright (C) 1998-1999 Be Incorporated. All rights reseved. * Copyright (C) 1998-1999 Be Incorporated. All rights reseved.
* Distributed under the terms of the Be Sample Code license. * Distributed under the terms of the Be Sample Code license.
*
* Copyright (C) 2001-2008 Stephan Aßmus. All rights reserved.
* Distributed under the terms of the MIT license.
*/ */
#include "PeakView.h" #include "PeakView.h"
#include <new> #include <new>
@@ -21,66 +23,60 @@
using std::nothrow; using std::nothrow;
enum { enum {
MSG_PULSE = 'puls', MSG_PULSE = 'puls',
MSG_LOCK_PEAKS = 'lpks' MSG_LOCK_PEAKS = 'lpks'
}; };
// constructor
PeakView::PeakView(const char* name, bool useGlobalPulse, bool displayLabels) PeakView::PeakView(const char* name, bool useGlobalPulse, bool displayLabels)
: BView(BRect(0.0, 0.0, 155.0 + 4.0, 10.0 + 4.0), :
BView(BRect(0.0, 0.0, 155.0 + 4.0, 10.0 + 4.0),
name, B_FOLLOW_LEFT | B_FOLLOW_TOP, name, B_FOLLOW_LEFT | B_FOLLOW_TOP,
useGlobalPulse ? B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS useGlobalPulse ? B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS
: B_WILL_DRAW | B_FRAME_EVENTS), : B_WILL_DRAW | B_FRAME_EVENTS),
fUseGlobalPulse(useGlobalPulse), fUseGlobalPulse(useGlobalPulse),
fDisplayLabels(displayLabels), fDisplayLabels(displayLabels),
fPeakLocked(false), fPeakLocked(false),
fRefreshDelay(20000), fRefreshDelay(20000),
fPulse(NULL), fPulse(NULL),
fCurrentMaxL(0.0), fChannelInfos(NULL),
fLastMaxL(0.0), fChannelCount(0),
fOvershotL(false),
fCurrentMaxR(0.0), fBackBitmap(NULL),
fLastMaxR(0.0), fPeakNotificationWhat(0)
fOvershotR(false),
fBackBitmap(new BBitmap(BRect(0.0, 0.0, 256.0, 18.0), B_CMAP8)),
fPeakNotificationWhat(0)
{ {
GetFontHeight(&fFontHeight); GetFontHeight(&fFontHeight);
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
SetViewColor(B_TRANSPARENT_COLOR); SetViewColor(B_TRANSPARENT_COLOR);
FrameResized(Bounds().Width(), Bounds().Height());
if (fDisplayLabels) if (fDisplayLabels)
ResizeBy(0, ceilf(fFontHeight.ascent + fFontHeight.descent)); ResizeBy(0, ceilf(fFontHeight.ascent + fFontHeight.descent));
SetChannelCount(2);
} }
// destructor
PeakView::~PeakView() PeakView::~PeakView()
{ {
delete fPulse; delete fPulse;
delete fBackBitmap; delete fBackBitmap;
delete[] fChannelInfos;
} }
// MessageReceived
void void
PeakView::MessageReceived(BMessage* message) PeakView::MessageReceived(BMessage* message)
{ {
if (message->what == fPeakNotificationWhat) { if (message->what == fPeakNotificationWhat) {
float maxL; float max;
if (message->FindFloat("max", 0, &maxL) < B_OK) for (int32 i = 0; message->FindFloat("max", i, &max) == B_OK; i++)
maxL = 0.0; SetMax(max, i);
float maxR; return;
if (message->FindFloat("max", 1, &maxR) < B_OK)
maxR = 0.0;
SetMax(maxL, maxR);
return;
} }
switch (message->what) { switch (message->what) {
@@ -98,7 +94,7 @@ PeakView::MessageReceived(BMessage* message)
} }
} }
// AttachedToWindow
void void
PeakView::AttachedToWindow() PeakView::AttachedToWindow()
{ {
@@ -106,11 +102,11 @@ PeakView::AttachedToWindow()
delete fPulse; delete fPulse;
BMessage message(MSG_PULSE); BMessage message(MSG_PULSE);
fPulse = new BMessageRunner(BMessenger(this), &message, fPulse = new BMessageRunner(BMessenger(this), &message,
fRefreshDelay); fRefreshDelay);
} }
} }
// DetachedFromWindow
void void
PeakView::DetachedFromWindow() PeakView::DetachedFromWindow()
{ {
@@ -118,7 +114,7 @@ PeakView::DetachedFromWindow()
fPulse = NULL; fPulse = NULL;
} }
// MouseDown
void void
PeakView::MouseDown(BPoint where) PeakView::MouseDown(BPoint where)
{ {
@@ -127,13 +123,17 @@ PeakView::MouseDown(BPoint where)
buttons = B_PRIMARY_MOUSE_BUTTON; buttons = B_PRIMARY_MOUSE_BUTTON;
if (buttons & B_PRIMARY_MOUSE_BUTTON) { if (buttons & B_PRIMARY_MOUSE_BUTTON) {
fOvershotL = false; // Reset the overshot flag and set the observed max to the current
fOvershotR = false; // value.
fLastMaxL = fCurrentMaxL; for (uint32 i = 0; i < fChannelCount; i++) {
fLastMaxR = fCurrentMaxR; fChannelInfos[i].overshot = false;
fChannelInfos[i].last_max = fChannelInfos[i].current_max;
}
} else if (buttons & B_TERTIARY_MOUSE_BUTTON) { } else if (buttons & B_TERTIARY_MOUSE_BUTTON) {
// Toggle locking of the observed max value.
fPeakLocked = !fPeakLocked; fPeakLocked = !fPeakLocked;
} else { } else {
// Display context menu
BPopUpMenu* menu = new BPopUpMenu("peak context menu"); BPopUpMenu* menu = new BPopUpMenu("peak context menu");
BMenuItem* item = new BMenuItem("Lock Peaks", BMenuItem* item = new BMenuItem("Lock Peaks",
new BMessage(MSG_LOCK_PEAKS)); new BMessage(MSG_LOCK_PEAKS));
@@ -158,7 +158,7 @@ PeakView::MouseDown(BPoint where)
} }
} }
// Draw
void void
PeakView::Draw(BRect area) PeakView::Draw(BRect area)
{ {
@@ -171,7 +171,7 @@ PeakView::Draw(BRect area)
float width = r.Width(); float width = r.Width();
r.InsetBy(-2.0, -2.0); r.InsetBy(-2.0, -2.0);
// frame // frame
BeginLineArray(9); BeginLineArray(8);
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), lightShadow); AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), lightShadow);
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top),
lightShadow); lightShadow);
@@ -188,8 +188,6 @@ PeakView::Draw(BRect area)
AddLine(BPoint(r.right - 1.0, r.bottom), AddLine(BPoint(r.right - 1.0, r.bottom),
BPoint(r.left + 1.0, r.bottom), lightShadow); BPoint(r.left + 1.0, r.bottom), lightShadow);
r.InsetBy(1.0, 1.0); r.InsetBy(1.0, 1.0);
AddLine(BPoint(r.left, (r.top + r.bottom) / 2.0),
BPoint(r.right, (r.top + r.bottom) / 2.0), black);
EndLineArray(); EndLineArray();
// peak bitmap // peak bitmap
@@ -208,39 +206,39 @@ PeakView::Draw(BRect area)
} }
} }
// FrameResized
void void
PeakView::FrameResized(float width, float height) PeakView::FrameResized(float width, float height)
{ {
BRect bitmapFrame = _BackBitmapFrame(); BRect bitmapFrame = _BackBitmapFrame();
_ResizeBackBitmap(bitmapFrame.IntegerWidth() + 1); _ResizeBackBitmap(bitmapFrame.IntegerWidth() + 1, fChannelCount);
_UpdateBackBitmap(); _UpdateBackBitmap();
} }
// Pulse
void void
PeakView::Pulse() PeakView::Pulse()
{ {
if (!fBackBitmap) if (fBackBitmap == NULL)
return; return;
if (!fPeakLocked) { if (!fPeakLocked) {
fLastMaxL = 0.90 * fLastMaxL; for (uint32 i = 0; i < fChannelCount; i++) {
if (fCurrentMaxL > fLastMaxL) fChannelInfos[i].last_max *= 0.90f;
fLastMaxL = fCurrentMaxL; if (fChannelInfos[i].current_max > fChannelInfos[i].last_max)
fLastMaxR = 0.90 * fLastMaxR; fChannelInfos[i].last_max = fChannelInfos[i].current_max;
if (fCurrentMaxR > fLastMaxR) }
fLastMaxR = fCurrentMaxR;
} }
_UpdateBackBitmap(); _UpdateBackBitmap();
fCurrentMaxL = 0.0;
fCurrentMaxR = 0.0; for (uint32 i = 0; i < fChannelCount; i++)
fChannelInfos[i].current_max = 0.0f;
_DrawBitmap(); _DrawBitmap();
Flush(); Flush();
} }
// GetPreferredSize
void void
PeakView::GetPreferredSize(float* _width, float* _height) PeakView::GetPreferredSize(float* _width, float* _height)
{ {
@@ -262,49 +260,74 @@ PeakView::GetPreferredSize(float* _width, float* _height)
*_height = minHeight; *_height = minHeight;
} }
// IsValid
bool bool
PeakView::IsValid() const PeakView::IsValid() const
{ {
return fBackBitmap && fBackBitmap->IsValid(); return fBackBitmap != NULL && fBackBitmap->IsValid()
&& fChannelInfos != NULL;
} }
// SetPeakRefreshDelay
void void
PeakView::SetPeakRefreshDelay(bigtime_t delay) PeakView::SetPeakRefreshDelay(bigtime_t delay)
{ {
if (fRefreshDelay == delay) if (fRefreshDelay == delay)
return; return;
fRefreshDelay = delay; fRefreshDelay = delay;
if (fPulse)
if (fPulse != NULL)
fPulse->SetInterval(fRefreshDelay); fPulse->SetInterval(fRefreshDelay);
} }
// SetPeakNotificationWhat
void void
PeakView::SetPeakNotificationWhat(uint32 what) PeakView::SetPeakNotificationWhat(uint32 what)
{ {
fPeakNotificationWhat = what; fPeakNotificationWhat = what;
} }
// SetMax
void
PeakView::SetMax(float maxL, float maxR)
{
if (fCurrentMaxL < maxL)
fCurrentMaxL = maxL;
if (fCurrentMaxR < maxR)
fCurrentMaxR = maxR;
if (fCurrentMaxL > 1.0) void
fOvershotL = true; PeakView::SetChannelCount(uint32 channelCount)
if (fCurrentMaxR > 1.0) {
fOvershotR = true; if (channelCount == fChannelCount)
return;
delete[] fChannelInfos;
fChannelInfos = new(std::nothrow) ChannelInfo[channelCount];
if (fChannelInfos != NULL) {
fChannelCount = channelCount;
for (uint32 i = 0; i < fChannelCount; i++) {
fChannelInfos[i].current_max = 0.0f;
fChannelInfos[i].last_max = 0.0f;
fChannelInfos[i].overshot = false;
}
_ResizeBackBitmap(_BackBitmapFrame().IntegerWidth() + 1,
fChannelCount);
} else
fChannelCount = 0;
} }
void
PeakView::SetMax(float max, uint32 channel)
{
if (channel >= fChannelCount)
return;
if (fChannelInfos[channel].current_max < max)
fChannelInfos[channel].current_max = max;
if (fChannelInfos[channel].current_max > 1.0)
fChannelInfos[channel].overshot = true;
}
// #pragma mark - // #pragma mark -
// _BackBitmapFrame
BRect BRect
PeakView::_BackBitmapFrame() const PeakView::_BackBitmapFrame() const
{ {
@@ -315,17 +338,23 @@ PeakView::_BackBitmapFrame() const
return frame; return frame;
} }
// _ResizeBackBitmap
void void
PeakView::_ResizeBackBitmap(int32 width) PeakView::_ResizeBackBitmap(int32 width, int32 channels)
{ {
if (fBackBitmap) { if (fBackBitmap != NULL) {
if (fBackBitmap->Bounds().IntegerWidth() + 1 == width) if (fBackBitmap->Bounds().IntegerWidth() + 1 == width
&& fBackBitmap->Bounds().IntegerHeight() + 1 == channels) {
return; return;
}
} }
if (channels <= 0)
channels = 2;
delete fBackBitmap; delete fBackBitmap;
fBackBitmap = new (nothrow) BBitmap(BRect(0, 0, width - 1, 1), 0, B_RGB32); BRect bounds(0, 0, width - 1, channels - 1);
if (!fBackBitmap || !fBackBitmap->IsValid()) { fBackBitmap = new(std::nothrow) BBitmap(bounds, 0, B_RGB32);
if (fBackBitmap == NULL || !fBackBitmap->IsValid()) {
delete fBackBitmap; delete fBackBitmap;
fBackBitmap = NULL; fBackBitmap = NULL;
return; return;
@@ -333,21 +362,23 @@ PeakView::_ResizeBackBitmap(int32 width)
memset(fBackBitmap->Bits(), 0, fBackBitmap->BitsLength()); memset(fBackBitmap->Bits(), 0, fBackBitmap->BitsLength());
} }
// _UpdateBackBitmap
void void
PeakView::_UpdateBackBitmap() PeakView::_UpdateBackBitmap()
{ {
if (!fBackBitmap) if (!fBackBitmap)
return; return;
uint8* l = (uint8*)fBackBitmap->Bits(); uint8* span = (uint8*)fBackBitmap->Bits();
uint8* r = l + fBackBitmap->BytesPerRow();
uint32 width = fBackBitmap->Bounds().IntegerWidth() + 1; uint32 width = fBackBitmap->Bounds().IntegerWidth() + 1;
_RenderSpan(l, width, fCurrentMaxL, fLastMaxL, fOvershotL); for (uint32 i = 0; i < fChannelCount; i++) {
_RenderSpan(r, width, fCurrentMaxR, fLastMaxR ,fOvershotR); _RenderSpan(span, width, fChannelInfos[i].current_max,
fChannelInfos[i].last_max, fChannelInfos[i].overshot);
span += fBackBitmap->BytesPerRow();
}
} }
// _RenderSpan
void void
PeakView:: _RenderSpan(uint8* span, uint32 width, float current, float peak, PeakView:: _RenderSpan(uint8* span, uint32 width, float current, float peak,
bool overshot) bool overshot)
@@ -412,20 +443,26 @@ PeakView:: _RenderSpan(uint8* span, uint32 width, float current, float peak,
} }
} }
// _DrawBitmap
void void
PeakView::_DrawBitmap() PeakView::_DrawBitmap()
{ {
BRect r = _BackBitmapFrame(); SetHighColor(0, 0, 0);
BRect topHalf = r; BRect bitmapFrame = _BackBitmapFrame();
topHalf.bottom = (r.top + r.bottom) / 2.0 - 1;
BRect bottomHalf = r;
bottomHalf.top = topHalf.bottom + 2;
BRect bitmapRect = fBackBitmap->Bounds(); BRect bitmapRect = fBackBitmap->Bounds();
bitmapRect.bottom = bitmapRect.top; bitmapRect.bottom = bitmapRect.top;
DrawBitmapAsync(fBackBitmap, bitmapRect, topHalf); float channelHeight = (bitmapFrame.Height() + 2) / fChannelCount;
bitmapRect.OffsetBy(0, 1); for (uint32 i = 0; i < fChannelCount; i++) {
DrawBitmapAsync(fBackBitmap, bitmapRect, bottomHalf); BRect viewRect(bitmapFrame);
viewRect.top += floorf(i * channelHeight);
viewRect.bottom = viewRect.top + ceilf(channelHeight - 2);
DrawBitmapAsync(fBackBitmap, bitmapRect, viewRect);
if (i < fChannelCount - 1) {
StrokeLine(BPoint(viewRect.left, viewRect.bottom + 1),
BPoint(viewRect.right, viewRect.bottom + 1));
}
bitmapRect.OffsetBy(0, 1);
}
} }
+13 -9
View File
@@ -58,16 +58,19 @@ public:
bool IsValid() const; bool IsValid() const;
void SetPeakRefreshDelay(bigtime_t delay); void SetPeakRefreshDelay(bigtime_t delay);
void SetPeakNotificationWhat(uint32 what); void SetPeakNotificationWhat(uint32 what);
void SetMax(float maxL, float maxR);
private: void SetChannelCount(uint32 count);
void SetMax(float max, uint32 channel);
private:
BRect _BackBitmapFrame() const; BRect _BackBitmapFrame() const;
void _ResizeBackBitmap(int32 width); void _ResizeBackBitmap(int32 width, int32 channels);
void _UpdateBackBitmap(); void _UpdateBackBitmap();
void _RenderSpan(uint8* span, uint32 width, void _RenderSpan(uint8* span, uint32 width,
float current, float peak, bool overshot); float current, float peak, bool overshot);
void _DrawBitmap(); void _DrawBitmap();
private:
bool fUseGlobalPulse; bool fUseGlobalPulse;
bool fDisplayLabels; bool fDisplayLabels;
bool fPeakLocked; bool fPeakLocked;
@@ -75,13 +78,14 @@ public:
bigtime_t fRefreshDelay; bigtime_t fRefreshDelay;
BMessageRunner* fPulse; BMessageRunner* fPulse;
float fCurrentMaxL; struct ChannelInfo {
float fLastMaxL; float current_max;
bool fOvershotL; float last_max;
bool overshot;
};
float fCurrentMaxR; ChannelInfo* fChannelInfos;
float fLastMaxR; uint32 fChannelCount;
bool fOvershotR;
BBitmap* fBackBitmap; BBitmap* fBackBitmap;
font_height fFontHeight; font_height fFontHeight;