mirror of
https://github.com/cookiengineer/audacity
synced 2025-09-23 15:41:09 +02:00
Merge branch 'master' into sampleCount
This commit is contained in:
commit
1fdbccbcc5
@ -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);
|
||||
|
@ -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( ) + "/";
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user