1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-12 14:47:43 +02:00

Merge branch 'master' into scrubbing2

This commit is contained in:
Paul Licameli 2016-06-01 13:29:49 -04:00
commit a40a567690
12 changed files with 4504 additions and 4316 deletions

View File

@ -123,6 +123,9 @@ from there. Audacity will look for a file called "Pause.png".
DEFINE_IMAGE( bmpMic, wxImage( 25, 25 ), wxT("Mic"));
DEFINE_IMAGE( bmpSpeaker, wxImage( 25, 25 ), wxT("Speaker"));
DEFINE_IMAGE( bmpPinnedPlayRecordHead, wxImage( 27, 27 ), wxT("PinnedPlayRecordHead"));
DEFINE_IMAGE( bmpUnpinnedPlayRecordHead, wxImage( 27, 27 ), wxT("UnpinnedPlayRecordHead"));
SET_THEME_FLAGS( resFlagPaired );
DEFINE_IMAGE( bmpZoomFit, wxImage( 27, 27 ), wxT("ZoomFit"));
DEFINE_IMAGE( bmpZoomFitDisabled, wxImage( 27, 27 ), wxT("ZoomFitDisabled"));

View File

@ -69,6 +69,7 @@ simplifies construction of menu items.
#include "export/Export.h"
#include "export/ExportMultiple.h"
#include "prefs/PrefsDialog.h"
#include "prefs/PlaybackPrefs.h"
#include "ShuttleGui.h"
#include "HistoryWindow.h"
#include "LyricsWindow.h"
@ -772,6 +773,11 @@ void AudacityProject::CreateMenusAndCommands()
c->AddSeparator();
c->AddCheck(wxT("PinnedHead"), _("Pinned Recording/Playback Head"),
FN(OnTogglePinnedHead), 0,
// Switching of scrolling on and off is permitted even during transport
AlwaysEnabledFlag, AlwaysEnabledFlag);
c->AddCheck(wxT("Duplex"), _("&Overdub (on/off)"), FN(OnTogglePlayRecording), 0);
c->AddCheck(wxT("SWPlaythrough"), _("So&ftware Playthrough (on/off)"), FN(OnToggleSWPlaythrough), 0);
@ -1840,6 +1846,10 @@ void AudacityProject::ModifyToolbarMenus()
gPrefs->Read(wxT("/AudioIO/AutomatedInputLevelAdjustment"),&active, false);
mCommandManager.Check(wxT("AutomatedInputLevelAdjustmentOnOff"), active);
#endif
active = PlaybackPrefs::GetPinnedHeadPreference();
mCommandManager.Check(wxT("PinnedHead"), active);
gPrefs->Read(wxT("/AudioIO/Duplex"),&active, true);
mCommandManager.Check(wxT("Duplex"), active);
gPrefs->Read(wxT("/AudioIO/SWPlaythrough"),&active, false);
@ -2360,6 +2370,23 @@ void AudacityProject::OnToggleSoundActivated()
ModifyAllProjectToolbarMenus();
}
void AudacityProject::OnTogglePinnedHead()
{
PlaybackPrefs::SetPinnedHeadPreference(
!PlaybackPrefs::GetPinnedHeadPreference(), true);
ModifyAllProjectToolbarMenus();
// Change what happens in case transport is in progress right now
auto ctb = GetActiveProject()->GetControlToolBar();
if (ctb)
ctb->StartScrollingIfPreferred();
auto ruler = GetRulerPanel();
if (ruler)
// Update button image
ruler->UpdateButtonStates();
}
void AudacityProject::OnTogglePlayRecording()
{
bool Duplex;

View File

@ -313,6 +313,7 @@ void OnResetToolBars();
void OnSoundActivated();
void OnToggleSoundActivated();
void OnTogglePinnedHead();
void OnTogglePlayRecording();
void OnToggleSWPlaythrough();
#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT

File diff suppressed because it is too large Load Diff

View File

@ -19,13 +19,25 @@
*//********************************************************************/
#include "../Audacity.h"
#include "PlaybackPrefs.h"
#include <wx/defs.h>
#include <wx/textctrl.h>
#include "../ShuttleGui.h"
#include "../Prefs.h"
#include "PlaybackPrefs.h"
namespace {
const wxChar *PinnedHeadPreferenceKey()
{
return wxT("/AudioIO/PinnedHead");
}
bool PinnedHeadPreferenceDefault()
{
return false;
}
}
PlaybackPrefs::PlaybackPrefs(wxWindow * parent)
: PrefsPanel(parent, _("Playback"))
@ -113,6 +125,11 @@ void PlaybackPrefs::PopulateOrExchange(ShuttleGui & S)
S.EndThreeColumn();
}
S.EndStatic();
// This affects recording too, though it is in playback preferences.
S.TieCheckBox(_("Pinned playback/recording head"),
PinnedHeadPreferenceKey(),
PinnedHeadPreferenceDefault());
}
bool PlaybackPrefs::Apply()
@ -123,8 +140,21 @@ bool PlaybackPrefs::Apply()
return true;
}
bool PlaybackPrefs::GetPinnedHeadPreference()
{
return gPrefs->ReadBool(PinnedHeadPreferenceKey(), PinnedHeadPreferenceDefault());
}
void PlaybackPrefs::SetPinnedHeadPreference(bool value, bool flush)
{
gPrefs->Write(PinnedHeadPreferenceKey(), value);
if(flush)
gPrefs->Flush();
}
PrefsPanel *PlaybackPrefsFactory::Create(wxWindow *parent)
{
wxASSERT(parent); // to justify safenew
return safenew PlaybackPrefs(parent);
}

