* The SeekSlider did not update the knob when it was resized.
* Subtile visual improvements to the SeekSlider. * Added a PeakView for displaying the audio peaks that are produced by the AudioProducer. * A MessageEvent can now directly take a custom BMessage for delivery. * The peak notification mechanism is a bit separate from the rest of the Controller notification design, since the notification delivery should be delayed until the audio is actually audible. I may change this quick and dirty design though, since it is not so nice. The target time could also be part of the message and be handled at a different stage, but that would make it less efficient. * Layout improvements to the playback controls. * Code cleanup here and there, changed some license statements. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26280 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
e146a7bf2f
commit
9282400ff4
@ -32,7 +32,7 @@
|
||||
|
||||
ControllerView::ControllerView(BRect frame, Controller* controller,
|
||||
Playlist* playlist)
|
||||
: TransportControlGroup(frame)
|
||||
: TransportControlGroup(frame, true, true, false)
|
||||
, fController(controller)
|
||||
, fPlaylist(playlist)
|
||||
, fPlaylistObserver(new PlaylistObserver(this))
|
||||
|
@ -26,6 +26,7 @@ for sourceDir in $(sourceDirs) {
|
||||
Application MediaPlayer :
|
||||
# interface
|
||||
DrawingTidbits.cpp
|
||||
PeakView.cpp
|
||||
SeekSlider.cpp
|
||||
TransportButton.cpp
|
||||
VolumeSlider.cpp
|
||||
|
@ -41,8 +41,10 @@
|
||||
#include <String.h>
|
||||
#include <View.h>
|
||||
|
||||
#include "AudioProducer.h"
|
||||
#include "ControllerObserver.h"
|
||||
#include "MainApp.h"
|
||||
#include "PeakView.h"
|
||||
#include "PlaylistObserver.h"
|
||||
#include "PlaylistWindow.h"
|
||||
#include "SettingsWindow.h"
|
||||
@ -170,6 +172,9 @@ MainWin::MainWin()
|
||||
fPlaylist->AddListener(fPlaylistObserver);
|
||||
fController->SetVideoView(fVideoView);
|
||||
fController->AddListener(fControllerObserver);
|
||||
PeakView* peakView = fControls->GetPeakView();
|
||||
peakView->SetPeakNotificationWhat(MSG_PEAK_NOTIFICATION);
|
||||
fController->SetPeakListener(peakView);
|
||||
|
||||
// printf("fMenuBarHeight %d\n", fMenuBarHeight);
|
||||
// printf("fControlsHeight %d\n", fControlsHeight);
|
||||
@ -201,6 +206,7 @@ MainWin::~MainWin()
|
||||
|
||||
fPlaylist->RemoveListener(fPlaylistObserver);
|
||||
fController->RemoveListener(fControllerObserver);
|
||||
fController->SetPeakListener(NULL);
|
||||
|
||||
// give the views a chance to detach from any notifiers
|
||||
// before we delete them
|
||||
|
@ -1,13 +1,10 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
* Copyright © 2006-2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
||||
// that I did during the VLC 0.4.3 - 0.4.6 times. Code not done by me
|
||||
// that I did during the VLC 0.4.3 - 0.4.6 times. Code not written by me
|
||||
// removed. -Stephan Aßmus
|
||||
|
||||
#include "TransportControlGroup.h"
|
||||
@ -18,6 +15,7 @@
|
||||
#include <String.h>
|
||||
|
||||
#include "ButtonBitmaps.h"
|
||||
#include "PeakView.h"
|
||||
#include "PlaybackState.h"
|
||||
#include "SeekSlider.h"
|
||||
#include "TransportButton.h"
|
||||
@ -53,63 +51,55 @@ enum {
|
||||
|
||||
// constructor
|
||||
TransportControlGroup::TransportControlGroup(BRect frame, bool useSkipButtons,
|
||||
bool useWindButtons)
|
||||
bool usePeakView, bool useWindButtons)
|
||||
: BView(frame, "transport control group",
|
||||
B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
|
||||
B_WILL_DRAW | B_FRAME_EVENTS)
|
||||
, fBottomControlHeight(0.0)
|
||||
, fPeakViewMinWidth(0.0)
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
frame.Set(0.0, 0.0, 10.0, 10.0);
|
||||
|
||||
// Seek Slider
|
||||
fSeekSlider = new SeekSlider(frame, "seek slider",
|
||||
new BMessage(MSG_SEEK),
|
||||
0, kPositionFactor);
|
||||
fSeekSlider = new SeekSlider(frame, "seek slider", new BMessage(MSG_SEEK),
|
||||
0, kPositionFactor);
|
||||
fSeekSlider->ResizeToPreferred();
|
||||
AddChild(fSeekSlider);
|
||||
|
||||
// Buttons
|
||||
if (useSkipButtons) {
|
||||
// Skip Back
|
||||
frame.right = kRewindBitmapWidth - 1;
|
||||
frame.bottom = kRewindBitmapHeight - 1;
|
||||
if (useSkipButtons) {
|
||||
// Skip Back
|
||||
frame.right = kRewindBitmapWidth - 1;
|
||||
frame.bottom = kRewindBitmapHeight - 1;
|
||||
fBottomControlHeight = kRewindBitmapHeight - 1.0;
|
||||
fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSkipBackBitmapBits,
|
||||
kPressedSkipBackBitmapBits,
|
||||
kDisabledSkipBackBitmapBits,
|
||||
new BMessage(MSG_SKIP_BACKWARDS));
|
||||
AddChild(fSkipBack);
|
||||
|
||||
// Skip Foward
|
||||
fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSkipForwardBitmapBits,
|
||||
kPressedSkipForwardBitmapBits,
|
||||
kDisabledSkipForwardBitmapBits,
|
||||
new BMessage(MSG_SKIP_FORWARD));
|
||||
AddChild(fSkipForward);
|
||||
} else {
|
||||
fSkipBack = NULL;
|
||||
fSkipForward = NULL;
|
||||
fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSkipBackBitmapBits, kPressedSkipBackBitmapBits,
|
||||
kDisabledSkipBackBitmapBits, new BMessage(MSG_SKIP_BACKWARDS));
|
||||
AddChild(fSkipBack);
|
||||
|
||||
// Skip Foward
|
||||
fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSkipForwardBitmapBits, kPressedSkipForwardBitmapBits,
|
||||
kDisabledSkipForwardBitmapBits, new BMessage(MSG_SKIP_FORWARD));
|
||||
AddChild(fSkipForward);
|
||||
} else {
|
||||
fSkipBack = NULL;
|
||||
fSkipForward = NULL;
|
||||
}
|
||||
|
||||
if (useWindButtons) {
|
||||
// Forward
|
||||
fForward = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kForwardBitmapBits,
|
||||
kPressedForwardBitmapBits,
|
||||
kDisabledForwardBitmapBits,
|
||||
new BMessage(MSG_FORWARD));
|
||||
kForwardBitmapBits, kPressedForwardBitmapBits,
|
||||
kDisabledForwardBitmapBits, new BMessage(MSG_FORWARD));
|
||||
AddChild(fForward);
|
||||
|
||||
|
||||
// Rewind
|
||||
fRewind = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kRewindBitmapBits,
|
||||
kPressedRewindBitmapBits,
|
||||
kDisabledRewindBitmapBits,
|
||||
new BMessage(MSG_REWIND));
|
||||
kRewindBitmapBits, kPressedRewindBitmapBits,
|
||||
kDisabledRewindBitmapBits, new BMessage(MSG_REWIND));
|
||||
AddChild(fRewind);
|
||||
} else {
|
||||
fForward = NULL;
|
||||
@ -117,56 +107,56 @@ TransportControlGroup::TransportControlGroup(BRect frame, bool useSkipButtons,
|
||||
}
|
||||
|
||||
// Play Pause
|
||||
frame.right = kPlayPauseBitmapWidth - 1;
|
||||
frame.bottom = kPlayPauseBitmapHeight - 1;
|
||||
frame.right = kPlayPauseBitmapWidth - 1;
|
||||
frame.bottom = kPlayPauseBitmapHeight - 1;
|
||||
if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
|
||||
fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
|
||||
fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
|
||||
kPlayButtonBitmapBits,
|
||||
kPressedPlayButtonBitmapBits,
|
||||
kDisabledPlayButtonBitmapBits,
|
||||
kPlayingPlayButtonBitmapBits,
|
||||
kPressedPlayingPlayButtonBitmapBits,
|
||||
kPausedPlayButtonBitmapBits,
|
||||
kPressedPausedPlayButtonBitmapBits,
|
||||
new BMessage(MSG_PLAY));
|
||||
fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
|
||||
kPlayButtonBitmapBits, kPressedPlayButtonBitmapBits,
|
||||
kDisabledPlayButtonBitmapBits, kPlayingPlayButtonBitmapBits,
|
||||
kPressedPlayingPlayButtonBitmapBits, kPausedPlayButtonBitmapBits,
|
||||
kPressedPausedPlayButtonBitmapBits, new BMessage(MSG_PLAY));
|
||||
|
||||
AddChild(fPlayPause);
|
||||
AddChild(fPlayPause);
|
||||
|
||||
// Stop
|
||||
frame.right = kStopBitmapWidth - 1;
|
||||
frame.bottom = kStopBitmapHeight - 1;
|
||||
// Stop
|
||||
frame.right = kStopBitmapWidth - 1;
|
||||
frame.bottom = kStopBitmapHeight - 1;
|
||||
if (fBottomControlHeight < kStopBitmapHeight - 1.0)
|
||||
fBottomControlHeight = kStopBitmapHeight - 1.0;
|
||||
fStop = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kStopButtonBitmapBits,
|
||||
kPressedStopButtonBitmapBits,
|
||||
kDisabledStopButtonBitmapBits,
|
||||
new BMessage(MSG_STOP));
|
||||
fStop = new TransportButton(frame, B_EMPTY_STRING, kStopButtonBitmapBits,
|
||||
kPressedStopButtonBitmapBits, kDisabledStopButtonBitmapBits,
|
||||
new BMessage(MSG_STOP));
|
||||
AddChild(fStop);
|
||||
|
||||
// Mute
|
||||
frame.right = kSpeakerIconBitmapWidth - 1;
|
||||
frame.bottom = kSpeakerIconBitmapHeight - 1;
|
||||
frame.right = kSpeakerIconBitmapWidth - 1;
|
||||
frame.bottom = kSpeakerIconBitmapHeight - 1;
|
||||
if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
|
||||
fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
|
||||
fMute = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSpeakerIconBits,
|
||||
kPressedSpeakerIconBits,
|
||||
kSpeakerIconBits,
|
||||
new BMessage(MSG_SET_MUTE));
|
||||
fMute = new TransportButton(frame, B_EMPTY_STRING, kSpeakerIconBits,
|
||||
kPressedSpeakerIconBits, kSpeakerIconBits, new BMessage(MSG_SET_MUTE));
|
||||
|
||||
AddChild(fMute);
|
||||
|
||||
// Volume Slider
|
||||
// Volume Slider
|
||||
fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
|
||||
kVolumeSliderBitmapHeight - 1.0),
|
||||
"volume slider",
|
||||
_DbToGain(_ExponentialToLinear(kVolumeDbMin)) * kVolumeFactor,
|
||||
_DbToGain(_ExponentialToLinear(kVolumeDbMax)) * kVolumeFactor,
|
||||
new BMessage(MSG_SET_VOLUME));
|
||||
fVolumeSlider->SetValue(_DbToGain(_ExponentialToLinear(0.0)) * kVolumeFactor);
|
||||
kVolumeSliderBitmapHeight - 1.0), "volume slider",
|
||||
_DbToGain(_ExponentialToLinear(kVolumeDbMin)) * kVolumeFactor,
|
||||
_DbToGain(_ExponentialToLinear(kVolumeDbMax)) * kVolumeFactor,
|
||||
new BMessage(MSG_SET_VOLUME));
|
||||
fVolumeSlider->SetValue(_DbToGain(_ExponentialToLinear(0.0))
|
||||
* kVolumeFactor);
|
||||
AddChild(fVolumeSlider);
|
||||
|
||||
// Peak view
|
||||
if (usePeakView) {
|
||||
fPeakView = new PeakView("peak view", false, false);
|
||||
AddChild(fPeakView);
|
||||
fPeakView->GetPreferredSize(&fPeakViewMinWidth, NULL);
|
||||
} else {
|
||||
fPeakView = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
@ -469,6 +459,8 @@ TransportControlGroup::_LayoutControls(BRect frame) const
|
||||
minWidth += fSkipForward->Bounds().Width();
|
||||
minWidth += fMute->Bounds().Width();
|
||||
minWidth += VOLUME_MIN_WIDTH;
|
||||
if (fPeakView)
|
||||
minWidth += fPeakViewMinWidth;
|
||||
|
||||
// layout seek slider
|
||||
r.bottom = r.top + fSeekSlider->Bounds().Height();
|
||||
@ -481,7 +473,8 @@ TransportControlGroup::_LayoutControls(BRect frame) const
|
||||
float currentWidth = frame.Width();
|
||||
float space = (currentWidth - minWidth) / 6.0;
|
||||
// apply weighting
|
||||
space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
|
||||
space = min_c(MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT,
|
||||
MIN_SPACE * 2.0);
|
||||
// layout controls with "space" inbetween
|
||||
r.left = frame.left;
|
||||
r.top = r.bottom + MIN_SPACE + 1.0;
|
||||
@ -522,11 +515,24 @@ TransportControlGroup::_LayoutControls(BRect frame) const
|
||||
r.left = r.right + space + space;
|
||||
r.right = r.left + fMute->Bounds().Width();
|
||||
_LayoutControl(fMute, r);
|
||||
|
||||
// volume slider
|
||||
r.left = r.right + SPEAKER_SLIDER_DIST;
|
||||
// keep speaker icon and volume slider attached
|
||||
r.right = frame.right;
|
||||
// layout volume slider
|
||||
float peakViewWidth = 0.0;
|
||||
if (fPeakView)
|
||||
peakViewWidth = (frame.right - r.left) / 2 + space;
|
||||
|
||||
r.right = frame.right - peakViewWidth;
|
||||
_LayoutControl(fVolumeSlider, r, true);
|
||||
|
||||
if (fPeakView) {
|
||||
peakViewWidth -= space;
|
||||
r.left = r.right + space;
|
||||
r.right = r.left + peakViewWidth;
|
||||
_LayoutControl(fPeakView, r, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
// _MinFrame
|
||||
@ -547,6 +553,8 @@ TransportControlGroup::_MinFrame() const
|
||||
minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
|
||||
minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
|
||||
minWidth += VOLUME_MIN_WIDTH;
|
||||
if (fPeakView)
|
||||
minWidth += fPeakViewMinWidth;
|
||||
|
||||
// add up height of seek slider and heighest control on bottom
|
||||
float minHeight = 2 * BORDER_INSET;
|
||||
|
@ -1,9 +1,6 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
* Copyright © 2006-2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
||||
@ -15,6 +12,7 @@
|
||||
|
||||
#include <View.h>
|
||||
|
||||
class PeakView;
|
||||
class PlayPauseButton;
|
||||
class TransportButton;
|
||||
class SeekSlider;
|
||||
@ -33,8 +31,9 @@ enum {
|
||||
class TransportControlGroup : public BView {
|
||||
public:
|
||||
TransportControlGroup(BRect frame,
|
||||
bool useSkipButtons = true,
|
||||
bool useWindButtons = false);
|
||||
bool useSkipButtons,
|
||||
bool usePeakView,
|
||||
bool useWindButtons);
|
||||
virtual ~TransportControlGroup();
|
||||
|
||||
// BView interface
|
||||
@ -67,6 +66,9 @@ class TransportControlGroup : public BView {
|
||||
void SetVolume(float value);
|
||||
void SetPosition(float value);
|
||||
|
||||
PeakView* GetPeakView() const
|
||||
{ return fPeakView; }
|
||||
|
||||
private:
|
||||
void _LayoutControls(BRect frame) const;
|
||||
BRect _MinFrame() const;
|
||||
@ -91,7 +93,7 @@ class TransportControlGroup : public BView {
|
||||
float _GainToDb(float gain);
|
||||
|
||||
SeekSlider* fSeekSlider;
|
||||
|
||||
PeakView* fPeakView;
|
||||
VolumeSlider* fVolumeSlider;
|
||||
|
||||
TransportButton* fSkipBack;
|
||||
@ -103,6 +105,7 @@ class TransportControlGroup : public BView {
|
||||
TransportButton* fMute;
|
||||
|
||||
float fBottomControlHeight;
|
||||
float fPeakViewMinWidth;
|
||||
};
|
||||
|
||||
#endif // TRANSPORT_CONTROL_GROUP_H
|
||||
|
429
src/apps/mediaplayer/interface/PeakView.cpp
Normal file
429
src/apps/mediaplayer/interface/PeakView.cpp
Normal file
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright (C) 1998-1999 Be Incorporated. All rights reseved.
|
||||
* 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 <new>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <MenuItem.h>
|
||||
#include <Message.h>
|
||||
#include <MessageRunner.h>
|
||||
#include <Messenger.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <Window.h>
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
enum {
|
||||
MSG_PULSE = 'puls',
|
||||
MSG_LOCK_PEAKS = 'lpks'
|
||||
};
|
||||
|
||||
// constructor
|
||||
PeakView::PeakView(const char* name, bool useGlobalPulse, bool displayLabels)
|
||||
: BView(BRect(0.0, 0.0, 155.0 + 4.0, 10.0 + 4.0),
|
||||
name, B_FOLLOW_LEFT | B_FOLLOW_TOP,
|
||||
useGlobalPulse ? B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS
|
||||
: B_WILL_DRAW | B_FRAME_EVENTS),
|
||||
fUseGlobalPulse(useGlobalPulse),
|
||||
fDisplayLabels(displayLabels),
|
||||
fPeakLocked(false),
|
||||
|
||||
fRefreshDelay(20000),
|
||||
fPulse(NULL),
|
||||
|
||||
fCurrentMaxL(0.0),
|
||||
fLastMaxL(0.0),
|
||||
fOvershotL(false),
|
||||
|
||||
fCurrentMaxR(0.0),
|
||||
fLastMaxR(0.0),
|
||||
fOvershotR(false),
|
||||
|
||||
fBackBitmap(new BBitmap(BRect(0.0, 0.0, 256.0, 18.0), B_CMAP8)),
|
||||
fPeakNotificationWhat(0)
|
||||
{
|
||||
GetFontHeight(&fFontHeight);
|
||||
|
||||
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
SetViewColor(B_TRANSPARENT_COLOR);
|
||||
|
||||
FrameResized(Bounds().Width(), Bounds().Height());
|
||||
|
||||
if (fDisplayLabels)
|
||||
ResizeBy(0, ceilf(fFontHeight.ascent + fFontHeight.descent));
|
||||
}
|
||||
|
||||
// destructor
|
||||
PeakView::~PeakView()
|
||||
{
|
||||
delete fPulse;
|
||||
delete fBackBitmap;
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
PeakView::MessageReceived(BMessage* message)
|
||||
{
|
||||
if (message->what == fPeakNotificationWhat) {
|
||||
float maxL;
|
||||
if (message->FindFloat("max", 0, &maxL) < B_OK)
|
||||
maxL = 0.0;
|
||||
float maxR;
|
||||
if (message->FindFloat("max", 1, &maxR) < B_OK)
|
||||
maxR = 0.0;
|
||||
SetMax(maxL, maxR);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message->what) {
|
||||
case MSG_PULSE:
|
||||
Pulse();
|
||||
break;
|
||||
|
||||
case MSG_LOCK_PEAKS:
|
||||
fPeakLocked = !fPeakLocked;
|
||||
break;
|
||||
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
PeakView::AttachedToWindow()
|
||||
{
|
||||
if (!fUseGlobalPulse) {
|
||||
delete fPulse;
|
||||
BMessage message(MSG_PULSE);
|
||||
fPulse = new BMessageRunner(BMessenger(this), &message,
|
||||
fRefreshDelay);
|
||||
}
|
||||
}
|
||||
|
||||
// DetachedFromWindow
|
||||
void
|
||||
PeakView::DetachedFromWindow()
|
||||
{
|
||||
delete fPulse;
|
||||
fPulse = NULL;
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
PeakView::MouseDown(BPoint where)
|
||||
{
|
||||
int32 buttons;
|
||||
if (Window()->CurrentMessage()->FindInt32("buttons", &buttons) < B_OK)
|
||||
buttons = B_PRIMARY_MOUSE_BUTTON;
|
||||
|
||||
if (buttons & B_PRIMARY_MOUSE_BUTTON) {
|
||||
fOvershotL = false;
|
||||
fOvershotR = false;
|
||||
fLastMaxL = fCurrentMaxL;
|
||||
fLastMaxR = fCurrentMaxR;
|
||||
} else if (buttons & B_TERTIARY_MOUSE_BUTTON) {
|
||||
fPeakLocked = !fPeakLocked;
|
||||
} else {
|
||||
BPopUpMenu* menu = new BPopUpMenu("peak context menu");
|
||||
BMenuItem* item = new BMenuItem("Lock Peaks",
|
||||
new BMessage(MSG_LOCK_PEAKS));
|
||||
item->SetMarked(fPeakLocked);
|
||||
menu->AddItem(item);
|
||||
menu->SetTargetForItems(this);
|
||||
|
||||
menu->SetAsyncAutoDestruct(true);
|
||||
menu->SetFont(be_plain_font);
|
||||
|
||||
where = ConvertToScreen(where);
|
||||
bool keepOpen = false; // ?
|
||||
if (keepOpen) {
|
||||
BRect mouseRect(where, where);
|
||||
mouseRect.InsetBy(-3.0, -3.0);
|
||||
where += BPoint(3.0, 3.0);
|
||||
menu->Go(where, true, false, mouseRect, true);
|
||||
} else {
|
||||
where += BPoint(3.0, 3.0);
|
||||
menu->Go(where, true, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
PeakView::Draw(BRect area)
|
||||
{
|
||||
rgb_color background = LowColor();
|
||||
rgb_color lightShadow = tint_color(background, B_DARKEN_1_TINT);
|
||||
rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
|
||||
rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
|
||||
rgb_color black = tint_color(background, B_DARKEN_MAX_TINT);
|
||||
BRect r(_BackBitmapFrame());
|
||||
float width = r.Width();
|
||||
r.InsetBy(-2.0, -2.0);
|
||||
// frame
|
||||
BeginLineArray(9);
|
||||
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),
|
||||
lightShadow);
|
||||
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom),
|
||||
light);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), light);
|
||||
r.InsetBy(1.0, 1.0);
|
||||
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), darkShadow);
|
||||
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top),
|
||||
darkShadow);
|
||||
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom),
|
||||
lightShadow);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), lightShadow);
|
||||
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();
|
||||
|
||||
// peak bitmap
|
||||
if (fBackBitmap)
|
||||
_DrawBitmap();
|
||||
|
||||
// dB
|
||||
if (fDisplayLabels) {
|
||||
font_height fh;
|
||||
GetFontHeight(&fh);
|
||||
float y = Bounds().bottom;
|
||||
y -= fh.descent;
|
||||
DrawString("0", BPoint(4.0 + width - StringWidth("0"), y));
|
||||
DrawString("-6", BPoint(0.477 * width, y));
|
||||
DrawString("-12", BPoint(0.227 * width, y));
|
||||
}
|
||||
}
|
||||
|
||||
// FrameResized
|
||||
void
|
||||
PeakView::FrameResized(float width, float height)
|
||||
{
|
||||
BRect bitmapFrame = _BackBitmapFrame();
|
||||
_ResizeBackBitmap(bitmapFrame.IntegerWidth() + 1);
|
||||
_UpdateBackBitmap();
|
||||
}
|
||||
|
||||
// Pulse
|
||||
void
|
||||
PeakView::Pulse()
|
||||
{
|
||||
if (!fBackBitmap)
|
||||
return;
|
||||
|
||||
if (!fPeakLocked) {
|
||||
if (fCurrentMaxL > fLastMaxL)
|
||||
fLastMaxL = fCurrentMaxL;
|
||||
if (fCurrentMaxR > fLastMaxR)
|
||||
fLastMaxR = fCurrentMaxR;
|
||||
}
|
||||
_UpdateBackBitmap();
|
||||
fCurrentMaxL = 0.0;
|
||||
fCurrentMaxR = 0.0;
|
||||
|
||||
_DrawBitmap();
|
||||
Flush();
|
||||
}
|
||||
|
||||
// GetPreferredSize
|
||||
void
|
||||
PeakView::GetPreferredSize(float* _width, float* _height)
|
||||
{
|
||||
float minWidth = 0;
|
||||
float minHeight = 0;
|
||||
if (fBackBitmap) {
|
||||
minWidth = 20 + 4;
|
||||
minHeight = 3 + 4;
|
||||
}
|
||||
if (fDisplayLabels) {
|
||||
font_height fh;
|
||||
GetFontHeight(&fh);
|
||||
minWidth = max_c(60.0, minWidth);
|
||||
minHeight += ceilf(fh.ascent + fh.descent);
|
||||
}
|
||||
if (_width)
|
||||
*_width = minWidth;
|
||||
if (_height)
|
||||
*_height = minHeight;
|
||||
}
|
||||
|
||||
// IsValid
|
||||
bool
|
||||
PeakView::IsValid() const
|
||||
{
|
||||
return fBackBitmap && fBackBitmap->IsValid();
|
||||
}
|
||||
|
||||
// SetPeakRefreshDelay
|
||||
void
|
||||
PeakView::SetPeakRefreshDelay(bigtime_t delay)
|
||||
{
|
||||
if (fRefreshDelay == delay)
|
||||
return;
|
||||
fRefreshDelay = delay;
|
||||
if (fPulse)
|
||||
fPulse->SetInterval(fRefreshDelay);
|
||||
}
|
||||
|
||||
// SetPeakNotificationWhat
|
||||
void
|
||||
PeakView::SetPeakNotificationWhat(uint32 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)
|
||||
fOvershotL = true;
|
||||
if (fCurrentMaxR > 1.0)
|
||||
fOvershotR = true;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _BackBitmapFrame
|
||||
BRect
|
||||
PeakView::_BackBitmapFrame() const
|
||||
{
|
||||
BRect frame = Bounds();
|
||||
frame.InsetBy(2, 2);
|
||||
if (fDisplayLabels)
|
||||
frame.bottom -= ceilf(fFontHeight.ascent + fFontHeight.descent);
|
||||
return frame;
|
||||
}
|
||||
|
||||
// _ResizeBackBitmap
|
||||
void
|
||||
PeakView::_ResizeBackBitmap(int32 width)
|
||||
{
|
||||
if (fBackBitmap) {
|
||||
if (fBackBitmap->Bounds().IntegerWidth() + 1 == width)
|
||||
return;
|
||||
}
|
||||
delete fBackBitmap;
|
||||
fBackBitmap = new (nothrow) BBitmap(BRect(0, 0, width - 1, 1), 0, B_RGB32);
|
||||
if (!fBackBitmap || !fBackBitmap->IsValid()) {
|
||||
delete fBackBitmap;
|
||||
fBackBitmap = NULL;
|
||||
return;
|
||||
}
|
||||
memset(fBackBitmap->Bits(), 0, fBackBitmap->BitsLength());
|
||||
}
|
||||
|
||||
// _UpdateBackBitmap
|
||||
void
|
||||
PeakView::_UpdateBackBitmap()
|
||||
{
|
||||
if (!fBackBitmap)
|
||||
return;
|
||||
|
||||
uint8* l = (uint8*)fBackBitmap->Bits();
|
||||
uint8* r = l + fBackBitmap->BytesPerRow();
|
||||
uint32 width = fBackBitmap->Bounds().IntegerWidth() + 1;
|
||||
_RenderSpan(l, width, fCurrentMaxL, fLastMaxL, fOvershotL);
|
||||
_RenderSpan(r, width, fCurrentMaxR, fLastMaxR ,fOvershotR);
|
||||
}
|
||||
|
||||
// _RenderSpan
|
||||
void
|
||||
PeakView:: _RenderSpan(uint8* span, uint32 width, float current, float peak,
|
||||
bool overshot)
|
||||
{
|
||||
uint8 emptyR = 15;
|
||||
uint8 emptyG = 36;
|
||||
uint8 emptyB = 16;
|
||||
|
||||
uint8 fillR = 41;
|
||||
uint8 fillG = 120;
|
||||
uint8 fillB = 45;
|
||||
|
||||
uint8 currentR = 45;
|
||||
uint8 currentG = 255;
|
||||
uint8 currentB = 45;
|
||||
|
||||
uint8 lastR = 255;
|
||||
uint8 lastG = 229;
|
||||
uint8 lastB = 87;
|
||||
|
||||
uint8 overR = 255;
|
||||
uint8 overG = 89;
|
||||
uint8 overB = 7;
|
||||
|
||||
uint8 kFadeFactor = 180;
|
||||
|
||||
uint32 split = (uint32)(current * (width - 2) + 0.5);
|
||||
split += split & 1;
|
||||
uint32 last = (uint32)(peak * (width - 2) + 0.5);
|
||||
last += last & 1;
|
||||
uint32 over = overshot ? width - 1 : width;
|
||||
over += over & 1;
|
||||
|
||||
for (uint32 x = 0; x < width - 1; x += 2) {
|
||||
uint8 fadedB = (uint8)(((int)span[0] * kFadeFactor) >> 8);
|
||||
uint8 fadedG = (uint8)(((int)span[1] * kFadeFactor) >> 8);
|
||||
uint8 fadedR = (uint8)(((int)span[2] * kFadeFactor) >> 8);
|
||||
if (x < split) {
|
||||
span[0] = max_c(fillB, fadedB);
|
||||
span[1] = max_c(fillG, fadedG);
|
||||
span[2] = max_c(fillR, fadedR);
|
||||
} else if (x == split) {
|
||||
span[0] = currentB;
|
||||
span[1] = currentG;
|
||||
span[2] = currentR;
|
||||
} else if (x > split) {
|
||||
span[0] = max_c(emptyB, fadedB);
|
||||
span[1] = max_c(emptyG, fadedG);
|
||||
span[2] = max_c(emptyR, fadedR);
|
||||
}
|
||||
if (x == last) {
|
||||
span[0] = lastB;
|
||||
span[1] = lastG;
|
||||
span[2] = lastR;
|
||||
}
|
||||
if (x == over) {
|
||||
span[0] = overB;
|
||||
span[1] = overG;
|
||||
span[2] = overR;
|
||||
}
|
||||
span += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// _DrawBitmap
|
||||
void
|
||||
PeakView::_DrawBitmap()
|
||||
{
|
||||
BRect r = _BackBitmapFrame();
|
||||
BRect topHalf = r;
|
||||
topHalf.bottom = (r.top + r.bottom) / 2.0 - 1;
|
||||
BRect bottomHalf = r;
|
||||
bottomHalf.top = topHalf.bottom + 2;
|
||||
BRect bitmapRect = fBackBitmap->Bounds();
|
||||
bitmapRect.bottom = bitmapRect.top;
|
||||
DrawBitmapAsync(fBackBitmap, bitmapRect, topHalf);
|
||||
bitmapRect.OffsetBy(0, 1);
|
||||
DrawBitmapAsync(fBackBitmap, bitmapRect, bottomHalf);
|
||||
}
|
||||
|
||||
|
92
src/apps/mediaplayer/interface/PeakView.h
Normal file
92
src/apps/mediaplayer/interface/PeakView.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 1998-1999 Be Incorporated. All rights reseved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------
|
||||
PURPOSE:
|
||||
gui class for displaying stereo audio peak level info
|
||||
|
||||
FEATURES:
|
||||
- uses a bitmap, but not a view accepting one, to redraw
|
||||
without flickering.
|
||||
- can be configured to use it's own message runner instead
|
||||
of the windows current pulse (in case you have text views in
|
||||
the window as well, which use a slow pulse for cursor blinking)
|
||||
- if used with own message runner, refresh delay is configurable
|
||||
- can be used in a dynamic liblayout gui
|
||||
|
||||
USAGE:
|
||||
To display the peak level of your streaming audio, just
|
||||
calculate the local maximum of both channels within your
|
||||
audio buffer and call SetMax() once for every buffer. The
|
||||
PeakView will take care of the rest.
|
||||
min = 0.0
|
||||
max = 1.0
|
||||
----------------------------------------------------------*/
|
||||
#ifndef PEAK_VIEW_H
|
||||
#define PEAL_VIEW_H
|
||||
|
||||
|
||||
#include <View.h>
|
||||
|
||||
class BBitmap;
|
||||
class BMessageRunner;
|
||||
|
||||
class PeakView : public BView {
|
||||
public:
|
||||
PeakView(const char* name,
|
||||
bool useGlobalPulse = true,
|
||||
bool displayLabels = true);
|
||||
virtual ~PeakView();
|
||||
|
||||
// BView interface
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void AttachedToWindow();
|
||||
virtual void DetachedFromWindow();
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void Draw(BRect area);
|
||||
virtual void FrameResized(float width, float height);
|
||||
virtual void Pulse();
|
||||
virtual void GetPreferredSize(float* _width,
|
||||
float* _height);
|
||||
|
||||
// PeakView
|
||||
bool IsValid() const;
|
||||
void SetPeakRefreshDelay(bigtime_t delay);
|
||||
void SetPeakNotificationWhat(uint32 what);
|
||||
void SetMax(float maxL, float maxR);
|
||||
|
||||
private:
|
||||
BRect _BackBitmapFrame() const;
|
||||
void _ResizeBackBitmap(int32 width);
|
||||
void _UpdateBackBitmap();
|
||||
void _RenderSpan(uint8* span, uint32 width,
|
||||
float current, float peak, bool overshot);
|
||||
void _DrawBitmap();
|
||||
|
||||
bool fUseGlobalPulse;
|
||||
bool fDisplayLabels;
|
||||
bool fPeakLocked;
|
||||
|
||||
bigtime_t fRefreshDelay;
|
||||
BMessageRunner* fPulse;
|
||||
|
||||
float fCurrentMaxL;
|
||||
float fLastMaxL;
|
||||
bool fOvershotL;
|
||||
|
||||
float fCurrentMaxR;
|
||||
float fLastMaxR;
|
||||
bool fOvershotR;
|
||||
|
||||
BBitmap* fBackBitmap;
|
||||
font_height fFontHeight;
|
||||
|
||||
uint32 fPeakNotificationWhat;
|
||||
};
|
||||
|
||||
#endif // PEAK_VIEW_H
|
@ -1,13 +1,10 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
* Copyright © 2006-2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
||||
// that I did during the VLC 0.4.3 - 0.4.6 times. Code not done by me
|
||||
// that I did during the VLC 0.4.3 - 0.4.6 times. Code not written by me
|
||||
// removed. -Stephan Aßmus
|
||||
|
||||
#include "SeekSlider.h"
|
||||
@ -32,7 +29,7 @@ const char* kDisabledSeekMessage = "Drop files to play";
|
||||
SeekSlider::SeekSlider(BRect frame, const char* name, BMessage* message,
|
||||
int32 minValue, int32 maxValue)
|
||||
: BControl(frame, name, NULL, message, B_FOLLOW_LEFT | B_FOLLOW_TOP,
|
||||
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
|
||||
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS)
|
||||
, fTracking(false)
|
||||
, fLastTrackTime(0)
|
||||
, fKnobPos(_KnobPosFor(Bounds(), Value()))
|
||||
@ -101,9 +98,9 @@ SeekSlider::Draw(BRect updateRect)
|
||||
rgb_color dotGrey = midShadow;
|
||||
rgb_color dotGreen = greenShadow;
|
||||
// draw frame
|
||||
_StrokeFrame(r, softShadow, softShadow, softLight, softLight);
|
||||
_StrokeFrame(r, softShadow, softShadow, light, light);
|
||||
r.InsetBy(1.0, 1.0);
|
||||
_StrokeFrame(r, black, black, light, light);
|
||||
_StrokeFrame(r, black, black, softShadow, softShadow);
|
||||
if (IsEnabled()) {
|
||||
// *** enabled look ***
|
||||
r.InsetBy(1.0, 1.0);
|
||||
@ -280,6 +277,13 @@ SeekSlider::ResizeToPreferred()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SeekSlider::FrameResized(float width, float height)
|
||||
{
|
||||
_SetKnobPosition(_KnobPosFor(Bounds(), Value()));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SeekSlider::SetPosition(float position)
|
||||
{
|
||||
|
@ -1,9 +1,6 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
* Copyright © 2006-2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef SEEK_SLIDER_H
|
||||
@ -15,10 +12,8 @@
|
||||
class SeekSlider : public BControl {
|
||||
public:
|
||||
SeekSlider(BRect frame,
|
||||
const char* name,
|
||||
BMessage* message,
|
||||
int32 minValue,
|
||||
int32 maxValue);
|
||||
const char* name, BMessage* message,
|
||||
int32 minValue, int32 maxValue);
|
||||
|
||||
virtual ~SeekSlider();
|
||||
|
||||
@ -28,9 +23,10 @@ class SeekSlider : public BControl {
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* dragMessage);
|
||||
const BMessage* dragMessage);
|
||||
virtual void MouseUp(BPoint where);
|
||||
virtual void ResizeToPreferred();
|
||||
virtual void FrameResized(float width, float height);
|
||||
|
||||
// SeekSlider
|
||||
void SetPosition(float position);
|
||||
@ -41,10 +37,8 @@ private:
|
||||
int32 _KnobPosFor(BRect bounds,
|
||||
int32 value) const;
|
||||
void _StrokeFrame(BRect frame,
|
||||
rgb_color left,
|
||||
rgb_color top,
|
||||
rgb_color right,
|
||||
rgb_color bottom);
|
||||
rgb_color left, rgb_color top,
|
||||
rgb_color right, rgb_color bottom);
|
||||
void _SetKnobPosition(int32 knobPos);
|
||||
|
||||
|
||||
|
@ -51,7 +51,8 @@ NodeManager::NodeManager()
|
||||
fVideoTarget(NULL),
|
||||
fAudioSupplier(NULL),
|
||||
fVideoSupplier(NULL),
|
||||
fVideoBounds(0, 0, -1, -1)
|
||||
fVideoBounds(0, 0, -1, -1),
|
||||
fPeakListener(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@ -233,13 +234,22 @@ NodeManager::SetVolume(float percent)
|
||||
// our audio node...
|
||||
}
|
||||
|
||||
// SetPeakListener
|
||||
void
|
||||
NodeManager::SetPeakListener(BHandler* handler)
|
||||
{
|
||||
fPeakListener = handler;
|
||||
if (fAudioProducer)
|
||||
fAudioProducer->SetPeakListener(fPeakListener);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _SetUpNodes
|
||||
status_t
|
||||
NodeManager::_SetUpNodes(color_space preferredVideoFormat)
|
||||
{
|
||||
printf("NodeManager::_SetUpNodes()\n");
|
||||
TRACE("NodeManager::_SetUpNodes()\n");
|
||||
|
||||
// find the media roster
|
||||
fStatus = B_OK;
|
||||
@ -425,6 +435,7 @@ status_t
|
||||
NodeManager::_SetUpAudioNodes()
|
||||
{
|
||||
fAudioProducer = new AudioProducer("MediaPlayer Audio Out", fAudioSupplier);
|
||||
fAudioProducer->SetPeakListener(fPeakListener);
|
||||
fStatus = fMediaRoster->RegisterNode(fAudioProducer);
|
||||
if (fStatus != B_OK) {
|
||||
print_error("unable to register audio producer node!\n", fStatus);
|
||||
|
@ -62,6 +62,8 @@ class NodeManager : public PlaybackManager {
|
||||
|
||||
virtual void SetVolume(float percent);
|
||||
|
||||
void SetPeakListener(BHandler* handler);
|
||||
|
||||
private:
|
||||
status_t _SetUpNodes(color_space preferredVideoFormat);
|
||||
status_t _SetUpVideoNodes(
|
||||
@ -103,6 +105,8 @@ private:
|
||||
AudioSupplier* fAudioSupplier;
|
||||
VideoSupplier* fVideoSupplier;
|
||||
BRect fVideoBounds;
|
||||
|
||||
BHandler* fPeakListener;
|
||||
};
|
||||
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include <TimeSource.h>
|
||||
|
||||
#include "AudioSupplier.h"
|
||||
#include "EventQueue.h"
|
||||
#include "MessageEvent.h"
|
||||
|
||||
#define DEBUG_TO_FILE 0
|
||||
|
||||
@ -94,7 +96,9 @@ AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier,
|
||||
fFramesSent(0),
|
||||
fStartTime(0),
|
||||
fSupplier(supplier),
|
||||
fRunning(false)
|
||||
fRunning(false),
|
||||
|
||||
fPeakListener(NULL)
|
||||
{
|
||||
TRACE("%p->AudioProducer::AudioProducer(%s, %p, %d)\n", this, name,
|
||||
supplier, lowLatency);
|
||||
@ -661,6 +665,13 @@ AudioProducer::SetRunning(bool running)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioProducer::SetPeakListener(BHandler* handler)
|
||||
{
|
||||
fPeakListener = handler;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
@ -739,6 +750,42 @@ AudioProducer::_FillNextBuffer(bigtime_t eventTime)
|
||||
}
|
||||
#endif // DEBUG_TO_FILE
|
||||
|
||||
if (fPeakListener
|
||||
&& fOutput.format.u.raw_audio.format
|
||||
== media_raw_audio_format::B_AUDIO_FLOAT) {
|
||||
// TODO: extend the peak notifier for other sample formats
|
||||
int32 channels = fOutput.format.u.raw_audio.channel_count;
|
||||
float max[channels];
|
||||
float min[channels];
|
||||
for (int32 i = 0; i < channels; i++) {
|
||||
max[i] = -1.0;
|
||||
min[i] = 1.0;
|
||||
}
|
||||
float* sample = (float*)buffer->Data();
|
||||
for (uint32 i = 0; i < frameCount; i++) {
|
||||
for (int32 k = 0; k < channels; k++) {
|
||||
if (*sample < min[k])
|
||||
min[k] = *sample;
|
||||
if (*sample > max[k])
|
||||
max[k] = *sample;
|
||||
sample++;
|
||||
}
|
||||
}
|
||||
BMessage message(MSG_PEAK_NOTIFICATION);
|
||||
for (int32 i = 0; i < channels; i++) {
|
||||
float maxAbs = max_c(fabs(min[i]), fabs(max[i]));
|
||||
message.AddFloat("max", maxAbs);
|
||||
}
|
||||
bigtime_t realTime = TimeSource()->RealTimeFor(performanceTime, 0);
|
||||
realTime -= 2000;
|
||||
// deliver event about one video frame earlier to account
|
||||
// for latency between app_server and client
|
||||
MessageEvent* event = new (nothrow) MessageEvent(realTime,
|
||||
fPeakListener, message);
|
||||
if (event != NULL)
|
||||
EventQueue::Default().AddEvent(event);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,11 @@
|
||||
#include <MediaEventLooper.h>
|
||||
|
||||
class AudioSupplier;
|
||||
class BHandler;
|
||||
|
||||
enum {
|
||||
MSG_PEAK_NOTIFICATION = 'pknt'
|
||||
};
|
||||
|
||||
class AudioProducer : public BBufferProducer, public BMediaEventLooper {
|
||||
public:
|
||||
@ -95,6 +100,9 @@ public:
|
||||
|
||||
void SetRunning(bool running);
|
||||
|
||||
// AudioProducer
|
||||
void SetPeakListener(BHandler* handler);
|
||||
|
||||
private:
|
||||
status_t _AllocateBuffers(media_format* format);
|
||||
BBuffer* _FillNextBuffer(bigtime_t eventTime);
|
||||
@ -116,6 +124,8 @@ private:
|
||||
|
||||
AudioSupplier* fSupplier;
|
||||
volatile bool fRunning;
|
||||
|
||||
BHandler* fPeakListener;
|
||||
};
|
||||
|
||||
#endif // AUDIO_PRODUCER_H
|
||||
|
@ -11,7 +11,16 @@
|
||||
MessageEvent::MessageEvent(bigtime_t time, BHandler* handler, uint32 command)
|
||||
: Event(time),
|
||||
AbstractLOAdapter(handler),
|
||||
fCommand(command)
|
||||
fMessage(command)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
MessageEvent::MessageEvent(bigtime_t time, BHandler* handler,
|
||||
const BMessage& message)
|
||||
: Event(time),
|
||||
AbstractLOAdapter(handler),
|
||||
fMessage(message)
|
||||
{
|
||||
}
|
||||
|
||||
@ -31,7 +40,7 @@ MessageEvent::~MessageEvent()
|
||||
void
|
||||
MessageEvent::Execute()
|
||||
{
|
||||
BMessage msg(fCommand);
|
||||
BMessage msg(fMessage);
|
||||
msg.AddInt64("time", Time());
|
||||
DeliverMessage(msg);
|
||||
}
|
||||
|
@ -7,12 +7,14 @@
|
||||
#define MESSAGE_EVENT_H
|
||||
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
#include "AbstractLOAdapter.h"
|
||||
#include "Event.h"
|
||||
|
||||
|
||||
enum {
|
||||
MSG_EVENT = 'evnt',
|
||||
MSG_EVENT = 'evnt'
|
||||
};
|
||||
|
||||
|
||||
@ -21,6 +23,9 @@ class MessageEvent : public Event, public AbstractLOAdapter {
|
||||
MessageEvent(bigtime_t time,
|
||||
BHandler* handler,
|
||||
uint32 command = MSG_EVENT);
|
||||
MessageEvent(bigtime_t time,
|
||||
BHandler* handler,
|
||||
const BMessage& message);
|
||||
MessageEvent(bigtime_t time,
|
||||
const BMessenger& messenger);
|
||||
virtual ~MessageEvent();
|
||||
@ -28,7 +33,7 @@ class MessageEvent : public Event, public AbstractLOAdapter {
|
||||
virtual void Execute();
|
||||
|
||||
private:
|
||||
uint32 fCommand;
|
||||
BMessage fMessage;
|
||||
};
|
||||
|
||||
#endif // MESSAGE_EVENT_H
|
||||
|
Loading…
Reference in New Issue
Block a user