* 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:
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
ControllerView::ControllerView(BRect frame, Controller* controller,
|
ControllerView::ControllerView(BRect frame, Controller* controller,
|
||||||
Playlist* playlist)
|
Playlist* playlist)
|
||||||
: TransportControlGroup(frame)
|
: TransportControlGroup(frame, true, true, false)
|
||||||
, fController(controller)
|
, fController(controller)
|
||||||
, fPlaylist(playlist)
|
, fPlaylist(playlist)
|
||||||
, fPlaylistObserver(new PlaylistObserver(this))
|
, fPlaylistObserver(new PlaylistObserver(this))
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ for sourceDir in $(sourceDirs) {
|
|||||||
Application MediaPlayer :
|
Application MediaPlayer :
|
||||||
# interface
|
# interface
|
||||||
DrawingTidbits.cpp
|
DrawingTidbits.cpp
|
||||||
|
PeakView.cpp
|
||||||
SeekSlider.cpp
|
SeekSlider.cpp
|
||||||
TransportButton.cpp
|
TransportButton.cpp
|
||||||
VolumeSlider.cpp
|
VolumeSlider.cpp
|
||||||
|
|||||||
@@ -41,8 +41,10 @@
|
|||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
|
|
||||||
|
#include "AudioProducer.h"
|
||||||
#include "ControllerObserver.h"
|
#include "ControllerObserver.h"
|
||||||
#include "MainApp.h"
|
#include "MainApp.h"
|
||||||
|
#include "PeakView.h"
|
||||||
#include "PlaylistObserver.h"
|
#include "PlaylistObserver.h"
|
||||||
#include "PlaylistWindow.h"
|
#include "PlaylistWindow.h"
|
||||||
#include "SettingsWindow.h"
|
#include "SettingsWindow.h"
|
||||||
@@ -170,6 +172,9 @@ MainWin::MainWin()
|
|||||||
fPlaylist->AddListener(fPlaylistObserver);
|
fPlaylist->AddListener(fPlaylistObserver);
|
||||||
fController->SetVideoView(fVideoView);
|
fController->SetVideoView(fVideoView);
|
||||||
fController->AddListener(fControllerObserver);
|
fController->AddListener(fControllerObserver);
|
||||||
|
PeakView* peakView = fControls->GetPeakView();
|
||||||
|
peakView->SetPeakNotificationWhat(MSG_PEAK_NOTIFICATION);
|
||||||
|
fController->SetPeakListener(peakView);
|
||||||
|
|
||||||
// printf("fMenuBarHeight %d\n", fMenuBarHeight);
|
// printf("fMenuBarHeight %d\n", fMenuBarHeight);
|
||||||
// printf("fControlsHeight %d\n", fControlsHeight);
|
// printf("fControlsHeight %d\n", fControlsHeight);
|
||||||
@@ -201,6 +206,7 @@ MainWin::~MainWin()
|
|||||||
|
|
||||||
fPlaylist->RemoveListener(fPlaylistObserver);
|
fPlaylist->RemoveListener(fPlaylistObserver);
|
||||||
fController->RemoveListener(fControllerObserver);
|
fController->RemoveListener(fControllerObserver);
|
||||||
|
fController->SetPeakListener(NULL);
|
||||||
|
|
||||||
// give the views a chance to detach from any notifiers
|
// give the views a chance to detach from any notifiers
|
||||||
// before we delete them
|
// before we delete them
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006, Haiku.
|
* Copyright © 2006-2008 Stephan Aßmus <[email protected]>
|
||||||
* Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Stephan Aßmus <[email protected]>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
// 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
|
// removed. -Stephan Aßmus
|
||||||
|
|
||||||
#include "TransportControlGroup.h"
|
#include "TransportControlGroup.h"
|
||||||
@@ -18,6 +15,7 @@
|
|||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
#include "ButtonBitmaps.h"
|
#include "ButtonBitmaps.h"
|
||||||
|
#include "PeakView.h"
|
||||||
#include "PlaybackState.h"
|
#include "PlaybackState.h"
|
||||||
#include "SeekSlider.h"
|
#include "SeekSlider.h"
|
||||||
#include "TransportButton.h"
|
#include "TransportButton.h"
|
||||||
@@ -53,63 +51,55 @@ enum {
|
|||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
TransportControlGroup::TransportControlGroup(BRect frame, bool useSkipButtons,
|
TransportControlGroup::TransportControlGroup(BRect frame, bool useSkipButtons,
|
||||||
bool useWindButtons)
|
bool usePeakView, bool useWindButtons)
|
||||||
: BView(frame, "transport control group",
|
: BView(frame, "transport control group",
|
||||||
B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
|
B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
|
||||||
B_WILL_DRAW | B_FRAME_EVENTS)
|
B_WILL_DRAW | B_FRAME_EVENTS)
|
||||||
, fBottomControlHeight(0.0)
|
, fBottomControlHeight(0.0)
|
||||||
|
, fPeakViewMinWidth(0.0)
|
||||||
{
|
{
|
||||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
|
||||||
frame.Set(0.0, 0.0, 10.0, 10.0);
|
frame.Set(0.0, 0.0, 10.0, 10.0);
|
||||||
|
|
||||||
// Seek Slider
|
// Seek Slider
|
||||||
fSeekSlider = new SeekSlider(frame, "seek slider",
|
fSeekSlider = new SeekSlider(frame, "seek slider", new BMessage(MSG_SEEK),
|
||||||
new BMessage(MSG_SEEK),
|
0, kPositionFactor);
|
||||||
0, kPositionFactor);
|
|
||||||
fSeekSlider->ResizeToPreferred();
|
fSeekSlider->ResizeToPreferred();
|
||||||
AddChild(fSeekSlider);
|
AddChild(fSeekSlider);
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
if (useSkipButtons) {
|
if (useSkipButtons) {
|
||||||
// Skip Back
|
// Skip Back
|
||||||
frame.right = kRewindBitmapWidth - 1;
|
frame.right = kRewindBitmapWidth - 1;
|
||||||
frame.bottom = kRewindBitmapHeight - 1;
|
frame.bottom = kRewindBitmapHeight - 1;
|
||||||
fBottomControlHeight = kRewindBitmapHeight - 1.0;
|
fBottomControlHeight = kRewindBitmapHeight - 1.0;
|
||||||
fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
|
fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
|
||||||
kSkipBackBitmapBits,
|
kSkipBackBitmapBits, kPressedSkipBackBitmapBits,
|
||||||
kPressedSkipBackBitmapBits,
|
kDisabledSkipBackBitmapBits, new BMessage(MSG_SKIP_BACKWARDS));
|
||||||
kDisabledSkipBackBitmapBits,
|
AddChild(fSkipBack);
|
||||||
new BMessage(MSG_SKIP_BACKWARDS));
|
|
||||||
AddChild(fSkipBack);
|
// Skip Foward
|
||||||
|
fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
|
||||||
// Skip Foward
|
kSkipForwardBitmapBits, kPressedSkipForwardBitmapBits,
|
||||||
fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
|
kDisabledSkipForwardBitmapBits, new BMessage(MSG_SKIP_FORWARD));
|
||||||
kSkipForwardBitmapBits,
|
AddChild(fSkipForward);
|
||||||
kPressedSkipForwardBitmapBits,
|
} else {
|
||||||
kDisabledSkipForwardBitmapBits,
|
fSkipBack = NULL;
|
||||||
new BMessage(MSG_SKIP_FORWARD));
|
fSkipForward = NULL;
|
||||||
AddChild(fSkipForward);
|
|
||||||
} else {
|
|
||||||
fSkipBack = NULL;
|
|
||||||
fSkipForward = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useWindButtons) {
|
if (useWindButtons) {
|
||||||
// Forward
|
// Forward
|
||||||
fForward = new TransportButton(frame, B_EMPTY_STRING,
|
fForward = new TransportButton(frame, B_EMPTY_STRING,
|
||||||
kForwardBitmapBits,
|
kForwardBitmapBits, kPressedForwardBitmapBits,
|
||||||
kPressedForwardBitmapBits,
|
kDisabledForwardBitmapBits, new BMessage(MSG_FORWARD));
|
||||||
kDisabledForwardBitmapBits,
|
|
||||||
new BMessage(MSG_FORWARD));
|
|
||||||
AddChild(fForward);
|
AddChild(fForward);
|
||||||
|
|
||||||
// Rewind
|
// Rewind
|
||||||
fRewind = new TransportButton(frame, B_EMPTY_STRING,
|
fRewind = new TransportButton(frame, B_EMPTY_STRING,
|
||||||
kRewindBitmapBits,
|
kRewindBitmapBits, kPressedRewindBitmapBits,
|
||||||
kPressedRewindBitmapBits,
|
kDisabledRewindBitmapBits, new BMessage(MSG_REWIND));
|
||||||
kDisabledRewindBitmapBits,
|
|
||||||
new BMessage(MSG_REWIND));
|
|
||||||
AddChild(fRewind);
|
AddChild(fRewind);
|
||||||
} else {
|
} else {
|
||||||
fForward = NULL;
|
fForward = NULL;
|
||||||
@@ -117,56 +107,56 @@ TransportControlGroup::TransportControlGroup(BRect frame, bool useSkipButtons,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Play Pause
|
// Play Pause
|
||||||
frame.right = kPlayPauseBitmapWidth - 1;
|
frame.right = kPlayPauseBitmapWidth - 1;
|
||||||
frame.bottom = kPlayPauseBitmapHeight - 1;
|
frame.bottom = kPlayPauseBitmapHeight - 1;
|
||||||
if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
|
if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
|
||||||
fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
|
fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
|
||||||
fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
|
fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
|
||||||
kPlayButtonBitmapBits,
|
kPlayButtonBitmapBits, kPressedPlayButtonBitmapBits,
|
||||||
kPressedPlayButtonBitmapBits,
|
kDisabledPlayButtonBitmapBits, kPlayingPlayButtonBitmapBits,
|
||||||
kDisabledPlayButtonBitmapBits,
|
kPressedPlayingPlayButtonBitmapBits, kPausedPlayButtonBitmapBits,
|
||||||
kPlayingPlayButtonBitmapBits,
|
kPressedPausedPlayButtonBitmapBits, new BMessage(MSG_PLAY));
|
||||||
kPressedPlayingPlayButtonBitmapBits,
|
|
||||||
kPausedPlayButtonBitmapBits,
|
|
||||||
kPressedPausedPlayButtonBitmapBits,
|
|
||||||
new BMessage(MSG_PLAY));
|
|
||||||
|
|
||||||
AddChild(fPlayPause);
|
AddChild(fPlayPause);
|
||||||
|
|
||||||
// Stop
|
// Stop
|
||||||
frame.right = kStopBitmapWidth - 1;
|
frame.right = kStopBitmapWidth - 1;
|
||||||
frame.bottom = kStopBitmapHeight - 1;
|
frame.bottom = kStopBitmapHeight - 1;
|
||||||
if (fBottomControlHeight < kStopBitmapHeight - 1.0)
|
if (fBottomControlHeight < kStopBitmapHeight - 1.0)
|
||||||
fBottomControlHeight = kStopBitmapHeight - 1.0;
|
fBottomControlHeight = kStopBitmapHeight - 1.0;
|
||||||
fStop = new TransportButton(frame, B_EMPTY_STRING,
|
fStop = new TransportButton(frame, B_EMPTY_STRING, kStopButtonBitmapBits,
|
||||||
kStopButtonBitmapBits,
|
kPressedStopButtonBitmapBits, kDisabledStopButtonBitmapBits,
|
||||||
kPressedStopButtonBitmapBits,
|
new BMessage(MSG_STOP));
|
||||||
kDisabledStopButtonBitmapBits,
|
|
||||||
new BMessage(MSG_STOP));
|
|
||||||
AddChild(fStop);
|
AddChild(fStop);
|
||||||
|
|
||||||
// Mute
|
// Mute
|
||||||
frame.right = kSpeakerIconBitmapWidth - 1;
|
frame.right = kSpeakerIconBitmapWidth - 1;
|
||||||
frame.bottom = kSpeakerIconBitmapHeight - 1;
|
frame.bottom = kSpeakerIconBitmapHeight - 1;
|
||||||
if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
|
if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
|
||||||
fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
|
fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
|
||||||
fMute = new TransportButton(frame, B_EMPTY_STRING,
|
fMute = new TransportButton(frame, B_EMPTY_STRING, kSpeakerIconBits,
|
||||||
kSpeakerIconBits,
|
kPressedSpeakerIconBits, kSpeakerIconBits, new BMessage(MSG_SET_MUTE));
|
||||||
kPressedSpeakerIconBits,
|
|
||||||
kSpeakerIconBits,
|
|
||||||
new BMessage(MSG_SET_MUTE));
|
|
||||||
|
|
||||||
AddChild(fMute);
|
AddChild(fMute);
|
||||||
|
|
||||||
// Volume Slider
|
// Volume Slider
|
||||||
fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
|
fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
|
||||||
kVolumeSliderBitmapHeight - 1.0),
|
kVolumeSliderBitmapHeight - 1.0), "volume slider",
|
||||||
"volume slider",
|
_DbToGain(_ExponentialToLinear(kVolumeDbMin)) * kVolumeFactor,
|
||||||
_DbToGain(_ExponentialToLinear(kVolumeDbMin)) * kVolumeFactor,
|
_DbToGain(_ExponentialToLinear(kVolumeDbMax)) * kVolumeFactor,
|
||||||
_DbToGain(_ExponentialToLinear(kVolumeDbMax)) * kVolumeFactor,
|
new BMessage(MSG_SET_VOLUME));
|
||||||
new BMessage(MSG_SET_VOLUME));
|
fVolumeSlider->SetValue(_DbToGain(_ExponentialToLinear(0.0))
|
||||||
fVolumeSlider->SetValue(_DbToGain(_ExponentialToLinear(0.0)) * kVolumeFactor);
|
* kVolumeFactor);
|
||||||
AddChild(fVolumeSlider);
|
AddChild(fVolumeSlider);
|
||||||
|
|
||||||
|
// Peak view
|
||||||
|
if (usePeakView) {
|
||||||
|
fPeakView = new PeakView("peak view", false, false);
|
||||||
|
AddChild(fPeakView);
|
||||||
|
fPeakView->GetPreferredSize(&fPeakViewMinWidth, NULL);
|
||||||
|
} else {
|
||||||
|
fPeakView = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// destructor
|
// destructor
|
||||||
@@ -469,6 +459,8 @@ TransportControlGroup::_LayoutControls(BRect frame) const
|
|||||||
minWidth += fSkipForward->Bounds().Width();
|
minWidth += fSkipForward->Bounds().Width();
|
||||||
minWidth += fMute->Bounds().Width();
|
minWidth += fMute->Bounds().Width();
|
||||||
minWidth += VOLUME_MIN_WIDTH;
|
minWidth += VOLUME_MIN_WIDTH;
|
||||||
|
if (fPeakView)
|
||||||
|
minWidth += fPeakViewMinWidth;
|
||||||
|
|
||||||
// layout seek slider
|
// layout seek slider
|
||||||
r.bottom = r.top + fSeekSlider->Bounds().Height();
|
r.bottom = r.top + fSeekSlider->Bounds().Height();
|
||||||
@@ -481,7 +473,8 @@ TransportControlGroup::_LayoutControls(BRect frame) const
|
|||||||
float currentWidth = frame.Width();
|
float currentWidth = frame.Width();
|
||||||
float space = (currentWidth - minWidth) / 6.0;
|
float space = (currentWidth - minWidth) / 6.0;
|
||||||
// apply weighting
|
// 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
|
// layout controls with "space" inbetween
|
||||||
r.left = frame.left;
|
r.left = frame.left;
|
||||||
r.top = r.bottom + MIN_SPACE + 1.0;
|
r.top = r.bottom + MIN_SPACE + 1.0;
|
||||||
@@ -522,11 +515,24 @@ TransportControlGroup::_LayoutControls(BRect frame) const
|
|||||||
r.left = r.right + space + space;
|
r.left = r.right + space + space;
|
||||||
r.right = r.left + fMute->Bounds().Width();
|
r.right = r.left + fMute->Bounds().Width();
|
||||||
_LayoutControl(fMute, r);
|
_LayoutControl(fMute, r);
|
||||||
|
|
||||||
// volume slider
|
// volume slider
|
||||||
r.left = r.right + SPEAKER_SLIDER_DIST;
|
r.left = r.right + SPEAKER_SLIDER_DIST;
|
||||||
// keep speaker icon and volume slider attached
|
// 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);
|
_LayoutControl(fVolumeSlider, r, true);
|
||||||
|
|
||||||
|
if (fPeakView) {
|
||||||
|
peakViewWidth -= space;
|
||||||
|
r.left = r.right + space;
|
||||||
|
r.right = r.left + peakViewWidth;
|
||||||
|
_LayoutControl(fPeakView, r, true, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _MinFrame
|
// _MinFrame
|
||||||
@@ -547,6 +553,8 @@ TransportControlGroup::_MinFrame() const
|
|||||||
minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
|
minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
|
||||||
minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
|
minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
|
||||||
minWidth += VOLUME_MIN_WIDTH;
|
minWidth += VOLUME_MIN_WIDTH;
|
||||||
|
if (fPeakView)
|
||||||
|
minWidth += fPeakViewMinWidth;
|
||||||
|
|
||||||
// add up height of seek slider and heighest control on bottom
|
// add up height of seek slider and heighest control on bottom
|
||||||
float minHeight = 2 * BORDER_INSET;
|
float minHeight = 2 * BORDER_INSET;
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006, Haiku.
|
* Copyright © 2006-2008 Stephan Aßmus <superstippi@gmx.de>
|
||||||
* Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Stephan Aßmus <superstippi@gmx.de>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
||||||
@@ -15,6 +12,7 @@
|
|||||||
|
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
|
|
||||||
|
class PeakView;
|
||||||
class PlayPauseButton;
|
class PlayPauseButton;
|
||||||
class TransportButton;
|
class TransportButton;
|
||||||
class SeekSlider;
|
class SeekSlider;
|
||||||
@@ -33,8 +31,9 @@ enum {
|
|||||||
class TransportControlGroup : public BView {
|
class TransportControlGroup : public BView {
|
||||||
public:
|
public:
|
||||||
TransportControlGroup(BRect frame,
|
TransportControlGroup(BRect frame,
|
||||||
bool useSkipButtons = true,
|
bool useSkipButtons,
|
||||||
bool useWindButtons = false);
|
bool usePeakView,
|
||||||
|
bool useWindButtons);
|
||||||
virtual ~TransportControlGroup();
|
virtual ~TransportControlGroup();
|
||||||
|
|
||||||
// BView interface
|
// BView interface
|
||||||
@@ -67,6 +66,9 @@ class TransportControlGroup : public BView {
|
|||||||
void SetVolume(float value);
|
void SetVolume(float value);
|
||||||
void SetPosition(float value);
|
void SetPosition(float value);
|
||||||
|
|
||||||
|
PeakView* GetPeakView() const
|
||||||
|
{ return fPeakView; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _LayoutControls(BRect frame) const;
|
void _LayoutControls(BRect frame) const;
|
||||||
BRect _MinFrame() const;
|
BRect _MinFrame() const;
|
||||||
@@ -91,7 +93,7 @@ class TransportControlGroup : public BView {
|
|||||||
float _GainToDb(float gain);
|
float _GainToDb(float gain);
|
||||||
|
|
||||||
SeekSlider* fSeekSlider;
|
SeekSlider* fSeekSlider;
|
||||||
|
PeakView* fPeakView;
|
||||||
VolumeSlider* fVolumeSlider;
|
VolumeSlider* fVolumeSlider;
|
||||||
|
|
||||||
TransportButton* fSkipBack;
|
TransportButton* fSkipBack;
|
||||||
@@ -103,6 +105,7 @@ class TransportControlGroup : public BView {
|
|||||||
TransportButton* fMute;
|
TransportButton* fMute;
|
||||||
|
|
||||||
float fBottomControlHeight;
|
float fBottomControlHeight;
|
||||||
|
float fPeakViewMinWidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRANSPORT_CONTROL_GROUP_H
|
#endif // TRANSPORT_CONTROL_GROUP_H
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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.
|
* Copyright © 2006-2008 Stephan Aßmus <superstippi@gmx.de>
|
||||||
* Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Stephan Aßmus <superstippi@gmx.de>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
// 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
|
// removed. -Stephan Aßmus
|
||||||
|
|
||||||
#include "SeekSlider.h"
|
#include "SeekSlider.h"
|
||||||
@@ -32,7 +29,7 @@ const char* kDisabledSeekMessage = "Drop files to play";
|
|||||||
SeekSlider::SeekSlider(BRect frame, const char* name, BMessage* message,
|
SeekSlider::SeekSlider(BRect frame, const char* name, BMessage* message,
|
||||||
int32 minValue, int32 maxValue)
|
int32 minValue, int32 maxValue)
|
||||||
: BControl(frame, name, NULL, message, B_FOLLOW_LEFT | B_FOLLOW_TOP,
|
: 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)
|
, fTracking(false)
|
||||||
, fLastTrackTime(0)
|
, fLastTrackTime(0)
|
||||||
, fKnobPos(_KnobPosFor(Bounds(), Value()))
|
, fKnobPos(_KnobPosFor(Bounds(), Value()))
|
||||||
@@ -101,9 +98,9 @@ SeekSlider::Draw(BRect updateRect)
|
|||||||
rgb_color dotGrey = midShadow;
|
rgb_color dotGrey = midShadow;
|
||||||
rgb_color dotGreen = greenShadow;
|
rgb_color dotGreen = greenShadow;
|
||||||
// draw frame
|
// draw frame
|
||||||
_StrokeFrame(r, softShadow, softShadow, softLight, softLight);
|
_StrokeFrame(r, softShadow, softShadow, light, light);
|
||||||
r.InsetBy(1.0, 1.0);
|
r.InsetBy(1.0, 1.0);
|
||||||
_StrokeFrame(r, black, black, light, light);
|
_StrokeFrame(r, black, black, softShadow, softShadow);
|
||||||
if (IsEnabled()) {
|
if (IsEnabled()) {
|
||||||
// *** enabled look ***
|
// *** enabled look ***
|
||||||
r.InsetBy(1.0, 1.0);
|
r.InsetBy(1.0, 1.0);
|
||||||
@@ -280,6 +277,13 @@ SeekSlider::ResizeToPreferred()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SeekSlider::FrameResized(float width, float height)
|
||||||
|
{
|
||||||
|
_SetKnobPosition(_KnobPosFor(Bounds(), Value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SeekSlider::SetPosition(float position)
|
SeekSlider::SetPosition(float position)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006, Haiku.
|
* Copyright © 2006-2008 Stephan Aßmus <superstippi@gmx.de>
|
||||||
* Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Stephan Aßmus <superstippi@gmx.de>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SEEK_SLIDER_H
|
#ifndef SEEK_SLIDER_H
|
||||||
@@ -15,10 +12,8 @@
|
|||||||
class SeekSlider : public BControl {
|
class SeekSlider : public BControl {
|
||||||
public:
|
public:
|
||||||
SeekSlider(BRect frame,
|
SeekSlider(BRect frame,
|
||||||
const char* name,
|
const char* name, BMessage* message,
|
||||||
BMessage* message,
|
int32 minValue, int32 maxValue);
|
||||||
int32 minValue,
|
|
||||||
int32 maxValue);
|
|
||||||
|
|
||||||
virtual ~SeekSlider();
|
virtual ~SeekSlider();
|
||||||
|
|
||||||
@@ -28,9 +23,10 @@ class SeekSlider : public BControl {
|
|||||||
virtual void Draw(BRect updateRect);
|
virtual void Draw(BRect updateRect);
|
||||||
virtual void MouseDown(BPoint where);
|
virtual void MouseDown(BPoint where);
|
||||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
const BMessage* dragMessage);
|
const BMessage* dragMessage);
|
||||||
virtual void MouseUp(BPoint where);
|
virtual void MouseUp(BPoint where);
|
||||||
virtual void ResizeToPreferred();
|
virtual void ResizeToPreferred();
|
||||||
|
virtual void FrameResized(float width, float height);
|
||||||
|
|
||||||
// SeekSlider
|
// SeekSlider
|
||||||
void SetPosition(float position);
|
void SetPosition(float position);
|
||||||
@@ -41,10 +37,8 @@ private:
|
|||||||
int32 _KnobPosFor(BRect bounds,
|
int32 _KnobPosFor(BRect bounds,
|
||||||
int32 value) const;
|
int32 value) const;
|
||||||
void _StrokeFrame(BRect frame,
|
void _StrokeFrame(BRect frame,
|
||||||
rgb_color left,
|
rgb_color left, rgb_color top,
|
||||||
rgb_color top,
|
rgb_color right, rgb_color bottom);
|
||||||
rgb_color right,
|
|
||||||
rgb_color bottom);
|
|
||||||
void _SetKnobPosition(int32 knobPos);
|
void _SetKnobPosition(int32 knobPos);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ NodeManager::NodeManager()
|
|||||||
fVideoTarget(NULL),
|
fVideoTarget(NULL),
|
||||||
fAudioSupplier(NULL),
|
fAudioSupplier(NULL),
|
||||||
fVideoSupplier(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...
|
// our audio node...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPeakListener
|
||||||
|
void
|
||||||
|
NodeManager::SetPeakListener(BHandler* handler)
|
||||||
|
{
|
||||||
|
fPeakListener = handler;
|
||||||
|
if (fAudioProducer)
|
||||||
|
fAudioProducer->SetPeakListener(fPeakListener);
|
||||||
|
}
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
// _SetUpNodes
|
// _SetUpNodes
|
||||||
status_t
|
status_t
|
||||||
NodeManager::_SetUpNodes(color_space preferredVideoFormat)
|
NodeManager::_SetUpNodes(color_space preferredVideoFormat)
|
||||||
{
|
{
|
||||||
printf("NodeManager::_SetUpNodes()\n");
|
TRACE("NodeManager::_SetUpNodes()\n");
|
||||||
|
|
||||||
// find the media roster
|
// find the media roster
|
||||||
fStatus = B_OK;
|
fStatus = B_OK;
|
||||||
@@ -425,6 +435,7 @@ status_t
|
|||||||
NodeManager::_SetUpAudioNodes()
|
NodeManager::_SetUpAudioNodes()
|
||||||
{
|
{
|
||||||
fAudioProducer = new AudioProducer("MediaPlayer Audio Out", fAudioSupplier);
|
fAudioProducer = new AudioProducer("MediaPlayer Audio Out", fAudioSupplier);
|
||||||
|
fAudioProducer->SetPeakListener(fPeakListener);
|
||||||
fStatus = fMediaRoster->RegisterNode(fAudioProducer);
|
fStatus = fMediaRoster->RegisterNode(fAudioProducer);
|
||||||
if (fStatus != B_OK) {
|
if (fStatus != B_OK) {
|
||||||
print_error("unable to register audio producer node!\n", fStatus);
|
print_error("unable to register audio producer node!\n", fStatus);
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ class NodeManager : public PlaybackManager {
|
|||||||
|
|
||||||
virtual void SetVolume(float percent);
|
virtual void SetVolume(float percent);
|
||||||
|
|
||||||
|
void SetPeakListener(BHandler* handler);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _SetUpNodes(color_space preferredVideoFormat);
|
status_t _SetUpNodes(color_space preferredVideoFormat);
|
||||||
status_t _SetUpVideoNodes(
|
status_t _SetUpVideoNodes(
|
||||||
@@ -103,6 +105,8 @@ private:
|
|||||||
AudioSupplier* fAudioSupplier;
|
AudioSupplier* fAudioSupplier;
|
||||||
VideoSupplier* fVideoSupplier;
|
VideoSupplier* fVideoSupplier;
|
||||||
BRect fVideoBounds;
|
BRect fVideoBounds;
|
||||||
|
|
||||||
|
BHandler* fPeakListener;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include <TimeSource.h>
|
#include <TimeSource.h>
|
||||||
|
|
||||||
#include "AudioSupplier.h"
|
#include "AudioSupplier.h"
|
||||||
|
#include "EventQueue.h"
|
||||||
|
#include "MessageEvent.h"
|
||||||
|
|
||||||
#define DEBUG_TO_FILE 0
|
#define DEBUG_TO_FILE 0
|
||||||
|
|
||||||
@@ -94,7 +96,9 @@ AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier,
|
|||||||
fFramesSent(0),
|
fFramesSent(0),
|
||||||
fStartTime(0),
|
fStartTime(0),
|
||||||
fSupplier(supplier),
|
fSupplier(supplier),
|
||||||
fRunning(false)
|
fRunning(false),
|
||||||
|
|
||||||
|
fPeakListener(NULL)
|
||||||
{
|
{
|
||||||
TRACE("%p->AudioProducer::AudioProducer(%s, %p, %d)\n", this, name,
|
TRACE("%p->AudioProducer::AudioProducer(%s, %p, %d)\n", this, name,
|
||||||
supplier, lowLatency);
|
supplier, lowLatency);
|
||||||
@@ -661,6 +665,13 @@ AudioProducer::SetRunning(bool running)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioProducer::SetPeakListener(BHandler* handler)
|
||||||
|
{
|
||||||
|
fPeakListener = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -739,6 +750,42 @@ AudioProducer::_FillNextBuffer(bigtime_t eventTime)
|
|||||||
}
|
}
|
||||||
#endif // DEBUG_TO_FILE
|
#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;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,11 @@
|
|||||||
#include <MediaEventLooper.h>
|
#include <MediaEventLooper.h>
|
||||||
|
|
||||||
class AudioSupplier;
|
class AudioSupplier;
|
||||||
|
class BHandler;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSG_PEAK_NOTIFICATION = 'pknt'
|
||||||
|
};
|
||||||
|
|
||||||
class AudioProducer : public BBufferProducer, public BMediaEventLooper {
|
class AudioProducer : public BBufferProducer, public BMediaEventLooper {
|
||||||
public:
|
public:
|
||||||
@@ -95,6 +100,9 @@ public:
|
|||||||
|
|
||||||
void SetRunning(bool running);
|
void SetRunning(bool running);
|
||||||
|
|
||||||
|
// AudioProducer
|
||||||
|
void SetPeakListener(BHandler* handler);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _AllocateBuffers(media_format* format);
|
status_t _AllocateBuffers(media_format* format);
|
||||||
BBuffer* _FillNextBuffer(bigtime_t eventTime);
|
BBuffer* _FillNextBuffer(bigtime_t eventTime);
|
||||||
@@ -116,6 +124,8 @@ private:
|
|||||||
|
|
||||||
AudioSupplier* fSupplier;
|
AudioSupplier* fSupplier;
|
||||||
volatile bool fRunning;
|
volatile bool fRunning;
|
||||||
|
|
||||||
|
BHandler* fPeakListener;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AUDIO_PRODUCER_H
|
#endif // AUDIO_PRODUCER_H
|
||||||
|
|||||||
@@ -11,7 +11,16 @@
|
|||||||
MessageEvent::MessageEvent(bigtime_t time, BHandler* handler, uint32 command)
|
MessageEvent::MessageEvent(bigtime_t time, BHandler* handler, uint32 command)
|
||||||
: Event(time),
|
: Event(time),
|
||||||
AbstractLOAdapter(handler),
|
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
|
void
|
||||||
MessageEvent::Execute()
|
MessageEvent::Execute()
|
||||||
{
|
{
|
||||||
BMessage msg(fCommand);
|
BMessage msg(fMessage);
|
||||||
msg.AddInt64("time", Time());
|
msg.AddInt64("time", Time());
|
||||||
DeliverMessage(msg);
|
DeliverMessage(msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,14 @@
|
|||||||
#define MESSAGE_EVENT_H
|
#define MESSAGE_EVENT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Message.h>
|
||||||
|
|
||||||
#include "AbstractLOAdapter.h"
|
#include "AbstractLOAdapter.h"
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MSG_EVENT = 'evnt',
|
MSG_EVENT = 'evnt'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -21,6 +23,9 @@ class MessageEvent : public Event, public AbstractLOAdapter {
|
|||||||
MessageEvent(bigtime_t time,
|
MessageEvent(bigtime_t time,
|
||||||
BHandler* handler,
|
BHandler* handler,
|
||||||
uint32 command = MSG_EVENT);
|
uint32 command = MSG_EVENT);
|
||||||
|
MessageEvent(bigtime_t time,
|
||||||
|
BHandler* handler,
|
||||||
|
const BMessage& message);
|
||||||
MessageEvent(bigtime_t time,
|
MessageEvent(bigtime_t time,
|
||||||
const BMessenger& messenger);
|
const BMessenger& messenger);
|
||||||
virtual ~MessageEvent();
|
virtual ~MessageEvent();
|
||||||
@@ -28,7 +33,7 @@ class MessageEvent : public Event, public AbstractLOAdapter {
|
|||||||
virtual void Execute();
|
virtual void Execute();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32 fCommand;
|
BMessage fMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MESSAGE_EVENT_H
|
#endif // MESSAGE_EVENT_H
|
||||||
|
|||||||
Reference in New Issue
Block a user