1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-09-23 23:41:21 +02:00

Merge branch 'master' into sampleCount

This commit is contained in:
Paul Licameli 2016-09-04 16:09:24 -04:00
commit 1fdbccbcc5
6 changed files with 160 additions and 68 deletions

View File

@ -117,6 +117,7 @@ void AboutDialog::CreateCreditsList()
AddCredit(wxString(wxT("Mike Underwood, ")) + _("developer"), roleContributor);
AddCredit(wxString(wxT("Philip Van Baren, ")) + _("developer"), roleContributor);
AddCredit(wxString(wxT("Salvo Ventura, ")) + _("developer"), roleContributor);
AddCredit(wxString(wxT("Darrell Walisser, ")) + _("developer"), roleContributor);
AddCredit(wxString(wxT("Jun Wan, ")) + _("developer"), roleContributor);
AddCredit(wxString(wxT("Daniel Winzen, ")) + _("developer"), roleContributor);
AddCredit(wxString(wxT("Tom Woodhams, ")) + _("developer"), roleContributor);

View File

@ -1590,7 +1590,14 @@ bool AudacityApp::IsTempDirectoryNameOK( const wxString & Name ){
// use Long Path to expand out any abbreviated long substrings.
wxString BadPath = tmpFile.GetLongPath();
::wxRemoveFile(tmpFile.GetFullPath());
#ifdef __WXMAC__
// This test is to fix bug 1220 on a 1.x to 2.x to 2.1.3 upgrade.
// It is less permissive than we could be as it stops a path
// with this string ANYWHERE within it rather than excluding just
// the paths that the earlier Audacities used to create.
if( Name.Contains( "/tmp/") )
return false;
BadPath = BadPath.BeforeLast( '/' ) + "/";
wxFileName cmpFile( Name );
wxString NameCanonical = cmpFile.GetLongPath( ) + "/";

View File

@ -636,16 +636,21 @@ void GetDefaultWindowRect(wxRect *defRect)
}
}
// true iff we have enough of the top bar to be able to reposition the window.
bool IsWindowAccessible(wxRect *requestedRect)
{
wxDisplay display;
wxRect targetTitleRect(requestedRect->GetLeftTop(), requestedRect->GetBottomRight());
// Hackery to approximate a window top bar size from a window size.
// and exclude the open/close and borders.
targetTitleRect.x += 15;
targetTitleRect.width -= 100;
if (targetTitleRect.width < 165) targetTitleRect.width = 165;
targetTitleRect.height = 15;
int targetBottom = targetTitleRect.GetBottom();
int targetRight = targetTitleRect.GetRight();
// This looks like overkill to check each and every pixel in the ranges.
// and decide that if any is visible on screen we are OK.
for (int i = targetTitleRect.GetLeft(); i < targetRight; i++) {
for (int j = targetTitleRect.GetTop(); j < targetBottom; j++) {
int monitor = display.GetFromPoint(wxPoint(i, j));
@ -657,6 +662,18 @@ bool IsWindowAccessible(wxRect *requestedRect)
return FALSE;
}
// Returns the screen containing a rectangle, or -1 if none does.
int ScreenContaining( wxRect & r ){
unsigned int n = wxDisplay::GetCount();
for(unsigned int i = 0;i<n;i++){
wxDisplay d(i);
wxRect scr = d.GetClientArea();
if( scr.Contains( r ) )
return (int)i;
}
return -1;
}
// BG: Calculate where to place the next window (could be the first window)
// BG: Does not store X and Y in prefs. This is intentional.
//
@ -692,9 +709,10 @@ void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
windowRect = defaultRect;
}
wxRect screenRect = wxGetClientDisplayRect();
wxRect screenRect( wxGetClientDisplayRect());
#if defined(__WXMAC__)
// On OSX, the top of the window should never be less than the menu height,
// so something is amiss if it is
if (normalRect.y < screenRect.y) {
@ -705,16 +723,16 @@ void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
}
#endif
// Make sure initial sizes fit within the display bounds
// We don't mind being 32 pixels off the screen in any direction.
// Make sure initial sizes (pretty much) fit within the display bounds
// We used to trim the sizes which could result in ridiculously small windows.
// contributing to bug 1243.
// Now instead if the window doesn't fit the screen, we use the default
// Now instead if the window significantly doesn't fit the screen, we use the default
// window instead, which we know does.
if (!screenRect.Contains( normalRect )) {
if (ScreenContaining( wxRect(normalRect).Deflate( 32, 32 ))<0) {
normalRect = defaultRect;
}
if (!screenRect.Contains( windowRect )) {
if (ScreenContaining( wxRect(windowRect).Deflate( 32, 32 ) )<0) {
windowRect = defaultRect;
}
@ -754,10 +772,29 @@ void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
nextRect->y += inc;
}
// defaultrect is a rectangle on the first screen. It's the right fallback to
// use most of the time if things are not working out right with sizing.
// windowRect is a saved rectangle size.
// normalRect seems to be a substitute for windowRect when iconized or maximised.
//Have we hit the right side of the screen?
// Windows can say that we are off screen when actually we are not.
// On Windows 10 I am seeing miscalculation by about 6 pixels.
// To fix this we allow some sloppiness on the edge being counted as off screen.
// This matters most when restoring very carefully sized windows that are maximised
// in one dimension (height or width) but not both.
const int edgeSlop = 10;
// Next four lines are getting the rectangle for the screen that contains the
// top left corner of nextRect (and defaulting to rect of screen 0 otherwise).
wxPoint p = nextRect->GetLeftTop();
int scr = std::max( 0, wxDisplay::GetFromPoint( p ));
wxDisplay d( scr );
screenRect = d.GetClientArea();
// Now we (possibly) start trimming our rectangle down.
// Have we hit the right side of the screen?
wxPoint bottomRight = nextRect->GetBottomRight();
if (bottomRight.x > screenRect.GetRight()) {
if (bottomRight.x > (screenRect.GetRight()+edgeSlop)) {
int newWidth = screenRect.GetWidth() - nextRect->GetLeft();
if (newWidth < defaultRect.GetWidth()) {
nextRect->x = windowRect.x;
@ -769,16 +806,19 @@ void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
}
}
//Have we hit the bottom of the screen?
// Have we hit the bottom of the screen?
bottomRight = nextRect->GetBottomRight();
if (bottomRight.y > screenRect.GetBottom()) {
if (bottomRight.y > (screenRect.GetBottom()+edgeSlop)) {
nextRect->y -= inc;
bottomRight = nextRect->GetBottomRight();
if (bottomRight.y > screenRect.GetBottom()) {
if (bottomRight.y > (screenRect.GetBottom()+edgeSlop)) {
nextRect->SetBottom(screenRect.GetBottom());
}
}
// After all that we could have a window that does not have a visible
// top bar. [It is unlikely, but something might have gone wrong]
// If so, use the safe fallback size.
if (!IsWindowAccessible(nextRect)) {
*nextRect = defaultRect;
}

View File

@ -1167,8 +1167,12 @@ void TrackPanel::HandleInterruptedDrag()
WasOverCutLine,
IsStretching
*/
// The bogus id isn't used anywhere, but may help with debugging.
// as this is sending a bogus mouse up. The mouse button is still actually down
// and may go up again.
const int idBogusUp = 2;
wxMouseEvent evt { wxEVT_LEFT_UP };
evt.SetId( idBogusUp );
evt.SetPosition(this->ScreenToClient(::wxGetMousePosition()));
this->ProcessEvent(evt);
}
@ -1888,6 +1892,44 @@ void TrackPanel::SelectRangeOfTracks(Track *sTrack, Track *eTrack)
}
}
void TrackPanel::ChangeSelectionOnShiftClick(Track * pTrack){
// Optional: Track already selected? Nothing to do.
// If we enable this, Shift-Click behaves like click in this case.
//if( pTrack->GetSelected() )
// return;
// Find first and last selected track.
Track* pFirst = nullptr;
Track* pLast = nullptr;
// We will either extend from the first or from the last.
Track* pExtendFrom= nullptr;
TrackListIterator iter(GetTracks());
for (Track *t = iter.First(); t; t = iter.Next()) {
const bool isSelected = t->GetSelected();
// If our track is after the first, extend from the first.
if( t == pTrack ){
pExtendFrom = pFirst;
}
// Record first and last selected.
if( isSelected ){
if( !pFirst )
pFirst = t;
pLast = t;
}
}
// Our track was the first or earlier. Extend from the last.
if( !pExtendFrom )
pExtendFrom = pLast;
SelectNone();
if( pExtendFrom )
SelectRangeOfTracks(pTrack, pExtendFrom);
else
SelectTrack( pTrack, true );
}
/// This method gets called when we're handling selection
/// and the mouse was just clicked.
void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
@ -1923,17 +1965,24 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
bool stretch = HitTestStretch(pTrack, rect, event);
#endif
if (event.ShiftDown()
bool bShiftDown = event.ShiftDown();
bool bCtrlDown = event.ControlDown();
if (bShiftDown || bCtrlDown
#ifdef USE_MIDI
&& !stretch
#endif
) {
SelectNone();
if (mLastPickedTrack && event.ShiftDown())
SelectRangeOfTracks(pTrack, mLastPickedTrack);
else
SelectTrack(pTrack, true);
if( bShiftDown )
ChangeSelectionOnShiftClick( pTrack );
if( bCtrlDown ){
//bool bIsSelected = pTrack->GetSelected();
bool bIsSelected = false;
// could set bIsSelected true here, but toggling is more technically correct.
// if we want to match behaviour in Track Control Panel.
SelectTrack( pTrack, !bIsSelected, false );
}
double value;
// Shift-click, choose closest boundary
@ -2722,7 +2771,8 @@ void TrackPanel::SelectionHandleDrag(wxMouseEvent & event, Track *clickedTrack)
if (event.CmdDown()) {
// Ctrl-drag has no meaning, fuhggeddaboudit
return;
// JKC YES it has meaning.
//return;
}
wxRect rect = mCapturedRect;
@ -3022,7 +3072,10 @@ void TrackPanel::HandleEnvelope(wxMouseEvent & event)
if (mCapturedTrack)
ForwardEventToEnvelope(event);
if (event.LeftUp()) {
// We test for IsEnveloping, because we could have had our action stopped already,
// and already recorded and the second mouse up is bogus.
// e.g could be stopped by some key press. Bug 1496.
if ((mMouseCapture == IsEnveloping ) && event.LeftUp()) {
SetCapturedTrack( NULL );
MakeParentPushState(
/* i18n-hint: (verb) Audacity has just adjusted the envelope .*/
@ -4977,7 +5030,7 @@ void TrackPanel::HandleListSelection(Track *t, bool shift, bool ctrl,
}
else {
if (shift && mLastPickedTrack)
SelectRangeOfTracks(t, mLastPickedTrack);
ChangeSelectionOnShiftClick( t );
else{
SelectNone();
SelectTrack(t, true);
@ -6207,8 +6260,8 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &rect,
bool bShift = event.ShiftDown();
bool bCtrlDown = event.ControlDown();
bool unsafe = IsUnsafe();
if( bShift || bCtrlDown ){
bCtrlDown = false;
if( /*bShift ||*/ bCtrlDown ){
HandleListSelection(track, bShift, bCtrlDown, !unsafe);
return true;
@ -6284,7 +6337,7 @@ bool TrackPanel::HandleLabelTrackClick(LabelTrack * lTrack, wxRect &rect, wxMous
bool bCtrlDown = event.ControlDown();
bool unsafe = IsUnsafe();
if( bShift || bCtrlDown ){
if( /*bShift ||*/ bCtrlDown ){
HandleListSelection(lTrack, bShift, bCtrlDown, !unsafe);
return true;

View File

@ -296,6 +296,7 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
protected:
virtual void ChangeSelectionOnShiftClick(Track * pTrack);
virtual void SelectionHandleClick(wxMouseEvent &event,
Track* pTrack, wxRect rect);
virtual void StartSelection (int mouseXCoordinate, int trackLeftEdge);

View File

@ -43,7 +43,6 @@
#include "Experimental.h"
//#undef _OPENMP
#ifdef _OPENMP
#include <omp.h>
#else
@ -930,8 +929,18 @@ bool SpecCache::CalculateOneSpectrum
int correctedX = (floor(0.5 + xx + timeCorrection * pixelsPerSecond / rate));
if (correctedX >= lowerBoundX && correctedX < upperBoundX)
result = true,
out[half * correctedX + bin] += power;
{
result = true;
int index = half * correctedX + bin;
#ifdef _OPENMP
// This assignment can race if index reaches into another thread's bins.
// The probability of a race very low, so this carries little overhead,
// about 5% slower vs allowing it to race.
#pragma omp atomic update
#endif
out[index] += power;
}
}
}
}
@ -990,29 +999,6 @@ void SpecCache::Populate
if (!autocorrelation)
ComputeSpectrogramGainFactors(fftLen, rate, frequencyGain, gainFactors);
#ifdef _OPENMP
// todo: query # of threads or make it a setting
const int numThreads = 8;
omp_set_num_threads(numThreads);
// We need certain per-thread data for thread safety
// Assumes WaveTrackCache is reentrant since it takes a const* to WaveTrack
struct {
WaveTrackCache* cache;
float* scratch;
} threadLocalStorage[numThreads];
// May as well use existing data for one of the threads
assert(numThreads > 0);
threadLocalStorage[0].cache = &waveTrackCache;
threadLocalStorage[0].scratch = &scratch[0];
for (int i = 1; i < numThreads; i++) {
threadLocalStorage[i].cache = new WaveTrackCache( waveTrackCache.GetTrack() );
threadLocalStorage[i].scratch = new float[scratchSize];
}
#endif
// Loop over the ranges before and after the copied portion and compute anew.
// One of the ranges may be empty.
for (int jj = 0; jj < 2; ++jj) {
@ -1020,24 +1006,36 @@ void SpecCache::Populate
const int upperBoundX = jj == 0 ? copyBegin : numPixels;
#ifdef _OPENMP
#pragma omp parallel for
// Storage for mutable per-thread data.
// private clause ensures one copy per thread
struct ThreadLocalStorage {
ThreadLocalStorage() { cache = nullptr; }
~ThreadLocalStorage() { delete cache; }
void init(WaveTrackCache &waveTrackCache, size_t scratchSize) {
if (!cache) {
cache = new WaveTrackCache(waveTrackCache.GetTrack());
scratch.resize(scratchSize);
}
}
WaveTrackCache* cache;
std::vector<float> scratch;
} tls;
#pragma omp parallel for private(tls)
#endif
for (auto xx = lowerBoundX; xx < upperBoundX; ++xx)
{
#ifdef _OPENMP
int threadNum = omp_get_thread_num();
assert(threadNum >=0 && threadNum < numThreads);
WaveTrackCache* cache = threadLocalStorage[threadNum].cache;
float* buffer = threadLocalStorage[threadNum].scratch;
tls.init(waveTrackCache, scratchSize);
WaveTrackCache& cache = *tls.cache;
float* buffer = &tls.scratch[0];
#else
WaveTrackCache* cache = &waveTrackCache;
WaveTrackCache& cache = waveTrackCache;
float* buffer = &scratch[0];
#endif
CalculateOneSpectrum(
settings, *cache, xx, numSamples,
settings, cache, xx, numSamples,
offset, rate, pixelsPerSecond,
lowerBoundX, upperBoundX,
gainFactors, buffer, &freq[0]);
@ -1098,14 +1096,6 @@ void SpecCache::Populate
}
}
}
#ifdef _OPENMP
for (int i = 1; i < numThreads; i++)
{
delete[] threadLocalStorage[i].scratch;
delete threadLocalStorage[i].cache;
}
#endif
}
bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,