View File

@ -27,6 +27,9 @@ class PlaybackPrefs final : public PrefsPanel
virtual ~PlaybackPrefs();
bool Apply() override;
static bool GetPinnedHeadPreference();
static void SetPinnedHeadPreference(bool value, bool flush = false);
private:
void Populate();
void PopulateOrExchange(ShuttleGui & S);

View File

@ -68,6 +68,7 @@
#include "../widgets/Meter.h"
#include "../tracks/ui/Scrubbing.h"
#include "../prefs/PlaybackPrefs.h"
IMPLEMENT_CLASS(ControlToolBar, ToolBar);
@ -635,15 +636,16 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
NoteTrackArray(),
#endif
tcp0, tcp1, myOptions);
} else
{
}
else {
// Cannot create cut preview tracks, clean up and exit
SetPlay(false);
SetStop(false);
SetRecord(false);
return -1;
}
} else {
}
else {
// Lifted the following into AudacityProject::GetDefaultPlayOptions()
/*
if (!timetrack) {
@ -682,6 +684,8 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
return -1;
}
StartScrollingIfPreferred();
// Let other UI update appearance
if (p)
p->GetRulerPanel()->HideQuickPlayIndicator();
@ -745,25 +749,17 @@ void ControlToolBar::OnKeyEvent(wxKeyEvent & event)
void ControlToolBar::OnPlay(wxCommandEvent & WXUNUSED(evt))
{
auto doubleClicked = mPlay->IsDoubleClicked();
mPlay->ClearDoubleClicked();
auto p = GetActiveProject();
if (doubleClicked)
p->GetPlaybackScroller().Activate
(AudacityProject::PlaybackScroller::Mode::Centered);
else {
if (!CanStopAudioStream())
return;
if (!CanStopAudioStream())
return;
StopPlaying();
StopPlaying();
if (p) p->TP_DisplaySelection();
if (p) p->TP_DisplaySelection();
PlayDefault();
UpdateStatusBar(p);
}
PlayDefault();
UpdateStatusBar(p);
}
void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt))
@ -792,11 +788,11 @@ void ControlToolBar::PlayDefault()
void ControlToolBar::StopPlaying(bool stopStream /* = true*/)
{
StopScrolling();
AudacityProject *project = GetActiveProject();
if(project) {
project->GetPlaybackScroller().Activate
(AudacityProject::PlaybackScroller::Mode::Off);
// Let scrubbing code do some appearance change
project->GetScrubber().StopScrubbing();
}
@ -853,29 +849,6 @@ void ControlToolBar::Pause()
void ControlToolBar::OnRecord(wxCommandEvent &evt)
{
auto doubleClicked = mRecord->IsDoubleClicked();
mRecord->ClearDoubleClicked();
if (doubleClicked) {
// Display a fixed recording head while scrolling the waves continuously.
// If you overdub, you may want to anticipate some context in existing tracks,
// so center the head. If not, put it rightmost to display as much wave as we can.
const auto project = GetActiveProject();
bool duplex;
gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, true);
if (duplex) {
// See if there is really anything being overdubbed
if (gAudioIO->GetNumPlaybackChannels() == 0)
// No.
duplex = false;
}
using Mode = AudacityProject::PlaybackScroller::Mode;
project->GetPlaybackScroller().Activate(duplex ? Mode::Centered : Mode::Right);
return;
}
if (gAudioIO->IsBusy()) {
if (!CanStopAudioStream() || 0 == gAudioIO->GetNumCaptureChannels())
mRecord->PopUp();
@ -1092,6 +1065,8 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
if (success) {
p->SetAudioIOToken(token);
mBusyProject = p;
StartScrollingIfPreferred();
}
else {
if (shifted) {
@ -1278,3 +1253,50 @@ void ControlToolBar::UpdateStatusBar(AudacityProject *pProject)
{
pProject->GetStatusBar()->SetStatusText(StateForStatusBar(), stateStatusBarField);
}
void ControlToolBar::StartScrollingIfPreferred()
{
if (PlaybackPrefs::GetPinnedHeadPreference())
StartScrolling();
else
StopScrolling();
}
void ControlToolBar::StartScrolling()
{
using Mode = AudacityProject::PlaybackScroller::Mode;
const auto project = GetActiveProject();
if (project) {
auto mode = Mode::Centered;
if (gAudioIO->GetNumCaptureChannels() > 0) {
// recording
// Display a fixed recording head while scrolling the waves continuously.
// If you overdub, you may want to anticipate some context in existing tracks,
// so center the head. If not, put it rightmost to display as much wave as we can.
bool duplex;
gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, true);
if (duplex) {
// See if there is really anything being overdubbed
if (gAudioIO->GetNumPlaybackChannels() == 0)
// No.
duplex = false;
}
if (!duplex)
mode = Mode::Right;
}
project->GetPlaybackScroller().Activate(mode);
}
}
void ControlToolBar::StopScrolling()
{
const auto project = GetActiveProject();
if(project)
project->GetPlaybackScroller().Activate
(AudacityProject::PlaybackScroller::Mode::Off);
}

View File

@ -106,6 +106,11 @@ class ControlToolBar final : public ToolBar {
int WidthForStatusBar(wxStatusBar* const);
void UpdateStatusBar(AudacityProject *pProject);
// Starting and stopping of scrolling display
void StartScrollingIfPreferred();
void StartScrolling();
void StopScrolling();
private:
AButton *MakeButton(teBmps eEnabledUp, teBmps eEnabledDown, teBmps eDisabled,

View File

@ -476,23 +476,11 @@ void TranscriptionToolBar::OnPlaySpeed(wxCommandEvent & WXUNUSED(event))
{
auto button = mButtons[TTB_PlaySpeed];
auto doubleClicked = button->IsDoubleClicked();
button->ClearDoubleClicked();
if (doubleClicked) {
GetActiveProject()->GetPlaybackScroller().Activate
(AudacityProject::PlaybackScroller::Mode::Centered);
// Pop up the button
SetButton(false, button);
}
else {
// Let control have precedence over shift
const bool cutPreview = mButtons[TTB_PlaySpeed]->WasControlDown();
const bool looped = !cutPreview &&
button->WasShiftDown();
PlayAtSpeed(looped, cutPreview);
}
// Let control have precedence over shift
const bool cutPreview = mButtons[TTB_PlaySpeed]->WasControlDown();
const bool looped = !cutPreview &&
button->WasShiftDown();
PlayAtSpeed(looped, cutPreview);
}
void TranscriptionToolBar::OnSpeedSlider(wxCommandEvent& WXUNUSED(event))

View File

@ -508,8 +508,6 @@ void Scrubber::StopScrubbing()
UncheckAllMenuItems();
mScrubStartPosition = -1;
mProject->GetPlaybackScroller().Activate
(AudacityProject::PlaybackScroller::Mode::Off);
mDragging = false;
if (!IsScrubbing())
@ -784,20 +782,21 @@ bool Scrubber::PollIsSeeking()
void Scrubber::ActivateScroller()
{
using Mode = AudacityProject::PlaybackScroller::Mode;
mProject->GetPlaybackScroller().Activate(mSmoothScrollingScrub
? Mode::Centered
:
const auto ctb = mProject->GetControlToolBar();
if (mSmoothScrollingScrub)
ctb->StartScrolling();
else {
#ifdef __WXMAC__
// PRL: cause many "unnecessary" refreshes. For reasons I don't understand,
// doing this causes wheel rotation events (mapped from the double finger vertical
// swipe) to be delivered more uniformly to the application, so that spped control
// works better.
Mode::Refresh
// PRL: cause many "unnecessary" refreshes. For reasons I don't understand,
// doing this causes wheel rotation events (mapped from the double finger vertical
// swipe) to be delivered more uniformly to the application, so that speed control
// works better.
mProject->GetPlaybackScroller().Activate
(AudacityProject::PlaybackScroller::Mode::Refresh);
#else
Mode::Off
ctb->StopScrolling();
#endif
);
}
}
void Scrubber::DoScrub(bool scroll, bool seek)

View File

@ -66,6 +66,7 @@ array of Ruler::Label.
#include <wx/menuitem.h>
#include <wx/tooltip.h>
#include "AButton.h"
#include "../AColor.h"
#include "../AudioIO.h"
#include "../Internat.h"
@ -82,10 +83,10 @@ array of Ruler::Label.
#include "../Prefs.h"
#include "../Snap.h"
#include "../tracks/ui/Scrubbing.h"
#include "../prefs/PlaybackPrefs.h"
#include "../prefs/TracksPrefs.h"
//#define SCRUB_ABOVE
#define RULER_DOUBLE_CLICK
using std::min;
using std::max;
@ -1916,6 +1917,8 @@ enum {
OnAutoScrollID,
OnLockPlayRegionID,
OnTogglePinnedStateID,
OnShowHideScrubbingID,
};
@ -1938,6 +1941,10 @@ BEGIN_EVENT_TABLE(AdornedRulerPanel, OverlayPanel)
// Pop up menus on Windows
EVT_CONTEXT_MENU(AdornedRulerPanel::OnContextMenu)
EVT_COMMAND( OnTogglePinnedStateID,
wxEVT_COMMAND_BUTTON_CLICKED,
AdornedRulerPanel::OnTogglePinnedState )
END_EVENT_TABLE()
AdornedRulerPanel::AdornedRulerPanel(AudacityProject* parent,
@ -2034,6 +2041,9 @@ namespace {
void AdornedRulerPanel::UpdatePrefs()
{
// Update button texts for language change
UpdateButtonStates();
#ifdef EXPERIMENTAL_SCROLLING_LIMITS
#ifdef EXPERIMENTAL_TWO_TONE_TIME_RULER
{
@ -2052,8 +2062,56 @@ void AdornedRulerPanel::UpdatePrefs()
RegenerateTooltips(mPrevZone);
}
namespace
{
wxString ComposeButtonLabel
(AudacityProject &project, const wxString &commandName, const wxString &label)
{
auto pCmdMgr = project.GetCommandManager();
const auto &keyString = pCmdMgr->GetKeyFromName(commandName);
return keyString.empty()
? label
: label + wxT(" (") + keyString + wxT(")");
}
}
void AdornedRulerPanel::ReCreateButtons()
{
for (auto & button : mButtons) {
if (button)
button->Destroy();
button = nullptr;
}
// Make the short row of time ruler pushbottons.
// Don't bother with sizers. Their sizes and positions are fixed.
wxPoint position{ FocusBorderLeft, FocusBorderTop };
size_t iButton = 0;
const auto size = theTheme.ImageSize( bmpRecoloredUpSmall );
auto buttonMaker = [&]
(wxWindowID id, teBmps bitmap, bool toggle)
{
const auto button =
ToolBar::MakeButton(
this,
bmpRecoloredUpSmall, bmpRecoloredDownSmall, bmpRecoloredHiliteSmall,
bitmap, bitmap, bitmap,
id, position, toggle, size
);
position.x += size.GetWidth();
mButtons[iButton++] = button;
return button;
};
auto button = buttonMaker(OnTogglePinnedStateID, bmpPinnedPlayRecordHead, false);
ToolBar::MakeAlternateImages(
*button, 1,
bmpRecoloredUpSmall, bmpRecoloredDownSmall, bmpRecoloredHiliteSmall,
bmpUnpinnedPlayRecordHead, bmpUnpinnedPlayRecordHead, bmpUnpinnedPlayRecordHead,
size);
UpdateButtonStates();
}
void AdornedRulerPanel::InvalidateRuler()
@ -2116,6 +2174,14 @@ void AdornedRulerPanel::OnCapture(wxCommandEvent & evt)
void AdornedRulerPanel::OnPaint(wxPaintEvent & WXUNUSED(evt))
{
if (mNeedButtonUpdate) {
// Visit this block once only in the lifetime of this panel
mNeedButtonUpdate = false;
// Do this first time setting of button status texts
// when we are sure the CommandManager is initialized.
UpdateButtonStates();
}
wxPaintDC dc(this);
auto &backDC = GetBackingDCForRepaint();
@ -2378,15 +2444,7 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
}
}
#ifdef RULER_DOUBLE_CLICK
if (evt.LeftDClick()) {
mDoubleClick = true;
HandleQPDoubleClick(evt, mousePosX);
}
else
#endif
if (evt.LeftDown()) {
mDoubleClick = false;
HandleQPClick(evt, mousePosX);
HandleQPDrag(evt, mousePosX);
ShowQuickPlayIndicator();
@ -2402,12 +2460,6 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
}
}
void AdornedRulerPanel::HandleQPDoubleClick(wxMouseEvent &evt, wxCoord mousePosX)
{
mProject->GetPlaybackScroller().Activate
(AudacityProject::PlaybackScroller::Mode::Centered);
}
void AdornedRulerPanel::HandleQPClick(wxMouseEvent &evt, wxCoord mousePosX)
{
// Temporarily unlock locked play region
@ -2541,9 +2593,6 @@ void AdornedRulerPanel::HandleQPDrag(wxMouseEvent &event, wxCoord mousePosX)
void AdornedRulerPanel::HandleQPRelease(wxMouseEvent &evt)
{
if (mDoubleClick)
return;
if (HasCapture())
ReleaseMouse();
else
@ -2716,6 +2765,28 @@ void AdornedRulerPanel::OnContextMenu(wxContextMenuEvent & WXUNUSED(event))
ShowContextMenu(MenuChoice::QuickPlay, nullptr);
}
void AdornedRulerPanel::UpdateButtonStates()
{
bool state = PlaybackPrefs::GetPinnedHeadPreference();
auto pinButton = static_cast<AButton*>(FindWindow(OnTogglePinnedStateID));
pinButton->PopUp();
pinButton->SetAlternateIdx(state ? 0 : 1);
const auto label = state
// Label descibes the present state, not what the click does
// (which is, to toggle the state)
? _("Pinned play/record Head")
: _("Unpinned play/record Head");
const auto &fullLabel = ComposeButtonLabel(*mProject, _("PinnedHead"), label);
pinButton->SetLabel(fullLabel);
pinButton->SetToolTip(fullLabel);
}
void AdornedRulerPanel::OnTogglePinnedState(wxCommandEvent & event)
{
mProject->OnTogglePinnedHead();
UpdateButtonStates();
}
void AdornedRulerPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(evt))
{
HideQuickPlayIndicator();

View File

@ -336,7 +336,6 @@ private:
void OnSize(wxSizeEvent &evt);
void UpdateRects();
void OnMouseEvents(wxMouseEvent &evt);
void HandleQPDoubleClick(wxMouseEvent &event, wxCoord mousePosX);
void HandleQPClick(wxMouseEvent &event, wxCoord mousePosX);
void HandleQPDrag(wxMouseEvent &event, wxCoord mousePosX);
void HandleQPRelease(wxMouseEvent &event);
@ -350,8 +349,10 @@ private:
void DoDrawEdge(wxDC *dc);
void DoDrawMarks(wxDC * dc, bool /*text */ );
void DoDrawSelection(wxDC * dc);
public:
void DoDrawIndicator(wxDC * dc, wxCoord xx, bool playing, int width, bool scrub);
void UpdateButtonStates();
private:
QuickPlayIndicatorOverlay *GetOverlay();
@ -416,6 +417,8 @@ private:
void OnContextMenu(wxContextMenuEvent & WXUNUSED(event));
void OnTogglePinnedState(wxCommandEvent & event);
bool mPlayRegionDragsSelection;
bool mTimelineToolTip;
bool mQuickPlayEnabled;
@ -439,11 +442,12 @@ private:
bool mShowScrubbing { true };
bool mDoubleClick {};
DECLARE_EVENT_TABLE()
friend QuickPlayRulerOverlay;
wxWindow *mButtons[1] { {} };
bool mNeedButtonUpdate { true };
};
#endif //define __AUDACITY_RULER__