From 9842d0742f95dafc9949c775506d2f96c4ac3256 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 19 Mar 2017 10:42:23 -0400 Subject: [PATCH 01/91] Fix compilation of EXPERIMENTAL_EFFECTS_RACK --- src/Experimental.h | 2 +- src/effects/EffectRack.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Experimental.h b/src/Experimental.h index 364ee066a..b8fc187fd 100644 --- a/src/Experimental.h +++ b/src/Experimental.h @@ -148,7 +148,7 @@ #define EXPERIMENTAL_REALTIME_AUDACITY_EFFECTS // Define to include the effects rack (such as it is). -//#define EXPERIMENTAL_EFFECTS_RACK +#define EXPERIMENTAL_EFFECTS_RACK // Define to make the meters look like a row of LEDs //#define EXPERIMENTAL_METER_LED_STYLE diff --git a/src/effects/EffectRack.cpp b/src/effects/EffectRack.cpp index 76b7bdf8d..20e0c3602 100644 --- a/src/effects/EffectRack.cpp +++ b/src/effects/EffectRack.cpp @@ -289,7 +289,7 @@ void EffectRack::OnTimer(wxTimerEvent & WXUNUSED(evt)) void EffectRack::OnApply(wxCommandEvent & WXUNUSED(evt)) { AudacityProject *project = GetActiveProject(); - + for (size_t i = 0, cnt = mEffects.size(); i < cnt; i++) { if (mPowerState[i]) From d38dde213eb61d2cd207eb5d4db6ba7ec007a0c3 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 19 Mar 2017 10:51:00 -0400 Subject: [PATCH 02/91] Revert "Fix compilation of EXPERIMENTAL_EFFECTS_RACK" This reverts commit 9842d0742f95dafc9949c775506d2f96c4ac3256. --- src/Experimental.h | 2 +- src/effects/EffectRack.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Experimental.h b/src/Experimental.h index b8fc187fd..364ee066a 100644 --- a/src/Experimental.h +++ b/src/Experimental.h @@ -148,7 +148,7 @@ #define EXPERIMENTAL_REALTIME_AUDACITY_EFFECTS // Define to include the effects rack (such as it is). -#define EXPERIMENTAL_EFFECTS_RACK +//#define EXPERIMENTAL_EFFECTS_RACK // Define to make the meters look like a row of LEDs //#define EXPERIMENTAL_METER_LED_STYLE diff --git a/src/effects/EffectRack.cpp b/src/effects/EffectRack.cpp index 20e0c3602..76b7bdf8d 100644 --- a/src/effects/EffectRack.cpp +++ b/src/effects/EffectRack.cpp @@ -289,7 +289,7 @@ void EffectRack::OnTimer(wxTimerEvent & WXUNUSED(evt)) void EffectRack::OnApply(wxCommandEvent & WXUNUSED(evt)) { AudacityProject *project = GetActiveProject(); - + for (size_t i = 0, cnt = mEffects.size(); i < cnt; i++) { if (mPowerState[i]) From 148fc40b784429e553ef3cd23e9a60ed968acba2 Mon Sep 17 00:00:00 2001 From: James Crook Date: Sun, 19 Mar 2017 18:46:44 +0000 Subject: [PATCH 03/91] Restore menu items removed for DarkAudacity. I'm not sure how useful they are, but Audacity may want them still. Changed 'Store' to 'Save' to avoid confusion with 'Restore'. --- src/Menus.cpp | 52 +++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index ffa420543..fbe1a63e3 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -588,7 +588,7 @@ void AudacityProject::CreateMenusAndCommands() c->AddItem(wxT("SelStartCursor"), _("Track &Start to Cursor"), FN(OnSelectStartCursor), wxT("Shift+J")); c->AddItem(wxT("SelCursorEnd"), _("Cursor to Track &End"), FN(OnSelectCursorEnd), wxT("Shift+K")); - c->AddItem(wxT("SelCursorStoredCursor"), _("Cursor to Stored &Cursor Position"), FN(OnSelectCursorStoredCursor), + c->AddItem(wxT("SelCursorStoredCursor"), _("Cursor to Saved &Cursor Position"), FN(OnSelectCursorStoredCursor), wxT(""), TracksExistFlag, TracksExistFlag); @@ -612,6 +612,15 @@ void AudacityProject::CreateMenusAndCommands() c->AddSeparator(); c->AddItem(wxT("ZeroCross"), _("Ends to &Zero Crossings"), FN(OnZeroCrossing), wxT("Z")); c->AddSeparator(); + +#ifndef EXPERIMENTAL_DA + c->AddItem(wxT("StoreCursorPosition"), _("Save Cursor Pos&ition"), FN(OnCursorPositionStore), + WaveTracksExistFlag, + WaveTracksExistFlag); + // Save cursor position is used in some selctions. + // Maybe there should be a restore for it? +#endif + // Audacity has 'Store Re&gion' here. c->AddItem(wxT("SelSave"), _("Save Sele&ction"), FN(OnSelectionSave), WaveTracksSelectedFlag, @@ -621,10 +630,6 @@ void AudacityProject::CreateMenusAndCommands() TracksExistFlag, TracksExistFlag); c->EndSubMenu(); - //Present in Audacity... - //c->AddItem(wxT("StoreCursorPosition"), _("Store Cursor Pos&ition"), FN(OnCursorPositionStore), - // WaveTracksExistFlag, - // WaveTracksExistFlag); ///////////////////////////////////////////////////////////////////////////// @@ -802,6 +807,19 @@ void AudacityProject::CreateMenusAndCommands() WaveTracksExistFlag | AudioIONotBusyFlag); c->EndSubMenu(); +#ifndef EXPERIMENTAL_DA + // JKC: ANSWER-ME: How is this different to 'Skip To' and how is it useful? + c->BeginSubMenu(_("Cursor to")); + + c->AddItem(wxT("CursSelStart"), _("Selection Star&t"), FN(OnCursorSelStart)); + c->AddItem(wxT("CursSelEnd"), _("Selection En&d"), FN(OnCursorSelEnd)); + + c->AddItem(wxT("CursTrackStart"), _("Track &Start"), FN(OnCursorTrackStart), wxT("J")); + c->AddItem(wxT("CursTrackEnd"), _("Track &End"), FN(OnCursorTrackEnd), wxT("K")); + + c->EndSubMenu(); +#endif + c->AddSeparator(); ///////////////////////////////////////////////////////////////////////////// @@ -819,22 +837,6 @@ void AudacityProject::CreateMenusAndCommands() c->AddSeparator(); -#if 0 - // Taken from the edit menu, where it did not belong. - ///////////////////////////////////////////////////////////////////////////// - - c->BeginSubMenu(_("Skip to")); - - c->AddItem(wxT("CursSelStart"), _("Selection Star&t"), FN(OnCursorSelStart)); - c->AddItem(wxT("CursSelEnd"), _("Selection En&d"), FN(OnCursorSelEnd)); - - c->AddItem(wxT("CursTrackStart"), _("Track &Start"), FN(OnCursorTrackStart), wxT("J")); - c->AddItem(wxT("CursTrackEnd"), _("Track &End"), FN(OnCursorTrackEnd), wxT("K")); - - c->EndSubMenu(); -#endif - - c->BeginSubMenu(_("Transport Options")); c->AddCheck(wxT("PinnedHead"), _("Pinned Play/Record &Head (on/off)"), FN(OnTogglePinnedHead), 0, @@ -969,7 +971,11 @@ void AudacityProject::CreateMenusAndCommands() c->AddSeparator(); #ifdef EXPERIMENTAL_SYNC_LOCK +#ifdef EXPERIMENTAL_DA c->AddCheck(wxT("SyncLock"), _("Time-&Lock Tracks (on/off)"), FN(OnSyncLock), 0, +#else + c->AddCheck(wxT("SyncLock"), _("Sync-&Lock Tracks (on/off)"), FN(OnSyncLock), 0, +#endif AlwaysEnabledFlag, AlwaysEnabledFlag); c->AddSeparator(); @@ -1154,7 +1160,9 @@ void AudacityProject::CreateMenusAndCommands() c->AddSeparator(); #endif - //c->AddItem(wxT("Updates"), _("&Check for Updates..."), FN(OnCheckForUpdates)); +#ifndef EXPERIMENTAL_DA + c->AddItem(wxT("Updates"), _("&Check for Updates..."), FN(OnCheckForUpdates)); +#endif c->AddItem(wxT("About"), _("&About Audacity..."), FN(OnAbout)); c->EndMenu(); From 8f71aa67dfaf2bdc0455a1e2898782dc1ae927d2 Mon Sep 17 00:00:00 2001 From: James Crook Date: Sun, 19 Mar 2017 19:28:14 +0000 Subject: [PATCH 04/91] Allow same command more than once in the menus. Pause appears in both Record and Play, and we want the P shortcut to work. --- src/Menus.cpp | 7 +++---- src/commands/CommandManager.cpp | 10 +++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index fbe1a63e3..6661a315b 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -786,10 +786,9 @@ void AudacityProject::CreateMenusAndCommands() c->AddItem(wxT("Record"), _("&Record"), FN(OnRecord), wxT("R")); c->AddItem(wxT("TimerRecord"), _("&Timer Record..."), FN(OnTimerRecord), wxT("Shift+T")); c->AddItem(wxT("RecordBelow"), _("Record Below"), FN(OnRecordBelow), wxT("Shift+R")); - // I decided to duplicate this between play and record, rather than put it at the top level. - // However I must not set the short cut here, as setting it twice disables it! - // TODO: find a way that it is OK to have the same shortcut for a repeated function. - c->AddItem(wxT("Pause"), _("&Pause"), FN(OnPause));//, wxT("P")); + // JKC: I decided to duplicate this between play and record, rather than put it + // at the top level. AddItem can now cope with simple duplicated items. + c->AddItem(wxT("Pause"), _("&Pause"), FN(OnPause), wxT("P")); c->EndSubMenu(); // Scrubbing sub-menu diff --git a/src/commands/CommandManager.cpp b/src/commands/CommandManager.cpp index 902cc7fb3..152b18dc7 100644 --- a/src/commands/CommandManager.cpp +++ b/src/commands/CommandManager.cpp @@ -848,6 +848,14 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & name, int index, int count) { + // If we have the identifier already, reuse it. + CommandListEntry *prev = mCommandNameHash[name]; + if (!prev); + else if( prev->label != label ); + else if( multi ); + else + return prev; + { // Make a unique_ptr or shared_ptr as appropriate: auto entry = make_movable(); @@ -918,7 +926,7 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & name, mCommandIDHash[entry->id] = entry; #if defined(__WXDEBUG__) - CommandListEntry *prev = mCommandNameHash[entry->name]; + prev = mCommandNameHash[entry->name]; if (prev) { // Under Linux it looks as if we may ask for a newID for the same command // more than once. So it's only an error if two different commands From 5b9ae95930c53e9a52eff5275b7f1a236df599cc Mon Sep 17 00:00:00 2001 From: James Crook Date: Mon, 20 Mar 2017 11:53:39 +0000 Subject: [PATCH 05/91] Bug 1610 - Unable to save projects We were throwing an exception for attempting to delete a file that was not there. --- src/xml/XMLWriter.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/xml/XMLWriter.cpp b/src/xml/XMLWriter.cpp index f4c7cf121..939ba36d9 100644 --- a/src/xml/XMLWriter.cpp +++ b/src/xml/XMLWriter.cpp @@ -321,15 +321,17 @@ void XMLFileWriter::Commit() auto tempPath = GetName(); CloseWithoutEndingTags(); - if (mKeepBackup) { - if (! mBackupFile.Close() || - ! wxRenameFile( mOutputPath, mBackupName ) ) - ThrowException( mBackupName, mCaption ); - } - else { - if ( ! wxRemoveFile( mOutputPath ) ) - ThrowException( mOutputPath, mCaption ); + // JKC: NOT translating error messages. Rationale is that they should + // not be seen, and if they are the untranslated version is more useful to + // developers. + if ( mKeepBackup) { + if (! mBackupFile.Close() || ! wxRenameFile( mOutputPath, mBackupName ) ) + ThrowException( mBackupName, mCaption + " renaming backup"); } + else if (! wxFileExists( mOutputPath ) ); + else if (! wxRemoveFile( mOutputPath ) ) + ThrowException( mOutputPath, mCaption + " removing old version"); + // Now we have vacated the file at the output path and are committed. // But not completely finished with steps of the commit operation. From ec7fe2dfcc62d49dd08ab03ebb385a74118c5934 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Mon, 20 Mar 2017 13:23:59 +0000 Subject: [PATCH 06/91] Fix for bug 613: menu key deselects track. When the menu key is pressed, mouse events are also generated, and one of these was interpreted as a mouse click outside the tracks, which deselected the tracks. A possible fix would have been to make a change in TrackPanel::HandleTrackSpecificMouseEvent() so that only left clicks outside of tracks would deselect tracks. However, I decided that a better fix was to modify TrackPanel::OnMouseEvent to ignore the mouse events generated when the menu key is pressed. This should prevent these mouse events from causing bugs in any new code. --- src/TrackPanel.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 118bbbbd9..ec0bee7b8 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -6075,6 +6075,16 @@ try } #endif + // If a mouse event originates from a keyboard context menu event then + // event.GetPosition() == wxDefaultPosition. wxContextMenu events are handled in + // TrackPanel::OnContextMenu(), and therefore associated mouse events are ignored here. + // Not ignoring them was causing bug 613: the mouse events were interpreted as clicking + // outside the tracks. + if (event.GetPosition() == wxDefaultPosition && (event.RightDown() || event.RightUp())) { + event.Skip(); + return; + } + if (event.m_wheelRotation != 0) HandleWheelRotation(event); From 879579475d2cbd4271aeea20cf5e9a0459d9c1d6 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Mon, 20 Mar 2017 15:06:59 +0000 Subject: [PATCH 07/91] Fix for bug 1611: after select none, temporary in-correctness After select none, the timeline and selection times are temporarily not updated. Fix: AudacityProject::SelectNone refreshes the TrackPanel, so call it after changing the SelectedRegion. --- src/Menus.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 6661a315b..ecb5aae6d 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -5169,8 +5169,8 @@ void AudacityProject::OnSelectAll() void AudacityProject::OnSelectNone() { - this->SelectNone(); mViewInfo.selectedRegion.collapseToT0(); + SelectNone(); ModifyState(false); } From c6b4e2fffeae1676e9f21300bb5682a28b12474b Mon Sep 17 00:00:00 2001 From: James Crook Date: Mon, 20 Mar 2017 17:06:29 +0000 Subject: [PATCH 08/91] Add code to capture menus So far, this only walks the menus, printing out their contents to debug. --- src/Screenshot.cpp | 9 +++++ src/commands/ScreenshotCommand.cpp | 58 ++++++++++++++++++++++++++++++ src/commands/ScreenshotCommand.h | 1 + 3 files changed, 68 insertions(+) diff --git a/src/Screenshot.cpp b/src/Screenshot.cpp index 728d4c55b..7a9ac8e6d 100644 --- a/src/Screenshot.cpp +++ b/src/Screenshot.cpp @@ -70,6 +70,7 @@ class ScreenFrame final : public wxFrame void OnCaptureWindowPlus(wxCommandEvent & event); void OnCaptureFullScreen(wxCommandEvent & event); void OnCaptureToolbars(wxCommandEvent & event); + void OnCaptureMenus(wxCommandEvent & event); void OnCaptureSelectionBar(wxCommandEvent & event); void OnCaptureTools(wxCommandEvent & event); void OnCaptureTransport(wxCommandEvent & event); @@ -178,6 +179,7 @@ enum IdDelayCheckBox, IdCaptureToolbars, + IdCaptureMenus, IdCaptureSelectionBar, IdCaptureTools, IdCaptureTransport, @@ -222,6 +224,7 @@ BEGIN_EVENT_TABLE(ScreenFrame, wxFrame) EVT_BUTTON(IdCaptureFullScreen, ScreenFrame::OnCaptureFullScreen) EVT_BUTTON(IdCaptureToolbars, ScreenFrame::OnCaptureToolbars) + EVT_BUTTON(IdCaptureMenus, ScreenFrame::OnCaptureMenus) EVT_BUTTON(IdCaptureSelectionBar, ScreenFrame::OnCaptureSelectionBar) EVT_BUTTON(IdCaptureTools, ScreenFrame::OnCaptureTools) EVT_BUTTON(IdCaptureTransport, ScreenFrame::OnCaptureTransport) @@ -382,6 +385,7 @@ void ScreenFrame::PopulateOrExchange(ShuttleGui & S) S.StartHorizontalLay(); { S.Id(IdCaptureToolbars).AddButton(_("All Toolbars")); + S.Id(IdCaptureMenus).AddButton(_("All Menus")); S.Id(IdCaptureSelectionBar).AddButton(_("SelectionBar")); S.Id(IdCaptureTools).AddButton(_("Tools")); S.Id(IdCaptureTransport).AddButton(_("Transport")); @@ -603,6 +607,11 @@ void ScreenFrame::OnCaptureToolbars(wxCommandEvent & WXUNUSED(event)) DoCapture(wxT("toolbars")); } +void ScreenFrame::OnCaptureMenus(wxCommandEvent & WXUNUSED(event)) +{ + DoCapture(wxT("menus")); +} + void ScreenFrame::OnCaptureSelectionBar(wxCommandEvent & WXUNUSED(event)) { DoCapture(wxT("selectionbar")); diff --git a/src/commands/ScreenshotCommand.cpp b/src/commands/ScreenshotCommand.cpp index 4064f1d11..56f4d91fa 100644 --- a/src/commands/ScreenshotCommand.cpp +++ b/src/commands/ScreenshotCommand.cpp @@ -266,6 +266,59 @@ void ScreenshotCommand::CaptureDock(wxWindow *win, const wxString &fileName) Capture(fileName, win, x, y, width, height); } +void ExploreMenu( wxMenu * pMenu, int Id, int depth ){ + Id;//compiler food. + if( !pMenu ) + return; + + wxMenuItemList list = pMenu->GetMenuItems(); + size_t lcnt = list.GetCount(); + wxMenuItem * item; + wxString Label; + + for (size_t lndx = 0; lndx < lcnt; lndx++) { + item = list.Item(lndx)->GetData(); + Label = item->GetItemLabelText(); + if( item->IsSeparator() ) + Label = "----"; + wxLogDebug("%2i: %s", depth, Label ); + if (item->IsSubMenu()) { + pMenu = item->GetSubMenu(); + ExploreMenu( pMenu, item->GetId(), depth+1 ); + } + } +} + +void ScreenshotCommand::CaptureMenus(wxMenuBar*pBar, const wxString &fileName) +{ + fileName;//compiler food. + if(!pBar ){ + wxLogDebug("No menus"); + return; + } + + size_t cnt = pBar->GetMenuCount(); + size_t i; + wxString Label; + for(i=0;iGetMenuLabelText( i ); + wxLogDebug( "MenuBar: %s", Label ); + ExploreMenu( pBar->GetMenu( i ), pBar->GetId(), 0 ); + } + +#if 0 + int x = 0, y = 0; + int width, height; + + win->ClientToScreen(&x, &y); + win->GetParent()->ScreenToClient(&x, &y); + win->GetClientSize(&width, &height); + + Capture(fileName, win, x, y, width, height); +#endif +} + wxString ScreenshotCommandType::BuildName() { return wxT("Screenshot"); @@ -279,6 +332,7 @@ void ScreenshotCommandType::BuildSignature(CommandSignature &signature) captureModeValidator->AddOption(wxT("windowplus")); captureModeValidator->AddOption(wxT("fullscreen")); captureModeValidator->AddOption(wxT("toolbars")); + captureModeValidator->AddOption(wxT("menus")); captureModeValidator->AddOption(wxT("selectionbar")); captureModeValidator->AddOption(wxT("tools")); captureModeValidator->AddOption(wxT("transport")); @@ -423,6 +477,10 @@ bool ScreenshotCommand::Apply(CommandExecutionContext context) { CaptureDock(context.GetProject()->GetToolManager()->GetTopDock(), fileName); } + else if (captureMode.IsSameAs(wxT("menus"))) + { + CaptureMenus(context.GetProject()->GetMenuBar(), fileName); + } else if (captureMode.IsSameAs(wxT("selectionbar"))) { CaptureDock(context.GetProject()->GetToolManager()->GetBotDock(), fileName); diff --git a/src/commands/ScreenshotCommand.h b/src/commands/ScreenshotCommand.h index 4a7e06926..9a0cac50a 100644 --- a/src/commands/ScreenshotCommand.h +++ b/src/commands/ScreenshotCommand.h @@ -49,6 +49,7 @@ private: bool bg = false); void CaptureToolbar(ToolManager *man, int type, const wxString &name); void CaptureDock(wxWindow *win, const wxString &fileName); + void CaptureMenus(wxMenuBar*pBar, const wxString &fileName); public: wxTopLevelWindow *GetFrontWindow(AudacityProject *project); From 7b7ad75a49518dbe814c87392184e29be431402a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 20 Mar 2017 12:45:06 -0400 Subject: [PATCH 09/91] Remove Sequence::CopyWrite and needless file reads in Sequence::Set --- src/Sequence.cpp | 83 +++++++++++++++++++++++------------------------- src/Sequence.h | 4 --- 2 files changed, 39 insertions(+), 48 deletions(-) diff --git a/src/Sequence.cpp b/src/Sequence.cpp index b19601c45..5be77ac49 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -1134,29 +1134,6 @@ bool Sequence::Read(samplePtr buffer, sampleFormat format, return true; } -bool Sequence::CopyWrite(SampleBuffer &scratch, - samplePtr buffer, SeqBlock &b, - size_t blockRelativeStart, size_t len) -{ - // We don't ever write to an existing block; to support Undo, - // we copy the old block entirely into memory, dereference it, - // make the change, and then write the NEW block to disk. - - const auto length = b.f->GetLength(); - wxASSERT(length <= mMaxSamples); - wxASSERT(blockRelativeStart + len <= length); - - auto sampleSize = SAMPLE_SIZE(mSampleFormat); - - Read(scratch.ptr(), mSampleFormat, b, 0, length); - memcpy(scratch.ptr() + - blockRelativeStart * sampleSize, buffer, len*sampleSize); - - b.f = mDirManager->NewSimpleBlockFile(scratch.ptr(), length, mSampleFormat); - - return true; -} - bool Sequence::Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len) const { @@ -1218,32 +1195,50 @@ bool Sequence::Set(samplePtr buffer, sampleFormat format, const auto fileLength = block.f->GetLength(); const auto blen = limitSampleBufferSize( fileLength - bstart, len ); - if (buffer) { - if (format == mSampleFormat) - CopyWrite(scratch, buffer, block, bstart, blen); - else { - // To do: remove the extra movement. Can we copy-samples within CopyWrite? - CopySamples(buffer, format, temp.ptr(), mSampleFormat, blen); - CopyWrite(scratch, temp.ptr(), block, bstart, blen); + samplePtr useBuffer = buffer; + if (buffer && format != mSampleFormat) + { + // To do: remove the extra movement. + CopySamples(buffer, format, temp.ptr(), mSampleFormat, blen); + useBuffer = temp.ptr(); + } + + // We don't ever write to an existing block; to support Undo, + // we copy the old block entirely into memory, dereference it, + // make the change, and then write the NEW block to disk. + + if (!(fileLength <= mMaxSamples && + bstart + blen <= fileLength)) + //THROW_INCONSISTENCY_EXCEPTION + wxASSERT(false) + ; + + if ( bstart > 0 || blen < fileLength ) { + Read(scratch.ptr(), mSampleFormat, block, 0, fileLength); + + if (useBuffer) { + auto sampleSize = SAMPLE_SIZE(mSampleFormat); + memcpy(scratch.ptr() + + bstart * sampleSize, useBuffer, blen * sampleSize); } - buffer += (blen * SAMPLE_SIZE(format)); + else + ClearSamples(scratch.ptr(), mSampleFormat, bstart, blen); + + block.f = mDirManager->NewSimpleBlockFile( + scratch.ptr(), fileLength, mSampleFormat); } else { - // If it's a full block of silence - if (start == block.start && - blen == fileLength) { - - block.f = make_blockfile(blen); - } - else { - // Odd partial blocks of silence at start or end. - temp.Allocate(blen, format); - ClearSamples(temp.ptr(), format, 0, blen); - // Otherwise write silence just to the portion of the block - CopyWrite(scratch, temp.ptr(), block, bstart, blen); - } + // Avoid reading the disk when the replacement is total + if (useBuffer) + block.f = mDirManager->NewSimpleBlockFile( + useBuffer, fileLength, mSampleFormat); + else + block.f = make_blockfile(fileLength); } + if( buffer ) + buffer += (blen * SAMPLE_SIZE(format)); + len -= blen; start += blen; b++; diff --git a/src/Sequence.h b/src/Sequence.h index 716882739..e97a3303a 100644 --- a/src/Sequence.h +++ b/src/Sequence.h @@ -252,10 +252,6 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{ const SeqBlock &b, size_t blockRelativeStart, size_t len) const; - bool CopyWrite(SampleBuffer &scratch, - samplePtr buffer, SeqBlock &b, - size_t blockRelativeStart, size_t len); - void Blockify(BlockArray &list, sampleCount start, samplePtr buffer, size_t len); bool Get(int b, samplePtr buffer, sampleFormat format, From 2677796b0cda577404553f566009407a4abc6202 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 22 Dec 2016 12:30:07 -0500 Subject: [PATCH 10/91] Zero and return false for all failures to read block file summary... ... Though in the only place where these summaries are used, which is Sequence::GetWaveDisplay, we ignore the correctly reported error code anyway. Also RAII in management of relevant memory buffers and mutexes. --- src/BlockFile.cpp | 108 ++++++++++++++------------ src/BlockFile.h | 4 +- src/Sequence.cpp | 4 + src/blockfile/LegacyBlockFile.cpp | 21 +++-- src/blockfile/LegacyBlockFile.h | 2 +- src/blockfile/ODDecodeBlockFile.cpp | 21 ++--- src/blockfile/ODDecodeBlockFile.h | 2 +- src/blockfile/ODPCMAliasBlockFile.cpp | 45 ++++++----- src/blockfile/ODPCMAliasBlockFile.h | 2 +- src/blockfile/SilentBlockFile.cpp | 5 +- src/blockfile/SilentBlockFile.h | 2 +- src/blockfile/SimpleBlockFile.cpp | 32 ++++---- src/blockfile/SimpleBlockFile.h | 2 +- 13 files changed, 140 insertions(+), 110 deletions(-) diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp index 671eadf62..fcb3f9d2f 100644 --- a/src/BlockFile.cpp +++ b/src/BlockFile.cpp @@ -424,6 +424,8 @@ void BlockFile::GetMinMax(float *outMin, float *outMax, float *outRMS) const /// data provides information about the minimum value, the maximum /// value, and the maximum RMS value for every group of 256 samples in the /// file. +/// Fill with zeroes and return false if data are unavailable for any reason. +/// /// /// @param *buffer The area where the summary information will be /// written. It must be at least len*3 long. @@ -434,54 +436,17 @@ bool BlockFile::Read256(float *buffer, { wxASSERT(start >= 0); - ArrayOf summary{ mSummaryInfo.totalSummaryBytes }; - // FIXME: TRAP_ERR ReadSummary() could return fail. - this->ReadSummary(summary.get()); + ArrayOf< char > summary; + // In case of failure, summary is filled with zeroes + auto result = this->ReadSummary(summary); start = std::min( start, mSummaryInfo.frames256 ); len = std::min( len, mSummaryInfo.frames256 - start ); - CopySamples(summary.get() + mSummaryInfo.offset256 + (start * mSummaryInfo.bytesPerFrame), - mSummaryInfo.format, - (samplePtr)buffer, floatSample, len * mSummaryInfo.fields); - - if (mSummaryInfo.fields == 2) { - // No RMS info - for(auto i = len; i--;) { - buffer[3*i+2] = (fabs(buffer[2*i]) + fabs(buffer[2*i+1]))/4.0; - buffer[3*i+1] = buffer[2*i+1]; - buffer[3*i] = buffer[2*i]; - } - } - - return true; -} - -/// Retrieves a portion of the 64K summary buffer from this BlockFile. This -/// data provides information about the minimum value, the maximum -/// value, and the maximum RMS value for every group of 64K samples in the -/// file. -/// -/// @param *buffer The area where the summary information will be -/// written. It must be at least len*3 long. -/// @param start The offset in 64K-sample increments -/// @param len The number of 64K-sample summary frames to read -bool BlockFile::Read64K(float *buffer, - size_t start, size_t len) -{ - wxASSERT(start >= 0); - - ArrayOf summary{ mSummaryInfo.totalSummaryBytes }; - // FIXME: TRAP_ERR ReadSummary() could return fail. - this->ReadSummary(summary.get()); - - start = std::min( start, mSummaryInfo.frames64K ); - len = std::min( len, mSummaryInfo.frames64K - start ); - - CopySamples(summary.get() + mSummaryInfo.offset64K + + CopySamples(summary.get() + mSummaryInfo.offset256 + (start * mSummaryInfo.bytesPerFrame), mSummaryInfo.format, - (samplePtr)buffer, floatSample, len*mSummaryInfo.fields); + (samplePtr)buffer, floatSample, len * mSummaryInfo.fields); if (mSummaryInfo.fields == 2) { // No RMS info; make guess @@ -492,7 +457,46 @@ bool BlockFile::Read64K(float *buffer, } } - return true; + return result; +} + +/// Retrieves a portion of the 64K summary buffer from this BlockFile. This +/// data provides information about the minimum value, the maximum +/// value, and the maximum RMS value for every group of 64K samples in the +/// file. +/// Fill with zeroes and return false if data are unavailable for any reason. +/// +/// @param *buffer The area where the summary information will be +/// written. It must be at least len*3 long. +/// @param start The offset in 64K-sample increments +/// @param len The number of 64K-sample summary frames to read +bool BlockFile::Read64K(float *buffer, + size_t start, size_t len) +{ + wxASSERT(start >= 0); + + ArrayOf< char > summary; + // In case of failure, summary is filled with zeroes + auto result = this->ReadSummary(summary); + + start = std::min( start, mSummaryInfo.frames64K ); + len = std::min( len, mSummaryInfo.frames64K - start ); + + CopySamples(summary.get() + mSummaryInfo.offset64K + + (start * mSummaryInfo.bytesPerFrame), + mSummaryInfo.format, + (samplePtr)buffer, floatSample, len * mSummaryInfo.fields); + + if (mSummaryInfo.fields == 2) { + // No RMS info; make guess + for(auto i = len; i--;) { + buffer[3*i+2] = (fabs(buffer[2*i]) + fabs(buffer[2*i+1]))/4.0; + buffer[3*i+1] = buffer[2*i+1]; + buffer[3*i] = buffer[2*i]; + } + } + + return result; } size_t BlockFile::CommonReadData( @@ -714,11 +718,13 @@ AliasBlockFile::~AliasBlockFile() /// Read the summary of this alias block from disk. Since the audio data /// is elsewhere, this consists of reading the entire summary file. +/// Fill with zeroes and return false if data are unavailable for any reason. /// /// @param *data The buffer where the summary data will be stored. It must /// be at least mSummaryInfo.totalSummaryBytes long. -bool AliasBlockFile::ReadSummary(void *data) +bool AliasBlockFile::ReadSummary(ArrayOf &data) { + data.reinit( mSummaryInfo.totalSummaryBytes ); wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb")); { @@ -729,24 +735,28 @@ bool AliasBlockFile::ReadSummary(void *data) if (!summaryFile.IsOpened()){ // NEW model; we need to return valid data - memset(data, 0, mSummaryInfo.totalSummaryBytes); + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); // we silence the logging for this operation in this object // after first occurrence of error; it's already reported and // spewing at the user will complicate the user's ability to // deal mSilentLog = TRUE; - return true; + return false; } else mSilentLog = FALSE; // worked properly, any future error is NEW } - auto read = summaryFile.Read(data, mSummaryInfo.totalSummaryBytes); + auto read = summaryFile.Read(data.get(), mSummaryInfo.totalSummaryBytes); + if (read != mSummaryInfo.totalSummaryBytes) { + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); + return false; + } - FixSummary(data); + FixSummary(data.get()); - return (read == mSummaryInfo.totalSummaryBytes); + return true; } /// Modify this block to point at a different file. This is generally diff --git a/src/BlockFile.h b/src/BlockFile.h index a45d0c4de..5c6233253 100644 --- a/src/BlockFile.h +++ b/src/BlockFile.h @@ -181,7 +181,7 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ { float *summary256, float *summary64K); /// Read the summary section of the file. Derived classes implement. - virtual bool ReadSummary(void *data) = 0; + virtual bool ReadSummary(ArrayOf &data) = 0; /// Byte-swap the summary data, in case it was saved by a system /// on a different platform @@ -251,7 +251,7 @@ class AliasBlockFile /* not final */ : public BlockFile /// Write the summary to disk, using the derived ReadData() to get the data virtual void WriteSummary(); /// Read the summary into a buffer - bool ReadSummary(void *data) override; + bool ReadSummary(ArrayOf &data) override; wxFileNameWrapper mAliasedFileName; sampleCount mAliasStart; diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 5be77ac49..911d2c722 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -1402,6 +1402,8 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl, // Read triples //check to see if summary data has been computed if (seqBlock.f->IsSummaryAvailable()) + // Ignore the return value. + // This function fills with zeroes if read fails seqBlock.f->Read256(temp.get(), startPosition, num); else //otherwise, mark the display as not yet computed @@ -1411,6 +1413,8 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl, // Read triples //check to see if summary data has been computed if (seqBlock.f->IsSummaryAvailable()) + // Ignore the return value. + // This function fills with zeroes if read fails seqBlock.f->Read64K(temp.get(), startPosition, num); else //otherwise, mark the display as not yet computed diff --git a/src/blockfile/LegacyBlockFile.cpp b/src/blockfile/LegacyBlockFile.cpp index 7e90a7ae2..f64ba2abf 100644 --- a/src/blockfile/LegacyBlockFile.cpp +++ b/src/blockfile/LegacyBlockFile.cpp @@ -151,11 +151,13 @@ LegacyBlockFile::~LegacyBlockFile() } /// Read the summary section of the disk file. +/// Fill with zeroes and return false if data are unavailable for any reason. /// /// @param *data The buffer to write the data to. It must be at least /// mSummaryinfo.totalSummaryBytes long. -bool LegacyBlockFile::ReadSummary(void *data) +bool LegacyBlockFile::ReadSummary(ArrayOf &data) { + data.reinit( mSummaryInfo.totalSummaryBytes ); wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb")); size_t read; { @@ -163,20 +165,25 @@ bool LegacyBlockFile::ReadSummary(void *data) if (mSilentLog) silence.create(); - if (!summaryFile.IsOpened()){ + if (!summaryFile.IsOpened()) { - memset(data, 0, mSummaryInfo.totalSummaryBytes); + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); mSilentLog = TRUE; - return true; + return false; } - read = summaryFile.Read(data, mSummaryInfo.totalSummaryBytes); + read = summaryFile.Read(data.get(), mSummaryInfo.totalSummaryBytes); } - mSilentLog=FALSE; + mSilentLog = FALSE; - return (read == mSummaryInfo.totalSummaryBytes); + if (read != mSummaryInfo.totalSummaryBytes) { + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); + return false; + } + + return true; } /// Read the data portion of the block file using libsndfile. Convert it diff --git a/src/blockfile/LegacyBlockFile.h b/src/blockfile/LegacyBlockFile.h index 150472da3..549b216af 100644 --- a/src/blockfile/LegacyBlockFile.h +++ b/src/blockfile/LegacyBlockFile.h @@ -48,7 +48,7 @@ class LegacyBlockFile final : public BlockFile { // Reading /// Read the summary section of the disk file - bool ReadSummary(void *data) override; + bool ReadSummary(ArrayOf &data) override; /// Read the data section of the disk file size_t ReadData(samplePtr data, sampleFormat format, size_t start, size_t len) const override; diff --git a/src/blockfile/ODDecodeBlockFile.cpp b/src/blockfile/ODDecodeBlockFile.cpp index 6788c6cef..c87207948 100644 --- a/src/blockfile/ODDecodeBlockFile.cpp +++ b/src/blockfile/ODDecodeBlockFile.cpp @@ -126,6 +126,7 @@ void ODDecodeBlockFile::GetMinMax(float *outMin, float *outMax, float *outRMS) c } /// Returns the 256 byte summary data block +/// Fill with zeroes and return false if data are unavailable for any reason. bool ODDecodeBlockFile::Read256(float *buffer, size_t start, size_t len) { if(IsSummaryAvailable()) @@ -134,13 +135,13 @@ bool ODDecodeBlockFile::Read256(float *buffer, size_t start, size_t len) } else { - //this should not be reached (client should check IsSummaryAvailable()==true before this. - buffer = NULL; - return true; + ClearSamples((samplePtr)buffer, floatSample, 0, len); + return false; } } /// Returns the 64K summary data block +/// Fill with zeroes and return false if data are unavailable for any reason. bool ODDecodeBlockFile::Read64K(float *buffer, size_t start, size_t len) { if(IsSummaryAvailable()) @@ -149,8 +150,8 @@ bool ODDecodeBlockFile::Read64K(float *buffer, size_t start, size_t len) } else { - //this should not be reached (client should check IsSummaryAvailable()==true before this. - return true; + ClearSamples((samplePtr)buffer, floatSample, 0, len); + return false; } } @@ -450,17 +451,19 @@ size_t ODDecodeBlockFile::ReadData(samplePtr data, sampleFormat format, /// Read the summary of this alias block from disk. Since the audio data /// is elsewhere, this consists of reading the entire summary file. +/// Fill with zeroes and return false if data are unavailable for any reason. /// /// @param *data The buffer where the summary data will be stored. It must /// be at least mSummaryInfo.totalSummaryBytes long. -bool ODDecodeBlockFile::ReadSummary(void *data) +bool ODDecodeBlockFile::ReadSummary(ArrayOf &data) { - //I dont think we need to add a mutex here because only the main thread changes filenames and calls ReadSummarz + //I dont think we need to add a mutex here because only the main thread changes filenames and calls ReadSummary if(IsSummaryAvailable()) return SimpleBlockFile::ReadSummary(data); - memset(data, 0, mSummaryInfo.totalSummaryBytes); - return true; + data.reinit( mSummaryInfo.totalSummaryBytes ); + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); + return false; } ///set the decoder, diff --git a/src/blockfile/ODDecodeBlockFile.h b/src/blockfile/ODDecodeBlockFile.h index 06d66f58d..3a743ffd9 100644 --- a/src/blockfile/ODDecodeBlockFile.h +++ b/src/blockfile/ODDecodeBlockFile.h @@ -112,7 +112,7 @@ class ODDecodeBlockFile final : public SimpleBlockFile size_t start, size_t len) const override; /// Read the summary into a buffer - bool ReadSummary(void *data) override; + bool ReadSummary(ArrayOf &data) override; ///Returns the type of audiofile this blockfile is loaded from. unsigned int GetDecodeType() /* not override */ const { return mType; } diff --git a/src/blockfile/ODPCMAliasBlockFile.cpp b/src/blockfile/ODPCMAliasBlockFile.cpp index 01d93fa78..44d057c3f 100644 --- a/src/blockfile/ODPCMAliasBlockFile.cpp +++ b/src/blockfile/ODPCMAliasBlockFile.cpp @@ -155,7 +155,8 @@ void ODPCMAliasBlockFile::GetMinMax(float *outMin, float *outMax, float *outRMS) } } -/// Returns the 256 byte summary data block. Clients should check to see if the summary is available before trying to read it with this call. +/// Returns the 256 byte summary data block. +/// Fill with zeroes and return false if data are unavailable for any reason. bool ODPCMAliasBlockFile::Read256(float *buffer, size_t start, size_t len) { if(IsSummaryAvailable()) @@ -165,12 +166,13 @@ bool ODPCMAliasBlockFile::Read256(float *buffer, size_t start, size_t len) else { //return nothing. - buffer = NULL; - return true; + ClearSamples((samplePtr)buffer, floatSample, 0, len); + return false; } } -/// Returns the 64K summary data block. Clients should check to see if the summary is available before trying to read it with this call. +/// Returns the 64K summary data block. +/// Fill with zeroes and return false if data are unavailable for any reason. bool ODPCMAliasBlockFile::Read64K(float *buffer, size_t start, size_t len) { if(IsSummaryAvailable()) @@ -180,8 +182,8 @@ bool ODPCMAliasBlockFile::Read64K(float *buffer, size_t start, size_t len) else { //return nothing - it hasn't been calculated yet - buffer = NULL; - return true; + ClearSamples((samplePtr)buffer, floatSample, 0, len); + return false; } } @@ -505,40 +507,43 @@ size_t ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, /// Read the summary of this alias block from disk. Since the audio data /// is elsewhere, this consists of reading the entire summary file. +/// Fill with zeroes and return false if data are unavailable for any reason. /// /// @param *data The buffer where the summary data will be stored. It must /// be at least mSummaryInfo.totalSummaryBytes long. -bool ODPCMAliasBlockFile::ReadSummary(void *data) +bool ODPCMAliasBlockFile::ReadSummary(ArrayOf &data) { + data.reinit( mSummaryInfo.totalSummaryBytes ); - mFileNameMutex.Lock(); + ODLocker locker{ &mFileNameMutex }; wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb")); - if( !summaryFile.IsOpened() ){ + if( !summaryFile.IsOpened() ) { // NEW model; we need to return valid data - memset(data, 0, mSummaryInfo.totalSummaryBytes); + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); // we silence the logging for this operation in this object // after first occurrence of error; it's already reported and // spewing at the user will complicate the user's ability to // deal - mSilentLog=TRUE; - - mFileNameMutex.Unlock(); - return true; + mSilentLog = TRUE; + return false; } else - mSilentLog=FALSE; // worked properly, any future error is NEW + mSilentLog = FALSE; // worked properly, any future error is NEW - auto read = summaryFile.Read(data, mSummaryInfo.totalSummaryBytes); + auto read = summaryFile.Read(data.get(), mSummaryInfo.totalSummaryBytes); - FixSummary(data); + if (read != mSummaryInfo.totalSummaryBytes) { + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); + return false; + } + + FixSummary(data.get()); - - mFileNameMutex.Unlock(); - return (read == mSummaryInfo.totalSummaryBytes); + return true; } /// Prevents a read on other threads. diff --git a/src/blockfile/ODPCMAliasBlockFile.h b/src/blockfile/ODPCMAliasBlockFile.h index 10b5463df..1653b1e65 100644 --- a/src/blockfile/ODPCMAliasBlockFile.h +++ b/src/blockfile/ODPCMAliasBlockFile.h @@ -121,7 +121,7 @@ class ODPCMAliasBlockFile final : public PCMAliasBlockFile size_t start, size_t len) const override; /// Read the summary into a buffer - bool ReadSummary(void *data) override; + bool ReadSummary(ArrayOf &data) override; ///sets the file name the summary info will be saved in. threadsafe. void SetFileName(wxFileNameWrapper &&name) override; diff --git a/src/blockfile/SilentBlockFile.cpp b/src/blockfile/SilentBlockFile.cpp index 89cbc5b03..a2d33effb 100644 --- a/src/blockfile/SilentBlockFile.cpp +++ b/src/blockfile/SilentBlockFile.cpp @@ -24,9 +24,10 @@ SilentBlockFile::~SilentBlockFile() { } -bool SilentBlockFile::ReadSummary(void *data) +bool SilentBlockFile::ReadSummary(ArrayOf &data) { - memset(data, 0, mSummaryInfo.totalSummaryBytes); + data.reinit( mSummaryInfo.totalSummaryBytes ); + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); return true; } diff --git a/src/blockfile/SilentBlockFile.h b/src/blockfile/SilentBlockFile.h index 24b6452dd..e1788bccc 100644 --- a/src/blockfile/SilentBlockFile.h +++ b/src/blockfile/SilentBlockFile.h @@ -33,7 +33,7 @@ class SilentBlockFile final : public BlockFile { // Reading /// Read the summary section of the disk file - bool ReadSummary(void *data) override; + bool ReadSummary(ArrayOf &data) override; /// Read the data section of the disk file size_t ReadData(samplePtr data, sampleFormat format, size_t start, size_t len) const override; diff --git a/src/blockfile/SimpleBlockFile.cpp b/src/blockfile/SimpleBlockFile.cpp index 14bad5ad4..c1482b984 100644 --- a/src/blockfile/SimpleBlockFile.cpp +++ b/src/blockfile/SimpleBlockFile.cpp @@ -321,9 +321,8 @@ void SimpleBlockFile::FillCache() } // Read summary data into cache - mCache.summaryData.reinit(mSummaryInfo.totalSummaryBytes); - if (!ReadSummary(mCache.summaryData.get())) - memset(mCache.summaryData.get(), 0, mSummaryInfo.totalSummaryBytes); + // Fills with zeroes in case of failure: + ReadSummary(mCache.summaryData); // Cache is active but already on disk mCache.active = true; @@ -336,12 +335,12 @@ void SimpleBlockFile::FillCache() /// /// @param *data The buffer to write the data to. It must be at least /// mSummaryinfo.totalSummaryBytes long. -bool SimpleBlockFile::ReadSummary(void *data) +bool SimpleBlockFile::ReadSummary(ArrayOf &data) { - if (mCache.active) - { + data.reinit( mSummaryInfo.totalSummaryBytes ); + if (mCache.active) { //wxLogDebug("SimpleBlockFile::ReadSummary(): Summary is already in cache."); - memcpy(data, mCache.summaryData.get(), mSummaryInfo.totalSummaryBytes); + memcpy(data.get(), mCache.summaryData.get(), mSummaryInfo.totalSummaryBytes); return true; } else @@ -357,23 +356,24 @@ bool SimpleBlockFile::ReadSummary(void *data) // FIXME: TRAP_ERR no report to user of absent summary files? // filled with zero instead. if (!file.IsOpened()){ - memset(data, 0, mSummaryInfo.totalSummaryBytes); + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); mSilentLog = TRUE; - return true; + return false; } } - mSilentLog=FALSE; + mSilentLog = FALSE; // The offset is just past the au header - // FIXME: Seek in summary file could fail. - if( !file.Seek(sizeof(auHeader)) ) + if( !file.Seek(sizeof(auHeader)) || + file.Read(data.get(), mSummaryInfo.totalSummaryBytes) != + mSummaryInfo.totalSummaryBytes ) { + memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); return false; + } - auto read = file.Read(data, mSummaryInfo.totalSummaryBytes); + FixSummary(data.get()); - FixSummary(data); - - return (read == mSummaryInfo.totalSummaryBytes); + return true; } } diff --git a/src/blockfile/SimpleBlockFile.h b/src/blockfile/SimpleBlockFile.h index f733559c9..f95e80bfb 100644 --- a/src/blockfile/SimpleBlockFile.h +++ b/src/blockfile/SimpleBlockFile.h @@ -63,7 +63,7 @@ class PROFILE_DLL_API SimpleBlockFile /* not final */ : public BlockFile { // Reading /// Read the summary section of the disk file - bool ReadSummary(void *data) override; + bool ReadSummary(ArrayOf &data) override; /// Read the data section of the disk file size_t ReadData(samplePtr data, sampleFormat format, size_t start, size_t len) const override; From 52fd607b42f91769f039d5c94a78b3088c7e584e Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 29 Nov 2016 08:41:10 -0500 Subject: [PATCH 11/91] Sequence::AppendBlock and Sequence::Blockify are static --- src/Sequence.cpp | 39 ++++++++++++++++++++++++++------------- src/Sequence.h | 11 +++++++++-- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 911d2c722..465edb0be 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -185,7 +185,8 @@ bool Sequence::ConvertToSampleFormat(sampleFormat format, bool* pbChanged) // Using Blockify will handle the cases where len > the NEW mMaxSamples. Previous code did not. const auto blockstart = oldSeqBlock.start; const unsigned prevSize = newBlockArray.size(); - Blockify(newBlockArray, blockstart, bufferNew.ptr(), len); + Blockify(*mDirManager, mMaxSamples, mSampleFormat, + newBlockArray, blockstart, bufferNew.ptr(), len); bSuccess = (newBlockArray.size() > prevSize); if (bSuccess) *pbChanged = true; @@ -425,7 +426,8 @@ std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const // If there are blocks in the middle, copy the blockfiles directly for (int bb = b0 + 1; bb < b1; ++bb) - dest->AppendBlock(mBlock[bb]); // Increase ref count or duplicate file + AppendBlock(*dest->mDirManager, dest->mBlock, dest->mNumSamples, mBlock[bb]); + // Increase ref count or duplicate file // Do the last block if (b1 > b0) { @@ -440,7 +442,8 @@ std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const } else // Special case, copy exactly - dest->AppendBlock(block); // Increase ref count or duplicate file + AppendBlock(*dest->mDirManager, dest->mBlock, dest->mNumSamples, block); + // Increase ref count or duplicate file } if (! ConsistencyCheck(wxT("Sequence::Copy()"))) @@ -507,7 +510,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) // minimum size for (unsigned int i = 0; i < srcNumBlocks; i++) - AppendBlock(srcBlock[i]); // Increase ref count or duplicate file + AppendBlock(*mDirManager, mBlock, mNumSamples, srcBlock[i]); + // Increase ref count or duplicate file return ConsistencyCheck(wxT("Paste branch one")); } @@ -583,7 +587,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) splitBlock, splitPoint, splitLen - splitPoint); - Blockify(newBlock, splitBlock.start, sumBuffer.ptr(), sum); + Blockify(*mDirManager, mMaxSamples, mSampleFormat, + newBlock, splitBlock.start, sumBuffer.ptr(), sum); } else { // The final case is that we're inserting at least five blocks. @@ -609,7 +614,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) src->Get(0, sampleBuffer.ptr() + splitPoint*sampleSize, mSampleFormat, 0, srcFirstTwoLen); - Blockify(newBlock, splitBlock.start, sampleBuffer.ptr(), leftLen); + Blockify(*mDirManager, mMaxSamples, mSampleFormat, + newBlock, splitBlock.start, sampleBuffer.ptr(), leftLen); for (i = 2; i < srcNumBlocks - 2; i++) { const SeqBlock &block = srcBlock[i]; @@ -628,7 +634,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) Read(sampleBuffer.ptr() + srcLastTwoLen * sampleSize, mSampleFormat, splitBlock, splitPoint, rightSplit); - Blockify(newBlock, s + lastStart, sampleBuffer.ptr(), rightLen); + Blockify(*mDirManager, mMaxSamples, mSampleFormat, + newBlock, s + lastStart, sampleBuffer.ptr(), rightLen); } // Copy remaining blocks to NEW block array and @@ -734,14 +741,16 @@ bool Sequence::AppendCoded(const wxString &fName, sampleCount start, return true; } -bool Sequence::AppendBlock(const SeqBlock &b) +bool Sequence::AppendBlock + (DirManager &mDirManager, + BlockArray &mBlock, sampleCount &mNumSamples, const SeqBlock &b) { // Quick check to make sure that it doesn't overflow if (Overflows((mNumSamples.as_double()) + ((double)b.f->GetLength()))) return false; SeqBlock newBlock( - mDirManager->CopyBlockFile(b.f), // Bump ref count if not locked, else copy + mDirManager.CopyBlockFile(b.f), // Bump ref count if not locked, else copy mNumSamples ); if (!newBlock.f) { @@ -1592,7 +1601,9 @@ bool Sequence::Append(samplePtr buffer, sampleFormat format, return true; } -void Sequence::Blockify(BlockArray &list, sampleCount start, samplePtr buffer, size_t len) +void Sequence::Blockify + (DirManager &mDirManager, size_t mMaxSamples, sampleFormat mSampleFormat, + BlockArray &list, sampleCount start, samplePtr buffer, size_t len) { if (len <= 0) return; @@ -1607,7 +1618,7 @@ void Sequence::Blockify(BlockArray &list, sampleCount start, samplePtr buffer, s int newLen = ((i + 1) * len / num) - offset; samplePtr bufStart = buffer + (offset * SAMPLE_SIZE(mSampleFormat)); - b.f = mDirManager->NewSimpleBlockFile(bufStart, newLen, mSampleFormat); + b.f = mDirManager.NewSimpleBlockFile(bufStart, newLen, mSampleFormat); list.push_back(b); } @@ -1713,7 +1724,8 @@ bool Sequence::Delete(sampleCount start, sampleCount len) preBlock, 0, preBufferLen); newBlock.erase(newBlock.end() - 1); - Blockify(newBlock, prepreBlock.start, scratch.ptr(), sum); + Blockify(*mDirManager, mMaxSamples, mSampleFormat, + newBlock, prepreBlock.start, scratch.ptr(), sum); } } else { @@ -1757,7 +1769,8 @@ bool Sequence::Delete(sampleCount start, sampleCount len) Read(scratch.ptr() + (postBufferLen * sampleSize), mSampleFormat, postpostBlock, 0, postpostLen); - Blockify(newBlock, start, scratch.ptr(), sum); + Blockify(*mDirManager, mMaxSamples, mSampleFormat, + newBlock, start, scratch.ptr(), sum); b1++; } } diff --git a/src/Sequence.h b/src/Sequence.h index e97a3303a..278a1082b 100644 --- a/src/Sequence.h +++ b/src/Sequence.h @@ -246,13 +246,20 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{ int FindBlock(sampleCount pos) const; - bool AppendBlock(const SeqBlock &b); + static bool AppendBlock + (DirManager &dirManager, + BlockArray &blocks, sampleCount &numSamples, const SeqBlock &b); bool Read(samplePtr buffer, sampleFormat format, const SeqBlock &b, size_t blockRelativeStart, size_t len) const; - void Blockify(BlockArray &list, sampleCount start, samplePtr buffer, size_t len); + // Accumulate NEW block files onto the end of a block array. + // Does not change this sequence. The intent is to use + // CommitChangesIfConsistent later. + static void Blockify + (DirManager &dirManager, size_t maxSamples, sampleFormat format, + BlockArray &list, sampleCount start, samplePtr buffer, size_t len); bool Get(int b, samplePtr buffer, sampleFormat format, sampleCount start, size_t len) const; From 5e3a4fa29d79251e60850276e13b4f6e2df1a488 Mon Sep 17 00:00:00 2001 From: James Crook Date: Tue, 21 Mar 2017 13:31:33 +0000 Subject: [PATCH 12/91] Name Record Beside menu option correctly. --- src/Menus.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Menus.cpp b/src/Menus.cpp index ecb5aae6d..000ee7b49 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -785,7 +785,16 @@ void AudacityProject::CreateMenusAndCommands() /* i18n-hint: (verb)*/ c->AddItem(wxT("Record"), _("&Record"), FN(OnRecord), wxT("R")); c->AddItem(wxT("TimerRecord"), _("&Timer Record..."), FN(OnTimerRecord), wxT("Shift+T")); + +// The RecordBelow function is actually 'record-other', i.e. if normal record record beside, +// it records below, if normal record records below, it records beside. +// TODO: fix the naming, and also check we do 'the right thing' with other options like +// TimerRecord. +#ifdef EXPERIMENTAL_DA c->AddItem(wxT("RecordBelow"), _("Record Below"), FN(OnRecordBelow), wxT("Shift+R")); +#else + c->AddItem(wxT("RecordBelow"), _("Record Beside"), FN(OnRecordBelow), wxT("Shift+R")); +#endif // JKC: I decided to duplicate this between play and record, rather than put it // at the top level. AddItem can now cope with simple duplicated items. c->AddItem(wxT("Pause"), _("&Pause"), FN(OnPause), wxT("P")); From 12e3d1d2e20dc221f17d377b28ff29a3ae45f5ad Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 21 Mar 2017 11:21:25 -0400 Subject: [PATCH 13/91] Small correction to parsing of LOF file --- src/import/ImportLOF.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/import/ImportLOF.cpp b/src/import/ImportLOF.cpp index 1519230a1..722a4f428 100644 --- a/src/import/ImportLOF.cpp +++ b/src/import/ImportLOF.cpp @@ -368,7 +368,8 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) // To identify filename and open it tokenholder = temptok1.GetNextToken(); - targetfile = temptok1.GetNextToken(); + wxString targettoken = temptok1.GetNextToken(); + targetfile = targettoken; // If path is relative, make absolute path from LOF path if(!wxIsAbsolutePath(targetfile)) { @@ -400,7 +401,7 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) } // Set tok to right after filename - temptok2.SetString(targetfile); + temptok2.SetString(targettoken); tokenplace = temptok2.CountTokens(); for (int i = 0; i < tokenplace; i++) From e9a4fc83543a207ac361d538bf7773912eb30c77 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 18 Mar 2017 15:04:51 -0400 Subject: [PATCH 14/91] fix the XML writer -- don't throw if target path did not previously exist. --- src/xml/XMLWriter.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/xml/XMLWriter.cpp b/src/xml/XMLWriter.cpp index 939ba36d9..cc82cbed5 100644 --- a/src/xml/XMLWriter.cpp +++ b/src/xml/XMLWriter.cpp @@ -321,17 +321,16 @@ void XMLFileWriter::Commit() auto tempPath = GetName(); CloseWithoutEndingTags(); - // JKC: NOT translating error messages. Rationale is that they should - // not be seen, and if they are the untranslated version is more useful to - // developers. - if ( mKeepBackup) { - if (! mBackupFile.Close() || ! wxRenameFile( mOutputPath, mBackupName ) ) - ThrowException( mBackupName, mCaption + " renaming backup"); + if (mKeepBackup) { + if (! mBackupFile.Close() || + ! wxRenameFile( mOutputPath, mBackupName ) ) + ThrowException( mBackupName, mCaption ); + } + else { + if ( wxFileName::FileExists( mOutputPath ) && + ! wxRemoveFile( mOutputPath ) ) + ThrowException( mOutputPath, mCaption ); } - else if (! wxFileExists( mOutputPath ) ); - else if (! wxRemoveFile( mOutputPath ) ) - ThrowException( mOutputPath, mCaption + " removing old version"); - // Now we have vacated the file at the output path and are committed. // But not completely finished with steps of the commit operation. From 7927fe065f50b3f16d305b2f38923e1e832515e5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 21 Mar 2017 12:45:04 -0400 Subject: [PATCH 15/91] Fix move constructors and assignments of AudacityException classes --- src/AudacityException.cpp | 1 + src/FileException.h | 5 +++++ src/InconsistencyException.h | 11 +++++++++-- src/UserException.h | 2 ++ src/blockfile/NotYetAvailableException.cpp | 2 +- src/blockfile/NotYetAvailableException.h | 4 +--- 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/AudacityException.cpp b/src/AudacityException.cpp index 84451970a..46504d4cc 100644 --- a/src/AudacityException.cpp +++ b/src/AudacityException.cpp @@ -31,6 +31,7 @@ MessageBoxException &MessageBoxException::operator = ( MessageBoxException &&tha { caption = that.caption; if ( this != &that ) { + AudacityException::operator=( std::move(that) ); if (!moved) wxAtomicDec( sOutstandingMessages ); diff --git a/src/FileException.h b/src/FileException.h index 8cf1dfd6f..ef8f5e506 100644 --- a/src/FileException.h +++ b/src/FileException.h @@ -27,8 +27,13 @@ public: FileException(FileException&& that) : MessageBoxException(std::move(that)) + , cause{ that.cause } + , fileName{ that.fileName } + , renameTarget{ that.renameTarget } {} + FileException& operator= (FileException&&) PROHIBITED; + ~FileException() override; protected: diff --git a/src/InconsistencyException.h b/src/InconsistencyException.h index fdc0741bd..065919eff 100644 --- a/src/InconsistencyException.h +++ b/src/InconsistencyException.h @@ -27,11 +27,18 @@ public: InconsistencyException(InconsistencyException&& that) : MessageBoxException(std::move(that)) + , func{ that.func } + , file{ that.file } + , line{ that.line } {} InconsistencyException &operator = (InconsistencyException &&that) { - if (this != &that) - operator= (std::move(that)); + if (this != &that) { + MessageBoxException::operator= (std::move(that)); + func = that.func; + file = that.file; + line = that.line; + } return *this; } diff --git a/src/UserException.h b/src/UserException.h index cf3989162..e59b881cc 100644 --- a/src/UserException.h +++ b/src/UserException.h @@ -25,6 +25,8 @@ public: : AudacityException{ std::move( that ) } {} + UserException& operator= (UserException&&) PROHIBITED; + ~UserException() override; void DelayedHandlerAction() override; diff --git a/src/blockfile/NotYetAvailableException.cpp b/src/blockfile/NotYetAvailableException.cpp index 81ebcc785..656c606a9 100644 --- a/src/blockfile/NotYetAvailableException.cpp +++ b/src/blockfile/NotYetAvailableException.cpp @@ -23,6 +23,6 @@ wxString NotYetAvailableException::ErrorMessage() const { return wxString::Format( _("This operation cannot be done until importation of %s completes."), - mFileName.GetFullName() + fileName.GetFullName() ); } diff --git a/src/blockfile/NotYetAvailableException.h b/src/blockfile/NotYetAvailableException.h index c54c262e7..d961bcec7 100644 --- a/src/blockfile/NotYetAvailableException.h +++ b/src/blockfile/NotYetAvailableException.h @@ -21,14 +21,12 @@ public: : FileException{ Cause::Read, fileName } {} NotYetAvailableException(NotYetAvailableException &&that) : FileException( std::move( that ) ) {} + NotYetAvailableException& operator= (NotYetAvailableException&&) PROHIBITED; ~NotYetAvailableException(); protected: std::unique_ptr< AudacityException > Move() override; wxString ErrorMessage() const override; - -private: - wxFileName mFileName; }; #endif From 82dd7545c9a5f26cb9fb93f87622c6183745dc94 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 14 Mar 2017 19:54:11 -0400 Subject: [PATCH 16/91] Reviewed uses of release(); prefer Destroy_ptr to hold window objects --- src/Menus.cpp | 6 ++++-- src/Project.cpp | 11 ++--------- src/Project.h | 4 ++-- src/TrackPanel.cpp | 2 +- src/effects/VST/VSTEffect.cpp | 2 +- src/effects/audiounits/AudioUnitEffect.cpp | 2 +- src/effects/lv2/LV2Effect.cpp | 4 +++- 7 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 000ee7b49..185aa08f9 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -5609,7 +5609,8 @@ void AudacityProject::OnPlotSpectrum() where.x = 150; where.y = 150; - mFreqWindow = safenew FreqWindow(this, -1, _("Frequency Analysis"), where); + mFreqWindow.reset( safenew FreqWindow( + this, -1, _("Frequency Analysis"), where ) ); } mFreqWindow->Show(true); @@ -5626,7 +5627,8 @@ void AudacityProject::OnContrast() where.x = 150; where.y = 150; - mContrastDialog = safenew ContrastDialog(this, -1, _("Contrast Analysis (WCAG 2 compliance)"), where); + mContrastDialog.reset( safenew ContrastDialog( + this, -1, _("Contrast Analysis (WCAG 2 compliance)"), where ) ); } mContrastDialog->CentreOnParent(); diff --git a/src/Project.cpp b/src/Project.cpp index 276a5d5d8..346c39557 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -2482,15 +2482,8 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) // Streams can be for play, recording, or monitoring. But maybe it still // makes sense to stop any recording before putting up the dialog. - if (mFreqWindow) { - mFreqWindow->Destroy(); - mFreqWindow = NULL; - } - - if (mContrastDialog) { - mContrastDialog->Destroy(); - mContrastDialog = NULL; - } + mFreqWindow.reset(); + mContrastDialog.reset(); // Check to see if we were playing or recording // audio, and if so, make sure Audio I/O is completely finished. diff --git a/src/Project.h b/src/Project.h index fc454ffc6..3888f742f 100644 --- a/src/Project.h +++ b/src/Project.h @@ -630,8 +630,8 @@ private: MixerBoard* mMixerBoard{}; MixerBoardFrame* mMixerBoardFrame{}; - FreqWindow *mFreqWindow{}; - ContrastDialog *mContrastDialog{}; + Destroy_ptr mFreqWindow; + Destroy_ptr mContrastDialog; // dialog for missing alias warnings wxDialog *mAliasMissingWarningDialog{}; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index ec0bee7b8..ec0eded34 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -447,7 +447,7 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, // wxWidgets owns the accessible object SetAccessible(mAx = pAx.release()); #else - // wxWidgets doesn not own the object, but we need to retain it + // wxWidgets does not own the object, but we need to retain it mAx = std::move(pAx); #endif } diff --git a/src/effects/VST/VSTEffect.cpp b/src/effects/VST/VSTEffect.cpp index e7201f188..636ba2d2e 100644 --- a/src/effects/VST/VSTEffect.cpp +++ b/src/effects/VST/VSTEffect.cpp @@ -2715,7 +2715,7 @@ void VSTEffect::BuildFancy() // Turn the power on...some effects need this when the editor is open PowerOn(); - auto control = std::make_unique(); + auto control = Destroy_ptr{ safenew VSTControl }; if (!control) { return; diff --git a/src/effects/audiounits/AudioUnitEffect.cpp b/src/effects/audiounits/AudioUnitEffect.cpp index b6b145d23..d9bd279e4 100644 --- a/src/effects/audiounits/AudioUnitEffect.cpp +++ b/src/effects/audiounits/AudioUnitEffect.cpp @@ -1729,7 +1729,7 @@ bool AudioUnitEffect::PopulateUI(wxWindow *parent) } else { - auto pControl = std::make_unique(); + auto pControl = Destroy_ptr( safenew AUControl ); if (!pControl) { return false; diff --git a/src/effects/lv2/LV2Effect.cpp b/src/effects/lv2/LV2Effect.cpp index cb1542461..86aad37c0 100644 --- a/src/effects/lv2/LV2Effect.cpp +++ b/src/effects/lv2/LV2Effect.cpp @@ -1398,7 +1398,9 @@ bool LV2Effect::BuildFancy() // Use a panel to host the plugins GUI // container is owned by mParent, but we may destroy it if there are // any errors before completing the build of UI. - auto container = std::make_unique(mParent, wxID_ANY); + auto container = Destroy_ptr{ + safenew wxPanelWrapper{ mParent, wxID_ANY} + }; if (!container) { lilv_uis_free(uis); From 41f1ebfb5dbc4837fedb926404729e574bd04c05 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 18 Dec 2016 23:44:38 -0500 Subject: [PATCH 17/91] Commit resampling of tracks to undo history one track at a time --- src/Menus.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 185aa08f9..dbcf5d95f 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -7167,6 +7167,7 @@ void AudacityProject::OnResample() } int ndx = 0; + auto flags = UndoPush::AUTOSAVE; for (Track *t = iter.First(); t; t = iter.Next()) { wxString msg; @@ -7175,12 +7176,24 @@ void AudacityProject::OnResample() ProgressDialog progress(_("Resample"), msg); - if (t->GetSelected() && t->GetKind() == Track::Wave) + if (t->GetSelected() && t->GetKind() == Track::Wave) { + // The resampling of a track may be stopped by the user. This might + // leave a track with multiple clips in a partially resampled state. + // But the thrown exception will cause rollback in the application + // level handler. + if (!((WaveTrack*)t)->Resample(newRate, &progress)) break; + + // Each time a track is successfully, completely resampled, + // commit that to the undo stack. The second and later times, + // consolidate. + + PushState(_("Resampled audio track(s)"), _("Resample Track"), flags); + flags = flags | UndoPush::CONSOLIDATE; + } } - PushState(_("Resampled audio track(s)"), _("Resample Track")); RedrawProject(); // Need to reset From 68c726918b6eb8d2af67527d95f2895043ecb428 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 17 Dec 2016 10:05:15 -0500 Subject: [PATCH 18/91] If exception in cut/copy, leave clipboard clear (no partial results) --- src/Menus.cpp | 27 ++++++++++++++++++++++++--- src/Project.cpp | 8 +++++++- src/Track.h | 3 +++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index dbcf5d95f..52a3b0e9c 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -4149,6 +4149,9 @@ void AudacityProject::OnCut() } ClearClipboard(); + + TrackList newClipboard; + n = iter.First(); while (n) { if (n->GetSelected()) { @@ -4164,11 +4167,17 @@ void AudacityProject::OnCut() mViewInfo.selectedRegion.t1()); if (dest) - FinishCopy(n, std::move(dest), *msClipboard); + FinishCopy(n, std::move(dest), newClipboard); } n = iter.Next(); } + // Survived possibility of exceptions. Commit changes to the clipboard now. + newClipboard.Swap(*msClipboard); + + // Proceed to change the project. If this throws, the project will be + // rolled back by the top level handler. + n = iter.First(); while (n) { // We clear from selected and sync-lock selected tracks. @@ -4220,6 +4229,9 @@ void AudacityProject::OnSplitCut() Track *n = iter.First(); ClearClipboard(); + + TrackList newClipboard; + while (n) { if (n->GetSelected()) { Track::Holder dest; @@ -4237,11 +4249,14 @@ void AudacityProject::OnSplitCut() mViewInfo.selectedRegion.t1()); } if (dest) - FinishCopy(n, std::move(dest), *msClipboard); + FinishCopy(n, std::move(dest), newClipboard); } n = iter.Next(); } + // Survived possibility of exceptions. Commit changes to the clipboard now. + newClipboard.Swap(*msClipboard); + msClipT0 = mViewInfo.selectedRegion.t0(); msClipT1 = mViewInfo.selectedRegion.t1(); msClipProject = this; @@ -4275,17 +4290,23 @@ void AudacityProject::OnCopy() } ClearClipboard(); + + TrackList newClipboard; + n = iter.First(); while (n) { if (n->GetSelected()) { auto dest = n->Copy(mViewInfo.selectedRegion.t0(), mViewInfo.selectedRegion.t1()); if (dest) - FinishCopy(n, std::move(dest), *msClipboard); + FinishCopy(n, std::move(dest), newClipboard); } n = iter.Next(); } + // Survived possibility of exceptions. Commit changes to the clipboard now. + newClipboard.Swap(*msClipboard); + msClipT0 = mViewInfo.selectedRegion.t0(); msClipT1 = mViewInfo.selectedRegion.t1(); msClipProject = this; diff --git a/src/Project.cpp b/src/Project.cpp index 346c39557..fdda5a74d 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -4917,6 +4917,9 @@ void AudacityProject::EditClipboardByLabel( EditDestFunction action ) } ClearClipboard(); + + TrackList newClipboard; + //Apply action on wavetracks starting from //labeled regions in the end. This is to correctly perform //actions like 'Cut' which collapse the track area. @@ -4961,10 +4964,13 @@ void AudacityProject::EditClipboardByLabel( EditDestFunction action ) regions.at(i + 1).start - region.end); } if( merged ) - msClipboard->Add( std::move(merged) ); + newClipboard.Add( std::move(merged) ); } } + // Survived possibility of exceptions. Commit changes to the clipboard now. + newClipboard.Swap(*msClipboard); + msClipT0 = regions.front().start; msClipT1 = regions.back().end; diff --git a/src/Track.h b/src/Track.h index 64a8fe05a..8e2bc533f 100644 --- a/src/Track.h +++ b/src/Track.h @@ -408,6 +408,9 @@ DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_TRACKLIST_UPDATED, -1); class TrackList final : public wxEvtHandler, public ListOfTracks { + // privatize this, make you use Swap instead: + using ListOfTracks::swap; + public: // Create an empty TrackList TrackList(); From 63e44e2b6becf968a3b204b4a60b1de6d2812716 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 18 Dec 2016 16:37:56 -0500 Subject: [PATCH 19/91] Rearrange a few things in time shift button up... ... to reclaim some memory earlier, before possible throws --- src/TrackPanel.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index ec0eded34..85d81b5e1 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -3329,6 +3329,20 @@ void TrackPanel::HandleSlide(wxMouseEvent & event) DoSlide(event); if (event.LeftUp()) { + + SetCapturedTrack( NULL ); + + mSnapManager.reset(); + + // Do not draw yellow lines + if (mSnapLeft != -1 || mSnapRight != -1) { + mSnapLeft = mSnapRight = -1; + Refresh(false); + } + + if (!mDidSlideVertically && mHSlideAmount==0) + return; + for (size_t i = 0; i < mCapturedClipArray.size(); i++) { TrackClip &trackClip = mCapturedClipArray[i]; @@ -3349,19 +3363,6 @@ void TrackPanel::HandleSlide(wxMouseEvent & event) } } - SetCapturedTrack( NULL ); - - mSnapManager.reset(); - - // Do not draw yellow lines - if (mSnapLeft != -1 || mSnapRight != -1) { - mSnapLeft = mSnapRight = -1; - Refresh(false); - } - - if (!mDidSlideVertically && mHSlideAmount==0) - return; - MakeParentRedrawScrollbars(); wxString msg; From 1a90b7d9424f6bc4f6f1fad40bf557fffefb9a74 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 15 Mar 2017 12:14:33 -0400 Subject: [PATCH 20/91] TimerRecordDialog: comment why nothing need be done for exceptions --- src/TimerRecordDialog.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/TimerRecordDialog.cpp b/src/TimerRecordDialog.cpp index 426f10cf9..debcf5547 100644 --- a/src/TimerRecordDialog.cpp +++ b/src/TimerRecordDialog.cpp @@ -684,9 +684,13 @@ int TimerRecordDialog::ExecutePostRecordActions(bool bWasStopped) { break; } + // If we have simply recorded, exported and then plan to Exit/Restart/Shutdown // then we will have a temporary project setup. Let's get rid of that! if (m_bAutoExportEnabled && !m_bAutoSaveEnabled) { + // PRL: Move the following cleanup into a finally? + // No, I think you would want to skip this, in case recording + // succeeded but then save or export threw an exception. DirManager::CleanTempDir(); } } while (false); @@ -694,6 +698,9 @@ int TimerRecordDialog::ExecutePostRecordActions(bool bWasStopped) { // Do we need to cleanup the orphaned temporary project? if (m_bProjectCleanupRequired && !bErrorOverride) { + // PRL: Move the following cleanup into a finally? + // No, I think you would want to skip this, in case recording + // succeeded but then save or export threw an exception. RemoveAllAutoSaveFiles(); } From 195732f074268e86055b6a774eb29ba7b03d8741 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 15 Mar 2017 15:29:35 -0400 Subject: [PATCH 21/91] Exception safety in: BatchCommands --- src/BatchCommands.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/BatchCommands.cpp b/src/BatchCommands.cpp index a817854ca..930abdeca 100644 --- a/src/BatchCommands.cpp +++ b/src/BatchCommands.cpp @@ -481,10 +481,14 @@ bool BatchCommands::WriteMp3File( const wxString & Name, int bitrate ) bool rc; long prevBitRate = gPrefs->Read(wxT("/FileFormats/MP3Bitrate"), 128); gPrefs->Write(wxT("/FileFormats/MP3Bitrate"), bitrate); + + auto cleanup = finally( [&] { + gPrefs->Write(wxT("/FileFormats/MP3Bitrate"), prevBitRate); + gPrefs->Flush(); + } ); + // Use Mp3Stereo to control if export is to a stereo or mono file rc = mExporter.Process(project, numChannels, wxT("MP3"), Name, false, 0.0, endTime); - gPrefs->Write(wxT("/FileFormats/MP3Bitrate"), prevBitRate); - gPrefs->Flush(); return rc; } From 664974d3ff6f1881d32cb68a429afd70307fd08e Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 15 Mar 2017 23:02:00 -0400 Subject: [PATCH 22/91] Exception safety in: ondemand --- src/blockfile/ODPCMAliasBlockFile.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/blockfile/ODPCMAliasBlockFile.cpp b/src/blockfile/ODPCMAliasBlockFile.cpp index 44d057c3f..c90440319 100644 --- a/src/blockfile/ODPCMAliasBlockFile.cpp +++ b/src/blockfile/ODPCMAliasBlockFile.cpp @@ -348,10 +348,9 @@ bool ODPCMAliasBlockFile::IsSummaryAvailable() const ///Calls write summary, and makes sure it is only done once in a thread-safe fashion. void ODPCMAliasBlockFile::DoWriteSummary() { - mWriteSummaryMutex.Lock(); + ODLocker locker { &mWriteSummaryMutex }; if(!IsSummaryAvailable()) WriteSummary(); - mWriteSummaryMutex.Unlock(); } ///sets the file name the summary info will be saved in. threadsafe. From 40aa70a255adad93686007fda6f32ad105f707de Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 27 Nov 2016 10:08:57 -0500 Subject: [PATCH 23/91] Exception safety for Edit toolbar button presses --- src/toolbars/EditToolBar.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/toolbars/EditToolBar.cpp b/src/toolbars/EditToolBar.cpp index 2d37ec83d..3727e3ea4 100644 --- a/src/toolbars/EditToolBar.cpp +++ b/src/toolbars/EditToolBar.cpp @@ -243,6 +243,10 @@ void EditToolBar::OnButton(wxCommandEvent &event) int id = event.GetId(); // FIXME: Some "SelectAllIfNone()" do not work as expected // due to bugs elsewhere (see: AudacityProject::UpdateMenus() ) + + // Be sure the pop-up happens even if there are exceptions + auto cleanup = finally( [&] { SetButton(false, mButtons[id]); } ); + switch (id) { case ETBCutID: p->SelectAllIfNone(); @@ -299,8 +303,6 @@ void EditToolBar::OnButton(wxCommandEvent &event) break; #endif } - - SetButton(false, mButtons[id]); } void EditToolBar::EnableDisableButtons() From abbe9276f0b0784c9e2475fef9deaad0accab932 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 24 Nov 2016 17:17:37 -0500 Subject: [PATCH 24/91] Exception safety in: CommandManager --- src/commands/CommandManager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/commands/CommandManager.cpp b/src/commands/CommandManager.cpp index 152b18dc7..25d688bb8 100644 --- a/src/commands/CommandManager.cpp +++ b/src/commands/CommandManager.cpp @@ -1127,10 +1127,9 @@ bool CommandManager::FilterKeyEvent(AudacityProject *project, const wxKeyEvent & // rest of the command handling. But, to use the common handler, we // enable them temporarily and then disable them again after handling. // LL: Why do they need to be disabled??? - entry->enabled = true; - bool ret = HandleCommandEntry(entry, NoFlagsSpecifed, NoFlagsSpecifed, &evt); entry->enabled = false; - return ret; + auto cleanup = valueRestorer( entry->enabled, true ); + return HandleCommandEntry(entry, NoFlagsSpecifed, NoFlagsSpecifed, &evt); } // Any other keypresses must be destined for this project window. From 464828d88fa05aff96fc06206d9d6be042484454 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 3 Dec 2016 14:33:10 -0500 Subject: [PATCH 25/91] Exception safety in: batch processing --- src/BatchCommands.cpp | 54 +++++++++++++++++-------------------- src/effects/EffectManager.h | 15 +++++++++++ 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/BatchCommands.cpp b/src/BatchCommands.cpp index 930abdeca..ed16d34d4 100644 --- a/src/BatchCommands.cpp +++ b/src/BatchCommands.cpp @@ -328,7 +328,7 @@ wxString BatchCommands::PromptForParamsFor(const wxString & command, const wxStr wxString res = params; - EffectManager::Get().SetBatchProcessing(ID, true); + auto cleanup = EffectManager::Get().SetBatchProcessing(ID); if (EffectManager::Get().SetEffectParameters(ID, params)) { @@ -338,8 +338,6 @@ wxString BatchCommands::PromptForParamsFor(const wxString & command, const wxStr } } - EffectManager::Get().SetBatchProcessing(ID, false); - return res; } @@ -606,7 +604,7 @@ bool BatchCommands::ApplyEffectCommand(const PluginID & ID, const wxString & com bool res = false; - EffectManager::Get().SetBatchProcessing(ID, true); + auto cleanup = EffectManager::Get().SetBatchProcessing(ID); // transfer the parameters to the effect... if (EffectManager::Get().SetEffectParameters(ID, params)) @@ -617,8 +615,6 @@ bool BatchCommands::ApplyEffectCommand(const PluginID & ID, const wxString & com AudacityProject::OnEffectFlags::kDontRepeatLast); } - EffectManager::Get().SetBatchProcessing(ID, false); - return res; } @@ -652,17 +648,15 @@ bool BatchCommands::ApplyCommand(const wxString & command, const wxString & para bool BatchCommands::ApplyCommandInBatchMode(const wxString & command, const wxString ¶ms) { AudacityProject *project = GetActiveProject(); - bool rc; // enter batch mode... bool prevShowMode = project->GetShowId3Dialog(); + auto cleanup = finally( [&] { + // exit batch mode... + project->SetShowId3Dialog(prevShowMode); + } ); - rc = ApplyCommand( command, params ); - - // exit batch mode... - project->SetShowId3Dialog(prevShowMode); - - return rc; + return ApplyCommand( command, params ); } // ApplyChain returns true on success, false otherwise. @@ -670,29 +664,31 @@ bool BatchCommands::ApplyCommandInBatchMode(const wxString & command, const wxSt bool BatchCommands::ApplyChain(const wxString & filename) { mFileName = filename; - unsigned int i; - bool res = true; + + AudacityProject *proj = GetActiveProject(); + bool res = false; + auto cleanup = finally( [&] { + if (!res) { + if(proj) { + // Chain failed or was cancelled; revert to the previous state + proj->RollbackState(); + } + } + } ); mAbort = false; - for (i = 0; i < mCommandChain.GetCount(); i++) { - if (!ApplyCommandInBatchMode(mCommandChain[i], mParamsChain[i]) || mAbort) { - res = false; + size_t i = 0; + for (; i < mCommandChain.GetCount(); i++) { + if (!ApplyCommandInBatchMode(mCommandChain[i], mParamsChain[i]) || mAbort) break; - } } + res = (i == mCommandChain.GetCount()); + if (!res) + return false; + mFileName.Empty(); - AudacityProject *proj = GetActiveProject(); - - if (!res) - { - if(proj) { - // Chain failed or was cancelled; revert to the previous state - proj->RollbackState(); - } - return false; - } // Chain was successfully applied; save the NEW project state wxString longDesc, shortDesc; diff --git a/src/effects/EffectManager.h b/src/effects/EffectManager.h index eb35ceb81..6a7c32f58 100644 --- a/src/effects/EffectManager.h +++ b/src/effects/EffectManager.h @@ -91,7 +91,22 @@ public: bool HasPresets(const PluginID & ID); wxString GetPreset(const PluginID & ID, const wxString & params, wxWindow * parent); wxString GetDefaultPreset(const PluginID & ID); + +private: void SetBatchProcessing(const PluginID & ID, bool start); + struct UnsetBatchProcessing { + PluginID mID; + void operator () (EffectManager *p) const + { if(p) p->SetBatchProcessing(mID, false); } + }; + using BatchProcessingScope = + std::unique_ptr< EffectManager, UnsetBatchProcessing >; +public: + // RAII for the function above + BatchProcessingScope SetBatchProcessing(const PluginID &ID) + { + SetBatchProcessing(ID, true); return BatchProcessingScope{ this, {ID} }; + } /** Allow effects to disable saving the state at run time */ void SetSkipStateFlag(bool flag); From 48459404a5e82afb54a0fdc225f5cb90400f3499 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 24 Dec 2016 12:37:46 -0500 Subject: [PATCH 26/91] Exception safety in: general exporting routines --- src/Project.cpp | 34 +++++++++++---------- src/export/Export.cpp | 32 ++++++++++++-------- src/export/ExportMultiple.cpp | 56 ++++++++++++++++++++--------------- 3 files changed, 69 insertions(+), 53 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index fdda5a74d..355a6e3b7 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -3914,6 +3914,23 @@ bool AudacityProject::Save(bool overwrite /* = true */ , pWaveTrack = (WaveTrack*)pTrack; pSavedTrackList.Add(mTrackFactory->DuplicateWaveTrack(*pWaveTrack)); } + auto cleanup = finally( [&] { + // Restore the saved track states and clean up. + TrackListIterator savedTrackIter(&pSavedTrackList); + Track *pSavedTrack; + for (pTrack = iter.First(), pSavedTrack = savedTrackIter.First(); + ((pTrack != NULL) && (pSavedTrack != NULL)); + pTrack = iter.Next(), pSavedTrack = savedTrackIter.Next()) + { + pWaveTrack = (WaveTrack*)pTrack; + pWaveTrack->SetSelected(pSavedTrack->GetSelected()); + pWaveTrack->SetMute(pSavedTrack->GetMute()); + pWaveTrack->SetSolo(pSavedTrack->GetSolo()); + + pWaveTrack->SetGain(((WaveTrack*)pSavedTrack)->GetGain()); + pWaveTrack->SetPan(((WaveTrack*)pSavedTrack)->GetPan()); + } + } ); if (numWaveTracks == 0) // Nothing to save compressed => success. Delete the copies and go. @@ -3923,6 +3940,7 @@ bool AudacityProject::Save(bool overwrite /* = true */ , for (pTrack = iter.First(); pTrack != NULL; pTrack = iter.Next()) { pWaveTrack = (WaveTrack*)pTrack; + pWaveTrack->SetSelected(false); pWaveTrack->SetMute(false); pWaveTrack->SetSolo(false); @@ -3968,22 +3986,6 @@ bool AudacityProject::Save(bool overwrite /* = true */ , } } - // Restore the saved track states and clean up. - TrackListIterator savedTrackIter(&pSavedTrackList); - Track *pSavedTrack; - for (pTrack = iter.First(), pSavedTrack = savedTrackIter.First(); - ((pTrack != NULL) && (pSavedTrack != NULL)); - pTrack = iter.Next(), pSavedTrack = savedTrackIter.Next()) - { - pWaveTrack = (WaveTrack*)pTrack; - pWaveTrack->SetSelected(pSavedTrack->GetSelected()); - pWaveTrack->SetMute(pSavedTrack->GetMute()); - pWaveTrack->SetSolo(pSavedTrack->GetSolo()); - - pWaveTrack->SetGain(((WaveTrack*)pSavedTrack)->GetGain()); - pWaveTrack->SetPan(((WaveTrack*)pSavedTrack)->GetPan()); - } - return bSuccess; } #endif diff --git a/src/export/Export.cpp b/src/export/Export.cpp index 71598ad9f..40812e807 100644 --- a/src/export/Export.cpp +++ b/src/export/Export.cpp @@ -827,7 +827,22 @@ bool Exporter::ExportTracks() ::wxRenameFile(mActualName.GetFullPath(), mFilename.GetFullPath()); } - auto success = mPlugins[mFormat]->Export(mProject, + bool success = false; + + auto cleanup = finally( [&] { + if (mActualName != mFilename) { + // Remove backup + if ( success ) + ::wxRemoveFile(mFilename.GetFullPath()); + else { + // Restore original, if needed + ::wxRemoveFile(mActualName.GetFullPath()); + ::wxRenameFile(mFilename.GetFullPath(), mActualName.GetFullPath()); + } + } + } ); + + auto result = mPlugins[mFormat]->Export(mProject, mChannels, mActualName.GetFullPath(), mSelectedOnly, @@ -837,19 +852,10 @@ bool Exporter::ExportTracks() NULL, mSubFormat); - if (mActualName != mFilename) { - // Remove backup - if (success == ProgressResult::Success || success == ProgressResult::Stopped) { - ::wxRemoveFile(mFilename.GetFullPath()); - } - else { - // Restore original, if needed - ::wxRemoveFile(mActualName.GetFullPath()); - ::wxRenameFile(mFilename.GetFullPath(), mActualName.GetFullPath()); - } - } + success = + result == ProgressResult::Success || result == ProgressResult::Stopped; - return (success == ProgressResult::Success || success == ProgressResult::Stopped); + return success; } void Exporter::CreateUserPaneCallback(wxWindow *parent, wxUIntPtr userdata) diff --git a/src/export/ExportMultiple.cpp b/src/export/ExportMultiple.cpp index edfe2db2f..0c1dddb21 100644 --- a/src/export/ExportMultiple.cpp +++ b/src/export/ExportMultiple.cpp @@ -566,21 +566,11 @@ void ExportMultiple::OnExport(wxCommandEvent& WXUNUSED(event)) } // bool overwrite = mOverwrite->GetValue(); - ProgressResult ok; + ProgressResult ok = ProgressResult::Failed; mExported.Empty(); - if (mLabel->GetValue()) { - ok = ExportMultipleByLabel(mByName->GetValue() || mByNumberAndName->GetValue(), - mPrefix->GetValue(), - mByNumberAndName->GetValue()); - } - else { - ok = ExportMultipleByTrack(mByName->GetValue() || mByNumberAndName->GetValue(), - mPrefix->GetValue(), - mByNumberAndName->GetValue()); - } - // Give 'em the result + auto cleanup = finally( [&] { wxString msg; msg.Printf( @@ -598,12 +588,26 @@ void ExportMultiple::OnExport(wxCommandEvent& WXUNUSED(event)) FileList += mExported[i]; FileList += '\n'; } - // This results dialog is a child of this dialog. - HelpSystem::ShowInfoDialog( this, - _("Export Multiple"), - msg, - FileList, - 450,400); + + CallAfter( [=] { + // This results dialog is a child of this dialog. + HelpSystem::ShowInfoDialog( this, + _("Export Multiple"), + msg, + FileList, + 450,400); + } ); + } ); + + if (mLabel->GetValue()) { + ok = ExportMultipleByLabel(mByName->GetValue() || mByNumberAndName->GetValue(), + mPrefix->GetValue(), + mByNumberAndName->GetValue()); + } + else { + ok = ExportMultipleByTrack(mByName->GetValue() || mByNumberAndName->GetValue(), + mPrefix->GetValue(), + mByNumberAndName->GetValue()); } if (ok == ProgressResult::Success || ok == ProgressResult::Stopped) { @@ -797,6 +801,12 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName, } } + auto cleanup = finally( [&] { + // Restore the selection states + for (auto pTrack : selected) + pTrack->SetSelected(true); + } ); + /* Examine all tracks in turn, collecting export information */ for (tr = iter.First(mTracks); tr != NULL; tr = iter.Next()) { @@ -932,10 +942,6 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName, } - // Restore the selection states - for (auto pTrack : selected) - pTrack->SetSelected(true); - return ok ; } @@ -950,8 +956,10 @@ ProgressResult ExportMultiple::DoExport(unsigned channels, wxLogDebug(wxT("Doing multiple Export: File name \"%s\""), (inName.GetFullName()).c_str()); wxLogDebug(wxT("Channels: %i, Start: %lf, End: %lf "), channels, t0, t1); - if (selectedOnly) wxLogDebug(wxT("Selected Region Only")); - else wxLogDebug(wxT("Whole Project")); + if (selectedOnly) + wxLogDebug(wxT("Selected Region Only")); + else + wxLogDebug(wxT("Whole Project")); if (mOverwrite->GetValue()) { // Make sure we don't overwrite (corrupt) alias files From 0c8bedc59a65768100de93343e23f1e2de786746 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 24 Dec 2016 08:57:27 -0500 Subject: [PATCH 27/91] Exception safety in: subclasses of ExportPlugin; and more error checking --- src/FileIO.h | 2 ++ src/export/ExportCL.cpp | 22 +++++++++---- src/export/ExportFFmpeg.cpp | 20 +++++++---- src/export/ExportFLAC.cpp | 66 ++++++++++++++++++++++--------------- src/export/ExportMP2.cpp | 16 +++++---- src/export/ExportMP3.cpp | 43 +++++++++++++----------- src/export/ExportOGG.cpp | 39 +++++++++++++--------- src/export/ExportPCM.cpp | 43 +++++++++++++++--------- 8 files changed, 156 insertions(+), 95 deletions(-) diff --git a/src/FileIO.h b/src/FileIO.h index b4967513e..5200503df 100644 --- a/src/FileIO.h +++ b/src/FileIO.h @@ -26,6 +26,8 @@ class FileIO public: FileIO(const wxString & name, FileIOMode mode); + + // Calls Close() ~FileIO(); bool IsOpened(); diff --git a/src/export/ExportCL.cpp b/src/export/ExportCL.cpp index 2132daf51..e1c41230c 100644 --- a/src/export/ExportCL.cpp +++ b/src/export/ExportCL.cpp @@ -354,14 +354,19 @@ ProgressResult ExportCL::Export(AudacityProject *project, // Kick off the command ExportCLProcess process(&output); - rc = wxExecute(cmd, wxEXEC_ASYNC, &process); + { #if defined(__WXMSW__) - if (!opath.IsEmpty()) { - wxSetEnv(wxT("PATH"),opath.c_str()); - } + auto cleanup = finally( [&] { + if (!opath.IsEmpty()) { + wxSetEnv(wxT("PATH"),opath.c_str()); + } + } ); #endif + rc = wxExecute(cmd, wxEXEC_ASYNC, &process); + } + if (!rc) { wxMessageBox(wxString::Format(_("Cannot export audio to %s"), fName.c_str())); @@ -435,6 +440,11 @@ ProgressResult ExportCL::Export(AudacityProject *project, auto updateResult = ProgressResult::Success; { + auto closeIt = finally ( [&] { + // Should make the process die, before propagating any exception + process.CloseOutput(); + } ); + // Prepare the progress display ProgressDialog progress(_("Export"), selectionOnly ? @@ -475,6 +485,7 @@ ProgressResult ExportCL::Export(AudacityProject *project, while (bytes > 0) { os->Write(mixed, bytes); if (!os->IsOk()) { + updateResult = ProgressResult::Cancelled; break; } bytes -= os->LastWrite(); @@ -487,9 +498,6 @@ ProgressResult ExportCL::Export(AudacityProject *project, // Done with the progress display } - // Should make the process die - process.CloseOutput(); - // Wait for process to terminate while (process.IsActive()) { wxMilliSleep(10); diff --git a/src/export/ExportFFmpeg.cpp b/src/export/ExportFFmpeg.cpp index 9ec87dd37..9b215a3bf 100644 --- a/src/export/ExportFFmpeg.cpp +++ b/src/export/ExportFFmpeg.cpp @@ -165,7 +165,7 @@ private: unsigned mChannels{}; bool mSupportsUTF8{}; - // Smart pointer fields, their order is the reverse in which they are reset in Finalize(): + // Smart pointer fields, their order is the reverse in which they are reset in FreeResources(): AVFifoBufferHolder mEncAudioFifo; // FIFO to write incoming audio samples into AVMallocHolder mEncAudioFifoOutBuf; // buffer to read _out_ of the FIFO into AVFormatContextHolder mEncFormatCtx; // libavformat's context for our output file @@ -357,7 +357,7 @@ bool ExportFFmpeg::Init(const char *shortname, AudacityProject *project, const T return false; } - // Only now, we can keep all the resources until Finalize(). + // Only now, we can keep all the resources until after Finalize(). // Cancel the local cleanup. cleanup.release(); @@ -737,7 +737,6 @@ bool ExportFFmpeg::Finalize() // Write any file trailers. av_write_trailer(mEncFormatCtx.get()); - FreeResources(); return true; } @@ -774,7 +773,8 @@ bool ExportFFmpeg::EncodeAudioFrame(int16_t *pFrame, size_t frameSize) // Put the raw audio samples into the FIFO. ret = av_fifo_generic_write(mEncAudioFifo.get(), pRawSamples, nBytesToWrite,NULL); - wxASSERT(ret == nBytesToWrite); + if(ret != nBytesToWrite) + return false; if (nAudioFrameSizeOut > mEncAudioFifoOutBufSiz) { wxMessageBox(wxString::Format(_("FFmpeg : ERROR - nAudioFrameSizeOut too large.")), @@ -853,11 +853,13 @@ ProgressResult ExportFFmpeg::Export(AudacityProject *project, if (mSubFormat == FMT_OTHER) shortname = gPrefs->Read(wxT("/FileFormats/FFmpegFormat"),wxT("matroska")); ret = Init(shortname.mb_str(),project, metadata, subformat); + auto cleanup = finally ( [&] { FreeResources(); } ); if (!ret) return ProgressResult::Cancelled; size_t pcmBufferSize = 1024; + const WaveTrackConstArray waveTracks = tracks->GetWaveTrackConstArray(selectionOnly, false); auto mixer = CreateMixer(waveTracks, @@ -881,13 +883,19 @@ ProgressResult ExportFFmpeg::Export(AudacityProject *project, short *pcmBuffer = (short *)mixer->GetBuffer(); - EncodeAudioFrame(pcmBuffer, (pcmNumSamples)*sizeof(int16_t)*mChannels); + if (!EncodeAudioFrame( + pcmBuffer, (pcmNumSamples)*sizeof(int16_t)*mChannels)) { + updateResult = ProgressResult::Cancelled; + break; + } updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0); } } - Finalize(); + if ( updateResult != ProgressResult::Cancelled ) + if ( !Finalize() ) + return ProgressResult::Cancelled; return updateResult; } diff --git a/src/export/ExportFLAC.cpp b/src/export/ExportFLAC.cpp index 2f427d92c..b3d376990 100644 --- a/src/export/ExportFLAC.cpp +++ b/src/export/ExportFLAC.cpp @@ -204,6 +204,7 @@ private: bool GetMetadata(AudacityProject *project, const Tags *tags); + // Should this be a stack variable instead in Export? FLAC__StreamMetadataHandle mMetadata; }; @@ -262,6 +263,10 @@ ProgressResult ExportFLAC::Export(AudacityProject *project, encoder.set_metadata(&p, 1); } + auto cleanup1 = finally( [&] { + mMetadata.reset(); // need this? + } ); + sampleFormat format; if (bitDepthPref == wxT("24")) { format = int24Sample; @@ -312,6 +317,13 @@ ProgressResult ExportFLAC::Export(AudacityProject *project, mMetadata.reset(); + auto cleanup2 = finally( [&] { +#ifndef LEGACY_FLAC + f.Detach(); // libflac closes the file +#endif + encoder.finish(); + } ); + const WaveTrackConstArray waveTracks = tracks->GetWaveTrackConstArray(selectionOnly, false); auto mixer = CreateMixer(waveTracks, @@ -322,38 +334,40 @@ ProgressResult ExportFLAC::Export(AudacityProject *project, ArraysOf tmpsmplbuf{ numChannels, SAMPLES_PER_RUN, true }; - { - ProgressDialog progress(wxFileName(fName).GetName(), - selectionOnly ? - _("Exporting the selected audio as FLAC") : - _("Exporting the entire project as FLAC")); + ProgressDialog progress(wxFileName(fName).GetName(), + selectionOnly ? + _("Exporting the selected audio as FLAC") : + _("Exporting the entire project as FLAC")); - while (updateResult == ProgressResult::Success) { - auto samplesThisRun = mixer->Process(SAMPLES_PER_RUN); - if (samplesThisRun == 0) { //stop encoding - break; - } - else { - for (size_t i = 0; i < numChannels; i++) { - samplePtr mixed = mixer->GetBuffer(i); - if (format == int24Sample) { - for (decltype(samplesThisRun) j = 0; j < samplesThisRun; j++) { - tmpsmplbuf[i][j] = ((int *)mixed)[j]; - } - } - else { - for (decltype(samplesThisRun) j = 0; j < samplesThisRun; j++) { - tmpsmplbuf[i][j] = ((short *)mixed)[j]; - } + while (updateResult == ProgressResult::Success) { + auto samplesThisRun = mixer->Process(SAMPLES_PER_RUN); + if (samplesThisRun == 0) { //stop encoding + break; + } + else { + for (size_t i = 0; i < numChannels; i++) { + samplePtr mixed = mixer->GetBuffer(i); + if (format == int24Sample) { + for (decltype(samplesThisRun) j = 0; j < samplesThisRun; j++) { + tmpsmplbuf[i][j] = ((int *)mixed)[j]; + } + } + else { + for (decltype(samplesThisRun) j = 0; j < samplesThisRun; j++) { + tmpsmplbuf[i][j] = ((short *)mixed)[j]; } } - encoder.process(reinterpret_cast(tmpsmplbuf.get()), samplesThisRun); } - updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0); + if (! encoder.process( + reinterpret_cast( tmpsmplbuf.get() ), + samplesThisRun) ) { + updateResult = ProgressResult::Cancelled; + break; + } } - f.Detach(); // libflac closes the file - encoder.finish(); } + if (updateResult == ProgressResult::Success) + updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0); return updateResult; } diff --git a/src/export/ExportMP2.cpp b/src/export/ExportMP2.cpp index 1de353290..1bc651f0c 100644 --- a/src/export/ExportMP2.cpp +++ b/src/export/ExportMP2.cpp @@ -217,6 +217,7 @@ ProgressResult ExportMP2::Export(AudacityProject *project, twolame_options *encodeOptions; encodeOptions = twolame_init(); + auto cleanup = finally( [&] { twolame_close(&encodeOptions); } ); twolame_set_in_samplerate(encodeOptions, (int)(rate + 0.5)); twolame_set_out_samplerate(encodeOptions, (int)(rate + 0.5)); @@ -227,7 +228,6 @@ ProgressResult ExportMP2::Export(AudacityProject *project, { wxMessageBox(_("Cannot export MP2 with this sample rate and bit rate"), _("Error"), wxICON_STOP); - twolame_close(&encodeOptions); return ProgressResult::Cancelled; } @@ -238,7 +238,6 @@ ProgressResult ExportMP2::Export(AudacityProject *project, FileIO outFile(fName, FileIO::Output); if (!outFile.IsOpened()) { wxMessageBox(_("Unable to open target file for writing")); - twolame_close(&encodeOptions); return ProgressResult::Cancelled; } @@ -288,6 +287,11 @@ ProgressResult ExportMP2::Export(AudacityProject *project, mp2Buffer.get(), mp2BufferSize); + if (mp2BufferNumBytes < 0) { + updateResult = ProgressResult::Cancelled; + break; + } + outFile.Write(mp2Buffer.get(), mp2BufferNumBytes); updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0); @@ -302,15 +306,11 @@ ProgressResult ExportMP2::Export(AudacityProject *project, if (mp2BufferNumBytes > 0) outFile.Write(mp2Buffer.get(), mp2BufferNumBytes); - twolame_close(&encodeOptions); - /* Write ID3 tag if it was supposed to be at the end of the file */ if (id3len && endOfFile) outFile.Write(id3buffer.get(), id3len); - /* Close file */ - outFile.Close(); return updateResult; @@ -328,7 +328,9 @@ struct id3_tag_deleter { using id3_tag_holder = std::unique_ptr; // returns buffer len; caller frees -int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), ArrayOf &buffer, bool *endOfFile, const Tags *tags) +int ExportMP2::AddTags( + AudacityProject * WXUNUSED(project), ArrayOf< char > &buffer, + bool *endOfFile, const Tags *tags) { #ifdef USE_LIBID3TAG id3_tag_holder tp { id3_tag_new() }; diff --git a/src/export/ExportMP3.cpp b/src/export/ExportMP3.cpp index a51047f44..64cc96bb2 100644 --- a/src/export/ExportMP3.cpp +++ b/src/export/ExportMP3.cpp @@ -1809,6 +1809,9 @@ ProgressResult ExportMP3::Export(AudacityProject *project, long bytes; size_t bufferSize = std::max(0, exporter.GetOutBufferSize()); + if (bufferSize == 0) + return ProgressResult::Cancelled; + ArrayOf buffer{ bufferSize }; wxASSERT(buffer); @@ -1873,6 +1876,7 @@ ProgressResult ExportMP3::Export(AudacityProject *project, wxString msg; msg.Printf(_("Error %ld returned from MP3 encoder"), bytes); wxMessageBox(msg); + updateResult = ProgressResult::Cancelled; break; } @@ -1882,28 +1886,29 @@ ProgressResult ExportMP3::Export(AudacityProject *project, } } - bytes = exporter.FinishStream(buffer.get()); + if ( updateResult != ProgressResult::Cancelled ) { + bytes = exporter.FinishStream(buffer.get()); - if (bytes) { - outFile.Write(buffer.get(), bytes); + if (bytes > 0) { + outFile.Write(buffer.get(), bytes); + } + + // Write ID3 tag if it was supposed to be at the end of the file + if (id3len > 0 && endOfFile) { + outFile.Write(id3buffer.get(), id3len); + } + + // Always write the info (Xing/Lame) tag. Until we stop supporting Lame + // versions before 3.98, we must do this after the MP3 file has been + // closed. + // + // Also, if beWriteInfoTag() is used, mGF will no longer be valid after + // this call, so do not use it. + exporter.PutInfoTag(outFile, pos); + + outFile.Close(); } - // Write ID3 tag if it was supposed to be at the end of the file - if (id3len && endOfFile) { - outFile.Write(id3buffer.get(), id3len); - } - - // Always write the info (Xing/Lame) tag. Until we stop supporting Lame - // versions before 3.98, we must do this after the MP3 file has been - // closed. - // - // Also, if beWriteInfoTag() is used, mGF will no longer be valid after - // this call, so do not use it. - exporter.PutInfoTag(outFile, pos); - - // Close the file - outFile.Close(); - return updateResult; } diff --git a/src/export/ExportOGG.cpp b/src/export/ExportOGG.cpp index 838b2486f..12f6e951e 100644 --- a/src/export/ExportOGG.cpp +++ b/src/export/ExportOGG.cpp @@ -193,6 +193,15 @@ ProgressResult ExportOGG::Export(AudacityProject *project, vorbis_dsp_state dsp; vorbis_block block; + auto cleanup = finally( [&] { + ogg_stream_clear(&stream); + + vorbis_block_clear(&block); + vorbis_dsp_clear(&dsp); + vorbis_info_clear(&info); + vorbis_comment_clear(&comment); + } ); + // Encoding setup vorbis_info_init(&info); vorbis_encode_init_vbr(&info, numChannels, (int)(rate + 0.5), quality); @@ -257,9 +266,10 @@ ProgressResult ExportOGG::Export(AudacityProject *project, float **vorbis_buffer = vorbis_analysis_buffer(&dsp, SAMPLES_PER_RUN); auto samplesThisRun = mixer->Process(SAMPLES_PER_RUN); + int err; if (samplesThisRun == 0) { // Tell the library that we wrote 0 bytes - signalling the end. - vorbis_analysis_wrote(&dsp, 0); + err = vorbis_analysis_wrote(&dsp, 0); } else { @@ -269,7 +279,7 @@ ProgressResult ExportOGG::Export(AudacityProject *project, } // tell the encoder how many samples we have - vorbis_analysis_wrote(&dsp, samplesThisRun); + err = vorbis_analysis_wrote(&dsp, samplesThisRun); } // I don't understand what this call does, so here is the comment @@ -278,22 +288,23 @@ ProgressResult ExportOGG::Export(AudacityProject *project, // vorbis does some data preanalysis, then divvies up blocks // for more involved (potentially parallel) processing. Get // a single block for encoding now - while (vorbis_analysis_blockout(&dsp, &block) == 1) { + while (!err && vorbis_analysis_blockout(&dsp, &block) == 1) { // analysis, assume we want to use bitrate management - vorbis_analysis(&block, NULL); - vorbis_bitrate_addblock(&block); + err = vorbis_analysis(&block, NULL); + if (!err) + err = vorbis_bitrate_addblock(&block); - while (vorbis_bitrate_flushpacket(&dsp, &packet)) { + while (!err && vorbis_bitrate_flushpacket(&dsp, &packet)) { // add the packet to the bitstream - ogg_stream_packetin(&stream, &packet); + err = ogg_stream_packetin(&stream, &packet); // From vorbis-tools-1.0/oggenc/encode.c: // If we've gone over a page boundary, we can do actual output, // so do so (for however many pages are available). - while (!eos) { + while (!err && !eos) { int result = ogg_stream_pageout(&stream, &page); if (!result) { break; @@ -309,17 +320,15 @@ ProgressResult ExportOGG::Export(AudacityProject *project, } } + if (err) { + updateResult = ProgressResult::Cancelled; + break; + } + updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0); } } - ogg_stream_clear(&stream); - - vorbis_block_clear(&block); - vorbis_dsp_clear(&dsp); - vorbis_info_clear(&info); - vorbis_comment_clear(&comment); - outFile.Close(); return updateResult; diff --git a/src/export/ExportPCM.cpp b/src/export/ExportPCM.cpp index e9df03804..5fae06093 100644 --- a/src/export/ExportPCM.cpp +++ b/src/export/ExportPCM.cpp @@ -331,7 +331,7 @@ private: ArrayOf AdjustString(const wxString & wxStr, int sf_format); bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format); - void AddID3Chunk(wxString fName, const Tags *tags, int sf_format); + bool AddID3Chunk(wxString fName, const Tags *tags, int sf_format); }; @@ -516,6 +516,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project, _("Error while writing %s file (disk full?).\nLibsndfile says \"%s\""), formatStr.c_str(), wxString::FromAscii(buffer2).c_str())); + updateResult = ProgressResult::Cancelled; break; } @@ -534,7 +535,8 @@ ProgressResult ExportPCM::Export(AudacityProject *project, if (((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) || ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)) - AddID3Chunk(fName, metadata, sf_format); + if (!AddID3Chunk(fName, metadata, sf_format) ) + return ProgressResult::Cancelled; return updateResult; } @@ -699,7 +701,7 @@ struct id3_tag_deleter { }; using id3_tag_holder = std::unique_ptr; -void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format) +bool ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format) { #ifdef USE_LIBID3TAG id3_tag_holder tp { id3_tag_new() }; @@ -784,12 +786,12 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format) len = id3_tag_render(tp.get(), 0); if (len == 0) - return; + return true; if ((len % 2) != 0) len++; // Length must be even. ArrayOf buffer { len, true }; if (buffer == NULL) - return; + return false; // Zero all locations, for ending odd UTF16 content // correctly, i.e., two '\0's at the end. @@ -797,33 +799,44 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format) id3_tag_render(tp.get(), buffer.get()); wxFFile f(fName, wxT("r+b")); - // FIXME: TRAP_ERR wxFFILE ops in Export PCM ID3 could fail. if (f.IsOpened()) { wxUint32 sz; sz = (wxUint32) len; - f.SeekEnd(0); + if (!f.SeekEnd(0)) + return false; if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) - f.Write("id3 ", 4); // Must be lower case for foobar2000. + { + if (4 != f.Write("id3 ", 4))// Must be lower case for foobar2000. + return false ; + } else { - f.Write("ID3 ", 4); + if (4 != f.Write("ID3 ", 4)) + return false; sz = wxUINT32_SWAP_ON_LE(sz); } - f.Write(&sz, 4); + if (4 != f.Write(&sz, 4)) + return false; - f.Write(buffer.get(), len); + if (len != f.Write(buffer.get(), len)) + return false; sz = (wxUint32) f.Tell() - 8; if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) sz = wxUINT32_SWAP_ON_LE(sz); - f.Seek(4); - f.Write(&sz, 4); + if (!f.Seek(4)) + return false; + if (4 != f.Write(&sz, 4)) + return false; - f.Close(); + if (!f.Close()) + return false; } + else + return false; #endif - return; + return true; } wxWindow *ExportPCM::OptionsCreate(wxWindow *parent, int format) From 0bb6a3d971f0957cedc869a271c51415d6bdf719 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 20 Dec 2016 16:21:03 -0500 Subject: [PATCH 28/91] Exception safety in: importing functions... ... Side effects on preferences may persist even after errors. --- src/Menus.cpp | 17 ++++++---- src/Project.cpp | 75 +++++++++++++++---------------------------- src/import/Import.cpp | 22 +------------ 3 files changed, 38 insertions(+), 76 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 52a3b0e9c..413603bc3 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -5767,6 +5767,9 @@ void AudacityProject::OnImport() return; } + // PRL: This affects FFmpegImportPlugin::Open which resets the preference + // to false. Should it also be set to true on other paths that reach + // AudacityProject::Import ? gPrefs->Write(wxT("/NewImportingSession"), true); //sort selected files by OD status. Load non OD first so user can edit asap. @@ -5774,6 +5777,14 @@ void AudacityProject::OnImport() selectedFiles.Sort(CompareNoCaseFileName); ODManager::Pauser pauser; + auto cleanup = finally( [&] { + gPrefs->Write(wxT("/LastOpenType"),wxT("")); + + gPrefs->Flush(); + + HandleResize(); // Adjust scrollers for NEW track sizes. + } ); + for (size_t ff = 0; ff < selectedFiles.GetCount(); ff++) { wxString fileName = selectedFiles[ff]; @@ -5782,12 +5793,6 @@ void AudacityProject::OnImport() Import(fileName); } - - gPrefs->Write(wxT("/LastOpenType"),wxT("")); - - gPrefs->Flush(); - - HandleResize(); // Adjust scrollers for NEW track sizes. } void AudacityProject::OnImportLabels() diff --git a/src/Project.cpp b/src/Project.cpp index 355a6e3b7..84ff368ea 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -452,17 +452,16 @@ public: return GuardedCall< bool > ( [&] { //sort by OD non OD. load Non OD first so user can start editing asap. wxArrayString sortednames(filenames); + sortednames.Sort(CompareNoCaseFileName); ODManager::Pauser pauser; - sortednames.Sort(CompareNoCaseFileName); + auto cleanup = finally( [&] { + mProject->HandleResize(); // Adjust scrollers for NEW track sizes. + } ); - for (unsigned int i = 0; i < sortednames.GetCount(); i++) { - - mProject->Import(sortednames[i]); - } - - mProject->HandleResize(); // Adjust scrollers for NEW track sizes. + for (const auto &name : sortednames) + mProject->Import(name); return true; } ); @@ -4081,55 +4080,33 @@ bool AudacityProject::Import(const wxString &fileName, WaveTrackArray* pTrackArr TrackHolders newTracks; wxString errorMessage = wxEmptyString; - // Backup Tags, before the import. Be prepared to roll back changes. - struct TempTags { - TempTags(std::shared_ptr & pTags_) - : pTags(pTags_) - { - oldTags = pTags; - if (oldTags) - pTags = oldTags->Duplicate(); - } + { + // Backup Tags, before the import. Be prepared to roll back changes. + auto cleanup = valueRestorer( mTags, + mTags ? mTags->Duplicate() : decltype(mTags){} ); - ~TempTags() - { - if (oldTags) { - // roll back - pTags = oldTags; - } - } - - void Commit() - { - oldTags.reset(); - } - - std::shared_ptr & pTags; - std::shared_ptr oldTags; - }; - TempTags tempTags(mTags); - - bool success = Importer::Get().Import(fileName, + bool success = Importer::Get().Import(fileName, GetTrackFactory(), newTracks, mTags.get(), errorMessage); - if (!errorMessage.IsEmpty()) { -// Version that goes to internet... -// ShowErrorDialog(this, _("Error Importing"), -// errorMessage, wxT("http://audacity.sourceforge.net/help/faq?s=files&i=wma-proprietary")); -// Version that looks locally for the text. - ShowErrorDialog(this, _("Error Importing"), - errorMessage, wxT("innerlink:wma-proprietary")); + if (!errorMessage.IsEmpty()) { + // Version that goes to internet... + // ShowErrorDialog(this, _("Error Importing"), + // errorMessage, wxT("http://audacity.sourceforge.net/help/faq?s=files&i=wma-proprietary")); + // Version that looks locally for the text. + ShowErrorDialog(this, _("Error Importing"), + errorMessage, wxT("innerlink:wma-proprietary")); + } + if (!success) + return false; + + wxGetApp().AddFileToHistory(fileName); + + // no more errors, commit + cleanup.release(); } - if (!success) - return false; - - wxGetApp().AddFileToHistory(fileName); - - // no more errors - tempTags.Commit(); // for LOF ("list of files") files, do not import the file as if it // were an audio file itself diff --git a/src/import/Import.cpp b/src/import/Import.cpp index 57b6e8459..07dbc2c68 100644 --- a/src/import/Import.cpp +++ b/src/import/Import.cpp @@ -336,7 +336,7 @@ bool Importer::Import(const wxString &fName, wxString &errorMessage) { AudacityProject *pProj = GetActiveProject(); - pProj->mbBusyImporting = true; + auto cleanup = valueRestorer( pProj->mbBusyImporting, true ); wxString extension = fName.AfterLast(wxT('.')); @@ -509,7 +509,6 @@ bool Importer::Import(const wxString &fName, if (ImportDlg.ShowModal() == wxID_CANCEL) { - pProj->mbBusyImporting = false; return false; } } @@ -524,21 +523,18 @@ bool Importer::Import(const wxString &fName, // LOF ("list-of-files") has different semantics if (extension.IsSameAs(wxT("lof"), false)) { - pProj->mbBusyImporting = false; return true; } if (tracks.size() > 0) { // success! - pProj->mbBusyImporting = false; return true; } } if (res == ProgressResult::Cancelled || res == ProgressResult::Failed) { - pProj->mbBusyImporting = false; return false; } @@ -560,7 +556,6 @@ bool Importer::Import(const wxString &fName, errorMessage.Printf(_("This version of Audacity was not compiled with %s support."), unusableImportPlugin-> GetPluginFormatDescription().c_str()); - pProj->mbBusyImporting = false; return false; } } @@ -571,7 +566,6 @@ bool Importer::Import(const wxString &fName, // MIDI files must be imported, not opened if ((extension.IsSameAs(wxT("midi"), false))||(extension.IsSameAs(wxT("mid"), false))) { errorMessage.Printf(_("\"%s\" \nis a MIDI file, not an audio file. \nAudacity cannot open this type of file for playing, but you can\nedit it by clicking File > Import > MIDI."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } #endif @@ -582,87 +576,74 @@ bool Importer::Import(const wxString &fName, if (extension.IsSameAs(wxT("cda"), false)) { /* i18n-hint: %s will be the filename */ errorMessage.Printf(_("\"%s\" is an audio CD track. \nAudacity cannot open audio CDs directly. \nExtract (rip) the CD tracks to an audio format that \nAudacity can import, such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // playlist type files if ((extension.IsSameAs(wxT("m3u"), false))||(extension.IsSameAs(wxT("ram"), false))||(extension.IsSameAs(wxT("pls"), false))) { errorMessage.Printf(_("\"%s\" is a playlist file. \nAudacity cannot open this file because it only contains links to other files. \nYou may be able to open it in a text editor and download the actual audio files."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } //WMA files of various forms if ((extension.IsSameAs(wxT("wma"), false))||(extension.IsSameAs(wxT("asf"), false))) { errorMessage.Printf(_("\"%s\" is a Windows Media Audio file. \nAudacity cannot open this type of file due to patent restrictions. \nYou need to convert it to a supported audio format, such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } //AAC files of various forms (probably not encrypted) if ((extension.IsSameAs(wxT("aac"), false))||(extension.IsSameAs(wxT("m4a"), false))||(extension.IsSameAs(wxT("m4r"), false))||(extension.IsSameAs(wxT("mp4"), false))) { errorMessage.Printf(_("\"%s\" is an Advanced Audio Coding file. \nAudacity cannot open this type of file. \nYou need to convert it to a supported audio format, such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // encrypted itunes files if ((extension.IsSameAs(wxT("m4p"), false))) { errorMessage.Printf(_("\"%s\" is an encrypted audio file. \nThese typically are from an online music store. \nAudacity cannot open this type of file due to the encryption. \nTry recording the file into Audacity, or burn it to audio CD then \nextract the CD track to a supported audio format such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // Real Inc. files of various sorts if ((extension.IsSameAs(wxT("ra"), false))||(extension.IsSameAs(wxT("rm"), false))||(extension.IsSameAs(wxT("rpm"), false))) { errorMessage.Printf(_("\"%s\" is a RealPlayer media file. \nAudacity cannot open this proprietary format. \nYou need to convert it to a supported audio format, such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // Other notes-based formats if ((extension.IsSameAs(wxT("kar"), false))||(extension.IsSameAs(wxT("mod"), false))||(extension.IsSameAs(wxT("rmi"), false))) { errorMessage.Printf(_("\"%s\" is a notes-based file, not an audio file. \nAudacity cannot open this type of file. \nTry converting it to an audio file such as WAV or AIFF and \nthen import it, or record it into Audacity."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // MusePack files if ((extension.IsSameAs(wxT("mp+"), false))||(extension.IsSameAs(wxT("mpc"), false))||(extension.IsSameAs(wxT("mpp"), false))) { errorMessage.Printf(_("\"%s\" is a Musepack audio file. \nAudacity cannot open this type of file. \nIf you think it might be an mp3 file, rename it to end with \".mp3\" \nand try importing it again. Otherwise you need to convert it to a supported audio \nformat, such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // WavPack files if ((extension.IsSameAs(wxT("wv"), false))||(extension.IsSameAs(wxT("wvc"), false))) { errorMessage.Printf(_("\"%s\" is a Wavpack audio file. \nAudacity cannot open this type of file. \nYou need to convert it to a supported audio format, such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // AC3 files if ((extension.IsSameAs(wxT("ac3"), false))) { errorMessage.Printf(_("\"%s\" is a Dolby Digital audio file. \nAudacity cannot currently open this type of file. \nYou need to convert it to a supported audio format, such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // Speex files if ((extension.IsSameAs(wxT("spx"), false))) { errorMessage.Printf(_("\"%s\" is an Ogg Speex audio file. \nAudacity cannot currently open this type of file. \nYou need to convert it to a supported audio format, such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // Video files of various forms if ((extension.IsSameAs(wxT("mpg"), false))||(extension.IsSameAs(wxT("mpeg"), false))||(extension.IsSameAs(wxT("avi"), false))||(extension.IsSameAs(wxT("wmv"), false))||(extension.IsSameAs(wxT("rv"), false))) { errorMessage.Printf(_("\"%s\" is a video file. \nAudacity cannot currently open this type of file. \nYou need to extract the audio to a supported format, such as WAV or AIFF."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } // Audacity project if (extension.IsSameAs(wxT("aup"), false)) { errorMessage.Printf(_("\"%s\" is an Audacity Project file. \nUse the 'File > Open' command to open Audacity Projects."), fName.c_str()); - pProj->mbBusyImporting = false; return false; } @@ -685,7 +666,6 @@ bool Importer::Import(const wxString &fName, errorMessage.Printf(_("Audacity recognized the type of the file '%s'.\nImporters supposedly supporting such files are:\n%s,\nbut none of them understood this file format."),fName.c_str(), pluglist.c_str()); } - pProj->mbBusyImporting = false; return false; } From 2cbdd1cc4319da11d8270dc553c667c0f45b4175 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 3 Dec 2016 09:29:58 -0500 Subject: [PATCH 29/91] Exception safety in: ControlToolBar & Ruler functions... ... because SetupCutPreviewTracks has a small chance of throwing for want of disk space. StopStream however is considered nonthrowing. --- src/toolbars/ControlToolBar.cpp | 126 +++++++++++++++++--------------- src/widgets/Ruler.cpp | 34 +++++---- 2 files changed, 88 insertions(+), 72 deletions(-) diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 8bf3e7bec..5bb0e9133 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -508,6 +508,7 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, PlayAppearance appearance, /* = PlayOption::Straight */ bool backwards, /* = false */ bool playWhiteSpace /* = false */) +// STRONG-GUARANTEE (for state of mCutPreviewTracks) { if (!CanStopAudioStream()) return -1; @@ -526,28 +527,29 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, SetPlay(true, appearance); - if (gAudioIO->IsBusy()) { - SetPlay(false); + bool success = false; + auto cleanup = finally( [&] { + if (!success) { + SetPlay(false); + SetStop(false); + SetRecord(false); + } + } ); + + if (gAudioIO->IsBusy()) return -1; - } const bool cutpreview = appearance == PlayAppearance::CutPreview; - if (cutpreview && t0==t1) { - SetPlay(false); + if (cutpreview && t0==t1) return -1; /* msmeyer: makes no sense */ - } AudacityProject *p = GetActiveProject(); - if (!p) { - SetPlay(false); + if (!p) return -1; // Should never happen, but... - } TrackList *t = p->GetTracks(); - if (!t) { - mPlay->PopUp(); + if (!t) return -1; // Should never happen, but... - } p->mLastPlayMode = mode; @@ -566,10 +568,8 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, double latestEnd = (playWhiteSpace)? t1 : t->GetEndTime(); - if (!hasaudio) { - SetPlay(false); + if (!hasaudio) return -1; // No need to continue without audio tracks - } #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR) double init_seek = 0.0; @@ -620,7 +620,7 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, } int token = -1; - bool success = false; + if (t1 != t0) { if (cutpreview) { const double tless = std::min(t0, t1); @@ -647,13 +647,9 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, #endif tcp0, tcp1, myOptions); } - else { + else // Cannot create cut preview tracks, clean up and exit - SetPlay(false); - SetStop(false); - SetRecord(false); return -1; - } } else { // Lifted the following into AudacityProject::GetDefaultPlayOptions() @@ -687,12 +683,8 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, } } - if (!success) { - SetPlay(false); - SetStop(false); - SetRecord(false); + if (!success) return -1; - } StartScrollingIfPreferred(); @@ -768,8 +760,8 @@ void ControlToolBar::OnPlay(wxCommandEvent & WXUNUSED(evt)) if (p) p->TP_DisplaySelection(); + auto cleanup = finally( [&]{ UpdateStatusBar(p); } ); PlayDefault(); - UpdateStatusBar(p); } void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt)) @@ -861,6 +853,7 @@ void ControlToolBar::Pause() } void ControlToolBar::OnRecord(wxCommandEvent &evt) +// STRONG-GUARANTEE (for state of current project's tracks) { if (gAudioIO->IsBusy()) { if (!CanStopAudioStream() || 0 == gAudioIO->GetNumCaptureChannels()) @@ -878,14 +871,43 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) SetRecord(true, mRecord->WasShiftDown()); + bool success = false; + + bool shifted = mRecord->WasShiftDown(); +#ifdef EXPERIMENTAL_DA + shifted = !shifted; +#endif + + TrackList *trackList = p->GetTracks(); + TrackList tracksCopy{}; + bool tracksCopied = false; + + WaveTrackArray recordingTracks; + + auto cleanup = finally( [&] { + if (!success) { + if (tracksCopied) + // Restore the tracks to remove any inserted silence + *trackList = std::move(tracksCopy); + + if ( ! shifted ) { + // msmeyer: Delete recently added tracks if opening stream fails + for ( auto track : recordingTracks ) + trackList->Remove(track); + } + + SetPlay(false); + SetStop(false); + SetRecord(false); + } + + // Success or not: + UpdateStatusBar(GetActiveProject()); + } ); + if (p) { - TrackList *trackList = p->GetTracks(); TrackListIterator it(trackList); - bool shifted = mRecord->WasShiftDown(); -#ifdef EXPERIMENTAL_DA - shifted = !shifted; -#endif bool hasWave = false; for (auto t = it.First(); t; t = it.Next()) { if (t->GetKind() == Track::Wave) { @@ -905,7 +927,6 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) /* TODO: set up stereo tracks if that is how the user has set up * their preferences, and choose sample format based on prefs */ - WaveTrackArray newRecordingTracks; WaveTrackConstArray playbackTracks; #ifdef EXPERIMENTAL_MIDI_OUT NoteTrackArray midiTracks; @@ -928,8 +949,6 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) // If SHIFT key was down, the user wants append to tracks int recordingChannels = 0; - TrackList tracksCopy{}; - bool tracksCopied = false; if (shifted) { recordingChannels = gPrefs->Read(wxT("/AudioIO/RecordChannels"), 2); @@ -975,10 +994,15 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) t1 = wt->GetEndTime(); if (t1 < t0) { if (!tracksCopied) { + // Duplicate all tracks before modifying any of them. + // The duplicates are used to restore state in case + // of failure. tracksCopied = true; tracksCopy = *trackList; } + // Pad the recording track with silence, up to the + // maximum time. auto newTrack = p->GetTrackFactory()->NewWaveTrack(); newTrack->InsertSilence(0.0, t0 - t1); newTrack->Flush(); @@ -987,9 +1011,9 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) wxASSERT(bResult); // TO DO: Actually handle this. wxUnusedVar(bResult); } - newRecordingTracks.push_back(wt); + recordingTracks.push_back(wt); // Don't record more channels than configured recording pref. - if( (int)newRecordingTracks.size() >= recordingChannels ){ + if( (int)recordingTracks.size() >= recordingChannels ){ break; } } @@ -1076,7 +1100,7 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) } // Let the list hold the track, and keep a pointer to it - newRecordingTracks.push_back( + recordingTracks.push_back( static_cast( trackList->Add( std::move(newTrack)))); @@ -1090,13 +1114,13 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) AudioIOStartStreamOptions options(p->GetDefaultPlayOptions()); int token = gAudioIO->StartStream(playbackTracks, - newRecordingTracks, + recordingTracks, #ifdef EXPERIMENTAL_MIDI_OUT midiTracks, #endif t0, t1, options); - bool success = (token != 0); + success = (token != 0); if (success) { p->SetAudioIOToken(token); @@ -1105,28 +1129,11 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) StartScrollingIfPreferred(); } else { - if (shifted) { - // Restore the tracks to remove any inserted silence - if (tracksCopied) - *trackList = std::move(tracksCopy); - } - else { - // msmeyer: Delete recently added tracks if opening stream fails - for (unsigned int i = 0; i < newRecordingTracks.size(); i++) { - trackList->Remove(newRecordingTracks[i]); - } - } - // msmeyer: Show error message if stream could not be opened wxMessageBox(_("Error opening sound device. Try changing the audio host, recording device and the project sample rate."), _("Error"), wxOK | wxICON_EXCLAMATION, this); - - SetPlay(false); - SetStop(false); - SetRecord(false); } } - UpdateStatusBar(GetActiveProject()); } @@ -1187,6 +1194,8 @@ void ControlToolBar::OnFF(wxCommandEvent & WXUNUSED(evt)) void ControlToolBar::SetupCutPreviewTracks(double WXUNUSED(playStart), double cutStart, double cutEnd, double WXUNUSED(playEnd)) + +// STRONG-GUARANTEE (for state of mCutPreviewTracks) { ClearCutPreviewTracks(); AudacityProject *p = GetActiveProject(); @@ -1207,6 +1216,7 @@ void ControlToolBar::SetupCutPreviewTracks(double WXUNUSED(playStart), double cu if (track1) { // Duplicate and change tracks + // Clear has a very small chance of throwing auto new1 = track1->Duplicate(); new1->Clear(cutStart, cutEnd); decltype(new1) new2{}; @@ -1216,6 +1226,8 @@ void ControlToolBar::SetupCutPreviewTracks(double WXUNUSED(playStart), double cu new2->Clear(cutStart, cutEnd); } + // use NOTHROW-GUARANTEE: + mCutPreviewTracks = std::make_unique(); mCutPreviewTracks->Add(std::move(new1)); if (track2) diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp index 04d59df1c..eab3a30b4 100644 --- a/src/widgets/Ruler.cpp +++ b/src/widgets/Ruler.cpp @@ -2672,19 +2672,21 @@ void AdornedRulerPanel::HandleQPRelease(wxMouseEvent &evt) ClearPlayRegion(); } - StartQPPlay(evt.ShiftDown(), evt.ControlDown()); - mMouseEventState = mesNone; mIsDragging = false; mLeftDownClick = -1; - if (mPlayRegionLock) { - // Restore Locked Play region - SetPlayRegion(mOldPlayRegionStart, mOldPlayRegionEnd); - mProject->OnLockPlayRegion(); - // and release local lock - mPlayRegionLock = false; - } + auto cleanup = finally( [&] { + if (mPlayRegionLock) { + // Restore Locked Play region + SetPlayRegion(mOldPlayRegionStart, mOldPlayRegionEnd); + mProject->OnLockPlayRegion(); + // and release local lock + mPlayRegionLock = false; + } + } ); + + StartQPPlay(evt.ShiftDown(), evt.ControlDown()); } void AdornedRulerPanel::StartQPPlay(bool looped, bool cutPreview) @@ -2732,18 +2734,20 @@ void AdornedRulerPanel::StartQPPlay(bool looped, bool cutPreview) options.timeTrack = NULL; ControlToolBar::PlayAppearance appearance = - cutPreview ? ControlToolBar::PlayAppearance::CutPreview - : options.playLooped ? ControlToolBar::PlayAppearance::Looped - : ControlToolBar::PlayAppearance::Straight; + cutPreview ? ControlToolBar::PlayAppearance::CutPreview + : options.playLooped ? ControlToolBar::PlayAppearance::Looped + : ControlToolBar::PlayAppearance::Straight; + + mPlayRegionStart = start; + mPlayRegionEnd = end; + Refresh(); + ctb->PlayPlayRegion((SelectedRegion(start, end)), options, PlayMode::normalPlay, appearance, false, true); - mPlayRegionStart = start; - mPlayRegionEnd = end; - Refresh(); } } From 79c3bef2ced0b388ba284e9ba3e7af906ff60afb Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 16 Dec 2016 13:27:24 -0500 Subject: [PATCH 30/91] Exception safety in: general effect performing functions --- include/audacity/EffectInterface.h | 3 +- src/Menus.cpp | 41 +-- src/effects/Effect.cpp | 388 +++++++++++++++-------------- src/effects/Effect.h | 17 +- src/effects/EffectRack.cpp | 29 ++- 5 files changed, 259 insertions(+), 219 deletions(-) diff --git a/include/audacity/EffectInterface.h b/include/audacity/EffectInterface.h index a4ce21845..a1cff1fea 100755 --- a/include/audacity/EffectInterface.h +++ b/include/audacity/EffectInterface.h @@ -131,7 +131,8 @@ public: virtual bool IsReady() = 0; virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL) = 0; - virtual bool ProcessFinalize() = 0; + // This may be called during stack unwinding: + virtual bool ProcessFinalize() /* noexcept */ = 0; virtual size_t ProcessBlock(float **inBlock, float **outBlock, size_t blockLen) = 0; virtual bool RealtimeInitialize() = 0; diff --git a/src/Menus.cpp b/src/Menus.cpp index 413603bc3..6a534808e 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -3628,6 +3628,27 @@ bool AudacityProject::OnEffect(const PluginID & ID, int flags) WaveTrack *newTrack{}; wxWindow *focus = wxWindow::FindFocus(); + bool success = false; + auto cleanup = finally( [&] { + + if (!success) { + if (newTrack) { + mTracks->Remove(newTrack); + mTrackPanel->Refresh(false); + } + + // For now, we're limiting realtime preview to a single effect, so + // make sure the menus reflect that fact that one may have just been + // opened. + UpdateMenus(false); + } + + if (focus != NULL) { + focus->SetFocus(); + } + + } ); + //double prevEndTime = mTracks->GetEndTime(); int count = 0; bool clean = true; @@ -3650,24 +3671,13 @@ bool AudacityProject::OnEffect(const PluginID & ID, int flags) EffectManager & em = EffectManager::Get(); - bool success = em.DoEffect(ID, this, mRate, + success = em.DoEffect(ID, this, mRate, GetTracks(), GetTrackFactory(), &mViewInfo.selectedRegion, (flags & OnEffectFlags::kConfigured) == 0); - if (!success) { - if (newTrack) { - mTracks->Remove(newTrack); - mTrackPanel->Refresh(false); - } - - // For now, we're limiting realtime preview to a single effect, so - // make sure the menus reflect that fact that one may have just been - // opened. - UpdateMenus(false); - + if (!success) return false; - } if (em.GetSkipStateFlag()) flags = flags | OnEffectFlags::kSkipState; @@ -3681,7 +3691,7 @@ bool AudacityProject::OnEffect(const PluginID & ID, int flags) if (!(flags & OnEffectFlags::kDontRepeatLast)) { - // Only remember a successful effect, don't rmemeber insert, + // Only remember a successful effect, don't remember insert, // or analyze effects. if (type == EffectTypeProcess) { wxString shortDesc = em.GetEffectName(ID); @@ -3705,9 +3715,6 @@ bool AudacityProject::OnEffect(const PluginID & ID, int flags) // mTrackPanel->Refresh(false); } RedrawProject(); - if (focus != NULL) { - focus->SetFocus(); - } mTrackPanel->EnsureVisible(mTrackPanel->GetFirstSelectedTrack()); mTrackPanel->Refresh(false); diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index f540bf21a..c833fe66c 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -1118,16 +1118,6 @@ void Effect::SetBatchProcessing(bool start) } } -namespace { - struct SetProgress { - SetProgress(ProgressDialog *& mProgress_, ProgressDialog *progress) - : mProgress(mProgress_) - { mProgress = progress; } - ~SetProgress() { mProgress = nullptr; } - ProgressDialog *& mProgress; - }; -} - bool Effect::DoEffect(wxWindow *parent, double projectRate, TrackList *list, @@ -1191,26 +1181,33 @@ bool Effect::DoEffect(wxWindow *parent, // Prompting will be bypassed when applying an effect that has already // been configured, e.g. repeating the last effect on a different selection. + // Prompting may call Effect::Preview if (shouldPrompt && IsInteractive() && !PromptUser(parent)) { return false; } + auto cleanup = finally( [&] { + End(); + + // In case of failed effect, be sure to free memory. + ReplaceProcessedTracks( false ); + } ); + bool returnVal = true; bool skipFlag = CheckWhetherSkipEffect(); if (skipFlag == false) { - ProgressDialog progress(GetName(), + ProgressDialog progress{ + GetName(), wxString::Format(_("Applying %s..."), GetName().c_str()), - pdlgHideStopButton); - SetProgress sp(mProgress, &progress); + pdlgHideStopButton + }; + auto vr = valueRestorer( mProgress, &progress ); + returnVal = Process(); } - End(); - - mOutputTracks.reset(); - if (returnVal) { selectedRegion->setTimes(mT0, mT1); @@ -1286,8 +1283,8 @@ bool Effect::ProcessPass() bool editClipCanMove; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove, true); - mInBuffer.reset(); - mOutBuffer.reset(); + FloatBuffers inBuffer, outBuffer; + ArrayOf inBufPos, outBufPos; ChannelName map[3]; @@ -1389,36 +1386,36 @@ bool Effect::ProcessPass() { // Always create the number of input buffers the client expects even if we don't have // the same number of channels. - mInBufPos.reinit( mNumAudioIn ); - mInBuffer.reinit( mNumAudioIn, mBufferSize ); + inBufPos.reinit( mNumAudioIn ); + inBuffer.reinit( mNumAudioIn, mBufferSize ); // We won't be using more than the first 2 buffers, so clear the rest (if any) for (size_t i = 2; i < mNumAudioIn; i++) { for (size_t j = 0; j < mBufferSize; j++) { - mInBuffer[i][j] = 0.0; + inBuffer[i][j] = 0.0; } } // Always create the number of output buffers the client expects even if we don't have // the same number of channels. - mOutBufPos.reinit( mNumAudioOut ); // Output buffers get an extra mBlockSize worth to give extra room if // the plugin adds latency - mOutBuffer.reinit( mNumAudioOut, mBufferSize + mBlockSize ); + outBufPos.reinit( mNumAudioOut ); + outBuffer.reinit( mNumAudioOut, mBufferSize + mBlockSize ); } // (Re)Set the input buffer positions for (size_t i = 0; i < mNumAudioIn; i++) { - mInBufPos[i] = mInBuffer[i].get(); + inBufPos[i] = inBuffer[i].get(); } // (Re)Set the output buffer positions for (size_t i = 0; i < mNumAudioOut; i++) { - mOutBufPos[i] = mOutBuffer[i].get(); + outBufPos[i] = outBuffer[i].get(); } // Clear unused input buffers @@ -1426,13 +1423,15 @@ bool Effect::ProcessPass() { for (size_t j = 0; j < mBufferSize; j++) { - mInBuffer[1][j] = 0.0; + inBuffer[1][j] = 0.0; } clear = true; } // Go process the track(s) - bGoodResult = ProcessTrack(count, map, left, right, leftStart, rightStart, len); + bGoodResult = ProcessTrack( + count, map, left, right, leftStart, rightStart, len, + inBuffer, outBuffer, inBufPos, outBufPos); if (!bGoodResult) { break; @@ -1441,11 +1440,6 @@ bool Effect::ProcessPass() count++; } - mOutBuffer.reset(); - mOutBufPos.reset(); - mInBuffer.reset(); - mInBufPos.reset(); - if (bGoodResult && GetType() == EffectTypeGenerate) { mT1 = mT0 + mDuration; @@ -1460,7 +1454,11 @@ bool Effect::ProcessTrack(int count, WaveTrack *right, sampleCount leftStart, sampleCount rightStart, - sampleCount len) + sampleCount len, + FloatBuffers &inBuffer, + FloatBuffers &outBuffer, + ArrayOf< float * > &inBufPos, + ArrayOf< float *> &outBufPos) { bool rc = true; @@ -1470,6 +1468,16 @@ bool Effect::ProcessTrack(int count, return false; } + { // Start scope for cleanup + auto cleanup = finally( [&] { + // Allow the plugin to cleanup + if (!ProcessFinalize()) + { + // In case of non-exceptional flow of control, set rc + rc = false; + } + } ); + // For each input block of samples, we pass it to the effect along with a // variable output location. This output location is simply a pointer into a // much larger buffer. This reduces the number of calls required to add the @@ -1539,16 +1547,16 @@ bool Effect::ProcessTrack(int count, limitSampleBufferSize( mBufferSize, inputRemaining ); // Fill the input buffers - left->Get((samplePtr) mInBuffer[0].get(), floatSample, inLeftPos, inputBufferCnt); + left->Get((samplePtr) inBuffer[0].get(), floatSample, inLeftPos, inputBufferCnt); if (right) { - right->Get((samplePtr) mInBuffer[1].get(), floatSample, inRightPos, inputBufferCnt); + right->Get((samplePtr) inBuffer[1].get(), floatSample, inRightPos, inputBufferCnt); } // Reset the input buffer positions for (size_t i = 0; i < mNumChannels; i++) { - mInBufPos[i] = mInBuffer[i].get(); + inBufPos[i] = inBuffer[i].get(); } } @@ -1568,7 +1576,7 @@ bool Effect::ProcessTrack(int count, { for (decltype(cnt) j = 0 ; j < cnt; j++) { - mInBufPos[i][j + curBlockSize] = 0.0; + inBufPos[i][j + curBlockSize] = 0.0; } } @@ -1595,12 +1603,12 @@ bool Effect::ProcessTrack(int count, // Reset the input buffer positions for (size_t i = 0; i < mNumChannels; i++) { - mInBufPos[i] = mInBuffer[i].get(); + inBufPos[i] = inBuffer[i].get(); // And clear for (size_t j = 0; j < mBlockSize; j++) { - mInBuffer[i][j] = 0.0; + inBuffer[i][j] = 0.0; } } cleared = true; @@ -1611,7 +1619,7 @@ bool Effect::ProcessTrack(int count, decltype(curBlockSize) processed; try { - processed = ProcessBlock(mInBufPos.get(), mOutBufPos.get(), curBlockSize); + processed = ProcessBlock(inBufPos.get(), outBufPos.get(), curBlockSize); } catch( const AudacityException &e ) { @@ -1635,7 +1643,7 @@ bool Effect::ProcessTrack(int count, { for (size_t i = 0; i < mNumChannels; i++) { - mInBufPos[i] += curBlockSize; + inBufPos[i] += curBlockSize; } inputRemaining -= curBlockSize; inputBufferCnt -= curBlockSize; @@ -1672,7 +1680,7 @@ bool Effect::ProcessTrack(int count, curBlockSize -= delay; for (size_t i = 0; i < chans; i++) { - memmove(mOutBufPos[i], mOutBufPos[i] + delay, sizeof(float) * curBlockSize); + memmove(outBufPos[i], outBufPos[i] + delay, sizeof(float) * curBlockSize); } curDelay = 0; } @@ -1687,7 +1695,7 @@ bool Effect::ProcessTrack(int count, // Bump to next output buffer position for (size_t i = 0; i < chans; i++) { - mOutBufPos[i] += curBlockSize; + outBufPos[i] += curBlockSize; } } // Output buffers have filled @@ -1696,32 +1704,32 @@ bool Effect::ProcessTrack(int count, if (isProcessor) { // Write them out - left->Set((samplePtr) mOutBuffer[0].get(), floatSample, outLeftPos, outputBufferCnt); + left->Set((samplePtr) outBuffer[0].get(), floatSample, outLeftPos, outputBufferCnt); if (right) { if (chans >= 2) { - right->Set((samplePtr) mOutBuffer[1].get(), floatSample, outRightPos, outputBufferCnt); + right->Set((samplePtr) outBuffer[1].get(), floatSample, outRightPos, outputBufferCnt); } else { - right->Set((samplePtr) mOutBuffer[0].get(), floatSample, outRightPos, outputBufferCnt); + right->Set((samplePtr) outBuffer[0].get(), floatSample, outRightPos, outputBufferCnt); } } } else if (isGenerator) { - genLeft->Append((samplePtr) mOutBuffer[0].get(), floatSample, outputBufferCnt); + genLeft->Append((samplePtr) outBuffer[0].get(), floatSample, outputBufferCnt); if (genRight) { - genRight->Append((samplePtr) mOutBuffer[1].get(), floatSample, outputBufferCnt); + genRight->Append((samplePtr) outBuffer[1].get(), floatSample, outputBufferCnt); } } // Reset the output buffer positions for (size_t i = 0; i < chans; i++) { - mOutBufPos[i] = mOutBuffer[i].get(); + outBufPos[i] = outBuffer[i].get(); } // Bump to the next track position @@ -1753,34 +1761,34 @@ bool Effect::ProcessTrack(int count, } // Put any remaining output - if (outputBufferCnt) + if (rc && outputBufferCnt) { if (isProcessor) { - left->Set((samplePtr) mOutBuffer[0].get(), floatSample, outLeftPos, outputBufferCnt); + left->Set((samplePtr) outBuffer[0].get(), floatSample, outLeftPos, outputBufferCnt); if (right) { if (chans >= 2) { - right->Set((samplePtr) mOutBuffer[1].get(), floatSample, outRightPos, outputBufferCnt); + right->Set((samplePtr) outBuffer[1].get(), floatSample, outRightPos, outputBufferCnt); } else { - right->Set((samplePtr) mOutBuffer[0].get(), floatSample, outRightPos, outputBufferCnt); + right->Set((samplePtr) outBuffer[0].get(), floatSample, outRightPos, outputBufferCnt); } } } else if (isGenerator) { - genLeft->Append((samplePtr) mOutBuffer[0].get(), floatSample, outputBufferCnt); + genLeft->Append((samplePtr) outBuffer[0].get(), floatSample, outputBufferCnt); if (genRight) { - genRight->Append((samplePtr) mOutBuffer[1].get(), floatSample, outputBufferCnt); + genRight->Append((samplePtr) outBuffer[1].get(), floatSample, outputBufferCnt); } } } - if (isGenerator) + if (rc && isGenerator) { AudacityProject *p = GetActiveProject(); @@ -1794,7 +1802,7 @@ bool Effect::ProcessTrack(int count, // The purpose was to remap split lines inside the selected region when // a generator replaces it with sound of different duration. But // the "correct" version might have the effect of mapping some splits too - // far left, to before the seletion. + // far left, to before the selection. // In practice the wrong version probably did nothing most of the time, // because the cutoff time for the step time warper was 44100 times too // far from mT0. @@ -1813,12 +1821,7 @@ bool Effect::ProcessTrack(int count, } } - // Allow the plugin to cleanup - if (!ProcessFinalize()) - { - return false; - } - + } // End scope for cleanup return rc; } @@ -2125,20 +2128,26 @@ auto Effect::ModifyAnalysisTrack // Else clear and DELETE mOutputTracks copies. void Effect::ReplaceProcessedTracks(const bool bGoodResult) { - wxASSERT(mOutputTracks); // Make sure we at least did the CopyInputTracks(). - if (!bGoodResult) { + // Free resources, unless already freed. + // Processing failed or was cancelled so throw away the processed tracks. - mOutputTracks->Clear(); + if ( mOutputTracks ) + mOutputTracks->Clear(); // Reset map mIMap.clear(); mOMap.clear(); + mOutputTracksType = Track::None; + //TODO:undo the non-gui ODTask transfer return; } + // Assume resources need to be freed. + wxASSERT(mOutputTracks); // Make sure we at least did the CopyInputTracks(). + auto iterOut = mOutputTracks->begin(), iterEnd = mOutputTracks->end(); size_t cnt = mOMap.size(); @@ -2465,142 +2474,144 @@ void Effect::Preview(bool dryOnly) return; bool success = true; - double oldT0 = mT0; - double oldT1 = mT1; + auto vr0 = valueRestorer( mT0 ); + auto vr1 = valueRestorer( mT1 ); // Most effects should stop at t1. if (!mPreviewFullSelection) mT1 = t1; - { - // Save the original track list - TrackList *saveTracks = mTracks; - auto cleanup = finally( [&] { mTracks = saveTracks; } ); + // Save the original track list + TrackList *saveTracks = mTracks; - // Build NEW tracklist from rendering tracks - auto uTracks = std::make_unique(); - mTracks = uTracks.get(); + auto cleanup = finally( [&] { + mTracks = saveTracks; - // Linear Effect preview optimised by pre-mixing to one track. - // Generators need to generate per track. - if (mIsLinearEffect && !isGenerator) { - WaveTrack::Holder mixLeft, mixRight; - MixAndRender(saveTracks, mFactory, rate, floatSample, mT0, t1, mixLeft, mixRight); - if (!mixLeft) - return; - - mixLeft->Offset(-mixLeft->GetStartTime()); - mixLeft->InsertSilence(0.0, mT0); - mixLeft->SetSelected(true); - mixLeft->SetDisplay(WaveTrack::NoDisplay); - mTracks->Add(std::move(mixLeft)); - if (mixRight) { - mixRight->Offset(-mixRight->GetStartTime()); - mixRight->InsertSilence(0.0, mT0); - mixRight->SetSelected(true); - mTracks->Add(std::move(mixRight)); - } - } - else { - TrackListOfKindIterator iter(Track::Wave, saveTracks); - WaveTrack *src = (WaveTrack *) iter.First(); - while (src) - { - if (src->GetSelected() || mPreviewWithNotSelected) { - auto dest = src->Copy(mT0, t1); - dest->InsertSilence(0.0, mT0); - dest->SetSelected(src->GetSelected()); - static_cast(dest.get())->SetDisplay(WaveTrack::NoDisplay); - mTracks->Add(std::move(dest)); - } - src = (WaveTrack *) iter.Next(); - } - } - - - // Update track/group counts - CountWaveTracks(); - - // Apply effect + // Effect is already inited; we will call Process, End, and then Init + // again, so the state is exactly the way it was before Preview + // was called. if (!dryOnly) { - ProgressDialog progress(GetName(), - _("Preparing preview"), - pdlgHideCancelButton); // Have only "Stop" button. - SetProgress sp(mProgress, &progress); - mIsPreview = true; - success = Process(); - mIsPreview = false; + End(); + GuardedCall< void >( [&]{ Init(); } ); } - if (success) - { - WaveTrackConstArray playbackTracks; - WaveTrackArray recordingTracks; - - SelectedTrackListOfKindIterator iter(Track::Wave, mTracks); - WaveTrack *src = (WaveTrack *) iter.First(); - while (src) { - playbackTracks.push_back(src); - src = (WaveTrack *) iter.Next(); - } - // Some effects (Paulstretch) may need to generate more - // than previewLen, so take the min. - t1 = std::min(mT0 + previewLen, mT1); - -#ifdef EXPERIMENTAL_MIDI_OUT - NoteTrackArray empty; -#endif - // Start audio playing - AudioIOStartStreamOptions options { rate }; - int token = - gAudioIO->StartStream(playbackTracks, recordingTracks, -#ifdef EXPERIMENTAL_MIDI_OUT - empty, -#endif - mT0, t1, options); - - if (token) { - auto previewing = ProgressResult::Success; - // The progress dialog must be deleted before stopping the stream - // to allow events to flow to the app during StopStream processing. - // The progress dialog blocks these events. - { - ProgressDialog progress - (GetName(), _("Previewing"), pdlgHideCancelButton); - - while (gAudioIO->IsStreamActive(token) && previewing == ProgressResult::Success) { - ::wxMilliSleep(100); - previewing = progress.Update(gAudioIO->GetStreamTime() - mT0, t1 - mT0); - } - } - - gAudioIO->StopStream(); - - while (gAudioIO->IsBusy()) { - ::wxMilliSleep(100); - } - } - else { - wxMessageBox(_("Error opening sound device. Try changing the audio host, playback device and the project sample rate."), - _("Error"), wxOK | wxICON_EXCLAMATION, FocusDialog); - } - } - if (FocusDialog) { FocusDialog->SetFocus(); } - - mOutputTracks.reset(); + + // In case of failed effect, be sure to free memory. + ReplaceProcessedTracks( false ); + } ); + + // Build NEW tracklist from rendering tracks + auto uTracks = std::make_unique(); + mTracks = uTracks.get(); + + // Linear Effect preview optimised by pre-mixing to one track. + // Generators need to generate per track. + if (mIsLinearEffect && !isGenerator) { + WaveTrack::Holder mixLeft, mixRight; + MixAndRender(saveTracks, mFactory, rate, floatSample, mT0, t1, mixLeft, mixRight); + if (!mixLeft) + return; + + mixLeft->Offset(-mixLeft->GetStartTime()); + mixLeft->InsertSilence(0.0, mT0); + mixLeft->SetSelected(true); + mixLeft->SetDisplay(WaveTrack::NoDisplay); + mTracks->Add(std::move(mixLeft)); + if (mixRight) { + mixRight->Offset(-mixRight->GetStartTime()); + mixRight->InsertSilence(0.0, mT0); + mixRight->SetSelected(true); + mTracks->Add(std::move(mixRight)); + } + } + else { + TrackListOfKindIterator iter(Track::Wave, saveTracks); + WaveTrack *src = (WaveTrack *) iter.First(); + while (src) + { + if (src->GetSelected() || mPreviewWithNotSelected) { + auto dest = src->Copy(mT0, t1); + dest->InsertSilence(0.0, mT0); + dest->SetSelected(src->GetSelected()); + static_cast(dest.get())->SetDisplay(WaveTrack::NoDisplay); + mTracks->Add(std::move(dest)); + } + src = (WaveTrack *) iter.Next(); + } } - mT0 = oldT0; - mT1 = oldT1; - // Effect is already inited; we call Process, End, and then Init - // again, so the state is exactly the way it was before Preview - // was called. + // Update track/group counts + CountWaveTracks(); + + // Apply effect if (!dryOnly) { - End(); - Init(); + ProgressDialog progress{ + GetName(), + _("Preparing preview"), + pdlgHideCancelButton + }; // Have only "Stop" button. + auto vr = valueRestorer( mProgress, &progress ); + + auto vr2 = valueRestorer( mIsPreview, true ); + + success = Process(); + } + + if (success) + { + WaveTrackConstArray playbackTracks; + WaveTrackArray recordingTracks; + + SelectedTrackListOfKindIterator iter(Track::Wave, mTracks); + WaveTrack *src = (WaveTrack *) iter.First(); + while (src) { + playbackTracks.push_back(src); + src = (WaveTrack *) iter.Next(); + } + // Some effects (Paulstretch) may need to generate more + // than previewLen, so take the min. + t1 = std::min(mT0 + previewLen, mT1); + +#ifdef EXPERIMENTAL_MIDI_OUT + NoteTrackArray empty; +#endif + // Start audio playing + AudioIOStartStreamOptions options { rate }; + int token = + gAudioIO->StartStream(playbackTracks, recordingTracks, +#ifdef EXPERIMENTAL_MIDI_OUT + empty, +#endif + mT0, t1, options); + + if (token) { + auto previewing = ProgressResult::Success; + // The progress dialog must be deleted before stopping the stream + // to allow events to flow to the app during StopStream processing. + // The progress dialog blocks these events. + { + ProgressDialog progress + (GetName(), _("Previewing"), pdlgHideCancelButton); + + while (gAudioIO->IsStreamActive(token) && previewing == ProgressResult::Success) { + ::wxMilliSleep(100); + previewing = progress.Update(gAudioIO->GetStreamTime() - mT0, t1 - mT0); + } + } + + gAudioIO->StopStream(); + + while (gAudioIO->IsBusy()) { + ::wxMilliSleep(100); + } + } + else { + wxMessageBox(_("Error opening sound device. Try changing the audio host, playback device and the project sample rate."), + _("Error"), wxOK | wxICON_EXCLAMATION, FocusDialog); + } } } @@ -3167,11 +3178,10 @@ void EffectUIHost::OnApply(wxCommandEvent & evt) // Progress dialog no longer yields, so this "shouldn't" be necessary (yet to be proven // for sure), but it is a nice visual cue that something is going on. mApplyBtn->Disable(); + auto cleanup = finally( [&] { mApplyBtn->Enable(); } ); mEffect->Apply(); - mApplyBtn->Enable(); - return; } diff --git a/src/effects/Effect.h b/src/effects/Effect.h index c72ece483..9010666fe 100644 --- a/src/effects/Effect.h +++ b/src/effects/Effect.h @@ -287,7 +287,9 @@ protected: virtual bool InitPass2(); virtual int GetPass(); - // clean up any temporary memory + // clean up any temporary memory, needed only per invocation of the + // effect, after either successful or failed or exception-aborted processing. + // Invoked inside a "finally" block so it must be no-throw. virtual void End(); // Most effects just use the previewLength, but time-stretching/compressing @@ -470,8 +472,12 @@ protected: WaveTrack *right, sampleCount leftStart, sampleCount rightStart, - sampleCount len); - + sampleCount len, + FloatBuffers &inBuffer, + FloatBuffers &outBuffer, + ArrayOf< float * > &inBufPos, + ArrayOf< float *> &outBufPos); + // // private data // @@ -505,11 +511,6 @@ private: size_t mNumAudioIn; size_t mNumAudioOut; - FloatBuffers mInBuffer, mOutBuffer; - - using Positions = ArrayOf < float* > ; // Array of non-owning pointers into the above - Positions mInBufPos, mOutBufPos; - size_t mBufferSize; size_t mBlockSize; unsigned mNumChannels; diff --git a/src/effects/EffectRack.cpp b/src/effects/EffectRack.cpp index 76b7bdf8d..f1ecf8f45 100644 --- a/src/effects/EffectRack.cpp +++ b/src/effects/EffectRack.cpp @@ -17,6 +17,8 @@ #if defined(EXPERIMENTAL_EFFECTS_RACK) #include "../MemoryX.h" +#include "../UndoManager.h" + #include #include #include @@ -289,17 +291,36 @@ void EffectRack::OnTimer(wxTimerEvent & WXUNUSED(evt)) void EffectRack::OnApply(wxCommandEvent & WXUNUSED(evt)) { AudacityProject *project = GetActiveProject(); - + + bool success = false; + auto state = project->GetUndoManager()->GetCurrentState(); + auto cleanup = finally( [&] { + if(!success) + project->SetStateTo(state); + } ); + for (size_t i = 0, cnt = mEffects.size(); i < cnt; i++) { if (mPowerState[i]) { - project->OnEffect(mEffects[i]->GetID(), - AudacityProject::OnEffectFlags::kConfigured); + if (!project->OnEffect(mEffects[i]->GetID(), + AudacityProject::OnEffectFlags::kConfigured)) + // If any effect fails (or throws), then stop. + return; + } + } + success = true; + + // Only after all succeed, do the following. + for (size_t i = 0, cnt = mEffects.size(); i < cnt; i++) + { + if (mPowerState[i]) + { mPowerState[i] = false; - wxBitmapButton *btn = static_cast(FindWindowById(ID_POWER + i)); + wxBitmapButton *btn = + static_cast(FindWindowById(ID_POWER + i)); btn->SetBitmapLabel(mPowerRaised); btn->SetBitmapSelected(mPowerRaised); } From 1fad6292a245d8ddb57756ec88ce193eb2d4919b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 16 Dec 2016 15:32:56 -0500 Subject: [PATCH 31/91] Exception safety in: overrides of ShowInterface --- src/effects/Effect.cpp | 14 ++++++-------- src/effects/Effect.h | 1 - src/effects/Equalization.cpp | 6 +----- src/effects/VST/VSTEffect.cpp | 8 ++++++-- src/effects/audiounits/AudioUnitEffect.cpp | 8 ++++++-- src/effects/ladspa/LadspaEffect.cpp | 8 ++++++-- src/effects/lv2/LV2Effect.cpp | 8 ++++++-- 7 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index c833fe66c..e0e36d7ed 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -88,8 +88,6 @@ WX_DECLARE_VOIDPTR_HASH_MAP( bool, t2bHash ); Effect::Effect() { - mParent = NULL; - mClient = NULL; mTracks = NULL; @@ -520,7 +518,8 @@ bool Effect::ShowInterface(wxWindow *parent, bool forceModal) if (mUIDialog) { - mUIDialog->Close(true); + if ( mUIDialog->Close(true) ) + mUIDialog = nullptr; return false; } @@ -529,8 +528,9 @@ bool Effect::ShowInterface(wxWindow *parent, bool forceModal) return mClient->ShowInterface(parent, forceModal); } - mParent = parent; - + // mUIDialog is null + auto cleanup = valueRestorer( mUIDialog ); + mUIDialog = CreateUI(parent, this); if (!mUIDialog) { @@ -544,14 +544,13 @@ bool Effect::ShowInterface(wxWindow *parent, bool forceModal) if (SupportsRealtime() && !forceModal) { mUIDialog->Show(); + cleanup.release(); // Return false to bypass effect processing return false; } bool res = mUIDialog->ShowModal() != 0; - mUIDialog = NULL; - mParent = NULL; return res; } @@ -1131,7 +1130,6 @@ bool Effect::DoEffect(wxWindow *parent, mFactory = factory; mProjectRate = projectRate; - mParent = parent; mTracks = list; bool isSelection = false; diff --git a/src/effects/Effect.h b/src/effects/Effect.h index 9010666fe..df57c9dcb 100644 --- a/src/effects/Effect.h +++ b/src/effects/Effect.h @@ -484,7 +484,6 @@ protected: // Used only by the base Effect class // private: - wxWindow *mParent; TrackList *mTracks; // the complete list of all tracks bool mIsBatch; diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index fa67ed2fb..41338f0fa 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -570,14 +570,10 @@ bool EffectEqualization::PopulateUI(wxWindow *parent) bool EffectEqualization::CloseUI() { - mUIParent->RemoveEventHandler(this); - - mUIParent = NULL; - mCurve = NULL; mPanel = NULL; - return true; + return Effect::CloseUI(); } void EffectEqualization::PopulateOrExchange(ShuttleGui & S) diff --git a/src/effects/VST/VSTEffect.cpp b/src/effects/VST/VSTEffect.cpp index 636ba2d2e..340afa4fc 100644 --- a/src/effects/VST/VSTEffect.cpp +++ b/src/effects/VST/VSTEffect.cpp @@ -1544,10 +1544,14 @@ bool VSTEffect::ShowInterface(wxWindow *parent, bool forceModal) { if (mDialog) { - mDialog->Close(true); + if ( mDialog->Close(true) ) + mDialog = nullptr; return false; } + // mDialog is null + auto cleanup = valueRestorer( mDialog ); + // mProcessLevel = 1; // in GUI thread // Set some defaults since some VSTs need them...these will be reset when @@ -1569,12 +1573,12 @@ bool VSTEffect::ShowInterface(wxWindow *parent, bool forceModal) if (SupportsRealtime() && !forceModal) { mDialog->Show(); + cleanup.release(); return false; } bool res = mDialog->ShowModal() != 0; - mDialog = NULL; return res; } diff --git a/src/effects/audiounits/AudioUnitEffect.cpp b/src/effects/audiounits/AudioUnitEffect.cpp index d9bd279e4..393885403 100644 --- a/src/effects/audiounits/AudioUnitEffect.cpp +++ b/src/effects/audiounits/AudioUnitEffect.cpp @@ -1423,10 +1423,14 @@ bool AudioUnitEffect::ShowInterface(wxWindow *parent, bool forceModal) { if (mDialog) { - mDialog->Close(true); + if( mDialog->Close(true) ) + mDialog = nullptr; return false; } + // mDialog is null + auto cleanup = valueRestorer( mDialog ); + mDialog = mHost->CreateUI(parent, this); if (!mDialog) { @@ -1436,12 +1440,12 @@ bool AudioUnitEffect::ShowInterface(wxWindow *parent, bool forceModal) if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal) { mDialog->Show(); + cleanup.release(); return false; } bool res = mDialog->ShowModal() != 0; - mDialog = NULL; return res; } diff --git a/src/effects/ladspa/LadspaEffect.cpp b/src/effects/ladspa/LadspaEffect.cpp index fe77cc4d0..ae7d48b88 100644 --- a/src/effects/ladspa/LadspaEffect.cpp +++ b/src/effects/ladspa/LadspaEffect.cpp @@ -996,10 +996,14 @@ bool LadspaEffect::ShowInterface(wxWindow *parent, bool forceModal) { if (mDialog) { - mDialog->Close(true); + if ( mDialog->Close(true) ) + mDialog = nullptr; return false; } + // mDialog is null + auto cleanup = valueRestorer( mDialog ); + mDialog = mHost->CreateUI(parent, this); if (!mDialog) { @@ -1013,12 +1017,12 @@ bool LadspaEffect::ShowInterface(wxWindow *parent, bool forceModal) if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal) { mDialog->Show(); + cleanup.release(); return false; } bool res = mDialog->ShowModal() != 0; - mDialog = NULL; return res; } diff --git a/src/effects/lv2/LV2Effect.cpp b/src/effects/lv2/LV2Effect.cpp index 86aad37c0..98a6a98ff 100644 --- a/src/effects/lv2/LV2Effect.cpp +++ b/src/effects/lv2/LV2Effect.cpp @@ -921,10 +921,14 @@ bool LV2Effect::ShowInterface(wxWindow *parent, bool forceModal) { if (mDialog) { - mDialog->Close(true); + if ( mDialog->Close(true) ) + mDialog = nullptr; return false; } + // mDialog is null + auto cleanup = valueRestorer( mDialog ); + mDialog = mHost->CreateUI(parent, this); if (!mDialog) { @@ -939,12 +943,12 @@ bool LV2Effect::ShowInterface(wxWindow *parent, bool forceModal) if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal) { mDialog->Show(); + cleanup.release(); return false; } bool res = mDialog->ShowModal() != 0; - mDialog = NULL; return res; } From 22a12c685248ca56b0ccc9a80fa41df7e836f9aa Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 15 Dec 2016 07:30:14 -0500 Subject: [PATCH 32/91] Exception safety in: some effects and generators... ... Those that directly call WaveTrack functions in their Process() routines, which might throw exceptions for disk space exhaustion. --- src/effects/Amplify.cpp | 7 +--- src/effects/Equalization.cpp | 4 +- src/effects/Equalization48x.cpp | 53 ++++++++++++------------ src/effects/NoiseReduction.cpp | 5 +-- src/effects/NoiseRemoval.cpp | 26 ++++++------ src/effects/NoiseRemoval.h | 2 +- src/effects/SBSMSEffect.cpp | 2 - src/effects/SimpleMono.cpp | 6 +-- src/effects/SoundTouchEffect.cpp | 9 ++-- src/effects/SoundTouchEffect.h | 6 ++- src/effects/StereoToMono.cpp | 6 ++- src/effects/StereoToMono.h | 1 + src/effects/TimeScale.cpp | 3 +- src/effects/nyquist/Nyquist.cpp | 71 ++++++++++++++++++-------------- src/effects/nyquist/Nyquist.h | 2 +- 15 files changed, 106 insertions(+), 97 deletions(-) diff --git a/src/effects/Amplify.cpp b/src/effects/Amplify.cpp index 21b16e939..82437e11f 100644 --- a/src/effects/Amplify.cpp +++ b/src/effects/Amplify.cpp @@ -179,13 +179,10 @@ bool EffectAmplify::Init() void EffectAmplify::Preview(bool dryOnly) { - double ratio = mRatio; - double peak = mPeak; + auto cleanup1 = valueRestorer( mRatio ); + auto cleanup2 = valueRestorer( mPeak ); Effect::Preview(dryOnly); - - mRatio = ratio; - mPeak = peak; } void EffectAmplify::PopulateOrExchange(ShuttleGui & S) diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index 41338f0fa..954f733fb 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -1092,9 +1092,7 @@ bool EffectEqualization::ProcessOne(int count, WaveTrack * t, for(size_t j = mM - 1; j < wcopy; j++) buffer[i+j] = thisWindow[j]; - float *tempP = thisWindow; - thisWindow = lastWindow; - lastWindow = tempP; + std::swap( thisWindow, lastWindow ); } //next i, lump of this block output->Append((samplePtr)buffer.get(), floatSample, block); diff --git a/src/effects/Equalization48x.cpp b/src/effects/Equalization48x.cpp index 594f76355..0a6c2170c 100644 --- a/src/effects/Equalization48x.cpp +++ b/src/effects/Equalization48x.cpp @@ -16,6 +16,7 @@ #include "../Audacity.h" #include "../Experimental.h" #ifdef EXPERIMENTAL_EQ_SSE_THREADED +#include "../MemoryX.h" #include "../Project.h" #include "Equalization.h" #include "../WaveTrack.h" @@ -296,6 +297,7 @@ bool EffectEqualization48x::Process(EffectEqualization* effectEqualization) if(sMathPath) // !!! Filter MUST BE QUAD WORD ALIGNED !!!! mEffectEqualization->mM=(mEffectEqualization->mM&(~15))+1; AllocateBuffersWorkers(sMathPath&MATH_FUNCTION_THREADED); + auto cleanup = finally( [&] { FreeBuffersWorkers(); } ); SelectedTrackListOfKindIterator iter(Track::Wave, mEffectEqualization->mOutputTracks.get()); WaveTrack *track = (WaveTrack *) iter.First(); int count = 0; @@ -316,7 +318,6 @@ bool EffectEqualization48x::Process(EffectEqualization* effectEqualization) track = (WaveTrack *) iter.Next(); count++; } - FreeBuffersWorkers(); mEffectEqualization->ReplaceProcessedTracks(!bBreakLoop); return !bBreakLoop; @@ -331,6 +332,7 @@ bool EffectEqualization48x::TrackCompare() if(sMathPath) // !!! Filter MUST BE QUAD WORD ALIGNED !!!! mEffectEqualization->mM=(mEffectEqualization->mM&(~15))+1; AllocateBuffersWorkers(sMathPath&MATH_FUNCTION_THREADED); + auto cleanup = finally( [&] { FreeBuffersWorkers(); } ); // Reset map // PRL: These two maps aren't really used std::vector SecondIMap; @@ -402,9 +404,8 @@ bool EffectEqualization48x::TrackCompare() track = (WaveTrack *) iter.Next(); track2 = (WaveTrack *) iter2.Next(); } - FreeBuffersWorkers(); - mEffectEqualization->ReplaceProcessedTracks(!bBreakLoop); - return bBreakLoop; + mEffectEqualization->ReplaceProcessedTracks(!bBreakLoop); + return bBreakLoop; // return !bBreakLoop ? } bool EffectEqualization48x::DeltaTrack(WaveTrack * t, WaveTrack * t2, sampleCount start, sampleCount len) @@ -446,6 +447,7 @@ bool EffectEqualization48x::Benchmark(EffectEqualization* effectEqualization) if(sMathPath) // !!! Filter MUST BE QUAD WORD ALIGNED !!!! mEffectEqualization->mM=(mEffectEqualization->mM&(~15))+1; AllocateBuffersWorkers(MATH_FUNCTION_THREADED); + auto cleanup = finally( [&] { FreeBuffersWorkers(); } ); SelectedTrackListOfKindIterator iter(Track::Wave, mEffectEqualization->mOutputTracks.get()); long times[] = { 0,0,0,0,0 }; @@ -494,7 +496,6 @@ bool EffectEqualization48x::Benchmark(EffectEqualization* effectEqualization) times[i]=timer.Time(); } } - FreeBuffersWorkers(); mBenching=false; bBreakLoop=false; mEffectEqualization->ReplaceProcessedTracks(bBreakLoop); @@ -507,7 +508,7 @@ bool EffectEqualization48x::Benchmark(EffectEqualization* effectEqualization) wxMessageBox(wxString::Format(_("Benchmark times:\nOriginal: %s\nDefault Segmented: %s\nDefault Threaded: %s\nSSE: %s\nSSE Threaded: %s\n"),tsDefault.Format(wxT("%M:%S.%l")).c_str(), tsDefaultEnhanced.Format(wxT("%M:%S.%l")).c_str(), tsDefaultThreaded.Format(wxT("%M:%S.%l")).c_str(),tsSSE.Format(wxT("%M:%S.%l")).c_str(),tsSSEThreaded.Format(wxT("%M:%S.%l")).c_str())); - return bBreakLoop; + return bBreakLoop; // return !bBreakLoop ? } bool EffectEqualization48x::ProcessTail(WaveTrack * t, WaveTrack * output, sampleCount start, sampleCount len) @@ -862,30 +863,32 @@ bool EffectEqualization48x::ProcessOne4x(int count, WaveTrack * t, ProcessTail(t, output.get(), start, len); return bBreakLoop; } + void *EQWorker::Entry() { while(!mExitLoop) { - mMutex->Lock(); - bool bufferAquired=false; - for(int i=0;iUnlock(); - switch (mProcessingType) - { + int i = 0; + { + wxMutexLocker locker( mMutex ); + for(; i < mBufferInfoCount; i++) { + if(mBufferInfoList[i].mBufferStatus==BufferReady) { // we found an unlocked ready buffer + mBufferInfoList[i].mBufferStatus=BufferBusy; // we own it now + break; + } + } + } + if ( i < mBufferInfoCount ) { + switch (mProcessingType) + { case 1: mEffectEqualization48x->ProcessBuffer1x(&mBufferInfoList[i]); break; - case 4: + case 4: mEffectEqualization48x->ProcessBuffer4x(&mBufferInfoList[i]); break; - } - mBufferInfoList[i].mBufferStatus=BufferDone; // we're done - break; - } - if(!bufferAquired) - mMutex->Unlock(); + } + mBufferInfoList[i].mBufferStatus=BufferDone; // we're done + } } return NULL; } @@ -940,7 +943,7 @@ bool EffectEqualization48x::ProcessOne1x4xThreaded(int count, WaveTrack * t, bBreakLoop=mEffectEqualization->TrackProgress(count, (double)(bigBlocksWritten)/bigRuns.as_double()); if( bBreakLoop ) break; - mDataMutex.Lock(); // Get in line for data + wxMutexLocker locker( mDataMutex ); // Get in line for data // process as many blocks as we can while((mBufferInfo[currentIndex].mBufferStatus==BufferDone) && (bigBlocksWrittenAppend((samplePtr)&mBufferInfo[currentIndex].mBufferDest[0][(bigBlocksWritten?mBlockSize:0)+(mFilterSize>>1)], floatSample, subBufferSize-((bigBlocksWritten?mBlockSize:0)+(mFilterSize>>1))); @@ -961,7 +964,6 @@ bool EffectEqualization48x::ProcessOne1x4xThreaded(int count, WaveTrack * t, } else mBufferInfo[currentIndex].mBufferStatus=BufferEmpty; // this is completely unecessary currentIndex=(currentIndex+1)%mWorkerDataCount; } - mDataMutex.Unlock(); // Get back in line for data } if(singleProcessLength && !bBreakLoop) { t->Get((samplePtr)mBigBuffer.get(), floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1)); @@ -1237,7 +1239,7 @@ bool EffectEqualization48x::ProcessOne8xThreaded(int count, WaveTrack * t, { break; } - mDataMutex.Lock(); // Get in line for data + wxMutexLocker locker( mDataMutex ); // Get in line for data // process as many blocks as we can while((mBufferInfo[currentIndex].mBufferStatus==BufferDone) && (bigBlocksWrittenAppend((samplePtr)&mBufferInfo[currentIndex].mBufferDest[0][(bigBlocksWritten?mBlockSize:0)+(mFilterSize>>1)], floatSample, mSubBufferSize-((bigBlocksWritten?mBlockSize:0)+(mFilterSize>>1))); @@ -1258,7 +1260,6 @@ bool EffectEqualization48x::ProcessOne8xThreaded(int count, WaveTrack * t, } else mBufferInfo[currentIndex].mBufferStatus=BufferEmpty; // this is completely unecessary currentIndex=(currentIndex+1)%mWorkerDataCount; } - mDataMutex.Unlock(); // Get back in line for data } if(singleProcessLength && !bBreakLoop) { t->Get((samplePtr)mBigBuffer.get(), floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1)); diff --git a/src/effects/NoiseReduction.cpp b/src/effects/NoiseReduction.cpp index 24e494151..647879780 100644 --- a/src/effects/NoiseReduction.cpp +++ b/src/effects/NoiseReduction.cpp @@ -1656,14 +1656,11 @@ void EffectNoiseReduction::Dialog::OnPreview(wxCommandEvent & WXUNUSED(event)) return; // Save & restore parameters around Preview, because we didn't do OK. - EffectNoiseReduction::Settings oldSettings(*m_pSettings); - + auto cleanup = valueRestorer( *m_pSettings ); *m_pSettings = mTempSettings; m_pSettings->mDoProfile = false; m_pEffect->Preview(); - - *m_pSettings = oldSettings; } void EffectNoiseReduction::Dialog::OnReduceNoise( wxCommandEvent & WXUNUSED(event)) diff --git a/src/effects/NoiseRemoval.cpp b/src/effects/NoiseRemoval.cpp index 26b50e2c6..761bf6098 100644 --- a/src/effects/NoiseRemoval.cpp +++ b/src/effects/NoiseRemoval.cpp @@ -224,7 +224,6 @@ bool EffectNoiseRemoval::Process() auto len = end - start; if (!ProcessOne(count, track, start, len)) { - Cleanup(); bGoodResult = false; break; } @@ -238,8 +237,6 @@ bool EffectNoiseRemoval::Process() mDoProfile = false; } - if (bGoodResult) - Cleanup(); this->ReplaceProcessedTracks(bGoodResult); return bGoodResult; } @@ -305,7 +302,7 @@ void EffectNoiseRemoval::Initialize() } } -void EffectNoiseRemoval::Cleanup() +void EffectNoiseRemoval::End() { hFFT.reset(); @@ -322,6 +319,8 @@ void EffectNoiseRemoval::Cleanup() mInWaveBuffer.reset(); mWindow.reset(); mOutOverlapBuffer.reset(); + + mOutputTrack.reset(); } void EffectNoiseRemoval::StartNewTrack() @@ -579,9 +578,6 @@ bool EffectNoiseRemoval::ProcessOne(int count, WaveTrack * track, bool bResult = track->ClearAndPaste(t0, t0 + tLen, mOutputTrack.get(), true, false); wxASSERT(bResult); // TO DO: Actually handle this. } - - // Delete the outputTrack now that its data is inserted in place - mOutputTrack.reset(); } return bLoopSuccess; @@ -688,14 +684,16 @@ void NoiseRemovalDialog::OnPreview(wxCommandEvent & WXUNUSED(event)) m_pEffect->mFreqSmoothingHz = mFreq; m_pEffect->mAttackDecayTime = mTime; - m_pEffect->Preview(); + auto cleanup = finally( [&] { + m_pEffect->mSensitivity = oldSensitivity; + m_pEffect->mNoiseGain = oldGain; + m_pEffect->mFreqSmoothingHz = oldFreq; + m_pEffect->mAttackDecayTime = oldTime; + m_pEffect->mbLeaveNoise = oldLeaveNoise; + m_pEffect->mDoProfile = oldDoProfile; + } ); - m_pEffect->mSensitivity = oldSensitivity; - m_pEffect->mNoiseGain = oldGain; - m_pEffect->mFreqSmoothingHz = oldFreq; - m_pEffect->mAttackDecayTime = oldTime; - m_pEffect->mbLeaveNoise = oldLeaveNoise; - m_pEffect->mDoProfile = oldDoProfile; + m_pEffect->Preview(); } void NoiseRemovalDialog::OnRemoveNoise( wxCommandEvent & WXUNUSED(event)) diff --git a/src/effects/NoiseRemoval.h b/src/effects/NoiseRemoval.h index ba13bb4dc..3e888aa2a 100644 --- a/src/effects/NoiseRemoval.h +++ b/src/effects/NoiseRemoval.h @@ -61,6 +61,7 @@ public: bool Init() override; bool CheckWhetherSkipEffect() override; bool Process() override; + void End() override; private: @@ -98,7 +99,6 @@ private: void RemoveNoise(); void RotateHistoryWindows(); void FinishTrack(); - void Cleanup(); // Variables that only exist during processing std::unique_ptr mOutputTrack; diff --git a/src/effects/SBSMSEffect.cpp b/src/effects/SBSMSEffect.cpp index 91070f553..8278cd7ac 100644 --- a/src/effects/SBSMSEffect.cpp +++ b/src/effects/SBSMSEffect.cpp @@ -34,8 +34,6 @@ public: ResampleBuf() { processed = 0; - outputLeftTrack = NULL; - outputRightTrack = NULL; } ~ResampleBuf() diff --git a/src/effects/SimpleMono.cpp b/src/effects/SimpleMono.cpp index da48e3595..cd247ded7 100644 --- a/src/effects/SimpleMono.cpp +++ b/src/effects/SimpleMono.cpp @@ -103,10 +103,9 @@ bool EffectSimpleMono::ProcessOne(WaveTrack * track, track->Get((samplePtr) buffer.get(), floatSample, s, block); //Process the buffer. If it fails, clean up and exit. - if (!ProcessSimpleMono(buffer.get(), block)) { + if (!ProcessSimpleMono(buffer.get(), block)) //Return false because the effect failed. return false; - } //Processing succeeded. copy the newly-changed samples back //onto the track. @@ -118,9 +117,8 @@ bool EffectSimpleMono::ProcessOne(WaveTrack * track, //Update the Progress meter if (TrackProgress(mCurTrackNum, (s - start).as_double() / - len)) { + len)) return false; - } } //Return true because the effect processing succeeded. diff --git a/src/effects/SoundTouchEffect.cpp b/src/effects/SoundTouchEffect.cpp index 1783d16c5..b56de741c 100644 --- a/src/effects/SoundTouchEffect.cpp +++ b/src/effects/SoundTouchEffect.cpp @@ -159,14 +159,17 @@ bool EffectSoundTouch::ProcessWithTimeWarper(const TimeWarper &warper) if (bGoodResult) ReplaceProcessedTracks(bGoodResult); - mSoundTouch.reset(); - // mT0 = mCurT0; // mT1 = mCurT0 + m_maxNewLength; // Update selection. return bGoodResult; } +void EffectSoundTouch::End() +{ + mSoundTouch.reset(); +} + //ProcessOne() takes a track, transforms it to bunch of buffer-blocks, //and executes ProcessSoundTouch on these blocks bool EffectSoundTouch::ProcessOne(WaveTrack *track, @@ -345,7 +348,7 @@ bool EffectSoundTouch::ProcessStereo( return true; } -bool EffectSoundTouch::ProcessStereoResults(const unsigned int outputCount, +bool EffectSoundTouch::ProcessStereoResults(const size_t outputCount, WaveTrack* outputLeftTrack, WaveTrack* outputRightTrack) { diff --git a/src/effects/SoundTouchEffect.h b/src/effects/SoundTouchEffect.h index ed38f94ad..7588766cf 100644 --- a/src/effects/SoundTouchEffect.h +++ b/src/effects/SoundTouchEffect.h @@ -39,6 +39,10 @@ class EffectSoundTouch /* not final */ : public Effect { public: + // Effect implementation + + void End() override; + // EffectSoundTouch implementation #ifdef USE_MIDI @@ -66,7 +70,7 @@ private: bool ProcessStereo(WaveTrack* leftTrack, WaveTrack* rightTrack, sampleCount start, sampleCount end, const TimeWarper &warper); - bool ProcessStereoResults(const unsigned int outputCount, + bool ProcessStereoResults(const size_t outputCount, WaveTrack* outputLeftTrack, WaveTrack* outputRightTrack); diff --git a/src/effects/StereoToMono.cpp b/src/effects/StereoToMono.cpp index a5e257497..f4721f067 100644 --- a/src/effects/StereoToMono.cpp +++ b/src/effects/StereoToMono.cpp @@ -125,11 +125,15 @@ bool EffectStereoToMono::Process() count++; } - mOutTrack.reset(); this->ReplaceProcessedTracks(bGoodResult); return bGoodResult; } +void EffectStereoToMono::End() +{ + mOutTrack.reset(); +} + bool EffectStereoToMono::ProcessOne(int count) { float curLeftFrame; diff --git a/src/effects/StereoToMono.h b/src/effects/StereoToMono.h index d65f4eff6..754a7ba19 100644 --- a/src/effects/StereoToMono.h +++ b/src/effects/StereoToMono.h @@ -41,6 +41,7 @@ public: // Effect implementation bool Process() override; + void End() override; bool IsHidden() override; private: diff --git a/src/effects/TimeScale.cpp b/src/effects/TimeScale.cpp index 225493174..1501726ce 100644 --- a/src/effects/TimeScale.cpp +++ b/src/effects/TimeScale.cpp @@ -165,9 +165,8 @@ double EffectTimeScale::CalcPreviewInputLength(double previewLength) void EffectTimeScale::Preview(bool dryOnly) { previewSelectedDuration = Effect::GetDuration(); - bPreview = true; + auto cleanup = valueRestorer( bPreview, true ); Effect::Preview(dryOnly); - bPreview = false; } bool EffectTimeScale::Process() diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index a402dc8dc..6d4736bb8 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -117,6 +117,8 @@ END_EVENT_TABLE() NyquistEffect::NyquistEffect(const wxString &fName) { + mOutputTrack[0] = mOutputTrack[1] = nullptr; + mAction = _("Applying Nyquist Effect..."); mInputCmd = wxEmptyString; mCmd = wxEmptyString; @@ -670,6 +672,13 @@ _("Selection too long for Nyquist code.\nMaximum allowed selection is %ld sample nyx_set_os_callback(StaticOSCallback, (void *)this); nyx_capture_output(StaticOutputCallback, (void *)this); + auto cleanup = finally( [&] { + nyx_capture_output(NULL, (void *)NULL); + nyx_set_os_callback(NULL, (void *)NULL); + nyx_cleanup(); + } ); + + if (mVersion >= 4) { mPerTrackProps = wxEmptyString; @@ -709,10 +718,6 @@ _("Selection too long for Nyquist code.\nMaximum allowed selection is %ld sample success = ProcessOne(); - nyx_capture_output(NULL, (void *)NULL); - nyx_set_os_callback(NULL, (void *)NULL); - nyx_cleanup(); - // Reset previous locale wxSetlocale(LC_NUMERIC, prevlocale); @@ -1110,16 +1115,23 @@ bool NyquistEffect::ProcessOne() cmd += mCmd; } - int i; - for (i = 0; i < mCurNumChannels; i++) { + // Put the fetch buffers in a clean initial state + for (size_t i = 0; i < mCurNumChannels; i++) mCurBuffer[i].Free(); - } + // Guarantee release of memory when done + auto cleanup = finally( [&] { + for (size_t i = 0; i < mCurNumChannels; i++) + mCurBuffer[i].Free(); + } ); + + // Evaluate the expression, which may invoke the get callback, but often does + // not, leaving that to delayed evaluation of the output sound rval = nyx_eval_expression(cmd.mb_str(wxConvUTF8)); // Audacity has no idea how long Nyquist processing will take, but // can monitor audio being returned. - // Anything other than audio should be returmed almost instantly + // Anything other than audio should be returned almost instantly // so notify the user that process has completed (bug 558) if ((rval != nyx_audio) && ((mCount + mCurNumChannels) == mNumSelectedChannels)) { if (mCurNumChannels == 1) { @@ -1225,19 +1237,30 @@ bool NyquistEffect::ProcessOne() return false; } + std::unique_ptr outputTrack[2]; + double rate = mCurTrack[0]->GetRate(); - for (i = 0; i < outChannels; i++) { + for (size_t i = 0; i < outChannels; i++) { sampleFormat format = mCurTrack[i]->GetSampleFormat(); if (outChannels == (int)mCurNumChannels) { rate = mCurTrack[i]->GetRate(); } - mOutputTrack[i] = mFactory->NewWaveTrack(format, rate); + outputTrack[i] = mFactory->NewWaveTrack(format, rate); + + // Clean the initial buffer states again for the get callbacks + // -- is this really needed? mCurBuffer[i].Free(); } - int success = nyx_get_audio(StaticPutCallback, (void *)this); + // Now fully evaluate the sound + int success; + { + auto vr0 = valueRestorer( mOutputTrack[0], outputTrack[0].get() ); + auto vr1 = valueRestorer( mOutputTrack[1], outputTrack[1].get() ); + success = nyx_get_audio(StaticPutCallback, (void *)this); + } // See if GetCallback found read errors if (mFailedFileName.IsOk()) @@ -1250,38 +1273,29 @@ bool NyquistEffect::ProcessOne() // what, then? success = false; - if (!success) { - for(i = 0; i < outChannels; i++) { - mOutputTrack[i].reset(); - } - + if (!success) return false; - } - for (i = 0; i < outChannels; i++) { - mOutputTrack[i]->Flush(); - mCurBuffer[i].Free(); - mOutputTime = mOutputTrack[i]->GetEndTime(); + for (size_t i = 0; i < outChannels; i++) { + outputTrack[i]->Flush(); + mOutputTime = outputTrack[i]->GetEndTime(); if (mOutputTime <= 0) { wxMessageBox(_("Nyquist did not return audio.\n"), wxT("Nyquist"), wxOK | wxCENTRE, mUIParent); - for (int j = 0; j < outChannels; j++) { - mOutputTrack[j].reset(); - } return true; } } - for (i = 0; i < mCurNumChannels; i++) { + for (size_t i = 0; i < mCurNumChannels; i++) { WaveTrack *out; if (outChannels == (int)mCurNumChannels) { - out = mOutputTrack[i].get(); + out = outputTrack[i].get(); } else { - out = mOutputTrack[0].get(); + out = outputTrack[0].get(); } if (mMergeClips < 0) { @@ -1310,9 +1324,6 @@ bool NyquistEffect::ProcessOne() mFirstInGroup = false; } - for (i = 0; i < outChannels; i++) { - mOutputTrack[i].reset(); - } mProjectChanged = true; return true; } diff --git a/src/effects/nyquist/Nyquist.h b/src/effects/nyquist/Nyquist.h index 7009d4ece..6db9e0b04 100644 --- a/src/effects/nyquist/Nyquist.h +++ b/src/effects/nyquist/Nyquist.h @@ -224,7 +224,7 @@ private: sampleCount mCurBufferStart[2]; size_t mCurBufferLen[2]; - std::unique_ptr mOutputTrack[2]; + WaveTrack *mOutputTrack[2]; wxArrayString mCategories; From 4d4cd91d910a104900dd54c8f9f8ee22f1a852e6 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 19 Dec 2016 14:13:46 -0500 Subject: [PATCH 33/91] Hoist, and delay, the saving of import tag while opening the file... ... so that AudacityProject::AudacityProject no longer has a path in the static call graph that reaches block file write operations that might throw. So it is easier to prove that other functions, calling that, don't throw. Also delay the possibly thowing save of the import until after certain other steps in the file opening procedure. --- src/Project.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 84ff368ea..68064d633 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -3124,6 +3124,8 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) wxGetApp().AddFileToHistory(fileName); } + bool saved = false; + if (mIsRecovered) { // This project has been recovered, so write a NEW auto-save file @@ -3182,9 +3184,20 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) // this->PushState(_("Project checker repaired file"), _("Project Repair")); if (status & FSCKstatus_SAVE_AUP) - this->Save(); + this->Save(), saved = true; } } + + if (mImportXMLTagHandler) { + if (!saved) + // We processed an tag, so save it as a normal project, + // with no tags. + this->Save(); + + // Shouldn't need it any more. + mImportXMLTagHandler.reset(); + } + } else { // Vaughan, 2011-10-30: // See first topic at http://bugzilla.audacityteam.org/show_bug.cgi?id=451#c16. @@ -4298,14 +4311,6 @@ For an audio file that will open in other apps, use 'Export'.\n"), void AudacityProject::InitialState() { - if (mImportXMLTagHandler) { - // We processed an tag, so save it as a normal project, with no tags. - this->Save(); - - // Shouldn't need it any more. - mImportXMLTagHandler.reset(); - } - GetUndoManager()->ClearStates(); GetUndoManager()->PushState(GetTracks(), mViewInfo.selectedRegion, mTags, From 54c1b0c95544c2b68e2665efbe6ae7bb51604a3c Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 24 Nov 2016 10:03:55 -0500 Subject: [PATCH 34/91] Exception safety in: opening and saving of projects --- src/Project.cpp | 149 +++++++++++++++++++++++++++++++----------------- src/Project.h | 9 ++- 2 files changed, 103 insertions(+), 55 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 68064d633..a22e3d251 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -2866,6 +2866,11 @@ void AudacityProject::OpenFiles(AudacityProject *proj) selectedFiles.Sort(CompareNoCaseFileName); ODManager::Pauser pauser; + auto cleanup = finally( [] { + gPrefs->Write(wxT("/LastOpenType"),wxT("")); + gPrefs->Flush(); + } ); + for (size_t ff = 0; ff < selectedFiles.GetCount(); ff++) { const wxString &fileName = selectedFiles[ff]; @@ -2895,9 +2900,6 @@ void AudacityProject::OpenFiles(AudacityProject *proj) // and it's okay to open a NEW project inside this window. proj->OpenFile(fileName); } - - gPrefs->Write(wxT("/LastOpenType"),wxT("")); - gPrefs->Flush(); } // Most of this string was duplicated 3 places. Made the warning consistent in this global. @@ -2977,6 +2979,7 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) wxMessageBox(_("Could not open file: ") + fileName, _("Error opening file"), wxOK | wxCENTRE, this); + return; } int numRead = ff.Read(buf, 15); if (numRead != 15) { @@ -3045,6 +3048,12 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) XMLFileReader xmlFile; bool bParseSuccess = xmlFile.Parse(this, fileName); + + // Clean up now unused recording recovery handler if any + mRecordingRecoveryHandler.reset(); + + bool err = false; + if (bParseSuccess) { // By making a duplicate set of pointers to the existing blocks // on disk, we add one to their reference count, guaranteeing @@ -3052,7 +3061,6 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) // the version saved on disk will be preserved until the // user selects Save(). - bool err = false; Track *t; TrackListIterator iter(GetTracks()); mLastSavedTracks = std::make_unique(); @@ -3123,7 +3131,31 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) if (addtohistory) { wxGetApp().AddFileToHistory(fileName); } + } + // Use a finally block here, because there are calls to Save() below which + // might throw. + bool closed = false; + auto cleanup = finally( [&] { + //release the flag. + ODManager::UnmarkLoadedODFlag(); + + if (! closed ) { + // Shouldn't need it any more. + mImportXMLTagHandler.reset(); + + if ( bParseSuccess ) { + GetDirManager()->FillBlockfilesCache(); + EnqueueODTasks(); + } + + // For an unknown reason, OSX requires that the project window be + // raised if a recovery took place. + CallAfter( [this] { Raise(); } ); + } + } ); + + if (bParseSuccess) { bool saved = false; if (mIsRecovered) @@ -3162,12 +3194,15 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) SetProjectTitle(); mTrackPanel->Refresh(true); */ + closed = true; this->OnClose(); + return; } else if (status & FSCKstatus_CHANGED) { // Mark the wave tracks as changed and redraw. - t = iter.First(); + TrackListIterator iter(GetTracks()); + Track *t = iter.First(); while (t) { if (t->GetKind() == Track::Wave) { @@ -3193,12 +3228,9 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) // We processed an tag, so save it as a normal project, // with no tags. this->Save(); - - // Shouldn't need it any more. - mImportXMLTagHandler.reset(); } - - } else { + } + else { // Vaughan, 2011-10-30: // See first topic at http://bugzilla.audacityteam.org/show_bug.cgi?id=451#c16. // Calling mTracks->Clear() with deleteTracks true results in data loss. @@ -3224,15 +3256,10 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) _("Error Opening Project"), wxOK | wxCENTRE, this); } +} - // Clean up now unused recording recovery handler if any - mRecordingRecoveryHandler.reset(); - - if (!bParseSuccess) - return; // No need to do further processing if parse failed. - - GetDirManager()->FillBlockfilesCache(); - +void AudacityProject::EnqueueODTasks() +{ //check the ODManager to see if we should add the tracks to the ODManager. //this flag would have been set in the HandleXML calls from above, if there were //OD***Blocks. @@ -3290,14 +3317,7 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) } for(unsigned int i=0;iAddNewTask(std::move(newTasks[i])); - - //release the flag. - ODManager::UnmarkLoadedODFlag(); } - - // For an unknown reason, OSX requires that the project window be - // raised if a recovery took place. - Raise(); } bool AudacityProject::HandleXMLTag(const wxChar *tag, const wxChar **attrs) @@ -3570,7 +3590,7 @@ void AudacityProject::WriteXMLHeader(XMLWriter &xmlFile) const xmlFile.Write(wxT(">\n")); } -void AudacityProject::WriteXML(XMLWriter &xmlFile) +void AudacityProject::WriteXML(XMLWriter &xmlFile, bool bWantSaveCompressed) // may throw { //TIMER_START( "AudacityProject::WriteXML", xml_writer_timer ); @@ -3621,7 +3641,7 @@ void AudacityProject::WriteXML(XMLWriter &xmlFile) t = iter.First(); unsigned int ndx = 0; while (t) { - if ((t->GetKind() == Track::Wave) && mWantSaveCompressed) + if ((t->GetKind() == Track::Wave) && bWantSaveCompressed) { //vvv This should probably be a method, WaveTrack::WriteCompressedTrackXML(). xmlFile.StartTag(wxT("import")); @@ -3760,8 +3780,19 @@ bool AudacityProject::Save(bool overwrite /* = true */ , if (wxFileExists(safetyFileName)) wxRemoveFile(safetyFileName); - wxRename(mFileName, safetyFileName); + if ( !wxRenameFile(mFileName, safetyFileName) ) { + wxMessageBox(_("Could not create safety file: ") + safetyFileName, + _("Error"), wxICON_STOP, this); + return false; + } } + auto cleanup = finally( [&] { + if (safetyFileName != wxT("")) { + if (wxFileExists(mFileName)) + wxRemove(mFileName); + wxRename(safetyFileName, mFileName); + } + } ); if (fromSaveAs || mDirManager->GetProjectName() == wxT("")) { // Write the tracks. @@ -3773,12 +3804,9 @@ bool AudacityProject::Save(bool overwrite /* = true */ , wxString projName = wxFileNameFromPath(project) + wxT("_data"); wxString projPath = wxPathOnly(project); - mWantSaveCompressed = bWantSaveCompressed; bool success = false; if( !wxDir::Exists( projPath ) ){ - if (safetyFileName != wxT("")) - wxRename(safetyFileName, mFileName); wxMessageBox(wxString::Format( _("Could not save project. Path not found. Try creating \ndirectory \"%s\" before saving project with this name."), projPath.c_str()), @@ -3823,8 +3851,6 @@ bool AudacityProject::Save(bool overwrite /* = true */ , } if (!success) { - if (safetyFileName != wxT("")) - wxRename(safetyFileName, mFileName); wxMessageBox(wxString::Format(_("Could not save project. Perhaps %s \nis not writable or the disk is full."), project.c_str()), _("Error Saving Project"), @@ -3838,7 +3864,7 @@ bool AudacityProject::Save(bool overwrite /* = true */ , XMLFileWriter saveFile{ mFileName, _("Error Saving Project") }; WriteXMLHeader(saveFile); - WriteXML(saveFile); + WriteXML(saveFile, bWantSaveCompressed); mStrOtherNamesArray.Clear(); saveFile.Commit(); @@ -3849,9 +3875,9 @@ bool AudacityProject::Save(bool overwrite /* = true */ , if (!success) return false; - if (bWantSaveCompressed) - mWantSaveCompressed = false; // Don't want this mode for AudacityProject::WriteXML() any more. - else + // SAVE HAS SUCCEEDED -- following are further no-fail commit operations. + + if ( !bWantSaveCompressed ) { // Now that we have saved the file, we can DELETE the auto-saved version DeleteCurrentAutoSaveFile(); @@ -3868,7 +3894,8 @@ bool AudacityProject::Save(bool overwrite /* = true */ , mIsRecovered = false; mRecoveryAutoSaveDataDir = wxT(""); SetProjectTitle(); - } else if (fromSaveAs) + } + else if (fromSaveAs) { // On save as, always remove orphaned blockfiles that may be left over // because the user is trying to overwrite another project @@ -3899,7 +3926,9 @@ bool AudacityProject::Save(bool overwrite /* = true */ , // the .bak file (because it now does not fit our block files anymore // anyway). if (safetyFileName != wxT("")) - wxRemoveFile(safetyFileName); + wxRemoveFile(safetyFileName), + // cancel the cleanup: + safetyFileName = wxT(""); mStatusBar->SetStatusText(wxString::Format(_("Saved %s"), mFileName.c_str()), mainStatusBarField); @@ -4177,19 +4206,25 @@ bool AudacityProject::SaveAs(const wxString & newFileName, bool bWantSaveCompres } mFileName = newFileName; + bool success = false; + auto cleanup = finally( [&] { + if (!success || bWantSaveCompressed) + // Restore file name on error + mFileName = oldFileName; + } ); + //Don't change the title, unless we succeed. //SetProjectTitle(); - bool success = Save(false, true, bWantSaveCompressed); + success = Save(false, true, bWantSaveCompressed); if (success && addToHistory) { wxGetApp().AddFileToHistory(mFileName); } if (!success || bWantSaveCompressed) // bWantSaveCompressed doesn't actually change current project. { - // Restore file name on error - mFileName = oldFileName; - } else { + } + else { mbLoadedFromAup = true; SetProjectTitle(); } @@ -4281,8 +4316,14 @@ For an audio file that will open in other apps, use 'Export'.\n"), wxString oldFileName = mFileName; mFileName = fName; + bool success = false; + auto cleanup = finally( [&] { + if (!success || bWantSaveCompressed) + // Restore file name on error + mFileName = oldFileName; + } ); - bool success = Save(false, true, bWantSaveCompressed); + success = Save(false, true, bWantSaveCompressed); if (success) { wxGetApp().AddFileToHistory(mFileName); @@ -4294,9 +4335,8 @@ For an audio file that will open in other apps, use 'Export'.\n"), } if (!success || bWantSaveCompressed) // bWantSaveCompressed doesn't actually change current project. { - // Reset file name on error - mFileName = oldFileName; - } else { + } + else { mbLoadedFromAup = true; SetProjectTitle(); } @@ -5103,7 +5143,7 @@ void AudacityProject::AutoSave() AutoSaveFile buffer; WriteXMLHeader(buffer); - WriteXML(buffer); + WriteXML(buffer, false); mStrOtherNamesArray.Clear(); wxFFile saveFile; @@ -5563,7 +5603,7 @@ bool AudacityProject::SaveFromTimerRecording(wxFileName fnFile) { wxString sNewFileName = fnFile.GetFullPath(); // MY: To allow SaveAs from Timer Recording we need to check what - // the value of mFileName is befoer we change it. + // the value of mFileName is before we change it. wxString sOldFilename = ""; if (IsProjectSaved()) { sOldFilename = mFileName; @@ -5577,16 +5617,19 @@ bool AudacityProject::SaveFromTimerRecording(wxFileName fnFile) { } mFileName = sNewFileName; + bool bSuccess = false; + auto cleanup = finally( [&] { + if (!bSuccess) + // Restore file name on error + mFileName = sOldFilename; + } ); - bool bSuccess = Save(false, true, false); + bSuccess = Save(false, true, false); if (bSuccess) { wxGetApp().AddFileToHistory(mFileName); mbLoadedFromAup = true; SetProjectTitle(); - } else { - // Restore file name on error - mFileName = sOldFilename; } return bSuccess; diff --git a/src/Project.h b/src/Project.h index 3888f742f..4198bef9f 100644 --- a/src/Project.h +++ b/src/Project.h @@ -243,6 +243,11 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame, static bool IsAlreadyOpen(const wxString & projPathName); static void OpenFiles(AudacityProject *proj); void OpenFile(const wxString &fileName, bool addtohistory = true); + +private: + void EnqueueODTasks(); + +public: bool WarnOfLegacyFile( ); // If pNewTrackList is passed in non-NULL, it gets filled with the pointers to NEW tracks. @@ -511,7 +516,8 @@ public: bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override; XMLTagHandler *HandleXMLChild(const wxChar *tag) override; - void WriteXML(XMLWriter &xmlFile) /* not override */; + void WriteXML( + XMLWriter &xmlFile, bool bWantSaveCompressed) /* not override */; void WriteXMLHeader(XMLWriter &xmlFile) const; @@ -702,7 +708,6 @@ private: // Dependencies have been imported and a warning should be shown on save bool mImportedDependencies{ false }; - bool mWantSaveCompressed{ false }; wxArrayString mStrOtherNamesArray; // used to make sure compressed file names are unique // Last effect applied to this project From 7159966eb4686716b058efa02a5d4c0985b1c681 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 20 Mar 2017 11:18:30 -0400 Subject: [PATCH 35/91] Comment that cache-filling should be no-fail (we don't use it anyway) --- src/BlockFile.h | 3 ++- src/DirManager.h | 4 +++- src/Project.cpp | 2 ++ src/blockfile/SimpleBlockFile.cpp | 2 ++ src/blockfile/SimpleBlockFile.h | 3 ++- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/BlockFile.h b/src/BlockFile.h index 5c6233253..71b63ed78 100644 --- a/src/BlockFile.h +++ b/src/BlockFile.h @@ -78,7 +78,8 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ { // Fill read cache of block file, if it has any virtual bool GetNeedFillCache() { return false; } - virtual void FillCache() { /* no cache by default */ } + + virtual void FillCache() /* noexcept */ { /* no cache by default */ } /// Stores a representation of this file in XML virtual void SaveXML(XMLWriter &xmlFile) = 0; diff --git a/src/DirManager.h b/src/DirManager.h index f98996368..55b2e8b76 100644 --- a/src/DirManager.h +++ b/src/DirManager.h @@ -177,7 +177,9 @@ class PROFILE_DLL_API DirManager final : public XMLTagHandler { // Write all write-cached block files to disc, if any void WriteCacheToDisk(); - // Fill cache of blockfiles, if caching is enabled (otherwise do nothing) + // (Try to) fill cache of blockfiles, if caching is enabled (otherwise do + // nothing) + // A no-fail operation that does not throw void FillBlockfilesCache(); private: diff --git a/src/Project.cpp b/src/Project.cpp index a22e3d251..137cd1be5 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -3145,6 +3145,7 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) mImportXMLTagHandler.reset(); if ( bParseSuccess ) { + // This is a no-fail: GetDirManager()->FillBlockfilesCache(); EnqueueODTasks(); } @@ -4183,6 +4184,7 @@ bool AudacityProject::Import(const wxString &fileName, WaveTrackArray* pTrackArr OnEffectFlags::kConfigured); } + // This is a no-fail: GetDirManager()->FillBlockfilesCache(); return true; } diff --git a/src/blockfile/SimpleBlockFile.cpp b/src/blockfile/SimpleBlockFile.cpp index c1482b984..c791a6551 100644 --- a/src/blockfile/SimpleBlockFile.cpp +++ b/src/blockfile/SimpleBlockFile.cpp @@ -267,6 +267,8 @@ bool SimpleBlockFile::WriteSimpleBlockFile( return true; } +// This function should try to fill the cache, but just return without effect +// (not throwing) if there is failure. void SimpleBlockFile::FillCache() { if (mCache.active) diff --git a/src/blockfile/SimpleBlockFile.h b/src/blockfile/SimpleBlockFile.h index f95e80bfb..a7fc761a3 100644 --- a/src/blockfile/SimpleBlockFile.h +++ b/src/blockfile/SimpleBlockFile.h @@ -82,7 +82,8 @@ class PROFILE_DLL_API SimpleBlockFile /* not final */ : public BlockFile { void WriteCacheToDisk() override; bool GetNeedFillCache() override { return !mCache.active; } - void FillCache() override; + + void FillCache() /* noexcept */ override; protected: From f5fe9281e4ff625ad8c64a7143977e4d66c7b9d3 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 24 Nov 2016 10:04:40 -0500 Subject: [PATCH 36/91] Strong safety guarantee for removing file dependencies --- src/BlockFile.cpp | 1 + src/Dependencies.cpp | 40 +++++++++++++++++++++------------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp index fcb3f9d2f..db43cfc26 100644 --- a/src/BlockFile.cpp +++ b/src/BlockFile.cpp @@ -116,6 +116,7 @@ unsigned long BlockFile::gBlockFileDestructionCount { 0 }; BlockFile::~BlockFile() { if (!IsLocked() && mFileName.HasName()) + // PRL: what should be done if this fails? wxRemoveFile(mFileName.GetFullPath()); ++gBlockFileDestructionCount; diff --git a/src/Dependencies.cpp b/src/Dependencies.cpp index c728e4cd5..1406e30b5 100644 --- a/src/Dependencies.cpp +++ b/src/Dependencies.cpp @@ -81,16 +81,12 @@ static void GetAllSeqBlocks(AudacityProject *project, // tracks and replace each aliased block file with its replacement. // Note that this code respects reference-counting and thus the // process of making a project self-contained is actually undoable. -static void ReplaceBlockFiles(AudacityProject *project, +static void ReplaceBlockFiles(BlockPtrArray &blocks, ReplacedBlockFileHash &hash) +// NOFAIL-GUARANTEE { - //const auto &dirManager = project->GetDirManager(); - BlockPtrArray blocks; - GetAllSeqBlocks(project, &blocks); - - int i; - for (i = 0; i < (int)blocks.size(); i++) { - auto &f = blocks[i]->f; + for (const auto &pBlock : blocks) { + auto &f = pBlock->f; const auto src = &*f; if (hash.count( src ) > 0) { const auto &dst = hash[src]; @@ -156,6 +152,7 @@ void FindDependencies(AudacityProject *project, // all of those alias block files with disk block files. static void RemoveDependencies(AudacityProject *project, AliasedFileArray &aliasedFiles) +// STRONG-GUARANTEE { const auto &dirManager = project->GetDirManager(); @@ -198,6 +195,8 @@ static void RemoveDependencies(AudacityProject *project, BlockFilePtr newBlockFile; { SampleBuffer buffer(len, format); + // We tolerate exceptions from NewSimpleBlockFile and so we + // can allow exceptions from ReadData too f->ReadData(buffer.ptr(), format, 0, len); newBlockFile = dirManager->NewSimpleBlockFile(buffer.ptr(), len, format); @@ -210,15 +209,18 @@ static void RemoveDependencies(AudacityProject *project, completedBytes += SAMPLE_SIZE(format) * len; updateResult = progress.Update(completedBytes, totalBytesToProcess); if (updateResult != ProgressResult::Success) - break; + // leave the project unchanged + return; } } + // COMMIT OPERATIONS needing NOFAIL-GUARANTEE: + // Above, we created a SimpleBlockFile contained in our project // to go with each AliasBlockFile that we wanted to migrate. // However, that didn't actually change any references to these // blockfiles in the Sequences, so we do that next... - ReplaceBlockFiles(project, blockFileHash); + ReplaceBlockFiles(blocks, blockFileHash); } // @@ -473,22 +475,22 @@ void DependencyDialog::OnYes(wxCommandEvent & WXUNUSED(event)) void DependencyDialog::OnCopySelectedFiles(wxCommandEvent & WXUNUSED(event)) { - AliasedFileArray aliasedFilesToDelete; + AliasedFileArray aliasedFilesToDelete, remainingAliasedFiles; long i = 0; - for(auto iter = mAliasedFiles.begin(); iter != mAliasedFiles.end();) { - if (mFileListCtrl->GetItemState(i, wxLIST_STATE_SELECTED)) { - // Two-step move could be simplified when all compilers have C++11 vector - aliasedFilesToDelete.push_back(AliasedFile{}); - aliasedFilesToDelete.back() = std::move(*iter); - iter = mAliasedFiles.erase(iter); - } + for( const auto &file : mAliasedFiles ) { + if (mFileListCtrl->GetItemState(i, wxLIST_STATE_SELECTED)) + aliasedFilesToDelete.push_back( file ); else - ++iter; + remainingAliasedFiles.push_back( file ); ++i; } + // provides STRONG-GUARANTEE RemoveDependencies(mProject, aliasedFilesToDelete); + + // COMMIT OPERATIONS needing NOFAIL-GUARANTEE: + mAliasedFiles.swap( remainingAliasedFiles ); PopulateList(); if (mAliasedFiles.empty() || !mHasNonMissingFiles) From ed6f2ea80f78f8b1ad811f7401c0d0376dc5f77f Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 28 Nov 2016 14:28:44 -0500 Subject: [PATCH 37/91] Exception safety in: locking of BlockFile for read --- src/BlockFile.h | 32 +++++++++++++++++++++++++++ src/DirManager.cpp | 26 +++++----------------- src/blockfile/ODDecodeBlockFile.cpp | 24 +++++++++----------- src/blockfile/ODPCMAliasBlockFile.cpp | 26 ++++++++-------------- src/ondemand/ODDecodeTask.cpp | 19 ++++++++-------- 5 files changed, 66 insertions(+), 61 deletions(-) diff --git a/src/BlockFile.h b/src/BlockFile.h index 71b63ed78..8e9813a62 100644 --- a/src/BlockFile.h +++ b/src/BlockFile.h @@ -163,11 +163,43 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ { // not balanced by unlocking calls. virtual void CloseLock(){Lock();} + protected: /// Prevents a read on other threads. The basic blockfile runs on only one thread, so does nothing. virtual void LockRead() const {} /// Allows reading on other threads. virtual void UnlockRead() const {} + struct ReadLocker { void operator () ( const BlockFile *p ) const { + if (p) p->LockRead(); } }; + struct ReadUnlocker { void operator () ( const BlockFile *p ) const { + if (p) p->UnlockRead(); } }; + using ReadLockBase = + movable_ptr_with_deleter< const BlockFile, ReadUnlocker >; + + public: + class ReadLock : public ReadLockBase + { + friend BlockFile; + ReadLock ( const BlockFile *p, const BlockFile::ReadUnlocker &u ) + : ReadLockBase { p, u } {} + public: +#ifdef __AUDACITY_OLD_STD__ + ReadLock (const ReadLock &that) : ReadLockBase( that ) {} + ReadLock &operator= (const ReadLock &that) + { + *((ReadLockBase*)this) = that; + } +#endif + ReadLock(ReadLock&&that) : ReadLockBase{ std::move(that) } {} + using Suspension = std::unique_ptr< const BlockFile, ReadLocker >; + Suspension Suspend() const + { if (get()) get()->UnlockRead(); + return Suspension{ get(), ReadLocker{} }; } + }; + + // RAII wrapper about the read locking functions + ReadLock LockForRead() const { LockRead(); return { this, ReadUnlocker{} }; } + private: protected: diff --git a/src/DirManager.cpp b/src/DirManager.cpp index 7a544ca3e..44afdd9b7 100644 --- a/src/DirManager.cpp +++ b/src/DirManager.cpp @@ -1405,6 +1405,7 @@ bool DirManager::EnsureSafeFilename(const wxFileName &fName) bool needToRename = false; wxBusyCursor busy; BlockHash::iterator iter = mBlockFileHash.begin(); + std::vector< BlockFile::ReadLock > readLocks; while (iter != mBlockFileHash.end()) { BlockFilePtr b = iter->second.lock(); @@ -1420,14 +1421,14 @@ bool DirManager::EnsureSafeFilename(const wxFileName &fName) needToRename = true; //ODBlocks access the aliased file on another thread, so we need to pause them before this continues. - ab->LockRead(); + readLocks.push_back( ab->LockForRead() ); } //now for encoded OD blocks (e.g. flac) else if (!b->IsDataAvailable() && db->GetEncodedAudioFilename() == fName) { needToRename = true; //ODBlocks access the aliased file on another thread, so we need to pause them before this continues. - db->LockRead(); + readLocks.push_back( db->LockForRead() ); } } ++iter; @@ -1443,27 +1444,12 @@ bool DirManager::EnsureSafeFilename(const wxFileName &fName) // second earlier.) But we'll handle this scenario // just in case!!! - // Put things back where they were - BlockHash::iterator iter = mBlockFileHash.begin(); - while (iter != mBlockFileHash.end()) - { - BlockFilePtr b = iter->second.lock(); - if (b) { - auto ab = static_cast< AliasBlockFile * > ( &*b ); - auto db = static_cast< ODDecodeBlockFile * > ( &*b ); - - if (b->IsAlias() && (ab->GetAliasedFileName() == fName)) - ab->UnlockRead(); - if (!b->IsDataAvailable() && (db->GetEncodedAudioFilename() == fName)) - db->UnlockRead(); - } - ++iter; - } - // Print error message and cancel the export wxLogSysError(_("Unable to rename '%s' to '%s'."), fullPath.c_str(), renamedFullPath.c_str()); + + // Destruction of readLocks puts things back where they were return false; } else @@ -1480,14 +1466,12 @@ bool DirManager::EnsureSafeFilename(const wxFileName &fName) if (b->IsAlias() && ab->GetAliasedFileName() == fName) { ab->ChangeAliasedFileName(wxFileNameWrapper{ renamedFileName }); - ab->UnlockRead(); wxPrintf(_("Changed block %s to new alias name\n"), b->GetFileName().name.GetFullName().c_str()); } else if (!b->IsDataAvailable() && db->GetEncodedAudioFilename() == fName) { db->ChangeAudioFile(wxFileNameWrapper{ renamedFileName }); - db->UnlockRead(); } } ++iter; diff --git a/src/blockfile/ODDecodeBlockFile.cpp b/src/blockfile/ODDecodeBlockFile.cpp index c87207948..e5c0f3681 100644 --- a/src/blockfile/ODDecodeBlockFile.cpp +++ b/src/blockfile/ODDecodeBlockFile.cpp @@ -164,7 +164,7 @@ BlockFilePtr ODDecodeBlockFile::Copy(wxFileNameWrapper &&newFileName) BlockFilePtr newBlockFile; //mAliasedFile can change so we lock readdatamutex, which is responsible for it. - LockRead(); + auto locker = LockForRead(); if(IsSummaryAvailable()) { //create a simpleblockfile, because once it has the summary it is a simpleblockfile for all intents an purposes @@ -181,8 +181,6 @@ BlockFilePtr ODDecodeBlockFile::Copy(wxFileNameWrapper &&newFileName) //It can do this by checking for IsDataAvailable()==false. } - UnlockRead(); - return newBlockFile; } @@ -194,7 +192,7 @@ BlockFilePtr ODDecodeBlockFile::Copy(wxFileNameWrapper &&newFileName) void ODDecodeBlockFile::SaveXML(XMLWriter &xmlFile) // may throw { - LockRead(); + auto locker = LockForRead(); if(IsSummaryAvailable()) { SimpleBlockFile::SaveXML(xmlFile); @@ -202,12 +200,12 @@ void ODDecodeBlockFile::SaveXML(XMLWriter &xmlFile) else { xmlFile.StartTag(wxT("oddecodeblockfile")); - //unlock to prevent deadlock and resume lock after. - UnlockRead(); - mFileNameMutex.Lock(); - xmlFile.WriteAttr(wxT("summaryfile"), mFileName.GetFullName()); - mFileNameMutex.Unlock(); - LockRead(); + { + //unlock to prevent deadlock and resume lock after. + auto suspension = locker.Suspend(); + ODLocker locker2{ &mFileNameMutex }; + xmlFile.WriteAttr(wxT("summaryfile"), mFileName.GetFullName()); + } xmlFile.WriteAttr(wxT("audiofile"), mAudioFileName.GetFullPath()); xmlFile.WriteAttr(wxT("aliasstart"), mAliasStart.as_long_long()); @@ -217,7 +215,6 @@ void ODDecodeBlockFile::SaveXML(XMLWriter &xmlFile) xmlFile.EndTag(wxT("oddecodeblockfile")); } - UnlockRead(); } /// Constructs a ODDecodeBlockFile from the xml output of WriteXML. @@ -435,17 +432,16 @@ size_t ODDecodeBlockFile::ReadData(samplePtr data, sampleFormat format, size_t start, size_t len) const { size_t ret; - LockRead(); + auto locker = LockForRead(); if(IsSummaryAvailable()) ret = SimpleBlockFile::ReadData(data,format,start,len); else { - //we should do an ODRequest to start processing the data here, and wait till it finishes. and just do a SimpleBlockFIle + //we should do an ODRequest to start processing the data here, and wait till it finishes. and just do a SimpleBlockFile //ReadData. ClearSamples(data, format, 0, len); ret = len; } - UnlockRead(); return ret; } diff --git a/src/blockfile/ODPCMAliasBlockFile.cpp b/src/blockfile/ODPCMAliasBlockFile.cpp index c90440319..678d74f88 100644 --- a/src/blockfile/ODPCMAliasBlockFile.cpp +++ b/src/blockfile/ODPCMAliasBlockFile.cpp @@ -196,7 +196,7 @@ BlockFilePtr ODPCMAliasBlockFile::Copy(wxFileNameWrapper &&newFileName) BlockFilePtr newBlockFile; //mAliasedFile can change so we lock readdatamutex, which is responsible for it. - LockRead(); + auto locker = LockForRead(); //If the file has been written AND it has been saved, we create a PCM alias blockfile because for //all intents and purposes, it is the same. //However, if it hasn't been saved yet, we shouldn't create one because the default behavior of the @@ -218,8 +218,6 @@ BlockFilePtr ODPCMAliasBlockFile::Copy(wxFileNameWrapper &&newFileName) //The client code will need to schedule this blockfile for OD summarizing if it is going to a NEW track. } - UnlockRead(); - return newBlockFile; } @@ -232,7 +230,7 @@ void ODPCMAliasBlockFile::SaveXML(XMLWriter &xmlFile) // may throw { //we lock this so that mAliasedFileName doesn't change. - LockRead(); + auto locker = LockForRead(); if(IsSummaryAvailable()) { PCMAliasBlockFile::SaveXML(xmlFile); @@ -243,11 +241,11 @@ void ODPCMAliasBlockFile::SaveXML(XMLWriter &xmlFile) xmlFile.StartTag(wxT("odpcmaliasblockfile")); //unlock to prevent deadlock and resume lock after. - UnlockRead(); - mFileNameMutex.Lock(); - xmlFile.WriteAttr(wxT("summaryfile"), mFileName.GetFullName()); - mFileNameMutex.Unlock(); - LockRead(); + { + auto suspension = locker.Suspend(); + ODLocker locker2 { &mFileNameMutex }; + xmlFile.WriteAttr(wxT("summaryfile"), mFileName.GetFullName()); + } xmlFile.WriteAttr(wxT("aliasfile"), mAliasedFileName.GetFullPath()); xmlFile.WriteAttr(wxT("aliasstart"), @@ -257,8 +255,6 @@ void ODPCMAliasBlockFile::SaveXML(XMLWriter &xmlFile) xmlFile.EndTag(wxT("odpcmaliasblockfile")); } - - UnlockRead(); } /// Constructs a ODPCMAliasBlockFile from the xml output of WriteXML. @@ -488,20 +484,16 @@ size_t ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, size_t start, size_t len) const { - LockRead(); + auto locker = LockForRead(); if(!mAliasedFileName.IsOk()){ // intentionally silenced memset(data,0,SAMPLE_SIZE(format)*len); - UnlockRead(); return len; } - auto result = CommonReadData( + return CommonReadData( mAliasedFileName, mSilentAliasLog, this, mAliasStart, mAliasChannel, data, format, start, len); - - UnlockRead(); - return result; } /// Read the summary of this alias block from disk. Since the audio data diff --git a/src/ondemand/ODDecodeTask.cpp b/src/ondemand/ODDecodeTask.cpp index 91e7d78fe..32a191c5d 100644 --- a/src/ondemand/ODDecodeTask.cpp +++ b/src/ondemand/ODDecodeTask.cpp @@ -57,15 +57,16 @@ void ODDecodeTask::DoSomeInternal() //OD TODO: somehow pass the bf a reference to the decoder that manages its file. //we need to ensure that the filename won't change or be moved. We do this by calling LockRead(), //which the dirmanager::EnsureSafeFilename also does. - bf->LockRead(); - //Get the decoder. If the file was moved, we need to create another one and init it. - decoder = GetOrCreateMatchingFileDecoder( &*bf ); - if(!decoder->IsInitialized()) - decoder->Init(); - bf->SetODFileDecoder(decoder); - // Does not throw: - ret = bf->DoWriteBlockFile(); - bf->UnlockRead(); + { + auto locker = bf->LockForRead(); + //Get the decoder. If the file was moved, we need to create another one and init it. + decoder = GetOrCreateMatchingFileDecoder( &*bf ); + if(!decoder->IsInitialized()) + decoder->Init(); + bf->SetODFileDecoder(decoder); + // Does not throw: + ret = bf->DoWriteBlockFile(); + } if(ret >= 0) { success = true; From 2626f6cd5b4bf5f5277754f2cc5b8247556376ff Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 16 Aug 2016 13:56:15 -0400 Subject: [PATCH 38/91] Exception safety in: subclasses of ImportFileHandle --- src/import/ImportFFmpeg.cpp | 2 + src/import/ImportFLAC.cpp | 3 +- src/import/ImportGStreamer.cpp | 21 +++++--- src/import/ImportLOF.cpp | 96 ++++++++++++++++++---------------- src/import/ImportMP3.cpp | 16 +++--- src/import/ImportOGG.cpp | 3 +- src/import/ImportPCM.cpp | 9 +++- src/import/ImportPlugin.h | 3 ++ src/import/ImportQT.cpp | 60 ++++++++++++--------- 9 files changed, 124 insertions(+), 89 deletions(-) diff --git a/src/import/ImportFFmpeg.cpp b/src/import/ImportFFmpeg.cpp index 5b07978d4..be51feec5 100644 --- a/src/import/ImportFFmpeg.cpp +++ b/src/import/ImportFFmpeg.cpp @@ -847,6 +847,8 @@ void FFmpegImportFileHandle::GetMetadata(Tags *tags, const wxChar *tag, const ch FFmpegImportFileHandle::~FFmpegImportFileHandle() { + av_log_set_callback(av_log_default_callback); + // Do this before unloading the libraries mContext.reset(); diff --git a/src/import/ImportFLAC.cpp b/src/import/ImportFLAC.cpp index 1a1ab45f4..a65f3af58 100644 --- a/src/import/ImportFLAC.cpp +++ b/src/import/ImportFLAC.cpp @@ -561,7 +561,8 @@ ProgressResult FLACImportFileHandle::Import(TrackFactory *trackFactory, FLACImportFileHandle::~FLACImportFileHandle() { - //don't DELETE mFile if we are using OD. + //don't finish *mFile if we are using OD, + //because it was not initialized in Init(). #ifndef EXPERIMENTAL_OD_FLAC mFile->finish(); #endif diff --git a/src/import/ImportGStreamer.cpp b/src/import/ImportGStreamer.cpp index 5ad602c87..0a339481f 100644 --- a/src/import/ImportGStreamer.cpp +++ b/src/import/ImportGStreamer.cpp @@ -157,7 +157,8 @@ struct GStreamContext }; // For RAII on gst objects -template using GstObjHandle = std::unique_ptr < T, Deleter > ; +template using GstObjHandle = + std::unique_ptr < T, Deleter > ; ///! Does actual import, returned by GStreamerImportPlugin::Open class GStreamerImportFileHandle final : public ImportFileHandle @@ -225,8 +226,8 @@ private: TrackFactory *mTrackFactory; //!< Factory to create tracks when samples arrive GstString mUri; //!< URI of file - GstObjHandle mPipeline; //!< GStreamer pipeline - GstObjHandle mBus; //!< Message bus + GstObjHandle mPipeline; //!< GStreamer pipeline + GstObjHandle mBus; //!< Message bus GstElement *mDec; //!< uridecodebin element bool mAsyncDone; //!< true = 1st async-done message received @@ -273,17 +274,21 @@ GetGStreamerImportPlugin(ImportPluginList &importPluginList, // Initialize gstreamer GErrorHandle error; - int argc = 0; - char **argv = NULL; - GError *ee; - if (!gst_init_check(&argc, &argv, &ee)) + bool initError; + { + int argc = 0; + char **argv = NULL; + GError *ee; + initError = !gst_init_check(&argc, &argv, &ee); + error.reset(ee); + } + if ( initError ) { wxLogMessage(wxT("Failed to initialize GStreamer. Error %d: %s"), error.get()->code, wxString::FromUTF8(error.get()->message).c_str()); return; } - error.reset(ee); guint major, minor, micro, nano; gst_version(&major, &minor, µ, &nano); diff --git a/src/import/ImportLOF.cpp b/src/import/ImportLOF.cpp index 722a4f428..730315639 100644 --- a/src/import/ImportLOF.cpp +++ b/src/import/ImportLOF.cpp @@ -142,24 +142,23 @@ public: private: // Takes a line of text in lof file and interprets it and opens files void lofOpenFiles(wxString* ln); - void doDuration(); - void doScrollOffset(); + void doDurationAndScrollOffset(); std::unique_ptr mTextFile; wxFileName mLOFFileName; /**< The name of the LOF file, which is used to interpret relative paths in it */ - AudacityProject *mProject; + AudacityProject *mProject{ GetActiveProject() }; // In order to know whether or not to create a NEW window - bool windowCalledOnce; + bool windowCalledOnce{ false }; // In order to zoom in, it must be done after files are opened - bool callDurationFactor; - double durationFactor; + bool callDurationFactor{ false }; + double durationFactor{ 1 }; // In order to offset scrollbar, it must be done after files are opened - bool callScrollOffset; - double scrollOffset; + bool callScrollOffset{ false }; + double scrollOffset{ 0 }; }; LOFImportFileHandle::LOFImportFileHandle @@ -168,12 +167,6 @@ LOFImportFileHandle::LOFImportFileHandle mTextFile(std::move(file)) , mLOFFileName{name} { - mProject = GetActiveProject(); - windowCalledOnce = false; - callDurationFactor = false; - durationFactor = 1; - callScrollOffset = false; - scrollOffset = 0; } void GetLOFImportPlugin(ImportPluginList &importPluginList, @@ -190,28 +183,27 @@ wxString LOFImportPlugin::GetPluginFormatDescription() std::unique_ptr LOFImportPlugin::Open(const wxString &filename) { // Check if it is a binary file - wxFile binaryFile; - if (!binaryFile.Open(filename)) - return nullptr; // File not found - - char buf[BINARY_FILE_CHECK_BUFFER_SIZE]; - int count = binaryFile.Read(buf, BINARY_FILE_CHECK_BUFFER_SIZE); - - for (int i = 0; i < count; i++) { - // Check if this char is below the space character, but not a - // line feed or carriage return - if (buf[i] < 32 && buf[i] != 10 && buf[i] != 13) + wxFile binaryFile; + if (!binaryFile.Open(filename)) + return nullptr; // File not found + + char buf[BINARY_FILE_CHECK_BUFFER_SIZE]; + int count = binaryFile.Read(buf, BINARY_FILE_CHECK_BUFFER_SIZE); + + for (int i = 0; i < count; i++) { - // Assume it is a binary file - binaryFile.Close(); - return nullptr; + // Check if this char is below the space character, but not a + // line feed or carriage return + if (buf[i] < 32 && buf[i] != 10 && buf[i] != 13) + { + // Assume it is a binary file + binaryFile.Close(); + return nullptr; + } } } - // Close it again so it can be opened as a text file - binaryFile.Close(); - // Now open the file again as text file auto file = std::make_unique(filename); file->Open(); @@ -235,6 +227,18 @@ auto LOFImportFileHandle::GetFileUncompressedBytes() -> ByteCount ProgressResult LOFImportFileHandle::Import(TrackFactory * WXUNUSED(trackFactory), TrackHolders &outTracks, Tags * WXUNUSED(tags)) { + // Unlike other ImportFileHandle subclasses, this one never gives any tracks + // back to the caller. + // Instead, it recursively calls AudacityProject::Import for each file listed + // in the .lof file. + // Each importation creates a new undo state. + // If there is an error or exception during one of them, only that one's + // side effects are rolled back, and the rest of the import list is skipped. + // The file may have "window" directives that cause new AudacityProjects + // to be created, and the undo states are pushed onto the latest project. + // If a project is created but the first file import into it fails, destroy + // the project. + outTracks.clear(); wxASSERT(mTextFile->IsOpened()); @@ -256,15 +260,13 @@ ProgressResult LOFImportFileHandle::Import(TrackFactory * WXUNUSED(trackFactory) // for last line lofOpenFiles(&line); + if(!mTextFile->Close()) + return ProgressResult::Failed; + // set any duration/offset factors for last window, as all files were called - doDuration(); - doScrollOffset(); + doDurationAndScrollOffset(); - // exited ok - if(mTextFile->Close()) - return ProgressResult::Success; - - return ProgressResult::Failed; + return ProgressResult::Success; } static int CountNumTracks(AudacityProject *proj) @@ -302,8 +304,7 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) if (tokenholder.IsSameAs(wxT("window"), false)) { // set any duration/offset factors for last window, as all files were called - doDuration(); - doScrollOffset(); + doDurationAndScrollOffset(); if (windowCalledOnce) { @@ -380,6 +381,8 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) } } + // Do recursive call to import + #ifdef USE_MIDI // If file is a midi if (targetfile.AfterLast(wxT('.')).IsSameAs(wxT("mid"), false) @@ -459,6 +462,9 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) t->SetOffset(offset); } } + + // Amend the undo transaction made by import + mProject->TP_ModifyState(false); } // end of converting "offset" argument else { @@ -481,23 +487,25 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) } } -void LOFImportFileHandle::doDuration() +void LOFImportFileHandle::doDurationAndScrollOffset() { + bool doSomething = callDurationFactor || callScrollOffset; if (callDurationFactor) { double longestDuration = mProject->GetTracks()->GetEndTime(); mProject->ZoomBy(longestDuration / durationFactor); callDurationFactor = false; } -} -void LOFImportFileHandle::doScrollOffset() -{ if (callScrollOffset && (scrollOffset != 0)) { mProject->TP_ScrollWindow(scrollOffset); callScrollOffset = false; } + + if (doSomething) + // Amend last undo state + mProject->TP_ModifyState(false); } LOFImportFileHandle::~LOFImportFileHandle() diff --git a/src/import/ImportMP3.cpp b/src/import/ImportMP3.cpp index 14663e944..6941f8138 100644 --- a/src/import/ImportMP3.cpp +++ b/src/import/ImportMP3.cpp @@ -269,6 +269,10 @@ void MP3ImportFileHandle::ImportID3(Tags *tags) #ifdef USE_LIBID3TAG wxFile f; // will be closed when it goes out of scope struct id3_file *fp = NULL; + auto cleanup = finally([&]{ + if (fp) + id3_file_close(fp); + }); if (f.Open(mFilename)) { // Use id3_file_fdopen() instead of id3_file_open since wxWidgets can open a @@ -285,10 +289,8 @@ void MP3ImportFileHandle::ImportID3(Tags *tags) f.Detach(); struct id3_tag *tp = id3_file_tag(fp); - if (!tp) { - id3_file_close(fp); + if (!tp) return; - } tags->Clear(); @@ -357,6 +359,7 @@ void MP3ImportFileHandle::ImportID3(Tags *tags) else if (frame->nfields == 3) { ustr = id3_field_getstring(&frame->fields[1]); if (ustr) { + // Is this duplication really needed? MallocString<> str{ (char *)id3_ucs4_utf8duplicate(ustr) }; n = UTF8CTOWX(str.get()); } @@ -368,24 +371,23 @@ void MP3ImportFileHandle::ImportID3(Tags *tags) } if (ustr) { + // Is this duplication really needed? MallocString<> str{ (char *)id3_ucs4_utf8duplicate(ustr) }; v = UTF8CTOWX(str.get()); } if (!n.IsEmpty() && !v.IsEmpty()) { tags->SetTag(n, v); + } } -} // Convert v1 genre to name if (tags->HasTag(TAG_GENRE)) { long g = -1; if (tags->GetTag(TAG_GENRE).ToLong(&g)) { tags->SetTag(TAG_GENRE, tags->GetGenre(g)); + } } -} - - id3_file_close(fp); #endif // ifdef USE_LIBID3TAG } diff --git a/src/import/ImportOGG.cpp b/src/import/ImportOGG.cpp index 177327ea9..49f4122ac 100644 --- a/src/import/ImportOGG.cpp +++ b/src/import/ImportOGG.cpp @@ -211,7 +211,6 @@ std::unique_ptr OggImportPlugin::Open(const wxString &filename } // what to do with message? - file->Close(); return nullptr; } @@ -230,7 +229,7 @@ auto OggImportFileHandle::GetFileUncompressedBytes() -> ByteCount } ProgressResult OggImportFileHandle::Import(TrackFactory *trackFactory, TrackHolders &outTracks, - Tags *tags) + Tags *tags) { outTracks.clear(); diff --git a/src/import/ImportPCM.cpp b/src/import/ImportPCM.cpp index e3fe02e33..68e774efe 100644 --- a/src/import/ImportPCM.cpp +++ b/src/import/ImportPCM.cpp @@ -478,6 +478,11 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory, else block = SFCall(sf_readf_float, mFile.get(), (float *)srcbuffer.ptr(), block); + if(block < 0 || block > maxBlock) { + wxASSERT(false); + block = maxBlock; + } + if (block) { auto iter = channels.begin(); for(int c=0; cnfields == 3) { ustr = id3_field_getstring(&frame->fields[1]); if (ustr) { + // Is this duplication really needed? MallocString<> str{ (char *)id3_ucs4_utf8duplicate(ustr) }; n = UTF8CTOWX(str.get()); } @@ -681,6 +687,7 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory, } if (ustr) { + // Is this duplication really needed? MallocString<> str{ (char *)id3_ucs4_utf8duplicate(ustr) }; v = UTF8CTOWX(str.get()); } @@ -700,8 +707,6 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory, break; } - - f.Close(); } } #endif diff --git a/src/import/ImportPlugin.h b/src/import/ImportPlugin.h index d63cce077..73548a5c3 100644 --- a/src/import/ImportPlugin.h +++ b/src/import/ImportPlugin.h @@ -155,6 +155,9 @@ public: // do the actual import, creating whatever tracks are necessary with // the TrackFactory and calling the progress callback every iteration // through the importing loop + // The given Tags structure may also be modified. + // In case of errors or exceptions, it is not necessary to leave outTracks + // or tags unmodified. virtual ProgressResult Import(TrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) = 0; diff --git a/src/import/ImportQT.cpp b/src/import/ImportQT.cpp index 2426b534d..f7072480c 100644 --- a/src/import/ImportQT.cpp +++ b/src/import/ImportQT.cpp @@ -245,9 +245,14 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory, UInt32 quality = kQTAudioRenderQuality_Max; AudioStreamBasicDescription desc; UInt32 maxSampleSize; - UInt32 bufsize; bool res = false; + auto cleanup = finally( [&] { + if (maer) { + MovieAudioExtractionEnd(maer); + } + } ); + CreateProgress(); do @@ -301,7 +306,7 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory, } auto numchan = desc.mChannelsPerFrame; - bufsize = 5 * desc.mSampleRate; + const size_t bufsize = 5 * desc.mSampleRate; // determine sample format sampleFormat format; @@ -320,32 +325,38 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory, break; } - std::unique_ptr abl - { static_cast - (calloc(1, offsetof(AudioBufferList, mBuffers) + - (sizeof(AudioBuffer) * numchan))) }; + // Allocate an array of pointers, whose size is not known statically, + // and prefixed with the AudioBufferList structure. + MallocPtr< AudioBufferList > abl{ + static_cast< AudioBufferList * >( + calloc( 1, offsetof( AudioBufferList, mBuffers ) + + (sizeof(AudioBuffer) * numchan))) }; abl->mNumberBuffers = numchan; TrackHolders channels{ numchan }; - ArraysOf holders{ numchan, sizeof(float) * bufsize }; - int c; - for (c = 0; c < numchan; c++) { - abl->mBuffers[c].mNumberChannels = 1; - abl->mBuffers[c].mDataByteSize = sizeof(float) * bufsize; + const auto size = sizeof(float) * bufsize; + ArraysOf holders{ numchan, size }; + for (size_t c = 0; c < numchan; c++) { + auto &buffer = abl->mBuffers[c]; + auto &holder = holders[c]; + auto &channel = channels[c]; - abl->mBuffers[c].mData = holders[c].get(); + buffer.mNumberChannels = 1; + buffer.mDataByteSize = size; + + buffer.mData = holder.get(); - channels[c] = trackFactory->NewWaveTrack(format); - channels[c]->SetRate(desc.mSampleRate); + channel = trackFactory->NewWaveTrack( format ); + channel->SetRate( desc.mSampleRate ); if (numchan == 2) { if (c == 0) { - channels[c]->SetChannel(Track::LeftChannel); - channels[c]->SetLinked(true); + channel->SetChannel(Track::LeftChannel); + channel->SetLinked(true); } else if (c == 1) { - channels[c]->SetChannel(Track::RightChannel); + channel->SetChannel(Track::RightChannel); } } } @@ -363,7 +374,7 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory, break; } - for (c = 0; c < numchan; c++) { + for (size_t c = 0; c < numchan; c++) { channels[c]->Append((char *) abl->mBuffers[c].mData, floatSample, numFrames); } @@ -398,10 +409,6 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory, // done: - if (maer) { - MovieAudioExtractionEnd(maer); - } - return (res ? ProgressResult::Success : ProgressResult::Failed); } @@ -436,6 +443,12 @@ names[] = void QTImportFileHandle::AddMetadata(Tags *tags) { QTMetaDataRef metaDataRef = NULL; + auto cleanup = finally( [&] { + // we are done so release our metadata object + if ( metaDataRef ) + QTMetaDataRelease(metaDataRef); + } ); + OSErr err; err = QTCopyMovieMetaData(mMovie, &metaDataRef); @@ -526,9 +539,6 @@ void QTImportFileHandle::AddMetadata(Tags *tags) } } - // we are done so release our metadata object - QTMetaDataRelease(metaDataRef); - return; } From 1552ff188f9989ddfc9fe88523619980a402ae8c Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 20 Dec 2016 13:13:00 -0500 Subject: [PATCH 39/91] When opening a file into a new project, delete the project on failure --- src/AudacityApp.cpp | 7 +++---- src/AutoRecovery.cpp | 8 ++------ src/Menus.cpp | 26 ++++++++++++++++++-------- src/Menus.h | 7 ++++++- src/Project.cpp | 21 ++++++++++++++++----- src/Project.h | 8 ++++++++ src/import/ImportLOF.cpp | 24 ++++++++++++++++-------- 7 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp index af8e265b2..67675ce9f 100644 --- a/src/AudacityApp.cpp +++ b/src/AudacityApp.cpp @@ -831,13 +831,12 @@ bool AudacityApp::MRUOpen(const wxString &fullPathStr) { // there are no tracks, but there's an Undo history, etc, then // bad things can happen, including data files moving to the NEW // project directory, etc. - if (!proj || proj->GetDirty() || !proj->GetIsEmpty()) { - proj = CreateNewAudacityProject(); - } + if (proj && (proj->GetDirty() || !proj->GetIsEmpty())) + proj = nullptr; // This project is clean; it's never been touched. Therefore // all relevant member variables are in their initial state, // and it's okay to open a NEW project inside this window. - proj->OpenFile(fullPathStr); + AudacityProject::OpenProject( proj, fullPathStr ); } else { // File doesn't exist - remove file from history diff --git a/src/AutoRecovery.cpp b/src/AutoRecovery.cpp index 2e0d452b1..9c6652227 100644 --- a/src/AutoRecovery.cpp +++ b/src/AutoRecovery.cpp @@ -198,7 +198,6 @@ static bool RecoverAllProjects(AudacityProject** pproj) // Open a project window for each auto save file wxString filename; - AudacityProject* proj = NULL; wxArrayString files; wxDir::GetAllFiles(FileNames::AutoSaveDir(), &files, @@ -206,21 +205,18 @@ static bool RecoverAllProjects(AudacityProject** pproj) for (unsigned int i = 0; i < files.GetCount(); i++) { + AudacityProject* proj{}; if (*pproj) { // Reuse existing project window proj = *pproj; *pproj = NULL; - } else - { - // Create NEW project window - proj = CreateNewAudacityProject(); } // Open project. When an auto-save file has been opened successfully, // the opened auto-save file is automatically deleted and a NEW one // is created. - proj->OpenFile(files[i], false); + AudacityProject::OpenProject( proj, files[i], false ); } return true; diff --git a/src/Menus.cpp b/src/Menus.cpp index 6a534808e..956b73b0e 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -5865,26 +5865,36 @@ void AudacityProject::OnImportMIDI() gPrefs->Write(wxT("/DefaultOpenPath"), path); gPrefs->Flush(); - DoImportMIDI(fileName); + AudacityProject::DoImportMIDI(this, fileName); } } -void AudacityProject::DoImportMIDI(const wxString &fileName) +AudacityProject *AudacityProject::DoImportMIDI( + AudacityProject *pProject, const wxString &fileName) { - auto newTrack = GetTrackFactory()->NewNoteTrack(); + AudacityProject *pNewProject {}; + if ( !pProject ) + pProject = pNewProject = CreateNewAudacityProject(); + auto cleanup = finally( [&] { if ( pNewProject ) pNewProject->Close(true); } ); + + auto newTrack = pProject->GetTrackFactory()->NewNoteTrack(); if (::ImportMIDI(fileName, newTrack.get())) { - SelectNone(); - auto pTrack = mTracks->Add(std::move(newTrack)); + pProject->SelectNone(); + auto pTrack = pProject->mTracks->Add(std::move(newTrack)); pTrack->SetSelected(true); - PushState(wxString::Format(_("Imported MIDI from '%s'"), + pProject->PushState(wxString::Format(_("Imported MIDI from '%s'"), fileName.c_str()), _("Import MIDI")); - RedrawProject(); - mTrackPanel->EnsureVisible(pTrack); + pProject->RedrawProject(); + pProject->mTrackPanel->EnsureVisible(pTrack); + pNewProject = nullptr; + return pProject; } + else + return nullptr; } #endif // USE_MIDI diff --git a/src/Menus.h b/src/Menus.h index f0c951d8d..19bb6ea9a 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -347,7 +347,12 @@ void OnRescanDevices(); void OnImport(); void OnImportLabels(); void OnImportMIDI(); -void DoImportMIDI(const wxString &fileName); + +// return null on failure; if success, return the given project, or a new +// one, if the given was null; create no new project if failure +static AudacityProject *DoImportMIDI( + AudacityProject *pProject, const wxString &fileName); + void OnImportRaw(); void OnEditMetadata(); diff --git a/src/Project.cpp b/src/Project.cpp index 137cd1be5..4c61ae08d 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -2891,14 +2891,13 @@ void AudacityProject::OpenFiles(AudacityProject *proj) // there are no tracks, but there's an Undo history, etc, then // bad things can happen, including data files moving to the NEW // project directory, etc. - if (!proj || proj->mDirty || !proj->mTracks->IsEmpty()) { - // Open in a NEW window - proj = CreateNewAudacityProject(); - } + if ( proj && ( proj->mDirty || !proj->mTracks->IsEmpty() ) ) + proj = nullptr; + // This project is clean; it's never been touched. Therefore // all relevant member variables are in their initial state, // and it's okay to open a NEW project inside this window. - proj->OpenFile(fileName); + proj = AudacityProject::OpenProject( proj, fileName ); } } @@ -2927,6 +2926,18 @@ bool AudacityProject::WarnOfLegacyFile( ) } +AudacityProject *AudacityProject::OpenProject( + AudacityProject *pProject, const wxString &fileNameArg, bool addtohistory) +{ + AudacityProject *pNewProject = nullptr; + if ( ! pProject ) + pProject = pNewProject = CreateNewAudacityProject(); + auto cleanup = finally( [&] { if( pNewProject ) pNewProject->Close(true); } ); + pProject->OpenFile( fileNameArg, addtohistory ); + pNewProject = nullptr; + return pProject; +} + // FIXME:? TRAP_ERR This should return a result that is checked. // See comment in AudacityApp::MRUOpen(). void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory) diff --git a/src/Project.h b/src/Project.h index 4198bef9f..971c92006 100644 --- a/src/Project.h +++ b/src/Project.h @@ -242,6 +242,14 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame, const wxString &extrafilter = wxEmptyString); static bool IsAlreadyOpen(const wxString & projPathName); static void OpenFiles(AudacityProject *proj); + + // Return the given project if that is not NULL, else create a project. + // Then open the given project path. + // But if an exception escapes this function, create no new project. + static AudacityProject *OpenProject( + AudacityProject *pProject, + const wxString &fileNameArg, bool addtohistory = true); + void OpenFile(const wxString &fileName, bool addtohistory = true); private: diff --git a/src/import/ImportLOF.cpp b/src/import/ImportLOF.cpp index 730315639..7c87d112b 100644 --- a/src/import/ImportLOF.cpp +++ b/src/import/ImportLOF.cpp @@ -307,9 +307,12 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) doDurationAndScrollOffset(); if (windowCalledOnce) - { - mProject = CreateNewAudacityProject(); - } + // Cause a project to be created with the next import + mProject = nullptr; + else + // Apply any offset and duration directives of the first "window" line + // to the previously open project, not a new one. + ; windowCalledOnce = true; @@ -388,7 +391,7 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) if (targetfile.AfterLast(wxT('.')).IsSameAs(wxT("mid"), false) || targetfile.AfterLast(wxT('.')).IsSameAs(wxT("midi"), false)) { - mProject->DoImportMIDI(targetfile); + mProject = AudacityProject::DoImportMIDI(mProject, targetfile); } // If not a midi, open audio file @@ -399,9 +402,7 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) * audio file. TODO: Some sort of message here? */ #endif // USE_MIDI - { - mProject->OpenFile(targetfile); - } + mProject = AudacityProject::OpenProject( mProject, targetfile ); // Set tok to right after filename temptok2.SetString(targettoken); @@ -427,7 +428,11 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) double offset; // handle an "offset" specifier - if (Internat::CompatibleToDouble(tokenholder, &offset)) + if (!mProject) + // there was an import error, + // presumably with its own error message + ; + else if (Internat::CompatibleToDouble(tokenholder, &offset)) { Track *t; TrackListIterator iter(mProject->GetTracks()); @@ -489,6 +494,9 @@ void LOFImportFileHandle::lofOpenFiles(wxString* ln) void LOFImportFileHandle::doDurationAndScrollOffset() { + if (!mProject) + return; + bool doSomething = callDurationFactor || callScrollOffset; if (callDurationFactor) { From 70d9e4bdc76e8c16d232bae45404de70dee02eb0 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 25 Dec 2016 08:40:15 -0500 Subject: [PATCH 40/91] GetMinMax, GetRMS functions take a mayThrow argument, return numbers --- src/Audacity.h | 2 +- src/BlockFile.cpp | 28 ++------- src/BlockFile.h | 8 ++- src/Sequence.cpp | 90 ++++++++++++--------------- src/Sequence.h | 7 +-- src/WaveClip.cpp | 41 +++++++----- src/WaveClip.h | 5 +- src/WaveTrack.cpp | 83 +++++++++++------------- src/WaveTrack.h | 6 +- src/blockfile/ODDecodeBlockFile.cpp | 31 +++++---- src/blockfile/ODDecodeBlockFile.h | 6 +- src/blockfile/ODPCMAliasBlockFile.cpp | 36 +++++++---- src/blockfile/ODPCMAliasBlockFile.h | 6 +- src/effects/Amplify.cpp | 4 +- src/effects/Contrast.cpp | 3 +- src/effects/Normalize.cpp | 5 +- src/effects/nyquist/Nyquist.cpp | 6 +- 17 files changed, 183 insertions(+), 184 deletions(-) diff --git a/src/Audacity.h b/src/Audacity.h index c5ea7591d..c5ff40e1e 100644 --- a/src/Audacity.h +++ b/src/Audacity.h @@ -175,7 +175,7 @@ void QuitAudacity(); #define LINEAR_TO_DB(x) (20.0 * log10(x)) #define MAX_AUDIO (1. - 1./(1<<15)) -#define JUST_BELOW_MAX_AUDIO (1. - 1./(1<<14)) +#define JUST_BELOW_MAX_AUDIO (1.f - 1.f/(1<<14)) // Marks strings for extraction only...must use wxGetTranslation() to translate. #define XO(s) wxT(s) diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp index db43cfc26..01c9d9f8b 100644 --- a/src/BlockFile.cpp +++ b/src/BlockFile.cpp @@ -371,14 +371,8 @@ void BlockFile::FixSummary(void *data) /// /// @param start The offset in this block where the region should begin /// @param len The number of samples to include in the region -/// @param *outMin A pointer to where the minimum value for this region -/// should be stored -/// @param *outMax A pointer to where the maximum value for this region -/// should be stored -/// @param *outRMS A pointer to where the maximum RMS value for this -/// region should be stored. -void BlockFile::GetMinMax(size_t start, size_t len, - float *outMin, float *outMax, float *outRMS) const +auto BlockFile::GetMinMaxRMS(size_t start, size_t len, bool mayThrow) + const -> MinMaxRMS { // TODO: actually use summaries SampleBuffer blockData(len, floatSample); @@ -399,26 +393,16 @@ void BlockFile::GetMinMax(size_t start, size_t len, sumsq += (sample*sample); } - *outMin = min; - *outMax = max; - *outRMS = sqrt(sumsq/len); + return { min, max, (float)sqrt(sumsq/len) }; } /// Retrieves the minimum, maximum, and maximum RMS of this entire /// block. This is faster than the other GetMinMax function since /// these values are already computed. -/// -/// @param *outMin A pointer to where the minimum value for this block -/// should be stored -/// @param *outMax A pointer to where the maximum value for this block -/// should be stored -/// @param *outRMS A pointer to where the maximum RMS value for this -/// block should be stored. -void BlockFile::GetMinMax(float *outMin, float *outMax, float *outRMS) const +auto BlockFile::GetMinMaxRMS(bool) + const -> MinMaxRMS { - *outMin = mMin; - *outMax = mMax; - *outRMS = mRMS; + return { mMin, mMax, mRMS }; } /// Retrieves a portion of the 256-byte summary buffer from this BlockFile. This diff --git a/src/BlockFile.h b/src/BlockFile.h index 8e9813a62..56a6cf123 100644 --- a/src/BlockFile.h +++ b/src/BlockFile.h @@ -117,11 +117,13 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ { /// Returns TRUE if this BlockFile is locked virtual bool IsLocked(); + struct MinMaxRMS { float min, max, RMS; }; + /// Gets extreme values for the specified region - virtual void GetMinMax(size_t start, size_t len, - float *outMin, float *outMax, float *outRMS) const; + virtual MinMaxRMS GetMinMaxRMS(size_t start, size_t len, + bool mayThrow = true) const; /// Gets extreme values for the entire block - virtual void GetMinMax(float *outMin, float *outMax, float *outRMS) const; + virtual MinMaxRMS GetMinMaxRMS(bool mayThrow = true) const; /// Returns the 256 byte summary data block virtual bool Read256(float *buffer, size_t start, size_t len); /// Returns the 64K summary data block diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 465edb0be..ce5641a38 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -225,13 +225,17 @@ bool Sequence::ConvertToSampleFormat(sampleFormat format, bool* pbChanged) return bSuccess; } -bool Sequence::GetMinMax(sampleCount start, sampleCount len, - float * outMin, float * outMax) const +std::pair Sequence::GetMinMax( + sampleCount start, sampleCount len, bool mayThrow) const { if (len == 0 || mBlock.size() == 0) { - *outMin = float(0.0); // FLT_MAX? So it doesn't look like a spurious '0' to a caller? - *outMax = float(0.0); // -FLT_MAX? So it doesn't look like a spurious '0' to a caller? - return true; + return { + 0.f, + // FLT_MAX? So it doesn't look like a spurious '0' to a caller? + + 0.f + // -FLT_MAX? So it doesn't look like a spurious '0' to a caller? + }; } float min = FLT_MAX; @@ -245,13 +249,12 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len, // already in memory. for (unsigned b = block0 + 1; b < block1; ++b) { - float blockMin, blockMax, blockRMS; - mBlock[b].f->GetMinMax(&blockMin, &blockMax, &blockRMS); + auto results = mBlock[b].f->GetMinMaxRMS(mayThrow); - if (blockMin < min) - min = blockMin; - if (blockMax > max) - max = blockMax; + if (results.min < min) + min = results.min; + if (results.max > max) + max = results.max; } // Now we take the first and last blocks into account, noting that the @@ -259,12 +262,11 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len, // of either of these blocks is within min...max, then we can ignore them. // If not, we need read some samples and summaries from disk. { - float block0Min, block0Max, block0RMS; const SeqBlock &theBlock = mBlock[block0]; const auto &theFile = theBlock.f; - theFile->GetMinMax(&block0Min, &block0Max, &block0RMS); + auto results = theFile->GetMinMaxRMS(mayThrow); - if (block0Min < min || block0Max > max) { + if (results.min < min || results.max > max) { // start lies within theBlock: auto s0 = ( start - theBlock.start ).as_size_t(); const auto maxl0 = ( @@ -274,54 +276,43 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len, wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19 const auto l0 = limitSampleBufferSize ( maxl0, len ); - float partialMin, partialMax, partialRMS; - theFile->GetMinMax(s0, l0, - &partialMin, &partialMax, &partialRMS); - if (partialMin < min) - min = partialMin; - if (partialMax > max) - max = partialMax; + results = theFile->GetMinMaxRMS(s0, l0, mayThrow); + if (results.min < min) + min = results.min; + if (results.max > max) + max = results.max; } } if (block1 > block0) { - float block1Min, block1Max, block1RMS; const SeqBlock &theBlock = mBlock[block1]; const auto &theFile = theBlock.f; - theFile->GetMinMax(&block1Min, &block1Max, &block1RMS); + auto results = theFile->GetMinMaxRMS(mayThrow); - if (block1Min < min || block1Max > max) { + if (results.min < min || results.max > max) { // start + len - 1 lies in theBlock: const auto l0 = ( start + len - theBlock.start ).as_size_t(); wxASSERT(l0 <= mMaxSamples); // Vaughan, 2011-10-19 - float partialMin, partialMax, partialRMS; - theFile->GetMinMax(0, l0, - &partialMin, &partialMax, &partialRMS); - if (partialMin < min) - min = partialMin; - if (partialMax > max) - max = partialMax; + results = theFile->GetMinMaxRMS(0, l0, mayThrow); + if (results.min < min) + min = results.min; + if (results.max > max) + max = results.max; } } - *outMin = min; - *outMax = max; - - return true; + return { min, max }; } -bool Sequence::GetRMS(sampleCount start, sampleCount len, - float * outRMS) const +float Sequence::GetRMS(sampleCount start, sampleCount len, bool mayThrow) const { // len is the number of samples that we want the rms of. // it may be longer than a block, and the code is carefully set up to handle that. - if (len == 0 || mBlock.size() == 0) { - *outRMS = float(0.0); - return true; - } + if (len == 0 || mBlock.size() == 0) + return 0.f; double sumsq = 0.0; sampleCount length = 0; // this is the cumulative length of the bits we have the ms of so far, and should end up == len @@ -333,12 +324,12 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len, // this is very fast because we have the rms of every entire block // already in memory. for (unsigned b = block0 + 1; b < block1; b++) { - float blockMin, blockMax, blockRMS; const SeqBlock &theBlock = mBlock[b]; const auto &theFile = theBlock.f; - theFile->GetMinMax(&blockMin, &blockMax, &blockRMS); + auto results = theFile->GetMinMaxRMS(mayThrow); const auto fileLen = theFile->GetLength(); + const auto blockRMS = results.RMS; sumsq += blockRMS * blockRMS * fileLen; length += fileLen; } @@ -357,9 +348,8 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len, wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19 const auto l0 = limitSampleBufferSize( maxl0, len ); - float partialMin, partialMax, partialRMS; - theFile->GetMinMax(s0, l0, &partialMin, &partialMax, &partialRMS); - + auto results = theFile->GetMinMaxRMS(s0, l0, mayThrow); + const auto partialRMS = results.RMS; sumsq += partialRMS * partialRMS * l0; length += l0; } @@ -372,8 +362,8 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len, const auto l0 = ( start + len - theBlock.start ).as_size_t(); wxASSERT(l0 <= mMaxSamples); // PRL: I think Vaughan missed this - float partialMin, partialMax, partialRMS; - theFile->GetMinMax(0, l0, &partialMin, &partialMax, &partialRMS); + auto results = theFile->GetMinMaxRMS(0, l0, mayThrow); + const auto partialRMS = results.RMS; sumsq += partialRMS * partialRMS * l0; length += l0; } @@ -381,9 +371,7 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len, // PRL: catch bugs like 1320: wxASSERT(length == len); - *outRMS = sqrt(sumsq / length.as_double() ); - - return true; + return sqrt(sumsq / length.as_double() ); } std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const diff --git a/src/Sequence.h b/src/Sequence.h index 278a1082b..3095e2c67 100644 --- a/src/Sequence.h +++ b/src/Sequence.h @@ -169,10 +169,9 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{ // Retrieving summary info // - bool GetMinMax(sampleCount start, sampleCount len, - float * min, float * max) const; - bool GetRMS(sampleCount start, sampleCount len, - float * outRMS) const; + std::pair GetMinMax( + sampleCount start, sampleCount len, bool mayThrow) const; + float GetRMS(sampleCount start, sampleCount len, bool mayThrow) const; // // Getting block size and alignment information diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index ecad3e6d7..33779c360 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -36,6 +36,8 @@ #include "WaveTrack.h" #include "FFT.h" #include "Profiler.h" +#include "InconsistencyException.h" +#include "UserException.h" #include "prefs/SpectrogramSettings.h" @@ -1284,43 +1286,48 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, return true; } -bool WaveClip::GetMinMax(float *min, float *max, - double t0, double t1) const +std::pair WaveClip::GetMinMax( + double t0, double t1, bool mayThrow) const { - *min = float(0.0); // harmless, but unused since Sequence::GetMinMax does not use these values - *max = float(0.0); // harmless, but unused since Sequence::GetMinMax does not use these values - - if (t0 > t1) - return false; + if (t0 > t1) { + if (mayThrow) + //THROW_INCONSISTENCY_EXCEPTION + ; + return { + 0.f, // harmless, but unused since Sequence::GetMinMax does not use these values + 0.f // harmless, but unused since Sequence::GetMinMax does not use these values + }; + } if (t0 == t1) - return true; + return{ 0.f, 0.f }; sampleCount s0, s1; TimeToSamplesClip(t0, &s0); TimeToSamplesClip(t1, &s1); - return mSequence->GetMinMax(s0, s1-s0, min, max); + return mSequence->GetMinMax(s0, s1-s0, mayThrow); } -bool WaveClip::GetRMS(float *rms, double t0, - double t1) +float WaveClip::GetRMS(double t0, double t1, bool mayThrow) const { - *rms = float(0.0); - - if (t0 > t1) - return false; + if (t0 > t1) { + if (mayThrow) + //THROW_INCONSISTENCY_EXCEPTION + ; + return 0.f; + } if (t0 == t1) - return true; + return 0.f; sampleCount s0, s1; TimeToSamplesClip(t0, &s0); TimeToSamplesClip(t1, &s1); - return mSequence->GetRMS(s0, s1-s0, rms); + return mSequence->GetRMS(s0, s1-s0, mayThrow); } void WaveClip::ConvertToSampleFormat(sampleFormat format) diff --git a/src/WaveClip.h b/src/WaveClip.h index 7800dd27b..ed0727d1e 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -278,8 +278,9 @@ public: const sampleCount *& where, size_t numPixels, double t0, double pixelsPerSecond) const; - bool GetMinMax(float *min, float *max, double t0, double t1) const; - bool GetRMS(float *rms, double t0, double t1); + std::pair GetMinMax( + double t0, double t1, bool mayThrow = true) const; + float GetRMS(double t0, double t1, bool mayThrow = true) const; // Set/clear/get rectangle that this WaveClip fills on screen. This is // called by TrackArtist while actually drawing the tracks and clips. diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 01ae05eab..9523dbc83 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -55,6 +55,8 @@ Track classes. #include "prefs/SpectrumPrefs.h" #include "prefs/WaveformPrefs.h" +#include "InconsistencyException.h" + #include "Experimental.h" using std::max; @@ -1902,61 +1904,58 @@ double WaveTrack::GetEndTime() const // expressed relative to t=0.0 at the track's sample rate. // -bool WaveTrack::GetMinMax(float *min, float *max, - double t0, double t1) const +std::pair WaveTrack::GetMinMax( + double t0, double t1, bool mayThrow) const { + std::pair results { + // we need these at extremes to make sure we find true min and max + FLT_MAX, -FLT_MAX + }; bool clipFound = false; - *min = FLT_MAX; // we need these at extremes to make sure we find true min and max - *max = -FLT_MAX; - - if (t0 > t1) - return false; + if (t0 > t1) { + if (mayThrow) + //THROW_INCONSISTENCY_EXCEPTION + ; + return results; + } if (t0 == t1) - return true; - - bool result = true; + return results; for (const auto &clip: mClips) { if (t1 >= clip->GetStartTime() && t0 <= clip->GetEndTime()) { clipFound = true; - float clipmin, clipmax; - if (clip->GetMinMax(&clipmin, &clipmax, t0, t1)) - { - if (clipmin < *min) - *min = clipmin; - if (clipmax > *max) - *max = clipmax; - } else - { - result = false; - } + auto clipResults = clip->GetMinMax(t0, t1, mayThrow); + if (clipResults.first < results.first) + results.first = clipResults.first; + if (clipResults.second > results.second) + results.second = clipResults.second; } } if(!clipFound) { - *min = float(0.0); // sensible defaults if no clips found - *max = float(0.0); + results = { 0.f, 0.f }; // sensible defaults if no clips found } - return result; + return results; } -bool WaveTrack::GetRMS(float *rms, double t0, double t1) const +float WaveTrack::GetRMS(double t0, double t1, bool mayThrow) const { - *rms = float(0.0); - - if (t0 > t1) - return false; + if (t0 > t1) { + if (mayThrow) + //THROW_INCONSISTENCY_EXCEPTION + ; + return 0.f; + } if (t0 == t1) - return true; + return 0.f; - bool result = true; double sumsq = 0.0; sampleCount length = 0; @@ -1967,25 +1966,17 @@ bool WaveTrack::GetRMS(float *rms, double t0, double t1) const // if (t1 >= clip->GetStartTime() && t0 <= clip->GetEndTime()) if (t1 >= clip->GetStartTime() && t0 <= clip->GetEndTime()) { - float cliprms; sampleCount clipStart, clipEnd; - if (clip->GetRMS(&cliprms, t0, t1)) - { - clip->TimeToSamplesClip(wxMax(t0, clip->GetStartTime()), &clipStart); - clip->TimeToSamplesClip(wxMin(t1, clip->GetEndTime()), &clipEnd); - sumsq += cliprms * cliprms * (clipEnd - clipStart).as_float(); - length += (clipEnd - clipStart); - } - else - { - result = false; - } + float cliprms = clip->GetRMS(t0, t1, mayThrow); + + clip->TimeToSamplesClip(wxMax(t0, clip->GetStartTime()), &clipStart); + clip->TimeToSamplesClip(wxMin(t1, clip->GetEndTime()), &clipEnd); + sumsq += cliprms * cliprms * (clipEnd - clipStart).as_float(); + length += (clipEnd - clipStart); } } - *rms = length > 0 ? sqrt(sumsq / length.as_double()) : 0.0; - - return result; + return length > 0 ? sqrt(sumsq / length.as_double()) : 0.0; } bool WaveTrack::Get(samplePtr buffer, sampleFormat format, diff --git a/src/WaveTrack.h b/src/WaveTrack.h index 15daad1b1..68c2d3607 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -257,9 +257,9 @@ class AUDACITY_DLL_API WaveTrack final : public Track { sampleCount start, size_t len); void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0) const; - bool GetMinMax(float *min, float *max, - double t0, double t1) const; - bool GetRMS(float *rms, double t0, double t1) const; + std::pair GetMinMax( + double t0, double t1, bool mayThrow = true) const; + float GetRMS(double t0, double t1, bool mayThrow = true) const; // // MM: We now have more than one sequence and envelope per track, so diff --git a/src/blockfile/ODDecodeBlockFile.cpp b/src/blockfile/ODDecodeBlockFile.cpp index e5c0f3681..c6dff23dd 100644 --- a/src/blockfile/ODDecodeBlockFile.cpp +++ b/src/blockfile/ODDecodeBlockFile.cpp @@ -29,6 +29,7 @@ The summary is eventually computed and written to a file in a background thread. #include "../FileFormats.h" #include "../Internat.h" +#include "NotYetAvailableException.h" const int bheaderTagLen = 20; char bheaderTag[bheaderTagLen + 1] = "AudacityBlockFile112"; @@ -91,37 +92,45 @@ auto ODDecodeBlockFile::GetSpaceUsage() const -> DiskByteCount /// Gets extreme values for the specified region -void ODDecodeBlockFile::GetMinMax(size_t start, size_t len, - float *outMin, float *outMax, float *outRMS) const +auto ODDecodeBlockFile::GetMinMaxRMS( + size_t start, size_t len, bool mayThrow) const -> MinMaxRMS { if(IsSummaryAvailable()) { - SimpleBlockFile::GetMinMax(start,len,outMin,outMax,outRMS); + return SimpleBlockFile::GetMinMaxRMS(start, len, mayThrow); } else { + if (mayThrow) + // throw NotYetAvailableException{ mAudioFileName } + ; + //fake values. These values are used usually for normalization and amplifying, so we want //the max to be maximal and the min to be minimal - *outMin = -1.0; - *outMax = 1.0; - *outRMS = (float)0.707;//sin with amp of 1 rms + return { + -1.0f, 1.0f, 0.707f //sin with amp of 1 rms + }; } } /// Gets extreme values for the entire block -void ODDecodeBlockFile::GetMinMax(float *outMin, float *outMax, float *outRMS) const +auto ODDecodeBlockFile::GetMinMaxRMS(bool mayThrow) const -> MinMaxRMS { if(IsSummaryAvailable()) { - SimpleBlockFile::GetMinMax(outMin,outMax,outRMS); + return SimpleBlockFile::GetMinMaxRMS(mayThrow); } else { + if (mayThrow) + // throw NotYetAvailableException{ mAudioFileName } + ; + //fake values. These values are used usually for normalization and amplifying, so we want //the max to be maximal and the min to be minimal - *outMin = -1.0; - *outMax = 1.0; - *outRMS = (float)0.707;//sin with amp of 1 rms + return { + -1.0f, 1.0f, 0.707f //sin with amp of 1 rms + }; } } diff --git a/src/blockfile/ODDecodeBlockFile.h b/src/blockfile/ODDecodeBlockFile.h index 3a743ffd9..0a98df679 100644 --- a/src/blockfile/ODDecodeBlockFile.h +++ b/src/blockfile/ODDecodeBlockFile.h @@ -63,10 +63,10 @@ class ODDecodeBlockFile final : public SimpleBlockFile //Calls that rely on summary files need to be overidden DiskByteCount GetSpaceUsage() const override; /// Gets extreme values for the specified region - void GetMinMax(size_t start, size_t len, - float *outMin, float *outMax, float *outRMS) const override; + MinMaxRMS GetMinMaxRMS( + size_t start, size_t len, bool mayThrow) const override; /// Gets extreme values for the entire block - void GetMinMax(float *outMin, float *outMax, float *outRMS) const override; + MinMaxRMS GetMinMaxRMS(bool mayThrow) const override; /// Returns the 256 byte summary data block bool Read256(float *buffer, size_t start, size_t len) override; /// Returns the 64K summary data block diff --git a/src/blockfile/ODPCMAliasBlockFile.cpp b/src/blockfile/ODPCMAliasBlockFile.cpp index 678d74f88..4f14be7f6 100644 --- a/src/blockfile/ODPCMAliasBlockFile.cpp +++ b/src/blockfile/ODPCMAliasBlockFile.cpp @@ -36,6 +36,8 @@ The summary is eventually computed and written to a file in a background thread. #include "../ondemand/ODManager.h" #include "../AudioIO.h" +#include "NotYetAvailableException.h" + //#include extern AudioIO *gAudioIO; @@ -121,37 +123,49 @@ void ODPCMAliasBlockFile::Unlock() /// Gets extreme values for the specified region -void ODPCMAliasBlockFile::GetMinMax(size_t start, size_t len, - float *outMin, float *outMax, float *outRMS) const +auto ODPCMAliasBlockFile::GetMinMaxRMS( + size_t start, size_t len, bool mayThrow) const -> MinMaxRMS { if(IsSummaryAvailable()) { - PCMAliasBlockFile::GetMinMax(start,len,outMin,outMax,outRMS); + return PCMAliasBlockFile::GetMinMaxRMS(start, len, mayThrow); } else { + if (mayThrow) + //throw NotYetAvailableException{ GetAliasedFileName() } + ; + //fake values. These values are used usually for normalization and amplifying, so we want //the max to be maximal and the min to be minimal - *outMin = -1.0*JUST_BELOW_MAX_AUDIO; - *outMax = 1.0*JUST_BELOW_MAX_AUDIO; - *outRMS = (float)0.707;//sin with amp of 1 rms + return { + -JUST_BELOW_MAX_AUDIO, + JUST_BELOW_MAX_AUDIO, + 0.707f //sin with amp of 1 rms + }; } } /// Gets extreme values for the entire block -void ODPCMAliasBlockFile::GetMinMax(float *outMin, float *outMax, float *outRMS) const +auto ODPCMAliasBlockFile::GetMinMaxRMS(bool mayThrow) const -> MinMaxRMS { if(IsSummaryAvailable()) { - PCMAliasBlockFile::GetMinMax(outMin,outMax,outRMS); + return PCMAliasBlockFile::GetMinMaxRMS(mayThrow); } else { + if (mayThrow) + //throw NotYetAvailableException{ GetAliasedFileName() } + ; + //fake values. These values are used usually for normalization and amplifying, so we want //the max to be maximal and the min to be minimal - *outMin = -1.0*JUST_BELOW_MAX_AUDIO; - *outMax = 1.0*JUST_BELOW_MAX_AUDIO; - *outRMS = (float)0.707;//sin with amp of 1 rms + return { + -JUST_BELOW_MAX_AUDIO, + JUST_BELOW_MAX_AUDIO, + 0.707f //sin with amp of 1 rms + }; } } diff --git a/src/blockfile/ODPCMAliasBlockFile.h b/src/blockfile/ODPCMAliasBlockFile.h index 1653b1e65..421eadad3 100644 --- a/src/blockfile/ODPCMAliasBlockFile.h +++ b/src/blockfile/ODPCMAliasBlockFile.h @@ -65,10 +65,10 @@ class ODPCMAliasBlockFile final : public PCMAliasBlockFile //Calls that rely on summary files need to be overidden DiskByteCount GetSpaceUsage() const override; /// Gets extreme values for the specified region - void GetMinMax(size_t start, size_t len, - float *outMin, float *outMax, float *outRMS) const override; + MinMaxRMS GetMinMaxRMS( + size_t start, size_t len, bool mayThrow) const override; /// Gets extreme values for the entire block - void GetMinMax(float *outMin, float *outMax, float *outRMS) const override; + MinMaxRMS GetMinMaxRMS(bool mayThrow) const override; /// Returns the 256 byte summary data block bool Read256(float *buffer, size_t start, size_t len) override; /// Returns the 64K summary data block diff --git a/src/effects/Amplify.cpp b/src/effects/Amplify.cpp index 82437e11f..995b29c2a 100644 --- a/src/effects/Amplify.cpp +++ b/src/effects/Amplify.cpp @@ -164,8 +164,8 @@ bool EffectAmplify::Init() for (Track *t = iter.First(); t; t = iter.Next()) { - float min, max; - ((WaveTrack *)t)->GetMinMax(&min, &max, mT0, mT1); + auto pair = ((WaveTrack *)t)->GetMinMax(mT0, mT1); // may throw + const float min = pair.first, max = pair.second; float newpeak = (fabs(min) > fabs(max) ? fabs(min) : fabs(max)); if (newpeak > mPeak) diff --git a/src/effects/Contrast.cpp b/src/effects/Contrast.cpp index c5cc25bfd..55ffd0bb9 100644 --- a/src/effects/Contrast.cpp +++ b/src/effects/Contrast.cpp @@ -84,7 +84,8 @@ bool ContrastDialog::GetDB(float &dB) return false; } - ((WaveTrack *)t)->GetRMS(&rms, mT0, mT1); + // Don't throw in this analysis dialog + rms = ((WaveTrack *)t)->GetRMS(mT0, mT1, false); meanSq += rms * rms; t = (WaveTrack *) iter.Next(); } diff --git a/src/effects/Normalize.cpp b/src/effects/Normalize.cpp index db3626144..838f6d4dd 100644 --- a/src/effects/Normalize.cpp +++ b/src/effects/Normalize.cpp @@ -344,7 +344,10 @@ bool EffectNormalize::AnalyseTrack(const WaveTrack * track, const wxString &msg, wxMilliSleep(100); } - track->GetMinMax(&min, &max, mCurT0, mCurT1); + // set mMin, mMax. No progress bar here as it's fast. + auto pair = track->GetMinMax(mCurT0, mCurT1); // may throw + min = pair.first, max = pair.second; + } else { min = -1.0, max = 1.0; // sensible defaults? } diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index 6d4736bb8..ff3607504 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -968,7 +968,8 @@ bool NyquistEffect::ProcessOne() if (mCurNumChannels > 1) clips += wxT(" )"); float min, max; - mCurTrack[i]->GetMinMax(&min, &max, mT0, mT1); + auto pair = mCurTrack[i]->GetMinMax(mT0, mT1); // may throw + min = pair.first, max = pair.second; maxPeak = wxMax(wxMax(fabs(min), fabs(max)), maxPeak); maxPeakLevel = wxMax(maxPeakLevel, maxPeak); @@ -980,8 +981,7 @@ bool NyquistEffect::ProcessOne() peakString += wxT("nil"); } - float rms = 0.0; - mCurTrack[i]->GetRMS(&rms, mT0, mT1); + float rms = mCurTrack[i]->GetRMS(mT0, mT1); // may throw if (!std::isinf(rms) && !std::isnan(rms)) { rmsString += wxString::Format(wxT("(float %s) "), Internat::ToString(rms).c_str()); } else { From 98d1468a018bc28c5e6c7c6668b5d0b95b95527b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 25 Dec 2016 08:42:44 -0500 Subject: [PATCH 41/91] BlockFile::ReadData overrides: on failure, pad with 0s or throw... ... as the mayThrow argument directs. --- src/BlockFile.cpp | 127 ++++++++++++++------------ src/BlockFile.h | 7 +- src/blockfile/LegacyBlockFile.cpp | 4 +- src/blockfile/LegacyBlockFile.h | 2 +- src/blockfile/ODDecodeBlockFile.cpp | 12 ++- src/blockfile/ODDecodeBlockFile.h | 2 +- src/blockfile/ODPCMAliasBlockFile.cpp | 6 +- src/blockfile/ODPCMAliasBlockFile.h | 2 +- src/blockfile/PCMAliasBlockFile.cpp | 4 +- src/blockfile/PCMAliasBlockFile.h | 2 +- src/blockfile/SilentBlockFile.cpp | 2 +- src/blockfile/SilentBlockFile.h | 2 +- src/blockfile/SimpleBlockFile.cpp | 23 +++-- src/blockfile/SimpleBlockFile.h | 2 +- 14 files changed, 113 insertions(+), 84 deletions(-) diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp index 01c9d9f8b..a83b3839f 100644 --- a/src/BlockFile.cpp +++ b/src/BlockFile.cpp @@ -376,7 +376,8 @@ auto BlockFile::GetMinMaxRMS(size_t start, size_t len, bool mayThrow) { // TODO: actually use summaries SampleBuffer blockData(len, floatSample); - this->ReadData(blockData.ptr(), floatSample, start, len); + + this->ReadData(blockData.ptr(), floatSample, start, len, mayThrow); float min = FLT_MAX; float max = -FLT_MAX; @@ -485,6 +486,7 @@ bool BlockFile::Read64K(float *buffer, } size_t BlockFile::CommonReadData( + bool mayThrow, const wxFileName &fileName, bool &mSilentLog, const AliasBlockFile *pAliasFile, sampleCount origin, unsigned channel, samplePtr data, sampleFormat format, size_t start, size_t len, @@ -534,80 +536,89 @@ size_t BlockFile::CommonReadData( // libsndfile can't (under Windows). sf.reset(SFCall(sf_open_fd, f.fd(), SFM_READ, &info, FALSE)); } - // FIXME: TRAP_ERR failure of wxFile open incompletely handled in BlockFile::CommonReadData. if (!sf) { memset(data, 0, SAMPLE_SIZE(format)*len); - mSilentLog = TRUE; - if (pAliasFile) { // Set a marker to display an error message for the silence if (!wxGetApp().ShouldShowMissingAliasedFileWarning()) wxGetApp().MarkAliasedFilesMissingWarning(pAliasFile); } - - return len; } } - mSilentLog=FALSE; - - SFCall( - sf_seek, sf.get(), ( origin + start ).as_long_long(), SEEK_SET); - - auto channels = info.channels; - wxASSERT(channels >= 1); - wxASSERT(channel < channels); + mSilentLog = !sf; size_t framesRead = 0; + if (sf) { + auto seek_result = SFCall( + sf_seek, sf.get(), ( origin + start ).as_long_long(), SEEK_SET); - if (channels == 1 && - format == int16Sample && - sf_subtype_is_integer(info.format)) { - // If both the src and dest formats are integer formats, - // read integers directly from the file, comversions not needed - framesRead = SFCall( - sf_readf_short, sf.get(), (short *)data, len); - } - else if (channels == 1 && - format == int24Sample && - sf_subtype_is_integer(info.format)) { - framesRead = SFCall(sf_readf_int, sf.get(), (int *)data, len); + if (seek_result < 0) + // error + ; + else { + auto channels = info.channels; + wxASSERT(channels >= 1); + wxASSERT(channel < channels); - // libsndfile gave us the 3 byte sample in the 3 most - // significant bytes -- we want it in the 3 least - // significant bytes. - int *intPtr = (int *)data; - for( int i = 0; i < framesRead; i++ ) - intPtr[i] = intPtr[i] >> 8; + if (channels == 1 && + format == int16Sample && + sf_subtype_is_integer(info.format)) { + // If both the src and dest formats are integer formats, + // read integers directly from the file, comversions not needed + framesRead = SFCall( + sf_readf_short, sf.get(), (short *)data, len); + } + else if (channels == 1 && + format == int24Sample && + sf_subtype_is_integer(info.format)) { + framesRead = SFCall( + sf_readf_int, sf.get(), (int *)data, len); + + // libsndfile gave us the 3 byte sample in the 3 most + // significant bytes -- we want it in the 3 least + // significant bytes. + int *intPtr = (int *)data; + for( int i = 0; i < framesRead; i++ ) + intPtr[i] = intPtr[i] >> 8; + } + else if (format == int16Sample && + !sf_subtype_more_than_16_bits(info.format)) { + // Special case: if the file is in 16-bit (or less) format, + // and the calling method wants 16-bit data, go ahead and + // read 16-bit data directly. This is a pretty common + // case, as most audio files are 16-bit. + SampleBuffer buffer(len * channels, int16Sample); + framesRead = SFCall( + sf_readf_short, sf.get(), (short *)buffer.ptr(), len); + for (int i = 0; i < framesRead; i++) + ((short *)data)[i] = + ((short *)buffer.ptr())[(channels * i) + channel]; + } + else { + // Otherwise, let libsndfile handle the conversion and + // scaling, and pass us normalized data as floats. We can + // then convert to whatever format we want. + SampleBuffer buffer(len * channels, floatSample); + framesRead = SFCall( + sf_readf_float, sf.get(), (float *)buffer.ptr(), len); + auto bufferPtr = (samplePtr)((float *)buffer.ptr() + channel); + CopySamples(bufferPtr, floatSample, + (samplePtr)data, format, + framesRead, + true /* high quality by default */, + channels /* source stride */); + } + } } - else if (format == int16Sample && - !sf_subtype_more_than_16_bits(info.format)) { - // Special case: if the file is in 16-bit (or less) format, - // and the calling method wants 16-bit data, go ahead and - // read 16-bit data directly. This is a pretty common - // case, as most audio files are 16-bit. - SampleBuffer buffer(len * channels, int16Sample); - framesRead = SFCall( - sf_readf_short, sf.get(), (short *)buffer.ptr(), len); - for (int i = 0; i < framesRead; i++) - ((short *)data)[i] = - ((short *)buffer.ptr())[(channels * i) + channel]; - } - else { - // Otherwise, let libsndfile handle the conversion and - // scaling, and pass us normalized data as floats. We can - // then convert to whatever format we want. - SampleBuffer buffer(len * channels, floatSample); - framesRead = SFCall( - sf_readf_float, sf.get(), (float *)buffer.ptr(), len); - auto bufferPtr = (samplePtr)((float *)buffer.ptr() + channel); - CopySamples(bufferPtr, floatSample, - (samplePtr)data, format, - framesRead, - true /* high quality by default */, - channels /* source stride */); + + if ( framesRead < len ) { + if (mayThrow) + //throw FileException{ FileException::Cause::Read, fileName } + ; + ClearSamples(data, format, framesRead, len - framesRead); } return framesRead; diff --git a/src/BlockFile.h b/src/BlockFile.h index 56a6cf123..1425754d0 100644 --- a/src/BlockFile.h +++ b/src/BlockFile.h @@ -67,8 +67,12 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ { // Reading /// Retrieves audio data from this BlockFile + /// Returns the number of samples really read, not more than len + /// If fewer can be read than len, throws an exception if mayThrow is true, + /// otherwise fills the remainder of data with zeroes. virtual size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const = 0; + size_t start, size_t len, bool mayThrow = true) + const = 0; // Other Properties @@ -223,6 +227,7 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ { virtual void FixSummary(void *data); static size_t CommonReadData( + bool mayThrow, const wxFileName &fileName, bool &mSilentLog, const AliasBlockFile *pAliasFile, sampleCount origin, unsigned channel, samplePtr data, sampleFormat format, size_t start, size_t len, diff --git a/src/blockfile/LegacyBlockFile.cpp b/src/blockfile/LegacyBlockFile.cpp index f64ba2abf..960f25416 100644 --- a/src/blockfile/LegacyBlockFile.cpp +++ b/src/blockfile/LegacyBlockFile.cpp @@ -194,10 +194,10 @@ bool LegacyBlockFile::ReadSummary(ArrayOf &data) /// @param start The offset in this block file /// @param len The number of samples to read size_t LegacyBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { sf_count_t origin = (mSummaryInfo.totalSummaryBytes / SAMPLE_SIZE(mFormat)); - return CommonReadData( + return CommonReadData( mayThrow, mFileName, mSilentLog, nullptr, origin, 0, data, format, start, len, &mFormat, mLen ); diff --git a/src/blockfile/LegacyBlockFile.h b/src/blockfile/LegacyBlockFile.h index 549b216af..a2fe1c792 100644 --- a/src/blockfile/LegacyBlockFile.h +++ b/src/blockfile/LegacyBlockFile.h @@ -51,7 +51,7 @@ class LegacyBlockFile final : public BlockFile { bool ReadSummary(ArrayOf &data) override; /// Read the data section of the disk file size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Create a NEW block file identical to this one BlockFilePtr Copy(wxFileNameWrapper &&newFileName) override; diff --git a/src/blockfile/ODDecodeBlockFile.cpp b/src/blockfile/ODDecodeBlockFile.cpp index c6dff23dd..141e57742 100644 --- a/src/blockfile/ODDecodeBlockFile.cpp +++ b/src/blockfile/ODDecodeBlockFile.cpp @@ -438,20 +438,22 @@ void *ODDecodeBlockFile::CalcSummary(samplePtr buffer, size_t len, /// @param start The offset within the block to begin reading /// @param len The number of samples to read size_t ODDecodeBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { - size_t ret; auto locker = LockForRead(); if(IsSummaryAvailable()) - ret = SimpleBlockFile::ReadData(data,format,start,len); + return SimpleBlockFile::ReadData(data, format, start, len, mayThrow); else { + if (mayThrow) + //throw NotYetAvailableException{ mFileName } + ; + //we should do an ODRequest to start processing the data here, and wait till it finishes. and just do a SimpleBlockFile //ReadData. ClearSamples(data, format, 0, len); - ret = len; + return 0; } - return ret; } /// Read the summary of this alias block from disk. Since the audio data diff --git a/src/blockfile/ODDecodeBlockFile.h b/src/blockfile/ODDecodeBlockFile.h index 0a98df679..042b4a6de 100644 --- a/src/blockfile/ODDecodeBlockFile.h +++ b/src/blockfile/ODDecodeBlockFile.h @@ -109,7 +109,7 @@ class ODDecodeBlockFile final : public SimpleBlockFile /// Reads the specified data from the aliased file using libsndfile size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Read the summary into a buffer bool ReadSummary(ArrayOf &data) override; diff --git a/src/blockfile/ODPCMAliasBlockFile.cpp b/src/blockfile/ODPCMAliasBlockFile.cpp index 4f14be7f6..886de43c6 100644 --- a/src/blockfile/ODPCMAliasBlockFile.cpp +++ b/src/blockfile/ODPCMAliasBlockFile.cpp @@ -414,7 +414,7 @@ void ODPCMAliasBlockFile::WriteSummary() // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data SampleBuffer sampleData(mLen, floatSample); - this->ReadData(sampleData.ptr(), floatSample, 0, mLen); + this->ReadData(sampleData.ptr(), floatSample, 0, mLen, true); ArrayOf cleanup; void *summaryData = CalcSummary(sampleData.ptr(), mLen, @@ -495,7 +495,7 @@ void *ODPCMAliasBlockFile::CalcSummary(samplePtr buffer, size_t len, /// @param start The offset within the block to begin reading /// @param len The number of samples to read size_t ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { auto locker = LockForRead(); @@ -505,7 +505,7 @@ size_t ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, return len; } - return CommonReadData( + return CommonReadData( mayThrow, mAliasedFileName, mSilentAliasLog, this, mAliasStart, mAliasChannel, data, format, start, len); } diff --git a/src/blockfile/ODPCMAliasBlockFile.h b/src/blockfile/ODPCMAliasBlockFile.h index 421eadad3..04752955f 100644 --- a/src/blockfile/ODPCMAliasBlockFile.h +++ b/src/blockfile/ODPCMAliasBlockFile.h @@ -118,7 +118,7 @@ class ODPCMAliasBlockFile final : public PCMAliasBlockFile /// Reads the specified data from the aliased file using libsndfile size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Read the summary into a buffer bool ReadSummary(ArrayOf &data) override; diff --git a/src/blockfile/PCMAliasBlockFile.cpp b/src/blockfile/PCMAliasBlockFile.cpp index 8ce192ee5..35719577f 100644 --- a/src/blockfile/PCMAliasBlockFile.cpp +++ b/src/blockfile/PCMAliasBlockFile.cpp @@ -75,14 +75,14 @@ PCMAliasBlockFile::~PCMAliasBlockFile() /// @param start The offset within the block to begin reading /// @param len The number of samples to read size_t PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { if(!mAliasedFileName.IsOk()){ // intentionally silenced memset(data, 0, SAMPLE_SIZE(format) * len); return len; } - return CommonReadData( + return CommonReadData( mayThrow, mAliasedFileName, mSilentAliasLog, this, mAliasStart, mAliasChannel, data, format, start, len); } diff --git a/src/blockfile/PCMAliasBlockFile.h b/src/blockfile/PCMAliasBlockFile.h index 738d84091..369642919 100644 --- a/src/blockfile/PCMAliasBlockFile.h +++ b/src/blockfile/PCMAliasBlockFile.h @@ -38,7 +38,7 @@ class PCMAliasBlockFile /* not final */ : public AliasBlockFile /// Reads the specified data from the aliased file using libsndfile size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; void SaveXML(XMLWriter &xmlFile) override; BlockFilePtr Copy(wxFileNameWrapper &&fileName) override; diff --git a/src/blockfile/SilentBlockFile.cpp b/src/blockfile/SilentBlockFile.cpp index a2d33effb..3250a77c6 100644 --- a/src/blockfile/SilentBlockFile.cpp +++ b/src/blockfile/SilentBlockFile.cpp @@ -32,7 +32,7 @@ bool SilentBlockFile::ReadSummary(ArrayOf &data) } size_t SilentBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t WXUNUSED(start), size_t len) const + size_t WXUNUSED(start), size_t len, bool) const { ClearSamples(data, format, 0, len); diff --git a/src/blockfile/SilentBlockFile.h b/src/blockfile/SilentBlockFile.h index e1788bccc..5003faed1 100644 --- a/src/blockfile/SilentBlockFile.h +++ b/src/blockfile/SilentBlockFile.h @@ -36,7 +36,7 @@ class SilentBlockFile final : public BlockFile { bool ReadSummary(ArrayOf &data) override; /// Read the data section of the disk file size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Create a NEW block file identical to this one BlockFilePtr Copy(wxFileNameWrapper &&newFileName) override; diff --git a/src/blockfile/SimpleBlockFile.cpp b/src/blockfile/SimpleBlockFile.cpp index c791a6551..9b3923a8b 100644 --- a/src/blockfile/SimpleBlockFile.cpp +++ b/src/blockfile/SimpleBlockFile.cpp @@ -315,7 +315,9 @@ void SimpleBlockFile::FillCache() // Read samples into cache mCache.sampleData.reinit(mLen * SAMPLE_SIZE(mCache.format)); - if (ReadData(mCache.sampleData.get(), mCache.format, 0, mLen) != mLen) + if (ReadData(mCache.sampleData.get(), mCache.format, 0, mLen, + // no exceptions! + false) != mLen) { // Could not read all samples mCache.sampleData.reset(); @@ -387,21 +389,30 @@ bool SimpleBlockFile::ReadSummary(ArrayOf &data) /// @param start The offset in this block file /// @param len The number of samples to read size_t SimpleBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { if (mCache.active) { //wxLogDebug("SimpleBlockFile::ReadData(): Data are already in cache."); - len = std::min(len, std::max(start, mLen) - start); + auto framesRead = std::min(len, std::max(start, mLen) - start); CopySamples( (samplePtr)(mCache.sampleData.get() + start * SAMPLE_SIZE(mCache.format)), - mCache.format, data, format, len); - return len; + mCache.format, data, format, framesRead); + + if ( framesRead < len ) { + if (mayThrow) + // Not the best exception class? + //throw FileException{ FileException::Cause::Read, mFileName } + ; + ClearSamples(data, format, framesRead, len - framesRead); + } + + return framesRead; } else - return CommonReadData( + return CommonReadData( mayThrow, mFileName, mSilentLog, nullptr, 0, 0, data, format, start, len); } diff --git a/src/blockfile/SimpleBlockFile.h b/src/blockfile/SimpleBlockFile.h index a7fc761a3..14c010d2e 100644 --- a/src/blockfile/SimpleBlockFile.h +++ b/src/blockfile/SimpleBlockFile.h @@ -66,7 +66,7 @@ class PROFILE_DLL_API SimpleBlockFile /* not final */ : public BlockFile { bool ReadSummary(ArrayOf &data) override; /// Read the data section of the disk file size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Create a NEW block file identical to this one BlockFilePtr Copy(wxFileNameWrapper &&newFileName) override; From 39b8d99a5669038414357b7cdcb781f006d3e973 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 20 Mar 2017 10:54:03 -0400 Subject: [PATCH 42/91] WaveTrack::Get, WaveClip::GetSamples take a mayThrow=true argument... ... and pass non-default in all needed places. Don't throw, don't put up error dialogs, in drawing or hit-test code. --- src/FreqWindow.cpp | 8 +++-- src/MixerBoard.cpp | 15 ++++++--- src/Sequence.cpp | 78 +++++++++++++++++++++++++-------------------- src/Sequence.h | 8 ++--- src/TrackArtist.cpp | 4 ++- src/TrackPanel.cpp | 11 +++++-- src/WaveClip.cpp | 6 ++-- src/WaveClip.h | 2 +- src/WaveTrack.cpp | 13 ++++---- src/WaveTrack.h | 3 +- 10 files changed, 88 insertions(+), 60 deletions(-) diff --git a/src/FreqWindow.cpp b/src/FreqWindow.cpp index a43addf75..3fd61e06f 100644 --- a/src/FreqWindow.cpp +++ b/src/FreqWindow.cpp @@ -566,7 +566,9 @@ void FreqWindow::GetAudio() // dataLen is not more than 10 * 2 ^ 20 mDataLen = dataLen.as_size_t(); mData = Floats{ mDataLen }; - track->Get((samplePtr)mData.get(), floatSample, start, mDataLen); + // Don't allow throw for bad reads + track->Get((samplePtr)mData.get(), floatSample, start, mDataLen, + fillZero, false); } else { if (track->GetRate() != mRate) { @@ -577,7 +579,9 @@ void FreqWindow::GetAudio() } auto start = track->TimeToLongSamples(p->mViewInfo.selectedRegion.t0()); Floats buffer2{ mDataLen }; - track->Get((samplePtr)buffer2.get(), floatSample, start, mDataLen); + // Again, stop exceptions + track->Get((samplePtr)buffer2.get(), floatSample, start, mDataLen, + fillZero, false); for (size_t i = 0; i < mDataLen; i++) mData[i] += buffer2[i]; } diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index fa21451b9..3514cd1eb 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -544,10 +544,11 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) // But this change is consistent with the others for EXPERIMENTAL_MIDI_OUT, so I accept it. if ((t0 < 0.0) || (t1 < 0.0) || (t0 >= t1) || // bad time value or nothing to show #ifdef EXPERIMENTAL_MIDI_OUT - ((mMixerBoard->HasSolo() || mTrack->GetMute()) && !mTrack->GetSolo())) + ((mMixerBoard->HasSolo() || mTrack->GetMute()) && !mTrack->GetSolo()) #else - ((mMixerBoard->HasSolo() || mLeftTrack->GetMute()) && !mLeftTrack->GetSolo())) + ((mMixerBoard->HasSolo() || mLeftTrack->GetMute()) && !mLeftTrack->GetSolo()) #endif + ) { //v Vaughan, 2011-02-25: Moved the update back to TrackPanel::OnTimer() as it helps with // playback issues reported by Bill and noted on Bug 258, so no assert. @@ -636,9 +637,11 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) // in about 1/20 second (ticks of TrackPanel timer), so this won't overflow auto nFrames = scnFrames.as_size_t(); - Floats tempFloatsArray{ size_t(nFrames) }; + Floats tempFloatsArray{ nFrames }; decltype(tempFloatsArray) meterFloatsArray; - bool bSuccess = mLeftTrack->Get((samplePtr)tempFloatsArray.get(), floatSample, startSample, nFrames); + // Don't throw on read error in this drawing update routine + bool bSuccess = mLeftTrack->Get((samplePtr)tempFloatsArray.get(), + floatSample, startSample, nFrames, fillZero, false); if (bSuccess) { // We always pass a stereo sample array to the meter, as it shows 2 channels. @@ -651,7 +654,9 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) meterFloatsArray[2 * index] = tempFloatsArray[index]; if (mRightTrack) - bSuccess = mRightTrack->Get((samplePtr)tempFloatsArray.get(), floatSample, startSample, nFrames); + // Again, don't throw + bSuccess = mRightTrack->Get((samplePtr)tempFloatsArray.get(), + floatSample, startSample, nFrames, fillZero, false); if (bSuccess) // Interleave right channel, or duplicate same signal for "right" channel in mono case. diff --git a/src/Sequence.cpp b/src/Sequence.cpp index ce5641a38..955672150 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -41,6 +41,8 @@ #include #include +#include "AudacityException.h" + #include "BlockFile.h" #include "blockfile/ODDecodeBlockFile.h" #include "DirManager.h" @@ -405,7 +407,7 @@ std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const blocklen = ( std::min(s1, block0.start + file->GetLength()) - s0 ).as_size_t(); wxASSERT(file->IsAlias() || (blocklen <= mMaxSamples)); // Vaughan, 2012-02-29 - Get(b0, buffer.ptr(), mSampleFormat, s0, blocklen); + Get(b0, buffer.ptr(), mSampleFormat, s0, blocklen, true); dest->Append(buffer.ptr(), mSampleFormat, blocklen); } @@ -425,7 +427,7 @@ std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const blocklen = (s1 - block.start).as_size_t(); wxASSERT(file->IsAlias() || (blocklen <= mMaxSamples)); // Vaughan, 2012-02-29 if (blocklen < file->GetLength()) { - Get(b1, buffer.ptr(), mSampleFormat, block.start, blocklen); + Get(b1, buffer.ptr(), mSampleFormat, block.start, blocklen, true); dest->Append(buffer.ptr(), mSampleFormat, blocklen); } else @@ -524,12 +526,12 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) auto sAddedLen = addedLen.as_size_t(); // s lies within block: auto splitPoint = ( s - block.start ).as_size_t(); - Read(buffer.ptr(), mSampleFormat, block, 0, splitPoint); + Read(buffer.ptr(), mSampleFormat, block, 0, splitPoint, true); src->Get(0, buffer.ptr() + splitPoint*sampleSize, - mSampleFormat, 0, sAddedLen); + mSampleFormat, 0, sAddedLen, true); Read(buffer.ptr() + (splitPoint + sAddedLen) * sampleSize, mSampleFormat, block, - splitPoint, length - splitPoint); + splitPoint, length - splitPoint, true); auto file = mDirManager->NewSimpleBlockFile( @@ -567,13 +569,13 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) const auto sum = splitLen + sAddedLen; SampleBuffer sumBuffer(sum, mSampleFormat); - Read(sumBuffer.ptr(), mSampleFormat, splitBlock, 0, splitPoint); + Read(sumBuffer.ptr(), mSampleFormat, splitBlock, 0, splitPoint, true); src->Get(0, sumBuffer.ptr() + splitPoint * sampleSize, mSampleFormat, - 0, sAddedLen); + 0, sAddedLen, true); Read(sumBuffer.ptr() + (splitPoint + sAddedLen) * sampleSize, mSampleFormat, splitBlock, splitPoint, - splitLen - splitPoint); + splitLen - splitPoint, true); Blockify(*mDirManager, mMaxSamples, mSampleFormat, newBlock, splitBlock.start, sumBuffer.ptr(), sum); @@ -598,9 +600,9 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) SampleBuffer sampleBuffer(std::max(leftLen, rightLen), mSampleFormat); - Read(sampleBuffer.ptr(), mSampleFormat, splitBlock, 0, splitPoint); + Read(sampleBuffer.ptr(), mSampleFormat, splitBlock, 0, splitPoint, true); src->Get(0, sampleBuffer.ptr() + splitPoint*sampleSize, - mSampleFormat, 0, srcFirstTwoLen); + mSampleFormat, 0, srcFirstTwoLen, true); Blockify(*mDirManager, mMaxSamples, mSampleFormat, newBlock, splitBlock.start, sampleBuffer.ptr(), leftLen); @@ -618,9 +620,9 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) auto lastStart = penultimate.start; src->Get(srcNumBlocks - 2, sampleBuffer.ptr(), mSampleFormat, - lastStart, srcLastTwoLen); + lastStart, srcLastTwoLen, true); Read(sampleBuffer.ptr() + srcLastTwoLen * sampleSize, mSampleFormat, - splitBlock, splitPoint, rightSplit); + splitBlock, splitPoint, rightSplit, true); Blockify(*mDirManager, mMaxSamples, mSampleFormat, newBlock, s + lastStart, sampleBuffer.ptr(), rightLen); @@ -1112,43 +1114,50 @@ int Sequence::FindBlock(sampleCount pos) const } bool Sequence::Read(samplePtr buffer, sampleFormat format, - const SeqBlock &b, size_t blockRelativeStart, size_t len) - const + const SeqBlock &b, size_t blockRelativeStart, size_t len, + bool mayThrow) { const auto &f = b.f; wxASSERT(blockRelativeStart + len <= f->GetLength()); - auto result = f->ReadData(buffer, format, blockRelativeStart, len); + // Either throws, or of !mayThrow, tells how many were really read + auto result = f->ReadData(buffer, format, blockRelativeStart, len, mayThrow); if (result != len) { wxLogWarning(wxT("Expected to read %ld samples, got %d samples."), len, result); - ClearSamples(buffer, format, result, len-result); + return false; } return true; } bool Sequence::Get(samplePtr buffer, sampleFormat format, - sampleCount start, size_t len) const + sampleCount start, size_t len, bool mayThrow) const { if (start == mNumSamples) { return len == 0; } if (start < 0 || start > mNumSamples || - start + len > mNumSamples) + start + len > mNumSamples) { + if (mayThrow) + //THROW_INCONSISTENCY_EXCEPTION + ; + ClearSamples( buffer, floatSample, 0, len ); return false; + } int b = FindBlock(start); - return Get(b, buffer, format, start, len); + return Get(b, buffer, format, start, len, mayThrow); } bool Sequence::Get(int b, samplePtr buffer, sampleFormat format, - sampleCount start, size_t len) const + sampleCount start, size_t len, bool mayThrow) const { + bool result = true; while (len) { const SeqBlock &block = mBlock[b]; // start is in block @@ -1156,15 +1165,15 @@ bool Sequence::Get(int b, samplePtr buffer, sampleFormat format, // bstart is not more than block length const auto blen = std::min(len, block.f->GetLength() - bstart); - Read(buffer, format, block, bstart, blen); + if (! Read(buffer, format, block, bstart, blen, mayThrow) ) + result = false; len -= blen; buffer += (blen * SAMPLE_SIZE(format)); b++; start += blen; } - - return true; + return result; } // Pass NULL to set silence @@ -1211,7 +1220,7 @@ bool Sequence::Set(samplePtr buffer, sampleFormat format, ; if ( bstart > 0 || blen < fileLength ) { - Read(scratch.ptr(), mSampleFormat, block, 0, fileLength); + Read(scratch.ptr(), mSampleFormat, block, 0, fileLength, true); if (useBuffer) { auto sampleSize = SAMPLE_SIZE(mSampleFormat); @@ -1393,7 +1402,8 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl, default: case 1: // Read samples - Read((samplePtr)temp.get(), floatSample, seqBlock, startPosition, num); + // no-throw for display operations! + Read((samplePtr)temp.get(), floatSample, seqBlock, startPosition, num, false); break; case 256: // Read triples @@ -1526,7 +1536,7 @@ bool Sequence::Append(samplePtr buffer, sampleFormat format, SeqBlock &lastBlock = *pLastBlock; const auto addLen = std::min(mMaxSamples - length, len); - Read(buffer2.ptr(), mSampleFormat, lastBlock, 0, length); + Read(buffer2.ptr(), mSampleFormat, lastBlock, 0, length, true); CopySamples(buffer, format, @@ -1653,12 +1663,12 @@ bool Sequence::Delete(sampleCount start, sampleCount len) scratch.Allocate(scratchSize, mSampleFormat); - Read(scratch.ptr(), mSampleFormat, b, 0, pos); + Read(scratch.ptr(), mSampleFormat, b, 0, pos, true); Read(scratch.ptr() + (pos * sampleSize), mSampleFormat, b, // ... and therefore pos + len // is not more than the length of the block - ( pos + len ).as_size_t(), newLen - pos); + ( pos + len ).as_size_t(), newLen - pos, true); b = SeqBlock( mDirManager->NewSimpleBlockFile(scratch.ptr(), newLen, mSampleFormat), @@ -1694,7 +1704,7 @@ bool Sequence::Delete(sampleCount start, sampleCount len) if (preBufferLen >= mMinSamples || b0 == 0) { if (!scratch.ptr()) scratch.Allocate(scratchSize, mSampleFormat); - Read(scratch.ptr(), mSampleFormat, preBlock, 0, preBufferLen); + Read(scratch.ptr(), mSampleFormat, preBlock, 0, preBufferLen, true); auto pFile = mDirManager->NewSimpleBlockFile(scratch.ptr(), preBufferLen, mSampleFormat); @@ -1707,9 +1717,9 @@ bool Sequence::Delete(sampleCount start, sampleCount len) if (!scratch.ptr()) scratch.Allocate(scratchSize, mSampleFormat); - Read(scratch.ptr(), mSampleFormat, prepreBlock, 0, prepreLen); + Read(scratch.ptr(), mSampleFormat, prepreBlock, 0, prepreLen, true); Read(scratch.ptr() + prepreLen*sampleSize, mSampleFormat, - preBlock, 0, preBufferLen); + preBlock, 0, preBufferLen, true); newBlock.erase(newBlock.end() - 1); Blockify(*mDirManager, mMaxSamples, mSampleFormat, @@ -1738,7 +1748,7 @@ bool Sequence::Delete(sampleCount start, sampleCount len) scratch.Allocate(postBufferLen, mSampleFormat); // start + len - 1 lies within postBlock auto pos = (start + len - postBlock.start).as_size_t(); - Read(scratch.ptr(), mSampleFormat, postBlock, pos, postBufferLen); + Read(scratch.ptr(), mSampleFormat, postBlock, pos, postBufferLen, true); auto file = mDirManager->NewSimpleBlockFile(scratch.ptr(), postBufferLen, mSampleFormat); @@ -1753,9 +1763,9 @@ bool Sequence::Delete(sampleCount start, sampleCount len) scratch.Allocate(sum, mSampleFormat); // start + len - 1 lies within postBlock auto pos = (start + len - postBlock.start).as_size_t(); - Read(scratch.ptr(), mSampleFormat, postBlock, pos, postBufferLen); + Read(scratch.ptr(), mSampleFormat, postBlock, pos, postBufferLen, true); Read(scratch.ptr() + (postBufferLen * sampleSize), mSampleFormat, - postpostBlock, 0, postpostLen); + postpostBlock, 0, postpostLen, true); Blockify(*mDirManager, mMaxSamples, mSampleFormat, newBlock, start, scratch.ptr(), sum); diff --git a/src/Sequence.h b/src/Sequence.h index 3095e2c67..c458c6119 100644 --- a/src/Sequence.h +++ b/src/Sequence.h @@ -86,7 +86,7 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{ sampleCount GetNumSamples() const { return mNumSamples; } bool Get(samplePtr buffer, sampleFormat format, - sampleCount start, size_t len) const; + sampleCount start, size_t len, bool mayThrow) const; // Note that len is not size_t, because nullptr may be passed for buffer, in // which case, silence is inserted, possibly a large amount. @@ -249,9 +249,9 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{ (DirManager &dirManager, BlockArray &blocks, sampleCount &numSamples, const SeqBlock &b); - bool Read(samplePtr buffer, sampleFormat format, + static bool Read(samplePtr buffer, sampleFormat format, const SeqBlock &b, - size_t blockRelativeStart, size_t len) const; + size_t blockRelativeStart, size_t len, bool mayThrow); // Accumulate NEW block files onto the end of a block array. // Does not change this sequence. The intent is to use @@ -261,7 +261,7 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{ BlockArray &list, sampleCount start, samplePtr buffer, size_t len); bool Get(int b, samplePtr buffer, sampleFormat format, - sampleCount start, size_t len) const; + sampleCount start, size_t len, bool mayThrow) const; public: diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index 81d25e9a3..4ab3901b3 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -1324,7 +1324,9 @@ void TrackArtist::DrawIndividualSamples(wxDC &dc, int leftOffset, const wxRect & return; Floats buffer{ size_t(slen) }; - clip->GetSamples((samplePtr)buffer.get(), floatSample, s0, slen); + clip->GetSamples((samplePtr)buffer.get(), floatSample, s0, slen, + // Suppress exceptions in this drawing operation: + false); ArrayOf xpos{ size_t(slen) }; ArrayOf ypos{ size_t(slen) }; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 85d81b5e1..4db2b03f0 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -2513,9 +2513,12 @@ void TrackPanel::StartSnappingFreqSelection (const WaveTrack *pTrack) end - start )); const auto effectiveLength = std::max(minLength, length); frequencySnappingData.resize(effectiveLength, 0.0f); + pTrack->Get( reinterpret_cast(&frequencySnappingData[0]), - floatSample, start, length); + floatSample, start, length, fillZero, + // Don't try to cope with exceptions, just read zeroes instead. + false); // Use same settings as are now used for spectrogram display, // except, shrink the window as needed so we get some answers @@ -6843,7 +6846,11 @@ bool TrackPanel::HitTestSamples(Track *track, const wxRect &rect, const wxMouseE // Just get one sample. float oneSample; auto s0 = (sampleCount)(tt * rate + 0.5); - wavetrack->Get((samplePtr)&oneSample, floatSample, s0, 1); + if ( !wavetrack->Get( + (samplePtr)&oneSample, floatSample, s0, 1, fillZero, + // Do not propagate exception but return a failure value + false)) + return false; // Get y distance of envelope point from center line (in pixels). float zoomMin, zoomMax; diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index 33779c360..fa830ab89 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -401,9 +401,9 @@ void WaveClip::SetOffset(double offset) } bool WaveClip::GetSamples(samplePtr buffer, sampleFormat format, - sampleCount start, size_t len) const + sampleCount start, size_t len, bool mayThrow) const { - return mSequence->Get(buffer, format, start, len); + return mSequence->Get(buffer, format, start, len, mayThrow); } bool WaveClip::SetSamples(samplePtr buffer, sampleFormat format, @@ -1855,7 +1855,7 @@ bool WaveClip::Resample(int rate, ProgressDialog *progress) bool isLast = ((pos + inLen) == numSamples); - if (!mSequence->Get((samplePtr)inBuffer.get(), floatSample, pos, inLen)) + if (!mSequence->Get((samplePtr)inBuffer.get(), floatSample, pos, inLen, true)) { error = true; break; diff --git a/src/WaveClip.h b/src/WaveClip.h index ed0727d1e..95fa6103e 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -251,7 +251,7 @@ public: bool AfterClip(double t) const; bool GetSamples(samplePtr buffer, sampleFormat format, - sampleCount start, size_t len) const; + sampleCount start, size_t len, bool mayThrow = true) const; bool SetSamples(samplePtr buffer, sampleFormat format, sampleCount start, size_t len); diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 9523dbc83..4dcd66c0b 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -1980,12 +1980,14 @@ float WaveTrack::GetRMS(double t0, double t1, bool mayThrow) const } bool WaveTrack::Get(samplePtr buffer, sampleFormat format, - sampleCount start, size_t len, fillFormat fill ) const + sampleCount start, size_t len, fillFormat fill, + bool mayThrow) const { // Simple optimization: When this buffer is completely contained within one clip, // don't clear anything (because we won't have to). Otherwise, just clear // everything to be on the safe side. bool doClear = true; + bool result = true; for (const auto &clip: mClips) { if (start >= clip->GetStartSample() && start+len <= clip->GetEndSample()) @@ -2046,15 +2048,12 @@ bool WaveTrack::Get(samplePtr buffer, sampleFormat format, (samplePtr)(((char*)buffer) + startDelta.as_size_t() * SAMPLE_SIZE(format)), - format, inclipDelta, samplesToCopy.as_size_t() )) - { - wxASSERT(false); // should always work - return false; - } + format, inclipDelta, samplesToCopy.as_size_t(), mayThrow )) + result = false; } } - return true; + return result; } bool WaveTrack::Set(samplePtr buffer, sampleFormat format, diff --git a/src/WaveTrack.h b/src/WaveTrack.h index 68c2d3607..73252c010 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -252,7 +252,8 @@ class AUDACITY_DLL_API WaveTrack final : public Track { /// guaranteed that the same samples are affected. /// bool Get(samplePtr buffer, sampleFormat format, - sampleCount start, size_t len, fillFormat fill=fillZero) const; + sampleCount start, size_t len, + fillFormat fill = fillZero, bool mayThrow = true) const; bool Set(samplePtr buffer, sampleFormat format, sampleCount start, size_t len); void GetEnvelopeValues(double *buffer, size_t bufferLen, From 987b038fd8df6b6595a9dbe5ed8165b62742a7a6 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 26 Dec 2016 13:58:08 -0500 Subject: [PATCH 43/91] Exception safety in overrides of WriteSummary --- src/BlockFile.cpp | 12 +++-- src/blockfile/ODPCMAliasBlockFile.cpp | 66 ++++++++++++++------------- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp index a83b3839f..8f5bb6ee8 100644 --- a/src/BlockFile.cpp +++ b/src/BlockFile.cpp @@ -680,6 +680,13 @@ AliasBlockFile::AliasBlockFile(wxFileNameWrapper &&existingSummaryFileName, /// summarize. void AliasBlockFile::WriteSummary() { + // To build the summary data, call ReadData (implemented by the + // derived classes) to get the sample data + // Call this first, so that in case of exceptions from ReadData, there is + // no new output file + SampleBuffer sampleData(mLen, floatSample); + this->ReadData(sampleData.ptr(), floatSample, 0, mLen); + // Now checked carefully in the DirManager //wxASSERT( !wxFileExists(FILENAME(mFileName.GetFullPath()))); @@ -697,11 +704,6 @@ void AliasBlockFile::WriteSummary() return; } - // To build the summary data, call ReadData (implemented by the - // derived classes) to get the sample data - SampleBuffer sampleData(mLen, floatSample); - this->ReadData(sampleData.ptr(), floatSample, 0, mLen); - ArrayOf cleanup; void *summaryData = BlockFile::CalcSummary(sampleData.ptr(), mLen, floatSample, cleanup); diff --git a/src/blockfile/ODPCMAliasBlockFile.cpp b/src/blockfile/ODPCMAliasBlockFile.cpp index 886de43c6..62f468559 100644 --- a/src/blockfile/ODPCMAliasBlockFile.cpp +++ b/src/blockfile/ODPCMAliasBlockFile.cpp @@ -380,42 +380,46 @@ auto ODPCMAliasBlockFile::GetFileName() const -> GetFileNameResult /// Write the summary to disk, using the derived ReadData() to get the data void ODPCMAliasBlockFile::WriteSummary() { - //the mFileName path may change, for example, when the project is saved. - //(it moves from /tmp/ to wherever it is saved to. - mFileNameMutex.Lock(); - - //wxFFile is not thread-safe - if any error occurs in opening the file, - // it posts a wxlog message which WILL crash - // Audacity because it goes into the wx GUI. - // For this reason I left the wxFFile method commented out. (mchinen) - // wxFFile summaryFile(mFileName.GetFullPath(), wxT("wb")); - - // ...and we use fopen instead. - FILE* summaryFile{}; - wxString sFullPath = mFileName.GetFullPath(); - { - ArrayOf < char > fileNameChar{ strlen(sFullPath.mb_str(wxConvFile)) + 1 }; - strcpy(fileNameChar.get(), sFullPath.mb_str(wxConvFile)); - summaryFile = fopen(fileNameChar.get(), "wb"); - - mFileNameMutex.Unlock(); - - // JKC ANSWER-ME: Whay is IsOpened() commented out? - if (!summaryFile){//.IsOpened() ){ - - // Never silence the Log w.r.t write errors; they always count - //however, this is going to be called from a non-main thread, - //and wxLog calls are not thread safe. - printf("Unable to write summary data to file: %s", fileNameChar.get()); - return; - } - } - // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data + // Call this first, so that in case of exceptions from ReadData, there is + // no new output file SampleBuffer sampleData(mLen, floatSample); this->ReadData(sampleData.ptr(), floatSample, 0, mLen, true); + ArrayOf< char > fileNameChar; + FILE *summaryFile{}; + { + //the mFileName path may change, for example, when the project is saved. + //(it moves from /tmp/ to wherever it is saved to. + ODLocker locker { &mFileNameMutex }; + + //wxFFile is not thread-safe - if any error occurs in opening the file, + // it posts a wxlog message which WILL crash + // Audacity because it goes into the wx GUI. + // For this reason I left the wxFFile method commented out. (mchinen) + // wxFFile summaryFile(mFileName.GetFullPath(), wxT("wb")); + + // ...and we use fopen instead. + wxString sFullPath = mFileName.GetFullPath(); + fileNameChar.reinit( strlen(sFullPath.mb_str(wxConvFile)) + 1 ); + strcpy(fileNameChar.get(), sFullPath.mb_str(wxConvFile)); + summaryFile = fopen(fileNameChar.get(), "wb"); + } + + // JKC ANSWER-ME: Whay is IsOpened() commented out? + if (!summaryFile){//.IsOpened() ){ + + // Never silence the Log w.r.t write errors; they always count + //however, this is going to be called from a non-main thread, + //and wxLog calls are not thread safe. + printf("Unable to write summary data to file: %s", fileNameChar.get()); + + // throw FileException{ + // FileException::Cause::Read, wxFileName{ fileNameChar.get() } }; + return; + } + ArrayOf cleanup; void *summaryData = CalcSummary(sampleData.ptr(), mLen, floatSample, cleanup); From 38b8e57e4efa94a3eeb75c13023b83aeb5d894d1 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 22 Dec 2016 17:08:29 -0500 Subject: [PATCH 44/91] Specify whether to throw on bad read in Mixer and WaveTrackCache... ... Do throw when exporting or mixing-and-rendering; don't if playing back or drawing a spectrogram, but then just use zeroes. --- src/AudioIO.cpp | 10 ++++++---- src/Mix.cpp | 13 +++++++++---- src/Mix.h | 4 +++- src/WaveClip.cpp | 4 +++- src/WaveTrack.cpp | 6 ++++-- src/WaveTrack.h | 3 ++- src/export/Export.cpp | 2 ++ 7 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index 4320e964c..ccddc5cb0 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -1883,10 +1883,12 @@ int AudioIO::StartStream(const ConstWaveTrackArray &playbackTracks, // MB: use normal time for the end time, not warped time! mPlaybackMixers[i] = std::make_unique (WaveTrackConstArray{ mPlaybackTracks[i] }, - warpOptions, - mT0, mT1, 1, - playbackMixBufferSize, false, - mRate, floatSample, false); + // Don't throw for read errors, just play silence: + false, + warpOptions, + mT0, mT1, 1, + playbackMixBufferSize, false, + mRate, floatSample, false); mPlaybackMixers[i]->ApplyTrackGains(false); } } diff --git a/src/Mix.cpp b/src/Mix.cpp index 71ddc7eb7..a16ca05e2 100644 --- a/src/Mix.cpp +++ b/src/Mix.cpp @@ -160,6 +160,8 @@ void MixAndRender(TrackList *tracks, TrackFactory *trackFactory, } Mixer mixer(waveArray, + // Throw to abort mix-and-render if read fails: + true, Mixer::WarpOptions(tracks->GetTimeTrack()), startTime, endTime, mono ? 1 : 2, maxBlockLen, false, rate, format); @@ -239,6 +241,7 @@ Mixer::WarpOptions::WarpOptions(double min, double max) } Mixer::Mixer(const WaveTrackConstArray &inputTracks, + bool mayThrow, const WarpOptions &warpOptions, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, @@ -254,6 +257,8 @@ Mixer::Mixer(const WaveTrackConstArray &inputTracks, , mNumChannels{ static_cast(numOutChannels) } , mGains{ mNumChannels } + + , mMayThrow{ mayThrow } { mHighQuality = highQuality; mInputTrack.reinit(mNumInputTracks); @@ -434,7 +439,7 @@ size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache, // Nothing to do if past end of play interval if (getLen > 0) { if (backwards) { - auto results = cache.Get(floatSample, *pos - (getLen - 1), getLen); + auto results = cache.Get(floatSample, *pos - (getLen - 1), getLen, mMayThrow); if (results) memcpy(&queue[*queueLen], results, sizeof(float) * getLen); else @@ -446,7 +451,7 @@ size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache, *pos -= getLen; } else { - auto results = cache.Get(floatSample, *pos, getLen); + auto results = cache.Get(floatSample, *pos, getLen, mMayThrow); if (results) memcpy(&queue[*queueLen], results, sizeof(float) * getLen); else @@ -554,7 +559,7 @@ size_t Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache, slen = std::min(slen, mMaxOut); if (backwards) { - auto results = cache.Get(floatSample, *pos - (slen - 1), slen); + auto results = cache.Get(floatSample, *pos - (slen - 1), slen, mMayThrow); if (results) memcpy(mFloatBuffer.get(), results, sizeof(float) * slen); else @@ -567,7 +572,7 @@ size_t Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache, *pos -= slen; } else { - auto results = cache.Get(floatSample, *pos, slen); + auto results = cache.Get(floatSample, *pos, slen, mMayThrow); if (results) memcpy(mFloatBuffer.get(), results, sizeof(float) * slen); else diff --git a/src/Mix.h b/src/Mix.h index 086b3d4ae..a2fefd82c 100644 --- a/src/Mix.h +++ b/src/Mix.h @@ -91,7 +91,7 @@ class AUDACITY_DLL_API Mixer { // Constructor / Destructor // - Mixer(const WaveTrackConstArray &inputTracks, + Mixer(const WaveTrackConstArray &inputTracks, bool mayThrow, const WarpOptions &warpOptions, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, @@ -183,6 +183,8 @@ class AUDACITY_DLL_API Mixer { double mRate; double mSpeed; bool mHighQuality; + + bool mMayThrow; }; #endif diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index fa830ab89..cfc527576 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -901,7 +901,9 @@ bool SpecCache::CalculateOneSpectrum floatSample, sampleCount( floor(0.5 + from.as_double() + offset * rate) ), - myLen) + myLen, + // Don't throw in this drawing operation + false) ); if (copy) { diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 4dcd66c0b..6e8f10c15 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -2621,7 +2621,7 @@ void WaveTrackCache::SetTrack(const WaveTrack *pTrack) } constSamplePtr WaveTrackCache::Get(sampleFormat format, - sampleCount start, size_t len) + sampleCount start, size_t len, bool mayThrow) { if (format == floatSample && len > 0) { const auto end = start + len; @@ -2671,7 +2671,9 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format, if (start0 >= 0) { const auto len0 = mPTrack->GetBestBlockSize(start0); wxASSERT(len0 <= mBufferSize); - if (!mPTrack->Get(samplePtr(mBuffers[0].data.get()), floatSample, start0, len0)) + if (!mPTrack->Get( + samplePtr(mBuffers[0].data.get()), floatSample, start0, len0, + fillZero, mayThrow)) return 0; mBuffers[0].start = start0; mBuffers[0].len = len0; diff --git a/src/WaveTrack.h b/src/WaveTrack.h index 73252c010..712b8d925 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -648,7 +648,8 @@ public: // Returns null on failure // Returned pointer may be invalidated if Get is called again // Do not DELETE[] the pointer - constSamplePtr Get(sampleFormat format, sampleCount start, size_t len); + constSamplePtr Get( + sampleFormat format, sampleCount start, size_t len, bool mayThrow); private: void Free(); diff --git a/src/export/Export.cpp b/src/export/Export.cpp index 40812e807..e92a7cbda 100644 --- a/src/export/Export.cpp +++ b/src/export/Export.cpp @@ -246,6 +246,8 @@ std::unique_ptr ExportPlugin::CreateMixer(const WaveTrackConstArray &inpu { // MB: the stop time should not be warped, this was a bug. return std::make_unique(inputTracks, + // Throw, to stop exporting, if read fails: + true, Mixer::WarpOptions(timeTrack), startTime, stopTime, numOutChannels, outBufferSize, outInterleaved, From 5f6a013a87a2f6c81c2f7a537fb8bc95b552df29 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Wed, 22 Mar 2017 11:33:10 +0000 Subject: [PATCH 45/91] Fix windows build Paul should check this fix. --- src/AudacityException.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudacityException.h b/src/AudacityException.h index 3c8ae685a..a0960fbdc 100644 --- a/src/AudacityException.h +++ b/src/AudacityException.h @@ -39,7 +39,7 @@ protected: // Make this protected to prevent slicing copies AudacityException( AudacityException&& ) {} AudacityException( const AudacityException& ) = default; - AudacityException &operator = (AudacityException &&) {} + AudacityException &operator = (AudacityException &&) { return *this;} AudacityException &operator = ( const AudacityException & ) PROHIBITED; }; From 1dce83006f4650a8de6ffbe943133fc0ae62a536 Mon Sep 17 00:00:00 2001 From: James Crook Date: Wed, 22 Mar 2017 16:42:40 +0000 Subject: [PATCH 46/91] Record on same track is now the default. Record new track is now accessed by SHIFT+R and is so named in the menu and tool tip. --- src/Menus.cpp | 18 ++++++++++-------- src/toolbars/ControlToolBar.cpp | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 956b73b0e..f0c26ba3a 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -784,17 +784,19 @@ void AudacityProject::CreateMenusAndCommands() AudioIONotBusyFlag | CanStopAudioStreamFlag); /* i18n-hint: (verb)*/ c->AddItem(wxT("Record"), _("&Record"), FN(OnRecord), wxT("R")); - c->AddItem(wxT("TimerRecord"), _("&Timer Record..."), FN(OnTimerRecord), wxT("Shift+T")); - -// The RecordBelow function is actually 'record-other', i.e. if normal record record beside, -// it records below, if normal record records below, it records beside. -// TODO: fix the naming, and also check we do 'the right thing' with other options like -// TimerRecord. -#ifdef EXPERIMENTAL_DA - c->AddItem(wxT("RecordBelow"), _("Record Below"), FN(OnRecordBelow), wxT("Shift+R")); + // The RecordBelow function is actually 'record-other', i.e. if normal record records beside, + // it records below, if normal record records below, it records beside. + // TODO: fix the naming, and also check we do 'the right thing' with other options like + // TimerRecord. + // PREFER_NEW_TRACKS is defined if we want the old behaviour of by default adding a new track on + // every new recording. +#ifndef PREFER_NEW_TRACKS + c->AddItem(wxT("RecordBelow"), _("Record New Track"), FN(OnRecordBelow), wxT("Shift+R")); #else c->AddItem(wxT("RecordBelow"), _("Record Beside"), FN(OnRecordBelow), wxT("Shift+R")); #endif + + c->AddItem(wxT("TimerRecord"), _("&Timer Record..."), FN(OnTimerRecord), wxT("Shift+T")); // JKC: I decided to duplicate this between play and record, rather than put it // at the top level. AddItem can now cope with simple duplicated items. c->AddItem(wxT("Pause"), _("&Pause"), FN(OnPause), wxT("P")); diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 5bb0e9133..e9693d37d 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -224,11 +224,11 @@ void ControlToolBar::RegenerateTooltips() break; case ID_RECORD_BUTTON: commands.push_back(wxT("Record")); -#ifndef EXPERIMENTAL_DA +#ifdef PREFER_NEW_TRACKS commands.push_back(_("Append Record")); commands.push_back(wxT("RecordAppend")); #else - commands.push_back(_("Record Below")); + commands.push_back(_("Record New Track")); commands.push_back(wxT("RecordBelow")); #endif break; @@ -874,7 +874,7 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) bool success = false; bool shifted = mRecord->WasShiftDown(); -#ifdef EXPERIMENTAL_DA +#ifndef PREFER_NEW_TRACKS shifted = !shifted; #endif From ebfca79b92a171e6dfe9b23ead4e16edc2842691 Mon Sep 17 00:00:00 2001 From: James Crook Date: Wed, 22 Mar 2017 17:47:23 +0000 Subject: [PATCH 47/91] Update Russian Translation by Alexander Gvaramiya --- locale/ru.po | 1278 +++++++++++++++++++++++++------------------------- 1 file changed, 627 insertions(+), 651 deletions(-) diff --git a/locale/ru.po b/locale/ru.po index 449728f1a..309a110e9 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Audacity\n" "Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n" -"POT-Creation-Date: 2017-03-18 18:41+0000\n" -"PO-Revision-Date: 2015-09-20 17:03+0000\n" +"POT-Creation-Date: 2017-03-20 14:56+0300\n" +"PO-Revision-Date: 2017-03-21 12:44+0300\n" "Last-Translator: Johnny Storm \n" "Language-Team: Russian (http://www.transifex.com/klyok/audacity/language/" "ru/)\n" @@ -26,6 +26,7 @@ msgstr "" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" "%100>=11 && n%100<=14)? 2 : 3);\n" +"X-Generator: Poedit 1.8.12\n" #: lib-src/FileDialog/gtk/FileDialogPrivate.cpp:75 #, c-format @@ -44,17 +45,16 @@ msgstr "Пожалуйста, выберите существующий файл #: src/AutoRecovery.cpp:195 src/Menus.cpp:4294 src/Menus.cpp:4306 #: src/Menus.cpp:7005 src/Menus.cpp:7084 src/Project.cpp:3124 #: src/Project.cpp:5118 src/Project.cpp:5137 src/TimerRecordDialog.cpp:471 -#: src/TimerRecordDialog.cpp:649 src/TrackPanel.cpp:8489 -#: src/WaveTrack.cpp:1316 src/WaveTrack.cpp:1335 src/WaveTrack.cpp:2487 -#: src/effects/Contrast.cpp:56 src/effects/Contrast.cpp:75 -#: src/effects/Contrast.cpp:82 src/effects/Contrast.cpp:96 -#: src/effects/Effect.cpp:2584 src/effects/Generator.cpp:59 -#: src/effects/nyquist/Nyquist.cpp:411 src/export/ExportFFmpeg.cpp:842 -#: src/export/ExportMP2.cpp:229 src/prefs/DirectoriesPrefs.cpp:210 -#: src/prefs/DirectoriesPrefs.cpp:239 src/prefs/KeyConfigPrefs.cpp:509 -#: src/prefs/KeyConfigPrefs.cpp:523 src/prefs/KeyConfigPrefs.cpp:548 -#: src/prefs/KeyConfigPrefs.cpp:1038 src/toolbars/ControlToolBar.cpp:686 -#: src/toolbars/ControlToolBar.cpp:1122 +#: src/TimerRecordDialog.cpp:649 src/TrackPanel.cpp:8489 src/WaveTrack.cpp:1316 +#: src/WaveTrack.cpp:1335 src/WaveTrack.cpp:2487 src/effects/Contrast.cpp:56 +#: src/effects/Contrast.cpp:75 src/effects/Contrast.cpp:82 +#: src/effects/Contrast.cpp:96 src/effects/Effect.cpp:2584 +#: src/effects/Generator.cpp:59 src/effects/nyquist/Nyquist.cpp:411 +#: src/export/ExportFFmpeg.cpp:842 src/export/ExportMP2.cpp:229 +#: src/prefs/DirectoriesPrefs.cpp:210 src/prefs/DirectoriesPrefs.cpp:239 +#: src/prefs/KeyConfigPrefs.cpp:509 src/prefs/KeyConfigPrefs.cpp:523 +#: src/prefs/KeyConfigPrefs.cpp:548 src/prefs/KeyConfigPrefs.cpp:1038 +#: src/toolbars/ControlToolBar.cpp:686 src/toolbars/ControlToolBar.cpp:1122 msgid "Error" msgstr "Ошибка" @@ -125,7 +125,7 @@ msgstr "" #: lib-src/mod-nyq-bench/NyqBench.cpp:763 msgid "&Go to" -msgstr "" +msgstr "&Перейти" #: lib-src/mod-nyq-bench/NyqBench.cpp:769 msgid "Select &Font..." @@ -184,14 +184,12 @@ msgstr "Сценарий" msgid "Output" msgstr "Вывод" -#: lib-src/mod-nyq-bench/NyqBench.cpp:1051 -#: src/effects/nyquist/Nyquist.cpp:2214 +#: lib-src/mod-nyq-bench/NyqBench.cpp:1051 src/effects/nyquist/Nyquist.cpp:2214 msgid "Load Nyquist script" msgstr "Загрузить скрипт Nyquist" #: lib-src/mod-nyq-bench/NyqBench.cpp:1054 -#: lib-src/mod-nyq-bench/NyqBench.cpp:1100 -#: src/effects/nyquist/Nyquist.cpp:2239 +#: lib-src/mod-nyq-bench/NyqBench.cpp:1100 src/effects/nyquist/Nyquist.cpp:2239 msgid "Nyquist scripts (*.ny)|*.ny|Lisp scripts (*.lsp)|*.lsp|All files|*" msgstr "Скрипты Nyquist (*.ny)|*.ny|Скрипты Lisp (*.lsp)|*.lsp|Все файлы|*" @@ -209,8 +207,7 @@ msgstr "Скрипт не сохранен" msgid "Warning" msgstr "Предупреждение" -#: lib-src/mod-nyq-bench/NyqBench.cpp:1097 -#: src/effects/nyquist/Nyquist.cpp:2236 +#: lib-src/mod-nyq-bench/NyqBench.cpp:1097 src/effects/nyquist/Nyquist.cpp:2236 msgid "Save Nyquist script" msgstr "Сохранить скрипт Nyquist" @@ -244,7 +241,7 @@ msgstr "" #: lib-src/mod-nyq-bench/NyqBench.cpp:1420 #: lib-src/mod-nyq-bench/NyqBench.cpp:1488 msgid "Nyquist Effect Workbench" -msgstr "Рабочее место эффектов Nyquist" +msgstr "Рабочая панель эффектов Nyquist" #: lib-src/mod-nyq-bench/NyqBench.cpp:1487 msgid "No matches found" @@ -430,7 +427,7 @@ msgstr "Остановить скрипт" #: src/AboutDialog.cpp:94 msgid "Check Online" -msgstr "" +msgstr "Проверить Online" #: src/AboutDialog.cpp:103 msgid "quality assurance" @@ -438,7 +435,7 @@ msgstr "контроль качества" #: src/AboutDialog.cpp:104 msgid "system administration" -msgstr "" +msgstr "системный администратор" #: src/AboutDialog.cpp:105 src/AboutDialog.cpp:108 src/AboutDialog.cpp:110 #: src/AboutDialog.cpp:112 src/AboutDialog.cpp:118 src/AboutDialog.cpp:120 @@ -458,22 +455,21 @@ msgstr "" #: src/AboutDialog.cpp:169 src/AboutDialog.cpp:170 src/AboutDialog.cpp:171 #: src/AboutDialog.cpp:172 src/AboutDialog.cpp:173 src/AboutDialog.cpp:174 #: src/AboutDialog.cpp:175 src/AboutDialog.cpp:176 -#, fuzzy msgid "developer" -msgstr "Огибающая" +msgstr "разработчик" #: src/AboutDialog.cpp:106 src/AboutDialog.cpp:127 msgid "co-founder and developer" -msgstr "" +msgstr "сооснователь и разработчик" #: src/AboutDialog.cpp:109 src/AboutDialog.cpp:113 src/AboutDialog.cpp:131 #: src/AboutDialog.cpp:132 msgid "documentation and support" -msgstr "" +msgstr "документация и техподдержка" #: src/AboutDialog.cpp:119 msgid "documentation and support, French" -msgstr "" +msgstr "документация и техподдержка на французком" #: src/AboutDialog.cpp:137 msgid "accessibility advisor" @@ -481,21 +477,19 @@ msgstr "" #: src/AboutDialog.cpp:156 msgid "graphic artist" -msgstr "" +msgstr "графический дизайнер" #: src/AboutDialog.cpp:163 msgid "composer" -msgstr "" +msgstr "компоновщик" #: src/AboutDialog.cpp:166 -#, fuzzy msgid "Nyquist plug-ins" -msgstr "Вывод Nyquist: " +msgstr "Плагины Nyquist: " #: src/AboutDialog.cpp:240 -#, fuzzy msgid "incorporating" -msgstr "Ошибка импортирования" +msgstr "" #: src/AboutDialog.cpp:294 msgid "About Audacity" @@ -508,7 +502,6 @@ msgid "OK" msgstr "OK" #: src/AboutDialog.cpp:327 -#, fuzzy msgid "" "Audacity is a free program written by a worldwide team of [[http://www." "audacityteam.org/about/credits|volunteers]]. Audacity is [[http://www." @@ -521,7 +514,6 @@ msgstr "" "\">доступна для Windows, Mac и GNU/Linux (и других Unix-подобных систем)." #: src/AboutDialog.cpp:337 -#, fuzzy msgid "" "If you find a bug or have a suggestion for us, please write, in English, to " "our [[mailto:feedback@audacityteam.org|feedback address]]. For help, view " @@ -541,14 +533,15 @@ msgstr "" #. * For example: "English translation by Dominic Mazzoni." #: src/AboutDialog.cpp:350 src/AboutDialog.cpp:352 msgid "translator_credits" -msgstr "Русская локализация — Александр Прокудин" +msgstr "" +"Александр Прокудин (ru)\n" +"Александр Гварамия (ru)" #: src/AboutDialog.cpp:359 -#, fuzzy msgid "" "Free, open source, cross-platform software for recording and editing sounds." msgstr "" -"бесплатное, открытое, кроссплатформенное програмное обеспечение для записи и " +"Бесплатное, открытое, кроссплатформенное програмное обеспечение для записи и " "редактирования звука
" #: src/AboutDialog.cpp:363 @@ -556,27 +549,24 @@ msgid "Credits" msgstr "Об авторах" #: src/AboutDialog.cpp:365 -#, fuzzy msgid "Audacity Team Members" -msgstr "Разработчики Audacity" +msgstr "Команда разработчиков Audacity:" #: src/AboutDialog.cpp:368 msgid "Emeritus:" -msgstr "" +msgstr "Почетные члены:" #: src/AboutDialog.cpp:369 msgid "Distinguished Audacity Team members, not currently active" -msgstr "" +msgstr "Выдающиеся члены команды разработчиков, не активные в настоящее время" #: src/AboutDialog.cpp:372 -#, fuzzy msgid "Contributors" msgstr "Прочие участники проекта" #: src/AboutDialog.cpp:375 -#, fuzzy msgid "Translators" -msgstr "Русская локализация — Александр Прокудин" +msgstr "Переводчики" #: src/AboutDialog.cpp:379 src/prefs/LibraryPrefs.cpp:49 msgid "Libraries" @@ -587,14 +577,12 @@ msgid "Special thanks:" msgstr "Особые благодарности:" #: src/AboutDialog.cpp:386 -#, fuzzy msgid "Audacity® software is copyright" msgstr "" "Программное обеспечение Audacity® является объектом авторского " "права." #: src/AboutDialog.cpp:388 -#, fuzzy msgid "" "The name Audacity® is a registered trademark of " "Dominic Mazzoni." @@ -607,6 +595,7 @@ msgid "" "Audacity website: [[http://www.audacityteam.org/|http://www.audacityteam." "org/]]" msgstr "" +"Сайт Audacity: [[http://www.audacityteam.org/|http://www.audacityteam.org/]]" #. i18n-hint: Information about when audacity was compiled #: src/AboutDialog.cpp:446 src/AboutDialog.cpp:459 src/AboutDialog.cpp:631 @@ -694,11 +683,11 @@ msgstr "Поддержка встроенного микшера звуково #: src/AboutDialog.cpp:612 src/AboutDialog.cpp:615 msgid "Pitch and Tempo Change support" -msgstr "Полная поддержка смены темпа и высоты тона" +msgstr "Поддержка смены темпа и высоты тона" #: src/AboutDialog.cpp:620 src/AboutDialog.cpp:623 msgid "Extreme Pitch and Tempo Change support" -msgstr "" +msgstr "Полная поддержка смены темпа и высоты тона" #: src/AboutDialog.cpp:635 msgid "Program build date: " @@ -773,7 +762,7 @@ msgstr "Файлы отсутствуют" #: src/AudacityApp.cpp:1047 #, c-format msgid "Language \"%s\" is unknown" -msgstr "" +msgstr "Язык \"%s\" не определен" #: src/AudacityApp.cpp:1170 msgid "Report generated to:" @@ -830,7 +819,6 @@ msgid "&File" msgstr "&Файл" #: src/AudacityApp.cpp:1773 -#, fuzzy msgid "" "Audacity could not find a safe place to store temporary files.\n" "Audacity needs a place where automatic cleanup programs won't delete the " @@ -956,8 +944,8 @@ msgstr "Журнал Audacity" msgid "&Save..." msgstr "&Сохранить..." -#: src/AudacityLogger.cpp:199 src/Tags.cpp:883 -#: src/prefs/KeyConfigPrefs.cpp:273 src/prefs/KeyConfigPrefs.cpp:781 +#: src/AudacityLogger.cpp:199 src/Tags.cpp:883 src/prefs/KeyConfigPrefs.cpp:273 +#: src/prefs/KeyConfigPrefs.cpp:781 msgid "Cl&ear" msgstr "О&чистить" @@ -1138,6 +1126,9 @@ msgid "" "\n" "Choosing \"Yes\" discards all projects immediately." msgstr "" +"Вы уверены, что хотите сбросить все проекты?\n" +"\n" +"Выбор \"Да\" немедленно сбросит все проекты." #: src/AutoRecovery.cpp:139 msgid "Confirm Discard Projects" @@ -1149,7 +1140,6 @@ msgid "Could not enumerate files in auto save directory." msgstr "Невозможно пронумеровать файлы в папке автоматического сохранения" #: src/AutoRecovery.cpp:760 -#, fuzzy msgid "Error Decoding File" msgstr "Ошибка декодирования файла" @@ -1503,9 +1493,8 @@ msgstr "" "в диалоге параметров программы." #: src/DirManager.cpp:424 -#, fuzzy msgid "Cleaning project temporary files" -msgstr "Выполняется очистка временных файлов" +msgstr "Очистка временных файлов проекта" #: src/DirManager.cpp:437 msgid "Cleaning up temporary files" @@ -1540,7 +1529,7 @@ msgstr "" #: src/DirManager.cpp:1371 #, c-format msgid "%s-old%d" -msgstr "%s-old%d" +msgstr "%s-старый%d" #: src/DirManager.cpp:1381 msgid "Unable to open/create test file." @@ -1566,7 +1555,7 @@ msgstr "Невозможно переименовать '%s' в '%s'." #: src/DirManager.cpp:1484 #, c-format msgid "Changed block %s to new alias name\n" -msgstr "" +msgstr "Блок %s переименован\n" #. i18n-hint: The audacity project file is XML and has 'tags' in it, #. rather like html tags some stuff. @@ -1575,7 +1564,7 @@ msgstr "" #. "Found problems with when checking project file." #: src/DirManager.cpp:1536 msgid "Project check read faulty Sequence tags." -msgstr "" +msgstr "Ошибка тегов в файлах проекта" #: src/DirManager.cpp:1538 src/DirManager.cpp:1592 msgid "Close project immediately with no changes" @@ -1587,6 +1576,10 @@ msgid "" "save the project in its current state, unless you \"Close project immediately" "\" on further error alerts." msgstr "" +"Продолжите с исправлениями, отмеченные в журнале, и проверьте на наличие " +"дополнительных ошибок. Это сохранит проект в его текущем состоянии, даже " +"если вы выбирете «Немедленно закрыть проект» на дальнейших предупреждениях " +"об ошибках." #: src/DirManager.cpp:1542 msgid "Warning - Problems Reading Sequence Tags" @@ -1649,7 +1642,7 @@ msgstr "" #: src/DirManager.cpp:1669 msgid "Regenerate alias summary files (safe and recommended)" -msgstr "Регенерировать сводные файлы псевдонимов (безопасно и рекомендуемо)" +msgstr "Восстановить сводные файлы псевдонимов (безопасно и рекомендуемо)" #: src/DirManager.cpp:1670 msgid "Fill in silence for missing display data (this session only)" @@ -1665,7 +1658,7 @@ msgstr "Внимание - Отсутствуют сводные файл(ы) п #: src/DirManager.cpp:1711 msgid " Project check regenerated missing alias summary file(s)." -msgstr "" +msgstr " В результате проверки проекта были восстановлены сводные файлы." #: src/DirManager.cpp:1729 #, c-format @@ -1696,6 +1689,8 @@ msgstr "Внимание, не найдена часть данных проек msgid "" " Project check replaced missing audio data block file(s) with silence." msgstr "" +" В результате проверки проекта потерянные блоки файлов были заполнены " +"тишиной." #: src/DirManager.cpp:1800 msgid "" @@ -1713,6 +1708,10 @@ msgid "" "unused by this project, but might belong to other projects. \n" "They are doing no harm and are small." msgstr "" +"В резултате проверки папки проекта \"%s\" \n" +"были обнаружены %d потерянных файлов. Эти файлы\n" +"не исползуются в данном проекте. \n" +"Они маленькие и не опасные." #: src/DirManager.cpp:1815 msgid "Continue without deleting; ignore the extra files this session" @@ -1724,7 +1723,7 @@ msgstr "Удаление потерянных файлов (безвозврат #: src/DirManager.cpp:1820 msgid "Warning - Orphan Block File(s)" -msgstr "" +msgstr "Предупреждение - Потерянные блоки файла(ов)" #: src/DirManager.cpp:1843 msgid "Cleaning up unused directories in project data" @@ -1734,6 +1733,8 @@ msgstr "Очистка неиспользуемых каталогов в дан msgid "" "Project check found file inconsistencies inspecting the loaded project data." msgstr "" +"Проверка проекта обнаружила несоответствия файлов, проверяя загруженные " +"данные проекта." #: src/DirManager.cpp:1862 msgid "" @@ -1769,7 +1770,7 @@ msgstr "Не найден файл блока данных: «%s»" #: src/DirManager.cpp:1999 #, c-format msgid "Orphan block file: '%s'" -msgstr "" +msgstr "Потерянный блок файла: '%s'" #: src/DirManager.cpp:2059 msgid "Caching audio" @@ -1994,7 +1995,7 @@ msgstr "&Экспортировать..." #: src/FreqWindow.cpp:437 msgid "&Replot..." -msgstr "" +msgstr "&Перерисовать..." #: src/FreqWindow.cpp:447 msgid "&Function:" @@ -2151,13 +2152,15 @@ msgstr "" msgid "" "

The version of Audacity you are using is an Alpha test version." -msgstr "" +msgstr "

Вы исползуете тестовую Альфа версию." #: src/HelpText.cpp:201 msgid "" "We strongly recommend that you use our latest stable released version, which " "has full documentation and support.

" msgstr "" +"Мы настоятельно рекомендуем использовать последнюю стабильную версию, " +"содержащую полную документацию и техподдержку.

" #: src/HelpText.cpp:202 msgid "" @@ -2167,7 +2170,7 @@ msgstr "" #: src/HelpText.cpp:205 msgid "How to get help" -msgstr "" +msgstr "Как получить помощь" #: src/HelpText.cpp:206 msgid "These are our support methods:" @@ -2247,9 +2250,8 @@ msgid "" msgstr "" #: src/HistoryWindow.cpp:59 -#, fuzzy msgid "History" -msgstr "&Журнал событий..." +msgstr "Журнал событий..." #: src/HistoryWindow.cpp:81 msgid "&Manage History" @@ -2282,14 +2284,12 @@ msgid "&Discard" msgstr "От&казаться" #: src/HistoryWindow.cpp:119 -#, fuzzy msgid "Clipboard space used" -msgstr "&Общее количество используемого пространства" +msgstr "&Используемое пространство буфером обмена" #: src/HistoryWindow.cpp:121 -#, fuzzy msgid "Discard" -msgstr "От&казаться" +msgstr "Отказаться" #: src/HistoryWindow.cpp:130 src/export/ExportCL.cpp:514 msgid "&OK" @@ -2332,12 +2332,12 @@ msgstr "Укажите новое наименование файла:" #. i18n-hint: An opening parenthesis, in some languages a right parenthesis #: src/Internat.cpp:265 msgid "(" -msgstr "" +msgstr "(" #. i18n-hint: A closing parenthesis, in some languages a left parenthesis #: src/Internat.cpp:267 msgid ")" -msgstr "" +msgstr ")" #: src/LabelDialog.cpp:102 msgid "Edit Labels" @@ -2383,15 +2383,13 @@ msgstr "Время завершения" #. i18n-hint: (noun) of a label #: src/LabelDialog.cpp:167 -#, fuzzy msgid "Low Frequency" -msgstr "Нижняя частота:" +msgstr "Нижняя частота" #. i18n-hint: (noun) of a label #: src/LabelDialog.cpp:169 -#, fuzzy msgid "High Frequency" -msgstr "Верхняя частота:" +msgstr "Верхняя частота" #: src/LabelDialog.cpp:184 msgid "New..." @@ -2458,9 +2456,8 @@ msgid "&Delete Label" msgstr "&Удалить метку" #: src/LabelTrack.cpp:2038 -#, fuzzy msgid "&Edit..." -msgstr "&Изменить" +msgstr "&Редактировать" #: src/LabelTrack.cpp:2074 src/LabelTrack.cpp:2089 src/TrackPanel.cpp:5970 #: src/TrackPanel.cpp:6014 src/TrackPanel.cpp:6490 @@ -2498,9 +2495,8 @@ msgstr "" "(%s)." #: src/Legacy.cpp:263 -#, fuzzy msgid "Error Converting Legacy Project File" -msgstr "Ошибка при сохранении проекта" +msgstr "" #: src/Legacy.cpp:304 #, c-format @@ -2531,10 +2527,9 @@ msgstr "&Сохранить проект" #: src/Menus.cpp:326 msgid "Save Project &As..." -msgstr "Сохранить проект &как..." +msgstr "Сохранить проект как..." #: src/Menus.cpp:328 -#, fuzzy msgid "Sa&ve Compressed Copy of Project..." msgstr "Сохранить сжатую копию проекта..." @@ -2543,9 +2538,8 @@ msgid "Chec&k Dependencies..." msgstr "П&роверить зависимости..." #: src/Menus.cpp:335 -#, fuzzy msgid "Edit Me&tadata Tags..." -msgstr "Свойства меток метаданных" +msgstr "Редактировать тэги..." #: src/Menus.cpp:341 src/import/ImportRaw.cpp:455 msgid "&Import" @@ -2557,7 +2551,7 @@ msgstr "&Звуковой файл..." #: src/Menus.cpp:344 msgid "&Labels..." -msgstr "От&метки..." +msgstr "&Метки..." #: src/Menus.cpp:346 msgid "&MIDI..." @@ -2577,16 +2571,15 @@ msgstr "Экспо&рт выделенного аудио..." #: src/Menus.cpp:366 msgid "Export &Labels..." -msgstr "Экспортировать &отметки..." +msgstr "Экспортировать &метки..." #: src/Menus.cpp:370 msgid "Export &Multiple..." msgstr "Экспортировать в &несколько файлов..." #: src/Menus.cpp:374 -#, fuzzy msgid "Export MI&DI..." -msgstr "Экспортировать MIDI..." +msgstr "Экспорт MIDI..." #: src/Menus.cpp:380 msgid "Appl&y Chain..." @@ -2633,7 +2626,7 @@ msgstr "С&оздать дубликат" #: src/Menus.cpp:454 msgid "R&emove Special" -msgstr "" +msgstr "Специальное у&даление" #. i18n-hint: (verb) Do a special kind of cut #: src/Menus.cpp:456 @@ -2657,11 +2650,11 @@ msgstr "Обреза&ть аудио" #: src/Menus.cpp:474 msgid "Paste Te&xt to New Label" -msgstr "Вставить &текст в новую отметку" +msgstr "Вставить текст из буфера в новую метку" #: src/Menus.cpp:482 msgid "Clip B&oundaries" -msgstr "" +msgstr "Фрагменты" #. i18n-hint: (verb) It's an item on a menu. #: src/Menus.cpp:484 @@ -2683,7 +2676,7 @@ msgstr "Раз&делить по тишине" #: src/Menus.cpp:500 msgid "La&beled Audio" -msgstr "По&меченное аудио" +msgstr "Области с метками" #. i18n-hint: (verb) #: src/Menus.cpp:505 @@ -2761,7 +2754,7 @@ msgstr "От &курсора до конца дорожки" #: src/Menus.cpp:561 msgid "Cursor to Stored &Cursor Position" -msgstr "" +msgstr "Переместить курсор в сохраненную позицию" #: src/Menus.cpp:567 msgid "In All &Tracks" @@ -2797,15 +2790,15 @@ msgstr "к &концу дорожки" #: src/Menus.cpp:600 msgid "Store Re&gion" -msgstr "" +msgstr "Сохранить область" #: src/Menus.cpp:603 msgid "Retrieve Regio&n" -msgstr "" +msgstr "Восстановить сохраненную область" #: src/Menus.cpp:606 msgid "Store Cursor Pos&ition" -msgstr "" +msgstr "Сохранить позицию курсора" #: src/Menus.cpp:614 msgid "Pla&y Region" @@ -2833,7 +2826,7 @@ msgstr "У&величить масштаб" #: src/Menus.cpp:655 msgid "Zoom &Normal" -msgstr "О&бычный масштаб" +msgstr "Сбросить масштаб" #: src/Menus.cpp:656 msgid "Zoom &Out" @@ -2841,15 +2834,15 @@ msgstr "У&меньшить масштаб" #: src/Menus.cpp:659 msgid "&Zoom to Selection" -msgstr "Масштабировать &выделенный фрагмент" +msgstr "Масштабировать по выделению" #: src/Menus.cpp:662 msgid "&Fit in Window" -msgstr "&По размеру окна" +msgstr "Уместить проект в окно" #: src/Menus.cpp:663 msgid "Fit &Vertically" -msgstr "Подогнать по &вертикали" +msgstr "Уместить по вертикали" #: src/Menus.cpp:666 msgid "Go to Selection Sta&rt" @@ -2861,16 +2854,15 @@ msgstr "К концу выделения" #: src/Menus.cpp:670 msgid "&Collapse All Tracks" -msgstr "&Свернуть все дорожки" +msgstr "Свернуть все дорожки" #: src/Menus.cpp:671 -#, fuzzy msgid "E&xpand Collapsed Tracks" -msgstr "&Развернуть все дорожки" +msgstr "Развернуть все дорожки" #: src/Menus.cpp:674 msgid "&Show Clipping" -msgstr "&Показывать перегрузку" +msgstr "Показать усечение импульсов (перегрузка)" #. i18n-hint: Clicking this menu item shows the various editing steps that have been taken. #: src/Menus.cpp:702 @@ -2901,19 +2893,18 @@ msgstr "Панель &редактирования" #. i18n-hint: Clicking this menu item shows the toolbar which has sound level meters #: src/Menus.cpp:720 -#, fuzzy msgid "Co&mbined Meter Toolbar" -msgstr "Комбинированный индикатор" +msgstr "Комбинированный индикатор уровня" #. i18n-hint: Clicking this menu item shows the toolbar with the recording level meters #: src/Menus.cpp:722 msgid "&Recording Meter Toolbar" -msgstr "" +msgstr "Панель индикатора уровня записи" #. i18n-hint: Clicking this menu item shows the toolbar with the playback level meter #: src/Menus.cpp:724 msgid "&Playback Meter Toolbar" -msgstr "" +msgstr "Панель индикатора уровня воспроизведения" #. i18n-hint: Clicking this menu item shows the toolbar with the mixer #: src/Menus.cpp:726 @@ -2927,9 +2918,8 @@ msgstr "Панель &выделения" #. i18n-hint: Clicking this menu item shows the toolbar for selecting a frequency range of audio #: src/Menus.cpp:731 -#, fuzzy msgid "Spe&ctral Selection Toolbar" -msgstr "Панель &выделения" +msgstr "Панель выделения спектра" #. i18n-hint: Clicking this menu item shows a toolbar that has some tools in it #: src/Menus.cpp:734 @@ -2938,26 +2928,23 @@ msgstr "Панель и&нструментов" #. i18n-hint: Clicking this menu item shows the toolbar for transcription (currently just vary play speed) #: src/Menus.cpp:736 -#, fuzzy msgid "Tra&nscription Toolbar" -msgstr "Панель &транскрипции" +msgstr "Панель &скорости воспроизведения" #. i18n-hint: Clicking this menu item shows the toolbar with the big buttons on it (play record etc) #: src/Menus.cpp:738 msgid "&Transport Toolbar" -msgstr "Панель &транспорта" +msgstr "Панель &кнопок управления" #. i18n-hint: Clicking this menu item shows the toolbar that enables Scrub or Seek playback and Scrub Ruler #: src/Menus.cpp:740 -#, fuzzy msgid "Scru&b Toolbar" -msgstr "&Панели инструментов" +msgstr "&Панель Scrub-инструментов" #. i18n-hint: (verb) #: src/Menus.cpp:745 -#, fuzzy msgid "Reset Toolb&ars" -msgstr "В&осстановить панели инструментов" +msgstr "Восстановить панели инструментов" #. i18n-hint: 'Transport' is the name given to the set of controls that #. play, record, pause etc. @@ -2968,19 +2955,19 @@ msgstr "&Управление" #. i18n-hint: (verb) Start or Stop audio playback #: src/Menus.cpp:761 msgid "Pl&ay/Stop" -msgstr "В&оспроизвести/Остановить" +msgstr "Старт/Стоп" #: src/Menus.cpp:762 msgid "Play/Stop and &Set Cursor" -msgstr "Воспроизвести/Остановить и &установить курсор" +msgstr "Старт/Стоп и установить курсор" #: src/Menus.cpp:763 msgid "&Loop Play" -msgstr "В&оспроизвести с повторением" +msgstr "Циклическое в&оспроизведение" #: src/Menus.cpp:770 msgid "&Pause" -msgstr "&Приостановить" +msgstr "&Пауза" #: src/Menus.cpp:771 msgid "S&kip to Start" @@ -2993,11 +2980,11 @@ msgstr "Перейти к концу дорожки" #. i18n-hint: (verb) #: src/Menus.cpp:782 msgid "&Record" -msgstr "&Записать" +msgstr "&Запись" #: src/Menus.cpp:783 msgid "&Timer Record..." -msgstr "&Таймер записи..." +msgstr "Запись по таймеру..." #: src/Menus.cpp:784 msgid "Appen&d Record" @@ -3005,31 +2992,31 @@ msgstr "До&писать" #: src/Menus.cpp:788 msgid "Pinned Recording/Playback &Head" -msgstr "" +msgstr "Закрепленный маркер записи/воспроизведения" #: src/Menus.cpp:793 msgid "&Overdub (on/off)" -msgstr "&Наложение (вкл./выкл.)" +msgstr "Наложение записи (вкл./выкл.)" #: src/Menus.cpp:794 msgid "So&ftware Playthrough (on/off)" -msgstr "" +msgstr "Программное сквозное воспроизведение (вкл/откл)" #: src/Menus.cpp:797 msgid "Sound A&ctivated Recording (on/off)" -msgstr "" +msgstr "Активируемая з&вуком запись (вкл/выкл)" #: src/Menus.cpp:798 msgid "Sound Activation Le&vel..." -msgstr "" +msgstr "Уровень громкости для акти&вации..." #: src/Menus.cpp:801 msgid "A&utomated Recording Level Adjustment (on/off)" -msgstr "" +msgstr "А&втоматическая коррекция уровня записи (вкл/выкл)" #: src/Menus.cpp:803 msgid "R&escan Audio Devices" -msgstr "П&овторно найти звуковые устройства" +msgstr "Пересканировать звуковые устройства" #: src/Menus.cpp:811 msgid "&Tracks" @@ -3041,11 +3028,11 @@ msgstr "&Создать новую" #: src/Menus.cpp:818 msgid "&Mono Track" -msgstr "&Монофоническую дорожку" +msgstr "&Моно дорожку" #: src/Menus.cpp:819 msgid "&Stereo Track" -msgstr "&Стереофоническую дорожку" +msgstr "&Стерео дорожку" #: src/Menus.cpp:820 msgid "&Label Track" @@ -3057,7 +3044,7 @@ msgstr "Дорожку &времени" #: src/Menus.cpp:835 msgid "Stereo Trac&k to Mono" -msgstr "Преобразовать стереозвук в &монофонический" +msgstr "Преобразовать стереозвук в моно" #: src/Menus.cpp:839 msgid "Mi&x and Render" @@ -3065,7 +3052,7 @@ msgstr "&Свести в последнюю дорожку" #: src/Menus.cpp:842 msgid "Mix and Render to Ne&w Track" -msgstr "Свести и записать в новую дорожку" +msgstr "Свести в новую дорожку" #: src/Menus.cpp:845 msgid "&Resample..." @@ -3089,27 +3076,27 @@ msgstr "Выровнять конец к концу" #: src/Menus.cpp:864 msgid "Align &Together" -msgstr "" +msgstr "Выровнять &вместе" #: src/Menus.cpp:867 msgid "Start to &Zero" -msgstr "" +msgstr "Поместить начало в ноль" #: src/Menus.cpp:868 msgid "Start to &Cursor/Selection Start" -msgstr "" +msgstr "Поместить начало в позицию курсора" #: src/Menus.cpp:869 msgid "Start to Selection &End" -msgstr "" +msgstr "Поместить начало в конец выделенной области" #: src/Menus.cpp:870 msgid "End to Cu&rsor/Selection Start" -msgstr "" +msgstr "Поместить конец в позицию курсора" #: src/Menus.cpp:871 msgid "End to Selection En&d" -msgstr "" +msgstr "Поместить конец дорожки в конец выделенной области" #: src/Menus.cpp:879 msgid "&Align Tracks" @@ -3117,34 +3104,31 @@ msgstr "В&ыровнять дорожки" #: src/Menus.cpp:890 msgid "Move Sele&ction when Aligning" -msgstr "" +msgstr "Перемещать выделение при выравнивании" #: src/Menus.cpp:904 src/Menus.cpp:6286 msgid "Synchronize MIDI with Audio" msgstr "Синхронизировать MIDI со звуком" #: src/Menus.cpp:912 -#, fuzzy msgid "Sync-&Lock Tracks (on/off)" -msgstr "Си&нхронизировать дорожки" +msgstr "Синхронизация дорожек (вкл/откл)" #: src/Menus.cpp:918 -#, fuzzy msgid "Add Label at &Selection" -msgstr "До&бавить отметку к выделению" +msgstr "Добавить метку к выделению" #: src/Menus.cpp:920 -#, fuzzy msgid "Add Label at &Playback Position" -msgstr "Доб&авить отметку в позицию воспроизведения" +msgstr "Добавить метку в позицию воспроизведения" #: src/Menus.cpp:929 msgid "&Edit Labels..." -msgstr "&Свойства отметок..." +msgstr "Редактировать метки..." #: src/Menus.cpp:931 msgid "&Type to Create a Label (on/off)" -msgstr "" +msgstr "Создавать метку при наборе с клавиатуры (вкл/откл)" #: src/Menus.cpp:938 msgid "S&ort Tracks" @@ -3194,9 +3178,8 @@ msgid "Plot Spectrum..." msgstr "Построить график спектра..." #: src/Menus.cpp:1042 -#, fuzzy msgid "&Window" -msgstr "окно" +msgstr "Окно" #. i18n-hint: Standard Macintosh Window menu item: Make (the current #. * window) shrink to an icon on the dock @@ -3207,9 +3190,8 @@ msgstr "" #. i18n-hint: Standard Macintosh Window menu item: Make (the current #. * window) full sized #: src/Menus.cpp:1049 -#, fuzzy msgid "&Zoom" -msgstr "Масштаб" +msgstr "" #: src/Menus.cpp:1055 msgid "&Bring All to Front" @@ -3572,7 +3554,7 @@ msgstr "Воспроизвести на скорости" #: src/Menus.cpp:1259 msgid "Loop Play at speed" -msgstr "Воспроизвести с повторением на скорости" +msgstr "Циклическое воспроизведение на скорости" #: src/Menus.cpp:1260 msgid "Play Cut Preview at speed" @@ -3591,19 +3573,16 @@ msgid "Decrease playback speed" msgstr "Уменьшить скорость воспроизведения" #: src/Menus.cpp:1265 -#, fuzzy msgid "Move to Next Label" -msgstr "Переместить активность на следующую дорожку и выделить" +msgstr "Переместить на следующую метку" #: src/Menus.cpp:1267 -#, fuzzy msgid "Move to Previous Label" -msgstr "Переместить активность на предыдущую дорожку и выделить" +msgstr "Переместить на предыдущую метку" #: src/Menus.cpp:1272 -#, fuzzy msgid "Minimize all projects" -msgstr "&Нормализовывать все дорожки в проекте" +msgstr "Свернуть все проекты" #: src/Menus.cpp:1396 src/Menus.cpp:1404 msgid "Unknown" @@ -3651,19 +3630,16 @@ msgid "Sort by Name" msgstr "Упорядочить по наименованию" #: src/Menus.cpp:2709 -#, fuzzy msgid "no label track" -msgstr "Дорожка отметок" +msgstr "нет дорожки меток" #: src/Menus.cpp:2716 -#, fuzzy msgid "no label track at or below focused track" -msgstr "Панорамирование влево для активной дорожки" +msgstr "нет дорожки меток около активной дорожки" #: src/Menus.cpp:2749 -#, fuzzy msgid "no labels in label track" -msgstr "Создан новая дорожка для отметок" +msgstr "нет меток в дорожке меток" #: src/Menus.cpp:2864 msgid "Set Left Selection Boundary" @@ -3780,7 +3756,7 @@ msgstr "Вставить текст в новую отметку" #: src/Menus.cpp:4670 #, c-format msgid "Trim selected audio tracks from %.2f seconds to %.2f seconds" -msgstr "" +msgstr "Обрезать выделенные дорожки с %.2f секунды до %.2f секунды" #: src/Menus.cpp:4672 src/toolbars/EditToolBar.cpp:209 msgid "Trim Audio" @@ -3798,7 +3774,7 @@ msgstr "Удалить с разделением" #: src/Menus.cpp:4728 #, c-format msgid "Detached %.2f seconds at t=%.2f" -msgstr "" +msgstr "Откреплено %.2f сек. начиная с t=%.2f" #: src/Menus.cpp:4731 msgid "Detach" @@ -3833,12 +3809,12 @@ msgstr "Создать дубликат" #. i18n-hint: (verb) past tense. Audacity has just cut the labeled audio regions. #: src/Menus.cpp:4828 msgid "Cut labeled audio regions to clipboard" -msgstr "" +msgstr "Вырезать отмеченные области аудио в буфер обмена" #. i18n-hint: (verb) #: src/Menus.cpp:4830 msgid "Cut Labeled Audio" -msgstr "" +msgstr "Вырезать отмеченные области аудио" #. i18n-hint: (verb) Audacity has just split cut the labeled audio regions #: src/Menus.cpp:4846 @@ -3848,7 +3824,7 @@ msgstr "" #. i18n-hint: (verb) Do a special kind of cut on the labels #: src/Menus.cpp:4848 msgid "Split Cut Labeled Audio" -msgstr "" +msgstr "Разделить вырезанием по меткам" #: src/Menus.cpp:4862 msgid "Copied labeled audio regions to clipboard" @@ -3857,17 +3833,17 @@ msgstr "" #. i18n-hint: (verb) #: src/Menus.cpp:4864 msgid "Copy Labeled Audio" -msgstr "" +msgstr "Копировать промаркированные области" #. i18n-hint: (verb) Audacity has just deleted the labeled audio regions #: src/Menus.cpp:4880 msgid "Deleted labeled audio regions" -msgstr "" +msgstr "Удаленные отмеченные области аудио" #. i18n-hint: (verb) #: src/Menus.cpp:4882 msgid "Delete Labeled Audio" -msgstr "" +msgstr "Удалить отмеченные области аудио" #. i18n-hint: (verb) Audacity has just done a special kind of DELETE on the labeled audio regions #: src/Menus.cpp:4896 @@ -3877,7 +3853,7 @@ msgstr "" #. i18n-hint: (verb) Do a special kind of DELETE on labeled audio regions #: src/Menus.cpp:4898 msgid "Split Delete Labeled Audio" -msgstr "" +msgstr "Разделить удаоением отмеченное" #. i18n-hint: (verb) #: src/Menus.cpp:4912 @@ -3887,7 +3863,7 @@ msgstr "" #. i18n-hint: (verb) #: src/Menus.cpp:4914 msgid "Silence Labeled Audio" -msgstr "" +msgstr "Заполнить тишиной отмеченное" #. i18n-hint: (verb) past tense. Audacity has just split the labeled audio (a point or a region) #: src/Menus.cpp:4925 @@ -3897,7 +3873,7 @@ msgstr "" #. i18n-hint: (verb) #: src/Menus.cpp:4927 msgid "Split Labeled Audio" -msgstr "" +msgstr "Разделить отмеченное" #. i18n-hint: (verb) Audacity has just joined the labeled audio (points or regions) #: src/Menus.cpp:4941 @@ -3907,19 +3883,19 @@ msgstr "" #. i18n-hint: (verb) #: src/Menus.cpp:4943 msgid "Join Labeled Audio" -msgstr "" +msgstr "Объединить отмеченное" #. i18n-hint: (verb) Audacity has just detached the labeled audio regions. #. This message appears in history and tells you about something #. Audacity has done. #: src/Menus.cpp:4959 msgid "Detached labeled audio regions" -msgstr "" +msgstr "Отделить отмеченные области" #. i18n-hint: (verb) #: src/Menus.cpp:4961 msgid "Detach Labeled Audio" -msgstr "" +msgstr "Отделить отмеченное" #: src/Menus.cpp:4983 src/TrackPanel.cpp:8048 msgid "Split" @@ -3959,6 +3935,8 @@ msgid "" "MIDI and Allegro files (*.mid;*.midi;*.gro)|*.mid;*.midi;*.gro|MIDI files (*." "mid;*.midi)|*.mid;*.midi|Allegro files (*.gro)|*.gro|All files|*" msgstr "" +"Файлы MIDI и Allegro (*.mid;*.midi;*.gro)|*.mid;*.midi;*.gro|Файлы MIDI (*." +"mid;*.midi)|*.mid;*.midi|Файлы Allegro (*.gro)|*.gro|Все файлы|*" #: src/Menus.cpp:5768 #, c-format @@ -3980,12 +3958,11 @@ msgstr "Все файлы|*" #: src/Menus.cpp:5810 src/export/Export.cpp:354 src/export/Export.cpp:977 #: src/export/ExportMultiple.cpp:734 src/export/ExportMultiple.cpp:876 msgid "Edit Metadata Tags" -msgstr "Свойства меток метаданных" +msgstr "Изменить тэги" #: src/Menus.cpp:5810 -#, fuzzy msgid "Metadata Tags" -msgstr "Свойства меток метаданных" +msgstr "Теги метаданных" #: src/Menus.cpp:5884 #, c-format @@ -4001,12 +3978,12 @@ msgstr "Рендер" #: src/Menus.cpp:5892 #, c-format msgid "Mixed and rendered %d tracks into one new stereo track" -msgstr "" +msgstr "Сведенные %d дорожек в одну стерео дорожку" #: src/Menus.cpp:5895 #, c-format msgid "Mixed and rendered %d tracks into one new mono track" -msgstr "" +msgstr "Сведенные %d дорожек в одну моно дорожку" #: src/Menus.cpp:5897 src/Mix.cpp:171 msgid "Mix and Render" @@ -4026,7 +4003,7 @@ msgstr "начать с конца выделения" #: src/Menus.cpp:6080 msgid "end to cursor/selection start" -msgstr "" +msgstr "поместить конец в позицию курсора" #: src/Menus.cpp:6081 src/Menus.cpp:6086 src/effects/Contrast.cpp:190 #: src/effects/ToneGen.cpp:328 src/toolbars/SelectionBar.cpp:162 @@ -4036,15 +4013,15 @@ msgstr "Конец" #: src/Menus.cpp:6085 msgid "end to selection end" -msgstr "" +msgstr "поместить конец в конец выделенной области" #: src/Menus.cpp:6091 msgid "end to end" -msgstr "" +msgstr "выровнять конец к концу" #: src/Menus.cpp:6092 msgid "End to End" -msgstr "" +msgstr "Выровнять конец к концу" #: src/Menus.cpp:6096 msgid "together" @@ -4131,11 +4108,14 @@ msgid "" "\n" "Please close any additional projects and try again." msgstr "" +"Запись по таймеру не может использоваться более чем с одним открытым " +"проектом.\n" +"\n" +"Пожалуйста, закройте все остальные проекты и попробуйте снова." #: src/Menus.cpp:6547 src/Menus.cpp:6558 src/TimerRecordDialog.cpp:658 -#, fuzzy msgid "Timer Recording" -msgstr "Ползунок записи" +msgstr "Запись по таймеру" #: src/Menus.cpp:6557 msgid "" @@ -4143,6 +4123,10 @@ msgid "" "\n" "Please save or close this project and try again." msgstr "" +"Запись по таймеру не может использоваться пока у вас есть не сохраненные " +"изменения.\n" +"\n" +"Пожалуйста, сохраните или закройте этот проект и попробуйте снова." #: src/Menus.cpp:6731 msgid "Edited labels" @@ -4244,7 +4228,7 @@ msgstr "Панорама" #: src/MixerBoard.cpp:281 src/MixerBoard.cpp:331 src/MixerBoard.cpp:1399 #: src/TrackPanel.cpp:9304 msgid "Mute" -msgstr "Отключить звук" +msgstr "Тихо" #. i18n-hint: This is on a button that will silence this track. #: src/MixerBoard.cpp:295 src/MixerBoard.cpp:332 src/MixerBoard.cpp:1449 @@ -4286,7 +4270,7 @@ msgstr "Модуль не поддерживается" #, c-format msgid "" "The module %s does not provide a version string. It will not be loaded." -msgstr "" +msgstr "Модуль %s не предоставляет строку версии. Он не будет загружен." #: src/ModuleManager.cpp:128 #, c-format @@ -4351,7 +4335,7 @@ msgstr "Менеджер плагинов: Эффекты, Генераторы #: src/PluginManager.cpp:529 msgid "Select effects, click the Enable or Disable button, then click OK." -msgstr "" +msgstr "Выбирите эффект, нажмите кнопку Включить или Отключить, и затем ОК." #. i18n-hint: This is before radio buttons selecting which effects to show #: src/PluginManager.cpp:543 @@ -4420,6 +4404,9 @@ msgid "" "\n" "%s" msgstr "" +"Включаются эффекты:\n" +"\n" +"%s" #: src/PluginManager.cpp:983 #, c-format @@ -4428,23 +4415,31 @@ msgid "" "\n" "%s" msgstr "" +"Включается эффект:\n" +"\n" +"%s" #: src/Prefs.cpp:182 #, c-format msgid "Failed to remove %s" -msgstr "Неполадка во время удаления '%s'." +msgstr "Ошибка при удалении '%s'." #: src/Prefs.cpp:182 msgid "Failed!" msgstr "Ошибка!" #: src/Prefs.cpp:199 +#, fuzzy msgid "" "Reset Preferences?\n" "\n" "This is a one-time question, after an 'install' where you asked to have the " "Preferences reset." msgstr "" +"Сбросить настройки?\n" +"\n" +"This is a one-time question, after an 'install' where you asked to have the " +"Preferences reset." #: src/Prefs.cpp:200 msgid "Reset Audacity Preferences" @@ -4477,18 +4472,17 @@ msgstr "(Восстановлен)" #: src/Project.cpp:2412 msgid "" -msgstr "" +msgstr "<без названия>" #. i18n-hint: The first %s numbers the project, the second %s is the project name. #: src/Project.cpp:2501 -#, fuzzy, c-format +#, c-format msgid "%sSave changes to %s?" -msgstr "Сохранить изменения?" +msgstr "%sСохранить изменения в %s?" #: src/Project.cpp:2502 -#, fuzzy msgid "Save project before closing?" -msgstr "Сохранить изменения перед закрытием?" +msgstr "Сохранить проект перед закрытием?" #: src/Project.cpp:2505 msgid "" @@ -4630,7 +4624,7 @@ msgstr "Не удалось удалить старый файл автомат #: src/Project.cpp:3276 src/Project.cpp:3277 msgid "" -msgstr "" +msgstr "<нераспознанная версия -- возможно поврежден файл проекта>" #: src/Project.cpp:3378 #, c-format @@ -4664,6 +4658,14 @@ msgid "" "\n" "Save anyway?" msgstr "" +"Ваш проект в данный момент пуст.\n" +"В случае сохранения, он будет без дорожек.\n" +"\n" +"Чтобы сохранить ранее открытые дорожки:\n" +"нажмите 'Нет', Правка > Отменить, пока не появятся\n" +"все дорожки, затем Файл > Сохранить проект.\n" +"\n" +"Все равно сохранить?" #: src/Project.cpp:3694 msgid "Warning - Empty Project" @@ -4731,22 +4733,34 @@ msgid "" "To open a compressed project takes longer than usual, as it imports \n" "each compressed track.\n" msgstr "" +"При использовании 'Сохранить сжатый проект' сохраняется проект Audacity, а " +"не звуковой файл.\n" +"Для сохранения звукового файла используйте 'Экспорт'.\n" +"\n" +"Сжатый проект - хороший способ для передачи ваших проектов онлайн, \n" +"но он теряет в качестве.\n" +"\n" +"To open a compressed project takes longer than usual, as it imports \n" +"each compressed track.\n" #: src/Project.cpp:4226 -#, fuzzy, c-format +#, c-format msgid "%sSave Compressed Project \"%s\" As..." -msgstr "Сохранить сжатый проект \"%s\" как..." +msgstr "%sСохранить сжатый проект \"%s\" как..." #: src/Project.cpp:4231 msgid "" "'Save Project' is for an Audacity project, not an audio file.\n" "For an audio file that will open in other apps, use 'Export'.\n" msgstr "" +"При использовании 'Сохранить проект' сохраняется проект Audacity, а не " +"звуковой файл.\n" +"Для сохранения звукового файла используйте 'Экспорт'.\n" #: src/Project.cpp:4236 -#, fuzzy, c-format +#, c-format msgid "%sSave Project \"%s\" As..." -msgstr "Сохранить проект \"%s\" как..." +msgstr "%sСохранить проект \"%s\" как..." #: src/Project.cpp:4315 msgid "Created new project" @@ -4764,7 +4778,7 @@ msgstr "Удалить" #: src/Project.cpp:4744 #, fuzzy, c-format msgid "Disk space remains for recording %s" -msgstr "Дисковое пространство выделенное для записи: %d минут." +msgstr "Оставшееся дисковое пространство для записи %s" #: src/Project.cpp:4766 msgid "On-demand import and waveform calculation complete." @@ -4827,13 +4841,13 @@ msgstr "Удалить дорожку" #: src/Project.cpp:5605 msgid "Less than 1 minute" -msgstr "" +msgstr "Менее 1 минуты" #. i18n-hint: A time in hours and minutes. Only translate the "and". #: src/Project.cpp:5618 #, c-format msgid "%d %s and %d %s." -msgstr "" +msgstr "%d %s и %d %s." #. i18n-hint: Audio data bit depth (precision): 16-bit integers #: src/SampleFormat.cpp:66 @@ -4929,7 +4943,7 @@ msgstr "Инструменты" #: src/Screenshot.cpp:387 src/toolbars/ControlToolBar.cpp:100 #: src/toolbars/ControlToolBar.cpp:284 msgid "Transport" -msgstr "" +msgstr "Управление" #: src/Screenshot.cpp:393 src/toolbars/MixerToolBar.cpp:58 #: src/toolbars/MixerToolBar.cpp:194 @@ -5025,13 +5039,12 @@ msgid "" msgstr "" #: src/Sequence.cpp:1052 -#, fuzzy msgid "Warning - Truncating Overlong Block File" -msgstr "Внимание - Открытие файла устаревшей версии проекта" +msgstr "" #: src/ShuttleGui.cpp:2176 src/effects/Effect.cpp:2953 msgid "&Preview" -msgstr "" +msgstr "&Прослушать" #: src/ShuttleGui.cpp:2180 msgid "Dry Previe&w" @@ -5039,7 +5052,7 @@ msgstr "" #: src/ShuttleGui.cpp:2186 msgid "&Settings" -msgstr "" +msgstr "&Параметры" #: src/ShuttleGui.cpp:2217 msgid "Debu&g" @@ -5051,11 +5064,11 @@ msgstr "Выкл" #: src/Snap.cpp:371 msgid "Nearest" -msgstr "" +msgstr "Ближайший" #: src/Snap.cpp:372 msgid "Prior" -msgstr "" +msgstr "Приоритетный" #: src/SoundActivatedRecord.cpp:34 msgid "Sound Activated Record" @@ -5104,6 +5117,7 @@ msgstr "Описание" #: src/Tags.cpp:844 msgid "Use arrow keys (or ENTER key after editing) to navigate fields." msgstr "" +"Используйте стрелки (или ENTER после редактирования) для навигации по полям." #: src/Tags.cpp:867 msgid "Tag" @@ -5253,15 +5267,15 @@ msgstr "" " %s" #: src/Theme.cpp:987 -#, fuzzy, c-format +#, c-format msgid "" "Some required files in:\n" " %s\n" "were already present. Overwrite?" msgstr "" -"Все требуемые файлы:\n" +"Некоторые требуемые файлы в:\n" " %s\n" -"уже присутствуют." +"уже присутствуют. Перезаписать?" #: src/Theme.cpp:1004 #, c-format @@ -5282,23 +5296,21 @@ msgstr "Длительность" #: src/TimerRecordDialog.cpp:143 msgid "Audacity Timer Record" -msgstr "Таймер записи Audacity" +msgstr "Запись по таймеру Audacity" #: src/TimerRecordDialog.cpp:312 -#, fuzzy msgid "" "The selected file name could not be used\n" "for Timer Recording because it would overwrite another project.\n" "Please try again and select an original name." msgstr "" -"Проект не был сохранён, так как предоставленное наименование файла заменит " -"файл другого проекта.\n" +"Выбранное имя файле не может быть использовано для Таймера Записи, так как " +"заменит файл другого проекта.\n" "Повторите снова, выбрав уникальное наименование." #: src/TimerRecordDialog.cpp:314 -#, fuzzy msgid "Error Saving Timer Recording Project" -msgstr "Ошибка при сохранении проекта" +msgstr "Ошибка при сохранении проекта записи по таймеру" #: src/TimerRecordDialog.cpp:365 msgid "Duration is zero. Nothing will be recorded." @@ -5310,75 +5322,66 @@ msgstr "Ошибка длительности" #: src/TimerRecordDialog.cpp:374 msgid "Automatic Save path is invalid." -msgstr "" +msgstr "Путь для автосохранения не действителен" #: src/TimerRecordDialog.cpp:375 -#, fuzzy msgid "Error in Automatic Save" -msgstr "Ошибка длительности" +msgstr "Ошибка автосохранения" #: src/TimerRecordDialog.cpp:381 msgid "Automatic Export path is invalid." -msgstr "" +msgstr "Путь для автоэкспорта не действителен" #: src/TimerRecordDialog.cpp:382 -#, fuzzy msgid "Error in Automatic Export" -msgstr "Ошибка длительности" +msgstr "Ошибка автоэкспорта" #: src/TimerRecordDialog.cpp:419 msgid "Timer Recording Disk Space Warning" msgstr "" #: src/TimerRecordDialog.cpp:461 src/TimerRecordDialog.cpp:869 -#, fuzzy msgid "Current Project" -msgstr "Применить к текущему &проекту" +msgstr "Текущий проект" #: src/TimerRecordDialog.cpp:525 -#, fuzzy msgid "Recording start:\n" -msgstr "Начало записи" +msgstr "Начало записи:\n" #: src/TimerRecordDialog.cpp:526 -#, fuzzy msgid "Duration:\n" -msgstr "Длительность:" +msgstr "Длительность:\n" #: src/TimerRecordDialog.cpp:527 -#, fuzzy msgid "" "Recording end:\n" "\n" -msgstr "Конец записи" +msgstr "Конец записи:\n" #: src/TimerRecordDialog.cpp:528 src/TimerRecordDialog.cpp:1006 msgid "Automatic Save enabled:\n" -msgstr "" +msgstr "Автоматическое сохранение включено:\n" #: src/TimerRecordDialog.cpp:529 src/TimerRecordDialog.cpp:1007 msgid "Automatic Export enabled:\n" -msgstr "" +msgstr "Автоматический экспорт включен:\n" #: src/TimerRecordDialog.cpp:530 src/TimerRecordDialog.cpp:1008 #: src/TimerRecordDialog.cpp:1051 -#, fuzzy msgid "Action after Timer Recording:" -msgstr "Таймер записи Audacity" +msgstr "Действие после записи по таймеру" #: src/TimerRecordDialog.cpp:545 msgid "Audacity Timer Record Progress" msgstr "Ход выполнения записи по таймеру" #: src/TimerRecordDialog.cpp:618 -#, fuzzy msgid "Timer Recording stopped." -msgstr "&Таймер записи..." +msgstr "Таймер записи остановлен" #: src/TimerRecordDialog.cpp:619 -#, fuzzy msgid "Timer Recording completed." -msgstr "Индикатор записи" +msgstr "Запись по таймеру закончена." #. i18n-hint: This string is used to configure the controls for times when the recording is #. * started and stopped. As such it is important that only the alphabetic parts of the string @@ -5419,112 +5422,100 @@ msgid "099 days 024 h 060 m 060 s" msgstr "099 дней 024 ч 060 м 060 с" #: src/TimerRecordDialog.cpp:857 -#, fuzzy msgid "Automatic Save" -msgstr "Автоматически" +msgstr "Автоматическое сохранение" #: src/TimerRecordDialog.cpp:860 msgid "Enable &Automatic Save?" -msgstr "" +msgstr "Вкдючить автоматическое сохранение?" #: src/TimerRecordDialog.cpp:871 src/TimerRecordDialog.cpp:872 -#, fuzzy msgid "Save Project As:" -msgstr "Сохранить проект &как..." +msgstr "Сохранить проект как:" #: src/TimerRecordDialog.cpp:875 src/TimerRecordDialog.cpp:890 -#, fuzzy msgid "Select..." -msgstr "Выделение" +msgstr "Выделить..." #: src/TimerRecordDialog.cpp:881 -#, fuzzy msgid "Automatic Export" -msgstr "Автоматически" +msgstr "Автоматический экспорт" #: src/TimerRecordDialog.cpp:883 -#, fuzzy msgid "Enable Automatic &Export?" -msgstr "Невозможно экспортировать" +msgstr "Включить автоматический экспорт?" #: src/TimerRecordDialog.cpp:886 src/TimerRecordDialog.cpp:887 -#, fuzzy msgid "Export Project As:" -msgstr "Экспортировать" +msgstr "Экспортировать проект как:" #: src/TimerRecordDialog.cpp:896 -#, fuzzy msgid "Options" -msgstr "Параметры..." +msgstr "Параметры" #: src/TimerRecordDialog.cpp:900 msgid "Do nothing" -msgstr "" +msgstr "Ничего не делать" #: src/TimerRecordDialog.cpp:901 -#, fuzzy msgid "Exit Audacity" -msgstr "Выйти из Audacity" +msgstr "Закрыть Audacity" #: src/TimerRecordDialog.cpp:902 msgid "Restart system" -msgstr "" +msgstr "Презагрузить систему" #: src/TimerRecordDialog.cpp:903 msgid "Shutdown system" -msgstr "" +msgstr "Выключить компьютер" #: src/TimerRecordDialog.cpp:913 -#, fuzzy msgid "After Recording completes:" -msgstr "Индикатор записи" +msgstr "После завершения записи:" #: src/TimerRecordDialog.cpp:1003 -#, fuzzy msgid "Waiting to start recording at:\n" -msgstr "Ожидание начала записи %s.\n" +msgstr "Ожидание начала записи в:\n" #: src/TimerRecordDialog.cpp:1004 -#, fuzzy msgid "Recording duration:\n" -msgstr "Запись звука" +msgstr "Длительность записи:\n" #: src/TimerRecordDialog.cpp:1005 msgid "" "Scheduled to stop at:\n" "\n" msgstr "" +"Остановка запланирована в:\n" +"\n" #: src/TimerRecordDialog.cpp:1024 msgid "Audacity Timer Record - Waiting for Start" msgstr "Таймер записи Audacity - Ожидание запуска" #: src/TimerRecordDialog.cpp:1027 -#, fuzzy msgid "Recording will commence in:" -msgstr "Устройство для записи" +msgstr "Запись начнется в:" #: src/TimerRecordDialog.cpp:1048 -#, fuzzy msgid "" "Timer Recording completed.\n" "\n" -msgstr "Индикатор записи" +msgstr "" +"Запись по таймеру закончена.\n" +"\n" #: src/TimerRecordDialog.cpp:1049 -#, fuzzy msgid "Recording Saved:\n" -msgstr "Конец записи" +msgstr "Запись сохранена:\n" #: src/TimerRecordDialog.cpp:1050 -#, fuzzy msgid "Recording Exported:\n" -msgstr "Конец записи" +msgstr "Запись экспортирована:\n" #: src/TimerRecordDialog.cpp:1066 -#, fuzzy msgid "Audacity Timer Record - Waiting" -msgstr "Таймер записи Audacity - Ожидание запуска" +msgstr "Таймер записи Audacity - Ожидание" #. i18n-hint: This is for screen reader software and indicates that #. this is a Time track. @@ -5538,19 +5529,19 @@ msgstr "&Другое..." #: src/TrackPanel.cpp:619 msgid "Wa&veform" -msgstr "" +msgstr "Волна" #: src/TrackPanel.cpp:620 msgid "&Waveform (dB)" -msgstr "&Осциллограмма (дБ)" +msgstr "Осциллограмма (дБ)" #: src/TrackPanel.cpp:621 msgid "&Spectrogram" -msgstr "&Спектрограмма" +msgstr "Спектрограмма" #: src/TrackPanel.cpp:622 msgid "S&pectrogram Settings..." -msgstr "" +msgstr "Параметры спектрограммы..." #: src/TrackPanel.cpp:627 msgid "&Mono" @@ -5561,9 +5552,8 @@ msgid "&Left Channel" msgstr "&Левый канал" #: src/TrackPanel.cpp:629 -#, fuzzy msgid "&Right Channel" -msgstr "Правый канал" +msgstr "&Правый канал" #: src/TrackPanel.cpp:630 msgid "Ma&ke Stereo Track" @@ -5571,49 +5561,47 @@ msgstr "Соз&дать стереофоническую дорожка" #: src/TrackPanel.cpp:631 msgid "Swap Stereo &Channels" -msgstr "" +msgstr "Поменять стерео &каналы" #: src/TrackPanel.cpp:632 msgid "Spl&it Stereo Track" -msgstr "" +msgstr "Раздел&ить стерео дорожку" #: src/TrackPanel.cpp:633 -#, fuzzy msgid "Split Stereo to Mo&no" -msgstr "Разделить стереофоническую дорожку в мoнофоническую '%s'" +msgstr "Разделить стерео дорожку в мoно" #: src/TrackPanel.cpp:636 msgid "&Format" -msgstr "" +msgstr "&Формат" #: src/TrackPanel.cpp:640 msgid "Rat&e" -msgstr "" +msgstr "Частота" #: src/TrackPanel.cpp:645 msgid "Up &Octave" -msgstr "" +msgstr "Верхняя &октава" #: src/TrackPanel.cpp:646 msgid "Down Octa&ve" -msgstr "" +msgstr "Нижняя окта&ва" #: src/TrackPanel.cpp:651 msgid "&Font..." msgstr "&Шрифт..." #: src/TrackPanel.cpp:657 -#, fuzzy msgid "L&ogarithmic scale" -msgstr "Логарифмическая" +msgstr "Л&огарифмическая шкала" #: src/TrackPanel.cpp:660 msgid "&Range..." -msgstr "" +msgstr "&Диапазон..." #: src/TrackPanel.cpp:661 msgid "Logarithmic &Interpolation" -msgstr "" +msgstr "Логарифмическая &интерполяция" #: src/TrackPanel.cpp:678 msgid "&Name..." @@ -5621,7 +5609,7 @@ msgstr "&Название..." #: src/TrackPanel.cpp:682 msgid "Move Track &Up" -msgstr "" +msgstr "Переместить дорожку &вверх" #: src/TrackPanel.cpp:684 msgid "Move Track &Down" @@ -5629,62 +5617,66 @@ msgstr "Переместить дорожку вн&из" #: src/TrackPanel.cpp:686 msgid "Move Track to &Top" -msgstr "" +msgstr "Переместить дорожку на &первое место" #: src/TrackPanel.cpp:688 msgid "Move Track to &Bottom" -msgstr "" +msgstr "Преместить дорожку на по&следнее место" #: src/TrackPanel.cpp:1378 -#, fuzzy msgid "Command-Click" -msgstr "Команда" +msgstr "Command+Клик" #: src/TrackPanel.cpp:1380 -#, fuzzy msgid "Ctrl-Click" -msgstr "Щелчок левой клавишей" +msgstr "Ctrl+Клик" #: src/TrackPanel.cpp:1390 msgid "" "Click to vertically zoom in. Shift-click to zoom out. Drag to specify a zoom " "region." msgstr "" +"Кликните для увеличения по вертикали. Shift+Клик для уменьшения по " +"вертикали. Потяните для установки области масштабирования." #: src/TrackPanel.cpp:1395 msgid "" "Click to verticaly zoom in, Shift-click to zoom out, Drag to create a " "particular zoom region." msgstr "" +"Кликните для увеличения по вертикали. Shift+Клик для уменьшения по " +"вертикали. Потяните для установки особой области масштабирования." #. i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac #: src/TrackPanel.cpp:1410 #, c-format msgid "%s to select or deselect track. Drag up or down to change track order." msgstr "" +"%s выбрать или отменить выбор дорожки. Перетащите вверх или вниз для " +"изменения порядка дорожек." #. i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac #: src/TrackPanel.cpp:1417 #, c-format msgid "%s to select or deselect track." -msgstr "" +msgstr "%s выбрать или отменить выбор дорожки." #: src/TrackPanel.cpp:1432 msgid "Click and drag to adjust relative size of stereo tracks." msgstr "" -"Щёлкните и перетащите для регуляции относительного размера стереодорожек" +"Кликните и перетащите для установки относительного размера стерео дорожек" #: src/TrackPanel.cpp:1435 msgid "Click and drag to resize the track." -msgstr "Щёлкните и перетащите для изменения высоты дорожки" +msgstr "Кликните и перетащите для изменения размера дорожки" #: src/TrackPanel.cpp:1466 msgid "Drag one or more label boundaries." -msgstr "" +msgstr "Перетащите одну или несколько марок." #: src/TrackPanel.cpp:1467 msgid "Drag label boundary." -msgstr "" +msgstr "Перетащите марку." #: src/TrackPanel.cpp:1512 src/TrackPanel.cpp:1519 msgid "Click and drag to move center selection frequency." @@ -5697,32 +5689,32 @@ msgstr "" #. i18n-hint: These are the names of a menu and a command in that menu #: src/TrackPanel.cpp:1569 msgid "Edit, Preferences..." -msgstr "" +msgstr "Редактировать, Параметры..." #: src/TrackPanel.cpp:1574 #, c-format msgid "Multi-Tool Mode: %s for Mouse and Keyboard Preferences." -msgstr "" +msgstr "Режим мульти-инструмента: %s для параметров мыши и клавиатуры." #: src/TrackPanel.cpp:1607 msgid "Click and drag to set frequency bandwidth." -msgstr "" +msgstr "Перетащите для установки диапазона частот" #: src/TrackPanel.cpp:1627 msgid "Click and drag to stretch within selected region." -msgstr "" +msgstr "Кликните и перетащите для растягивания внутри выделенной области." #: src/TrackPanel.cpp:1642 msgid "Click to move selection boundary to cursor." -msgstr "" +msgstr "Кликните для перемещения границ выделения к курсору." #: src/TrackPanel.cpp:1648 msgid "Click and drag to move left selection boundary." -msgstr "Щёлкните и перетащите отметку для установки левой границы выделения." +msgstr "Кликните и перетащите для установки левой границы выделения." #: src/TrackPanel.cpp:1652 msgid "Click and drag to move right selection boundary." -msgstr "Щёлкните и перетащите отметку для установки правой границы выделения." +msgstr "Кликните и перетащите для установки правой границы выделения." #: src/TrackPanel.cpp:1657 msgid "Click and drag to move bottom selection frequency." @@ -5738,7 +5730,7 @@ msgstr "" #: src/TrackPanel.cpp:2246 src/TrackPanel.cpp:2254 msgid "Click and drag to stretch selected region." -msgstr "Щёлкните и перетащите, чтобы растянуть выделенную область." +msgstr "Кликните и перетащите, чтобы растянуть выделенную область." #. i18n-hint: (noun) The track that is used for MIDI notes which can be #. dragged to change their duration. @@ -5757,7 +5749,7 @@ msgstr "Растянуть" #. i18n-hint: (verb) Audacity has just adjusted the envelope . #: src/TrackPanel.cpp:3193 msgid "Adjusted envelope." -msgstr "Огибающая скорректирована." +msgstr "Скорректированая огибающая." #. i18n-hint: The envelope is a curve that controls the audio loudness. #: src/TrackPanel.cpp:3195 src/prefs/MousePrefs.cpp:137 @@ -5765,9 +5757,8 @@ msgid "Envelope" msgstr "Огибающая" #: src/TrackPanel.cpp:3370 -#, fuzzy msgid "Moved clips to another track" -msgstr "Фрагмент перемещён из одной дорожки в другую" +msgstr "Фрагменты перемещёны в другую дорожку" #. i18n-hint: a direction as in left or right. #: src/TrackPanel.cpp:3376 @@ -5793,10 +5784,14 @@ msgstr "Сдвиг во времени" #: src/TrackPanel.cpp:4455 msgid "To use Draw, choose 'Waveform' in the Track Drop-down Menu." msgstr "" +"Для использования инструмента рисования, выбирите 'Волна' в выпадающем меню " +"дорожки." #: src/TrackPanel.cpp:4474 msgid "To use Draw, zoom in further until you can see the individual samples." msgstr "" +"Для использования инструмента рисования, увеличьте масштаб пока не увидите " +"отдельные пики." #: src/TrackPanel.cpp:4717 msgid "Moved Samples" @@ -5887,7 +5882,7 @@ msgstr "Канал" #: src/TrackPanel.cpp:8036 #, c-format msgid "Swapped Channels in '%s'" -msgstr "" +msgstr "Каналы поменяны местами в '%s'" #: src/TrackPanel.cpp:8038 msgid "Swap Channels" @@ -5905,31 +5900,33 @@ msgstr "Разделить стереофоническую дорожку в м #: src/TrackPanel.cpp:8057 msgid "Split to Mono" -msgstr "" +msgstr "Разделить на моно" #: src/TrackPanel.cpp:8160 #, c-format msgid "Made '%s' a stereo track" -msgstr "Создать стереодорожку '%s' " +msgstr "Создать стерео дорожку '%s'" #: src/TrackPanel.cpp:8163 msgid "Make Stereo" -msgstr "Создать стереофоническую дорожку" +msgstr "Создать стерео дорожку" #: src/TrackPanel.cpp:8198 msgid "" "To change Spectrogram Settings, stop any\n" ".playing or recording first." msgstr "" +"Для изменения параметоров Спектрограммы, остановите\n" +"сначала воспроизведение или запись." #: src/TrackPanel.cpp:8200 msgid "Stop the Audio First" -msgstr "" +msgstr "Сначала остановите воспроизведение" #: src/TrackPanel.cpp:8294 #, c-format msgid "Changed '%s' to %s Hz" -msgstr "" +msgstr "Изменено '%s' на %s Hz" #: src/TrackPanel.cpp:8296 msgid "Rate Change" @@ -5962,7 +5959,7 @@ msgstr "Предел повышения скорости" #: src/TrackPanel.cpp:8527 #, c-format msgid "Set range to '%ld' - '%ld'" -msgstr "" +msgstr "Установить диапазон на '%ld' - '%ld'" #. i18n-hint: (verb) #: src/TrackPanel.cpp:8532 @@ -5971,27 +5968,28 @@ msgstr "Установить диапазон" #: src/TrackPanel.cpp:8544 msgid "Set time track display to linear" -msgstr "" +msgstr "Линейная шкала времени дорожки" #: src/TrackPanel.cpp:8544 src/TrackPanel.cpp:8554 +#, fuzzy msgid "Set Display" -msgstr "" +msgstr "Отображение" #: src/TrackPanel.cpp:8554 msgid "Set time track display to logarithmic" -msgstr "" +msgstr "Логарифмическая шкала времени дорожки " #: src/TrackPanel.cpp:8564 msgid "Set time track interpolation to linear" -msgstr "" +msgstr "Линейная интерполяция времени дорожки" #: src/TrackPanel.cpp:8564 src/TrackPanel.cpp:8567 msgid "Set Interpolation" -msgstr "" +msgstr "Интерполяция" #: src/TrackPanel.cpp:8567 msgid "Set time track interpolation to logarithmic" -msgstr "" +msgstr "Логарифмическая интерполяция времени дорожки" #: src/TrackPanel.cpp:8680 msgid "Change track name to:" @@ -6055,7 +6053,7 @@ msgstr "Соло вкл." #. this track is selected. #: src/TrackPanelAx.cpp:387 src/TrackPanelAx.cpp:559 msgid " Select On" -msgstr "" +msgstr "Выделение" #. i18n-hint: This is for screen reader software and indicates that #. this track is shown with a sync-locked icon. @@ -6063,7 +6061,7 @@ msgstr "" #. if present, Jaws reads it as "dash". #: src/TrackPanelAx.cpp:395 msgid " Sync Lock Selected" -msgstr "" +msgstr "Синхронизация включена" #. i18n-hint: Voice key is an experimental/incomplete feature that #. is used to navigate in vocal recordings, to move forwards and @@ -6095,7 +6093,7 @@ msgstr "" #: src/VoiceKey.cpp:819 #, c-format msgid "Direction Changes -- mean: %1.4f sd: (%1.4f)\n" -msgstr "Смена напрвления -- среднее значение: %1.4f sd: (%1.4f)\n" +msgstr "Смена направления -- среднее значение: %1.4f sd: (%1.4f)\n" #. i18n-hint: The default name for an audio track. #: src/WaveTrack.cpp:106 src/prefs/TracksPrefs.cpp:130 @@ -6122,31 +6120,34 @@ msgid "" "There was a problem with your last action. If you think\n" "this is a bug, please tell us exactly where it occurred." msgstr "" +"Возникла проблема во время последней операции\n" +"Если Вы думаете что это баг, дайте нам знать где он в точности произошел." #: src/commands/CommandManager.cpp:1088 msgid "" "You can only do this when playing and recording are\n" "stopped. (Pausing is not sufficient.)" msgstr "" +"Вы можете сделать это только когда воспроизведение\n" +"или запись остановлены. (Паузы не достаточно.)" #: src/commands/CommandManager.cpp:1090 -#, fuzzy msgid "" "You must first select some stereo audio to perform this\n" "action. (You cannot use this with mono.)" -msgstr "Сначала придётся выделить область звука." +msgstr "" +"Сначала нужно выделить область стерео звука.\n" +"(С моно не работает)" #: src/commands/CommandManager.cpp:1092 -#, fuzzy msgid "You must first select some audio to perform this action." -msgstr "Сначала придётся выделить область звука." +msgstr "Сначала нужно выделить область стерео звука." #: src/commands/CommandManager.cpp:1094 -#, fuzzy msgid "" "You must first select some audio to perform this action.\n" "(Selecting other kinds of track won't work.)" -msgstr "Сначала придётся выделить область звука." +msgstr "Сначала нужно выделить область стерео звука." #: src/commands/CommandManager.cpp:1099 msgid "Disallowed" @@ -6159,7 +6160,7 @@ msgstr "Загружено %d клавиатурных комбинаций\n" #: src/commands/CommandManager.cpp:1426 msgid "Loading Keyboard Shortcuts" -msgstr "" +msgstr "Загружаются клавиатурные комбинации" #: src/commands/ScreenshotCommand.cpp:223 msgid "Saved " @@ -6176,7 +6177,7 @@ msgstr "Соотношение" #: src/effects/Amplify.cpp:90 msgid "Increases or decreases the volume of the audio you have selected" -msgstr "" +msgstr "Увеличивает или уменьшает уровень громкости выделенного вами аудио" #: src/effects/Amplify.cpp:220 msgid "Amplification (dB):" @@ -6231,12 +6232,16 @@ msgid "" "Reduces (ducks) the volume of one or more tracks whenever the volume of a " "specified \"control\" track reaches a particular level" msgstr "" +"Приглушает громкость одной или нескольких дорожек когда громкость " +"определенной (контрольной) дорожки достигнет заданного уровня." #: src/effects/AutoDuck.cpp:226 msgid "" "You selected a track which does not contain audio. AutoDuck can only process " "audio tracks." msgstr "" +"Вы выбрали дорожку, не содержащую аудио данных. AutoDuck может работать " +"толкьо с аудио дорожками." #. i18n-hint: Auto duck is the name of an effect that 'ducks' (reduces the volume) #. * of the audio automatically when there is sound on another track. Not as @@ -6311,18 +6316,16 @@ msgid "Link Sliders" msgstr "" #: src/effects/BassTreble.cpp:92 -#, fuzzy msgid "Simple tone control effect" -msgstr "Стянуть выделение слева" +msgstr "Простой эффект управления тоном" #: src/effects/BassTreble.cpp:209 msgid "Tone controls" -msgstr "" +msgstr "Регулировки тона" #: src/effects/BassTreble.cpp:218 -#, fuzzy msgid "Ba&ss (dB):" -msgstr "&Усиление (Дб):" +msgstr "Низы (dB):" #: src/effects/BassTreble.cpp:219 msgid "Bass (dB):" @@ -6330,12 +6333,11 @@ msgstr "" #: src/effects/BassTreble.cpp:229 msgid "&Treble (dB):" -msgstr "" +msgstr "Верхи (dB):" #: src/effects/BassTreble.cpp:249 -#, fuzzy msgid "&Volume (dB):" -msgstr "&Диапазон (Дб):" +msgstr "&Громкость (dB):" #: src/effects/BassTreble.cpp:254 src/effects/Normalize.cpp:35 msgid "Level" @@ -6347,7 +6349,7 @@ msgstr "" #: src/effects/BassTreble.h:26 msgid "Bass and Treble" -msgstr "" +msgstr "Низы и верхи" #: src/effects/ChangePitch.cpp:57 src/effects/ChangeSpeed.cpp:67 #: src/effects/ChangeTempo.cpp:51 @@ -6360,11 +6362,11 @@ msgstr "" #: src/effects/ChangePitch.cpp:126 msgid "Change the pitch of a track without changing its tempo" -msgstr "" +msgstr "Изменение высоты звука дорожки без изменения темпа" #: src/effects/ChangePitch.cpp:188 msgid "High Quality Pitch Change" -msgstr "" +msgstr "Высококачественное изменение высоты звука" #: src/effects/ChangePitch.cpp:245 msgid "Change Pitch without Changing Tempo" @@ -6378,7 +6380,7 @@ msgstr "" #. i18n-hint: (noun) Musical pitch. #: src/effects/ChangePitch.cpp:253 msgid "Pitch" -msgstr "" +msgstr "Высота звука" #: src/effects/ChangePitch.cpp:257 src/effects/ChangePitch.cpp:258 #: src/effects/ChangePitch.cpp:294 src/effects/ChangeSpeed.cpp:347 @@ -6434,7 +6436,7 @@ msgstr "Процентное изменение" #: src/effects/ChangePitch.cpp:331 src/effects/ChangeTempo.cpp:278 msgid "Use high quality stretching (slow)" -msgstr "" +msgstr "Использовать высококачественное растяжение (медленно)" #: src/effects/ChangePitch.h:39 msgid "Change Pitch" @@ -6466,7 +6468,7 @@ msgstr "Смена скорости, меняющая темп и высоту #: src/effects/ChangeSpeed.cpp:304 msgid "Speed Multiplier:" -msgstr "" +msgstr "Множитель скорости:" #. i18n-hint: "rpm" is an English abbreviation meaning "revolutions per minute". #: src/effects/ChangeSpeed.cpp:329 @@ -6550,32 +6552,32 @@ msgstr "Порог" #: src/effects/ClickRemoval.cpp:52 msgid "Width" -msgstr "" +msgstr "Ширина" #: src/effects/ClickRemoval.cpp:85 msgid "Click Removal is designed to remove clicks on audio tracks" -msgstr "" +msgstr "Удаление щелчков в звуковых дорожках" #: src/effects/ClickRemoval.cpp:191 msgid "Algorithm not effective on this audio. Nothing changed." -msgstr "" +msgstr "Алгоритм не эффективен на этих звуковых данных. Ничего не изменено." #: src/effects/ClickRemoval.cpp:204 #, c-format msgid "Selection must be larger than %d samples." -msgstr "" +msgstr "Выделение должно быть больше чем %d семплов." #: src/effects/ClickRemoval.cpp:336 msgid "Threshold (lower is more sensitive):" -msgstr "" +msgstr "Порог (чем ниже, тем чувствительней):" #: src/effects/ClickRemoval.cpp:350 msgid "Max Spike Width (higher is more sensitive):" -msgstr "" +msgstr "Макс. ширина скачка (чем выше, тем чувствительней)" #: src/effects/ClickRemoval.cpp:357 msgid "Max Spike Width" -msgstr "" +msgstr "Макс. ширина скачка" #: src/effects/ClickRemoval.h:29 msgid "Click Removal" @@ -6603,7 +6605,7 @@ msgstr "" #: src/effects/Compressor.cpp:105 msgid "Compresses the dynamic range of audio" -msgstr "" +msgstr "Сжимает динамический диапазон звука" #: src/effects/Compressor.cpp:219 msgid "Noise Floor:" @@ -6623,19 +6625,19 @@ msgstr "Соотношение:" #. * sound dies away. So this means 'onset duration'. #: src/effects/Compressor.cpp:245 msgid "Attack Time:" -msgstr "Длительность атаки: " +msgstr "Время нарастания:" #: src/effects/Compressor.cpp:252 msgid "Attack Time" -msgstr "Время атаки" +msgstr "Время нарастания" #: src/effects/Compressor.cpp:256 msgid "Release Time:" -msgstr "" +msgstr "Время затухания:" #: src/effects/Compressor.cpp:263 msgid "Release Time" -msgstr "" +msgstr "Время затухания" #. i18n-hint: Make-up, i.e. correct for any reduction, rather than fabricate it. #: src/effects/Compressor.cpp:274 @@ -6689,7 +6691,7 @@ msgstr "%.1f:1" #: src/effects/Compressor.cpp:622 #, c-format msgid "Attack Time %.2f secs" -msgstr "" +msgstr "Время нарастания %.2f сек" #: src/effects/Compressor.cpp:623 src/effects/ScoreAlignDialog.cpp:262 #: src/effects/ScoreAlignDialog.cpp:264 src/effects/ScoreAlignDialog.cpp:268 @@ -6701,7 +6703,7 @@ msgstr "%.2f с" #: src/effects/Compressor.cpp:626 #, c-format msgid "Release Time %.1f secs" -msgstr "" +msgstr "Время затухания %.1f сек" #: src/effects/Compressor.cpp:627 #, c-format @@ -6710,28 +6712,32 @@ msgstr "%.1f с" #: src/effects/Compressor.h:30 msgid "Compressor" -msgstr "Компрессоры" +msgstr "Компрессор" #: src/effects/Contrast.cpp:56 msgid "You can only measure one track at a time." -msgstr "" +msgstr "Вы можете измерить только одну дорожку за раз." #: src/effects/Contrast.cpp:75 msgid "" "Invalid audio selection.\n" "Please ensure that audio is selected." msgstr "" +"Выбраны недопустимые данные.\n" +"Убедитесь, пожалуйста, что выбраны звуковые данные." #: src/effects/Contrast.cpp:82 +#, fuzzy msgid "" "Nothing to measure.\n" "Please select a section of a track." msgstr "" +"Нечего измерять.\n" +"Выбирите, пожалуйста, часть дорожки." #: src/effects/Contrast.cpp:96 -#, fuzzy msgid "Please select an audio track." -msgstr "Выберите действие" +msgstr "Выберите звуковую дорожку." #: src/effects/Contrast.cpp:179 msgid "" @@ -6744,8 +6750,9 @@ msgid "Volume " msgstr "Громкость" #: src/effects/Contrast.cpp:195 +#, fuzzy msgid "&Foreground:" -msgstr "" +msgstr "&Передний план:" #. i18n-hint: Name of time display format that shows time in hours, #. * minutes, seconds and hundredths of a second (1/100 second) @@ -6756,28 +6763,33 @@ msgid "hh:mm:ss + hundredths" msgstr "чч:мм:сс + сотни" #: src/effects/Contrast.cpp:207 +#, fuzzy msgid "Foreground start time" -msgstr "Время начала фрагмента заднего плана" +msgstr "Время начала фрагмента переднего плана" #: src/effects/Contrast.cpp:224 +#, fuzzy msgid "Foreground end time" -msgstr "Время завершения фрагмента заднего плана" +msgstr "Время завершения фрагмента переднего плана" #: src/effects/Contrast.cpp:230 msgid "&Measure selection" msgstr "" #: src/effects/Contrast.cpp:235 +#, fuzzy msgid "&Background:" -msgstr "" +msgstr "&Задний план:" #: src/effects/Contrast.cpp:247 +#, fuzzy msgid "Background start time" -msgstr "Время начала фрагмента переднего плана" +msgstr "Время начала фрагмента заднего плана" #: src/effects/Contrast.cpp:264 +#, fuzzy msgid "Background end time" -msgstr "Время завершения фрагмента переднего плана" +msgstr "Время завершения фрагмента заднего плана" #: src/effects/Contrast.cpp:270 msgid "Mea&sure selection" @@ -6793,11 +6805,11 @@ msgstr "" #: src/effects/Contrast.cpp:286 msgid "R&eset" -msgstr "" +msgstr "Сброс" #: src/effects/Contrast.cpp:287 msgid "&Difference:" -msgstr "" +msgstr "&Отклонение" #: src/effects/Contrast.cpp:290 src/effects/Equalization.cpp:3163 msgid "E&xport..." @@ -6806,16 +6818,16 @@ msgstr "&Экспортировать" #: src/effects/Contrast.cpp:374 #, fuzzy msgid "Foreground level too high" -msgstr "Время завершения фрагмента заднего плана" +msgstr "Уровень переднего плана слишком высок" #: src/effects/Contrast.cpp:377 #, fuzzy msgid "Background level too high" -msgstr "Время завершения фрагмента переднего плана" +msgstr "Уровень заднего плана слишком высок" #: src/effects/Contrast.cpp:380 msgid "Background higher than foreground" -msgstr "" +msgstr "Бэк выше, чем фронт" #: src/effects/Contrast.cpp:383 msgid "WCAG2 Pass" @@ -6840,11 +6852,11 @@ msgid "%.2f dB Average RMS" msgstr "" #: src/effects/Contrast.cpp:399 -#, fuzzy msgid "Infinite dB difference" -msgstr "Актуальные различия" +msgstr "" #: src/effects/Contrast.cpp:405 +#, fuzzy msgid "Measured foreground level" msgstr "Измеренный уровень переднего плана" @@ -6953,24 +6965,20 @@ msgid "Data gathered" msgstr "Данные собраны" #: src/effects/Distortion.cpp:61 -#, fuzzy msgid "Hard Clipping" -msgstr "Поиск перегрузки" +msgstr "" #: src/effects/Distortion.cpp:62 -#, fuzzy msgid "Soft Clipping" -msgstr "&Показывать перегрузку" +msgstr "" #: src/effects/Distortion.cpp:63 -#, fuzzy msgid "Soft Overdrive" -msgstr "Подтверждение перезаписи" +msgstr "" #: src/effects/Distortion.cpp:64 -#, fuzzy msgid "Medium Overdrive" -msgstr "Подтверждение перезаписи" +msgstr "" #: src/effects/Distortion.cpp:65 msgid "Hard Overdrive" @@ -7014,19 +7022,16 @@ msgid "Threshold dB" msgstr "Порог: %d Дб" #: src/effects/Distortion.cpp:82 src/effects/Distortion.cpp:129 -#, fuzzy msgid "Parameter 1" -msgstr "Параметры" +msgstr "Параметр 1" #: src/effects/Distortion.cpp:83 src/effects/Distortion.cpp:130 -#, fuzzy msgid "Parameter 2" -msgstr "Параметры" +msgstr "Параметр 2" #: src/effects/Distortion.cpp:84 -#, fuzzy msgid "Repeats" -msgstr "Повтор..." +msgstr "Повторы" #: src/effects/Distortion.cpp:102 #, no-c-format @@ -7111,13 +7116,12 @@ msgid "Percussion Limiter" msgstr "" #: src/effects/Distortion.cpp:127 -#, fuzzy msgid "Upper Threshold" -msgstr "Порог" +msgstr "Верхний порог" #: src/effects/Distortion.cpp:131 msgid "Number of repeats" -msgstr "" +msgstr "Количество повторов" #: src/effects/Distortion.cpp:192 msgid "Waveshaping distortion effect" @@ -7125,26 +7129,23 @@ msgstr "" #: src/effects/Distortion.cpp:344 msgid "Distortion type:" -msgstr "" +msgstr "Тип искажения:" #: src/effects/Distortion.cpp:348 msgid "DC blocking filter" msgstr "" #: src/effects/Distortion.cpp:355 -#, fuzzy msgid "Threshold controls" -msgstr "Порог" +msgstr "Регулировки порога" #: src/effects/Distortion.cpp:395 -#, fuzzy msgid "Parameter controls" -msgstr "Параметры" +msgstr "Регулировки параметров" #: src/effects/Distortion.cpp:674 -#, fuzzy msgid "Clipping level" -msgstr "Перегрузка" +msgstr "Уровень перегрузки" #: src/effects/Distortion.cpp:676 msgid "Drive" @@ -7155,9 +7156,8 @@ msgid "Make-up Gain" msgstr "" #: src/effects/Distortion.cpp:688 -#, fuzzy msgid "Clipping threshold" -msgstr "Перегрузка" +msgstr "Порог перегрузки" #: src/effects/Distortion.cpp:690 msgid "Hardness" @@ -7173,9 +7173,8 @@ msgstr "" #: src/effects/Distortion.cpp:705 src/effects/Distortion.cpp:719 #: src/effects/Distortion.cpp:733 src/effects/Distortion.cpp:747 #: src/effects/Distortion.cpp:775 -#, fuzzy msgid "Output level" -msgstr "Вывод" +msgstr "Уровень выхода" #: src/effects/Distortion.cpp:748 #, fuzzy @@ -7234,9 +7233,8 @@ msgid " (0 to 5):" msgstr "" #: src/effects/Distortion.h:26 -#, fuzzy msgid "Distortion" -msgstr "Длительность" +msgstr "Искажение" #: src/effects/DtmfGen.cpp:39 msgid "Sequence" @@ -7305,11 +7303,11 @@ msgstr "Задержка" #: src/effects/Echo.cpp:37 msgid "Decay" -msgstr "" +msgstr "Затухание" #: src/effects/Echo.cpp:60 msgid "Repeats the selected audio again and again" -msgstr "" +msgstr "Повторяет выделенную область снова и снова" #: src/effects/Echo.cpp:102 src/effects/FindClipping.cpp:168 #: src/effects/Paulstretch.cpp:249 @@ -7350,7 +7348,7 @@ msgstr "чч:мм:сс + сэмплы" #: src/effects/Effect.cpp:1204 #, c-format msgid "Applying %s..." -msgstr "" +msgstr "Применяется %s..." #: src/effects/Effect.cpp:2526 msgid "Preparing preview" @@ -7361,7 +7359,6 @@ msgid "Previewing" msgstr "Предпрослушивание" #: src/effects/Effect.cpp:2583 src/toolbars/ControlToolBar.cpp:684 -#, fuzzy msgid "" "Error opening sound device. Try changing the audio host, playback device and " "the project sample rate." @@ -7372,56 +7369,56 @@ msgstr "" #: src/effects/Effect.cpp:2921 src/effects/Effect.cpp:2929 #: src/effects/Effect.cpp:2931 msgid "&Manage" -msgstr "" +msgstr "Управление" #: src/effects/Effect.cpp:2935 msgid "Manage presets and options" -msgstr "" +msgstr "Управление параметрами и преднастройками" #. i18n-hint: The access key "&P" should be the same in #. "Stop &Playback" and "Start &Playback" #: src/effects/Effect.cpp:2946 src/effects/Effect.cpp:3698 #: src/effects/Effect.cpp:3708 src/effects/Effect.cpp:3710 msgid "Start &Playback" -msgstr "" +msgstr "Старт" #: src/effects/Effect.cpp:2947 msgid "Start and stop playback" -msgstr "" +msgstr "Старт/Стоп" #: src/effects/Effect.cpp:2954 src/effects/Effect.cpp:2971 #: src/effects/Effect.cpp:2973 msgid "Preview effect" -msgstr "" +msgstr "Прослушивание эффекта" #: src/effects/Effect.cpp:2975 msgid "&Preview effect" -msgstr "" +msgstr "Прослушивание эффекта" #: src/effects/Effect.cpp:2985 src/effects/Effect.cpp:2995 #: src/effects/Effect.cpp:2997 msgid "Skip &Backward" -msgstr "" +msgstr "Перемотать назад" #: src/effects/Effect.cpp:3001 msgid "Skip backward" -msgstr "" +msgstr "Перемотать назад" #: src/effects/Effect.cpp:3006 msgid "Skip &Forward" -msgstr "" +msgstr "Перемотать вперед" #: src/effects/Effect.cpp:3016 src/effects/Effect.cpp:3018 msgid "Skip &Foreward" -msgstr "" +msgstr "Перемотать вперед" #: src/effects/Effect.cpp:3022 msgid "Skip forward" -msgstr "" +msgstr "Перемотать вперед" #: src/effects/Effect.cpp:3028 msgid "Enable" -msgstr "" +msgstr "Включить" #: src/effects/Effect.cpp:3138 msgid "You must select audio in the project window." @@ -7431,11 +7428,11 @@ msgstr "" #: src/effects/Effect.cpp:3815 src/effects/Effect.cpp:3851 #: src/effects/Effect.cpp:3872 src/effects/Effect.cpp:3928 msgid "User Presets" -msgstr "" +msgstr "Настройки пользователя" #: src/effects/Effect.cpp:3230 msgid "Save Preset..." -msgstr "" +msgstr "Сохранить настройки..." #: src/effects/Effect.cpp:3234 src/effects/Effect.cpp:3243 #: src/effects/Effect.cpp:3484 src/export/ExportFFmpegDialogs.cpp:1405 @@ -7444,7 +7441,7 @@ msgstr "Удалить" #: src/effects/Effect.cpp:3252 msgid "Defaults" -msgstr "" +msgstr "По умолчанию" #: src/effects/Effect.cpp:3261 src/effects/Effect.cpp:3892 #: src/effects/Effect.cpp:3956 src/prefs/QualityPrefs.cpp:73 @@ -7456,15 +7453,15 @@ msgstr "Нет" #: src/effects/Effect.cpp:3856 src/effects/Effect.cpp:3884 #: src/effects/Effect.cpp:3942 msgid "Factory Presets" -msgstr "" +msgstr "Преднастройки" #: src/effects/Effect.cpp:3271 msgid "Import..." -msgstr "" +msgstr "Импорт..." #: src/effects/Effect.cpp:3272 msgid "Export..." -msgstr "" +msgstr "Экспорт..." #: src/effects/Effect.cpp:3274 src/widgets/Meter.cpp:714 #: src/widgets/Meter.cpp:1894 @@ -7512,11 +7509,11 @@ msgstr "Сохранить" #: src/effects/Effect.cpp:3510 msgid "Preset name:" -msgstr "" +msgstr "Имя настройки:" #: src/effects/Effect.cpp:3536 msgid "You must specify a name" -msgstr "" +msgstr "Вы должны задать имя" #: src/effects/Effect.cpp:3546 msgid "" @@ -7524,35 +7521,38 @@ msgid "" "\n" "Replace?" msgstr "" +"Настройка уже существует.\n" +"\n" +"Перезаписать?" #. i18n-hint: The access key "&P" should be the same in #. "Stop &Playback" and "Start &Playback" #: src/effects/Effect.cpp:3676 src/effects/Effect.cpp:3686 #: src/effects/Effect.cpp:3688 msgid "Stop &Playback" -msgstr "" +msgstr "Остановить воспроизведение" #: src/effects/Effect.cpp:3787 msgid "Select Preset" -msgstr "" +msgstr "Выбрать настройку" #: src/effects/Effect.cpp:3797 msgid "Type:" -msgstr "" +msgstr "Тип:" #: src/effects/Effect.cpp:3801 msgid "&Preset:" -msgstr "" +msgstr "Настрока:" #: src/effects/Effect.cpp:3825 src/effects/Effect.cpp:3860 #: src/effects/Effect.cpp:3904 src/effects/Effect.cpp:3964 msgid "Current Settings" -msgstr "" +msgstr "Текущие настройки" #: src/effects/Effect.cpp:3830 src/effects/Effect.cpp:3864 #: src/effects/Effect.cpp:3910 src/effects/Effect.cpp:3970 msgid "Factory Defaults" -msgstr "" +msgstr "Заводские по умолчанию" #: src/effects/EffectManager.cpp:152 #, c-format @@ -7575,11 +7575,11 @@ msgstr "" #: src/effects/EffectRack.cpp:79 msgid "Effects Rack" -msgstr "" +msgstr "Панель эффектов" #: src/effects/EffectRack.cpp:120 msgid "&Apply" -msgstr "" +msgstr "Применить" #: src/effects/EffectRack.cpp:122 msgid "Latency: 0" @@ -7607,7 +7607,7 @@ msgstr "" #: src/effects/EffectRack.cpp:215 msgid "Move Up" -msgstr "" +msgstr "Переместить вверх" #: src/effects/EffectRack.cpp:216 msgid "Move effect up in the rack" @@ -7615,7 +7615,7 @@ msgstr "" #: src/effects/EffectRack.cpp:222 msgid "Move Down" -msgstr "" +msgstr "Переместить вниз" #: src/effects/EffectRack.cpp:223 msgid "Move effect down in the rack" @@ -7696,9 +7696,8 @@ msgid "Track sample rate is too low for this effect." msgstr "" #: src/effects/Equalization.cpp:491 -#, fuzzy msgid "Effect Unavailable" -msgstr "Прослушивание недоступно" +msgstr "Эффект недоступен" #: src/effects/Equalization.cpp:647 src/effects/ScienFilter.cpp:403 msgid "+ dB" @@ -7742,7 +7741,7 @@ msgstr "Графический EQ" #: src/effects/Equalization.cpp:768 msgid "Interpolation type" -msgstr "" +msgstr "Тип интерполяции" #: src/effects/Equalization.cpp:777 msgid "Li&near Frequency Scale" @@ -7766,7 +7765,7 @@ msgstr "Выбрать кривую:" #: src/effects/Equalization.cpp:842 msgid "Select Curve" -msgstr "" +msgstr "Выбрать кривую" #: src/effects/Equalization.cpp:847 msgid "S&ave/Manage Curves..." @@ -7782,11 +7781,11 @@ msgstr "&Инвертировать" #: src/effects/Equalization.cpp:854 msgid "Show g&rid lines" -msgstr "" +msgstr "Линии сетки" #: src/effects/Equalization.cpp:855 msgid "Show grid lines" -msgstr "" +msgstr "Линии сетки" #: src/effects/Equalization.cpp:877 msgid "&Processing: " @@ -7848,7 +7847,7 @@ msgstr "" #: src/effects/Equalization.cpp:1778 msgid "Curve not found" -msgstr "" +msgstr "Кривая не найдена" #: src/effects/Equalization.cpp:3110 src/effects/Equalization.cpp:3115 msgid "Manage Curves List" @@ -8033,7 +8032,7 @@ msgstr "Плавное затухание" #: src/effects/FindClipping.cpp:61 msgid "Creates labels where clipping is detected" -msgstr "" +msgstr "Создает метку при фиксации перегрузки" #: src/effects/FindClipping.cpp:98 msgid "Clipping" @@ -8057,7 +8056,7 @@ msgstr "Недостаточно места для создания звуков #: src/effects/Invert.cpp:40 msgid "Flips the audio samples upside-down, reversing their polarity" -msgstr "" +msgstr "Переворачивает звуковые данные, меняя их полярность" #: src/effects/Invert.h:20 msgid "Invert" @@ -8104,11 +8103,11 @@ msgstr "Степень выравнивания:" #: src/effects/Leveller.cpp:221 msgid "Noise Threshold:" -msgstr "" +msgstr "Порог шума:" #: src/effects/LoadEffects.cpp:242 src/effects/LoadEffects.cpp:247 msgid "Builtin Effects" -msgstr "" +msgstr "Встроенные эффекты" #: src/effects/LoadEffects.cpp:252 #: src/effects/audiounits/AudioUnitEffect.cpp:124 @@ -8136,7 +8135,7 @@ msgstr "" #: src/effects/Noise.cpp:78 msgid "Generates one of three different types of noise" -msgstr "" +msgstr "Генерирует один из трех видов шума" #: src/effects/Noise.cpp:221 msgid "Noise type:" @@ -8234,7 +8233,7 @@ msgstr "Подавление шума" #: src/effects/NoiseReduction.cpp:1461 msgid "&Sensitivity:" -msgstr "" +msgstr "Чувствительность:" #: src/effects/NoiseReduction.cpp:1461 src/effects/NoiseRemoval.cpp:743 msgid "Sensitivity" @@ -8320,7 +8319,7 @@ msgstr "" #: src/effects/NoiseReduction.cpp:1738 msgid "Advanced Settings" -msgstr "" +msgstr "Дополнительные настройки" #: src/effects/NoiseReduction.cpp:1746 msgid "&Window types" @@ -9109,13 +9108,13 @@ msgstr "Конечное смещение высоты тона" #: src/effects/TimeScale.h:27 msgid "Time Scale" -msgstr "" +msgstr "Шкала времени" #: src/effects/ToneGen.cpp:44 src/prefs/SpectrogramSettings.cpp:148 #: src/prefs/WaveformSettings.cpp:155 src/widgets/Meter.cpp:1993 #: src/widgets/Meter.cpp:1994 msgid "Linear" -msgstr "Линейный" +msgstr "Линейная" #: src/effects/ToneGen.cpp:45 src/prefs/SpectrogramSettings.cpp:149 #: src/prefs/WaveformSettings.cpp:156 @@ -9797,9 +9796,8 @@ msgid "Error writing to file: \"%s\"" msgstr "" #: src/effects/VST/VSTEffect.cpp:3565 -#, fuzzy msgid "Error Saving Effect Presets" -msgstr "Ошибка при сохранении проекта" +msgstr "" #: src/effects/VST/VSTEffect.cpp:3686 #, c-format @@ -10120,9 +10118,8 @@ msgstr "" #: src/export/ExportFFmpegDialogs.cpp:498 #: src/export/ExportFFmpegDialogs.cpp:522 -#, fuzzy msgid "Error Saving FFmpeg Presets" -msgstr "Ошибка при сохранении проекта" +msgstr "" #: src/export/ExportFFmpegDialogs.cpp:568 #, c-format @@ -11531,7 +11528,7 @@ msgstr "Интерфейс" #: src/prefs/DevicePrefs.cpp:120 msgid "&Host:" -msgstr "" +msgstr "Движок:" #: src/prefs/DevicePrefs.cpp:127 msgid "Using:" @@ -11544,7 +11541,7 @@ msgstr "Воспроизведение" #: src/prefs/DevicePrefs.cpp:139 msgid "&Device:" -msgstr "" +msgstr "Устройство:" #: src/prefs/DevicePrefs.cpp:147 src/prefs/MidiIOPrefs.cpp:154 #: src/prefs/RecordingPrefs.cpp:46 src/toolbars/ControlToolBar.cpp:114 @@ -11553,11 +11550,11 @@ msgstr "Запись" #: src/prefs/DevicePrefs.cpp:152 msgid "De&vice:" -msgstr "" +msgstr "Устройство:" #: src/prefs/DevicePrefs.cpp:157 msgid "Cha&nnels:" -msgstr "" +msgstr "Каналы:" #: src/prefs/DevicePrefs.cpp:194 msgid "No audio interfaces" @@ -11622,12 +11619,12 @@ msgstr "Выберите расположение каталога для хра #: src/prefs/DirectoriesPrefs.cpp:191 msgid "unavailable - above location doesn't exist" -msgstr "" +msgstr "не доступно - указанная папка не существует" #: src/prefs/DirectoriesPrefs.cpp:208 #, c-format msgid "Directory %s is not suitable (at risk of being cleaned out)" -msgstr "" +msgstr "Папка %s не подходит (есть риск ее автоматической очитстки)" #: src/prefs/DirectoriesPrefs.cpp:216 #, c-format @@ -11669,7 +11666,7 @@ msgstr "Audio Unit" #: src/prefs/EffectsPrefs.cpp:100 msgid "Effect Options" -msgstr "Настройки эффекта" +msgstr "Параметры меню эффектов" #: src/prefs/EffectsPrefs.cpp:107 msgid "Sorted by Effect Name" @@ -11685,31 +11682,31 @@ msgstr "Упорядочено по типу и названию эффекта" #: src/prefs/EffectsPrefs.cpp:110 msgid "Grouped by Publisher" -msgstr "Сгруппировано разработчиком" +msgstr "Сгруппировано по разработчикам" #: src/prefs/EffectsPrefs.cpp:111 msgid "Grouped by Type" -msgstr "" +msgstr "Сгруппировано по типу" #: src/prefs/EffectsPrefs.cpp:119 msgid "Effects in menus are:" -msgstr "" +msgstr "Эффекты в меню показаны:" #: src/prefs/EffectsPrefs.cpp:126 msgid "Maximum effects per group (0 to disable):" -msgstr "" +msgstr "Макс.количество эффектов в группе (0 - откл.):" #: src/prefs/EffectsPrefs.cpp:140 msgid "Plugin Options" -msgstr "" +msgstr "Параметры плагинов" #: src/prefs/EffectsPrefs.cpp:142 msgid "Check for updated plugins when Audacity starts" -msgstr "" +msgstr "Проверять наличие обновлений плагинов при старте" #: src/prefs/EffectsPrefs.cpp:145 msgid "Rescan plugins next time Audacity is started" -msgstr "" +msgstr "Пересканировать плагины при следующем старте" #: src/prefs/EffectsPrefs.cpp:153 msgid "Instruction Set" @@ -11717,7 +11714,7 @@ msgstr "Набор инструкций" #: src/prefs/EffectsPrefs.cpp:155 msgid "&Use SSE/SSE2/.../AVX" -msgstr "" +msgstr "Использовать SSE/SSE2/.../AVX" #: src/prefs/ExtImportPrefs.cpp:60 msgid "Extended Import" @@ -11725,7 +11722,7 @@ msgstr "Правила импорта" #: src/prefs/ExtImportPrefs.cpp:87 msgid "A&ttempt to use filter in OpenFile dialog first" -msgstr "" +msgstr "Использовать фильтр в диалоге открытия файла" #: src/prefs/ExtImportPrefs.cpp:90 msgid "Rules to choose import filters" @@ -11801,23 +11798,23 @@ msgstr "-36 Дб (не для правки сигнала с большой ам #: src/prefs/GUIPrefs.cpp:63 msgid "-48 dB (PCM range of 8 bit samples)" -msgstr "-48 Дб (диапазон PCM при 8 разрядах)" +msgstr "-48 Дб (8 разрядный диапазон PCM)" #: src/prefs/GUIPrefs.cpp:64 msgid "-60 dB (PCM range of 10 bit samples)" -msgstr "-60 Дб (диапазон PCM при 10-разрядных выборках)" +msgstr "-60 Дб (10 разрядный диапазон PCM)" #: src/prefs/GUIPrefs.cpp:65 msgid "-72 dB (PCM range of 12 bit samples)" -msgstr "" +msgstr "-72 Дб (12 разрядный диапазон PCM)" #: src/prefs/GUIPrefs.cpp:66 msgid "-84 dB (PCM range of 14 bit samples)" -msgstr "" +msgstr "-84 Дб (14 разрядный диапазон PCM)" #: src/prefs/GUIPrefs.cpp:67 msgid "-96 dB (PCM range of 16 bit samples)" -msgstr "-96 Дб (диапазон PCM при 16 разрядах)" +msgstr "-96 Дб (16 разрядный диапазон PCM)" #: src/prefs/GUIPrefs.cpp:68 msgid "-120 dB (approximate limit of human hearing)" @@ -11825,7 +11822,7 @@ msgstr "-120 Дб (предел слышимости человеческого #: src/prefs/GUIPrefs.cpp:69 msgid "-145 dB (PCM range of 24 bit samples)" -msgstr "-145 Дб (диапазон PCM при 24 разрядах)" +msgstr "-145 Дб (24 разрядный диапазон PCM)" #: src/prefs/GUIPrefs.cpp:81 msgid "Local" @@ -11842,7 +11839,7 @@ msgstr "Отображение" #: src/prefs/GUIPrefs.cpp:107 msgid "&Ergonomic order of Transport Toolbar buttons" -msgstr "&Эргономичное расположение кнопок транспорта на панели" +msgstr "&Эргономичное расположение кнопок управления на панели" #: src/prefs/GUIPrefs.cpp:110 msgid "S&how 'How to Get Help' dialog box at program start up" @@ -11850,7 +11847,7 @@ msgstr "&Показывать диалог «Как получить помощ #: src/prefs/GUIPrefs.cpp:119 msgid "Meter dB &range:" -msgstr "" +msgstr "&Диапазон (Дб):" #: src/prefs/GUIPrefs.cpp:126 msgid "&Language:" @@ -11866,11 +11863,11 @@ msgstr "Извещать звуком о завершении &длительн #: src/prefs/GUIPrefs.cpp:149 msgid "Re&tain labels if selection snaps to a label edge" -msgstr "" +msgstr "Сохранять метки при совпадении границ выделения с меткой" #: src/prefs/GUIPrefs.cpp:154 msgid "&Display a mono channel as virtual stereo" -msgstr "" +msgstr "Показывать моно каналы как виртуальное стерео" #: src/prefs/ImportExportPrefs.cpp:28 msgid "Import / Export" @@ -11891,7 +11888,7 @@ msgstr "&Читать несжатые звуковые данные напря #: src/prefs/ImportExportPrefs.cpp:64 msgid "&Normalize all tracks in project" -msgstr "&Нормализовывать все дорожки в проекте" +msgstr "&Нормализовать все дорожки в проекте" #: src/prefs/ImportExportPrefs.cpp:70 msgid "When exporting tracks to an audio file" @@ -11908,9 +11905,8 @@ msgstr "" "файла)" #: src/prefs/ImportExportPrefs.cpp:81 -#, fuzzy msgid "S&how Metadata Tags editor prior to export step" -msgstr "Открывать редактор &метаданных перед экспортом" +msgstr "Открывать редактор тэгов перед экспортом" #: src/prefs/ImportExportPrefs.cpp:90 msgid "When exporting track to an Allegro (.gro) file" @@ -11938,40 +11934,40 @@ msgstr "Создайте новый проект для изменения го #: src/prefs/KeyConfigPrefs.cpp:155 src/prefs/KeyConfigPrefs.cpp:604 msgid "&Hotkey:" -msgstr "" +msgstr "Горячая клавиша:" #: src/prefs/KeyConfigPrefs.cpp:170 src/prefs/KeyConfigPrefs.cpp:746 #: src/prefs/KeyConfigPrefs.cpp:758 msgid "Key Bindings" -msgstr "Клавиатурные комбинации" +msgstr "Клавиатурные сокращения" #: src/prefs/KeyConfigPrefs.cpp:178 msgid "View by:" -msgstr "" +msgstr "Вид:" #: src/prefs/KeyConfigPrefs.cpp:181 msgid "&Tree" -msgstr "" +msgstr "Дерево" #: src/prefs/KeyConfigPrefs.cpp:182 msgid "View by tree" -msgstr "" +msgstr "Дерево" #: src/prefs/KeyConfigPrefs.cpp:183 msgid "&Name" -msgstr "" +msgstr "Имя" #: src/prefs/KeyConfigPrefs.cpp:184 msgid "View by name" -msgstr "" +msgstr "По имени" #: src/prefs/KeyConfigPrefs.cpp:185 msgid "&Key" -msgstr "" +msgstr "Клавиша" #: src/prefs/KeyConfigPrefs.cpp:186 msgid "View by key" -msgstr "" +msgstr "По клавише" #: src/prefs/KeyConfigPrefs.cpp:200 src/prefs/KeyConfigPrefs.cpp:594 #: src/prefs/KeyConfigPrefs.cpp:599 @@ -11984,12 +11980,12 @@ msgstr "Комбинации" #: src/prefs/KeyConfigPrefs.cpp:255 msgid "Short cut" -msgstr "" +msgstr "Клавиатурное сокращение" #. i18n-hint: (verb) #: src/prefs/KeyConfigPrefs.cpp:272 msgid "&Set" -msgstr "" +msgstr "Установить" #: src/prefs/KeyConfigPrefs.cpp:278 src/prefs/KeyConfigPrefs.cpp:786 msgid "Note: Pressing Cmd+Q will quit. All other keys are valid." @@ -12008,7 +12004,7 @@ msgstr "Выберите XML-файл, содержащий клавиатурн #: src/prefs/KeyConfigPrefs.cpp:350 src/prefs/KeyConfigPrefs.cpp:922 msgid "Error Importing Keyboard Shortcuts" -msgstr "" +msgstr "Ошибка загрузки клавиатурных комбинаций" #: src/prefs/KeyConfigPrefs.cpp:363 src/prefs/KeyConfigPrefs.cpp:935 msgid "Export Keyboard Shortcuts As:" @@ -12016,7 +12012,7 @@ msgstr "Экспортировать клавиатурные комбинаци #: src/prefs/KeyConfigPrefs.cpp:380 src/prefs/KeyConfigPrefs.cpp:952 msgid "Error Exporting Keyboard Shortcuts" -msgstr "" +msgstr "Ошибка экспорта клавиатурный сокращений" #: src/prefs/KeyConfigPrefs.cpp:508 msgid "You may not assign a key to this entry" @@ -12118,7 +12114,7 @@ msgstr "Ска&чать" #: src/prefs/LibraryPrefs.cpp:153 msgid "Allow &background on-demand loading" -msgstr "" +msgstr "Разрешить фоновую загрузку по требованию" #: src/prefs/LibraryPrefs.cpp:209 msgid "" @@ -12134,9 +12130,8 @@ msgstr "Устройства MIDI" #. i18n-hint: (noun) #: src/prefs/MidiIOPrefs.cpp:123 -#, fuzzy msgid "Host:" -msgstr "Драйвер" +msgstr "" #: src/prefs/MidiIOPrefs.cpp:130 msgid "Using: PortMidi" @@ -12196,11 +12191,11 @@ msgstr "\"Новый\": вы еще не выбрали нужный вариа #: src/prefs/ModulePrefs.cpp:111 msgid "Changes to these settings only take effect when Audacity starts up." -msgstr "" +msgstr "Изменения этих параметров вступит в силу только после перезапуска." #: src/prefs/ModulePrefs.cpp:122 msgid "No modules were found" -msgstr "" +msgstr "Модули не найдены" #: src/prefs/MousePrefs.cpp:59 msgid "Ctrl" @@ -12321,22 +12316,20 @@ msgid "Zoom default" msgstr "Масштаб по умолчанию" #: src/prefs/MousePrefs.cpp:131 -#, fuzzy msgid "Move clip left/right or between tracks" -msgstr "Переместить область из одной дорожки в другую" +msgstr "Переместить фрагмент из одной дорожки в другую" #: src/prefs/MousePrefs.cpp:132 msgid "Shift-Left-Drag" msgstr "Shift-Перетаскивание левой клавишей" #: src/prefs/MousePrefs.cpp:132 -#, fuzzy msgid "Move all clips in track left/right" -msgstr "Сместить во времени все области в дорожке" +msgstr "Сместить во времени все фрагменты в дорожке" #: src/prefs/MousePrefs.cpp:133 src/prefs/MousePrefs.cpp:143 msgid "-Left-Drag" -msgstr "" +msgstr "Перетаскивание левой клавишей" #: src/prefs/MousePrefs.cpp:133 msgid "Move clip up/down between tracks" @@ -12390,27 +12383,24 @@ msgid "Any" msgstr "Любой" #: src/prefs/MousePrefs.cpp:157 -#, fuzzy msgid "Scroll tracks up or down" -msgstr "Прокрутить вверх или вниз" +msgstr "Прокрутить дорожки вверх/вниз" #: src/prefs/MousePrefs.cpp:158 msgid "Shift-Wheel-Rotate" msgstr "Shift-Вращение колесом" #: src/prefs/MousePrefs.cpp:158 -#, fuzzy msgid "Scroll waveform" -msgstr "Прокрутка влево или вправо" +msgstr "Прокрутить Волну вправо/влево" #: src/prefs/MousePrefs.cpp:159 msgid "-Wheel-Rotate" msgstr "-Вращение-колесом-мыши" #: src/prefs/MousePrefs.cpp:159 -#, fuzzy msgid "Zoom waveform in or out" -msgstr "Приблизить по точке" +msgstr "Увеличить/уменьшить " #: src/prefs/MousePrefs.cpp:160 #, fuzzy @@ -12418,9 +12408,8 @@ msgid "-Shift-Wheel-Rotate" msgstr "Shift-Вращение колесом" #: src/prefs/MousePrefs.cpp:160 -#, fuzzy msgid "Vertical Scale Waveform (dB) range" -msgstr "Осциллограммы dB &диапазона" +msgstr "" #: src/prefs/PlaybackPrefs.cpp:57 msgid "Effects Preview" @@ -12552,16 +12541,14 @@ msgstr "" "мониторинге" #: src/prefs/RecordingPrefs.cpp:84 -#, fuzzy msgid "&Software Playthrough: Listen to input while recording or monitoring" msgstr "" -"&Программное сквозное воспроизведение: новая дорожка слышна при её записи " -"или мониторинге" +"Программное сквозное воспроизведение: новая дорожка слышна при её записи или " +"мониторинге" #: src/prefs/RecordingPrefs.cpp:88 -#, fuzzy msgid "(uncheck when recording computer playback)" -msgstr "(не использовать при записи стереомикса)" +msgstr "(не использовать при записи звука с компьютера)" #: src/prefs/RecordingPrefs.cpp:93 msgid "Latency" @@ -12596,14 +12583,12 @@ msgid "Sound Activation Le&vel (dB):" msgstr "&Уровень громкости для активации (Дб):" #: src/prefs/RecordingPrefs.cpp:138 -#, fuzzy msgid "Naming newly recorded tracks" -msgstr "Микширование и сведение дорожек" +msgstr "Наименование новых записей" #: src/prefs/RecordingPrefs.cpp:142 -#, fuzzy msgid "Use Custom Track &Name" -msgstr "Название дорожки" +msgstr "Свое название дорожки" #: src/prefs/RecordingPrefs.cpp:148 #, fuzzy @@ -12611,55 +12596,53 @@ msgid "Recorded_Audio" msgstr "Записанный звук" #: src/prefs/RecordingPrefs.cpp:150 -#, fuzzy msgid "Custom name text" -msgstr "Экспорт через FFmpeg" +msgstr "Текст названия" #: src/prefs/RecordingPrefs.cpp:155 -#, fuzzy msgid "Add &Track Number" -msgstr "Номер дорожки" +msgstr "Добавить номер дорожки" #: src/prefs/RecordingPrefs.cpp:159 msgid "Add System &Date" -msgstr "" +msgstr "Добавить системную дату" #: src/prefs/RecordingPrefs.cpp:163 msgid "Add System T&ime" -msgstr "" +msgstr "Добавить системное время" #: src/prefs/RecordingPrefs.cpp:170 msgid "Automated Recording Level Adjustment" -msgstr "" +msgstr "Автоматическая коррекция уровня записи." #: src/prefs/RecordingPrefs.cpp:172 msgid "Enable Automated Recording Level Adjustment." -msgstr "" +msgstr "Включить автоматическую коррекцию уровня записи." #. i18n-hint: Desired maximum (peak) volume for sound #: src/prefs/RecordingPrefs.cpp:181 msgid "Target Peak:" -msgstr "" +msgstr "Целевой пик:" #: src/prefs/RecordingPrefs.cpp:187 msgid "Within:" -msgstr "" +msgstr "Внутри:" #: src/prefs/RecordingPrefs.cpp:197 msgid "Analysis Time:" -msgstr "" +msgstr "Время анализа:" #: src/prefs/RecordingPrefs.cpp:201 msgid "milliseconds (time of one analysis)" -msgstr "" +msgstr "мсек. (время одного анализа)" #: src/prefs/RecordingPrefs.cpp:203 msgid "Number of consecutive analysis:" -msgstr "" +msgstr "Число последовательных анализов:" #: src/prefs/RecordingPrefs.cpp:207 msgid "0 means endless" -msgstr "" +msgstr "0-бесконечный" #. i18n-hint: The name of a frequency scale in psychoacoustics #: src/prefs/SpectrogramSettings.cpp:151 @@ -12742,13 +12725,12 @@ msgstr "32768 — наиболее узкополосный" #. i18n-hint: use is a verb #: src/prefs/SpectrumPrefs.cpp:167 src/prefs/WaveformPrefs.cpp:83 -#, fuzzy msgid "&Use Preferences" -msgstr "Используйте настройки" +msgstr "Использовать настройки" #: src/prefs/SpectrumPrefs.cpp:174 src/prefs/WaveformPrefs.cpp:91 msgid "S&cale" -msgstr "" +msgstr "Шкала" #: src/prefs/SpectrumPrefs.cpp:179 msgid "Mi&nimum Frequency (Hz):" @@ -12784,23 +12766,23 @@ msgstr "Алгоритм" #: src/prefs/SpectrumPrefs.cpp:224 msgid "A&lgorithm" -msgstr "" +msgstr "Алгоритм" #: src/prefs/SpectrumPrefs.cpp:228 msgid "Window &size:" -msgstr "" +msgstr "Размер окна:" #: src/prefs/SpectrumPrefs.cpp:233 msgid "Window &type:" -msgstr "" +msgstr "Тип окна:" #: src/prefs/SpectrumPrefs.cpp:240 msgid "&Zero padding factor" -msgstr "" +msgstr "Отступ от нуля" #: src/prefs/SpectrumPrefs.cpp:251 msgid "Ena&ble Spectral Selection" -msgstr "" +msgstr "Включить выделение диапазона" #: src/prefs/SpectrumPrefs.cpp:256 msgid "Show a grid along the &Y-axis" @@ -12954,57 +12936,49 @@ msgid "Simple" msgstr "Простая" #: src/prefs/TracksPrefs.cpp:76 -#, fuzzy msgid "Multi-track" -msgstr "Универсальный" +msgstr "Универсальная" #: src/prefs/TracksPrefs.cpp:86 msgid "Waveform (dB)" msgstr "Волна (Дб)" #: src/prefs/TracksPrefs.cpp:89 -#, fuzzy msgid "Spectrogram" -msgstr "&Спектрограмма" +msgstr "Спектрограмма" #: src/prefs/TracksPrefs.cpp:107 msgid "&Pinned Recording/Playback head" -msgstr "" +msgstr "Закрепленный маркер записи/воспроизведения" #: src/prefs/TracksPrefs.cpp:110 -#, fuzzy msgid "&Update display when Recording/Playback head unpinned" -msgstr "Обновл&ять вид при воспроизведении" +msgstr "Обновл&ять вид при открепленном маркере записи/воспроизведения" #: src/prefs/TracksPrefs.cpp:113 msgid "Automatically &fit tracks vertically zoomed" msgstr "&Автоматически умещать дорожки по вертикали" #: src/prefs/TracksPrefs.cpp:121 -#, fuzzy msgid "Default &view mode:" -msgstr "&Режим отображения по умолчанию:" +msgstr "Вид по умолчанию" #: src/prefs/TracksPrefs.cpp:128 -#, fuzzy msgid "Default audio track &name:" -msgstr "Создана новая звуковая дорожка" +msgstr "Имя дорожки по умолчанию" #: src/prefs/TracksPrefs.cpp:135 -#, fuzzy msgid "Sho&w audio track name as overlay" msgstr "Показывать &название дорожки над волновой формой сигнала" #: src/prefs/TracksPrefs.cpp:143 -#, fuzzy msgid "&Select then act on entire project, if no audio selected" msgstr "При отсутствии &выделения выделять всё" #. i18n-hint: cut-lines are a lines indicating where to cut. #: src/prefs/TracksPrefs.cpp:147 -#, fuzzy msgid "Enable cut &lines" -msgstr "Показывать &линии отреза" +msgstr "Показывать линии отреза" #: src/prefs/TracksPrefs.cpp:150 msgid "Enable &dragging of left and right selection edges" @@ -13012,19 +12986,19 @@ msgstr "&Разрешить перетаскивание краев выделе #: src/prefs/TracksPrefs.cpp:153 msgid "\"Move track focus\" c&ycles repeatedly through tracks" -msgstr "&Фокус перемещается по дорожкам циклически" +msgstr "&Перемещать фокус по дорожкам циклически" #: src/prefs/TracksPrefs.cpp:156 msgid "Editing a clip can &move other clips" -msgstr "&При редактировании одного клипа другие могут быть пермещены" +msgstr "&Редактирование одного фрагмента может перемещать другие фрагменты" #: src/prefs/TracksPrefs.cpp:159 msgid "&Type to create a label" -msgstr "" +msgstr "Создавать метку при наборе с клавиатуры" #: src/prefs/TracksPrefs.cpp:163 msgid "Enable scrolling left of &zero" -msgstr "Позволить прокрутку слева от &нуля" +msgstr "Разрешить прокрутку слева от нуля" #: src/prefs/TracksPrefs.cpp:172 msgid "Solo &Button:" @@ -13060,11 +13034,11 @@ msgstr "Сведении &в стерео при экспорте" #: src/prefs/WarningsPrefs.cpp:72 msgid "Mixing down on export (&Custom FFmpeg or external program)" -msgstr "" +msgstr "Сведении при экспорте (FFmpeg или во внешнюю программу)" #: src/prefs/WarningsPrefs.cpp:75 msgid "&Importing uncompressed audio files" -msgstr "&Импорте несжатых звуковых данных" +msgstr "&Импорт несжатых звуковых данных" #: src/prefs/WaveformPrefs.cpp:29 msgid "Waveforms" @@ -13090,7 +13064,7 @@ msgstr "Приостановлено" #: src/toolbars/ControlToolBar.cpp:171 msgid "Pause" -msgstr "Приостановить" +msgstr "Пауза" #: src/toolbars/ControlToolBar.cpp:188 msgid "Skip to Start" @@ -13101,19 +13075,16 @@ msgid "Skip to End" msgstr "Перейти к концу дорожки" #: src/toolbars/ControlToolBar.cpp:222 -#, fuzzy msgid "Loop Play" -msgstr "В&оспроизвести с повторением" +msgstr "Циклическое в&оспроизведение" #: src/toolbars/ControlToolBar.cpp:228 -#, fuzzy msgid "Append Record" -msgstr "До&писать" +msgstr "Дописать в конец" #: src/toolbars/ControlToolBar.cpp:231 -#, fuzzy msgid "Record Below" -msgstr "Индикатор зап." +msgstr "Записать в новую дорожку" #: src/toolbars/ControlToolBar.cpp:1121 #, fuzzy @@ -13184,7 +13155,7 @@ msgstr "Обрезать аудиоданные вне выделенного" #: src/toolbars/EditToolBar.cpp:139 msgid "Silence audio selection" -msgstr "" +msgstr "Заполнить тишиной отмеченное" #: src/toolbars/EditToolBar.cpp:152 src/toolbars/EditToolBar.cpp:215 msgid "Sync-Lock Tracks" @@ -13317,9 +13288,8 @@ msgid "Seek" msgstr "" #: src/toolbars/ScrubbingToolBar.cpp:115 src/tracks/ui/Scrubbing.cpp:248 -#, fuzzy msgid "Scrub Ruler" -msgstr "Линейка" +msgstr "Scrub-линейка" #: src/toolbars/ScrubbingToolBar.cpp:126 src/tracks/ui/Scrubbing.cpp:238 msgid "Scrubbing" @@ -13330,14 +13300,12 @@ msgstr "" #. "Seeking" is normal speed playback but with skips #. #: src/toolbars/ScrubbingToolBar.cpp:159 -#, fuzzy msgid "Stop Scrubbing" -msgstr "Остановить скрипт" +msgstr "" #: src/toolbars/ScrubbingToolBar.cpp:160 -#, fuzzy msgid "Start Scrubbing" -msgstr "Запустить скрипт" +msgstr "" #. i18n-hint: These commands assist the user in finding a sound by ear. ... #. "Scrubbing" is variable-speed playback, ... @@ -13348,17 +13316,16 @@ msgid "Stop Seeking" msgstr "" #: src/toolbars/ScrubbingToolBar.cpp:171 -#, fuzzy msgid "Start Seeking" -msgstr "Включить мониторинг" +msgstr "" #: src/toolbars/ScrubbingToolBar.cpp:177 msgid "Hide Scrub Ruler" -msgstr "" +msgstr "Скрыть Scrub-линейку" #: src/toolbars/ScrubbingToolBar.cpp:178 msgid "Show Scrub Ruler" -msgstr "" +msgstr "Показать Scrub-линейку" #: src/toolbars/SelectionBar.cpp:88 src/toolbars/SelectionBar.cpp:303 msgid "Selection" @@ -13514,14 +13481,12 @@ msgid "Seeking" msgstr "" #: src/tracks/ui/Scrubbing.cpp:963 -#, fuzzy msgid "Move mouse pointer to Seek" -msgstr "Переместить активную дорожку в начало" +msgstr "" #: src/tracks/ui/Scrubbing.cpp:965 -#, fuzzy msgid "Move mouse pointer to Scrub" -msgstr "Переместить активную дорожку в конец" +msgstr "" #: src/tracks/ui/Scrubbing.cpp:994 msgid "Scru&bbing" @@ -13636,14 +13601,12 @@ msgid "Start Monitoring" msgstr "Включить мониторинг" #: src/widgets/Meter.cpp:1939 -#, fuzzy msgid "Recording Meter Options" -msgstr "Индикатор записи" +msgstr "Настройки индикатора записи" #: src/widgets/Meter.cpp:1939 -#, fuzzy msgid "Playback Meter Options" -msgstr "Индикатор воспроизведения" +msgstr "Настройки индикатора воспроизведения" #: src/widgets/Meter.cpp:1949 msgid "Refresh Rate" @@ -14014,9 +13977,8 @@ msgid "NaN" msgstr "NaN" #: src/widgets/numformatter.cpp:146 -#, fuzzy msgid "Infinity" -msgstr "-Бесконечность" +msgstr "Бесконечность" #: src/widgets/numformatter.cpp:150 msgid "-Infinity" @@ -14035,48 +13997,40 @@ msgid "Cancel" msgstr "Отменить" #: src/widgets/ProgressDialog.cpp:1507 -#, fuzzy msgid "Are you sure you wish to cancel?" -msgstr "Вы действительно хотите удалить %s?" +msgstr "Вы действительно хотите отменить?" #: src/widgets/ProgressDialog.cpp:1507 -#, fuzzy msgid "Confirm Cancel" -msgstr "Подтверждение удаления" +msgstr "Подтверждение отмены" #: src/widgets/ProgressDialog.cpp:1516 -#, fuzzy msgid "Are you sure you wish to stop?" -msgstr "Вы действительно хотите удалить %s?" +msgstr "Вы действительно хотите остановить?" #: src/widgets/ProgressDialog.cpp:1516 -#, fuzzy msgid "Confirm Stop" -msgstr "Подтверждение" +msgstr "Подтверждение остановки" #: src/widgets/ProgressDialog.cpp:1526 -#, fuzzy msgid "Are you sure you wish to close?" -msgstr "Вы действительно хотите удалить %s?" +msgstr "Вы действительно хотите закрыть?" #: src/widgets/ProgressDialog.cpp:1526 -#, fuzzy msgid "Confirm Close" -msgstr "Подтверждение" +msgstr "Подтверждение закрытия" #: src/widgets/Ruler.cpp:1920 msgid "Timeline" -msgstr "Временная шкала" +msgstr "Шкала времени" #: src/widgets/Ruler.cpp:2085 -#, fuzzy msgid "Click or drag to begin Seek" -msgstr "Щёлкните и перетащите для редактирования сэмплов" +msgstr "Щёлкните и перетащите для ручного поиска" #: src/widgets/Ruler.cpp:2087 -#, fuzzy msgid "Click or drag to begin Scrub" -msgstr "Кликните и протащите для изменения размеров панели" +msgstr "Щёлкните и перетащите для ручного поиска" #: src/widgets/Ruler.cpp:2089 msgid "Click & move to Scrub. Click & drag to Seek." @@ -14116,11 +14070,11 @@ msgstr "Быстрое воспроизведение включено" #: src/widgets/Ruler.cpp:2840 msgid "Pinned Record/Play head" -msgstr "" +msgstr "Закрепленный маркер записи/воспроизведения" #: src/widgets/Ruler.cpp:2841 msgid "Unpinned Record/Play head" -msgstr "" +msgstr "Открепленный маркер записи/воспроизведения" #: src/widgets/Ruler.cpp:2881 msgid "Disable Quick-Play" @@ -14164,12 +14118,11 @@ msgstr "Разблокировать область воспроизведени #: src/widgets/Ruler.cpp:2913 msgid "Disable Scrub Ruler" -msgstr "" +msgstr "Скрыть Scrub-линейку" #: src/widgets/Ruler.cpp:2915 -#, fuzzy msgid "Enable Scrub Ruler" -msgstr "Показывать &линии отреза" +msgstr "Показать Scrub-линейку" #: src/widgets/valnum.cpp:94 msgid "Validation error" @@ -14184,9 +14137,9 @@ msgid "Malformed number" msgstr "Неправильно сформированный номер" #: src/widgets/valnum.cpp:376 -#, fuzzy, c-format +#, c-format msgid "Not in range %d to %d" -msgstr "Не в диапазоне" +msgstr "Не в диапазоне от %d до %d" #: src/widgets/valnum.cpp:492 msgid "Value overflow" @@ -14197,19 +14150,19 @@ msgid "Too many decimal digits" msgstr "Слишком много разрядов" #: src/widgets/valnum.cpp:510 -#, fuzzy, c-format +#, c-format msgid "Value not in range: %s to %s" -msgstr "Значение не в диапазоне: от %.*f до %.*f" +msgstr "Значение не в диапазоне: от %s до %s" #: src/widgets/valnum.cpp:515 -#, fuzzy, c-format +#, c-format msgid "Value must not be less than %s" -msgstr "Значение не должно быть меньше, чем %.*f" +msgstr "Значение не должно быть меньше, чем %s" #: src/widgets/valnum.cpp:519 -#, fuzzy, c-format +#, c-format msgid "Value must not be greather than %s" -msgstr "Значение не должно быть больше, чем %.*f" +msgstr "Значение не должно быть больше, чем %s" #: src/widgets/valnum.cpp:536 msgid "e" @@ -14229,12 +14182,31 @@ msgstr "Ошибка: %hs в строке %lu" msgid "Could not load file: \"%s\"" msgstr "Не удалось загрузить файл: \"%s\"" +#~ msgid "Save Compressed Copy of Project..." +#~ msgstr "Сохранить сжатую копию проекта..." + +#~ msgid "Edit MetaData..." +#~ msgstr "Изменить теги..." + +#~ msgid "Export MIDI..." +#~ msgstr "Экспортировать MIDI..." + #~ msgid "Re&gion Save" #~ msgstr "&Сохранить область" #~ msgid "Regio&n Restore" #~ msgstr "Восстановить об&ласть" +#, fuzzy +#~ msgid "Expand All Tracks" +#~ msgstr "Развернуть все дорожки" + +#~ msgid "Add Label at Selection" +#~ msgstr "Добавить метку к выделению" + +#~ msgid "Add Label at Playback Position" +#~ msgstr "Добавить метку в позицию воспроизведения" + #~ msgid "Couldn't write to file \"%s\": %s" #~ msgstr "Не удалось записать в файл \"%s\": %s" @@ -14243,7 +14215,11 @@ msgstr "Не удалось загрузить файл: \"%s\"" #, fuzzy #~ msgid "Edit Metadata Tags for Export" -#~ msgstr "Свойства меток метаданных" +#~ msgstr "Изменить тэги для экспорта" + +#, fuzzy +#~ msgid "Default view mode:" +#~ msgstr "Режим отображения по умолчанию:" #~ msgid "Error Flushing File" #~ msgstr "Ошибка при очистке файла" @@ -14295,7 +14271,7 @@ msgstr "Не удалось загрузить файл: \"%s\"" #~ msgstr "Журнал отмены действий" #~ msgid "Edit Me&tadata..." -#~ msgstr "Свойства ме&таданных..." +#~ msgstr "Изменить тэги..." #~ msgid "Edit Metadata" #~ msgstr "Свойства метаданных" From f62062aa3e4d33001e8c57d24ccbd6215a916fd8 Mon Sep 17 00:00:00 2001 From: James Crook Date: Wed, 22 Mar 2017 17:48:22 +0000 Subject: [PATCH 48/91] Update Catalan Translation by Robert Gelonch --- locale/ca.po | 549 ++++++++++++++++++++++----------------------------- 1 file changed, 231 insertions(+), 318 deletions(-) diff --git a/locale/ca.po b/locale/ca.po index 052df8606..fd7c4bb9e 100644 --- a/locale/ca.po +++ b/locale/ca.po @@ -1,26 +1,26 @@ # Copyright (C) 2007 Free Software Foundation, Inc. # Francesc Busquets , 2007. -# Robert Antoni Buj Gelonch , 2016. +# Robert Antoni Buj Gelonch , 2016-2017. # msgid "" msgstr "" "Project-Id-Version: audacity 2.1.2\n" "Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n" "POT-Creation-Date: 2017-03-18 18:41+0000\n" -"PO-Revision-Date: 2016-10-18 19:24+0200\n" +"PO-Revision-Date: 2017-03-21 09:59+0100\n" "Last-Translator: Robert Antoni Buj Gelonch \n" "Language-Team: Catalan \n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.10\n" +"X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: lib-src/FileDialog/gtk/FileDialogPrivate.cpp:75 #, c-format msgid "File '%s' already exists, do you really want to overwrite it?" -msgstr "Ja existeix un fitxer anomenat '%s'. Voleu sobreescriure'l?" +msgstr "Ja existeix el fitxer '%s'. Voleu sobreescriure'l?" #: lib-src/FileDialog/gtk/FileDialogPrivate.cpp:78 src/LangChoice.cpp:135 msgid "Confirm" @@ -34,17 +34,16 @@ msgstr "Seleccioneu un fitxer existent." #: src/AutoRecovery.cpp:195 src/Menus.cpp:4294 src/Menus.cpp:4306 #: src/Menus.cpp:7005 src/Menus.cpp:7084 src/Project.cpp:3124 #: src/Project.cpp:5118 src/Project.cpp:5137 src/TimerRecordDialog.cpp:471 -#: src/TimerRecordDialog.cpp:649 src/TrackPanel.cpp:8489 -#: src/WaveTrack.cpp:1316 src/WaveTrack.cpp:1335 src/WaveTrack.cpp:2487 -#: src/effects/Contrast.cpp:56 src/effects/Contrast.cpp:75 -#: src/effects/Contrast.cpp:82 src/effects/Contrast.cpp:96 -#: src/effects/Effect.cpp:2584 src/effects/Generator.cpp:59 -#: src/effects/nyquist/Nyquist.cpp:411 src/export/ExportFFmpeg.cpp:842 -#: src/export/ExportMP2.cpp:229 src/prefs/DirectoriesPrefs.cpp:210 -#: src/prefs/DirectoriesPrefs.cpp:239 src/prefs/KeyConfigPrefs.cpp:509 -#: src/prefs/KeyConfigPrefs.cpp:523 src/prefs/KeyConfigPrefs.cpp:548 -#: src/prefs/KeyConfigPrefs.cpp:1038 src/toolbars/ControlToolBar.cpp:686 -#: src/toolbars/ControlToolBar.cpp:1122 +#: src/TimerRecordDialog.cpp:649 src/TrackPanel.cpp:8489 src/WaveTrack.cpp:1316 +#: src/WaveTrack.cpp:1335 src/WaveTrack.cpp:2487 src/effects/Contrast.cpp:56 +#: src/effects/Contrast.cpp:75 src/effects/Contrast.cpp:82 +#: src/effects/Contrast.cpp:96 src/effects/Effect.cpp:2584 +#: src/effects/Generator.cpp:59 src/effects/nyquist/Nyquist.cpp:411 +#: src/export/ExportFFmpeg.cpp:842 src/export/ExportMP2.cpp:229 +#: src/prefs/DirectoriesPrefs.cpp:210 src/prefs/DirectoriesPrefs.cpp:239 +#: src/prefs/KeyConfigPrefs.cpp:509 src/prefs/KeyConfigPrefs.cpp:523 +#: src/prefs/KeyConfigPrefs.cpp:548 src/prefs/KeyConfigPrefs.cpp:1038 +#: src/toolbars/ControlToolBar.cpp:686 src/toolbars/ControlToolBar.cpp:1122 msgid "Error" msgstr "Error" @@ -119,7 +118,7 @@ msgstr "&Vés a" #: lib-src/mod-nyq-bench/NyqBench.cpp:769 msgid "Select &Font..." -msgstr "Selecciona el tipus de &lletra..." +msgstr "Selecciona la &lletra..." #: lib-src/mod-nyq-bench/NyqBench.cpp:771 msgid "Split &Vertically" @@ -174,14 +173,12 @@ msgstr "Script" msgid "Output" msgstr "Sortida" -#: lib-src/mod-nyq-bench/NyqBench.cpp:1051 -#: src/effects/nyquist/Nyquist.cpp:2214 +#: lib-src/mod-nyq-bench/NyqBench.cpp:1051 src/effects/nyquist/Nyquist.cpp:2214 msgid "Load Nyquist script" msgstr "Carrega l'script Nyquist" #: lib-src/mod-nyq-bench/NyqBench.cpp:1054 -#: lib-src/mod-nyq-bench/NyqBench.cpp:1100 -#: src/effects/nyquist/Nyquist.cpp:2239 +#: lib-src/mod-nyq-bench/NyqBench.cpp:1100 src/effects/nyquist/Nyquist.cpp:2239 msgid "Nyquist scripts (*.ny)|*.ny|Lisp scripts (*.lsp)|*.lsp|All files|*" msgstr "" "Scripts Nyquist (*.ny)|*.ny|Scripts Lisp (*.lsp)|*.lsp|Tots els fitxers|*" @@ -200,8 +197,7 @@ msgstr "No s'ha desat l'script." msgid "Warning" msgstr "Advertència" -#: lib-src/mod-nyq-bench/NyqBench.cpp:1097 -#: src/effects/nyquist/Nyquist.cpp:2236 +#: lib-src/mod-nyq-bench/NyqBench.cpp:1097 src/effects/nyquist/Nyquist.cpp:2236 msgid "Save Nyquist script" msgstr "Desa l'script Nyquist" @@ -447,9 +443,8 @@ msgstr "" #: src/AboutDialog.cpp:169 src/AboutDialog.cpp:170 src/AboutDialog.cpp:171 #: src/AboutDialog.cpp:172 src/AboutDialog.cpp:173 src/AboutDialog.cpp:174 #: src/AboutDialog.cpp:175 src/AboutDialog.cpp:176 -#, fuzzy msgid "developer" -msgstr "Envolupant" +msgstr "desenvolupador" #: src/AboutDialog.cpp:106 src/AboutDialog.cpp:127 msgid "co-founder and developer" @@ -474,7 +469,7 @@ msgstr "" #: src/AboutDialog.cpp:163 msgid "composer" -msgstr "" +msgstr "compositor" #: src/AboutDialog.cpp:166 #, fuzzy @@ -545,9 +540,8 @@ msgid "Credits" msgstr "Crèdits" #: src/AboutDialog.cpp:365 -#, fuzzy msgid "Audacity Team Members" -msgstr "Desenvolupadors d'Audacity:" +msgstr "Els membres de l'equip d'Audacity" #: src/AboutDialog.cpp:368 msgid "Emeritus:" @@ -558,14 +552,12 @@ msgid "Distinguished Audacity Team members, not currently active" msgstr "" #: src/AboutDialog.cpp:372 -#, fuzzy msgid "Contributors" -msgstr "Altres contribuïdors" +msgstr "Contribuïdors" #: src/AboutDialog.cpp:375 -#, fuzzy msgid "Translators" -msgstr "Transporta" +msgstr "Traductors" #: src/AboutDialog.cpp:379 src/prefs/LibraryPrefs.cpp:49 msgid "Libraries" @@ -692,7 +684,7 @@ msgstr "Data de construcció del programa:" #: src/AboutDialog.cpp:636 msgid "Commit Id:" -msgstr "Id. de pujada:" +msgstr "Id. de comisió:" #: src/AboutDialog.cpp:638 src/AboutDialog.cpp:640 msgid "Build type:" @@ -943,15 +935,15 @@ msgstr "Registre d'Audacity" msgid "&Save..." msgstr "&Desa..." -#: src/AudacityLogger.cpp:199 src/Tags.cpp:883 -#: src/prefs/KeyConfigPrefs.cpp:273 src/prefs/KeyConfigPrefs.cpp:781 +#: src/AudacityLogger.cpp:199 src/Tags.cpp:883 src/prefs/KeyConfigPrefs.cpp:273 +#: src/prefs/KeyConfigPrefs.cpp:781 msgid "Cl&ear" msgstr "&Neteja" #: src/AudacityLogger.cpp:200 src/FreqWindow.cpp:466 src/Menus.cpp:321 #: src/ShuttleGui.cpp:2166 src/effects/Contrast.cpp:300 msgid "&Close" -msgstr "&Tanca" +msgstr "Tan&ca" #: src/AudacityLogger.cpp:293 msgid "log.txt" @@ -1015,8 +1007,8 @@ msgid "" "You may have to use the Time Shift Tool (<---> or F5) to drag the track to " "the right place." msgstr "" -"L'ajust de la correcció de latència ha fet que el so enregistrat hagi quedat " -"ocult abans del zero.\n" +"L'ajust de la correcció de la latència ha fet que el so enregistrat hagi " +"quedat ocult abans del zero.\n" "Audacity ha mogut el fragment per tal que comenci al zero.\n" "Podeu fer servir l'eina de desplaçament en el temps (<---> o F5) per " "arrossegar la pista al seu lloc." @@ -1127,7 +1119,7 @@ msgid "" "\n" "Choosing \"Yes\" discards all projects immediately." msgstr "" -"Segur que voleu descartar tots els projectes?\n" +"Esteu segur que voleu descartar tots els projectes?\n" "\n" "Si escolliu \"Sí\" es descartaran tots immediatament." @@ -1142,9 +1134,8 @@ msgstr "" "No s'han pogut enumerar els fitxers de la carpeta de desament automàtic." #: src/AutoRecovery.cpp:760 -#, fuzzy msgid "Error Decoding File" -msgstr "S'ha produït un error en descodificar el fitxer" +msgstr "Error en la descodificació del fitxer" #: src/BatchCommandDialog.cpp:60 src/BatchCommandDialog.cpp:64 #: src/BatchCommandDialog.cpp:65 @@ -1169,7 +1160,7 @@ msgstr "&Paràmetres" #: src/BatchCommandDialog.cpp:101 msgid "C&hoose command" -msgstr "Selecció d'&ordre" +msgstr "Trieu l'&ordre" #: src/BatchCommands.cpp:569 msgid "Ogg Vorbis support is not included in this build of Audacity" @@ -1216,25 +1207,25 @@ msgstr "Aplica %s" #: src/BatchProcessDialog.cpp:67 src/BatchProcessDialog.cpp:73 #: src/BatchProcessDialog.cpp:74 msgid "Apply Chain" -msgstr "Aplica la cadena d'ordres" +msgstr "Aplica la cadena" #. i18n-hint: A chain is a sequence of commands that can be applied #. * to one or more audio files. #: src/BatchProcessDialog.cpp:99 msgid "&Select Chain" -msgstr "&Seleccioneu una cadena d'ordres" +msgstr "&Seleccioneu la cadena" #: src/BatchProcessDialog.cpp:104 msgid "Chain" -msgstr "Cadena d'ordres" +msgstr "Cadena" #: src/BatchProcessDialog.cpp:111 msgid "Apply to Current &Project" -msgstr "Aplica-la al &projecte actual" +msgstr "Aplica-ho al &projecte actual" #: src/BatchProcessDialog.cpp:112 msgid "Apply to &Files..." -msgstr "Aplica-la als &fitxers..." +msgstr "Aplica-ho als &fitxers..." #: src/BatchProcessDialog.cpp:113 src/BatchProcessDialog.cpp:322 msgid "&Cancel" @@ -1242,7 +1233,7 @@ msgstr "&Cancel·la" #: src/BatchProcessDialog.cpp:152 src/BatchProcessDialog.cpp:226 msgid "No chain selected" -msgstr "No s'ha seleccionat cap cadena d'ordres" +msgstr "No s'ha seleccionat cap cadena" #: src/BatchProcessDialog.cpp:166 #, c-format @@ -1273,11 +1264,11 @@ msgstr "Fitxer" #: src/BatchProcessDialog.cpp:467 src/BatchProcessDialog.cpp:471 #: src/BatchProcessDialog.cpp:472 msgid "Edit Chains" -msgstr "Edita les cadenes d'ordres" +msgstr "Edita les cadenes" #: src/BatchProcessDialog.cpp:524 msgid "&Chains" -msgstr "&Cadenes d'ordres" +msgstr "&Cadenes" #: src/BatchProcessDialog.cpp:543 src/Tags.cpp:880 msgid "&Add" @@ -1293,7 +1284,7 @@ msgstr "&Canvia el nom" #: src/BatchProcessDialog.cpp:551 msgid "C&hain (Double-Click or press SPACE to edit)" -msgstr "Ca&dena d'ordres (feu doble clic o premeu ESPAI per editar-la)" +msgstr "Ca&dena (feu doble clic o premeu ESPAI per editar-la)" #. i18n-hint: This is the number of the command in the list #: src/BatchProcessDialog.cpp:561 @@ -1344,11 +1335,11 @@ msgstr "Voleu desar els canvis?" #: src/BatchProcessDialog.cpp:780 msgid "Enter name of new chain" -msgstr "Escriviu el nom de la cadena d'ordres" +msgstr "Introduïu el nom de la cadena nova" #: src/BatchProcessDialog.cpp:781 msgid "Name of new chain" -msgstr "&Nom de la cadena d'ordres nova" +msgstr "Nom de la cadena nova" #: src/BatchProcessDialog.cpp:792 msgid "Name must not be blank" @@ -1364,7 +1355,7 @@ msgstr "Els noms no poden contenir '%c' ni '%c'" #: src/BatchProcessDialog.cpp:833 #, c-format msgid "Are you sure you want to delete %s?" -msgstr "Segur que voleu eliminar %s?" +msgstr "Esteu segur que voleu suprimir %s?" #: src/Dependencies.cpp:163 msgid "Removing Dependencies" @@ -1419,7 +1410,7 @@ msgstr "Copia els fitxers seleccionats" #: src/Dependencies.cpp:349 src/Dependencies.cpp:507 msgid "Cancel Save" -msgstr "Cancel·la l'acció de desar" +msgstr "Cancel·la el desament" #: src/Dependencies.cpp:350 msgid "Save without Copying" @@ -1471,7 +1462,7 @@ msgid "" "imported files, it will no longer be self-contained. If you then Save " "without copying those files in, you may lose data." msgstr "" -"El vostre projecte és actualment de tipus \"autocontingut\"; no depèn de cap " +"El vostre projecte actualment és de tipus \"autocontingut\"; no depèn de cap " "fitxer extern de so. \n" "\n" "Si modifiqueu el projecte fent que tingui dependències externes de fitxers, " @@ -1814,7 +1805,7 @@ msgstr "Fitxer de blocs orfe: '%s'" #: src/DirManager.cpp:2059 msgid "Caching audio" -msgstr "Memòria cau de so" +msgstr "Memòria cau de l'àudio" #: src/DirManager.cpp:2060 msgid "Caching audio into memory" @@ -2138,7 +2129,7 @@ msgstr "S'està reproduint el so" #. i18n-hint: Title for a topic. #: src/HelpText.cpp:139 msgid "Recording Audio" -msgstr "S'està enregistrant el so" +msgstr "Enregistrament de l’àudio" #. i18n-hint: Title for a topic. #: src/HelpText.cpp:144 @@ -2296,9 +2287,8 @@ msgstr "" "d'Internet\"." #: src/HistoryWindow.cpp:59 -#, fuzzy msgid "History" -msgstr "&Historial..." +msgstr "Historial" #: src/HistoryWindow.cpp:81 msgid "&Manage History" @@ -2331,14 +2321,12 @@ msgid "&Discard" msgstr "&Descarta" #: src/HistoryWindow.cpp:119 -#, fuzzy msgid "Clipboard space used" -msgstr "&Espai de disc utilitzat" +msgstr "Espai utilitzat del porta-retalls" #: src/HistoryWindow.cpp:121 -#, fuzzy msgid "Discard" -msgstr "&Descarta" +msgstr "Descarta" #: src/HistoryWindow.cpp:130 src/export/ExportCL.cpp:514 msgid "&OK" @@ -2381,16 +2369,16 @@ msgstr "Indiqueu un nom de fitxer nou:" #. i18n-hint: An opening parenthesis, in some languages a right parenthesis #: src/Internat.cpp:265 msgid "(" -msgstr "" +msgstr "(" #. i18n-hint: A closing parenthesis, in some languages a left parenthesis #: src/Internat.cpp:267 msgid ")" -msgstr "" +msgstr ")" #: src/LabelDialog.cpp:102 msgid "Edit Labels" -msgstr "Edita les etiquetes" +msgstr "Edició de les etiquetes" #: src/LabelDialog.cpp:125 msgid "Press F2 or double click to edit cell contents." @@ -2423,24 +2411,22 @@ msgstr "Etiqueta" #. i18n-hint: (noun) of a label #: src/LabelDialog.cpp:163 src/TimerRecordDialog.cpp:797 msgid "Start Time" -msgstr "Temps inicial" +msgstr "Comença a l'instant" #. i18n-hint: (noun) of a label #: src/LabelDialog.cpp:165 src/TimerRecordDialog.cpp:825 msgid "End Time" -msgstr "Temps final" +msgstr "Acaba a l'instant" #. i18n-hint: (noun) of a label #: src/LabelDialog.cpp:167 -#, fuzzy msgid "Low Frequency" -msgstr "Freqüència baixa:" +msgstr "Freqüència baixa" #. i18n-hint: (noun) of a label #: src/LabelDialog.cpp:169 -#, fuzzy msgid "High Frequency" -msgstr "Freqüència alta:" +msgstr "Freqüència alta" #: src/LabelDialog.cpp:184 msgid "New..." @@ -2473,7 +2459,7 @@ msgstr "Pista d'etiquetes nova" #: src/LabelDialog.cpp:783 msgid "Enter track name" -msgstr "Escriviu el nom de la pista" +msgstr "Introduïu el nom de la pista" #. i18n-hint: (noun) it's the name of a kind of track. #. i18n-hint: This is for screen reader software and indicates that @@ -2507,9 +2493,8 @@ msgid "&Delete Label" msgstr "&Suprimeix l'etiqueta" #: src/LabelTrack.cpp:2038 -#, fuzzy msgid "&Edit..." -msgstr "E&dita..." +msgstr "&Edita..." #: src/LabelTrack.cpp:2074 src/LabelTrack.cpp:2089 src/TrackPanel.cpp:5970 #: src/TrackPanel.cpp:6014 src/TrackPanel.cpp:6490 @@ -2533,7 +2518,7 @@ msgstr "És la primera vegada que s'executa Audacity" #: src/LangChoice.cpp:93 msgid "Choose Language for Audacity to use:" -msgstr "Trieu l'idioma que farà servir Audacity:" +msgstr "Trieu l'idioma per utilitzar-lo amb Audacity:" #. i18n-hint: The %s's are replaced by translated and untranslated #. * versions of language names. @@ -2583,18 +2568,16 @@ msgid "Save Project &As..." msgstr "&Anomena i desa el projecte..." #: src/Menus.cpp:328 -#, fuzzy msgid "Sa&ve Compressed Copy of Project..." -msgstr "Desa una còpia comprimida del projecte..." +msgstr "Desa una còpia co&mprimida del projecte..." #: src/Menus.cpp:331 msgid "Chec&k Dependencies..." msgstr "Compro&va les dependències..." #: src/Menus.cpp:335 -#, fuzzy msgid "Edit Me&tadata Tags..." -msgstr "Edita les etiquetes de metadades" +msgstr "Edita les etiquetes de les me&tadades..." #: src/Menus.cpp:341 src/import/ImportRaw.cpp:455 msgid "&Import" @@ -2633,17 +2616,16 @@ msgid "Export &Multiple..." msgstr "Exporta &múltiples fitxers..." #: src/Menus.cpp:374 -#, fuzzy msgid "Export MI&DI..." -msgstr "Exporta a MIDI..." +msgstr "Exporta a MI&DI..." #: src/Menus.cpp:380 msgid "Appl&y Chain..." -msgstr "Execu&ta la cadena d'ordres..." +msgstr "Apl&ica la cadena..." #: src/Menus.cpp:383 msgid "Edit C&hains..." -msgstr "Edita les &cadenes d'ordres..." +msgstr "Edita les &cadenes..." #: src/Menus.cpp:387 msgid "Pa&ge Setup..." @@ -2878,7 +2860,7 @@ msgstr "&Visualització" #: src/Menus.cpp:652 msgid "Zoom &In" -msgstr "&Apropa el zoom" +msgstr "&Augmenta el zoom" #: src/Menus.cpp:655 msgid "Zoom &Normal" @@ -2886,11 +2868,11 @@ msgstr "Zoom &normal" #: src/Menus.cpp:656 msgid "Zoom &Out" -msgstr "Allunya el z&oom" +msgstr "Disminueix el z&oom" #: src/Menus.cpp:659 msgid "&Zoom to Selection" -msgstr "Fes &zoom a la selecció" +msgstr "&Zoom a la selecció" #: src/Menus.cpp:662 msgid "&Fit in Window" @@ -2902,11 +2884,11 @@ msgstr "Encabeix &verticalment" #: src/Menus.cpp:666 msgid "Go to Selection Sta&rt" -msgstr "Vés a l'&inici de la selecció" +msgstr "Vés al comen&çament de la selecció" #: src/Menus.cpp:667 msgid "Go to Selection En&d" -msgstr "Vés al &final de la selecció" +msgstr "Vés a l'acabament &de la selecció" #: src/Menus.cpp:670 msgid "&Collapse All Tracks" @@ -2976,9 +2958,8 @@ msgstr "Barra d'eines de &selecció" #. i18n-hint: Clicking this menu item shows the toolbar for selecting a frequency range of audio #: src/Menus.cpp:731 -#, fuzzy msgid "Spe&ctral Selection Toolbar" -msgstr "Barra d'eines de selecció e&spectral" +msgstr "Barra d'eines de selecció espe&ctral" #. i18n-hint: Clicking this menu item shows a toolbar that has some tools in it #: src/Menus.cpp:734 @@ -3004,9 +2985,8 @@ msgstr "Barres d'&eines" #. i18n-hint: (verb) #: src/Menus.cpp:745 -#, fuzzy msgid "Reset Toolb&ars" -msgstr "Restableix les &barres d'eines" +msgstr "Restableix les b&arres d'eines" #. i18n-hint: 'Transport' is the name given to the set of controls that #. play, record, pause etc. @@ -3134,7 +3114,7 @@ msgstr "Desemm&udeix totes les pistes" #: src/Menus.cpp:863 msgid "&Align End to End" -msgstr "&Alinea el final al final" +msgstr "&Alinea l'acabament a l'acabament" #: src/Menus.cpp:864 msgid "Align &Together" @@ -3150,7 +3130,7 @@ msgstr "Comença al &cursor o al començament de la selecció" #: src/Menus.cpp:869 msgid "Start to Selection &End" -msgstr "Comença al final de la s&elecció" +msgstr "Comença a l'acabament de la s&elecció" #: src/Menus.cpp:870 msgid "End to Cu&rsor/Selection Start" @@ -3178,12 +3158,10 @@ msgid "Sync-&Lock Tracks (on/off)" msgstr "Pistes &síncrones" #: src/Menus.cpp:918 -#, fuzzy msgid "Add Label at &Selection" msgstr "Afegeix una etiqueta a la &selecció" #: src/Menus.cpp:920 -#, fuzzy msgid "Add Label at &Playback Position" msgstr "Afegeix una etiqueta a la &posició de la reproducció" @@ -3243,23 +3221,20 @@ msgid "Plot Spectrum..." msgstr "Traça l'espectre..." #: src/Menus.cpp:1042 -#, fuzzy msgid "&Window" -msgstr "finestra" +msgstr "&Finestra" #. i18n-hint: Standard Macintosh Window menu item: Make (the current #. * window) shrink to an icon on the dock #: src/Menus.cpp:1045 -#, fuzzy msgid "&Minimize" -msgstr "Mínim" +msgstr "&Mínimitza" #. i18n-hint: Standard Macintosh Window menu item: Make (the current #. * window) full sized #: src/Menus.cpp:1049 -#, fuzzy msgid "&Zoom" -msgstr "Zoom" +msgstr "&Zoom" #: src/Menus.cpp:1055 msgid "&Bring All to Front" @@ -3641,19 +3616,16 @@ msgid "Decrease playback speed" msgstr "Redueix la velocitat de reproducció" #: src/Menus.cpp:1265 -#, fuzzy msgid "Move to Next Label" -msgstr "Vés a la pista següent i selecciona-la" +msgstr "Mou a la següent etiqueta" #: src/Menus.cpp:1267 -#, fuzzy msgid "Move to Previous Label" -msgstr "Vés a la pista anterior i selecciona-la" +msgstr "Mou a l'anterior etiqueta" #: src/Menus.cpp:1272 -#, fuzzy msgid "Minimize all projects" -msgstr "&Normalitza totes les pistes del projecte" +msgstr "Minimitza tots els projectes" #: src/Menus.cpp:1396 src/Menus.cpp:1404 msgid "Unknown" @@ -4036,12 +4008,11 @@ msgstr "Tots els fitxers|*" #: src/Menus.cpp:5810 src/export/Export.cpp:354 src/export/Export.cpp:977 #: src/export/ExportMultiple.cpp:734 src/export/ExportMultiple.cpp:876 msgid "Edit Metadata Tags" -msgstr "Edita les etiquetes de metadades" +msgstr "Edició de les etiquetes de les metadades" #: src/Menus.cpp:5810 -#, fuzzy msgid "Metadata Tags" -msgstr "Edita les etiquetes de metadades" +msgstr "Etiquetes de les metadades" #: src/Menus.cpp:5884 #, c-format @@ -4078,7 +4049,7 @@ msgstr "comença al cursor o al començament de la selecció" #: src/Menus.cpp:6075 msgid "start to selection end" -msgstr "comença al final de la selecció" +msgstr "comença a l'acabament de la selecció" #: src/Menus.cpp:6080 msgid "end to cursor/selection start" @@ -4088,7 +4059,7 @@ msgstr "acaba al cursor o al començament de la selecció" #: src/effects/ToneGen.cpp:328 src/toolbars/SelectionBar.cpp:162 #: src/toolbars/SelectionBar.cpp:165 src/toolbars/SelectionBar.cpp:270 msgid "End" -msgstr "Final" +msgstr "Acabament" #: src/Menus.cpp:6085 msgid "end to selection end" @@ -4096,11 +4067,11 @@ msgstr "acaba a l'acabament de la selecció" #: src/Menus.cpp:6091 msgid "end to end" -msgstr "final a final" +msgstr "acabament a l'acabament" #: src/Menus.cpp:6092 msgid "End to End" -msgstr "Final a Final" +msgstr "Acabament a l'acabament" #: src/Menus.cpp:6096 msgid "together" @@ -4253,7 +4224,7 @@ msgstr "Nova freqüència de mostreig (Hz):" #: src/Menus.cpp:7084 src/TrackPanel.cpp:8489 msgid "The entered value is invalid" -msgstr "El valor que heu escrit no és vàlid" +msgstr "El valor que heu introduït no és vàlid" #: src/Menus.cpp:7093 #, c-format @@ -4394,7 +4365,7 @@ msgstr "Sí" #: src/TimerRecordDialog.cpp:1018 src/TimerRecordDialog.cpp:1057 #: src/TimerRecordDialog.cpp:1058 msgid "No" -msgstr "Núm." +msgstr "No" #: src/ModuleManager.cpp:275 msgid "Audacity Module Loader" @@ -4558,14 +4529,13 @@ msgstr "" #. i18n-hint: The first %s numbers the project, the second %s is the project name. #: src/Project.cpp:2501 -#, fuzzy, c-format +#, c-format msgid "%sSave changes to %s?" -msgstr "Voleu desar els canvis?" +msgstr "%sVoleu desar els canvis a %s?" #: src/Project.cpp:2502 -#, fuzzy msgid "Save project before closing?" -msgstr "Voleu desar els canvis abans de tancar?" +msgstr "Voleu desar el projecte abans de tancar?" #: src/Project.cpp:2505 msgid "" @@ -4838,15 +4808,15 @@ msgid "" "'Save Project' is for an Audacity project, not an audio file.\n" "For an audio file that will open in other apps, use 'Export'.\n" msgstr "" -"'Desa el projecte' és només per a projectes Audacity, no per a fitxers de " -"so.\n" -"Feu 'Exporta' si voleu obtenir un fitxer de so que pugui ser utilitzat en " -"altres aplicacions.\n" +"'Desa el projecte' només és per als projectes d'Audacity, no per als fitxers " +"de so.\n" +"Feu 'Exporta' si voleu obtenir un fitxer de so que es pugui obrir en altres " +"aplicacions.\n" #: src/Project.cpp:4236 -#, fuzzy, c-format +#, c-format msgid "%sSave Project \"%s\" As..." -msgstr "Desa el projecte \"%s\" com a..." +msgstr "%sDesa el projecte \"%s\" com a..." #: src/Project.cpp:4315 msgid "Created new project" @@ -4957,7 +4927,7 @@ msgstr "Marc de captura de pantalla" #: src/Screenshot.cpp:316 msgid "Choose location to save files" -msgstr "Escull una ubicació per desar-hi els fitxers" +msgstr "Trieu una ubicació per desar-hi els fitxers" #: src/Screenshot.cpp:326 msgid "Save images to:" @@ -4965,7 +4935,7 @@ msgstr "Desa les imatges a:" #: src/Screenshot.cpp:328 src/export/ExportMultiple.cpp:271 msgid "Choose..." -msgstr "Navega..." +msgstr "Tria..." #: src/Screenshot.cpp:334 msgid "Capture entire window or screen" @@ -5117,7 +5087,7 @@ msgstr "Pistes llargues" #: src/Screenshot.cpp:523 msgid "Choose a location to save screenshot images" -msgstr "Escull una ubicació per desar-hi les imatges capturades" +msgstr "Trieu una ubicació per desar-hi les imatges capturades" #: src/Sequence.cpp:1050 #, fuzzy, c-format @@ -5241,11 +5211,11 @@ msgstr "Ca&rrega..." #: src/Tags.cpp:906 msgid "Set De&fault" -msgstr "&Estableix com a opció per defecte" +msgstr "&Estableix-ho com a predeterminat" #: src/Tags.cpp:1060 msgid "Edit Genres" -msgstr "Edita els gèneres" +msgstr "Edició dels gèneres" #: src/Tags.cpp:1094 src/Tags.cpp:1133 msgid "Unable to save genre file." @@ -5257,7 +5227,9 @@ msgstr "Restableix els gèneres" #: src/Tags.cpp:1105 msgid "Are you sure you want to reset the genre list to defaults?" -msgstr "Segur que voleu restablir la llista de gèneres als valors per defecte?" +msgstr "" +"Esteu segur que voleu restablir la llista de gèneres als valors " +"predeterminats?" #: src/Tags.cpp:1121 msgid "Unable to open genre file." @@ -5265,7 +5237,7 @@ msgstr "No s'ha pogut obrir el fitxer de gèneres." #: src/Tags.cpp:1155 msgid "Load Metadata As:" -msgstr "Llegeix les metadades com a:" +msgstr "Càrrega de metadades:" #: src/Tags.cpp:1180 msgid "Error Loading Metadata" @@ -5273,7 +5245,7 @@ msgstr "S'ha produït un error en carregar les metadades" #: src/Tags.cpp:1209 msgid "Save Metadata As:" -msgstr "Enregistra les metadades com a:" +msgstr "Desament de metadades:" #: src/Tags.cpp:1224 msgid "Error Saving Tags File" @@ -5419,44 +5391,40 @@ msgid "Automatic Save path is invalid." msgstr "" #: src/TimerRecordDialog.cpp:375 -#, fuzzy msgid "Error in Automatic Save" -msgstr "S'ha produït un error en la durada" +msgstr "Error en el desament automàtic" #: src/TimerRecordDialog.cpp:381 msgid "Automatic Export path is invalid." msgstr "" #: src/TimerRecordDialog.cpp:382 -#, fuzzy msgid "Error in Automatic Export" -msgstr "S'ha produït un error en la durada" +msgstr "Error en l'exportació automàtica" #: src/TimerRecordDialog.cpp:419 msgid "Timer Recording Disk Space Warning" msgstr "" #: src/TimerRecordDialog.cpp:461 src/TimerRecordDialog.cpp:869 -#, fuzzy msgid "Current Project" -msgstr "Aplica-la al &projecte actual" +msgstr "Projecte actual" #: src/TimerRecordDialog.cpp:525 -#, fuzzy msgid "Recording start:\n" -msgstr "Inici de l'enregistrament" +msgstr "Començament de l'enregistrament:\n" #: src/TimerRecordDialog.cpp:526 -#, fuzzy msgid "Duration:\n" -msgstr "Durada:" +msgstr "Durada:\n" #: src/TimerRecordDialog.cpp:527 -#, fuzzy msgid "" "Recording end:\n" "\n" -msgstr "Fi de l'enregistrament" +msgstr "" +"Acabament de l'enregistrament:\n" +"\n" #: src/TimerRecordDialog.cpp:528 src/TimerRecordDialog.cpp:1006 msgid "Automatic Save enabled:\n" @@ -5525,51 +5493,42 @@ msgid "099 days 024 h 060 m 060 s" msgstr "099 dies 024 h 060 m 060 s" #: src/TimerRecordDialog.cpp:857 -#, fuzzy msgid "Automatic Save" -msgstr "Automàtic" +msgstr "Desament automàtic" #: src/TimerRecordDialog.cpp:860 -#, fuzzy msgid "Enable &Automatic Save?" -msgstr "Activa la &compensació" +msgstr "Voleu habilitar el desament automàtic?" #: src/TimerRecordDialog.cpp:871 src/TimerRecordDialog.cpp:872 -#, fuzzy msgid "Save Project As:" -msgstr "&Anomena i desa el projecte..." +msgstr "Desa el projecte com a:" #: src/TimerRecordDialog.cpp:875 src/TimerRecordDialog.cpp:890 -#, fuzzy msgid "Select..." -msgstr "Selecciona" +msgstr "Selecciona..." #: src/TimerRecordDialog.cpp:881 -#, fuzzy msgid "Automatic Export" -msgstr "Automàtic" +msgstr "Exportació automàtica." #: src/TimerRecordDialog.cpp:883 -#, fuzzy msgid "Enable Automatic &Export?" -msgstr "No s'ha pogut exportar" +msgstr "Voleu habilitar l'exportació automàtica?" #: src/TimerRecordDialog.cpp:886 src/TimerRecordDialog.cpp:887 -#, fuzzy msgid "Export Project As:" -msgstr "Exporta els valors predefinits" +msgstr "Exporta el projecte com a:" #: src/TimerRecordDialog.cpp:896 -#, fuzzy msgid "Options" -msgstr "Opcions:" +msgstr "Opcions" #: src/TimerRecordDialog.cpp:900 msgid "Do nothing" msgstr "" #: src/TimerRecordDialog.cpp:901 -#, fuzzy msgid "Exit Audacity" msgstr "Surt d'Audacity" @@ -5592,9 +5551,8 @@ msgid "Waiting to start recording at:\n" msgstr "S'està esperant per començar l'enregistrament a %s.\n" #: src/TimerRecordDialog.cpp:1004 -#, fuzzy msgid "Recording duration:\n" -msgstr "S'està enregistrant el so" +msgstr "Durada de l'enregistrament:\n" #: src/TimerRecordDialog.cpp:1005 msgid "" @@ -5668,9 +5626,8 @@ msgid "&Left Channel" msgstr "Canal &esquerre" #: src/TrackPanel.cpp:629 -#, fuzzy msgid "&Right Channel" -msgstr "Canal dret" +msgstr "Canal d&ret" #: src/TrackPanel.cpp:630 msgid "Ma&ke Stereo Track" @@ -5707,16 +5664,15 @@ msgstr "Baixa-ho una octa&va" #: src/TrackPanel.cpp:651 msgid "&Font..." -msgstr "&Tipus de lletra..." +msgstr "&Lletra..." #: src/TrackPanel.cpp:657 -#, fuzzy msgid "L&ogarithmic scale" -msgstr "L&ogarítmic" +msgstr "Escala l&ogarítmica" #: src/TrackPanel.cpp:660 msgid "&Range..." -msgstr "&Rang..." +msgstr "Inte&rval..." #: src/TrackPanel.cpp:661 msgid "Logarithmic &Interpolation" @@ -6086,12 +6042,12 @@ msgstr "Límit superior de velocitat" #: src/TrackPanel.cpp:8527 #, c-format msgid "Set range to '%ld' - '%ld'" -msgstr "Fixa l'abast a '%ld' - '%ld'" +msgstr "Estableix l'interval a '%ld' - '%ld'" #. i18n-hint: (verb) #: src/TrackPanel.cpp:8532 msgid "Set Range" -msgstr "Especifica el rang" +msgstr "Estableix l'interval" #: src/TrackPanel.cpp:8544 msgid "Set time track display to linear" @@ -6137,17 +6093,17 @@ msgstr "Canvi de nom" #. i18n-hint: (noun) This is the font for the label track. #: src/TrackPanel.cpp:8740 msgid "Label Track Font" -msgstr "Tipus de lletra per la pista d'etiquetes" +msgstr "Lletra de la pista d'etiquetes" #. i18n-hint: (noun) The name of the typeface #: src/TrackPanel.cpp:8754 src/TrackPanel.cpp:8761 msgid "Face name" -msgstr "Nom de portada" +msgstr "Nom de la portada" #. i18n-hint: (noun) The size of the typeface #: src/TrackPanel.cpp:8766 src/TrackPanel.cpp:8773 msgid "Face size" -msgstr "Mida de portada" +msgstr "Mida de la portada" #: src/TrackPanel.cpp:9428 msgid "Stereo, 999999Hz" @@ -6456,9 +6412,8 @@ msgid "Tone controls" msgstr "" #: src/effects/BassTreble.cpp:218 -#, fuzzy msgid "Ba&ss (dB):" -msgstr "Baixos (dB):" +msgstr "Baixo&s (dB):" #: src/effects/BassTreble.cpp:219 msgid "Bass (dB):" @@ -6469,9 +6424,8 @@ msgid "&Treble (dB):" msgstr "Agu&ts (dB):" #: src/effects/BassTreble.cpp:249 -#, fuzzy msgid "&Volume (dB):" -msgstr "Agu&ts (dB):" +msgstr "&Volum(dB):" #: src/effects/BassTreble.cpp:254 src/effects/Normalize.cpp:35 msgid "Level" @@ -6651,19 +6605,16 @@ msgid "Change Tempo without Changing Pitch" msgstr "Canvia el temps sense canviar el to" #: src/effects/ChangeTempo.cpp:226 -#, fuzzy msgid "Beats per minute" -msgstr "Pulsacions per minut:" +msgstr "Pulsacions per minut" #: src/effects/ChangeTempo.cpp:233 -#, fuzzy msgid "Beats per minute, from" -msgstr "Pulsacions per minut:" +msgstr "Pulsacions per minut, de" #: src/effects/ChangeTempo.cpp:239 -#, fuzzy msgid "Beats per minute, to" -msgstr "Pulsacions per minut:" +msgstr "Pulsacions per minut, fins a" #: src/effects/ChangeTempo.cpp:247 #, fuzzy @@ -6741,7 +6692,7 @@ msgstr "UsePeak" #: src/effects/Compressor.cpp:105 msgid "Compresses the dynamic range of audio" -msgstr "Comprimeix el rang dinàmic de l'àudio" +msgstr "Comprimeix l'interval dinàmic de l'àudio" #: src/effects/Compressor.cpp:219 msgid "Noise Floor:" @@ -6869,9 +6820,8 @@ msgstr "" "Si us plau, seleccioneu una secció d'una pista." #: src/effects/Contrast.cpp:96 -#, fuzzy msgid "Please select an audio track." -msgstr "Seleccioneu una acció" +msgstr "Seleccioneu una pista d'àudio." #: src/effects/Contrast.cpp:179 msgid "" @@ -6977,12 +6927,11 @@ msgid "indeterminate" msgstr "Indeterminada" #: src/effects/Contrast.cpp:396 -#, fuzzy, c-format +#, c-format msgid "%.2f dB Average RMS" -msgstr "%.1f dB RMS mitjà" +msgstr "%.2f dB RMS mitjà" #: src/effects/Contrast.cpp:399 -#, fuzzy msgid "Infinite dB difference" msgstr "diferència en dB infinita" @@ -6995,9 +6944,9 @@ msgid "zero" msgstr "zero" #: src/effects/Contrast.cpp:409 src/effects/Contrast.cpp:422 -#, fuzzy, c-format +#, c-format msgid "%.2f dB" -msgstr "%.1f dB" +msgstr "%.2f dB" #: src/effects/Contrast.cpp:412 src/effects/Contrast.cpp:552 msgid "No foreground measured" @@ -7049,9 +6998,9 @@ msgid "Time ended = %2d hour(s), %2d minute(s), %.2f seconds." msgstr "Hora d'acabament = %2d hora(es), %2d minut(s), %.2f segons." #: src/effects/Contrast.cpp:478 src/effects/Contrast.cpp:497 -#, fuzzy, c-format +#, c-format msgid "Average RMS = %.2f dB." -msgstr "RMS mitjà = %.1f dB." +msgstr "RMS mitjà = %.2f dB." #: src/effects/Contrast.cpp:480 src/effects/Contrast.cpp:499 msgid "Average RMS = zero." @@ -7074,9 +7023,9 @@ msgid "Difference is indeterminate." msgstr "La diferència és indeterminada." #: src/effects/Contrast.cpp:509 -#, fuzzy, c-format +#, c-format msgid "Difference = %.2f Average RMS dB." -msgstr "Diferència = %.1f dB RMS mitjà." +msgstr "Diferència = %.2f dB RMS mitjà." #: src/effects/Contrast.cpp:511 msgid "Difference = infinite Average RMS dB." @@ -7156,19 +7105,16 @@ msgid "Threshold dB" msgstr "Llindar %d dB" #: src/effects/Distortion.cpp:82 src/effects/Distortion.cpp:129 -#, fuzzy msgid "Parameter 1" -msgstr "Paràmetres" +msgstr "Paràmetre 1" #: src/effects/Distortion.cpp:83 src/effects/Distortion.cpp:130 -#, fuzzy msgid "Parameter 2" -msgstr "Paràmetres" +msgstr "Paràmetre 2" #: src/effects/Distortion.cpp:84 -#, fuzzy msgid "Repeats" -msgstr "Repeteix" +msgstr "repeticions" #: src/effects/Distortion.cpp:102 #, no-c-format @@ -7258,18 +7204,16 @@ msgid "Upper Threshold" msgstr "Llindar" #: src/effects/Distortion.cpp:131 -#, fuzzy msgid "Number of repeats" -msgstr "Nombre de repeticions a afegir:" +msgstr "Nombre de repeticions" #: src/effects/Distortion.cpp:192 msgid "Waveshaping distortion effect" msgstr "" #: src/effects/Distortion.cpp:344 -#, fuzzy msgid "Distortion type:" -msgstr "Tipus d'interpolació" +msgstr "Tipus de distorsió:" #: src/effects/Distortion.cpp:348 msgid "DC blocking filter" @@ -7317,9 +7261,8 @@ msgstr "" #: src/effects/Distortion.cpp:705 src/effects/Distortion.cpp:719 #: src/effects/Distortion.cpp:733 src/effects/Distortion.cpp:747 #: src/effects/Distortion.cpp:775 -#, fuzzy msgid "Output level" -msgstr "Sortida" +msgstr "Nivell de sortida" #: src/effects/Distortion.cpp:748 #, fuzzy @@ -7335,9 +7278,8 @@ msgid "Levelling fine adjustment" msgstr "" #: src/effects/Distortion.cpp:790 -#, fuzzy msgid "Degree of Levelling" -msgstr "Grau d'anivellament:" +msgstr "Grau d'anivellament" #: src/effects/Distortion.cpp:814 msgid "dB Limit" @@ -7349,39 +7291,36 @@ msgid "Wet level" msgstr "amb 2 nivells" #: src/effects/Distortion.cpp:817 -#, fuzzy msgid "Residual level" -msgstr "Resid&u" +msgstr "Nivell residual" #: src/effects/Distortion.cpp:833 msgid " (Not Used):" -msgstr "" +msgstr " (sense utilitzar):" #. i18n-hint: Control range. #: src/effects/Distortion.cpp:838 msgid " (-100 to 0 dB):" -msgstr "" +msgstr " (-100 fins a 0 dB):" #. i18n-hint: Control range. #: src/effects/Distortion.cpp:853 msgid " (-80 to -20 dB):" -msgstr "" +msgstr " (-80 fins a -20 dB):" #. i18n-hint: Control range. #: src/effects/Distortion.cpp:864 src/effects/Distortion.cpp:875 -#, fuzzy msgid " (0 to 100):" -msgstr "(%) [-50 a 100]:" +msgstr " (0 fins a 100):" #. i18n-hint: Control range. #: src/effects/Distortion.cpp:886 msgid " (0 to 5):" -msgstr "" +msgstr " (0 fins a 5):" #: src/effects/Distortion.h:26 -#, fuzzy msgid "Distortion" -msgstr "Durada" +msgstr "Distorsió" #: src/effects/DtmfGen.cpp:39 msgid "Sequence" @@ -7650,7 +7589,7 @@ msgstr "Quant a" #: src/effects/Effect.cpp:3483 #, c-format msgid "Are you sure you want to delete \"%s\"?" -msgstr "Segur que voleu suprimir \"%s\"?" +msgstr "Esteu segur que voleu suprimir \"%s\"?" #: src/effects/Effect.cpp:3500 src/effects/Effect.cpp:3537 #: src/effects/Effect.cpp:3547 src/export/ExportFFmpegDialogs.cpp:1404 @@ -7836,10 +7775,10 @@ msgid "" "Choose the 'Save/Manage Curves...' button and rename the 'unnamed' curve, " "then use that one." msgstr "" -"Per fer servir aquesta corba d'equalització en una cadena d'ordres cal que " -"li doneu un nom.\n" -"Feu clic al botó 'Desa/Gestiona corbes...', poseu un nom a la corba 'sense " -"nom', i després utilitzeu-la. " +"Per utilitzar aquesta corba d'equalització en una cadena de lots cal que li " +"doneu un nom nou.\n" +"Feu clic al botó 'Desa/Gestiona les corbes...', reanomeneu la corba 'sense " +"nom', i després utilitzeu-la." #: src/effects/Equalization.cpp:367 msgid "EQ Curve needs a different name" @@ -7857,9 +7796,8 @@ msgid "Track sample rate is too low for this effect." msgstr "" #: src/effects/Equalization.cpp:491 -#, fuzzy msgid "Effect Unavailable" -msgstr "La vista prèvia no està disponible" +msgstr "L'efecte no està disponible" #: src/effects/Equalization.cpp:647 src/effects/ScienFilter.cpp:403 msgid "+ dB" @@ -7883,7 +7821,7 @@ msgstr "kHz" #: src/effects/Equalization.cpp:741 msgid "&EQ Type:" -msgstr "" +msgstr "Tipus d'equalitzador:" #: src/effects/Equalization.cpp:749 msgid "&Draw" @@ -8021,7 +7959,7 @@ msgstr "Gestiona la llista de corbes" #: src/effects/Equalization.cpp:3114 msgid "Manage Curves" -msgstr "Gestiona corbes" +msgstr "Gestiona les corbes" #: src/effects/Equalization.cpp:3149 msgid "&Curves" @@ -8134,7 +8072,7 @@ msgstr "La corba 'sense nom' és especial i no es pot esborrar." #: src/effects/Equalization.cpp:3466 msgid "Choose an EQ curve file" -msgstr "Escolliu un fitxer de corba d'equalització" +msgstr "Trieu un fitxer de corba d'equalització" #: src/effects/Equalization.cpp:3466 msgid "xml files (*.xml;*.XML)|*.xml;*.XML" @@ -8656,7 +8594,7 @@ msgstr "S'està normalitzant sense eliminar el desplaçament sobre el zero...\n" #: src/effects/Normalize.cpp:193 msgid "Analyzing: " -msgstr "S'està analitzant:" +msgstr "Anàlisi:" #: src/effects/Normalize.cpp:195 msgid "Analyzing first track of stereo pair: " @@ -8790,23 +8728,20 @@ msgid "Combines phase-shifted signals with the original signal" msgstr "Combina senyals de fase canviada amb el senyal original" #: src/effects/Phaser.cpp:247 -#, fuzzy msgid "&Stages:" -msgstr "Etapes:" +msgstr "Etape&s:" #: src/effects/Phaser.cpp:258 -#, fuzzy msgid "&Dry/Wet:" -msgstr "Sec/Mullat:" +msgstr "&Sec/Mullat:" #: src/effects/Phaser.cpp:263 msgid "Dry Wet" msgstr "Sec Mullat" #: src/effects/Phaser.cpp:268 src/effects/Wahwah.cpp:231 -#, fuzzy msgid "LFO Freq&uency (Hz):" -msgstr "Freqüència LFO (Hz):" +msgstr "Fr&eqüència LFO (Hz):" #: src/effects/Phaser.cpp:273 src/effects/Wahwah.cpp:236 msgid "LFO frequency in hertz" @@ -8822,9 +8757,8 @@ msgid "LFO start phase in degrees" msgstr "Fase d'inici LFO en graus" #: src/effects/Phaser.cpp:289 -#, fuzzy msgid "Dept&h:" -msgstr "Profunditat:" +msgstr "Profun&ditat:" #: src/effects/Phaser.cpp:294 src/effects/Wahwah.cpp:257 msgid "Depth in percent" @@ -8840,9 +8774,8 @@ msgid "Feedback in percent" msgstr "Retroalimentació en percentatge" #: src/effects/Phaser.cpp:310 src/effects/Wahwah.cpp:282 -#, fuzzy msgid "&Output gain (dB):" -msgstr "Guany de la sortida (dB):" +msgstr "Guany de la s&ortida (dB):" #: src/effects/Phaser.cpp:315 src/effects/Wahwah.cpp:287 msgid "Output gain (dB)" @@ -9167,9 +9100,8 @@ msgid "Frame Period" msgstr "Període de la trama d'àudio" #: src/effects/ScoreAlignDialog.cpp:109 -#, fuzzy msgid "Window Size:" -msgstr "Mida de la finestra" +msgstr "Mida de la finestra:" #: src/effects/ScoreAlignDialog.cpp:114 msgid "Window Size" @@ -9432,9 +9364,8 @@ msgid "Compress" msgstr "Comprimeix" #: src/effects/TruncSilence.cpp:66 -#, fuzzy msgid "Independent" -msgstr "StereoIndependent" +msgstr "Independent" #: src/effects/TruncSilence.cpp:119 msgid "" @@ -9492,14 +9423,12 @@ msgstr "" "es van fer populars als anys 70" #: src/effects/Wahwah.cpp:252 -#, fuzzy msgid "Dept&h (%):" -msgstr "Profunditat (%):" +msgstr "Profun&ditat (%):" #: src/effects/Wahwah.cpp:262 -#, fuzzy msgid "Reso&nance:" -msgstr "Ressonància:" +msgstr "Res&sonància:" #: src/effects/Wahwah.cpp:272 #, fuzzy @@ -9757,7 +9686,7 @@ msgstr "" #: src/effects/nyquist/Nyquist.cpp:646 msgid "Nyquist Error" -msgstr "" +msgstr "Error de Nyquist" #: src/effects/nyquist/Nyquist.cpp:737 msgid "Nyquist" @@ -9835,7 +9764,7 @@ msgstr "Hi ha un error al codi Nyquist" #: src/effects/nyquist/Nyquist.cpp:2075 msgid "Enter Nyquist Command: " -msgstr "Escriviu l'ordre del Nyquist:" +msgstr "Introduïu l'ordre de Nyquist:" #: src/effects/nyquist/Nyquist.cpp:2079 msgid "&Use legacy (version 3) syntax." @@ -10053,16 +9982,15 @@ msgstr "" #: src/export/Export.cpp:230 msgid "No format specific options" -msgstr "" +msgstr "No hi ha cap opció específica del format" #: src/export/Export.cpp:270 msgid "Export Audio" msgstr "Exporta l'àudio" #: src/export/Export.cpp:354 src/export/Export.cpp:978 -#, fuzzy msgid "Exported Tags" -msgstr "Exporta" +msgstr "Etiquetes exportades" #: src/export/Export.cpp:469 msgid "All selected audio is muted." @@ -10078,7 +10006,7 @@ msgstr "No s'ha pogut exportar" #: src/export/Export.cpp:596 msgid "Are you sure you want to export the file as \"" -msgstr "Segur que voleu exportar el fitxer com a \"" +msgstr "Esteu segur que voleu exportar el fitxer com a \"" #: src/export/Export.cpp:616 #, c-format @@ -10422,7 +10350,7 @@ msgstr "Voleu sobreescriure el valor predefinit '%s'?" #: src/export/ExportFFmpegDialogs.cpp:569 #: src/export/ExportFFmpegDialogs.cpp:764 msgid "Confirm Overwrite" -msgstr "Confirmació de l'operació de sobreescriure" +msgstr "Confirmeu la sobreescriptura" #: src/export/ExportFFmpegDialogs.cpp:580 msgid "Please select format before saving a profile" @@ -11041,9 +10969,8 @@ msgstr "" #. i18n-hint: LAME is the name of an MP3 converter and should not be translated #: src/export/ExportMP3.cpp:593 -#, fuzzy msgid "Locate LAME" -msgstr "Ubicació de LAME" +msgstr "Localitza LAME" #: src/export/ExportMP3.cpp:614 #, c-format @@ -11276,7 +11203,7 @@ msgstr "S'ha creat \"%s\" amb èxit." #: src/export/ExportMultiple.cpp:488 msgid "Choose a location to save the exported files" -msgstr "Escull una ubicació per desar-hi els fitxers exportats" +msgstr "Trieu una ubicació per desar-hi els fitxers exportats" #: src/export/ExportMultiple.cpp:587 #, c-format @@ -11757,7 +11684,7 @@ msgstr "llegeix directament" #: src/import/ImportPCM.cpp:269 msgid "Choose an import method" -msgstr "Escolliu un mètode d'importació" +msgstr "Trieu un mètode d'importació" #: src/import/ImportPCM.cpp:279 msgid "Make a © of the files before editing (safer)" @@ -11971,7 +11898,7 @@ msgstr "&Ubicació:" #: src/prefs/DirectoriesPrefs.cpp:94 msgid "C&hoose..." -msgstr "Es&colliu..." +msgstr "&Tria..." #: src/prefs/DirectoriesPrefs.cpp:96 msgid "Free Space:" @@ -12002,7 +11929,7 @@ msgstr "" #: src/prefs/DirectoriesPrefs.cpp:138 msgid "Choose a location to place the temporary directory" -msgstr "Trieu la ubicació del directori temporal" +msgstr "Trieu una ubicació per ubicar-hi el directori temporal" #: src/prefs/DirectoriesPrefs.cpp:191 msgid "unavailable - above location doesn't exist" @@ -12529,9 +12456,8 @@ msgstr "Dispositius MIDI" #. i18n-hint: (noun) #: src/prefs/MidiIOPrefs.cpp:123 -#, fuzzy msgid "Host:" -msgstr "&Servidor:" +msgstr "Amfitrió:" #: src/prefs/MidiIOPrefs.cpp:130 msgid "Using: PortMidi" @@ -12678,12 +12604,12 @@ msgstr "Canvia la velocitat de neteja" #: src/prefs/MousePrefs.cpp:124 msgid "Zoom in on Point" -msgstr "Zoom en un punt" +msgstr "Augmenta el zoom al punt" #: src/prefs/MousePrefs.cpp:125 src/prefs/MousePrefs.cpp:127 #: src/prefs/MousePrefs.cpp:148 msgid "Zoom in on a Range" -msgstr "Zoom en un rang" +msgstr "Augmenta el zoom a l'interval" #: src/prefs/MousePrefs.cpp:125 msgid "same as right-drag" @@ -12695,7 +12621,7 @@ msgstr "Clic amb el botó secundari" #: src/prefs/MousePrefs.cpp:126 src/prefs/MousePrefs.cpp:147 msgid "Zoom out one step" -msgstr "Allunya el zoom un pas" +msgstr "Disminueix el zoom un pas" #: src/prefs/MousePrefs.cpp:127 src/prefs/MousePrefs.cpp:148 msgid "Right-Drag" @@ -12711,7 +12637,7 @@ msgstr "Majúscules+Arrossega" #: src/prefs/MousePrefs.cpp:128 msgid "Zoom out on a Range" -msgstr "Zoom en un rang" +msgstr "Disminueix el zoom a l'interval" #: src/prefs/MousePrefs.cpp:129 msgid "Middle-Click" @@ -12719,7 +12645,7 @@ msgstr "Clic del mig" #: src/prefs/MousePrefs.cpp:129 msgid "Zoom default" -msgstr "Zoom per defecte" +msgstr "Zoom predeterminat" #: src/prefs/MousePrefs.cpp:131 #, fuzzy @@ -12809,9 +12735,8 @@ msgid "-Wheel-Rotate" msgstr "-Roda del ratolí" #: src/prefs/MousePrefs.cpp:159 -#, fuzzy msgid "Zoom waveform in or out" -msgstr "Zoom en un punt" +msgstr "Amplio i redueix el zoom de la forma d'ona" #: src/prefs/MousePrefs.cpp:160 #, fuzzy @@ -12978,7 +12903,7 @@ msgstr "mil·lisegons (valor més alt = més latència)" #: src/prefs/RecordingPrefs.cpp:106 msgid "L&atency correction:" -msgstr "Correcció de &latència:" +msgstr "Correcció de la &latència:" #: src/prefs/RecordingPrefs.cpp:110 src/prefs/RecordingPrefs.cpp:111 msgid "milliseconds (negative = backwards)" @@ -13007,9 +12932,8 @@ msgid "Use Custom Track &Name" msgstr "Nom de la pista" #: src/prefs/RecordingPrefs.cpp:148 -#, fuzzy msgid "Recorded_Audio" -msgstr "So enregistrat" +msgstr "Àudio_enregistrat" #: src/prefs/RecordingPrefs.cpp:150 #, fuzzy @@ -13017,17 +12941,16 @@ msgid "Custom name text" msgstr "Exportació FFmpeg personalitzada" #: src/prefs/RecordingPrefs.cpp:155 -#, fuzzy msgid "Add &Track Number" -msgstr "Número de pista" +msgstr "Afegeix el número de pis&ta" #: src/prefs/RecordingPrefs.cpp:159 msgid "Add System &Date" -msgstr "" +msgstr "Afegeix la &data del sistema" #: src/prefs/RecordingPrefs.cpp:163 msgid "Add System T&ime" -msgstr "" +msgstr "Afegeix l'hora del s&istema" #: src/prefs/RecordingPrefs.cpp:170 msgid "Automated Recording Level Adjustment" @@ -13110,7 +13033,7 @@ msgstr "La freqüència mínima ha de ser inferior a la freqüència màxima" #: src/prefs/SpectrogramSettings.cpp:213 msgid "The range must be at least 1 dB" -msgstr "El rang ha de ser d'almenys 1 dB" +msgstr "L’interval ha de ser d'almenys 1 dB" #: src/prefs/SpectrogramSettings.cpp:221 msgid "The frequency gain cannot be negative" @@ -13142,9 +13065,8 @@ msgstr "32768 - banda més estreta" #. i18n-hint: use is a verb #: src/prefs/SpectrumPrefs.cpp:167 src/prefs/WaveformPrefs.cpp:83 -#, fuzzy msgid "&Use Preferences" -msgstr "Utilitza les preferències" +msgstr "&Utilitza les preferències" #: src/prefs/SpectrumPrefs.cpp:174 src/prefs/WaveformPrefs.cpp:91 msgid "S&cale" @@ -13168,7 +13090,7 @@ msgstr "&Guany (dB):" #: src/prefs/SpectrumPrefs.cpp:202 msgid "&Range (dB):" -msgstr "&Rang (dB):" +msgstr "Inte&rval (dB):" #: src/prefs/SpectrumPrefs.cpp:207 msgid "Frequency g&ain (dB/dec):" @@ -13249,7 +13171,7 @@ msgstr "El guany ha de ser un nombre enter" #: src/prefs/SpectrumPrefs.cpp:328 msgid "The range must be a positive integer" -msgstr "El rang ha de ser un nombre enter positiu" +msgstr "L’interval ha de ser un nombre enter positiu" #: src/prefs/SpectrumPrefs.cpp:334 msgid "The frequency gain must be an integer" @@ -13265,7 +13187,7 @@ msgstr "El nombre màxim de notes ha de ser un enter" #: src/prefs/SpectrumPrefs.cpp:351 msgid "The maximum number of notes must be in the range 1..128" -msgstr "El nombre màxim de notes ha d'estar entre 1 i 128" +msgstr "El nombre màxim de notes ha d'estar dins de l’interval 1..128" #: src/prefs/ThemePrefs.cpp:60 msgid "Theme" @@ -13380,9 +13302,8 @@ msgid "Waveform (dB)" msgstr "So en forma d'ona (dB)" #: src/prefs/TracksPrefs.cpp:89 -#, fuzzy msgid "Spectrogram" -msgstr "E&spectrograma" +msgstr "Espectrograma" #: src/prefs/TracksPrefs.cpp:107 msgid "&Pinned Recording/Playback head" @@ -13398,7 +13319,6 @@ msgid "Automatically &fit tracks vertically zoomed" msgstr "Zoom vertical automàtic que permeti &encabir-hi totes les pistes" #: src/prefs/TracksPrefs.cpp:121 -#, fuzzy msgid "Default &view mode:" msgstr "Mode de &visualització predeterminat:" @@ -13487,7 +13407,7 @@ msgstr "Quan s'&importin fitxers d'àudio sense comprimir" #: src/prefs/WaveformPrefs.cpp:29 msgid "Waveforms" -msgstr "" +msgstr "Formes d'ona" #: src/prefs/WaveformPrefs.cpp:96 msgid "Waveform dB &range" @@ -13520,9 +13440,8 @@ msgid "Skip to End" msgstr "Vés al final" #: src/toolbars/ControlToolBar.cpp:222 -#, fuzzy msgid "Loop Play" -msgstr "Reprodueix en buc&le" +msgstr "Reproducció en buc&le" #: src/toolbars/ControlToolBar.cpp:228 #, fuzzy @@ -13612,11 +13531,11 @@ msgstr "Pistes de bloqueig de sincronització" #: src/toolbars/EditToolBar.cpp:158 src/toolbars/EditToolBar.cpp:218 msgid "Zoom In" -msgstr "Apropa el zoom" +msgstr "Augmenta el zoom" #: src/toolbars/EditToolBar.cpp:160 src/toolbars/EditToolBar.cpp:219 msgid "Zoom Out" -msgstr "Allunya el zoom" +msgstr "Disminueix el zoom" #: src/toolbars/EditToolBar.cpp:163 msgid "Fit selection in window" @@ -13797,7 +13716,7 @@ msgstr "Ajusta a:" #: src/toolbars/SelectionBar.cpp:154 src/toolbars/SelectionBar.cpp:262 msgid "Selection Start:" -msgstr "Inici de la selecció:" +msgstr "Començament de la selecció:" #: src/toolbars/SelectionBar.cpp:169 src/toolbars/SelectionBar.cpp:170 #: src/toolbars/SelectionBar.cpp:269 @@ -13810,7 +13729,7 @@ msgstr "ocult" #: src/toolbars/SelectionBar.cpp:191 src/toolbars/SelectionBar.cpp:281 msgid "Audio Position:" -msgstr "Posició de so:" +msgstr "Posició del so:" #: src/toolbars/SelectionBar.cpp:248 msgid "Snap To" @@ -14465,34 +14384,28 @@ msgid "Cancel" msgstr "Cancel·la" #: src/widgets/ProgressDialog.cpp:1507 -#, fuzzy msgid "Are you sure you wish to cancel?" -msgstr "Segur que voleu eliminar %s?" +msgstr "Esteu segur que voleu cancel·lar-ho?" #: src/widgets/ProgressDialog.cpp:1507 -#, fuzzy msgid "Confirm Cancel" -msgstr "Confirmeu l'esborrament" +msgstr "Confirmeu la cancel·lació" #: src/widgets/ProgressDialog.cpp:1516 -#, fuzzy msgid "Are you sure you wish to stop?" -msgstr "Segur que voleu eliminar %s?" +msgstr "Esteu segur que voleu aturar-ho?" #: src/widgets/ProgressDialog.cpp:1516 -#, fuzzy msgid "Confirm Stop" -msgstr "Confirma" +msgstr "Confirmeu l'aturada" #: src/widgets/ProgressDialog.cpp:1526 -#, fuzzy msgid "Are you sure you wish to close?" -msgstr "Segur que voleu eliminar %s?" +msgstr "Esteu segur que voleu tancar-ho?" #: src/widgets/ProgressDialog.cpp:1526 -#, fuzzy msgid "Confirm Close" -msgstr "Confirma" +msgstr "Confirmeu el tancament" #: src/widgets/Ruler.cpp:1920 msgid "Timeline" @@ -14615,9 +14528,9 @@ msgid "Malformed number" msgstr "Format de nombre incorrecte" #: src/widgets/valnum.cpp:376 -#, fuzzy, c-format +#, c-format msgid "Not in range %d to %d" -msgstr "Fora de rang" +msgstr "No està dins de l'interval %d fins a %d" #: src/widgets/valnum.cpp:492 msgid "Value overflow" @@ -14628,19 +14541,19 @@ msgid "Too many decimal digits" msgstr "Massa dígits decimals" #: src/widgets/valnum.cpp:510 -#, fuzzy, c-format +#, c-format msgid "Value not in range: %s to %s" -msgstr "El valor no es troba dins del rang: %.*f a %.*f" +msgstr "El valor no està dins de l'interval: %s fins a %s" #: src/widgets/valnum.cpp:515 -#, fuzzy, c-format +#, c-format msgid "Value must not be less than %s" -msgstr "El valor no pot ser inferior a %.*f" +msgstr "El valor no pot ser inferior a %s" #: src/widgets/valnum.cpp:519 -#, fuzzy, c-format +#, c-format msgid "Value must not be greather than %s" -msgstr "El valor no pot ser superior a %.*f" +msgstr "El valor no pot ser superior a %s" #: src/widgets/valnum.cpp:536 msgid "e" From def0d2badad232f481077b1b3297bf0d643fd2b1 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 22 Mar 2017 16:25:49 -0400 Subject: [PATCH 49/91] Fix Linux build --- src/export/ExportMP3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/export/ExportMP3.cpp b/src/export/ExportMP3.cpp index 64cc96bb2..615035879 100644 --- a/src/export/ExportMP3.cpp +++ b/src/export/ExportMP3.cpp @@ -1685,7 +1685,7 @@ ProgressResult ExportMP3::Export(AudacityProject *project, gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT(""))); gPrefs->Flush(); - return false; + return ProgressResult::Cancelled; } #else if (!exporter.LoadLibrary(parent, MP3Exporter::Maybe)) { From 260044bcb01f75a9ad8487072e1b09c43fe1b8ec Mon Sep 17 00:00:00 2001 From: Steve Daulton Date: Wed, 22 Mar 2017 20:26:39 +0000 Subject: [PATCH 50/91] Ffix wx assert in debug build --- src/effects/nyquist/Nyquist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index ff3607504..b78157608 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -539,7 +539,7 @@ bool NyquistEffect::Process() mProps += wxString::Format(wxT("(putprop '*SYSTEM-TIME* \"%s\" 'DAY-NAME)\n"), now.GetWeekDayName(day).c_str()); // TODO: Document: Number of open projects - mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'PROJECTS)\n"), gAudacityProjects.size()); + mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'PROJECTS)\n"), (int) gAudacityProjects.size()); // TODO: Document. NOTE: unnamed project returns an empty string. mProps += wxString::Format(wxT("(putprop '*PROJECT* \"%s\" 'NAME)\n"), project->GetName().c_str()); From 7a2b199cbf0a470cf742c7cb5d8d8695decc7918 Mon Sep 17 00:00:00 2001 From: James Crook Date: Thu, 23 Mar 2017 08:46:37 +0000 Subject: [PATCH 51/91] Fix Italian Translation Typos by Lorenzo Pini --- locale/it.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/locale/it.po b/locale/it.po index 5e26c098c..fd476e609 100644 --- a/locale/it.po +++ b/locale/it.po @@ -2218,8 +2218,8 @@ msgid "" "More:
Visit our [[http://wiki.audacityteam.org/index.php|Wiki]] for " "tips, tricks, extra tutorials and effects plug-ins." msgstr "" -"Di piiù: Visita il nostro [[http://wiki.audacityteam.org/index.php|" -"Wiki]] per suggerimenti, trucchi, altri tutorial plug-in effetti." +"Di più: Visita il nostro [[http://wiki.audacityteam.org/index.php|" +"Wiki]] per suggerimenti, trucchi, altri tutorial ed effetti audio." #: src/HelpText.cpp:223 msgid "" @@ -3646,7 +3646,7 @@ msgstr "Nessuna traccia etichetta" #: src/Menus.cpp:2716 msgid "no label track at or below focused track" -msgstr "nessuna etiichetta traccia nella o sotto la traccia evidenziata" +msgstr "nessuna etichetta traccia nella o sotto la traccia evidenziata" #: src/Menus.cpp:2749 msgid "no labels in label track" @@ -8228,7 +8228,7 @@ msgstr "I passi per blocco sono troppo pochi per i tipi finestra." #: src/effects/NoiseReduction.cpp:585 msgid "Steps per block cannot exceed the window size." -msgstr "I passi per blocco non possono superare la dimensione finestra." +msgstr "I passi per blocco non possono superare la dimensione della finestra." #: src/effects/NoiseReduction.cpp:590 msgid "Median method is not implemented for more than four steps per window." @@ -11258,7 +11258,7 @@ msgid "" "Error while writing %s file (disk full?).\n" "Libsndfile says \"%s\"" msgstr "" -"Errore nella scrittura del file %s (diisco pienol?).\n" +"Errore durante la scrittura del file %s (disco pieno?).\n" "Libsndfile indica \"%s\"" #: src/import/Import.cpp:508 @@ -12386,7 +12386,7 @@ msgstr "Dispositivo:" #: src/prefs/MidiIOPrefs.cpp:146 msgid "MIDI Synthesizer Latency (ms):" -msgstr "Latenza Sintetiizzatore MIDI (ms):" +msgstr "Latenza Sintetizzatore MIDI (ms):" #: src/prefs/MidiIOPrefs.cpp:184 msgid "No MIDI interfaces" From f4ac5c23500a5e2b1109f0ff7095dd059ef60565 Mon Sep 17 00:00:00 2001 From: James Crook Date: Thu, 23 Mar 2017 08:48:36 +0000 Subject: [PATCH 52/91] Update Ukranian Translation by Yuri Chonoivan --- locale/uk.po | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/locale/uk.po b/locale/uk.po index f48d8a1c3..824f8ac31 100644 --- a/locale/uk.po +++ b/locale/uk.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: Audacity 2.0.0\n" "Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n" "POT-Creation-Date: 2017-03-18 18:41+0000\n" -"PO-Revision-Date: 2017-02-13 19:31+0200\n" +"PO-Revision-Date: 2017-03-21 19:14+0200\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -423,7 +423,7 @@ msgstr "Зупинити скрипт" #: src/AboutDialog.cpp:94 msgid "Check Online" -msgstr "" +msgstr "У інтернеті" #: src/AboutDialog.cpp:103 msgid "quality assurance" @@ -1136,9 +1136,8 @@ msgid "Could not enumerate files in auto save directory." msgstr "Неможливо скласти список файлів у теці автозбереження." #: src/AutoRecovery.cpp:760 -#, fuzzy msgid "Error Decoding File" -msgstr "Помилка під час спроби декодування файла" +msgstr "Помилка під час декодування файла" #: src/BatchCommandDialog.cpp:60 src/BatchCommandDialog.cpp:64 #: src/BatchCommandDialog.cpp:65 @@ -1486,9 +1485,8 @@ msgstr "" "іншу теку для тимчасових файлів у діалоговому вікні налаштовування програми." #: src/DirManager.cpp:424 -#, fuzzy msgid "Cleaning project temporary files" -msgstr "Вилучення тимчасових файлів" +msgstr "Вилучаємо тимчасові файли проекту" #: src/DirManager.cpp:437 msgid "Cleaning up temporary files" @@ -2169,25 +2167,32 @@ msgstr "Відсутня локальна довідка" #: src/HelpText.cpp:198 msgid "Get the Official Released Version of Audacity" -msgstr "" +msgstr "Отримати офіційну випущену версію Audacity" #: src/HelpText.cpp:200 msgid "" "

The version of Audacity you are using is an Alpha test version." msgstr "" +"

Версія Audacity, якою ви користуєтеся є попередньою тестовою " +"версією (Alpha)." #: src/HelpText.cpp:201 msgid "" "We strongly recommend that you use our latest stable released version, which " "has full documentation and support.

" msgstr "" +"Ми наполегливо рекомендуємо вам скористатися найсвіжішою стабільною версією " +"програми, яку повністю документовано і яка супроводжується розробниками.
<" +"br>" #: src/HelpText.cpp:202 msgid "" "You can help us get Audacity ready for release by joining our [[http://www." "audacityteam.org/community/|community]].


" msgstr "" +"Ви можете допомогти нам поліпшити Audacity до випуску, долучившись до нашої " +"[[http://www.audacityteam.org/community/|community]].


" #: src/HelpText.cpp:205 msgid "How to get help" @@ -2516,9 +2521,8 @@ msgstr "" "%s (%s)." #: src/Legacy.cpp:263 -#, fuzzy msgid "Error Converting Legacy Project File" -msgstr "Помилка під час спроби збереження файла проекту" +msgstr "Помилка під час спроби перетворити застарілий файл проекту" #: src/Legacy.cpp:304 #, c-format @@ -9709,17 +9713,15 @@ msgstr "" "до кодування Latin-1]" #: src/effects/nyquist/Nyquist.cpp:1638 -#, fuzzy, c-format +#, c-format msgid "" "Bad Nyquist 'control' type specification: '%s' in plug-in file '%s'.\n" "Control not created." msgstr "" -"Помилкова специфікація керування «control» Nyquist: «%s» у файлі додатка " -"«%s».\n" -"Керування не створено." +"Помилкова специфікація керування «control» Nyquist: «%s» у файлі додатка «%" +"s».\nКерування не створено." #: src/effects/nyquist/Nyquist.cpp:1746 -#, fuzzy msgid "" "Your code looks like SAL syntax, but there is no 'return' statement.\n" "For SAL, use a return statement such as:\n" @@ -9729,11 +9731,9 @@ msgid "" " ." msgstr "" "Синтаксичні конструкції вашого коду нагадують SAL, але не вказано інструкції " -"return. Вам слід або скористатися інструкцією return ось так:\n" -"\treturn s * 0.1\n" -"для SAL, або почати з дужки, ось так:\n" -"\t(mult s 0.1)\n" -"як це робиться у LISP." +"return. Вам слід або скористатися інструкцією return ось так:\n\treturn " +"*track* * 0.1\nдля SAL, або почати з дужки, ось так:\n\t(mult *track* " +"0.1)\nяк це робиться у LISP." #: src/effects/nyquist/Nyquist.cpp:1749 msgid "Error in Nyquist code" @@ -9945,9 +9945,8 @@ msgid "Error writing to file: \"%s\"" msgstr "Помилка під час спроби записати дані до файла «%s»" #: src/effects/VST/VSTEffect.cpp:3565 -#, fuzzy msgid "Error Saving Effect Presets" -msgstr "Помилка під час спроби збереження шаблону VST" +msgstr "Помилка під час спроби зберегти шаблони ефектів" #: src/effects/VST/VSTEffect.cpp:3686 #, c-format @@ -10303,9 +10302,8 @@ msgstr "Відкрити вікно нетипових параметрів фо #: src/export/ExportFFmpegDialogs.cpp:498 #: src/export/ExportFFmpegDialogs.cpp:522 -#, fuzzy msgid "Error Saving FFmpeg Presets" -msgstr "Помилка під час спроби збереження шаблону VST" +msgstr "Помилка під час спроби зберегти шаблони FFmpeg" #: src/export/ExportFFmpegDialogs.cpp:568 #, c-format @@ -14283,9 +14281,8 @@ msgid "NaN" msgstr "Не число" #: src/widgets/numformatter.cpp:146 -#, fuzzy msgid "Infinity" -msgstr "-Нескінченність" +msgstr "Нескінченність" #: src/widgets/numformatter.cpp:150 msgid "-Infinity" From a07bf9c32590b3f8672f2d94e5005c1457cfe0af Mon Sep 17 00:00:00 2001 From: Steve Daulton Date: Thu, 23 Mar 2017 11:35:31 +0000 Subject: [PATCH 53/91] Rearrange 'Skip to' menu Group "cursor to project start / end" with other "Cursor to" commands. Move remaining two "Skip to" commands to View menu (subject to change). Access keys to be decided. --- src/Menus.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index f0c26ba3a..88f8fe0d8 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -684,6 +684,17 @@ void AudacityProject::CreateMenusAndCommands() c->AddSeparator(); + + c->AddSeparator(); + c->BeginSubMenu(_("S&kip to")); + c->AddItem(wxT("SkipSelStart"), _("Selection Sta&rt"), FN(OnGoSelStart), wxT("Ctrl+["), + TimeSelectedFlag, TimeSelectedFlag); + c->AddItem(wxT("SkipSelEnd"), _("Selection En&d"), FN(OnGoSelEnd), wxT("Ctrl+]"), + TimeSelectedFlag, TimeSelectedFlag); + c->EndSubMenu(); + + c->AddSeparator(); + c->AddCheck(wxT("ShowClipping"), _("&Show Clipping"), FN(OnShowClipping), gPrefs->Read(wxT("/GUI/ShowClipping"), 0L), AlwaysEnabledFlag, AlwaysEnabledFlag); @@ -805,18 +816,6 @@ void AudacityProject::CreateMenusAndCommands() // Scrubbing sub-menu GetScrubber().AddMenuItems(); - c->AddSeparator(); - c->BeginSubMenu(_("Skip to")); - c->AddItem(wxT("GoSelStart"), _("Selection Sta&rt"), FN(OnGoSelStart), wxT("Ctrl+["), TimeSelectedFlag, TimeSelectedFlag); - c->AddItem(wxT("GoSelEnd"), _("Selection En&d"), FN(OnGoSelEnd), wxT("Ctrl+]"), TimeSelectedFlag, TimeSelectedFlag); - - c->AddItem(wxT("SkipStart"), _("Track Start"), FN(OnSkipStart), wxT("Home"), - AudioIONotBusyFlag, AudioIONotBusyFlag); - c->AddItem(wxT("SkipEnd"), _("Track E&nd"), FN(OnSkipEnd), wxT("End"), - WaveTracksExistFlag | AudioIONotBusyFlag, - WaveTracksExistFlag | AudioIONotBusyFlag); - c->EndSubMenu(); - #ifndef EXPERIMENTAL_DA // JKC: ANSWER-ME: How is this different to 'Skip To' and how is it useful? c->BeginSubMenu(_("Cursor to")); @@ -827,6 +826,9 @@ void AudacityProject::CreateMenusAndCommands() c->AddItem(wxT("CursTrackStart"), _("Track &Start"), FN(OnCursorTrackStart), wxT("J")); c->AddItem(wxT("CursTrackEnd"), _("Track &End"), FN(OnCursorTrackEnd), wxT("K")); + c->AddItem(wxT("CursProjectStart"), _("&Project Start"), FN(OnSkipStart), wxT("Home")); + c->AddItem(wxT("CursProjectEnd"), _("Project E&nd"), FN(OnSkipEnd), wxT("End")); + c->EndSubMenu(); #endif From 3ffcc29bf643155d79c33f0e29b26f12f962862e Mon Sep 17 00:00:00 2001 From: James Crook Date: Thu, 23 Mar 2017 18:38:28 +0000 Subject: [PATCH 54/91] Add code to capture command List Capture the commands and key bindings to debug channel: a) From the menus b) from the preferences. --- src/commands/ScreenshotCommand.cpp | 8 +++++++- src/widgets/KeyView.cpp | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/commands/ScreenshotCommand.cpp b/src/commands/ScreenshotCommand.cpp index 56f4d91fa..ef3f62f4d 100644 --- a/src/commands/ScreenshotCommand.cpp +++ b/src/commands/ScreenshotCommand.cpp @@ -275,13 +275,19 @@ void ExploreMenu( wxMenu * pMenu, int Id, int depth ){ size_t lcnt = list.GetCount(); wxMenuItem * item; wxString Label; + wxString Accel; for (size_t lndx = 0; lndx < lcnt; lndx++) { item = list.Item(lndx)->GetData(); Label = item->GetItemLabelText(); + Accel = item->GetItemLabel(); + if( Accel.Contains("\t") ) + Accel = Accel.AfterLast('\t'); + else + Accel = ""; if( item->IsSeparator() ) Label = "----"; - wxLogDebug("%2i: %s", depth, Label ); + wxLogDebug("%2i,%s,%s", depth, Label,Accel ); if (item->IsSubMenu()) { pMenu = item->GetSubMenu(); ExploreMenu( pMenu, item->GetId(), depth+1 ); diff --git a/src/widgets/KeyView.cpp b/src/widgets/KeyView.cpp index b8467c591..de65a6cdf 100644 --- a/src/widgets/KeyView.cpp +++ b/src/widgets/KeyView.cpp @@ -351,6 +351,11 @@ KeyView::SetView(ViewByType type) SelectNode(index); } + int nLines = mLines.GetCount(); + for(int i=0;idepth, mLines[i]->label, mLines[i]->key ); + } + return; } From 78149bc3da4a7d18c0487baf7002b23759a814c3 Mon Sep 17 00:00:00 2001 From: James Crook Date: Thu, 23 Mar 2017 18:48:00 +0000 Subject: [PATCH 55/91] Disable command-list capture code, by default. Also added a comment to say what it is. --- src/widgets/KeyView.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/widgets/KeyView.cpp b/src/widgets/KeyView.cpp index de65a6cdf..87e2bfe06 100644 --- a/src/widgets/KeyView.cpp +++ b/src/widgets/KeyView.cpp @@ -351,10 +351,13 @@ KeyView::SetView(ViewByType type) SelectNode(index); } +#if 0 + // JKC: Optional code to list commants and shortcuts to debug console. int nLines = mLines.GetCount(); for(int i=0;idepth, mLines[i]->label, mLines[i]->key ); } +#endif return; } From e2a72826901c10f88314bb80cdf1a80095515474 Mon Sep 17 00:00:00 2001 From: windinthew Date: Mon, 27 Mar 2017 05:36:10 +0100 Subject: [PATCH 56/91] Fix wording issues reported on Wiki No ellipses in title bar of file open/import dialogs Auto Recovery Discard dialogs say only recoverable projects are discarded Capitalised button in Dependency dialogue per MS guidelines. --- src/AutoRecovery.cpp | 2 +- src/Dependencies.cpp | 4 ++-- src/LabelDialog.cpp | 2 +- src/Menus.cpp | 6 +++--- src/Project.cpp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/AutoRecovery.cpp b/src/AutoRecovery.cpp index 9c6652227..4d7471fa1 100644 --- a/src/AutoRecovery.cpp +++ b/src/AutoRecovery.cpp @@ -135,7 +135,7 @@ void AutoRecoveryDialog::OnQuitAudacity(wxCommandEvent & WXUNUSED(event)) void AutoRecoveryDialog::OnRecoverNone(wxCommandEvent & WXUNUSED(event)) { int ret = wxMessageBox( - _("Are you sure you want to discard all projects?\n\nChoosing \"Yes\" discards all projects immediately."), + _("Are you sure you want to discard all recoverable projects?\n\nChoosing \"Yes\" discards all recoverable projects immediately."), _("Confirm Discard Projects"), wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT, this); if (ret == wxYES) diff --git a/src/Dependencies.cpp b/src/Dependencies.cpp index 1406e30b5..6b43ab9fa 100644 --- a/src/Dependencies.cpp +++ b/src/Dependencies.cpp @@ -278,7 +278,7 @@ BEGIN_EVENT_TABLE(DependencyDialog, wxDialogWrapper) EVT_LIST_ITEM_DESELECTED(FileListID, DependencyDialog::OnList) EVT_BUTTON(CopySelectedFilesButtonID, DependencyDialog::OnCopySelectedFiles) EVT_SIZE(DependencyDialog::OnSize) - EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) // mIsSaving ? "Cancel Save" : "Save without Copying" + EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) // mIsSaving ? "Cancel Save" : "Save Without Copying" EVT_BUTTON(wxID_YES, DependencyDialog::OnYes) // "Copy All Files (Safer)" EVT_BUTTON(wxID_CANCEL, DependencyDialog::OnCancel) // "Cancel Save" END_EVENT_TABLE() @@ -349,7 +349,7 @@ void DependencyDialog::PopulateOrExchange(ShuttleGui& S) { if (mIsSaving) { S.Id(wxID_CANCEL).AddButton(_("Cancel Save")); - S.Id(wxID_NO).AddButton(_("Save without Copying")); + S.Id(wxID_NO).AddButton(_("Save Without Copying")); } else S.Id(wxID_NO).AddButton(_("Do Not Copy")); diff --git a/src/LabelDialog.cpp b/src/LabelDialog.cpp index cdb22c0f2..1c5852e1f 100644 --- a/src/LabelDialog.cpp +++ b/src/LabelDialog.cpp @@ -589,7 +589,7 @@ void LabelDialog::OnImport(wxCommandEvent & WXUNUSED(event)) // Ask user for a filename wxString fileName = - FileSelector(_("Select a text file containing labels..."), + FileSelector(_("Select a text file containing labels"), path, // Path wxT(""), // Name wxT(".txt"), // Extension diff --git a/src/Menus.cpp b/src/Menus.cpp index 88f8fe0d8..94725af9a 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -5811,7 +5811,7 @@ void AudacityProject::OnImportLabels() wxString path = gPrefs->Read(wxT("/DefaultOpenPath"),::wxGetCwd()); wxString fileName = - FileSelector(_("Select a text file containing labels..."), + FileSelector(_("Select a text file containing labels"), path, // Path wxT(""), // Name wxT(".txt"), // Extension @@ -5856,7 +5856,7 @@ void AudacityProject::OnImportMIDI() { wxString path = gPrefs->Read(wxT("/DefaultOpenPath"),::wxGetCwd()); - wxString fileName = FileSelector(_("Select a MIDI file..."), + wxString fileName = FileSelector(_("Select a MIDI file"), path, // Path wxT(""), // Name wxT(""), // Extension @@ -5907,7 +5907,7 @@ void AudacityProject::OnImportRaw() wxString path = gPrefs->Read(wxT("/DefaultOpenPath"),::wxGetCwd()); wxString fileName = - FileSelector(_("Select any uncompressed audio file..."), + FileSelector(_("Select any uncompressed audio file"), path, // Path wxT(""), // Name wxT(""), // Extension diff --git a/src/Project.cpp b/src/Project.cpp index 4c61ae08d..a12a43f97 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -2800,7 +2800,7 @@ wxArrayString AudacityProject::ShowOpenDialog(const wxString &extraformat, const wxArrayString selected; FileDialog dlog(NULL, - _("Select one or more audio files..."), + _("Select one or more files"), path, wxT(""), mask, From bdb0790150beb4abd61ea61612adb858c3b53a88 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sat, 18 Mar 2017 21:15:07 -0700 Subject: [PATCH 57/91] Fix compiling when USE_MIDI not is defined Compilation broke in TrackPanel in ed277ec and in TrackpanelAx in a96c719c. --- src/TrackPanel.cpp | 7 +++++-- src/TrackPanelAx.cpp | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 4db2b03f0..c977175c7 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -3732,8 +3732,11 @@ void TrackPanel::DoSlide(wxMouseEvent & event) #else { trySnap = true; - desiredSlideAmount = rint(mouseTrack->GetRate() * desiredSlideAmount) / - mouseTrack->GetRate(); // set it to a sample point + if (mouseTrack->GetKind() == Track::Wave) { + WaveTrack *mtw = (WaveTrack *)mouseTrack; + desiredSlideAmount = rint(mtw->GetRate() * desiredSlideAmount) / + mtw->GetRate(); // set it to a sample point + } if (mSnapManager && mCapturedClip) { clipLeft = mCapturedClip->GetStartTime() + desiredSlideAmount; clipRight = mCapturedClip->GetEndTime() + desiredSlideAmount; diff --git a/src/TrackPanelAx.cpp b/src/TrackPanelAx.cpp index 145b7f3a3..bf9a4ec7c 100644 --- a/src/TrackPanelAx.cpp +++ b/src/TrackPanelAx.cpp @@ -353,12 +353,14 @@ wxAccStatus TrackPanelAx::GetName( int childId, wxString* name ) this is a Time track.*/ name->Append( wxT(" ") + wxString(_("Time Track"))); } +#ifdef USE_MIDI else if (t->GetKind() == Track::Note) { /* i18n-hint: This is for screen reader software and indicates that this is a Note track.*/ name->Append( wxT(" ") + wxString(_("Note Track"))); } +#endif // LLL: Remove these during "refactor" if( t->GetMute() ) From 0ce95982748363af7e9ea65f1f754294de07ab2c Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 21 Feb 2017 18:05:35 -0800 Subject: [PATCH 58/91] Fix midi-related compile problems in AudioIO and NoteTrack The compilation was broken in 67cec5a but fixed in ed8c7fd. However, the warnings weren't fixed. The same general sign-related changes from 67cec5a were applied, fixing several warnings. This also changes the arguments for NoteTrack's label click handler, to match the ones found in TrackPanel. That's needed to handle some other const-related changes. Additionally, EXPERIMENTAL_MIDI_PLAYBACK was changed to EXPERIMENTAL_MIDI_OUT in the documentation, as that is the correct name. --- src/AudioIO.cpp | 8 ++++---- src/NoteTrack.cpp | 4 ++-- src/NoteTrack.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index ccddc5cb0..90afd7986 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -28,8 +28,8 @@ To highlight this deliniation, the file is divided into three parts based on what thread context each function is intended to run in. - \par EXPERIMENTAL_MIDI_PLAYBACK - If EXPERIMENTAL_MIDI_PLAYBACK is defined, this class also manages + \par EXPERIMENTAL_MIDI_OUT + If EXPERIMENTAL_MIDI_OUT is defined, this class also manages MIDI playback. The reason for putting MIDI here rather than in, say, class MidiIO, is that there is no high-level synchronization and transport architecture, so Audio and MIDI must be coupled in order @@ -3897,7 +3897,7 @@ void AudioIO::FillMidiBuffers() hasSolo = true; break; } - int numMidiPlaybackTracks = gAudioIO->mMidiPlaybackTracks.size(); + auto numMidiPlaybackTracks = gAudioIO->mMidiPlaybackTracks.size(); for(unsigned t = 0; t < numMidiPlaybackTracks; t++ ) if( gAudioIO->mMidiPlaybackTracks[t]->GetSolo() ) { hasSolo = true; @@ -4370,7 +4370,7 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, if( gAudioIO->mPlaybackTracks[t]->GetSolo() ) numSolo++; #ifdef EXPERIMENTAL_MIDI_OUT - int numMidiPlaybackTracks = gAudioIO->mMidiPlaybackTracks.size(); + auto numMidiPlaybackTracks = gAudioIO->mMidiPlaybackTracks.size(); for( unsigned t = 0; t < numMidiPlaybackTracks; t++ ) if( gAudioIO->mMidiPlaybackTracks[t]->GetSolo() ) numSolo++; diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 27b770469..f18931d01 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -239,7 +239,7 @@ void NoteTrack::WarpAndTransposeNotes(double t0, double t1, -int NoteTrack::DrawLabelControls(wxDC & dc, wxRect & r) +int NoteTrack::DrawLabelControls(wxDC & dc, const wxRect &r) { int wid = 23; int ht = 16; @@ -328,7 +328,7 @@ int NoteTrack::DrawLabelControls(wxDC & dc, wxRect & r) return box.GetBottom(); } -bool NoteTrack::LabelClick(wxRect & r, int mx, int my, bool right) +bool NoteTrack::LabelClick(const wxRect &r, int mx, int my, bool right) { int wid = 23; int ht = 16; diff --git a/src/NoteTrack.h b/src/NoteTrack.h index 30a034f22..7ea8a0ccf 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -69,8 +69,8 @@ class AUDACITY_DLL_API NoteTrack final : public Track { void WarpAndTransposeNotes(double t0, double t1, const TimeWarper &warper, double semitones); - int DrawLabelControls(wxDC & dc, wxRect & r); - bool LabelClick(wxRect & r, int x, int y, bool right); + int DrawLabelControls(wxDC & dc, const wxRect &r); + bool LabelClick(const wxRect &rect, int x, int y, bool right); void SetSequence(std::unique_ptr &&seq); Alg_seq* GetSequence(); From 2d912f3c934a988016391247e4cbbdb79ac473c2 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 21 Feb 2017 18:05:35 -0800 Subject: [PATCH 59/91] Replace assert calls with wxASSERT --- src/Menus.cpp | 2 +- src/MixerBoard.cpp | 2 +- src/NoteTrack.cpp | 10 +++++----- src/TrackArtist.cpp | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 94725af9a..b854edc52 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -6527,7 +6527,7 @@ void AudacityProject::OnScoreAlign() if (alignedNoteTrack->GetSequence() == NULL) { holder = alignedNoteTrack->Duplicate(); alignedNoteTrack = static_cast(holder.get()); - assert(alignedNoteTrack->GetSequence()); + wxASSERT(alignedNoteTrack->GetSequence()); } // Remove offset from NoteTrack because audio is // mixed starting at zero and incorporating clip offsets. diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 3514cd1eb..273465385 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -1175,7 +1175,7 @@ void MixerBoard::RemoveTrackCluster(const WaveTrack* pTrack) // Sanity check: if there is still a MixerTrackCluster with pTrack, then // we deleted the first but should have deleted the last: FindMixerTrackCluster(pTrack, &pMixerTrackCluster); - assert(pMixerTrackCluster == NULL); + wxASSERT(pMixerTrackCluster == NULL); #endif } diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index f18931d01..9f40661ee 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -137,7 +137,7 @@ Track::Holder NoteTrack::Duplicate() const // project object. if (mSeq) { SonifyBeginSerialize(); - assert(!mSerializationBuffer); + wxASSERT(!mSerializationBuffer); // serialize from this to duplicate's mSerializationBuffer void *buffer; mSeq->serialize(&buffer, @@ -146,13 +146,13 @@ Track::Holder NoteTrack::Duplicate() const SonifyEndSerialize(); } else if (mSerializationBuffer) { SonifyBeginUnserialize(); - assert(!mSeq); + wxASSERT(!mSeq); std::unique_ptr alg_track{ Alg_seq::unserialize(mSerializationBuffer.get(), mSerializationLength) }; - assert(alg_track->get_type() == 's'); + wxASSERT(alg_track->get_type() == 's'); duplicate->mSeq.reset(static_cast(alg_track.release())); SonifyEndUnserialize(); - } else assert(false); // bug if neither mSeq nor mSerializationBuffer + } else wxFAIL_MSG("neither mSeq nor mSerializationBuffer were present"); // bug if neither mSeq nor mSerializationBuffer // copy some other fields here duplicate->SetBottomNote(mBottomNote); duplicate->SetPitchHeight(mPitchHeight); @@ -826,7 +826,7 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const if (!mSeq) { // replace saveme with an (unserialized) duplicate holder = Duplicate(); saveme = static_cast(holder.get()); - assert(saveme->mSeq); + wxASSERT(saveme->mSeq); } saveme->mSeq->write(data, true); xmlFile.StartTag(wxT("notetrack")); diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index 4ab3901b3..7ed78c988 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -2807,17 +2807,17 @@ void TrackArtist::DrawNoteTrack(const NoteTrack *track, Alg_seq_ptr seq = track->mSeq.get(); if (!seq) { - assert(track->mSerializationBuffer); + wxASSERT(track->mSerializationBuffer); // JKC: Previously this indirected via seq->, a NULL pointer. // This was actually OK, since unserialize is a static function. // Alg_seq:: is clearer. std::unique_ptr alg_track{ Alg_seq::unserialize(track->mSerializationBuffer.get(), track->mSerializationLength) }; - assert(alg_track->get_type() == 's'); + wxASSERT(alg_track->get_type() == 's'); const_cast(track)->mSeq.reset(seq = static_cast(alg_track.release())); track->mSerializationBuffer.reset(); } - assert(seq); + wxASSERT(seq); int visibleChannels = track->mVisibleChannels; if (!track->GetSelected()) From 5badb9174aa3ca3159c9b2bc97dc35e2c294044f Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 27 Mar 2017 01:37:38 -0400 Subject: [PATCH 60/91] Needed to compile Pokechu22's fix-midi-output on Mac --- src/MixerBoard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 273465385..275b4d7e1 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -340,7 +340,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, wxSizeEvent event(GetSize(), GetId()); event.SetEventObject(this); GetEventHandler()->ProcessEvent(event); - UpdateGain(); + // UpdateGain(); // PRL: No such name. Proper compilation fix? #endif } From 9dadc5af6d003416a3d54cb7a04455320a1338f5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 27 Mar 2017 23:40:10 -0400 Subject: [PATCH 61/91] Revert "Needed to compile Pokechu22's fix-midi-output on Mac" This reverts commit 5badb9174aa3ca3159c9b2bc97dc35e2c294044f. --- src/MixerBoard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 275b4d7e1..273465385 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -340,7 +340,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, wxSizeEvent event(GetSize(), GetId()); event.SetEventObject(this); GetEventHandler()->ProcessEvent(event); - // UpdateGain(); // PRL: No such name. Proper compilation fix? + UpdateGain(); #endif } From c20a3526a6c07a6763e4334b47db67be7d8f8d69 Mon Sep 17 00:00:00 2001 From: James Crook Date: Wed, 29 Mar 2017 09:15:50 +0100 Subject: [PATCH 62/91] Update Chinese Translation by zhangmin --- locale/zh_CN.po | 294 +++++++++++++++++++++++++----------------------- 1 file changed, 153 insertions(+), 141 deletions(-) diff --git a/locale/zh_CN.po b/locale/zh_CN.po index fd30b5958..d41cec4c6 100644 --- a/locale/zh_CN.po +++ b/locale/zh_CN.po @@ -12,7 +12,7 @@ msgstr "" "Project-Id-Version: Audacity\n" "Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n" "POT-Creation-Date: 2017-03-18 18:41+0000\n" -"PO-Revision-Date: 2016-07-03 12:19+0000\n" +"PO-Revision-Date: 2017-03-27 15:01+0800\n" "Last-Translator: zhangmin \n" "Language-Team: Chinese (http://www.transifex.com/klyok/audacity/language/" "zh/)\n" @@ -21,6 +21,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Poedit 1.8.12\n" #: lib-src/FileDialog/gtk/FileDialogPrivate.cpp:75 #, c-format @@ -39,17 +40,16 @@ msgstr "请选择一个已存在的文件。" #: src/AutoRecovery.cpp:195 src/Menus.cpp:4294 src/Menus.cpp:4306 #: src/Menus.cpp:7005 src/Menus.cpp:7084 src/Project.cpp:3124 #: src/Project.cpp:5118 src/Project.cpp:5137 src/TimerRecordDialog.cpp:471 -#: src/TimerRecordDialog.cpp:649 src/TrackPanel.cpp:8489 -#: src/WaveTrack.cpp:1316 src/WaveTrack.cpp:1335 src/WaveTrack.cpp:2487 -#: src/effects/Contrast.cpp:56 src/effects/Contrast.cpp:75 -#: src/effects/Contrast.cpp:82 src/effects/Contrast.cpp:96 -#: src/effects/Effect.cpp:2584 src/effects/Generator.cpp:59 -#: src/effects/nyquist/Nyquist.cpp:411 src/export/ExportFFmpeg.cpp:842 -#: src/export/ExportMP2.cpp:229 src/prefs/DirectoriesPrefs.cpp:210 -#: src/prefs/DirectoriesPrefs.cpp:239 src/prefs/KeyConfigPrefs.cpp:509 -#: src/prefs/KeyConfigPrefs.cpp:523 src/prefs/KeyConfigPrefs.cpp:548 -#: src/prefs/KeyConfigPrefs.cpp:1038 src/toolbars/ControlToolBar.cpp:686 -#: src/toolbars/ControlToolBar.cpp:1122 +#: src/TimerRecordDialog.cpp:649 src/TrackPanel.cpp:8489 src/WaveTrack.cpp:1316 +#: src/WaveTrack.cpp:1335 src/WaveTrack.cpp:2487 src/effects/Contrast.cpp:56 +#: src/effects/Contrast.cpp:75 src/effects/Contrast.cpp:82 +#: src/effects/Contrast.cpp:96 src/effects/Effect.cpp:2584 +#: src/effects/Generator.cpp:59 src/effects/nyquist/Nyquist.cpp:411 +#: src/export/ExportFFmpeg.cpp:842 src/export/ExportMP2.cpp:229 +#: src/prefs/DirectoriesPrefs.cpp:210 src/prefs/DirectoriesPrefs.cpp:239 +#: src/prefs/KeyConfigPrefs.cpp:509 src/prefs/KeyConfigPrefs.cpp:523 +#: src/prefs/KeyConfigPrefs.cpp:548 src/prefs/KeyConfigPrefs.cpp:1038 +#: src/toolbars/ControlToolBar.cpp:686 src/toolbars/ControlToolBar.cpp:1122 msgid "Error" msgstr "错误" @@ -179,14 +179,12 @@ msgstr "脚本" msgid "Output" msgstr "输出" -#: lib-src/mod-nyq-bench/NyqBench.cpp:1051 -#: src/effects/nyquist/Nyquist.cpp:2214 +#: lib-src/mod-nyq-bench/NyqBench.cpp:1051 src/effects/nyquist/Nyquist.cpp:2214 msgid "Load Nyquist script" msgstr "加载 Nyquist 脚本" #: lib-src/mod-nyq-bench/NyqBench.cpp:1054 -#: lib-src/mod-nyq-bench/NyqBench.cpp:1100 -#: src/effects/nyquist/Nyquist.cpp:2239 +#: lib-src/mod-nyq-bench/NyqBench.cpp:1100 src/effects/nyquist/Nyquist.cpp:2239 msgid "Nyquist scripts (*.ny)|*.ny|Lisp scripts (*.lsp)|*.lsp|All files|*" msgstr "Nyquist 脚本 (*.ny)|*.ny|Lisp 脚本 (*.lsp)|*.lsp|所有文件|*" @@ -204,8 +202,7 @@ msgstr "脚本未被保存。" msgid "Warning" msgstr "警告" -#: lib-src/mod-nyq-bench/NyqBench.cpp:1097 -#: src/effects/nyquist/Nyquist.cpp:2236 +#: lib-src/mod-nyq-bench/NyqBench.cpp:1097 src/effects/nyquist/Nyquist.cpp:2236 msgid "Save Nyquist script" msgstr "保存 Nyquist 脚本" @@ -223,11 +220,11 @@ msgstr "Tango 图标库 (工具栏图标)" #: lib-src/mod-nyq-bench/NyqBench.cpp:1417 msgid "Leland Lucius" -msgstr "Leland Lucius" +msgstr "利兰卢修斯\\N" #: lib-src/mod-nyq-bench/NyqBench.cpp:1418 msgid "(C) 2009 by Leland Lucius" -msgstr "(C) 2009 by Leland Lucius" +msgstr "(C) 2009 by 利兰卢修斯\\N" #: lib-src/mod-nyq-bench/NyqBench.cpp:1419 msgid "" @@ -423,7 +420,7 @@ msgstr "停止脚本" #: src/AboutDialog.cpp:94 msgid "Check Online" -msgstr "" +msgstr "在线检查" #: src/AboutDialog.cpp:103 msgid "quality assurance" @@ -431,7 +428,7 @@ msgstr "质量保证" #: src/AboutDialog.cpp:104 msgid "system administration" -msgstr "" +msgstr "系统管理\\N" #: src/AboutDialog.cpp:105 src/AboutDialog.cpp:108 src/AboutDialog.cpp:110 #: src/AboutDialog.cpp:112 src/AboutDialog.cpp:118 src/AboutDialog.cpp:120 @@ -457,28 +454,28 @@ msgstr "包络线" #: src/AboutDialog.cpp:106 src/AboutDialog.cpp:127 msgid "co-founder and developer" -msgstr "" +msgstr "联合创始人和开发者\\N" #: src/AboutDialog.cpp:109 src/AboutDialog.cpp:113 src/AboutDialog.cpp:131 #: src/AboutDialog.cpp:132 msgid "documentation and support" -msgstr "" +msgstr "文档和支持\\N" #: src/AboutDialog.cpp:119 msgid "documentation and support, French" -msgstr "" +msgstr "文档和支持,法语" #: src/AboutDialog.cpp:137 msgid "accessibility advisor" -msgstr "" +msgstr "无障碍顾问" #: src/AboutDialog.cpp:156 msgid "graphic artist" -msgstr "" +msgstr "图形艺术家\\N" #: src/AboutDialog.cpp:163 msgid "composer" -msgstr "" +msgstr "作曲家\\N" #: src/AboutDialog.cpp:166 #, fuzzy @@ -513,7 +510,6 @@ msgstr "" "\">Audacity支持Windows、Mac OS X和GNU/Linux(以及其它的Unix类操作系统)。" #: src/AboutDialog.cpp:337 -#, fuzzy msgid "" "If you find a bug or have a suggestion for us, please write, in English, to " "our [[mailto:feedback@audacityteam.org|feedback address]]. For help, view " @@ -522,8 +518,8 @@ msgid "" msgstr "" "如果你找到一个bug或者有建议给我们,请用英语书写,发邮件到 反馈地址。如果想获得帮助,查看小贴士和小技" -"巧,请访问wiki论坛。" +"巧,请访问audacity维基audacity论坛。" #. i18n-hint: The translation of "translator_credits" will appear #. * in the credits in the About Audacity window. Use this to add @@ -555,11 +551,11 @@ msgstr "Audacity开发人员" #: src/AboutDialog.cpp:368 msgid "Emeritus:" -msgstr "" +msgstr "名誉:" #: src/AboutDialog.cpp:369 msgid "Distinguished Audacity Team members, not currently active" -msgstr "" +msgstr "杰出的Audacity团队成员,目前不活跃" #: src/AboutDialog.cpp:372 #, fuzzy @@ -567,9 +563,8 @@ msgid "Contributors" msgstr "其他贡献者" #: src/AboutDialog.cpp:375 -#, fuzzy msgid "Translators" -msgstr "播录" +msgstr "翻译" #: src/AboutDialog.cpp:379 src/prefs/LibraryPrefs.cpp:49 msgid "Libraries" @@ -596,6 +591,7 @@ msgid "" "Audacity website: [[http://www.audacityteam.org/|http://www.audacityteam." "org/]]" msgstr "" +"Audacity网站:[[http://www.audacityteam.org/|http://www.audacityteam.org/]]" #. i18n-hint: Information about when audacity was compiled #: src/AboutDialog.cpp:446 src/AboutDialog.cpp:459 src/AboutDialog.cpp:631 @@ -760,7 +756,7 @@ msgstr "文件丢失" #: src/AudacityApp.cpp:1047 #, c-format msgid "Language \"%s\" is unknown" -msgstr "" +msgstr "语言 \"%s\"未知" #: src/AudacityApp.cpp:1170 msgid "Report generated to:" @@ -939,8 +935,8 @@ msgstr "Audacity日志" msgid "&Save..." msgstr "保存...(&S)" -#: src/AudacityLogger.cpp:199 src/Tags.cpp:883 -#: src/prefs/KeyConfigPrefs.cpp:273 src/prefs/KeyConfigPrefs.cpp:781 +#: src/AudacityLogger.cpp:199 src/Tags.cpp:883 src/prefs/KeyConfigPrefs.cpp:273 +#: src/prefs/KeyConfigPrefs.cpp:781 msgid "Cl&ear" msgstr "清除(&e)" @@ -2119,25 +2115,27 @@ msgstr "没有本地帮助" #: src/HelpText.cpp:198 msgid "Get the Official Released Version of Audacity" -msgstr "" +msgstr "获得Audacity的官方发布版本" #: src/HelpText.cpp:200 msgid "" "

The version of Audacity you are using is an Alpha test version." -msgstr "" +msgstr "

您所使用的Audacity版本是 内部测试版." #: src/HelpText.cpp:201 msgid "" "We strongly recommend that you use our latest stable released version, which " "has full documentation and support.

" -msgstr "" +msgstr "我们强烈建议您使用我们最新的稳定版本,它具有完整的文档和支持。

" #: src/HelpText.cpp:202 msgid "" "You can help us get Audacity ready for release by joining our [[http://www." "audacityteam.org/community/|community]].


" msgstr "" +"您可以通过加入我们来帮助我们让Audacity准备发布 [[http://www.audacityteam.org/" +"community/|audacity社区]].


" #: src/HelpText.cpp:205 #, fuzzy @@ -2305,12 +2303,12 @@ msgstr "指定新文件名:" #. i18n-hint: An opening parenthesis, in some languages a right parenthesis #: src/Internat.cpp:265 msgid "(" -msgstr "" +msgstr "(" #. i18n-hint: A closing parenthesis, in some languages a left parenthesis #: src/Internat.cpp:267 msgid ")" -msgstr "" +msgstr ")" #: src/LabelDialog.cpp:102 msgid "Edit Labels" @@ -2732,7 +2730,7 @@ msgstr "光标移至音轨末(&E)" #: src/Menus.cpp:561 msgid "Cursor to Stored &Cursor Position" -msgstr "" +msgstr "游标存储光标位置" #: src/Menus.cpp:567 msgid "In All &Tracks" @@ -2768,15 +2766,15 @@ msgstr "到音轨结束点(&E)" #: src/Menus.cpp:600 msgid "Store Re&gion" -msgstr "" +msgstr "存储区域" #: src/Menus.cpp:603 msgid "Retrieve Regio&n" -msgstr "" +msgstr "检索区域&n" #: src/Menus.cpp:606 msgid "Store Cursor Pos&ition" -msgstr "" +msgstr "存储光标位置" #: src/Menus.cpp:614 msgid "Pla&y Region" @@ -2976,7 +2974,7 @@ msgstr "追加录音(&d)" #: src/Menus.cpp:788 msgid "Pinned Recording/Playback &Head" -msgstr "" +msgstr "固定录音/播放头" #: src/Menus.cpp:793 msgid "&Overdub (on/off)" @@ -3115,7 +3113,7 @@ msgstr "编辑标记(&E)" #: src/Menus.cpp:931 msgid "&Type to Create a Label (on/off)" -msgstr "" +msgstr "&键入以创建标签(开/关)" #: src/Menus.cpp:938 msgid "S&ort Tracks" @@ -3185,7 +3183,7 @@ msgstr "缩放" #: src/Menus.cpp:1055 msgid "&Bring All to Front" -msgstr "" +msgstr "全部带到前面" #: src/Menus.cpp:1066 src/Menus.cpp:1069 src/effects/Contrast.cpp:298 msgid "&Help" @@ -4105,7 +4103,7 @@ msgid "" "Timer Recording cannot be used with more than one open project.\n" "\n" "Please close any additional projects and try again." -msgstr "" +msgstr "定时录制不能与多个打开的项目一起使用。请关闭任何其他项目,然后重试。" #: src/Menus.cpp:6547 src/Menus.cpp:6558 src/TimerRecordDialog.cpp:658 #, fuzzy @@ -4117,7 +4115,7 @@ msgid "" "Timer Recording cannot be used while you have unsaved changes.\n" "\n" "Please save or close this project and try again." -msgstr "" +msgstr "在保存更改时,无法使用定时录像。请保存或关闭此项目,然后重试。" #: src/Menus.cpp:6731 msgid "Edited labels" @@ -4817,7 +4815,7 @@ msgstr "删除轨道" #: src/Project.cpp:5605 msgid "Less than 1 minute" -msgstr "" +msgstr "不到1分钟" #. i18n-hint: A time in hours and minutes. Only translate the "and". #: src/Project.cpp:5618 @@ -5299,7 +5297,7 @@ msgstr "持续时间错误" #: src/TimerRecordDialog.cpp:374 msgid "Automatic Save path is invalid." -msgstr "" +msgstr "自动保存路径无效。" #: src/TimerRecordDialog.cpp:375 #, fuzzy @@ -5308,7 +5306,7 @@ msgstr "持续时间错误" #: src/TimerRecordDialog.cpp:381 msgid "Automatic Export path is invalid." -msgstr "" +msgstr "自动导出路径无效。" #: src/TimerRecordDialog.cpp:382 #, fuzzy @@ -5317,7 +5315,7 @@ msgstr "持续时间错误" #: src/TimerRecordDialog.cpp:419 msgid "Timer Recording Disk Space Warning" -msgstr "" +msgstr "计时器记录磁盘空间通知" #: src/TimerRecordDialog.cpp:461 src/TimerRecordDialog.cpp:869 #, fuzzy @@ -5343,11 +5341,11 @@ msgstr "录制结束" #: src/TimerRecordDialog.cpp:528 src/TimerRecordDialog.cpp:1006 msgid "Automatic Save enabled:\n" -msgstr "" +msgstr "自动保存启用:\n" #: src/TimerRecordDialog.cpp:529 src/TimerRecordDialog.cpp:1007 msgid "Automatic Export enabled:\n" -msgstr "" +msgstr "自动导出启用:\n" #: src/TimerRecordDialog.cpp:530 src/TimerRecordDialog.cpp:1008 #: src/TimerRecordDialog.cpp:1051 @@ -5449,7 +5447,7 @@ msgstr "选项:" #: src/TimerRecordDialog.cpp:900 msgid "Do nothing" -msgstr "" +msgstr "什么都不做" #: src/TimerRecordDialog.cpp:901 #, fuzzy @@ -5458,11 +5456,11 @@ msgstr "退出 Audacity" #: src/TimerRecordDialog.cpp:902 msgid "Restart system" -msgstr "" +msgstr "重启系统" #: src/TimerRecordDialog.cpp:903 msgid "Shutdown system" -msgstr "" +msgstr "关机系统" #: src/TimerRecordDialog.cpp:913 #, fuzzy @@ -5483,7 +5481,7 @@ msgstr "录制音频" msgid "" "Scheduled to stop at:\n" "\n" -msgstr "" +msgstr "计划停在:\n" #: src/TimerRecordDialog.cpp:1024 msgid "Audacity Timer Record - Waiting for Start" @@ -5578,7 +5576,7 @@ msgstr "格式(&F)" #: src/TrackPanel.cpp:640 msgid "Rat&e" -msgstr "" +msgstr "Rat&e" #: src/TrackPanel.cpp:645 msgid "Up &Octave" @@ -5651,13 +5649,13 @@ msgstr "单击在垂直方向放大,按住Shift键单击缩小,拖拽创建 #: src/TrackPanel.cpp:1410 #, c-format msgid "%s to select or deselect track. Drag up or down to change track order." -msgstr "" +msgstr "%s选择或取消选择轨道。向上或向下拖动以更改轨道顺序。" #. i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac #: src/TrackPanel.cpp:1417 #, c-format msgid "%s to select or deselect track." -msgstr "" +msgstr "%s选择或取消选择轨道。" #: src/TrackPanel.cpp:1432 msgid "Click and drag to adjust relative size of stereo tracks." @@ -5910,10 +5908,12 @@ msgid "" "To change Spectrogram Settings, stop any\n" ".playing or recording first." msgstr "" +"要更改谱图设置,请停止任何\n" +"播放或录音." #: src/TrackPanel.cpp:8200 msgid "Stop the Audio First" -msgstr "" +msgstr "先停止音频" #: src/TrackPanel.cpp:8294 #, c-format @@ -6304,7 +6304,7 @@ msgstr "高音" #: src/effects/BassTreble.cpp:47 msgid "Link Sliders" -msgstr "" +msgstr "链接滑块" #: src/effects/BassTreble.cpp:92 #, fuzzy @@ -6313,7 +6313,7 @@ msgstr "选区的左端收缩" #: src/effects/BassTreble.cpp:209 msgid "Tone controls" -msgstr "" +msgstr "音调控制" #: src/effects/BassTreble.cpp:218 #, fuzzy @@ -6339,7 +6339,7 @@ msgstr "电平" #: src/effects/BassTreble.cpp:261 msgid "&Link Volume control to Tone controls" -msgstr "" +msgstr "&并将音量控制连接到音调控制" #: src/effects/BassTreble.h:26 msgid "Bass and Treble" @@ -6352,7 +6352,7 @@ msgstr "百分比" #: src/effects/ChangePitch.cpp:58 src/effects/ChangeTempo.cpp:52 msgid "SBSMS" -msgstr "" +msgstr "吕雪莉" #: src/effects/ChangePitch.cpp:126 msgid "Change the pitch of a track without changing its tempo" @@ -6360,7 +6360,7 @@ msgstr "改变音高,维持节奏不变" #: src/effects/ChangePitch.cpp:188 msgid "High Quality Pitch Change" -msgstr "" +msgstr "高质量的音高变化" #: src/effects/ChangePitch.cpp:245 msgid "Change Pitch without Changing Tempo" @@ -6430,7 +6430,7 @@ msgstr "改变百分比" #: src/effects/ChangePitch.cpp:331 src/effects/ChangeTempo.cpp:278 msgid "Use high quality stretching (slow)" -msgstr "" +msgstr "使用高品质的拉伸 (慢)" #: src/effects/ChangePitch.h:39 msgid "Change Pitch" @@ -6716,7 +6716,7 @@ msgstr "一次只能测量一个音轨。" msgid "" "Invalid audio selection.\n" "Please ensure that audio is selected." -msgstr "" +msgstr "音频选择无效请确保选择音频。" #: src/effects/Contrast.cpp:82 msgid "" @@ -6813,7 +6813,7 @@ msgstr "背景结束时间" #: src/effects/Contrast.cpp:380 msgid "Background higher than foreground" -msgstr "" +msgstr "背景高于前景" #: src/effects/Contrast.cpp:383 msgid "WCAG2 Pass" @@ -6972,19 +6972,19 @@ msgstr "确认覆盖" #: src/effects/Distortion.cpp:65 msgid "Hard Overdrive" -msgstr "" +msgstr "硬盘超速:" #: src/effects/Distortion.cpp:66 msgid "Cubic Curve (odd harmonics)" -msgstr "" +msgstr "立方曲线(奇次谐波)" #: src/effects/Distortion.cpp:67 msgid "Even Harmonics" -msgstr "" +msgstr "甚至谐波" #: src/effects/Distortion.cpp:68 msgid "Expand and Compress" -msgstr "" +msgstr "展开和压缩" #: src/effects/Distortion.cpp:69 src/effects/Leveller.h:21 msgid "Leveller" @@ -6992,11 +6992,11 @@ msgstr "水平器" #: src/effects/Distortion.cpp:70 msgid "Rectifier Distortion" -msgstr "" +msgstr "整流器失真" #: src/effects/Distortion.cpp:71 msgid "Hard Limiter 1413" -msgstr "" +msgstr "硬限制1413" #: src/effects/Distortion.cpp:78 src/effects/Noise.cpp:48 msgid "Type" @@ -7004,7 +7004,7 @@ msgstr "类型" #: src/effects/Distortion.cpp:79 msgid "DC Block" -msgstr "" +msgstr "直流块" #: src/effects/Distortion.cpp:80 #, fuzzy @@ -7029,84 +7029,84 @@ msgstr "重复" #: src/effects/Distortion.cpp:102 #, no-c-format msgid "Hard clip -12dB, 80% make-up gain" -msgstr "" +msgstr "硬夹80%增益12dB,化妆" #: src/effects/Distortion.cpp:104 #, no-c-format msgid "Soft clip -12dB, 80% make-up gain" -msgstr "" +msgstr "软夹80%增益12dB,化妆" #: src/effects/Distortion.cpp:105 msgid "Fuzz Box" -msgstr "" +msgstr "绒盒" #: src/effects/Distortion.cpp:106 msgid "Walkie-talkie" -msgstr "" +msgstr "对讲机" #: src/effects/Distortion.cpp:107 msgid "Blues drive sustain" -msgstr "" +msgstr "布鲁斯驱动支持" #: src/effects/Distortion.cpp:108 msgid "Light Crunch Overdrive" -msgstr "" +msgstr "光紧缩超速" #: src/effects/Distortion.cpp:109 msgid "Heavy Overdrive" -msgstr "" +msgstr "重超速" #: src/effects/Distortion.cpp:110 msgid "3rd Harmonic (Perfect Fifth)" -msgstr "" +msgstr "第三谐波(完美第五)" #: src/effects/Distortion.cpp:111 msgid "Valve Overdrive" -msgstr "" +msgstr "阀驱动" #: src/effects/Distortion.cpp:112 msgid "2nd Harmonic (Octave)" -msgstr "" +msgstr "第二谐波(倍频程)" #: src/effects/Distortion.cpp:113 msgid "Gated Expansion Distortion" -msgstr "" +msgstr "门控膨胀变形" #: src/effects/Distortion.cpp:114 msgid "Leveller, Light, -70dB noise floor" -msgstr "" +msgstr "矫直机、光、70分贝噪声地板" #: src/effects/Distortion.cpp:115 msgid "Leveller, Moderate, -70dB noise floor" -msgstr "" +msgstr "矫直机,温和,70分贝噪声地板" #: src/effects/Distortion.cpp:116 msgid "Leveller, Heavy, -70dB noise floor" -msgstr "" +msgstr "矫直机,重,70分贝噪声地板" #: src/effects/Distortion.cpp:117 msgid "Leveller, Heavier, -70dB noise floor" -msgstr "" +msgstr "矫直机,重,70分贝噪声地板" #: src/effects/Distortion.cpp:118 msgid "Leveller, Heaviest, -70dB noise floor" -msgstr "" +msgstr "矫直机,重,70分贝噪声地板" #: src/effects/Distortion.cpp:119 msgid "Half-wave Rectifier" -msgstr "" +msgstr "半波整流" #: src/effects/Distortion.cpp:120 msgid "Full-wave Rectifier" -msgstr "" +msgstr "全波整流" #: src/effects/Distortion.cpp:121 msgid "Full-wave Rectifier (DC blocked)" -msgstr "" +msgstr "全波整流器(直流阻塞)" #: src/effects/Distortion.cpp:122 msgid "Percussion Limiter" -msgstr "" +msgstr "冲击器" #: src/effects/Distortion.cpp:127 #, fuzzy @@ -7120,7 +7120,7 @@ msgstr "要添加的重复次数:" #: src/effects/Distortion.cpp:192 msgid "Waveshaping distortion effect" -msgstr "" +msgstr "波形失真影响" #: src/effects/Distortion.cpp:344 #, fuzzy @@ -7129,7 +7129,7 @@ msgstr "插值类型" #: src/effects/Distortion.cpp:348 msgid "DC blocking filter" -msgstr "" +msgstr "直流阻断滤波器" #: src/effects/Distortion.cpp:355 #, fuzzy @@ -7148,11 +7148,11 @@ msgstr "破音" #: src/effects/Distortion.cpp:676 msgid "Drive" -msgstr "" +msgstr "驱动" #: src/effects/Distortion.cpp:677 src/effects/Distortion.cpp:691 msgid "Make-up Gain" -msgstr "" +msgstr "弥补增益" #: src/effects/Distortion.cpp:688 #, fuzzy @@ -7161,14 +7161,14 @@ msgstr "静音阈值" #: src/effects/Distortion.cpp:690 msgid "Hardness" -msgstr "" +msgstr "硬度" #: src/effects/Distortion.cpp:704 src/effects/Distortion.cpp:718 #: src/effects/Distortion.cpp:732 src/effects/Distortion.cpp:746 #: src/effects/Distortion.cpp:760 src/effects/Distortion.cpp:774 #: src/effects/Distortion.cpp:802 msgid "Distortion amount" -msgstr "" +msgstr "变形量" #: src/effects/Distortion.cpp:705 src/effects/Distortion.cpp:719 #: src/effects/Distortion.cpp:733 src/effects/Distortion.cpp:747 @@ -7184,11 +7184,11 @@ msgstr "减小处理时间。" #: src/effects/Distortion.cpp:761 msgid "Harmonic brightness" -msgstr "" +msgstr "谐波的亮度" #: src/effects/Distortion.cpp:788 msgid "Levelling fine adjustment" -msgstr "" +msgstr "平微调" #: src/effects/Distortion.cpp:790 #, fuzzy @@ -7197,7 +7197,7 @@ msgstr "调平度:" #: src/effects/Distortion.cpp:814 msgid "dB Limit" -msgstr "" +msgstr "分贝限制" #: src/effects/Distortion.cpp:816 #, fuzzy @@ -7211,17 +7211,17 @@ msgstr "保留噪音(&u)" #: src/effects/Distortion.cpp:833 msgid " (Not Used):" -msgstr "" +msgstr "(未使用):" #. i18n-hint: Control range. #: src/effects/Distortion.cpp:838 msgid " (-100 to 0 dB):" -msgstr "" +msgstr "(- 100至0分贝):" #. i18n-hint: Control range. #: src/effects/Distortion.cpp:853 msgid " (-80 to -20 dB):" -msgstr "" +msgstr "(- 80至20分贝):" #. i18n-hint: Control range. #: src/effects/Distortion.cpp:864 src/effects/Distortion.cpp:875 @@ -7232,7 +7232,7 @@ msgstr "(%) [-50到100]:" #. i18n-hint: Control range. #: src/effects/Distortion.cpp:886 msgid " (0 to 5):" -msgstr "" +msgstr "(0至5):" #: src/effects/Distortion.h:26 #, fuzzy @@ -7315,7 +7315,7 @@ msgstr "一遍遍地重复选中音频" #: src/effects/Echo.cpp:102 src/effects/FindClipping.cpp:168 #: src/effects/Paulstretch.cpp:249 msgid "Requested value exceeds memory capacity." -msgstr "" +msgstr "请求值超过内存容量。" #: src/effects/Echo.cpp:159 msgid "Delay time (seconds):" @@ -7341,6 +7341,8 @@ msgid "" "\n" "%s" msgstr "" +"%s:无法加载下面的设置。将使用默认设置。\n" +"%s" #. i18n-hint: Name of time display format that shows time in hours, #. * minutes, seconds and samples (at the current project sample rate) @@ -7702,7 +7704,7 @@ msgstr "如果想应用均衡器,所有选择的轨道必须拥有相同的采 #: src/effects/Equalization.cpp:490 msgid "Track sample rate is too low for this effect." -msgstr "" +msgstr "跟踪采样率太低,这种效果。" #: src/effects/Equalization.cpp:491 #, fuzzy @@ -8052,7 +8054,7 @@ msgstr "淡出" #: src/effects/FindClipping.cpp:61 msgid "Creates labels where clipping is detected" -msgstr "" +msgstr "创建剪切检测到的标签" #: src/effects/FindClipping.cpp:98 msgid "Clipping" @@ -8563,6 +8565,9 @@ msgid "" "Try increasing the audio selection to at least %.1f seconds,\n" "or reducing the 'Time Resolution' to less than %.1f seconds." msgstr "" +"音频选择太短,无法预览。\n" +"尝试增加音频选择至少 %.1f seconds,\n" +" 或减少时间分辨率''小于 %.1f seconds." #. i18n-hint: 'Time Resolution' is the name of a control in the Paulstretch effect. #: src/effects/Paulstretch.cpp:291 @@ -8573,6 +8578,8 @@ msgid "" "For the current audio selection, the maximum\n" "'Time Resolution' is %.1f seconds." msgstr "" +"无法预览。\n" +"'Time Resolution' is %.1f seconds." #. i18n-hint: 'Time Resolution' is the name of a control in the Paulstretch effect. #: src/effects/Paulstretch.cpp:300 @@ -8583,6 +8590,9 @@ msgid "" "Try increasing the audio selection to at least %.1f seconds,\n" "or reducing the 'Time Resolution' to less than %.1f seconds." msgstr "" +"选择的时间分辨率太长。\n" +"尝试增加音频选择至少 %.1f seconds,\n" +"或减少“时间分辨率”小于 %.1f seconds." #: src/effects/Paulstretch.h:19 msgid "Paulstretch" @@ -8878,7 +8888,7 @@ msgstr "反向" #: src/effects/SBSMSEffect.h:38 msgid "SBSMS Time / Pitch Stretch" -msgstr "" +msgstr "吕雪莉时间/沥青拉伸" #. i18n-hint: Butterworth is the name of the person after whom the filter type is named. #: src/effects/ScienFilter.cpp:92 @@ -9187,11 +9197,11 @@ msgstr "插值" #: src/effects/ToneGen.cpp:132 msgid "Generates an ascending or descending tone of one of four types" -msgstr "" +msgstr "产生四种类型之一的升序或降序" #: src/effects/ToneGen.cpp:133 msgid "Generates a constant frequency tone of one of four types" -msgstr "" +msgstr "产生四种类型之一的恒定频率音调" #: src/effects/ToneGen.cpp:312 msgid "Waveform:" @@ -9268,7 +9278,7 @@ msgstr "自动减小指定音量以下片段的长度" msgid "" "When truncating independently, there may only be one selected audio track in " "each Sync-Locked Track Group." -msgstr "" +msgstr "当独立截断时,每个同步锁定的轨道组中只能有一个选定的音轨。" #: src/effects/TruncSilence.cpp:702 msgid "Detect Silence" @@ -9549,6 +9559,8 @@ msgid "" "in the track Spectrogram settings and select the\n" "frequency range for the effect to act on." msgstr "" +"要使用“光谱效应”,请在轨道光谱图设置中启用“光谱选择”,并选择要作用的效果的频" +"率范围。" #: src/effects/nyquist/Nyquist.cpp:621 msgid "" @@ -10798,7 +10810,7 @@ msgstr "立体声" #: src/export/ExportMP3.cpp:427 msgid "Force export to mono" -msgstr "" +msgstr "强制输出到单声道" #. i18n-hint: LAME is the name of an MP3 converter and should not be translated #: src/export/ExportMP3.cpp:593 @@ -11741,7 +11753,7 @@ msgstr "不可用 - 上面的位置不存在" #: src/prefs/DirectoriesPrefs.cpp:208 #, c-format msgid "Directory %s is not suitable (at risk of being cleaned out)" -msgstr "" +msgstr "目录 %s是不合适的 (冒被清理的危险)" #: src/prefs/DirectoriesPrefs.cpp:216 #, c-format @@ -12732,11 +12744,11 @@ msgstr "轨道编号" #: src/prefs/RecordingPrefs.cpp:159 msgid "Add System &Date" -msgstr "" +msgstr "添加系统和日期" #: src/prefs/RecordingPrefs.cpp:163 msgid "Add System T&ime" -msgstr "" +msgstr "添加系统T&ime" #: src/prefs/RecordingPrefs.cpp:170 msgid "Automated Recording Level Adjustment" @@ -13084,7 +13096,7 @@ msgstr "频谱图(&S)" #: src/prefs/TracksPrefs.cpp:107 msgid "&Pinned Recording/Playback head" -msgstr "" +msgstr "&固定录音/播放头" #: src/prefs/TracksPrefs.cpp:110 #, fuzzy @@ -13135,7 +13147,7 @@ msgstr "编辑一段会移动 其它片段(&M)" #: src/prefs/TracksPrefs.cpp:159 msgid "&Type to create a label" -msgstr "" +msgstr "&键入以创建标签" #: src/prefs/TracksPrefs.cpp:163 msgid "Enable scrolling left of &zero" @@ -13175,7 +13187,7 @@ msgstr "导出时混合到立体声(&S)" #: src/prefs/WarningsPrefs.cpp:72 msgid "Mixing down on export (&Custom FFmpeg or external program)" -msgstr "" +msgstr "混合导出(定制ffmpeg或外部程序)" #: src/prefs/WarningsPrefs.cpp:75 msgid "&Importing uncompressed audio files" @@ -13459,7 +13471,7 @@ msgstr "启动脚本" #. #: src/toolbars/ScrubbingToolBar.cpp:170 msgid "Stop Seeking" -msgstr "" +msgstr "停止寻求" #: src/toolbars/ScrubbingToolBar.cpp:171 #, fuzzy @@ -13468,11 +13480,11 @@ msgstr "开始监视" #: src/toolbars/ScrubbingToolBar.cpp:177 msgid "Hide Scrub Ruler" -msgstr "" +msgstr "隐藏磨砂标尺" #: src/toolbars/ScrubbingToolBar.cpp:178 msgid "Show Scrub Ruler" -msgstr "" +msgstr "显示磨砂标尺" #: src/toolbars/SelectionBar.cpp:88 src/toolbars/SelectionBar.cpp:303 msgid "Selection" @@ -13620,7 +13632,7 @@ msgstr "跟随播放" #: src/tracks/ui/Scrubbing.cpp:243 msgid "See&k" -msgstr "" +msgstr "See&k" #: src/tracks/ui/Scrubbing.cpp:243 #, fuzzy @@ -14198,27 +14210,27 @@ msgstr "点击并拖动以缩放工具栏" #: src/widgets/Ruler.cpp:2089 msgid "Click & move to Scrub. Click & drag to Seek." -msgstr "" +msgstr "点击和移动到擦洗。点击拖动寻找。" #: src/widgets/Ruler.cpp:2101 msgid "Move to Seek" -msgstr "" +msgstr "去寻找" #: src/widgets/Ruler.cpp:2103 msgid "Move to Scrub" -msgstr "" +msgstr "移动擦洗" #: src/widgets/Ruler.cpp:2110 msgid "Drag to Seek. Release to stop seeking." -msgstr "" +msgstr "拖动寻找。释放停止寻求。" #: src/widgets/Ruler.cpp:2112 msgid "Drag to Seek. Release and move to Scrub." -msgstr "" +msgstr "拖动寻求。释放并移动到" #: src/widgets/Ruler.cpp:2115 msgid "Move to Scrub. Drag to Seek." -msgstr "" +msgstr "移动磨砂拖动寻求。" #: src/widgets/Ruler.cpp:2133 msgid "Timeline actions disabled during recording" @@ -14234,11 +14246,11 @@ msgstr "快速播放已启用" #: src/widgets/Ruler.cpp:2840 msgid "Pinned Record/Play head" -msgstr "" +msgstr "固定录音/播放头" #: src/widgets/Ruler.cpp:2841 msgid "Unpinned Record/Play head" -msgstr "" +msgstr "解除记录/播放头" #: src/widgets/Ruler.cpp:2881 msgid "Disable Quick-Play" @@ -14282,7 +14294,7 @@ msgstr "解锁播放区域" #: src/widgets/Ruler.cpp:2913 msgid "Disable Scrub Ruler" -msgstr "" +msgstr "禁用磨砂标尺" #: src/widgets/Ruler.cpp:2915 #, fuzzy From 80984c9f1d77492eb85b5e2d6c0556e432a0327f Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 28 Mar 2017 15:50:07 -0400 Subject: [PATCH 63/91] From Pokechu22: Rename gain to velocity on note tracks "Velocity" is the technical term, and it's the term that's used everywhere. "Gain" was probably only used because "gain" is used on wave tracks; since note tracks aren't wave tracks (and shouldn't be treated as them) the corresponding variables should be named velocity. --- src/AudioIO.cpp | 2 +- src/MixerBoard.cpp | 4 ++-- src/NoteTrack.cpp | 8 ++++---- src/NoteTrack.h | 6 +++--- src/TrackPanel.cpp | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index 90afd7986..a740523cc 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -3790,7 +3790,7 @@ void AudioIO::OutputEvent() data1 = mNextEvent->get_pitch(); if (mNextIsNoteOn) { data2 = mNextEvent->get_loud(); // get velocity - int offset = mNextEventTrack->GetGain(); + int offset = mNextEventTrack->GetVelocity(); data2 += offset; // offset comes from per-track slider // clip velocity to insure a legal note-on value data2 = (data2 < 0 ? 1 : (data2 > 127 ? 127 : data2)); diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 273465385..7da3ffd6e 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -395,7 +395,7 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/) mLeftTrack->SetGain(fValue); #ifdef EXPERIMENTAL_MIDI_OUT else - mNoteTrack->SetGain(fValue); + mNoteTrack->SetVelocity(fValue); #endif if (mRightTrack) mRightTrack->SetGain(fValue); @@ -512,7 +512,7 @@ void MixerTrackCluster::UpdateGain() #ifdef EXPERIMENTAL_MIDI_OUT if (mNoteTrack) { mSlider_Gain->SetStyle(VEL_SLIDER); - mSlider_Gain->Set(mNoteTrack->GetGain()); + mSlider_Gain->Set(mNoteTrack->GetVelocity()); return; } mSlider_Gain->SetStyle(DB_SLIDER); diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 9f40661ee..9e0d0d0cb 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -113,7 +113,7 @@ Track(projDirManager) mSerializationLength = 0; #ifdef EXPERIMENTAL_MIDI_OUT - mGain = 0; + mVelocity = 0; #endif mBottomNote = 24; mPitchHeight = 5; @@ -160,7 +160,7 @@ Track::Holder NoteTrack::Duplicate() const duplicate->mVisibleChannels = mVisibleChannels; duplicate->SetOffset(GetOffset()); #ifdef EXPERIMENTAL_MIDI_OUT - duplicate->SetGain(GetGain()); + duplicate->SetVelocity(GetVelocity()); #endif // This std::move is needed to "upcast" the pointer type return std::move(duplicate); @@ -782,7 +782,7 @@ bool NoteTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs) else if (!wxStrcmp(attr, wxT("velocity")) && XMLValueChecker::IsGoodString(strValue) && Internat::CompatibleToDouble(strValue, &dblValue)) - mGain = (float) dblValue; + mVelocity = (float) dblValue; #endif else if (!wxStrcmp(attr, wxT("bottomnote")) && XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) @@ -838,7 +838,7 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const xmlFile.WriteAttr(wxT("isSelected"), this->GetSelected()); #ifdef EXPERIMENTAL_MIDI_OUT - xmlFile.WriteAttr(wxT("velocity"), (double) saveme->mGain); + xmlFile.WriteAttr(wxT("velocity"), (double) saveme->mVelocity); #endif xmlFile.WriteAttr(wxT("bottomnote"), saveme->mBottomNote); xmlFile.WriteAttr(wxT("data"), wxString(data.str().c_str(), wxConvUTF8)); diff --git a/src/NoteTrack.h b/src/NoteTrack.h index 7ea8a0ccf..d6290f6ff 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -98,8 +98,8 @@ class AUDACITY_DLL_API NoteTrack final : public Track { bool Shift(double t) /* not override */; #ifdef EXPERIMENTAL_MIDI_OUT - float GetGain() const { return mGain; } - void SetGain(float gain) { mGain = gain; } + float GetVelocity() const { return mVelocity; } + void SetVelocity(float velocity) { mVelocity = velocity; } #endif double NearestBeatTime(double time, double *beat) const; @@ -202,7 +202,7 @@ class AUDACITY_DLL_API NoteTrack final : public Track { long mSerializationLength; #ifdef EXPERIMENTAL_MIDI_OUT - float mGain; // velocity offset + float mVelocity; // velocity offset #endif // mBottom is the Y offset of pitch 0 (normally off screen) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index c977175c7..aaf840f8d 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -4963,7 +4963,7 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan) // mCapturedTrack is not wave... if (!pan) { // .. so assume it is note - static_cast(mCapturedTrack)->SetGain(newValue); + static_cast(mCapturedTrack)->SetVelocity(newValue); #ifdef EXPERIMENTAL_MIXER_BOARD if (pMixerBoard) // probably should modify UpdateGain to take a track that is @@ -9377,7 +9377,7 @@ void TrackInfo::DrawVelocitySlider(wxDC *dc, NoteTrack *t, wxRect rect) const auto &gain = mGain; // mGains[index]; gain->SetStyle(VEL_SLIDER); GainSlider(index)->Move(wxPoint(gainRect.x, gainRect.y)); - GainSlider(index)->Set(t->GetGain()); + GainSlider(index)->Set(t->GetVelocity()); GainSlider(index)->OnPaint(*dc // , t->GetSelected() ); From c391a8f8842126d4af6d4e26523ab42923ef4945 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 8 Jan 2017 03:36:12 -0500 Subject: [PATCH 64/91] Define AudioTrack and PlayableTrack as common bases for Wave and Note --- src/NoteTrack.cpp | 4 ++-- src/NoteTrack.h | 12 +++++++++++- src/Track.h | 16 ++++++++++++++++ src/WaveTrack.cpp | 8 ++++---- src/WaveTrack.h | 2 +- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 9e0d0d0cb..8d9f669be 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -103,8 +103,8 @@ NoteTrack::Holder TrackFactory::NewNoteTrack() return std::make_unique(mDirManager); } -NoteTrack::NoteTrack(const std::shared_ptr &projDirManager): -Track(projDirManager) +NoteTrack::NoteTrack(const std::shared_ptr &projDirManager) + : NoteTrackBase(projDirManager) { SetDefaultName(_("Note Track")); SetName(GetDefaultName()); diff --git a/src/NoteTrack.h b/src/NoteTrack.h index d6290f6ff..a314db574 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -50,7 +50,17 @@ class wxRect; class DirManager; class Alg_seq; // from "allegro.h" -class AUDACITY_DLL_API NoteTrack final : public Track { +using NoteTrackBase = +#ifdef EXPERIMENTAL_MIDI_OUT + PlayableTrack +#else + AudioTrack +#endif + ; + +class AUDACITY_DLL_API NoteTrack final + : public NoteTrackBase +{ public: friend class TrackArtist; diff --git a/src/Track.h b/src/Track.h index 8e2bc533f..fb527aa94 100644 --- a/src/Track.h +++ b/src/Track.h @@ -251,6 +251,22 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler bool IsSyncLockSelected() const; }; +class AudioTrack /* not final */ : public Track +{ +public: + AudioTrack(const std::shared_ptr &projDirManager) + : Track{ projDirManager } {} + AudioTrack(const Track &orig) : Track{ orig } {} +}; + +class PlayableTrack /* not final */ : public AudioTrack +{ +public: + PlayableTrack(const std::shared_ptr &projDirManager) + : AudioTrack{ projDirManager } {} + PlayableTrack(const Track &orig) : AudioTrack{ orig } {} +}; + class AUDACITY_DLL_API TrackListIterator /* not final */ { public: diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 6e8f10c15..6c2fed45f 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -79,7 +79,7 @@ WaveTrack::Holder TrackFactory::NewWaveTrack(sampleFormat format, double rate) } WaveTrack::WaveTrack(const std::shared_ptr &projDirManager, sampleFormat format, double rate) : - Track(projDirManager) + PlayableTrack(projDirManager) { if (format == (sampleFormat)0) { @@ -116,7 +116,7 @@ WaveTrack::WaveTrack(const std::shared_ptr &projDirManager, sampleFo } WaveTrack::WaveTrack(const WaveTrack &orig): - Track(orig) + PlayableTrack(orig) , mpSpectrumSettings(orig.mpSpectrumSettings ? std::make_unique(*orig.mpSpectrumSettings) : nullptr @@ -141,7 +141,7 @@ WaveTrack::WaveTrack(const WaveTrack &orig): // Copy the track metadata but not the contents. void WaveTrack::Init(const WaveTrack &orig) { - Track::Init(orig); + PlayableTrack::Init(orig); mFormat = orig.mFormat; mRate = orig.mRate; mGain = orig.mGain; @@ -171,7 +171,7 @@ void WaveTrack::Merge(const Track &orig) SetWaveformSettings (wt.mpWaveformSettings ? std::make_unique(*wt.mpWaveformSettings) : nullptr); } - Track::Merge(orig); + PlayableTrack::Merge(orig); } WaveTrack::~WaveTrack() diff --git a/src/WaveTrack.h b/src/WaveTrack.h index 712b8d925..50e922b2d 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -69,7 +69,7 @@ class Regions : public std::vector < Region > {}; class Envelope; -class AUDACITY_DLL_API WaveTrack final : public Track { +class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { private: From f1bec856752f57507735a374e28749a9f73db886 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 27 Mar 2017 00:44:54 -0400 Subject: [PATCH 65/91] use AudioTrack --- src/Menus.cpp | 24 ++++++++---------------- src/toolbars/ControlToolBar.cpp | 6 +----- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index b854edc52..9a6eb6ee5 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -4608,11 +4608,13 @@ bool AudacityProject::HandlePasteNothingSelected() pNewTrack = mTrackFactory->NewWaveTrack(w->GetSampleFormat(), w->GetRate()); } break; + #ifdef USE_MIDI - case Track::Note: - pNewTrack = mTrackFactory->NewNoteTrack(); - break; - #endif // USE_MIDI + case Track::Note: + pNewTrack = mTrackFactory->NewNoteTrack(); + break; + #endif // USE_MIDI + case Track::Label: pNewTrack = mTrackFactory->NewLabelTrack(); break; @@ -6150,12 +6152,7 @@ void AudacityProject::HandleAlign(int index, bool moveSel) while (t) { // We only want Wave and Note tracks here. -#if defined(USE_MIDI) - if (t->GetSelected() && ((t->GetKind() == Track::Wave) || - (t->GetKind() == Track::Note))) -#else - if (t->GetSelected() && (t->GetKind() == Track::Wave)) -#endif + if (t->GetSelected() && dynamic_cast(t)) { offset = t->GetOffset(); if (t->GetLinked()) { // Left channel of stereo track. @@ -6236,12 +6233,7 @@ void AudacityProject::HandleAlign(int index, bool moveSel) while (t) { // This shifts different tracks in different ways, so no sync-lock move. // Only align Wave and Note tracks end to end. -#if defined(USE_MIDI) - if (t->GetSelected() && ((t->GetKind() == Track::Wave) || - (t->GetKind() == Track::Note))) -#else - if (t->GetSelected() && (t->GetKind() == Track::Wave)) -#endif + if (t->GetSelected() && dynamic_cast(t)) { t->SetOffset(newPos); // Move the track diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index e9693d37d..6fc4b24c6 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -418,11 +418,7 @@ void ControlToolBar::EnableDisableButtons() if (p) { TrackListIterator iter( p->GetTracks() ); for (Track *t = iter.First(); t; t = iter.Next()) { - if (t->GetKind() == Track::Wave -#if defined(USE_MIDI) - || t->GetKind() == Track::Note -#endif - ) { + if (dynamic_cast(t)) { tracks = true; break; } From b2ab9b5087dcce2724df624377acea465afe1512 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 27 Mar 2017 10:12:32 -0400 Subject: [PATCH 66/91] Simplify MixerBoard.cpp using the PlayableTrack type --- src/Menus.cpp | 5 +- src/MixerBoard.cpp | 374 ++++++++++++------------------------------ src/MixerBoard.h | 74 +++------ src/Project.cpp | 5 +- src/TrackPanel.cpp | 22 +-- src/widgets/ASlider.h | 3 +- 6 files changed, 140 insertions(+), 343 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 9a6eb6ee5..a1f28b552 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -6889,8 +6889,9 @@ void AudacityProject::OnRemoveTracks() while (t) { if (t->GetSelected()) { - if (mMixerBoard && (t->GetKind() == Track::Wave)) - mMixerBoard->RemoveTrackCluster((WaveTrack*)t); + auto playable = dynamic_cast(t); + if (mMixerBoard && playable) + mMixerBoard->RemoveTrackCluster(playable); if (!f) f = l; // Capture the track preceeding the first removed track t = iter.RemoveCurrent(); diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 7da3ffd6e..3b4d3567f 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -23,9 +23,9 @@ #include "AColor.h" #include "AudioIO.h" -#ifdef EXPERIMENTAL_MIDI_OUT - #include "NoteTrack.h" -#endif + +#include "NoteTrack.h" + #include "Project.h" #include "TrackPanel.h" // for EVT_TRACK_PANEL_TIMER #include "UndoManager.h" @@ -155,30 +155,17 @@ END_EVENT_TABLE() MixerTrackCluster::MixerTrackCluster(wxWindow* parent, MixerBoard* grandParent, AudacityProject* project, - WaveTrack* pLeftTrack, WaveTrack* pRightTrack /*= NULL*/, + PlayableTrack* pTrack, const wxPoint& pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/) : wxPanelWrapper(parent, -1, pos, size) +, mTrack{ pTrack } { mMixerBoard = grandParent; mProject = project; -#ifdef EXPERIMENTAL_MIDI_OUT - if (pLeftTrack->GetKind() == Track::Note) { - mLeftTrack = NULL; - mNoteTrack = (NoteTrack*) pLeftTrack; - mTrack = pLeftTrack; - } else { - wxASSERT(pLeftTrack->GetKind() == Track::Wave); - mTrack = mLeftTrack = pLeftTrack; - mNoteTrack = NULL; - } -#else - wxASSERT(pLeftTrack->GetKind() == Track::Wave); - mLeftTrack = pLeftTrack; -#endif - mRightTrack = pRightTrack; + wxASSERT( pTrack ); - SetName(mLeftTrack->GetName()); + SetName(mTrack->GetName()); this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); @@ -191,13 +178,8 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, wxPoint ctrlPos(kDoubleInset, kDoubleInset); wxSize ctrlSize(size.GetWidth() - kQuadrupleInset, TRACK_NAME_HEIGHT); mStaticText_TrackName = - #ifdef EXPERIMENTAL_MIDI_OUT safenew wxStaticText(this, -1, mTrack->GetName(), ctrlPos, ctrlSize, wxALIGN_CENTRE | wxST_NO_AUTORESIZE | wxSUNKEN_BORDER); - #else - safenew wxStaticText(this, -1, mLeftTrack->GetName(), ctrlPos, ctrlSize, - wxALIGN_CENTRE | 0x0001 | wxBORDER_SUNKEN); - #endif //v Useful when different tracks are different colors, but not now. // mStaticText_TrackName->SetBackgroundColour(this->GetTrackColor()); @@ -208,8 +190,8 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, const int nGainSliderHeight = size.GetHeight() - ctrlPos.y - kQuadrupleInset; ctrlSize.Set(kLeftSideStackWidth - kQuadrupleInset, nGainSliderHeight); -#ifdef EXPERIMENTAL_MIDI_OUT - if (mNoteTrack) { + + if (GetNote()) { mSlider_Gain = safenew MixerTrackSlider( this, ID_SLIDER_GAIN, @@ -217,15 +199,16 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, _("Velocity"), ctrlPos, ctrlSize, VEL_SLIDER, true, true, 0.0, wxVERTICAL); - } else -#endif - mSlider_Gain = - safenew MixerTrackSlider( - this, ID_SLIDER_GAIN, - /* i18n-hint: title of the Gain slider, used to adjust the volume */ - _("Gain"), - ctrlPos, ctrlSize, DB_SLIDER, true, - true, 0.0, wxVERTICAL); + } + else + mSlider_Gain = + safenew MixerTrackSlider( + this, ID_SLIDER_GAIN, + /* i18n-hint: title of the Gain slider, used to adjust the volume */ + _("Gain"), + ctrlPos, ctrlSize, DB_SLIDER, true, + true, 0.0, wxVERTICAL); + mSlider_Gain->SetName(_("Gain")); this->UpdateGain(); @@ -236,11 +219,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, // musical instrument image ctrlPos.x += kLeftSideStackWidth + kInset; // + kInset to center it in right side stack ctrlSize.Set(MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH, MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH); -#ifdef EXPERIMENTAL_MIDI_OUT - wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mTrack->GetName()); -#else - wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mLeftTrack); -#endif + wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mTrack); wxASSERT(bitmap); mBitmapButton_MusicalInstrument = safenew wxBitmapButton(this, ID_BITMAPBUTTON_MUSICAL_INSTRUMENT, *bitmap, @@ -306,34 +285,24 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, (PAN_HEIGHT + kDoubleInset) - (MUTE_SOLO_HEIGHT + (bSoloNone ? 0 : MUTE_SOLO_HEIGHT) + kDoubleInset); ctrlSize.Set(kRightSideStackWidth, nMeterHeight); -#ifdef EXPERIMENTAL_MIDI_OUT - if (mLeftTrack) { -#endif - mMeter = - safenew Meter(GetActiveProject(), // AudacityProject* project, - this, -1, // wxWindow* parent, wxWindowID id, - false, // bool isInput - ctrlPos, ctrlSize, // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, - Meter::MixerTrackCluster); // Style style = HorizontalStereo, - mMeter->SetName(_("Signal Level Meter")); -#ifdef EXPERIMENTAL_MIDI_OUT - } else { - mMeter = NULL; + + mMeter = NULL; + if (GetWave()) { + mMeter = + safenew Meter(GetActiveProject(), // AudacityProject* project, + this, -1, // wxWindow* parent, wxWindowID id, + false, // bool isInput + ctrlPos, ctrlSize, // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + Meter::MixerTrackCluster); // Style style = HorizontalStereo, + mMeter->SetName(_("Signal Level Meter")); } -#endif #if wxUSE_TOOLTIPS - #ifdef EXPERIMENTAL_MIDI_OUT mStaticText_TrackName->SetToolTip(mTrack->GetName()); - #else - mStaticText_TrackName->SetToolTip(mLeftTrack->GetName()); - #endif mToggleButton_Mute->SetToolTip(_("Mute")); mToggleButton_Solo->SetToolTip(_("Solo")); - #ifdef EXPERIMENTAL_MIDI_OUT - if (mLeftTrack) - #endif - mMeter->SetToolTip(_("Signal Level Meter")); + if (GetWave()) + mMeter->SetToolTip(_("Signal Level Meter")); #endif // wxUSE_TOOLTIPS #ifdef __WXMAC__ @@ -344,9 +313,29 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, #endif } +WaveTrack *MixerTrackCluster::GetWave() const +{ + return dynamic_cast< WaveTrack * >( mTrack ); +} + +WaveTrack *MixerTrackCluster::GetRight() const +{ + auto left = GetWave(); + if (left) + return static_cast(left); + else + return nullptr; +} + +NoteTrack *MixerTrackCluster::GetNote() const +{ + return dynamic_cast< NoteTrack * >( mTrack ); +} + void MixerTrackCluster::UpdatePrefs() { - mMeter->UpdatePrefs(); // in case meter range has changed + if (mMeter) + mMeter->UpdatePrefs(); // in case meter range has changed HandleResize(); // in case prefs "/GUI/Solo" changed } @@ -382,30 +371,24 @@ void MixerTrackCluster::HandleResize() // For wxSizeEvents, update gain slider a TRACK_NAME_HEIGHT + kDoubleInset + nRequiredHeightAboveMeter; const int nMeterHeight = nGainSliderHeight - nRequiredHeightAboveMeter; - #ifdef EXPERIMENTAL_MIDI_OUT if (mMeter) - #endif - mMeter->SetSize(-1, nMeterY, -1, nMeterHeight); + mMeter->SetSize(-1, nMeterY, -1, nMeterHeight); } void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/) { float fValue = mSlider_Gain->Get(); - if (mLeftTrack) - mLeftTrack->SetGain(fValue); + if (GetWave()) + GetWave()->SetGain(fValue); #ifdef EXPERIMENTAL_MIDI_OUT else - mNoteTrack->SetVelocity(fValue); + GetNote()->SetVelocity(fValue); #endif - if (mRightTrack) - mRightTrack->SetGain(fValue); + if (GetRight()) + GetRight()->SetGain(fValue); // Update the TrackPanel correspondingly. -#ifdef EXPERIMENTAL_MIDI_OUT mProject->RefreshTPTrack(mTrack); -#else - mProject->RefreshTPTrack(mLeftTrack); -#endif if (bWantPushState) mProject->TP_PushState(_("Moved gain slider"), _("Gain"), UndoPush::CONSOLIDATE ); } @@ -413,17 +396,13 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/) void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/) { float fValue = mSlider_Pan->Get(); - if (mLeftTrack) // test in case track is a NoteTrack - mLeftTrack->SetPan(fValue); - if (mRightTrack) - mRightTrack->SetPan(fValue); + if (GetWave()) // test in case track is a NoteTrack + GetWave()->SetPan(fValue); + if (GetRight()) + GetRight()->SetPan(fValue); // Update the TrackPanel correspondingly. -#ifdef EXPERIMENTAL_MIDI_OUT mProject->RefreshTPTrack(mTrack); -#else - mProject->RefreshTPTrack(mLeftTrack); -#endif if (bWantPushState) mProject->TP_PushState(_("Moved pan slider"), _("Pan"), UndoPush::CONSOLIDATE ); @@ -431,10 +410,8 @@ void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/) void MixerTrackCluster::ResetMeter(const bool bResetClipping) { -#ifdef EXPERIMENTAL_MIDI_OUT if (mMeter) -#endif - mMeter->Reset(mLeftTrack->GetRate(), bResetClipping); + mMeter->Reset(GetWave()->GetRate(), bResetClipping); } @@ -450,33 +427,20 @@ void MixerTrackCluster::UpdateForStateChange() void MixerTrackCluster::UpdateName() { -#ifdef EXPERIMENTAL_MIDI_OUT const wxString newName = mTrack->GetName(); -#else - const wxString newName = mLeftTrack->GetName(); -#endif SetName(newName); mStaticText_TrackName->SetLabel(newName); #if wxUSE_TOOLTIPS mStaticText_TrackName->SetToolTip(newName); #endif mBitmapButton_MusicalInstrument->SetBitmapLabel( -#ifdef EXPERIMENTAL_MIDI_OUT - *(mMixerBoard->GetMusicalInstrumentBitmap(newName))); -#else - *(mMixerBoard->GetMusicalInstrumentBitmap(mLeftTrack))); -#endif + *(mMixerBoard->GetMusicalInstrumentBitmap(mTrack))); } void MixerTrackCluster::UpdateMute() { -#ifdef EXPERIMENTAL_MIDI_OUT mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0); if (mTrack->GetMute()) -#else - mToggleButton_Mute->SetAlternateIdx(mLeftTrack->GetSolo() ? 1 : 0); - if (mLeftTrack->GetMute()) -#endif mToggleButton_Mute->PushDown(); else mToggleButton_Mute->PopUp(); @@ -484,11 +448,7 @@ void MixerTrackCluster::UpdateMute() void MixerTrackCluster::UpdateSolo() { -#ifdef EXPERIMENTAL_MIDI_OUT bool bIsSolo = mTrack->GetSolo(); -#else - bool bIsSolo = mLeftTrack->GetSolo(); -#endif if (bIsSolo) mToggleButton_Solo->PushDown(); else @@ -499,55 +459,36 @@ void MixerTrackCluster::UpdateSolo() void MixerTrackCluster::UpdatePan() { #ifdef EXPERIMENTAL_MIDI_OUT - if (mNoteTrack) { + if (!GetWave()) { mSlider_Pan->Hide(); return; } #endif - mSlider_Pan->Set(mLeftTrack->GetPan()); + mSlider_Pan->Set(GetWave()->GetPan()); } void MixerTrackCluster::UpdateGain() { #ifdef EXPERIMENTAL_MIDI_OUT - if (mNoteTrack) { + if (!GetWave()) { mSlider_Gain->SetStyle(VEL_SLIDER); - mSlider_Gain->Set(mNoteTrack->GetVelocity()); + mSlider_Gain->Set(GetNote()->GetVelocity()); return; } mSlider_Gain->SetStyle(DB_SLIDER); #endif - mSlider_Gain->Set(mLeftTrack->GetGain()); + mSlider_Gain->Set(GetWave()->GetGain()); } void MixerTrackCluster::UpdateMeter(const double t0, const double t1) { -#ifdef EXPERIMENTAL_MIDI_OUT // NoteTracks do not (currently) register on meters. It would probably be // a good idea to display 16 channel "active" lights rather than a meter - if (!mLeftTrack) + if (!GetWave()) return; -#else - wxASSERT(mLeftTrack && (mLeftTrack->GetKind() == Track::Wave)); -#endif - //vvv Vaughan, 2010-11-27: - // NOTE TO ROGER DANNENBERG: - // I undid the mTrack hack in this conditional, as the rest of the method still assumed it's a wavetrack - // so dereferencing mLeftTrack would have gotten a NULL pointer fault. - // I really think MixerTrackCluster should be factored for NoteTracks. - // REPLY: I think bSuccess prevents dereferencing mLeftTrack, but I will - // check. We should talk about whether it's better to factor - // MixerTrackCluster or more fully hide track types from MixerTrackCluster. - // For now, out change plan produced the following: - // Vaughan, 2011=10-15: There's no bSuccess here, so I don't know what you mean. - // But this change is consistent with the others for EXPERIMENTAL_MIDI_OUT, so I accept it. if ((t0 < 0.0) || (t1 < 0.0) || (t0 >= t1) || // bad time value or nothing to show -#ifdef EXPERIMENTAL_MIDI_OUT ((mMixerBoard->HasSolo() || mTrack->GetMute()) && !mTrack->GetSolo()) -#else - ((mMixerBoard->HasSolo() || mLeftTrack->GetMute()) && !mLeftTrack->GetSolo()) -#endif ) { //v Vaughan, 2011-02-25: Moved the update back to TrackPanel::OnTimer() as it helps with @@ -577,7 +518,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) //Floats rmsRight{kFramesPerBuffer}; // //#ifdef EXPERIMENTAL_MIDI_OUT - // bool bSuccess = (mLeftTrack != NULL); + // bool bSuccess = (GetWave() != nullptr); //#else // bool bSuccess = true; //#endif @@ -589,8 +530,8 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) //while (bSuccess && (i < kFramesPerBuffer)) //{ // bSuccess &= - // mLeftTrack->GetMinMax(&min, &(maxLeft[i]), dFrameT0, dFrameT1) && - // mLeftTrack->GetRMS(&(rmsLeft[i]), dFrameT0, dFrameT1); + // mTrack->GetMinMax(&min, &(maxLeft[i]), dFrameT0, dFrameT1) && + // mTrack->GetRMS(&(rmsLeft[i]), dFrameT0, dFrameT1); // if (bSuccess && mRightTrack) // bSuccess &= // mRightTrack->GetMinMax(&min, &(maxRight[i]), dFrameT0, dFrameT1) && @@ -613,7 +554,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) //{ // for (i = 0; i < kFramesPerBuffer; i++) // { - // float gain = mLeftTrack->GetChannelGain(0); + // float gain = mTrack->GetChannelGain(0); // maxLeft[i] *= gain; // rmsLeft[i] *= gain; // if (mRightTrack) @@ -621,17 +562,18 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) // maxRight[i] *= gain; // rmsRight[i] *= gain; // } - // mMeter->UpdateDisplay( + // if ( mMeter ) mMeter->UpdateDisplay( // 2, // If mono, show left track values in both meters, as in MeterToolBar, rather than kNumChannels. // kFramesPerBuffer, // maxLeft, rmsLeft, // maxRight, rmsRight, - // mLeftTrack->TimeToLongSamples(t1 - t0)); + // mTrack->TimeToLongSamples(t1 - t0)); //} // - auto startSample = (sampleCount)((mLeftTrack->GetRate() * t0) + 0.5); - auto scnFrames = (sampleCount)((mLeftTrack->GetRate() * (t1 - t0)) + 0.5); + const auto pTrack = GetWave(); + auto startSample = (sampleCount)((pTrack->GetRate() * t0) + 0.5); + auto scnFrames = (sampleCount)((pTrack->GetRate() * (t1 - t0)) + 0.5); // Expect that the difference of t1 and t0 is the part of a track played // in about 1/20 second (ticks of TrackPanel timer), so this won't overflow @@ -640,7 +582,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) Floats tempFloatsArray{ nFrames }; decltype(tempFloatsArray) meterFloatsArray; // Don't throw on read error in this drawing update routine - bool bSuccess = mLeftTrack->Get((samplePtr)tempFloatsArray.get(), + bool bSuccess = pTrack->Get((samplePtr)tempFloatsArray.get(), floatSample, startSample, nFrames, fillZero, false); if (bSuccess) { @@ -653,9 +595,9 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) for (int index = 0; index < nFrames; index++) meterFloatsArray[2 * index] = tempFloatsArray[index]; - if (mRightTrack) + if (GetRight()) // Again, don't throw - bSuccess = mRightTrack->Get((samplePtr)tempFloatsArray.get(), + bSuccess = GetRight()->Get((samplePtr)tempFloatsArray.get(), floatSample, startSample, nFrames, fillZero, false); if (bSuccess) @@ -669,14 +611,14 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) if (bSuccess) { //vvv Need to apply envelope, too? See Mixer::MixSameRate. - float gain = mLeftTrack->GetChannelGain(0); + float gain = pTrack->GetChannelGain(0); if (gain < 1.0) for (int index = 0; index < nFrames; index++) meterFloatsArray[2 * index] *= gain; - if (mRightTrack) - gain = mRightTrack->GetChannelGain(1); + if (GetRight()) + gain = GetRight()->GetChannelGain(1); else - gain = mLeftTrack->GetChannelGain(1); + gain = pTrack->GetChannelGain(1); if (gain < 1.0) for (int index = 0; index < nFrames; index++) meterFloatsArray[(2 * index) + 1] *= gain; @@ -705,13 +647,7 @@ wxColour MixerTrackCluster::GetTrackColor() void MixerTrackCluster::HandleSelect(bool bShiftDown, bool bControlDown) { -#ifdef EXPERIMENTAL_MIDI_OUT - Track *pTrack = mTrack; -#else - Track *pTrack = mLeftTrack; -#endif - - mProject->GetTrackPanel()->HandleListSelection(pTrack, bShiftDown, bControlDown); + mProject->GetTrackPanel()->HandleListSelection(mTrack, bShiftDown, bControlDown); } void MixerTrackCluster::OnMouseEvent(wxMouseEvent& event) @@ -735,11 +671,7 @@ void MixerTrackCluster::OnPaint(wxPaintEvent & WXUNUSED(event)) wxSize clusterSize = this->GetSize(); wxRect bev(0, 0, clusterSize.GetWidth() - 1, clusterSize.GetHeight() - 1); -#ifdef EXPERIMENTAL_MIDI_OUT auto selected = mTrack->GetSelected(); -#else - auto selected = mLeftTrack->GetSelected(); -#endif for (unsigned int i = 0; i < 4; i++) // 4 gives a big bevel, but there were complaints about visibility otherwise. { @@ -782,13 +714,8 @@ void MixerTrackCluster::OnSlider_Pan(wxCommandEvent& WXUNUSED(event)) void MixerTrackCluster::OnButton_Mute(wxCommandEvent& WXUNUSED(event)) { -#ifdef EXPERIMENTAL_MIDI_OUT mProject->HandleTrackMute(mTrack, mToggleButton_Mute->WasShiftDown()); mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0); -#else - mProject->HandleTrackMute(mLeftTrack, mToggleButton_Mute->WasShiftDown()); - mToggleButton_Mute->SetAlternateIdx(mLeftTrack->GetSolo() ? 1 : 0); -#endif // Update the TrackPanel correspondingly. if (mProject->IsSoloSimple()) @@ -799,22 +726,13 @@ void MixerTrackCluster::OnButton_Mute(wxCommandEvent& WXUNUSED(event)) } else // Update only the changed track. -#ifdef EXPERIMENTAL_MIDI_OUT mProject->RefreshTPTrack(mTrack); -#else - mProject->RefreshTPTrack(mLeftTrack); -#endif } void MixerTrackCluster::OnButton_Solo(wxCommandEvent& WXUNUSED(event)) { -#ifdef EXPERIMENTAL_MIDI_OUT mProject->HandleTrackSolo(mTrack, mToggleButton_Solo->WasShiftDown()); bool bIsSolo = mTrack->GetSolo(); -#else - mProject->HandleTrackSolo(mLeftTrack, mToggleButton_Solo->WasShiftDown()); - bool bIsSolo = mLeftTrack->GetSolo(); -#endif mToggleButton_Mute->SetAlternateIdx(bIsSolo ? 1 : 0); // Update the TrackPanel correspondingly. @@ -827,11 +745,7 @@ void MixerTrackCluster::OnButton_Solo(wxCommandEvent& WXUNUSED(event)) } else // Update only the changed track. -#ifdef EXPERIMENTAL_MIDI_OUT mProject->RefreshTPTrack(mTrack); -#else - mProject->RefreshTPTrack(mLeftTrack); -#endif } @@ -1010,18 +924,14 @@ void MixerBoard::UpdateTrackClusters() unsigned int nClusterIndex = 0; TrackListIterator iterTracks(mTracks); MixerTrackCluster* pMixerTrackCluster = NULL; - Track* pLeftTrack; + Track* pTrack; Track* pRightTrack; - pLeftTrack = iterTracks.First(); - while (pLeftTrack) { - pRightTrack = pLeftTrack->GetLinked() ? iterTracks.Next() : NULL; + pTrack = iterTracks.First(); + while (pTrack) { + pRightTrack = pTrack->GetLinked() ? iterTracks.Next() : NULL; - if (pLeftTrack->GetKind() == Track::Wave -#ifdef EXPERIMENTAL_MIDI_OUT - || pLeftTrack->GetKind() == Track::Note -#endif - ) + if (auto pPlayableTrack = dynamic_cast(pTrack)) { if (nClusterIndex < nClusterCount) { @@ -1029,20 +939,8 @@ void MixerBoard::UpdateTrackClusters() // Track clusters are maintained in the same order as the WaveTracks. // Track pointers can change for the "same" track for different states // on the undo stack, so update the pointers and display name. -#ifdef EXPERIMENTAL_MIDI_OUT - if (pLeftTrack->GetKind() == Track::Note) { - mMixerTrackClusters[nClusterIndex]->mNoteTrack = (NoteTrack*)pLeftTrack; - mMixerTrackClusters[nClusterIndex]->mLeftTrack = NULL; - } else { - mMixerTrackClusters[nClusterIndex]->mNoteTrack = NULL; - mMixerTrackClusters[nClusterIndex]->mLeftTrack = (WaveTrack*)pLeftTrack; - } -#else - mMixerTrackClusters[nClusterIndex]->mLeftTrack = (WaveTrack*)pLeftTrack; -#endif + mMixerTrackClusters[nClusterIndex]->mTrack = pPlayableTrack; // Assume linked track is wave or null - mMixerTrackClusters[nClusterIndex]->mRightTrack = - static_cast(pRightTrack); mMixerTrackClusters[nClusterIndex]->UpdateForStateChange(); } else @@ -1057,16 +955,14 @@ void MixerBoard::UpdateTrackClusters() wxSize clusterSize(kMixerTrackClusterWidth, nClusterHeight); pMixerTrackCluster = safenew MixerTrackCluster(mScrolledWindow, this, mProject, - static_cast(pLeftTrack), - // Assume linked track is wave or null - static_cast(pRightTrack), + pPlayableTrack, clusterPos, clusterSize); if (pMixerTrackCluster) mMixerTrackClusters.Add(pMixerTrackCluster); } nClusterIndex++; } - pLeftTrack = iterTracks.Next(); + pTrack = iterTracks.Next(); } if (pMixerTrackCluster) @@ -1083,11 +979,7 @@ void MixerBoard::UpdateTrackClusters() // We've already updated the track pointers for the clusters to the left, so just remove all the rest. // Keep nClusterIndex constant and successively DELETE from left to right. for (unsigned int nCounter = nClusterIndex; nCounter < nClusterCount; nCounter++) -#ifdef EXPERIMENTAL_MIDI_OUT this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mTrack); -#else - this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mLeftTrack); -#endif } } @@ -1100,13 +992,8 @@ int MixerBoard::GetTrackClustersWidth() kDoubleInset; // plus final right margin } -#ifdef EXPERIMENTAL_MIDI_OUT -void MixerBoard::MoveTrackCluster(const Track* pTrack, +void MixerBoard::MoveTrackCluster(const PlayableTrack* pTrack, bool bUp) // Up in TrackPanel is left in MixerBoard. -#else -void MixerBoard::MoveTrackCluster(const WaveTrack* pTrack, - bool bUp) // Up in TrackPanel is left in MixerBoard. -#endif { MixerTrackCluster* pMixerTrackCluster; int nIndex = FindMixerTrackCluster(pTrack, &pMixerTrackCluster); @@ -1140,11 +1027,7 @@ void MixerBoard::MoveTrackCluster(const WaveTrack* pTrack, } } -#ifdef EXPERIMENTAL_MIDI_OUT -void MixerBoard::RemoveTrackCluster(const Track* pTrack) -#else -void MixerBoard::RemoveTrackCluster(const WaveTrack* pTrack) -#endif +void MixerBoard::RemoveTrackCluster(const PlayableTrack* pTrack) { // Find and destroy. MixerTrackCluster* pMixerTrackCluster; @@ -1180,22 +1063,14 @@ void MixerBoard::RemoveTrackCluster(const WaveTrack* pTrack) } -#ifdef EXPERIMENTAL_MIDI_OUT -wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const wxString & name) -#else -wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack) -#endif +wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const Track* pTrack) { if (mMusicalInstruments.empty()) return NULL; - // random choice: return mMusicalInstruments[(int)pLeftTrack % mMusicalInstruments.GetCount()].mBitmap; + // random choice: return mMusicalInstruments[(int)pTrack % mMusicalInstruments.GetCount()].mBitmap; -#ifdef EXPERIMENTAL_MIDI_OUT - const wxString strTrackName(wxString{ name }.MakeLower()); -#else - const wxString strTrackName(pLeftTrack->GetName().MakeLower()); -#endif + const wxString strTrackName(pTrack->GetName().MakeLower()); size_t nBestItemIndex = 0; unsigned int nBestScore = 0; unsigned int nInstrIndex = 0; @@ -1242,11 +1117,7 @@ bool MixerBoard::HasSolo() return false; } -#ifdef EXPERIMENTAL_MIDI_OUT -void MixerBoard::RefreshTrackCluster(const Track* pTrack, bool bEraseBackground /*= true*/) -#else -void MixerBoard::RefreshTrackCluster(const WaveTrack* pTrack, bool bEraseBackground ) -#endif +void MixerBoard::RefreshTrackCluster(const PlayableTrack* pTrack, bool bEraseBackground /*= true*/) { MixerTrackCluster* pMixerTrackCluster; this->FindMixerTrackCluster(pTrack, &pMixerTrackCluster); @@ -1277,11 +1148,7 @@ void MixerBoard::ResetMeters(const bool bResetClipping) mMixerTrackClusters[i]->ResetMeter(bResetClipping); } -#ifdef EXPERIMENTAL_MIDI_OUT -void MixerBoard::UpdateName(const Track* pTrack) -#else -void MixerBoard::UpdateName(const WaveTrack* pTrack) -#endif +void MixerBoard::UpdateName(const PlayableTrack* pTrack) { MixerTrackCluster* pMixerTrackCluster; this->FindMixerTrackCluster(pTrack, &pMixerTrackCluster); @@ -1289,11 +1156,7 @@ void MixerBoard::UpdateName(const WaveTrack* pTrack) pMixerTrackCluster->UpdateName(); } -#ifdef EXPERIMENTAL_MIDI_OUT -void MixerBoard::UpdateMute(const Track* pTrack /*= NULL*/) // NULL means update for all tracks. -#else -void MixerBoard::UpdateMute(const WaveTrack* pTrack /*= NULL*/) // NULL means update for all tracks. -#endif +void MixerBoard::UpdateMute(const PlayableTrack* pTrack /*= NULL*/) // NULL means update for all tracks. { if (pTrack == NULL) { @@ -1309,11 +1172,7 @@ void MixerBoard::UpdateMute(const WaveTrack* pTrack /*= NULL*/) // NULL means up } } -#ifdef EXPERIMENTAL_MIDI_OUT -void MixerBoard::UpdateSolo(const Track* pTrack /*= NULL*/) // NULL means update for all tracks. -#else -void MixerBoard::UpdateSolo(const WaveTrack* pTrack /*= NULL*/) // NULL means update for all tracks. -#endif +void MixerBoard::UpdateSolo(const PlayableTrack* pTrack /*= NULL*/) // NULL means update for all tracks. { if (pTrack == NULL) { @@ -1329,11 +1188,7 @@ void MixerBoard::UpdateSolo(const WaveTrack* pTrack /*= NULL*/) // NULL means up } } -#ifdef EXPERIMENTAL_MIDI_OUT -void MixerBoard::UpdatePan(const Track* pTrack) -#else -void MixerBoard::UpdatePan(const WaveTrack* pTrack) -#endif +void MixerBoard::UpdatePan(const PlayableTrack* pTrack) { MixerTrackCluster* pMixerTrackCluster; FindMixerTrackCluster(pTrack, &pMixerTrackCluster); @@ -1341,11 +1196,7 @@ void MixerBoard::UpdatePan(const WaveTrack* pTrack) pMixerTrackCluster->UpdatePan(); } -#ifdef EXPERIMENTAL_MIDI_OUT -void MixerBoard::UpdateGain(const Track* pTrack) -#else -void MixerBoard::UpdateGain(const WaveTrack* pTrack) -#endif +void MixerBoard::UpdateGain(const PlayableTrack* pTrack) { MixerTrackCluster* pMixerTrackCluster; FindMixerTrackCluster(pTrack, &pMixerTrackCluster); @@ -1471,22 +1322,13 @@ void MixerBoard::CreateMuteSoloImages() mImageSoloDisabled = std::make_unique(mMuteSoloWidth, MUTE_SOLO_HEIGHT); // Leave empty because unused. } -#ifdef EXPERIMENTAL_MIDI_OUT -int MixerBoard::FindMixerTrackCluster(const Track* pTrack, - MixerTrackCluster** hMixerTrackCluster) const -#else -int MixerBoard::FindMixerTrackCluster(const WaveTrack* pLeftTrack, +int MixerBoard::FindMixerTrackCluster(const PlayableTrack* pTrack, MixerTrackCluster** hMixerTrackCluster) const -#endif { *hMixerTrackCluster = NULL; for (unsigned int i = 0; i < mMixerTrackClusters.GetCount(); i++) { -#ifdef EXPERIMENTAL_MIDI_OUT if (mMixerTrackClusters[i]->mTrack == pTrack) -#else - if (mMixerTrackClusters[i]->mLeftTrack == pLeftTrack) -#endif { *hMixerTrackCluster = mMixerTrackClusters[i]; return i; diff --git a/src/MixerBoard.h b/src/MixerBoard.h index 116f9dde7..f21d9ae2a 100644 --- a/src/MixerBoard.h +++ b/src/MixerBoard.h @@ -62,10 +62,11 @@ public: class AudacityProject; class Meter; class MixerBoard; -#ifdef EXPERIMENTAL_MIDI_OUT + class Track; class NoteTrack; -#endif +class PlayableTrack; + class WaveTrack; class MixerTrackCluster final : public wxPanelWrapper @@ -73,11 +74,15 @@ class MixerTrackCluster final : public wxPanelWrapper public: MixerTrackCluster(wxWindow* parent, MixerBoard* grandParent, AudacityProject* project, - WaveTrack* pLeftTrack, WaveTrack* pRightTrack = NULL, + PlayableTrack* pTrack, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); virtual ~MixerTrackCluster() {} + WaveTrack *GetWave() const; + WaveTrack *GetRight() const; + NoteTrack *GetNote() const; + void UpdatePrefs(); void HandleResize(); // For wxSizeEvents, update gain slider and meter. @@ -115,23 +120,7 @@ private: public: -#ifdef EXPERIMENTAL_MIDI_OUT - // mTrack is redundant, but simplifies code that operates on either - // mLeftTrack or mNoteTrack. - Track* mTrack; // either mLeftTrack or mNoteTrack, whichever is not NULL -#endif - WaveTrack* mLeftTrack; // NULL if Note Track - WaveTrack* mRightTrack; // NULL if mono - - //vvv Vaughan, 2010-11-05: - // I suggest that when this is no longer experimental, rather than all these #ifdef's, - // this be done by factoring, i.e., add two subclasses to MixerTrackCluster, - // MixerNoteTrackCluster and MixerWaveTrackCluster, such that all the common - // code is in the parent, and these #ifdef's are only around - // MixerNoteTrackCluster rather than sprinkled throughout MixerTrackCluster. -#ifdef EXPERIMENTAL_MIDI_OUT - NoteTrack* mNoteTrack; // NULL if Wave Track -#endif + PlayableTrack * mTrack; private: MixerBoard* mMixerBoard; @@ -213,45 +202,25 @@ public: void UpdateTrackClusters(); int GetTrackClustersWidth(); -#ifdef EXPERIMENTAL_MIDI_OUT - void MoveTrackCluster(const Track* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard. - void RemoveTrackCluster(const Track* pTrack); + void MoveTrackCluster(const PlayableTrack* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard. + void RemoveTrackCluster(const PlayableTrack* pTrack); - wxBitmap* GetMusicalInstrumentBitmap(const wxString & name); -#else - void MoveTrackCluster(const WaveTrack* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard. - void RemoveTrackCluster(const WaveTrack* pTrack); - - - wxBitmap* GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack); -#endif + wxBitmap* GetMusicalInstrumentBitmap(const Track *pTrack); bool HasSolo(); -#ifdef EXPERIMENTAL_MIDI_OUT - void RefreshTrackCluster(const Track* pTrack, bool bEraseBackground = true); -#else - void RefreshTrackCluster(const WaveTrack* pTrack, bool bEraseBackground = true); -#endif + void RefreshTrackCluster(const PlayableTrack* pTrack, bool bEraseBackground = true); void RefreshTrackClusters(bool bEraseBackground = true); void ResizeTrackClusters(); void ResetMeters(const bool bResetClipping); -#ifdef EXPERIMENTAL_MIDI_OUT - void UpdateName(const Track* pTrack); - void UpdateMute(const Track* pTrack = NULL); // NULL means update for all tracks. - void UpdateSolo(const Track* pTrack = NULL); // NULL means update for all tracks. - void UpdatePan(const Track* pTrack); - void UpdateGain(const Track* pTrack); -#else - void UpdateName(const WaveTrack* pTrack); - void UpdateMute(const WaveTrack* pTrack = NULL); // NULL means update for all tracks. - void UpdateSolo(const WaveTrack* pTrack = NULL); // NULL means update for all tracks. - void UpdatePan(const WaveTrack* pTrack); - void UpdateGain(const WaveTrack* pTrack); -#endif + void UpdateName(const PlayableTrack* pTrack); + void UpdateMute(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks. + void UpdateSolo(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks. + void UpdatePan(const PlayableTrack* pTrack); + void UpdateGain(const PlayableTrack* pTrack); void UpdateMeters(const double t1, const bool bLoopedPlay); @@ -259,13 +228,8 @@ public: private: void CreateMuteSoloImages(); -#ifdef EXPERIMENTAL_MIDI_OUT - int FindMixerTrackCluster(const Track* pTrack, + int FindMixerTrackCluster(const PlayableTrack* pTrack, MixerTrackCluster** hMixerTrackCluster) const; -#else - int FindMixerTrackCluster(const WaveTrack* pLeftTrack, - MixerTrackCluster** hMixerTrackCluster) const; -#endif void LoadMusicalInstruments(); // event handlers diff --git a/src/Project.cpp b/src/Project.cpp index a12a43f97..4cb842b53 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -5396,12 +5396,13 @@ void AudacityProject::RemoveTrack(Track * toRemove) wxString name = toRemove->GetName(); Track *partner = toRemove->GetLink(); - if (toRemove->GetKind() == Track::Wave) + auto playable = dynamic_cast(toRemove); + if (playable) { // Update mixer board displayed tracks. MixerBoard* pMixerBoard = this->GetMixerBoard(); if (pMixerBoard) - pMixerBoard->RemoveTrackCluster((WaveTrack*)toRemove); // Will remove partner shown in same cluster. + pMixerBoard->RemoveTrackCluster(playable); // Will remove partner shown in same cluster. } mTracks->Remove(toRemove); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index aaf840f8d..a9e947079 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -5212,27 +5212,17 @@ void TrackPanel::HandleRearrange(wxMouseEvent & event) if (event.m_y < mMoveUpThreshold || event.m_y < 0) { mTracks->MoveUp(mCapturedTrack); --mRearrangeCount; -#ifdef EXPERIMENTAL_MIDI_OUT - if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave || - mCapturedTrack->GetKind() == Track::Note)) - pMixerBoard->MoveTrackCluster(mCapturedTrack, true /* up */); -#else - if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave)) - pMixerBoard->MoveTrackCluster((WaveTrack*)mCapturedTrack, true /* up */); -#endif + if (pMixerBoard) + if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack )) + pMixerBoard->MoveTrackCluster(pPlayable, true /* up */); } else if (event.m_y > mMoveDownThreshold || event.m_y > GetRect().GetHeight()) { mTracks->MoveDown(mCapturedTrack); ++mRearrangeCount; /* i18n-hint: a direction as in up or down.*/ -#ifdef EXPERIMENTAL_MIDI_OUT - if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave || - mCapturedTrack->GetKind() == Track::Note)) - pMixerBoard->MoveTrackCluster(mCapturedTrack, false /* down */); -#else - if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave)) - pMixerBoard->MoveTrackCluster((WaveTrack*)mCapturedTrack, false /* down */); -#endif + if (pMixerBoard) + if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack )) + pMixerBoard->MoveTrackCluster(pPlayable, false /* down */); } else { diff --git a/src/widgets/ASlider.h b/src/widgets/ASlider.h index 7c4ecbd5d..90fb0cd93 100644 --- a/src/widgets/ASlider.h +++ b/src/widgets/ASlider.h @@ -44,9 +44,8 @@ class TipPanel; #define DB_SLIDER 2 // -36...36 dB #define PAN_SLIDER 3 // -1.0...1.0 #define SPEED_SLIDER 4 // 0.01 ..3.0 -#ifdef EXPERIMENTAL_MIDI_OUT + #define VEL_SLIDER 5 // -50..50 -#endif #define DB_MIN -36.0f #define DB_MAX 36.0f From ed0088491c347ddec1de5ba19ed31b8841d4d146 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 29 Mar 2017 00:41:36 -0400 Subject: [PATCH 67/91] Remove MixerTrackClusters right to left, remove assertion --- src/MixerBoard.cpp | 23 +++++++++++------------ src/MixerBoard.h | 1 + 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 3b4d3567f..949402439 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -920,7 +920,7 @@ void MixerBoard::UpdateTrackClusters() this->CreateMuteSoloImages(); const int nClusterHeight = mScrolledWindow->GetClientSize().GetHeight() - kDoubleInset; - const size_t nClusterCount = mMixerTrackClusters.GetCount(); + size_t nClusterCount = mMixerTrackClusters.GetCount(); unsigned int nClusterIndex = 0; TrackListIterator iterTracks(mTracks); MixerTrackCluster* pMixerTrackCluster = NULL; @@ -971,15 +971,14 @@ void MixerBoard::UpdateTrackClusters() this->UpdateWidth(); this->ResizeTrackClusters(); } - else if (nClusterIndex < nClusterCount) + else while (nClusterIndex < nClusterCount) { // We've got too many clusters. // This can happen only on things like Undo New Audio Track or Undo Import // that don't call RemoveTrackCluster explicitly. // We've already updated the track pointers for the clusters to the left, so just remove all the rest. - // Keep nClusterIndex constant and successively DELETE from left to right. - for (unsigned int nCounter = nClusterIndex; nCounter < nClusterCount; nCounter++) - this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mTrack); + // Successively DELETE from right to left. + RemoveTrackCluster(--nClusterCount); } } @@ -1032,9 +1031,16 @@ void MixerBoard::RemoveTrackCluster(const PlayableTrack* pTrack) // Find and destroy. MixerTrackCluster* pMixerTrackCluster; int nIndex = this->FindMixerTrackCluster(pTrack, &pMixerTrackCluster); + if (pMixerTrackCluster == NULL) return; // Couldn't find it. + RemoveTrackCluster(nIndex); +} + +void MixerBoard::RemoveTrackCluster(size_t nIndex) +{ + auto pMixerTrackCluster = mMixerTrackClusters[nIndex]; mMixerTrackClusters.RemoveAt(nIndex); pMixerTrackCluster->Destroy(); // DELETE is unsafe on wxWindow. @@ -1053,13 +1059,6 @@ void MixerBoard::RemoveTrackCluster(const PlayableTrack* pTrack) } this->UpdateWidth(); - -#ifdef EXPERIMENTAL_MIDI_OUT - // Sanity check: if there is still a MixerTrackCluster with pTrack, then - // we deleted the first but should have deleted the last: - FindMixerTrackCluster(pTrack, &pMixerTrackCluster); - wxASSERT(pMixerTrackCluster == NULL); -#endif } diff --git a/src/MixerBoard.h b/src/MixerBoard.h index f21d9ae2a..ae8f7ad58 100644 --- a/src/MixerBoard.h +++ b/src/MixerBoard.h @@ -204,6 +204,7 @@ public: int GetTrackClustersWidth(); void MoveTrackCluster(const PlayableTrack* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard. void RemoveTrackCluster(const PlayableTrack* pTrack); + void RemoveTrackCluster(size_t nIndex); wxBitmap* GetMusicalInstrumentBitmap(const Track *pTrack); From 6c4cf46c0694c1fb5a7390d4e2ae19ff2ee2cba2 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 29 Mar 2017 11:25:05 -0400 Subject: [PATCH 68/91] Move mute and solo state into PlayableTrack --- src/Menus.cpp | 9 ++- src/MixerBoard.cpp | 6 +- src/Project.cpp | 106 ++++++++++++++++--------- src/Track.cpp | 29 +++++-- src/Track.h | 18 +++-- src/TrackArtist.cpp | 12 ++- src/TrackPanel.cpp | 15 ++-- src/TrackPanelAx.cpp | 10 ++- src/commands/GetProjectInfoCommand.cpp | 6 +- src/commands/GetTrackInfoCommand.cpp | 10 ++- src/commands/SetProjectInfoCommand.cpp | 10 ++- src/export/Export.cpp | 8 +- src/export/ExportMultiple.cpp | 10 ++- 13 files changed, 165 insertions(+), 84 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index a1f28b552..970602c62 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -7088,8 +7088,9 @@ void AudacityProject::OnMuteAllTracks() while (t) { - if (t->GetKind() == Track::Wave) - t->SetMute(true); + auto pt = dynamic_cast(t); + if (pt) + pt->SetMute(true); t = iter.Next(); } @@ -7107,7 +7108,9 @@ void AudacityProject::OnUnMuteAllTracks() while (t) { - t->SetMute(false); + auto pt = dynamic_cast(t); + if (pt) + pt->SetMute(false); t = iter.Next(); } diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 949402439..2b3ffef51 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -1110,9 +1110,11 @@ bool MixerBoard::HasSolo() { TrackListIterator iterTracks(mTracks); Track* pTrack; - for (pTrack = iterTracks.First(); pTrack; pTrack = iterTracks.Next()) - if (pTrack->GetSolo()) + for (pTrack = iterTracks.First(); pTrack; pTrack = iterTracks.Next()) { + auto pPlayable = dynamic_cast( pTrack ); + if (pPlayable && pPlayable->GetSolo()) return true; + } return false; } diff --git a/src/Project.cpp b/src/Project.cpp index 4cb842b53..0683c5f3c 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -3655,6 +3655,8 @@ void AudacityProject::WriteXML(XMLWriter &xmlFile, bool bWantSaveCompressed) while (t) { if ((t->GetKind() == Track::Wave) && bWantSaveCompressed) { + auto wt = static_cast(t); + //vvv This should probably be a method, WaveTrack::WriteCompressedTrackXML(). xmlFile.StartTag(wxT("import")); xmlFile.WriteAttr(wxT("filename"), mStrOtherNamesArray[ndx]); // Assumes mTracks order hasn't changed! @@ -3665,8 +3667,8 @@ void AudacityProject::WriteXML(XMLWriter &xmlFile, bool bWantSaveCompressed) // xmlFile.WriteAttr(wxT("linked"), t->GetLinked()); xmlFile.WriteAttr(wxT("offset"), t->GetOffset(), 8); - xmlFile.WriteAttr(wxT("mute"), t->GetMute()); - xmlFile.WriteAttr(wxT("solo"), t->GetSolo()); + xmlFile.WriteAttr(wxT("mute"), wt->GetMute()); + xmlFile.WriteAttr(wxT("solo"), wt->GetSolo()); xmlFile.WriteAttr(wxT("height"), t->GetActualHeight()); xmlFile.WriteAttr(wxT("minimized"), t->GetMinimized()); @@ -3975,10 +3977,12 @@ bool AudacityProject::Save(bool overwrite /* = true */ , ((pTrack != NULL) && (pSavedTrack != NULL)); pTrack = iter.Next(), pSavedTrack = savedTrackIter.Next()) { - pWaveTrack = (WaveTrack*)pTrack; + pWaveTrack = static_cast(pTrack); + auto pSavedWaveTrack = static_cast(pSavedTrack); + pWaveTrack->SetSelected(pSavedTrack->GetSelected()); - pWaveTrack->SetMute(pSavedTrack->GetMute()); - pWaveTrack->SetSolo(pSavedTrack->GetSolo()); + pWaveTrack->SetMute(pSavedWaveTrack->GetMute()); + pWaveTrack->SetSolo(pSavedWaveTrack->GetSolo()); pWaveTrack->SetGain(((WaveTrack*)pSavedTrack)->GetGain()); pWaveTrack->SetPan(((WaveTrack*)pSavedTrack)->GetPan()); @@ -5430,36 +5434,45 @@ void AudacityProject::HandleTrackMute(Track *t, const bool exclusive) if (exclusive) { TrackListIterator iter(GetTracks()); - Track *i = iter.First(); - while (i) { - if (i == t) { - i->SetMute(true); - if(i->GetLinked()) { // also mute the linked track - i = iter.Next(); + Track *it = iter.First(); + while (it) { + auto i = dynamic_cast(it); + if (i) { + if (i == t) { i->SetMute(true); + if(i->GetLinked()) { // also mute the linked track + it = iter.Next(); + i->SetMute(true); + } } + else { + i->SetMute(false); + } + i->SetSolo(false); } - else { - i->SetMute(false); - } - i->SetSolo(false); - i = iter.Next(); + it = iter.Next(); } } else { // Normal click toggles this track. - t->SetMute(!t->GetMute()); + auto pt = dynamic_cast( t ); + if (!pt) + return; + + pt->SetMute(!pt->GetMute()); if(t->GetLinked()) // set mute the same on both, if a pair { - bool muted = t->GetMute(); + bool muted = pt->GetMute(); TrackListIterator iter(GetTracks()); Track *i = iter.First(); while (i != t) { // search for this track i = iter.Next(); } i = iter.Next(); // get the next one, since linked - i->SetMute(muted); // and mute it as well + auto pi = dynamic_cast( i ); + if (pi) + pi->SetMute(muted); // and mute it as well } if (IsSoloSimple() || IsSoloNone()) @@ -5471,18 +5484,23 @@ void AudacityProject::HandleTrackMute(Track *t, const bool exclusive) // We also set a solo indicator if we have just one track / stereo pair playing. // otherwise clear solo on everything. while (i) { - if( !i->GetMute()) - { - nPlaying += 1; - if(i->GetLinked()) - i = iter.Next(); // don't count this one as it is linked + auto pi = dynamic_cast( i ); + if (pi) { + if( !pi->GetMute()) + { + nPlaying += 1; + if(i->GetLinked()) + i = iter.Next(); // don't count this one as it is linked + } } i = iter.Next(); } i = iter.First(); while (i) { - i->SetSolo( (nPlaying==1) && !i->GetMute() ); // will set both of a stereo pair + auto pi = dynamic_cast( i ); + if (pi) + pi->SetSolo( (nPlaying==1) && !pi->GetMute() ); // will set both of a stereo pair i = iter.Next(); } } @@ -5492,8 +5510,12 @@ void AudacityProject::HandleTrackMute(Track *t, const bool exclusive) // Type of solo (standard or simple) follows the set preference, unless // alternate == true, which causes the opposite behavior. -void AudacityProject::HandleTrackSolo(Track *t, const bool alternate) +void AudacityProject::HandleTrackSolo(Track *const t, const bool alternate) { + const auto pt = dynamic_cast( t ); + if (!pt) + return; + bool bSoloMultiple = !IsSoloSimple() ^ alternate; // Standard and Simple solo have opposite defaults: @@ -5503,17 +5525,19 @@ void AudacityProject::HandleTrackSolo(Track *t, const bool alternate) // when in standard radio button mode. if ( bSoloMultiple ) { - t->SetSolo( !t->GetSolo() ); + pt->SetSolo( !pt->GetSolo() ); if(t->GetLinked()) { - bool soloed = t->GetSolo(); + bool soloed = pt->GetSolo(); TrackListIterator iter(GetTracks()); Track *i = iter.First(); while (i != t) { // search for this track i = iter.Next(); } i = iter.Next(); // get the next one, since linked - i->SetSolo(soloed); // and solo it as well + auto pi = dynamic_cast( i ); + if (pi) + pi->SetSolo(soloed); // and solo it as well } } else @@ -5522,26 +5546,32 @@ void AudacityProject::HandleTrackSolo(Track *t, const bool alternate) // OR unmute and unsolo everything. TrackListIterator iter(GetTracks()); Track *i = iter.First(); - bool bWasSolo = t->GetSolo(); + bool bWasSolo = pt->GetSolo(); while (i) { if( i==t ) { - i->SetSolo(!bWasSolo); + pt->SetSolo(!bWasSolo); if( IsSoloSimple() ) - i->SetMute(false); + pt->SetMute(false); if(t->GetLinked()) { i = iter.Next(); - i->SetSolo(!bWasSolo); - if( IsSoloSimple() ) - i->SetMute(false); + auto pi = dynamic_cast( i ); + if (pi) { + pi->SetSolo(!bWasSolo); + if( IsSoloSimple() ) + pi->SetMute(false); + } } } else { - i->SetSolo(false); - if( IsSoloSimple() ) - i->SetMute(!bWasSolo); + auto pi = dynamic_cast( i ); + if (pi) { + pi->SetSolo(false); + if( IsSoloSimple() ) + pi->SetMute(!bWasSolo); + } } i = iter.Next(); } diff --git a/src/Track.cpp b/src/Track.cpp index 7a5d93a82..166b2393b 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -50,8 +50,6 @@ Track::Track(const std::shared_ptr &projDirManager) mList = NULL; mSelected = false; mLinked = false; - mMute = false; - mSolo = false; mY = 0; mHeight = 150; @@ -92,8 +90,6 @@ void Track::Init(const Track &orig) mSelected = orig.mSelected; mLinked = orig.mLinked; - mMute = orig.mMute; - mSolo = orig.mSolo; mHeight = orig.mHeight; mMinimized = orig.mMinimized; mChannel = orig.mChannel; @@ -112,8 +108,6 @@ void Track::SetSelected(bool s) void Track::Merge(const Track &orig) { mSelected = orig.mSelected; - mMute = orig.mMute; - mSolo = orig.mSolo; } Track::~Track() @@ -331,6 +325,22 @@ bool Track::SyncLockAdjust(double oldT1, double newT1) return true; } +void PlayableTrack::Init( const PlayableTrack &orig ) +{ + mMute = orig.mMute; + mSolo = orig.mSolo; + AudioTrack::Init( orig ); +} + +void PlayableTrack::Merge( const Track &orig ) +{ + auto pOrig = dynamic_cast(&orig); + wxASSERT( pOrig ); + mMute = pOrig->mMute; + mSolo = pOrig->mSolo; + AudioTrack::Merge( *pOrig ); +} + // TrackListIterator TrackListIterator::TrackListIterator(TrackList * val) : l(val) @@ -1208,7 +1218,9 @@ unsigned TrackList::GetNumExportChannels(bool selectionOnly) const for (tr = iter.First(this); tr != NULL; tr = iter.Next()) { // Want only unmuted wave tracks. - if ((tr->GetKind() != Track::Wave) || tr->GetMute()) + auto wt = static_cast(tr); + if ((tr->GetKind() != Track::Wave) || + wt->GetMute()) continue; // do we only want selected ones? @@ -1265,8 +1277,9 @@ namespace { for (; p != end; ++p) { const auto &track = *p; + auto wt = static_cast(&*track); if (track->GetKind() == Track::Wave && - (includeMuted || !track->GetMute()) && + (includeMuted || !wt->GetMute()) && (track->GetSelected() || !selectionOnly)) { waveTrackArray.push_back(static_cast(track.get())); } diff --git a/src/Track.h b/src/Track.h index fb527aa94..39a994168 100644 --- a/src/Track.h +++ b/src/Track.h @@ -140,8 +140,6 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler protected: int mChannel; double mOffset; - bool mMute; - bool mSolo; mutable std::shared_ptr mDirManager; @@ -189,14 +187,10 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler void SetDefaultName( const wxString &n ) { mDefaultName = n; } bool GetSelected() const { return mSelected; } - bool GetMute () const { return mMute; } bool GetLinked () const { return mLinked; } - bool GetSolo () const { return mSolo; } virtual void SetSelected(bool s); - void SetMute (bool m) { mMute = m; } void SetLinked (bool l); - void SetSolo (bool s) { mSolo = s; } int GetChannel() const { return mChannel; } virtual double GetOffset() const = 0; @@ -265,6 +259,18 @@ public: PlayableTrack(const std::shared_ptr &projDirManager) : AudioTrack{ projDirManager } {} PlayableTrack(const Track &orig) : AudioTrack{ orig } {} + + bool GetMute () const { return mMute; } + bool GetSolo () const { return mSolo; } + void SetMute (bool m) { mMute = m; } + void SetSolo (bool s) { mSolo = s; } + + void Init( const PlayableTrack &init ); + void Merge( const Track &init ) override; + +protected: + bool mMute { false }; + bool mSolo { false }; }; class AUDACITY_DLL_API TrackListIterator /* not final */ diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index 7ed78c988..559c41280 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -336,7 +336,8 @@ void TrackArtist::DrawTracks(TrackList * tracks, bool hasSolo = false; for (t = iter.First(); t; t = iter.Next()) { - if (t->GetSolo()) { + auto pt = dynamic_cast(t); + if (pt && pt->GetSolo()) { hasSolo = true; break; } @@ -457,7 +458,8 @@ void TrackArtist::DrawTrack(const Track * t, clip->ClearDisplayRect(); } - bool muted = (hasSolo || t->GetMute()) && !t->GetSolo(); + bool muted = (hasSolo || wt->GetMute()) && + !wt->GetSolo(); #if defined(__WXMAC__) wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode(); @@ -493,7 +495,11 @@ void TrackArtist::DrawTrack(const Track * t, #ifdef USE_MIDI case Track::Note: { - bool muted = (hasSolo || t->GetMute()) && !t->GetSolo(); + auto nt = static_cast(t); + bool muted = false; +#ifdef EXPERIMENTAL_MIDI_OUT + muted = (hasSolo || nt->GetMute()) && !nt->GetSolo(); +#endif DrawNoteTrack((NoteTrack *)t, dc, rect, selectedRegion, zoomInfo, muted); break; } diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index a9e947079..14a71406e 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -9288,18 +9288,19 @@ void TrackInfo::DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t, return; // don't draw mute and solo buttons, because they don't fit into track label AColor::MediumTrackInfo( dc, t->GetSelected()); + auto pt = dynamic_cast(t); if( solo ) { - if( t->GetSolo() ) + if( pt && pt->GetSolo() ) { - AColor::Solo(dc, t->GetSolo(), t->GetSelected()); + AColor::Solo(dc, pt->GetSolo(), t->GetSelected()); } } else { - if( t->GetMute() ) + if( pt && pt->GetMute() ) { - AColor::Mute(dc, t->GetMute(), t->GetSelected(), t->GetSolo()); + AColor::Mute(dc, pt->GetMute(), t->GetSelected(), pt->GetSolo()); } } //(solo) ? AColor::Solo(dc, t->GetSolo(), t->GetSelected()) : @@ -9318,7 +9319,11 @@ void TrackInfo::DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t, dc->GetTextExtent(str, &textWidth, &textHeight); dc->DrawText(str, bev.x + (bev.width - textWidth) / 2, bev.y + (bev.height - textHeight) / 2); - AColor::BevelTrackInfo(*dc, (solo?t->GetSolo():t->GetMute()) == down, bev); + AColor::BevelTrackInfo( + *dc, + (solo ? pt->GetSolo() : (pt && pt->GetMute())) == down, + bev + ); if (solo && !down) { // Update the mute button, which may be grayed out depending on diff --git a/src/TrackPanelAx.cpp b/src/TrackPanelAx.cpp index bf9a4ec7c..3f8774428 100644 --- a/src/TrackPanelAx.cpp +++ b/src/TrackPanelAx.cpp @@ -363,7 +363,8 @@ wxAccStatus TrackPanelAx::GetName( int childId, wxString* name ) #endif // LLL: Remove these during "refactor" - if( t->GetMute() ) + auto pt = dynamic_cast(t); + if( pt && pt->GetMute() ) { // The following comment also applies to the solo, selected, // and synclockselected states. @@ -376,7 +377,7 @@ wxAccStatus TrackPanelAx::GetName( int childId, wxString* name ) name->Append( wxT(" ") + wxString(_( " Mute On" )) ); } - if( t->GetSolo() ) + if( pt && pt->GetSolo() ) { /* i18n-hint: This is for screen reader software and indicates that on this track solo is on.*/ @@ -547,12 +548,13 @@ wxAccStatus TrackPanelAx::GetValue( int WXUNUSED(childId), wxString* WXUNUSED(st } // LLL: Remove these during "refactor" - if( t->GetMute() ) + auto pt = dynamic_cast(t); + if( pt && pt->GetMute() ) { strValue->Append( _( " Mute On" ) ); } - if( t->GetSolo() ) + if( pt && pt->GetSolo() ) { strValue->Append( _( " Solo On" ) ); } diff --git a/src/commands/GetProjectInfoCommand.cpp b/src/commands/GetProjectInfoCommand.cpp index 047809c90..5d34168a6 100644 --- a/src/commands/GetProjectInfoCommand.cpp +++ b/src/commands/GetProjectInfoCommand.cpp @@ -161,10 +161,12 @@ bool GetProjectInfoCommand::testLinked(const Track * track) const bool GetProjectInfoCommand::testSolo(const Track * track) const { - return track->GetSolo(); + auto pt = dynamic_cast(track); + return pt && pt->GetSolo(); } bool GetProjectInfoCommand::testMute(const Track * track) const { - return track->GetMute(); + auto pt = dynamic_cast(track); + return pt && pt->GetMute(); } diff --git a/src/commands/GetTrackInfoCommand.cpp b/src/commands/GetTrackInfoCommand.cpp index f0889e837..455a799d8 100644 --- a/src/commands/GetTrackInfoCommand.cpp +++ b/src/commands/GetTrackInfoCommand.cpp @@ -127,15 +127,17 @@ bool GetTrackInfoCommand::Apply(CommandExecutionContext context) } else if (mode.IsSameAs(wxT("Solo"))) { - if (t->GetKind() == Track::Wave) - SendBooleanStatus(t->GetSolo()); + auto pt = dynamic_cast(t); + if (pt) + SendBooleanStatus(pt->GetSolo()); else SendBooleanStatus(false); } else if (mode.IsSameAs(wxT("Mute"))) { - if (t->GetKind() == Track::Wave) - SendBooleanStatus(t->GetMute()); + auto pt = dynamic_cast(t); + if (pt) + SendBooleanStatus(pt->GetMute()); else SendBooleanStatus(false); } diff --git a/src/commands/SetProjectInfoCommand.cpp b/src/commands/SetProjectInfoCommand.cpp index 0ae857f8e..d15180cfd 100644 --- a/src/commands/SetProjectInfoCommand.cpp +++ b/src/commands/SetProjectInfoCommand.cpp @@ -98,12 +98,14 @@ void SetProjectInfoCommand::setSelected(Track * trk, bool param) const void SetProjectInfoCommand::setSolo(Track * trk, bool param) const { - if(trk->GetKind() == Track::Wave) - trk->SetSolo(param); + auto pt = dynamic_cast(trk); + if (pt) + pt->SetSolo(param); } void SetProjectInfoCommand::setMute(Track * trk, bool param) const { - if(trk->GetKind() == Track::Wave) - trk->SetMute(param); + auto pt = dynamic_cast(trk); + if (pt) + pt->SetMute(param); } diff --git a/src/export/Export.cpp b/src/export/Export.cpp index e92a7cbda..a4dde5947 100644 --- a/src/export/Export.cpp +++ b/src/export/Export.cpp @@ -425,7 +425,9 @@ bool Exporter::ExamineTracks() while (tr) { if (tr->GetKind() == Track::Wave) { - if ( (tr->GetSelected() || !mSelectedOnly) && !tr->GetMute() ) { // don't count muted tracks + auto wt = static_cast(tr); + if ( (tr->GetSelected() || !mSelectedOnly) && + !wt->GetMute() ) { // don't count muted tracks mNumSelected++; if (tr->GetChannel() == Track::LeftChannel) { @@ -1255,7 +1257,9 @@ ExportMixerDialog::ExportMixerDialog( const TrackList *tracks, bool selectedOnly for( const Track *t = iter.First(); t; t = iter.Next() ) { - if( t->GetKind() == Track::Wave && ( t->GetSelected() || !selectedOnly ) && !t->GetMute() ) + auto wt = static_cast(t); + if( t->GetKind() == Track::Wave && ( t->GetSelected() || !selectedOnly ) && + !wt->GetMute() ) { numTracks++; const wxString sTrackName = (t->GetName()).Left(20); diff --git a/src/export/ExportMultiple.cpp b/src/export/ExportMultiple.cpp index 0c1dddb21..928c881a1 100644 --- a/src/export/ExportMultiple.cpp +++ b/src/export/ExportMultiple.cpp @@ -154,7 +154,8 @@ void ExportMultiple::CountTracksAndLabels() // Count WaveTracks, and for linked pairs, count only the second of the pair. case Track::Wave: { - if (!pTrack->GetMute() && !pTrack->GetLinked()) // Don't count muted tracks. + auto wt = static_cast(pTrack); + if (!wt->GetMute() && !pTrack->GetLinked()) // Don't count muted tracks. mNumWaveTracks++; break; } @@ -811,7 +812,9 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName, for (tr = iter.First(mTracks); tr != NULL; tr = iter.Next()) { // Want only non-muted wave tracks. - if ((tr->GetKind() != Track::Wave) || tr->GetMute()) + auto wt = static_cast(tr); + if ((tr->GetKind() != Track::Wave) || + wt->GetMute()) continue; // Get the times for the track @@ -898,7 +901,8 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName, for (tr = iter.First(mTracks); tr != NULL; tr = iter.Next()) { // Want only non-muted wave tracks. - if ((tr->GetKind() != Track::Wave) || (tr->GetMute() == true)) { + auto wt = static_cast(tr); + if ((tr->GetKind() != Track::Wave) || (wt->GetMute())) { continue; } From d109142693579545e60ad7e359192ffcd9004c79 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 29 Mar 2017 13:57:40 -0400 Subject: [PATCH 69/91] Make mute and solo of NoteTrack persistent, if EXPERIMENTAL_MIDI_OUT --- src/NoteTrack.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 8d9f669be..234975a24 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -831,6 +831,10 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const saveme->mSeq->write(data, true); xmlFile.StartTag(wxT("notetrack")); xmlFile.WriteAttr(wxT("name"), saveme->mName); +#ifdef EXPERIMENTAL_MIDI_OUT + xmlFile.WriteAttr(wxT("mute"), mMute); + xmlFile.WriteAttr(wxT("solo"), mSolo); +#endif xmlFile.WriteAttr(wxT("offset"), saveme->GetOffset()); xmlFile.WriteAttr(wxT("visiblechannels"), saveme->mVisibleChannels); xmlFile.WriteAttr(wxT("height"), saveme->GetActualHeight()); From 930e834aefefe62ff931bdb732bf7035aea6bfce Mon Sep 17 00:00:00 2001 From: windinthew Date: Thu, 30 Mar 2017 02:03:46 +0100 Subject: [PATCH 70/91] Mark Young PR 192 (modified) Change 2.1.2 to 2.1.3/2.2.0-alpha in win/compile.txt Git-ignore VisualStudio 2017 files. --- .gitignore | 1 + win/compile.txt | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 7f7e325bb..3a26b4edc 100644 --- a/.gitignore +++ b/.gitignore @@ -177,6 +177,7 @@ win/Debug win/Release win/Projects/*/Debug win/Projects/*/Release +win/.vs/ # All those help files help/manual* diff --git a/win/compile.txt b/win/compile.txt index 4352a7ce0..b4cac5c2f 100644 --- a/win/compile.txt +++ b/win/compile.txt @@ -14,7 +14,8 @@ Authors: Martyn Shaw ======================================================================== -This document is for Audacity version 2.1.2. +This document is for Audacity version 2.1.3 and is currently also valid +for building 2.2.0-alpha. If the advice here is inaccurate or incomplete, email audacity-devel@lists.sourceforge.net. @@ -41,7 +42,7 @@ To simplify the implementation of a near-identical user interface across platforms, Audacity uses wxWidgets, a GUI framework. -Audacity 2.1.2 requires wxWidgets 3.0.2. +Audacity 2.1.3 requires wxWidgets 3.0.2. To be able to build Audacity for Windows, download and install wxWidgets from http://www.wxwidgets.org/. From 64a6fa625d9dedb0abe9599bdb8459ca88862d0a Mon Sep 17 00:00:00 2001 From: windinthew Date: Thu, 30 Mar 2017 02:26:42 +0100 Subject: [PATCH 71/91] pacovila PR 183 verb to noun --- locale/es.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/locale/es.po b/locale/es.po index e52c72d91..aef54c70c 100644 --- a/locale/es.po +++ b/locale/es.po @@ -3,10 +3,10 @@ # Antonio Paniagua Navarro , 2011, 2012, 2013, 2014, 2015, 2016. msgid "" msgstr "" -"Project-Id-Version: Audacity 2.0.x\n" +"Project-Id-Version: Audacity 2.2.x\n" "Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n" "POT-Creation-Date: 2017-03-18 18:41+0000\n" -"PO-Revision-Date: 2016-11-22 17:44+0100\n" +"PO-Revision-Date: 2017-03-30 02:21-0000\n" "Last-Translator: Antonio Paniagua Navarro \n" "Language-Team: Spanish \n" "Language: es\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Lokalize 1.5\n" +"X-Generator: Poedit 1.6.9\n" #: lib-src/FileDialog/gtk/FileDialogPrivate.cpp:75 #, c-format @@ -3812,7 +3812,7 @@ msgstr "Pistas seleccionadas silenciadas durante %.2f segundos en %.2f" #: src/Menus.cpp:4772 src/effects/Silence.h:22 msgid "Silence" -msgstr "Silenciar" +msgstr "Silencio" #: src/Menus.cpp:4803 msgid "Duplicated" From 82f909fe3113d42d2a2720272f5a49d17cb4eb0a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 29 Mar 2017 16:44:20 -0400 Subject: [PATCH 72/91] Again, fix compilation without USE_MIDI --- src/MixerBoard.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 2b3ffef51..50c87f1d4 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -191,6 +191,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, size.GetHeight() - ctrlPos.y - kQuadrupleInset; ctrlSize.Set(kLeftSideStackWidth - kQuadrupleInset, nGainSliderHeight); +#ifdef USE_MIDI if (GetNote()) { mSlider_Gain = safenew MixerTrackSlider( @@ -201,6 +202,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, true, 0.0, wxVERTICAL); } else +#endif mSlider_Gain = safenew MixerTrackSlider( this, ID_SLIDER_GAIN, @@ -327,10 +329,12 @@ WaveTrack *MixerTrackCluster::GetRight() const return nullptr; } +#ifdef USE_MIDI NoteTrack *MixerTrackCluster::GetNote() const { return dynamic_cast< NoteTrack * >( mTrack ); } +#endif void MixerTrackCluster::UpdatePrefs() { From 1a86819b4b218ea194068253cfc0d6030bef6ca5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 30 Mar 2017 10:46:44 -0400 Subject: [PATCH 73/91] Fixes for clang build with 64 bit unsigned long --- include/audacity/Types.h | 4 +++- src/Mix.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/audacity/Types.h b/include/audacity/Types.h index 1614cc7dd..63f028964 100644 --- a/include/audacity/Types.h +++ b/include/audacity/Types.h @@ -70,7 +70,9 @@ public: sampleCount ( int v ) : value { v } {} sampleCount ( unsigned v ) : value { v } {} sampleCount ( long v ) : value { v } {} - sampleCount ( unsigned long v ) : value { v } {} + + // unsigned long is 64 bit on some platforms. Let it narrow. + sampleCount ( unsigned long v ) : value ( v ) {} // Beware implicit conversions from floating point values! // Otherwise the meaning of binary operators with sampleCount change diff --git a/src/Mix.cpp b/src/Mix.cpp index a16ca05e2..27993a8dd 100644 --- a/src/Mix.cpp +++ b/src/Mix.cpp @@ -255,7 +255,7 @@ Mixer::Mixer(const WaveTrackConstArray &inputTracks, , mQueueMaxLen{ 65536 } , mSampleQueue{ mNumInputTracks, mQueueMaxLen } - , mNumChannels{ static_cast(numOutChannels) } + , mNumChannels{ numOutChannels } , mGains{ mNumChannels } , mMayThrow{ mayThrow } From 7bda40f656c4459b74cf13ae910f310e1da0dfa6 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 30 Mar 2017 16:00:27 -0400 Subject: [PATCH 74/91] Common functions read and write mute and solo in Wave and Note --- src/NoteTrack.cpp | 7 +++---- src/Track.cpp | 27 +++++++++++++++++++++++++++ src/Track.h | 13 +++++++++++++ src/WaveTrack.cpp | 11 +++-------- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 234975a24..914a8f6c5 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -758,6 +758,8 @@ bool NoteTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs) double dblValue; if (!wxStrcmp(attr, wxT("name")) && XMLValueChecker::IsGoodString(strValue)) mName = strValue; + else if (this->NoteTrackBase::HandleXMLAttribute(attr, value)) + {} else if (!wxStrcmp(attr, wxT("offset")) && XMLValueChecker::IsGoodString(strValue) && Internat::CompatibleToDouble(strValue, &dblValue)) @@ -831,10 +833,7 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const saveme->mSeq->write(data, true); xmlFile.StartTag(wxT("notetrack")); xmlFile.WriteAttr(wxT("name"), saveme->mName); -#ifdef EXPERIMENTAL_MIDI_OUT - xmlFile.WriteAttr(wxT("mute"), mMute); - xmlFile.WriteAttr(wxT("solo"), mSolo); -#endif + this->NoteTrackBase::WriteXMLAttributes(xmlFile); xmlFile.WriteAttr(wxT("offset"), saveme->GetOffset()); xmlFile.WriteAttr(wxT("visiblechannels"), saveme->mVisibleChannels); xmlFile.WriteAttr(wxT("height"), saveme->GetActualHeight()); diff --git a/src/Track.cpp b/src/Track.cpp index 166b2393b..9004253a8 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -341,6 +341,33 @@ void PlayableTrack::Merge( const Track &orig ) AudioTrack::Merge( *pOrig ); } +// Serialize, not with tags of its own, but as attributes within a tag. +void PlayableTrack::WriteXMLAttributes(XMLWriter &xmlFile) const +{ + xmlFile.WriteAttr(wxT("mute"), mMute); + xmlFile.WriteAttr(wxT("solo"), mSolo); + AudioTrack::WriteXMLAttributes(xmlFile); +} + +// Return true iff the attribute is recognized. +bool PlayableTrack::HandleXMLAttribute(const wxChar *attr, const wxChar *value) +{ + const wxString strValue{ value }; + long nValue; + if (!wxStrcmp(attr, wxT("mute")) && + XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) { + mMute = (nValue != 0); + return true; + } + else if (!wxStrcmp(attr, wxT("solo")) && + XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) { + mSolo = (nValue != 0); + return true; + } + + return AudioTrack::HandleXMLAttribute(attr, value); +} + // TrackListIterator TrackListIterator::TrackListIterator(TrackList * val) : l(val) diff --git a/src/Track.h b/src/Track.h index 39a994168..2b74e076d 100644 --- a/src/Track.h +++ b/src/Track.h @@ -251,6 +251,13 @@ public: AudioTrack(const std::shared_ptr &projDirManager) : Track{ projDirManager } {} AudioTrack(const Track &orig) : Track{ orig } {} + + // Serialize, not with tags of its own, but as attributes within a tag. + void WriteXMLAttributes(XMLWriter &xmlFile) const {} + + // Return true iff the attribute is recognized. + bool HandleXMLAttribute(const wxChar * /*attr*/, const wxChar * /*value*/) + { return false; } }; class PlayableTrack /* not final */ : public AudioTrack @@ -268,6 +275,12 @@ public: void Init( const PlayableTrack &init ); void Merge( const Track &init ) override; + // Serialize, not with tags of its own, but as attributes within a tag. + void WriteXMLAttributes(XMLWriter &xmlFile) const; + + // Return true iff the attribute is recognized. + bool HandleXMLAttribute(const wxChar *attr, const wxChar *value); + protected: bool mMute { false }; bool mSolo { false }; diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 6c2fed45f..93c641a5a 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -1685,12 +1685,8 @@ bool WaveTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs) // track is created. mLegacyProjectFileOffset = dblValue; } - else if (!wxStrcmp(attr, wxT("mute")) && - XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) - mMute = (nValue != 0); - else if (!wxStrcmp(attr, wxT("solo")) && - XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) - mSolo = (nValue != 0); + else if (this->PlayableTrack::HandleXMLAttribute(attr, value)) + {} else if (!wxStrcmp(attr, wxT("height")) && XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) mHeight = nValue; @@ -1789,8 +1785,7 @@ void WaveTrack::WriteXML(XMLWriter &xmlFile) const xmlFile.WriteAttr(wxT("name"), mName); xmlFile.WriteAttr(wxT("channel"), mChannel); xmlFile.WriteAttr(wxT("linked"), mLinked); - xmlFile.WriteAttr(wxT("mute"), mMute); - xmlFile.WriteAttr(wxT("solo"), mSolo); + this->PlayableTrack::WriteXMLAttributes(xmlFile); #ifdef EXPERIMENTAL_OUTPUT_DISPLAY int height; if(MONO_PAN) From 23dc35a18cbe7059f11b4505594d0c245e8a0d7b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 30 Mar 2017 16:48:52 -0400 Subject: [PATCH 75/91] Bug1614: fix crash duplicating a clip --- src/Envelope.cpp | 2 +- src/Sequence.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Envelope.cpp b/src/Envelope.cpp index 1fb1b7da2..e483bb2b4 100644 --- a/src/Envelope.cpp +++ b/src/Envelope.cpp @@ -198,7 +198,7 @@ EnvPoint *Envelope::AddPointAtEnd( double t, double val ) void Envelope::CopyFrom(const Envelope *e, double t0, double t1) { - wxASSERT( t0 < t1 ); + wxASSERT( t0 <= t1 ); mOffset = wxMax(t0, e->mOffset); mTrackLen = wxMin(t1, e->mOffset + e->mTrackLen) - mOffset; diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 955672150..726029298 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -378,8 +378,10 @@ float Sequence::GetRMS(sampleCount start, sampleCount len, bool mayThrow) const std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const { - if (s0 >= s1 || s0 >= mNumSamples || s1 < 0) - return {}; + auto dest = std::make_unique(mDirManager, mSampleFormat); + if (s0 >= s1 || s0 >= mNumSamples || s1 < 0) { + return dest; + } int numBlocks = mBlock.size(); @@ -391,7 +393,6 @@ std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const wxUnusedVar(numBlocks); wxASSERT(b0 <= b1); - auto dest = std::make_unique(mDirManager, mSampleFormat); dest->mBlock.reserve(b1 - b0 + 1); SampleBuffer buffer(mMaxSamples, mSampleFormat); From a9879bddf0fbfad38784d276d5a80a1e5fd45cfc Mon Sep 17 00:00:00 2001 From: Steve Daulton Date: Fri, 31 Mar 2017 00:01:08 +0100 Subject: [PATCH 76/91] Refactor clipfix.ny to fix multiple problems Basically a rewrite based on the original algorithm. --- plug-ins/clipfix.ny | 203 +++++++++++++------------------- src/effects/nyquist/Nyquist.cpp | 1 - 2 files changed, 81 insertions(+), 123 deletions(-) diff --git a/plug-ins/clipfix.ny b/plug-ins/clipfix.ny index 637f4d8d3..2f1ec93a2 100644 --- a/plug-ins/clipfix.ny +++ b/plug-ins/clipfix.ny @@ -1,141 +1,100 @@ ;nyquist plug-in -;version 1 +;version 4 ;type process ;preview enabled -;categories "http://audacityteam.org/namespace#NoiseRemoval" ;name "Clip Fix..." ;action "Reconstructing clips..." -;author "Benjamin Schwartz" +;author "Benjamin Schwartz and Steve Daulton" ;copyright "Licensing confirmed under terms of the GNU General Public License version 2" -;; clipfix.ny by Benjamin Schwartz. -;; Licensing confirmed under terms of the GNU General Public License version 2: -;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html -;; with kind agreement of Benjamin Schwartz, December 2011. -;; GUI updated by Steve Daulton July 2012 -;; -;; For information about writing and modifying Nyquist plug-ins: -;; http://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference +;; Algorithm by Benjamin Schwartz +;; Clip Fix is a simple, stupid (but not blind) digital-clipping-corrector +;; The algorithm is fairly simple: +;; 1. Find all clipped regions +;; 2. Get the slope immediately on either side of the region +;; 3. Do a cubic spline interpolation. +;; 4. Go to next region -;control thresh "Threshold of Clipping (%)" real "" 95 0 100 +;control threshold "Threshold of Clipping (%)" float "" 95 0 100 +;control gain "Reduce amplitude to allow for restored peaks (dB)" float "" -9 -30 0 -(setf largenumber 100000000) ;;Largest number of samples that can be imported -(setf blocksize 100000) - -;;Clip Fix is a simple, stupid (but not blind) digital-clipping-corrector -;;The algorithm is fairly simple: -;;1. Find all clipped regions -;;2. Get the slope immediately on either side of the region -;;3. Do a cubic spline interpolation. -;;4. Go to next region - -;;Coded from start (didn't know lisp (well, scheme, but not not lisp and certainly not -;;some XLISP 2.0 derivative)) to finish -;;(fully working, more or less) in one afternoon (and some evening). -;;Written by Benjamin Schwartz, MIT class of 2006, on May 25, 2004. -;;Explanatory text added by Gale Andrews, May 2008. - -(defun declip (sin) ;;Central function -(let* ((threshold (* (peak sin largenumber) thresh 0.01)) -(s2 (snd-copy sin)) -(samplerate (snd-srate s2)) -(s2length (snd-length s2 largenumber))) - -(seqrep (i (1+ (/ s2length blocksize))) - (let ((l (min blocksize (- s2length (* i blocksize))))) - ;;(print (list i t0 l samplerate)) - (snd-from-array 0 samplerate - (workhorse - ;;(let () (print (list s2 (type-of s2) l (type-of l))) - (snd-fetch-array s2 l l) - ;;) - threshold)))) - -;;(setf r (snd-fetch-array (snd-copy s) (snd-length s largenumber) 1)) ;;Create a sound array -;;(snd-from-array (snd-t0 s) (snd-srate s) (workhorse r threshold)) -)) - -(defun workhorse (r threshold) - -(setf n (length r)) ;; Record its length - -(setf exithigh ()) ;;Times when the wavefrom left the allowed region -(setf returnhigh ()) ;;Times when it returned to the allowed region - -(setf drange 4) - -(let ((i drange) (max (- n drange))) ;;Leave room at ends for derivative processing - (while (< i max) - (if (>= (aref r i) threshold) - (if (< (aref r (- i 1)) threshold) - (setq exithigh (cons (- i 1) exithigh))) ;;We just crossed the threshold up - (if (>= (aref r (- i 1)) threshold) - (setq returnhigh (cons i returnhigh)))) ;;We just crossed the threshold down - (setq i (1+ i)))) - -(setq exithigh (reverse exithigh)) ;;List comes out backwards -(setq returnhigh (reverse returnhigh)) - -(if (>= (aref r (1- drange)) threshold) ;;If the audio begins in a clipped region, ignore - (setq returnhigh (cdr returnhigh))) ;the extra return from threshold - -(setf exitlow ()) ;; Same as above, but for the bottom threshold -(setf returnlow ()) - -(setf threshlow (* -1 threshold)) ;;Assumes your digital range is zero-centered +(setf threshold (/ threshold 100)) +(setf gain (db-to-linear gain)) +(setf buffersize 100000) +(setf slopelength 4) ; number of samples used to calculate the exit / re-entry slope -(let ((i drange) (max (- n drange))) - (while (< i max) - (if (<= (aref r i) threshlow) - (if (> (aref r (- i 1)) threshlow) - (setq exitlow (cons (- i 1) exitlow))) - (if (<= (aref r (- i 1)) threshlow) - (setq returnlow (cons i returnlow)))) - (setq i (1+ i)))) +(defun declip (sig thresh peak) + (let* ((threshold (* thresh peak)) + (ln (truncate len)) + (finalbufsize (rem ln buffersize))) + ;; Calculate the number of buffers we can process. + ;; if final buffer is not large enough for de-clipping we + ;; will just add it on the end as is. + (if (>= finalbufsize slopelength) + (setf buffercount (1+ (/ ln buffersize))) + (setf buffercount (/ ln buffersize))) + ;;; Make output sequence from processed buffers + (setf out + (seqrep (i buffercount) + (let* ((step (min buffersize (- ln (* i buffersize)))) + (buffer (snd-fetch-array sig step step)) + (processed (process buffer threshold step))) + (cue (mult gain + (snd-from-array 0 *sound-srate* processed)))))) + ;;; If there's unprocessed audio remaining, add it to the end + (if (and (> finalbufsize 0)(< finalbufsize slopelength)) + (seq out (cue (getfinalblock sig finalbufsize gain))) + out))) -(setq exitlow (reverse exitlow)) -(setq returnlow (reverse returnlow)) -(if (<= (aref r (1- drange)) threshlow) - (setq returnlow (cdr returnlow))) +(defun getfinalblock (sig step gain) + (let ((block (snd-fetch-array sig step step))) + (mult gain (snd-from-array 0 *sound-srate* block)))) -(while (and exithigh returnhigh) ;;If there are more clipped regions - (let* ((t1 (car exithigh)) ;;exit time - (t2 (car returnhigh)) ;;return time - (d1 (max 0 (/ (- (aref r t1) (aref r (- t1 (1- drange)))) (1- drange)))) ;;slope at exit - (d2 (min 0 (/ (- (aref r (+ t2 (1- drange))) (aref r t2)) (1- drange)))) ;;slope at return - (m (/ (+ d2 d1) (* (- t2 t1) (- t2 t1)))) ;;interpolation is by (t-t1)(t-t2)(mx+b) - (b (- (/ d2 (- t2 t1)) (* m t2))) ;;These values of m and b make the cubic seamless - (j (1+ t1))) ;; j is the index - (while (< j t2) - (setf (aref r j) (+ (aref r t1) (* (- j t1) (- j t2) (+ (* m j) b)))) - (setf (aref r j) (+ (* (- t2 j) (/ (aref r t1) (- t2 t1))) (* (- j t1) (/ (aref r t2) (- t2 t1))) (* (- j t1) (- j t2) (+ (* m j) b)))) - (setq j (1+ j)))) - (setq exithigh (cdr exithigh)) - (setq returnhigh (cdr returnhigh))) +(defun process (buffer threshold bufferlength) + ;;; Find threshold crossings + (setf exit-list ()) ; list of times when waveform exceeds threshold + (setf return-list ()) ; list of times when waveform returns below threshold + ;; Limitation of algorithm: the first and last 'slopelength' at ends of buffer are ignored + ;; so that we have enough samples beyond the threshold crossing to calculate the slope. + (let ((last-sample (- bufferlength slopelength))) + (do ((i slopelength (1+ i))) + ((>= i last-sample)) + (if (>= (abs (aref buffer i)) threshold) + (when (< (abs (aref buffer (- i 1))) threshold) ; we just crossed threshold + (push (- i 1) exit-list)) + (when (>= (abs (aref buffer (- i 1))) threshold) ; we just got back in range + (push i return-list))))) + ;; Reverse lists back into chronological order. + ;; This is faster than appending values in chronological order. + (setf exit-list (reverse exit-list)) + (setf return-list (reverse return-list)) + ;; If the audio begins in a clipped region, discard the first return + (when (>= (abs (aref buffer (1- slopelength))) threshold) + (setq return-list (cdr return-list))) + ;; Interpolate between each pair of exit / entry points + (let ((slopelen (1- slopelength))) + (mapc (lambda (t0 t1) + (interpolate buffer t0 t1 slopelen)) + exit-list return-list)) + buffer) -(while (and exitlow returnlow) ;;Same for bottom - (let* ((t1 (car exitlow)) - (t2 (car returnlow)) - (d1 (min 0 (/ (- (aref r t1) (aref r (- t1 (1- drange)))) (1- drange)))) ;;slope at exit - (d2 (max 0 (/ (- (aref r (+ t2 (1- drange))) (aref r t2)) (1- drange)))) ;;slope at return - (m (/ (+ d2 d1) (* (- t2 t1) (- t2 t1)))) - (b (- (/ d2 (- t2 t1)) (* m t2))) - (a (/ (+ (aref r t1) (aref r t2)) 2)) - (j (1+ t1))) - (while (< j t2) - (setf (aref r j) (+ (* (- t2 j) (/ (aref r t1) (- t2 t1))) (* (- j t1) (/ (aref r t2) (- t2 t1))) (* (- j t1) (- j t2) (+ (* m j) b)))) - (setq j (1+ j)))) - (setq exitlow (cdr exitlow)) - (setq returnlow (cdr returnlow))) -r) +(defun interpolate (buffer t0 t1 dur) + "Cubic spline interpolation" + (let* ((d0 (/ (- (aref buffer t0) (aref buffer (- t0 dur))) dur)) ; slope at start + (d1 (/ (- (aref buffer (+ t1 dur)) (aref buffer t1)) dur)) ; slope at end + (m (/ (+ d1 d0) (* (- t1 t0) (- t1 t0)))) + (b (- (/ d1 (- t1 t0)) (* m t1)))) + (do ((j (1+ t0) (1+ j))) + ((= j t1)) + (setf (aref buffer j) + (+ (* (- t1 j) (/ (aref buffer t0) (- t1 t0))) + (* (- j t0) (/ (aref buffer t1) (- t1 t0))) + (* (- j t0) (- j t1) (+ (* m j) b))))))) -(if (arrayp s) - (dotimes (j (length s)) - (setf (aref s j) (declip (aref s j)))) - (setq s (declip s))) -s +;; (get '*selection* 'peak) introduced in Audacity 2.1.3 +(multichan-expand #'declip *track* threshold (get '*selection* 'peak)) diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index b78157608..717c1a33e 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -998,7 +998,6 @@ bool NyquistEffect::ProcessOne() cmd += wxString::Format(wxT("(putprop '*SELECTION* (vector %s) 'PEAK)\n"), peakString) : cmd += wxString::Format(wxT("(putprop '*SELECTION* %s 'PEAK)\n"), peakString); - // TODO: Documen, PEAK-LEVEL is deprecated as of 2.1.3. // TODO: Document, PEAK-LEVEL is nil if NaN or INF. if (!std::isinf(maxPeakLevel) && !std::isnan(maxPeakLevel) && (maxPeakLevel < FLT_MAX)) { cmd += wxString::Format(wxT("(putprop '*SELECTION* (float %s) 'PEAK-LEVEL)\n"), From a936aed643ff8c5f844545623c878df915910615 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 30 Mar 2017 20:48:27 -0400 Subject: [PATCH 77/91] Another use of type AudioTrack --- src/Track.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Track.cpp b/src/Track.cpp index 9004253a8..2978489c0 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -616,16 +616,9 @@ SyncLockedTracksIterator::SyncLockedTracksIterator(TrackList * val) } namespace { - bool IsSyncLockableNonLabelTrack( const Track *pTrack ) + inline bool IsSyncLockableNonLabelTrack( const Track *pTrack ) { - if ( pTrack->GetKind() == Track::Wave ) - return true; -#ifdef USE_MIDI - else if ( pTrack->GetKind() == Track::Note ) - return true; -#endif - else - return false; + return nullptr != dynamic_cast< const AudioTrack * >( pTrack ); } } From 8928bd4d7b1ed4686b4836e058f0f3af39aecbca Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 31 Mar 2017 00:48:04 -0400 Subject: [PATCH 78/91] Correct MixerTrackCluster::GetRight() --- src/MixerBoard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 50c87f1d4..2538e85fe 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -324,7 +324,7 @@ WaveTrack *MixerTrackCluster::GetRight() const { auto left = GetWave(); if (left) - return static_cast(left); + return static_cast(left->GetLink()); else return nullptr; } From a1b88fe8d6ff35f8d96c3141e9829bcd7bfecb6a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 31 Mar 2017 13:02:57 -0400 Subject: [PATCH 79/91] Fix assertion in MIDI prefs when there are no devices --- src/prefs/MidiIOPrefs.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/prefs/MidiIOPrefs.cpp b/src/prefs/MidiIOPrefs.cpp index 926775602..5d3b3d63f 100644 --- a/src/prefs/MidiIOPrefs.cpp +++ b/src/prefs/MidiIOPrefs.cpp @@ -175,8 +175,10 @@ void MidiIOPrefs::PopulateOrExchange( ShuttleGui & S ) { void MidiIOPrefs::OnHost(wxCommandEvent & e) { + wxString itemAtIndex; int index = mHost->GetCurrentSelection(); - wxString itemAtIndex = mHostNames.Item(index); + if (index >= 0 && index < mHostNames.Count()) + itemAtIndex = mHostNames.Item(index); int nDevices = Pm_CountDevices(); if (nDevices == 0) { From d1cbac418151790e2abca6aeb22e233b6e3a376a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 24 Mar 2017 14:59:22 -0400 Subject: [PATCH 80/91] more finally, more const, remove unused, fix warnings --- src/Benchmark.cpp | 12 ++++++------ src/FileException.h | 2 +- src/Sequence.cpp | 5 +++-- src/Sequence.h | 2 +- src/WaveClip.cpp | 2 +- src/WaveClip.h | 2 +- src/effects/Effect.cpp | 2 -- 7 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Benchmark.cpp b/src/Benchmark.cpp index 22f78fa2f..8e2a3e553 100644 --- a/src/Benchmark.cpp +++ b/src/Benchmark.cpp @@ -337,11 +337,14 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event)) // Rememebr the old blocksize, so that we can restore it later. auto oldBlockSize = Sequence::GetMaxDiskBlockSize(); - const auto cleanup = finally([=] - { Sequence::SetMaxDiskBlockSize(oldBlockSize); } - ); Sequence::SetMaxDiskBlockSize(blockSize * 1024); + const auto cleanup = finally( [&] { + Sequence::SetMaxDiskBlockSize(oldBlockSize); + gPrefs->Write(wxT("/GUI/EditClipCanMove"), editClipCanMove); + gPrefs->Flush(); + } ); + wxBusyCursor busy; HoldPrint(true); @@ -540,7 +543,4 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event)) Printf(wxT("Benchmark completed successfully.\n")); HoldPrint(false); - - gPrefs->Write(wxT("/GUI/EditClipCanMove"), editClipCanMove); - gPrefs->Flush(); } diff --git a/src/FileException.h b/src/FileException.h index ef8f5e506..0d0225fc0 100644 --- a/src/FileException.h +++ b/src/FileException.h @@ -22,7 +22,7 @@ public: const wxString &caption = wxString{}, const wxFileName &renameTarget_ = {}) : MessageBoxException{ caption } - , fileName{ fileName_ }, cause{ cause_ }, renameTarget{ renameTarget_ } + , cause{ cause_ }, fileName{ fileName_ }, renameTarget{ renameTarget_ } {} FileException(FileException&& that) diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 726029298..34ced8a4b 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -1114,6 +1114,7 @@ int Sequence::FindBlock(sampleCount pos) const return rval; } +//static bool Sequence::Read(samplePtr buffer, sampleFormat format, const SeqBlock &b, size_t blockRelativeStart, size_t len, bool mayThrow) @@ -1298,7 +1299,7 @@ struct MinMaxSumsq } bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl, - size_t len, const sampleCount *where) + size_t len, const sampleCount *where) const { wxASSERT(len > 0); const auto s0 = std::max(sampleCount(0), where[0]); @@ -1333,7 +1334,7 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl, // Find the range of sample values for this block that // are in the display. - SeqBlock &seqBlock = mBlock[b]; + const SeqBlock &seqBlock = mBlock[b]; const auto start = seqBlock.start; nextSrcX = std::min(s1, start + seqBlock.f->GetLength()); diff --git a/src/Sequence.h b/src/Sequence.h index c458c6119..ede815556 100644 --- a/src/Sequence.h +++ b/src/Sequence.h @@ -101,7 +101,7 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{ // bl is negative wherever data are not yet available. // Return true if successful. bool GetWaveDisplay(float *min, float *max, float *rms, int* bl, - size_t len, const sampleCount *where); + size_t len, const sampleCount *where) const; std::unique_ptr Copy(sampleCount s0, sampleCount s1) const; bool Paste(sampleCount s0, const Sequence *src); diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index cfc527576..0478d8a48 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -1727,7 +1727,7 @@ bool WaveClip::ClearAndAddCutLine(double t0, double t1) bool WaveClip::FindCutLine(double cutLinePosition, double* cutlineStart /* = NULL */, - double* cutlineEnd /* = NULL */) + double* cutlineEnd /* = NULL */) const { for (const auto &cutline: mCutLines) { diff --git a/src/WaveClip.h b/src/WaveClip.h index 95fa6103e..79c1617a5 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -331,7 +331,7 @@ public: * position could be found. Return false otherwise. */ bool FindCutLine(double cutLinePosition, double* cutLineStart = NULL, - double *cutLineEnd = NULL); + double *cutLineEnd = NULL) const; /** Expand cut line (that is, re-insert audio, then DELETE audio saved in * cut line). Returns true if a cut line could be found and sucessfully diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index e0e36d7ed..5b3cb9ec7 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -1278,8 +1278,6 @@ bool Effect::ProcessPass() { bool bGoodResult = true; bool isGenerator = GetType() == EffectTypeGenerate; - bool editClipCanMove; - gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove, true); FloatBuffers inBuffer, outBuffer; ArrayOf inBufPos, outBufPos; From 8e2e4a53b84553937db9667184777d3aaa35c050 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 24 Mar 2017 14:40:39 -0400 Subject: [PATCH 81/91] Define SimpleMessageBoxException --- src/AudacityException.cpp | 15 +++++++++++++++ src/AudacityException.h | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/AudacityException.cpp b/src/AudacityException.cpp index 46504d4cc..e37edf175 100644 --- a/src/AudacityException.cpp +++ b/src/AudacityException.cpp @@ -50,6 +50,21 @@ MessageBoxException::~MessageBoxException() wxAtomicDec( sOutstandingMessages ); } +SimpleMessageBoxException::~SimpleMessageBoxException() +{ +} + +wxString SimpleMessageBoxException::ErrorMessage() const +{ + return message; +} + +std::unique_ptr< AudacityException > SimpleMessageBoxException::Move() +{ + return std::unique_ptr< AudacityException > + { safenew SimpleMessageBoxException{ std::move( *this ) } }; +} + // This is meant to be invoked via wxEvtHandler::CallAfter void MessageBoxException::DelayedHandlerAction() { diff --git a/src/AudacityException.h b/src/AudacityException.h index a0960fbdc..31e2e3382 100644 --- a/src/AudacityException.h +++ b/src/AudacityException.h @@ -69,6 +69,30 @@ private: mutable bool moved { false }; }; +// MessageBoxException that shows a given, unvarying string. +class SimpleMessageBoxException /* not final */ : public MessageBoxException +{ +public: + explicit SimpleMessageBoxException( const wxString &message_, + const wxString &caption = wxString{} ) + : MessageBoxException{ caption } + , message{ message_ } + {} + ~SimpleMessageBoxException() override; + + SimpleMessageBoxException( const SimpleMessageBoxException& ) = default; + SimpleMessageBoxException &operator = ( + SimpleMessageBoxException && ) PROHIBITED; + + std::unique_ptr< AudacityException > Move() override; + + // Format a default, internationalized error message for this exception. + virtual wxString ErrorMessage() const override; + +private: + wxString message; +}; + struct DefaultDelayedHandlerAction { void operator () (AudacityException *pException) const From 608dcc9b3fa403733855789b1e021da70c6ef381 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 24 Mar 2017 15:01:19 -0400 Subject: [PATCH 82/91] Reimplement prohibitions on moving clips by throwing exceptions... ... Also comment some strong and weak guarantees --- src/WaveClip.cpp | 79 +++++++++++++++++++++++----------------- src/WaveClip.h | 3 +- src/WaveTrack.cpp | 92 ++++++++++++++++++++++++----------------------- 3 files changed, 96 insertions(+), 78 deletions(-) diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index 0478d8a48..9d85cc16a 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -1539,6 +1539,7 @@ void WaveClip::WriteXML(XMLWriter &xmlFile) const } bool WaveClip::Paste(double t0, const WaveClip* other) +// STRONG-GUARANTEE { const bool clipNeedsResampling = other->mRate != mRate; const bool clipNeedsNewFormat = @@ -1558,34 +1559,42 @@ bool WaveClip::Paste(double t0, const WaveClip* other) // Force sample formats to match. newClip->ConvertToSampleFormat(mSequence->GetSampleFormat()); pastedClip = newClip.get(); - } else + } + else { // No resampling or format change needed, just use original clip without making a copy pastedClip = other; } + // Paste cut lines contained in pasted clip + WaveClipHolders newCutlines; + for (const auto &cutline: pastedClip->mCutLines) + { + newCutlines.push_back( + make_movable + ( *cutline, mSequence->GetDirManager(), + // Recursively copy cutlines of cutlines. They don't need + // their offsets adjusted. + true)); + newCutlines.back()->Offset(t0 - mOffset); + } + sampleCount s0; TimeToSamplesClip(t0, &s0); bool result = false; + + // Assume STRONG-GUARANTEE from Sequence::Paste if (mSequence->Paste(s0, pastedClip->mSequence.get())) { + // Assume NOFAIL-GUARANTEE in the remaining MarkChanged(); mEnvelope->Paste(s0.as_double()/mRate + mOffset, pastedClip->mEnvelope.get()); mEnvelope->RemoveUnneededPoints(); OffsetCutLines(t0, pastedClip->GetEndTime() - pastedClip->GetStartTime()); - // Paste cut lines contained in pasted clip - for (const auto &cutline: pastedClip->mCutLines) - { - mCutLines.push_back( - make_movable - ( *cutline, mSequence->GetDirManager(), - // Recursively copy cutlines of cutlines. They don't need - // their offsets adjusted. - true)); - mCutLines.back()->Offset(t0 - mOffset); - } + for (auto &holder : newCutlines) + mCutLines.push_back(std::move(holder)); result = true; } @@ -1745,28 +1754,33 @@ bool WaveClip::FindCutLine(double cutLinePosition, } bool WaveClip::ExpandCutLine(double cutLinePosition) +// STRONG-GUARANTEE { - for (auto it = mCutLines.begin(); it != mCutLines.end(); ++it) - { - WaveClip *const cutline = it->get(); - if (fabs(mOffset + cutline->GetOffset() - cutLinePosition) < 0.0001) - { - if (!Paste(mOffset+cutline->GetOffset(), cutline)) - return false; - // Now erase the cutline, - // but be careful to find it again, because Paste above may - // have modified the array of cutlines (if our cutline contained - // another cutline!), invalidating the iterator we had. - auto begin = mCutLines.begin(), end = mCutLines.end(); - it = std::find_if(begin, end, - [=](decltype(*begin) &p){ return p.get() == cutline; }); - if (it != end) - mCutLines.erase(it); // deletes cutline! - else { - wxASSERT(false); - } - return true; + auto end = mCutLines.end(); + auto it = std::find_if( mCutLines.begin(), end, + [&](const WaveClipHolder &cutline) { + return fabs(mOffset + cutline->GetOffset() - cutLinePosition) < 0.0001; + } ); + + if ( it != end ) { + auto cutline = it->get(); + // assume STRONG-GUARANTEE from Paste + if (!Paste(mOffset+cutline->GetOffset(), cutline)) + return false; + // Now erase the cutline, + // but be careful to find it again, because Paste above may + // have modified the array of cutlines (if our cutline contained + // another cutline!), invalidating the iterator we had. + end = mCutLines.end(); + it = std::find_if(mCutLines.begin(), end, + [=](const WaveClipHolder &p) { return p.get() == cutline; }); + if (it != end) + mCutLines.erase(it); // deletes cutline! + else { + // THROW_INCONSISTENCY_EXCEPTION; + wxASSERT(false); } + return true; } return false; @@ -1788,6 +1802,7 @@ bool WaveClip::RemoveCutLine(double cutLinePosition) } void WaveClip::OffsetCutLines(double t0, double len) +// NOFAIL-GUARANTEE { for (const auto &cutLine : mCutLines) { diff --git a/src/WaveClip.h b/src/WaveClip.h index 79c1617a5..44ee6a65f 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -141,7 +141,8 @@ public: class WaveClip; // Array of pointers that assume ownership -using WaveClipHolders = std::vector < movable_ptr< WaveClip > >; +using WaveClipHolder = movable_ptr< WaveClip >; +using WaveClipHolders = std::vector < WaveClipHolder >; using WaveClipConstHolders = std::vector < movable_ptr< const WaveClip > >; // Temporary arrays of mere pointers diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 93c641a5a..76463ca6f 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -1202,6 +1202,7 @@ bool WaveTrack::SyncLockAdjust(double oldT1, double newT1) } bool WaveTrack::Paste(double t0, const Track *src) +// WEAK-GUARANTEE { bool editClipCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove); @@ -1287,7 +1288,8 @@ bool WaveTrack::Paste(double t0, const Track *src) insideClip = clip.get(); break; } - } else + } + else { // If clips are immovable we also allow prepending to clips if (clip->WithinClip(t0) || @@ -1312,12 +1314,11 @@ bool WaveTrack::Paste(double t0, const Track *src) if (clip->GetStartTime() > insideClip->GetStartTime() && insideClip->GetEndTime() + insertDuration > clip->GetStartTime()) - { - wxMessageBox( - _("There is not enough room available to paste the selection"), - _("Error"), wxICON_STOP); - return false; - } + // STRONG-GUARANTEE in case of this path + // not that it matters. + throw SimpleMessageBoxException{ + _("There is not enough room available to paste the selection") + }; } } @@ -1331,12 +1332,11 @@ bool WaveTrack::Paste(double t0, const Track *src) //printf("paste: multi clip mode!\n"); if (!editClipCanMove && !IsEmpty(t0, t0+insertDuration-1.0/mRate)) - { - wxMessageBox( - _("There is not enough room available to paste the selection"), - _("Error"), wxICON_STOP); - return false; - } + // STRONG-GUARANTEE in case of this path + // not that it matters. + throw SimpleMessageBoxException{ + _("There is not enough room available to paste the selection") + }; for (const auto &clip : other->mClips) { @@ -2447,50 +2447,52 @@ void WaveTrack::UpdateLocationsCache() const // Expand cut line (that is, re-insert audio, then DELETE audio saved in cut line) bool WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart, double* cutlineEnd) +// STRONG-GUARANTEE { bool editClipCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove); // Find clip which contains this cut line - for (const auto &clip : mClips) + double start = 0, end = 0; + auto pEnd = mClips.end(); + auto pClip = std::find_if( mClips.begin(), pEnd, + [&](const WaveClipHolder &clip) { + return clip->FindCutLine(cutLinePosition, &start, &end); } ); + if (pClip != pEnd) { - double start = 0, end = 0; - - if (clip->FindCutLine(cutLinePosition, &start, &end)) + auto &clip = *pClip; + if (!editClipCanMove) { - if (!editClipCanMove) + // We are not allowed to move the other clips, so see if there + // is enough room to expand the cut line + for (const auto &clip2: mClips) { - // We are not allowed to move the other clips, so see if there - // is enough room to expand the cut line - for (const auto &clip2: mClips) - { - if (clip2->GetStartTime() > clip->GetStartTime() && - clip->GetEndTime() + end - start > clip2->GetStartTime()) - { - wxMessageBox( - _("There is not enough room available to expand the cut line"), - _("Error"), wxICON_STOP); - return false; - } - } - } + if (clip2->GetStartTime() > clip->GetStartTime() && + clip->GetEndTime() + end - start > clip2->GetStartTime()) + // STRONG-GUARANTEE in case of this path + throw SimpleMessageBoxException{ + _("There is not enough room available to expand the cut line") + }; + } + } - if (!clip->ExpandCutLine(cutLinePosition)) - return false; + if (!clip->ExpandCutLine(cutLinePosition)) + return false; - if (cutlineStart) - *cutlineStart = start; - if (cutlineEnd) - *cutlineEnd = end; + // STRONG-GUARANTEE provided that the following gives NOFAIL-GUARANTEE - // Move clips which are to the right of the cut line - if (editClipCanMove) + if (cutlineStart) + *cutlineStart = start; + if (cutlineEnd) + *cutlineEnd = end; + + // Move clips which are to the right of the cut line + if (editClipCanMove) + { + for (const auto &clip2 : mClips) { - for (const auto &clip2 : mClips) - { - if (clip2->GetStartTime() > clip->GetStartTime()) - clip2->Offset(end - start); - } + if (clip2->GetStartTime() > clip->GetStartTime()) + clip2->Offset(end - start); } return true; From ad34145dedeec3aaca5029e16c4da56c2c9f4a9a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 31 Mar 2017 14:58:01 -0400 Subject: [PATCH 83/91] Clarify paste logic, throw to rollback on error, keep TimeTrack unique... ... though TimeTracks are not yet ever cut or copied; but next commit will change that. --- src/Menus.cpp | 91 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 970602c62..4f9a345a3 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -4351,31 +4351,29 @@ void AudacityProject::OnPaste() if (c == NULL) return; Track *ff = NULL; - const Track *tmpSrc = NULL; - const Track *tmpC = NULL; - const Track *prev = NULL; + const Track *lastClipBeforeMismatch = NULL; + const Track *mismatchedClip = NULL; + const Track *prevClip = NULL; bool bAdvanceClipboard = true; bool bPastedSomething = false; - bool bTrackTypeMismatch = false; while (n && c) { if (n->GetSelected()) { bAdvanceClipboard = true; - if (tmpC) - c = tmpC; + if (mismatchedClip) + c = mismatchedClip; if (c->GetKind() != n->GetKind()) { - if (!bTrackTypeMismatch) { - tmpSrc = prev; - tmpC = c; + if (!mismatchedClip) { + lastClipBeforeMismatch = prevClip; + mismatchedClip = c; } - bTrackTypeMismatch = true; bAdvanceClipboard = false; - c = tmpSrc; + c = lastClipBeforeMismatch; // If the types still don't match... while (c && c->GetKind() != n->GetKind()) { - prev = c; + prevClip = c; c = clipIter.Next(); } } @@ -4383,7 +4381,7 @@ void AudacityProject::OnPaste() // Handle case where the first track in clipboard // is of different type than the first selected track if (!c) { - c = tmpC; + c = mismatchedClip; while (n && (c->GetKind() != n->GetKind() || !n->GetSelected())) { // Must perform sync-lock adjustment before incrementing n @@ -4399,39 +4397,40 @@ void AudacityProject::OnPaste() // The last possible case for cross-type pastes: triggered when we try to // paste 1+ tracks from one type into 1+ tracks of another type. If // there's a mix of types, this shouldn't run. - if (!c) { - wxMessageBox( - _("Pasting one type of track into another is not allowed."), - _("Error"), wxICON_ERROR, this); - c = n;//so we don't trigger any !c conditions on our way out - break; - } + if (!c) + // Throw, so that any previous changes to the project in this loop + // are discarded. + throw SimpleMessageBoxException{ + _("Pasting one type of track into another is not allowed.") + }; // When trying to copy from stereo to mono track, show error and exit // TODO: Automatically offer user to mix down to mono (unfortunately // this is not easy to implement if (c->GetLinked() && !n->GetLinked()) - { - wxMessageBox( - _("Copying stereo audio into a mono track is not allowed."), - _("Error"), wxICON_ERROR, this); - break; - } + // Throw, so that any previous changes to the project in this loop + // are discarded. + throw SimpleMessageBoxException{ + _("Copying stereo audio into a mono track is not allowed.") + }; if (!ff) ff = n; Maybe locker; if (msClipProject != this && c->GetKind() == Track::Wave) + // Cause duplication of block files on disk, when copy is + // between projects locker.create(static_cast(c)); - if (c->GetKind() == Track::Wave && n && n->GetKind() == Track::Wave) + wxASSERT( n && c ); + if (c->GetKind() == Track::Wave && n->GetKind() == Track::Wave) { bPastedSomething |= ((WaveTrack*)n)->ClearAndPaste(t0, t1, (WaveTrack*)c, true, true); } else if (c->GetKind() == Track::Label && - n && n->GetKind() == Track::Label) + n->GetKind() == Track::Label) { ((LabelTrack *)n)->Clear(t0, t1); @@ -4444,6 +4443,7 @@ void AudacityProject::OnPaste() } else { + n->Clear(t0, t1); bPastedSomething |= n->Paste(t0, c); } @@ -4464,7 +4464,7 @@ void AudacityProject::OnPaste() } if (bAdvanceClipboard){ - prev = c; + prevClip = c; c = clipIter.Next(); } } // if (n->GetSelected()) @@ -4487,7 +4487,8 @@ void AudacityProject::OnPaste() while (n) { if (n->GetSelected() && n->GetKind()==Track::Wave) { - if (c && c->GetKind() == Track::Wave) { + if (c) { + wxASSERT(c->GetKind() == Track::Wave); bPastedSomething |= ((WaveTrack *)n)->ClearAndPaste(t0, t1, (WaveTrack *)c, true, true); } @@ -4598,29 +4599,40 @@ bool AudacityProject::HandlePasteNothingSelected() while (pClip) { Maybe locker; if ((msClipProject != this) && (pClip->GetKind() == Track::Wave)) + // Cause duplication of block files on disk, when copy is + // between projects locker.create(static_cast(pClip)); - Track::Holder pNewTrack; + Track::Holder uNewTrack; + Track *pNewTrack; switch (pClip->GetKind()) { case Track::Wave: { WaveTrack *w = (WaveTrack *)pClip; - pNewTrack = mTrackFactory->NewWaveTrack(w->GetSampleFormat(), w->GetRate()); + uNewTrack = mTrackFactory->NewWaveTrack(w->GetSampleFormat(), w->GetRate()), + pNewTrack = uNewTrack.get(); } break; #ifdef USE_MIDI case Track::Note: - pNewTrack = mTrackFactory->NewNoteTrack(); + uNewTrack = mTrackFactory->NewNoteTrack(), + pNewTrack = uNewTrack.get(); break; #endif // USE_MIDI case Track::Label: - pNewTrack = mTrackFactory->NewLabelTrack(); + uNewTrack = mTrackFactory->NewLabelTrack(), + pNewTrack = uNewTrack.get(); break; - case Track::Time: - pNewTrack = mTrackFactory->NewTimeTrack(); + case Track::Time: { + // Maintain uniqueness of the time track! + pNewTrack = GetTracks()->GetTimeTrack(); + if (!pNewTrack) + uNewTrack = mTrackFactory->NewTimeTrack(), + pNewTrack = uNewTrack.get(); break; + } default: pClip = iterClip.Next(); continue; @@ -4632,10 +4644,13 @@ bool AudacityProject::HandlePasteNothingSelected() wxUnusedVar(bResult); if (!pFirstNewTrack) - pFirstNewTrack = pNewTrack.get(); + pFirstNewTrack = pNewTrack; pNewTrack->SetSelected(true); - FinishCopy(pClip, std::move(pNewTrack), *mTracks); + if (uNewTrack) + FinishCopy(pClip, std::move(uNewTrack), *mTracks); + else + FinishCopy(pClip, pNewTrack); pClip = iterClip.Next(); } From f1b354b141eec152c1348368c53af553bcf55717 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 31 Mar 2017 14:54:55 -0400 Subject: [PATCH 84/91] More pure virtuals in Track, supply Note and Time overrides --- src/NoteTrack.cpp | 12 +++++++++++ src/NoteTrack.h | 2 ++ src/TimeTrack.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++---- src/TimeTrack.h | 11 +++++++++- src/Track.h | 19 +++++++++--------- 5 files changed, 81 insertions(+), 14 deletions(-) diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 914a8f6c5..2b78d28da 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -534,6 +534,18 @@ bool NoteTrack::Paste(double t, const Track *src) return true; } +bool NoteTrack::Silence(double, double) +{ + // to do + return false; +} + +bool NoteTrack::InsertSilence(double, double) +{ + // to do + return false; +} + // Call this function to manipulate the underlying sequence data. This is // NOT the function that handles horizontal dragging. bool NoteTrack::Shift(double t) // t is always seconds diff --git a/src/NoteTrack.h b/src/NoteTrack.h index a314db574..3a62c50e0 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -105,6 +105,8 @@ class AUDACITY_DLL_API NoteTrack final bool Trim (double t0, double t1) /* not override */; bool Clear(double t0, double t1) override; bool Paste(double t, const Track *src) override; + bool Silence(double t0, double t1) override; + bool InsertSilence(double t, double len) override; bool Shift(double t) /* not override */; #ifdef EXPERIMENTAL_MIDI_OUT diff --git a/src/TimeTrack.cpp b/src/TimeTrack.cpp index 6f47af6f3..a552a1bce 100644 --- a/src/TimeTrack.cpp +++ b/src/TimeTrack.cpp @@ -63,20 +63,24 @@ TimeTrack::TimeTrack(const std::shared_ptr &projDirManager, const Zo blankPen.SetColour(214, 214, 214); } -TimeTrack::TimeTrack(const TimeTrack &orig): - Track(orig) +TimeTrack::TimeTrack(const TimeTrack &orig, double *pT0, double *pT1) + : Track(orig) , mZoomInfo(orig.mZoomInfo) { Init(orig); // this copies the TimeTrack metadata (name, range, etc) ///@TODO: Give Envelope:: a copy-constructor instead of this? mEnvelope = std::make_unique(); + mEnvelope->Flatten(1.0); mEnvelope->SetTrackLen(DBL_MAX); SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB - mEnvelope->Flatten(1.0); mEnvelope->SetOffset(0); mEnvelope->SetRange(orig.mEnvelope->GetMinValue(), orig.mEnvelope->GetMaxValue()); - mEnvelope->Paste(0.0, orig.mEnvelope.get()); + if ( pT0 && pT1 ) + // restricted copy + mEnvelope->CopyFrom(orig.mEnvelope.get(), *pT0, *pT1); + else + mEnvelope->Paste(0.0, orig.mEnvelope.get()); ///@TODO: Give Ruler:: a copy-constructor instead of this? mRuler = std::make_unique(); @@ -103,6 +107,45 @@ TimeTrack::~TimeTrack() { } +Track::Holder TimeTrack::Cut( double t0, double t1 ) +{ + auto result = Copy( t0, t1, false ); + Clear( t0, t1 ); + return result; +} + +Track::Holder TimeTrack::Copy( double t0, double t1, bool ) const +{ + auto result = std::make_unique( *this, &t0, &t1 ); + return Track::Holder{ std::move( result ) }; +} + +bool TimeTrack::Clear(double t0, double t1) +{ + mEnvelope->CollapseRegion(t0, t1); + return true; +} + +bool TimeTrack::Paste(double t, const Track * src) +{ + if (src->GetKind() != Track::Time) + return false; + + mEnvelope->Paste(t, static_cast(src)->mEnvelope.get()); + return true; +} + +bool TimeTrack::Silence(double t0, double t1) +{ + return true; +} + +bool TimeTrack::InsertSilence(double t, double len) +{ + mEnvelope->InsertSpace(t, len); + return true; +} + Track::Holder TimeTrack::Duplicate() const { return std::make_unique(*this); diff --git a/src/TimeTrack.h b/src/TimeTrack.h index 03aa29860..16e8743c7 100644 --- a/src/TimeTrack.h +++ b/src/TimeTrack.h @@ -34,11 +34,20 @@ class TimeTrack final : public Track { * Envelope:: and Ruler:: members in order to copy one to the other - unfortunately both lack a * copy-constructor to encapsulate this. * @param orig The original track to copy from + * @param pT0 if not null, then the start of the sub-range to copy + * @param pT1 if not null, then the end of the sub-range to copy */ - TimeTrack(const TimeTrack &orig); + TimeTrack(const TimeTrack &orig, double *pT0 = nullptr, double *pT1 = nullptr); virtual ~TimeTrack(); + Holder Cut( double t0, double t1 ) override; + Holder Copy( double t0, double t1, bool forClipboard ) const override; + bool Clear(double t0, double t1) override; + bool Paste(double t, const Track * src) override; + bool Silence(double t0, double t1) override; + bool InsertSilence(double t, double len) override; + // Identifying the type of track int GetKind() const override { return Time; } diff --git a/src/Track.h b/src/Track.h index 2b74e076d..334efeb41 100644 --- a/src/Track.h +++ b/src/Track.h @@ -206,28 +206,29 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler // separate from the Track. const std::shared_ptr &GetDirManager() const { return mDirManager; } - // Create a NEW track and modify this track (or return null for failure) - virtual Holder Cut(double WXUNUSED(t0), double WXUNUSED(t1)) { return{}; } + // Create a NEW track and modify this track + // Return non-NULL or else throw + virtual Holder Cut(double WXUNUSED(t0), double WXUNUSED(t1)) = 0; - // Create a NEW track and don't modify this track (or return null for failure) + // Create a NEW track and don't modify this track + // Return non-NULL or else throw // Note that subclasses may want to distinguish tracks stored in a clipboard // from those stored in a project virtual Holder Copy - (double WXUNUSED(t0), double WXUNUSED(t1), bool forClipboard = true) const - { return{}; } + (double WXUNUSED(t0), double WXUNUSED(t1), bool forClipboard = true) const = 0; // Return true for success - virtual bool Clear(double WXUNUSED(t0), double WXUNUSED(t1)) {return false;} + virtual bool Clear(double WXUNUSED(t0), double WXUNUSED(t1)) = 0; // Return true for success - virtual bool Paste(double WXUNUSED(t), const Track * WXUNUSED(src)) {return false;} + virtual bool Paste(double WXUNUSED(t), const Track * WXUNUSED(src)) = 0; // This can be used to adjust a sync-lock selected track when the selection // is replaced by one of a different length. virtual bool SyncLockAdjust(double oldT1, double newT1); - virtual bool Silence(double WXUNUSED(t0), double WXUNUSED(t1)) {return false;} - virtual bool InsertSilence(double WXUNUSED(t), double WXUNUSED(len)) {return false;} + virtual bool Silence(double WXUNUSED(t0), double WXUNUSED(t1)) = 0; + virtual bool InsertSilence(double WXUNUSED(t), double WXUNUSED(len)) = 0; virtual int GetKind() const { return None; } From 6b84dc1c1de21f4ce1fd7309b25f1d12952b7140 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 31 Mar 2017 15:00:16 -0400 Subject: [PATCH 85/91] Factory methods will return non-NULL or throw --- src/Benchmark.cpp | 7 +++-- src/LabelTrack.cpp | 9 +++---- src/Menus.cpp | 45 +++++++++++++-------------------- src/NoteTrack.cpp | 6 +++-- src/Sequence.cpp | 3 ++- src/Track.cpp | 1 - src/WaveTrack.cpp | 32 +++++++++++------------ src/effects/Equalization.cpp | 25 ++++++++---------- src/effects/Equalization48x.cpp | 23 ++++++++--------- 9 files changed, 70 insertions(+), 81 deletions(-) diff --git a/src/Benchmark.cpp b/src/Benchmark.cpp index 8e2a3e553..e333b046e 100644 --- a/src/Benchmark.cpp +++ b/src/Benchmark.cpp @@ -429,8 +429,11 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event)) if (mEditDetail) Printf(wxT("Cut: %d - %d \n"), x0 * chunkSize, (x0 + xlen) * chunkSize); - auto tmp = t->Cut(double (x0 * chunkSize), double ((x0 + xlen) * chunkSize)); - if (!tmp) { + Track::Holder tmp; + try { + tmp = t->Cut(double (x0 * chunkSize), double ((x0 + xlen) * chunkSize)); + } + catch (const AudacityException&) { Printf(wxT("Trial %d\n"), z); Printf(wxT("Cut (%d, %d) failed.\n"), (x0 * chunkSize), (x0 + xlen) * chunkSize); diff --git a/src/LabelTrack.cpp b/src/LabelTrack.cpp index e3cfd720f..a01cfdd2d 100644 --- a/src/LabelTrack.cpp +++ b/src/LabelTrack.cpp @@ -2339,10 +2339,10 @@ bool LabelTrack::Save(wxTextFile * out, bool overwrite) Track::Holder LabelTrack::Cut(double t0, double t1) { auto tmp = Copy(t0, t1); - if (!tmp) - return{}; + if (!Clear(t0, t1)) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; return tmp; } @@ -2353,8 +2353,7 @@ Track::Holder LabelTrack::SplitCut(double t0, double t1) // SplitCut() == Copy() + SplitDelete() Track::Holder tmp = Copy(t0, t1); - if (!tmp) - return {}; + if (!SplitDelete(t0, t1)) return {}; diff --git a/src/Menus.cpp b/src/Menus.cpp index 4f9a345a3..9d7a4178d 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -4177,8 +4177,7 @@ void AudacityProject::OnCut() dest = n->Copy(mViewInfo.selectedRegion.t0(), mViewInfo.selectedRegion.t1()); - if (dest) - FinishCopy(n, std::move(dest), newClipboard); + FinishCopy(n, std::move(dest), newClipboard); } n = iter.Next(); } @@ -4309,8 +4308,7 @@ void AudacityProject::OnCopy() if (n->GetSelected()) { auto dest = n->Copy(mViewInfo.selectedRegion.t0(), mViewInfo.selectedRegion.t1()); - if (dest) - FinishCopy(n, std::move(dest), newClipboard); + FinishCopy(n, std::move(dest), newClipboard); } n = iter.Next(); } @@ -4914,11 +4912,9 @@ void AudacityProject::OnDuplicate() // Make copies not for clipboard but for direct addition to the project auto dest = n->Copy(mViewInfo.selectedRegion.t0(), mViewInfo.selectedRegion.t1(), false); - if (dest) { - dest->Init(*n); - dest->SetOffset(wxMax(mViewInfo.selectedRegion.t0(), n->GetOffset())); - mTracks->Add(std::move(dest)); - } + dest->Init(*n); + dest->SetOffset(wxMax(mViewInfo.selectedRegion.t0(), n->GetOffset())); + mTracks->Add(std::move(dest)); } if (n == l) { @@ -5129,22 +5125,19 @@ void AudacityProject::OnSplit() double sel0 = mViewInfo.selectedRegion.t0(); double sel1 = mViewInfo.selectedRegion.t1(); - dest = NULL; - n->Copy(sel0, sel1, &dest); - if (dest) { - dest->Init(*n); - dest->SetOffset(wxMax(sel0, n->GetOffset())); + dest = n->Copy(sel0, sel1); + dest->Init(*n); + dest->SetOffset(wxMax(sel0, n->GetOffset())); - if (sel1 >= n->GetEndTime()) - n->Clear(sel0, sel1); - else if (sel0 <= n->GetOffset()) { - n->Clear(sel0, sel1); - n->SetOffset(sel1); - } else - n->Silence(sel0, sel1); + if (sel1 >= n->GetEndTime()) + n->Clear(sel0, sel1); + else if (sel0 <= n->GetOffset()) { + n->Clear(sel0, sel1); + n->SetOffset(sel1); + } else + n->Silence(sel0, sel1); - newTracks.Add(dest); - } + newTracks.Add(dest); } n = iter.Next(); } @@ -5190,10 +5183,8 @@ void AudacityProject::OnSplitNew() mViewInfo.selectedRegion.t1()); } #endif - if (dest) { - dest->SetOffset(wxMax(newt0, offset)); - FinishCopy(n, std::move(dest), *mTracks); - } + dest->SetOffset(wxMax(newt0, offset)); + FinishCopy(n, std::move(dest), *mTracks); } if (n == l) { diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 2b78d28da..637a614be 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -435,7 +435,8 @@ int NoteTrack::GetVisibleChannels() Track::Holder NoteTrack::Cut(double t0, double t1) { if (t1 <= t0) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; double len = t1-t0; auto newTrack = std::make_unique(mDirManager); @@ -457,7 +458,8 @@ Track::Holder NoteTrack::Cut(double t0, double t1) Track::Holder NoteTrack::Copy(double t0, double t1, bool) const { if (t1 <= t0) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; double len = t1-t0; auto newTrack = std::make_unique(mDirManager); diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 34ced8a4b..5058573ed 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -438,7 +438,8 @@ std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const } if (! ConsistencyCheck(wxT("Sequence::Copy()"))) - return {}; + //THROW_INCONSISTENCY_EXCEPTION + ; return dest; } diff --git a/src/Track.cpp b/src/Track.cpp index 2978489c0..7b0e5512a 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -309,7 +309,6 @@ bool Track::SyncLockAdjust(double oldT1, double newT1) return true; auto tmp = Cut(oldT1, GetEndTime()); - if (!tmp) return false; bool ret = Paste(newT1, tmp.get()); wxASSERT(ret); // TODO: handle this. diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 76463ca6f..040c14ca8 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -532,15 +532,14 @@ bool WaveTrack::IsEmpty(double t0, double t1) const Track::Holder WaveTrack::Cut(double t0, double t1) { if (t1 < t0) - return{}; + // THROW_INCONSISTENCY_EXCEPTION + ; auto tmp = Copy(t0, t1); - if (!tmp) - return{}; - if (!Clear(t0, t1)) - return{}; + // THROW_INCONSISTENCY_EXCEPTION + ; return tmp; } @@ -548,14 +547,15 @@ Track::Holder WaveTrack::Cut(double t0, double t1) Track::Holder WaveTrack::SplitCut(double t0, double t1) { if (t1 < t0) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; // SplitCut is the same as 'Copy', then 'SplitDelete' auto tmp = Copy(t0, t1); - if (!tmp) - return{}; + if (!SplitDelete(t0, t1)) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; return tmp; } @@ -564,14 +564,15 @@ Track::Holder WaveTrack::SplitCut(double t0, double t1) Track::Holder WaveTrack::CutAndAddCutLine(double t0, double t1) { if (t1 < t0) - return {}; + //THROW_INCONSISTENCY_EXCEPTION + ; // Cut is the same as 'Copy', then 'Delete' auto tmp = Copy(t0, t1); - if (!tmp) - return {}; + if (!ClearAndAddCutLine(t0, t1)) - return {}; + //THROW_INCONSISTENCY_EXCEPTION + ; return tmp; } @@ -636,7 +637,8 @@ bool WaveTrack::Trim (double t0, double t1) Track::Holder WaveTrack::Copy(double t0, double t1, bool forClipboard) const { if (t1 <= t0) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; WaveTrack *newTrack; Track::Holder result @@ -1166,8 +1168,6 @@ bool WaveTrack::SyncLockAdjust(double oldT1, double newT1) gPrefs->Read(wxT("/GUI/EditClipCanMove"), &clipsCanMove); if (clipsCanMove) { auto tmp = Cut (oldT1, GetEndTime() + 1.0/GetRate()); - if (!tmp) - return false; ret = Paste(newT1, tmp.get()); wxASSERT(ret); diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index 954f733fb..6adc84ebf 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -1173,20 +1173,17 @@ bool EffectEqualization::ProcessOne(int count, WaveTrack * t, //remove the old audio and get the NEW t->Clear(clipStartEndTimes[i].first,clipStartEndTimes[i].second); auto toClipOutput = output->Copy(clipStartEndTimes[i].first-startT+offsetT0,clipStartEndTimes[i].second-startT+offsetT0); - if(toClipOutput) - { - //put the processed audio in - bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); - //if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this - //This is not true when the selection is fully contained within one clip (second half of conditional) - if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || - clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) && - !(clipRealStartEndTimes[i].first <= startT && - clipRealStartEndTimes[i].second >= startT+lenT) ) - t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second); - } + //put the processed audio in + bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get()); + wxASSERT(bResult); // TO DO: Actually handle this. + wxUnusedVar(bResult); + //if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this + //This is not true when the selection is fully contained within one clip (second half of conditional) + if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || + clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) && + !(clipRealStartEndTimes[i].first <= startT && + clipRealStartEndTimes[i].second >= startT+lenT) ) + t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second); } } diff --git a/src/effects/Equalization48x.cpp b/src/effects/Equalization48x.cpp index 0a6c2170c..6e5ced834 100644 --- a/src/effects/Equalization48x.cpp +++ b/src/effects/Equalization48x.cpp @@ -558,19 +558,16 @@ bool EffectEqualization48x::ProcessTail(WaveTrack * t, WaveTrack * output, sampl t->Clear(clipStartEndTimes[i].first,clipStartEndTimes[i].second); // output->Copy(clipStartEndTimes[i].first-startT+offsetT0,clipStartEndTimes[i].second-startT+offsetT0, &toClipOutput); auto toClipOutput = output->Copy(clipStartEndTimes[i].first-startT, clipStartEndTimes[i].second-startT); - if(toClipOutput) - { - //put the processed audio in - bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - //if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this - //This is not true when the selection is fully contained within one clip (second half of conditional) - if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || - clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) && - !(clipRealStartEndTimes[i].first <= startT && - clipRealStartEndTimes[i].second >= startT+lenT) ) - t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second); - } + //put the processed audio in + bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get()); + wxASSERT(bResult); // TO DO: Actually handle this. + //if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this + //This is not true when the selection is fully contained within one clip (second half of conditional) + if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || + clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) && + !(clipRealStartEndTimes[i].first <= startT && + clipRealStartEndTimes[i].second >= startT+lenT) ) + t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second); } return true; } From e1473dfe76f81ec29633ed2839ae57192465b7eb Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 23 Mar 2017 11:10:14 -0400 Subject: [PATCH 86/91] void return, not boolean success, from some Track virtual functions... ... The return codes were mostly ignored anyway, and exceptions will be thrown instead. It seems there was also confusion whether the return values of Track::Paste and Track::SyncLockAdjust were to indicate success or indicate whether there was any change. No matter now. --- src/AudioIO.cpp | 7 +-- src/Benchmark.cpp | 6 ++- src/LabelTrack.cpp | 24 ++++----- src/LabelTrack.h | 8 +-- src/Menus.cpp | 32 +++++++----- src/NoteTrack.cpp | 23 ++++----- src/NoteTrack.h | 8 +-- src/Project.cpp | 4 +- src/TimeTrack.cpp | 15 +++--- src/TimeTrack.h | 8 +-- src/Track.cpp | 14 ++---- src/Track.h | 12 ++--- src/WaveTrack.cpp | 88 ++++++++++++++------------------- src/WaveTrack.h | 12 +++-- src/effects/Effect.cpp | 3 +- src/effects/Equalization.cpp | 4 +- src/effects/Equalization48x.cpp | 3 +- src/effects/Paulstretch.cpp | 8 +-- src/effects/Repeat.cpp | 4 +- src/effects/Silence.cpp | 5 +- src/effects/StereoToMono.cpp | 4 +- src/toolbars/ControlToolBar.cpp | 4 +- 22 files changed, 131 insertions(+), 165 deletions(-) diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index a740523cc..8a4852f01 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -2474,13 +2474,10 @@ void AudioIO::StopStream() } if( appendRecord ) { // append-recording - bool bResult; if (recordingOffset < 0) - bResult = track->Clear(mT0, mT0 - recordingOffset); // cut the latency out + track->Clear(mT0, mT0 - recordingOffset); // cut the latency out else - bResult = track->InsertSilence(mT0, recordingOffset); // put silence in - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + track->InsertSilence(mT0, recordingOffset); // put silence in } else { // recording into a NEW track diff --git a/src/Benchmark.cpp b/src/Benchmark.cpp index e333b046e..e83fe3d64 100644 --- a/src/Benchmark.cpp +++ b/src/Benchmark.cpp @@ -449,8 +449,10 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event)) if (mEditDetail) Printf(wxT("Paste: %d\n"), y0 * chunkSize); - if (!t->Paste((double)(y0 * chunkSize), tmp.get())) - { + try { + t->Paste((double)(y0 * chunkSize), tmp.get()); + } + catch (const AudacityException&) { Printf(wxT("Trial %d\nFailed on Paste.\n"), z); goto fail; } diff --git a/src/LabelTrack.cpp b/src/LabelTrack.cpp index a01cfdd2d..53922ac64 100644 --- a/src/LabelTrack.cpp +++ b/src/LabelTrack.cpp @@ -153,7 +153,7 @@ void LabelTrack::SetOffset(double dOffset) labelStruct.selectedRegion.move(dOffset); } -bool LabelTrack::Clear(double b, double e) +void LabelTrack::Clear(double b, double e) { // May DELETE labels, so use subscripts to iterate for (size_t i = 0; i < mLabels.size(); ++i) { @@ -175,8 +175,6 @@ bool LabelTrack::Clear(double b, double e) else if (relation == LabelStruct::WITHIN_LABEL) labelStruct.selectedRegion.moveT1( - (e-b)); } - - return true; } #if 0 @@ -2340,9 +2338,7 @@ Track::Holder LabelTrack::Cut(double t0, double t1) { auto tmp = Copy(t0, t1); - if (!Clear(t0, t1)) - //THROW_INCONSISTENCY_EXCEPTION - ; + Clear(t0, t1); return tmp; } @@ -2416,6 +2412,7 @@ Track::Holder LabelTrack::Copy(double t0, double t1, bool) const bool LabelTrack::PasteOver(double t, const Track * src) { if (src->GetKind() != Track::Label) + // THROW_INCONSISTENCY_EXCEPTION; // ? return false; int len = mLabels.size(); @@ -2439,17 +2436,18 @@ bool LabelTrack::PasteOver(double t, const Track * src) return true; } -bool LabelTrack::Paste(double t, const Track *src) +void LabelTrack::Paste(double t, const Track *src) { if (src->GetKind() != Track::Label) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; LabelTrack *lt = (LabelTrack *)src; double shiftAmt = lt->mClipLen > 0.0 ? lt->mClipLen : lt->GetEndTime(); ShiftLabelsOnInsert(shiftAmt, t); - return PasteOver(t, src); + PasteOver(t, src); } // This repeats the labels in a time interval a specified number of times. @@ -2505,7 +2503,7 @@ bool LabelTrack::Repeat(double t0, double t1, int n) return true; } -bool LabelTrack::Silence(double t0, double t1) +void LabelTrack::Silence(double t0, double t1) { int len = mLabels.size(); @@ -2549,11 +2547,9 @@ bool LabelTrack::Silence(double t0, double t1) } SortLabels(); - - return true; } -bool LabelTrack::InsertSilence(double t, double len) +void LabelTrack::InsertSilence(double t, double len) { for (auto &labelStruct: mLabels) { double t0 = labelStruct.getT0(); @@ -2565,8 +2561,6 @@ bool LabelTrack::InsertSilence(double t, double len) t1 += len; labelStruct.selectedRegion.setTimes(t0, t1); } - - return true; } int LabelTrack::GetNumLabels() const diff --git a/src/LabelTrack.h b/src/LabelTrack.h index 1f9b1fd9c..720b659e3 100644 --- a/src/LabelTrack.h +++ b/src/LabelTrack.h @@ -156,12 +156,12 @@ class AUDACITY_DLL_API LabelTrack final : public Track Track::Holder Cut (double t0, double t1) override; Track::Holder Copy (double t0, double t1, bool forClipboard = true) const override; - bool Clear(double t0, double t1) override; - bool Paste(double t, const Track * src) override; + void Clear(double t0, double t1) override; + void Paste(double t, const Track * src) override; bool Repeat(double t0, double t1, int n); - bool Silence(double t0, double t1) override; - bool InsertSilence(double t, double len) override; + void Silence(double t0, double t1) override; + void InsertSilence(double t, double len) override; int OverGlyph(int x, int y); static wxBitmap & GetGlyph( int i); diff --git a/src/Menus.cpp b/src/Menus.cpp index 9d7a4178d..61e1ff52e 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -4384,7 +4384,11 @@ void AudacityProject::OnPaste() { // Must perform sync-lock adjustment before incrementing n if (n->IsSyncLockSelected()) { - bPastedSomething |= n->SyncLockAdjust(t1, t0+(msClipT1 - msClipT0)); + auto newT1 = t0 + (msClipT1 - msClipT0); + if (t1 != newT1 && t1 <= n->GetEndTime()) { + n->SyncLockAdjust(t1, newT1); + bPastedSomething = true; + } } n = iter.Next(); } @@ -4441,8 +4445,9 @@ void AudacityProject::OnPaste() } else { + bPastedSomething = true; n->Clear(t0, t1); - bPastedSomething |= n->Paste(t0, c); + n->Paste(t0, c); } // When copying from mono to stereo track, paste the wave form @@ -4457,7 +4462,8 @@ void AudacityProject::OnPaste() else { n->Clear(t0, t1); - bPastedSomething |= n->Paste(t0, c); + bPastedSomething = true; + n->Paste(t0, c); } } @@ -4468,7 +4474,11 @@ void AudacityProject::OnPaste() } // if (n->GetSelected()) else if (n->IsSyncLockSelected()) { - bPastedSomething |= n->SyncLockAdjust(t1, t0 + msClipT1 - msClipT0); + auto newT1 = t0 + (msClipT1 - msClipT0); + if (t1 != newT1 && t1 <= n->GetEndTime()) { + n->SyncLockAdjust(t1, newT1); + bPastedSomething = true; + } } n = iter.Next(); @@ -4492,9 +4502,7 @@ void AudacityProject::OnPaste() } else { auto tmp = mTrackFactory->NewWaveTrack( ((WaveTrack*)n)->GetSampleFormat(), ((WaveTrack*)n)->GetRate()); - bool bResult = tmp->InsertSilence(0.0, msClipT1 - msClipT0); // MJS: Is this correct? - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + tmp->InsertSilence(0.0, msClipT1 - msClipT0); // MJS: Is this correct? tmp->Flush(); bPastedSomething |= @@ -4637,9 +4645,7 @@ bool AudacityProject::HandlePasteNothingSelected() } wxASSERT(pClip); - bool bResult = pNewTrack->Paste(0.0, pClip); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + pNewTrack->Paste(0.0, pClip); if (!pFirstNewTrack) pFirstNewTrack = pNewTrack; @@ -4941,7 +4947,7 @@ void AudacityProject::OnCutLabels() if( gPrefs->Read( wxT( "/GUI/EnableCutLines" ), ( long )0 ) ) EditByLabel( &WaveTrack::ClearAndAddCutLine, true ); else - EditByLabel( &WaveTrack::Clear, true ); + EditByLabel( &WaveTrack::Clear1, true ); msClipProject = this; @@ -4995,7 +5001,7 @@ void AudacityProject::OnDeleteLabels() if( mViewInfo.selectedRegion.isPoint() ) return; - EditByLabel( &WaveTrack::Clear, true ); + EditByLabel( &WaveTrack::Clear1, true ); mViewInfo.selectedRegion.collapseToT0(); @@ -5029,7 +5035,7 @@ void AudacityProject::OnSilenceLabels() if( mViewInfo.selectedRegion.isPoint() ) return; - EditByLabel( &WaveTrack::Silence, false ); + EditByLabel( &WaveTrack::Silence1, false ); PushState( /* i18n-hint: (verb)*/ diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 637a614be..746765cd9 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -492,20 +492,19 @@ bool NoteTrack::Trim(double t0, double t1) return true; } -bool NoteTrack::Clear(double t0, double t1) +void NoteTrack::Clear(double t0, double t1) { // If t1 = t0, should Clear return true? if (t1 <= t0) - return false; + // THROW_INCONSISTENCY_EXCEPTION; ? + return; double len = t1-t0; if (mSeq) mSeq->clear(t0 - GetOffset(), len, false); - - return true; } -bool NoteTrack::Paste(double t, const Track *src) +void NoteTrack::Paste(double t, const Track *src) { // Paste inserts src at time t. If src has a positive offset, // the offset is treated as silence which is also inserted. If @@ -517,11 +516,13 @@ bool NoteTrack::Paste(double t, const Track *src) //Check that src is a non-NULL NoteTrack if (src == NULL || src->GetKind() != Track::Note) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; NoteTrack* other = (NoteTrack*)src; if (other->mSeq == NULL) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; if(!mSeq) mSeq = std::make_unique(); @@ -532,20 +533,16 @@ bool NoteTrack::Paste(double t, const Track *src) t += other->GetOffset(); } mSeq->paste(t - GetOffset(), other->mSeq.get()); - - return true; } -bool NoteTrack::Silence(double, double) +void NoteTrack::Silence(double, double) { // to do - return false; } -bool NoteTrack::InsertSilence(double, double) +void NoteTrack::InsertSilence(double, double) { // to do - return false; } // Call this function to manipulate the underlying sequence data. This is diff --git a/src/NoteTrack.h b/src/NoteTrack.h index 3a62c50e0..b6d1e5a2a 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -103,10 +103,10 @@ class AUDACITY_DLL_API NoteTrack final Track::Holder Cut (double t0, double t1) override; Track::Holder Copy (double t0, double t1, bool forClipboard = true) const override; bool Trim (double t0, double t1) /* not override */; - bool Clear(double t0, double t1) override; - bool Paste(double t, const Track *src) override; - bool Silence(double t0, double t1) override; - bool InsertSilence(double t, double len) override; + void Clear(double t0, double t1) override; + void Paste(double t, const Track *src) override; + void Silence(double t0, double t1) override; + void InsertSilence(double t, double len) override; bool Shift(double t) /* not override */; #ifdef EXPERIMENTAL_MIDI_OUT diff --git a/src/Project.cpp b/src/Project.cpp index 0683c5f3c..1290455bb 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -4993,9 +4993,7 @@ void AudacityProject::EditClipboardByLabel( EditDestFunction action ) // right to left. Any placeholder already in merged is kept. // Only the rightmost placeholder is important in the final // result. - bool bResult = merged->Paste( 0.0 , dest.get() ); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + merged->Paste( 0.0 , dest.get() ); } } else // nothing copied but there is a 'region', so the 'region' must be a 'point label' so offset diff --git a/src/TimeTrack.cpp b/src/TimeTrack.cpp index a552a1bce..b48aea123 100644 --- a/src/TimeTrack.cpp +++ b/src/TimeTrack.cpp @@ -120,30 +120,27 @@ Track::Holder TimeTrack::Copy( double t0, double t1, bool ) const return Track::Holder{ std::move( result ) }; } -bool TimeTrack::Clear(double t0, double t1) +void TimeTrack::Clear(double t0, double t1) { mEnvelope->CollapseRegion(t0, t1); - return true; } -bool TimeTrack::Paste(double t, const Track * src) +void TimeTrack::Paste(double t, const Track * src) { if (src->GetKind() != Track::Time) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; mEnvelope->Paste(t, static_cast(src)->mEnvelope.get()); - return true; } -bool TimeTrack::Silence(double t0, double t1) +void TimeTrack::Silence(double t0, double t1) { - return true; } -bool TimeTrack::InsertSilence(double t, double len) +void TimeTrack::InsertSilence(double t, double len) { mEnvelope->InsertSpace(t, len); - return true; } Track::Holder TimeTrack::Duplicate() const diff --git a/src/TimeTrack.h b/src/TimeTrack.h index 16e8743c7..9a6214070 100644 --- a/src/TimeTrack.h +++ b/src/TimeTrack.h @@ -43,10 +43,10 @@ class TimeTrack final : public Track { Holder Cut( double t0, double t1 ) override; Holder Copy( double t0, double t1, bool forClipboard ) const override; - bool Clear(double t0, double t1) override; - bool Paste(double t, const Track * src) override; - bool Silence(double t0, double t1) override; - bool InsertSilence(double t, double len) override; + void Clear(double t0, double t1) override; + void Paste(double t, const Track * src) override; + void Silence(double t0, double t1) override; + void InsertSilence(double t, double len) override; // Identifying the type of track int GetKind() const override { return Time; } diff --git a/src/Track.cpp b/src/Track.cpp index 7b0e5512a..0f6a50f11 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -300,28 +300,22 @@ bool Track::IsSyncLockSelected() const return false; } -bool Track::SyncLockAdjust(double oldT1, double newT1) +void Track::SyncLockAdjust(double oldT1, double newT1) { if (newT1 > oldT1) { // Insert space within the track if (oldT1 > GetEndTime()) - return true; + return; auto tmp = Cut(oldT1, GetEndTime()); - bool ret = Paste(newT1, tmp.get()); - wxASSERT(ret); // TODO: handle this. - - return ret; + Paste(newT1, tmp.get()); } else if (newT1 < oldT1) { // Remove from the track - return Clear(newT1, oldT1); + Clear(newT1, oldT1); } - - // fall-through: no change - return true; } void PlayableTrack::Init( const PlayableTrack &orig ) diff --git a/src/Track.h b/src/Track.h index 334efeb41..77df12fa5 100644 --- a/src/Track.h +++ b/src/Track.h @@ -217,18 +217,16 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler virtual Holder Copy (double WXUNUSED(t0), double WXUNUSED(t1), bool forClipboard = true) const = 0; - // Return true for success - virtual bool Clear(double WXUNUSED(t0), double WXUNUSED(t1)) = 0; + virtual void Clear(double WXUNUSED(t0), double WXUNUSED(t1)) = 0; - // Return true for success - virtual bool Paste(double WXUNUSED(t), const Track * WXUNUSED(src)) = 0; + virtual void Paste(double WXUNUSED(t), const Track * WXUNUSED(src)) = 0; // This can be used to adjust a sync-lock selected track when the selection // is replaced by one of a different length. - virtual bool SyncLockAdjust(double oldT1, double newT1); + virtual void SyncLockAdjust(double oldT1, double newT1); - virtual bool Silence(double WXUNUSED(t0), double WXUNUSED(t1)) = 0; - virtual bool InsertSilence(double WXUNUSED(t), double WXUNUSED(len)) = 0; + virtual void Silence(double WXUNUSED(t0), double WXUNUSED(t1)) = 0; + virtual void InsertSilence(double WXUNUSED(t), double WXUNUSED(len)) = 0; virtual int GetKind() const { return None; } diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 040c14ca8..b5d864aab 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -537,9 +537,7 @@ Track::Holder WaveTrack::Cut(double t0, double t1) auto tmp = Copy(t0, t1); - if (!Clear(t0, t1)) - // THROW_INCONSISTENCY_EXCEPTION - ; + Clear(t0, t1); return tmp; } @@ -617,10 +615,7 @@ bool WaveTrack::Trim (double t0, double t1) //if inside0 is false, then the left selector was between //clips, so DELETE everything to its left. if(false == inside1) - { - if (!Clear(t1,GetEndTime())) - return false; - } + Clear(t1,GetEndTime()); if(false == inside0) { @@ -713,9 +708,9 @@ Track::Holder WaveTrack::CopyNonconst(double t0, double t1) return Copy(t0, t1); } -bool WaveTrack::Clear(double t0, double t1) +void WaveTrack::Clear(double t0, double t1) { - return HandleClear(t0, t1, false, false); + HandleClear(t0, t1, false, false); } bool WaveTrack::ClearAndAddCutLine(double t0, double t1) @@ -812,7 +807,8 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear // If duration is 0, then it's just a plain paste if (dur == 0.0) { - return Paste(t0, src); + Paste(t0, src); + return true; } // If provided time warper was NULL, use a default one that does nothing @@ -867,7 +863,8 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear if (HandleClear(t0, t1, false, false)) { // And paste in the NEW data - if (Paste(t0, src)) { + Paste(t0, src); + { // First, merge the NEW clip(s) in with the existing clips if (merge && splits.GetCount() > 0) { @@ -1147,7 +1144,7 @@ bool WaveTrack::HandleClear(double t0, double t1, return true; } -bool WaveTrack::SyncLockAdjust(double oldT1, double newT1) +void WaveTrack::SyncLockAdjust(double oldT1, double newT1) { if (newT1 > oldT1) { // Insert space within the track @@ -1156,62 +1153,57 @@ bool WaveTrack::SyncLockAdjust(double oldT1, double newT1) // GetEndTime() looks through the clips and may give us EXACTLY the same // value as T1, when T1 was set to be at the end of one of those clips. if (oldT1 >= GetEndTime()) - return true; + return; // If track is empty at oldT1 insert whitespace; otherwise, silence if (IsEmpty(oldT1, oldT1)) { - bool ret = true; - // Check if clips can move bool clipsCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &clipsCanMove); if (clipsCanMove) { auto tmp = Cut (oldT1, GetEndTime() + 1.0/GetRate()); - ret = Paste(newT1, tmp.get()); - wxASSERT(ret); + Paste(newT1, tmp.get()); } - - return ret; + return; } else { // AWD: Could just use InsertSilence() on its own here, but it doesn't // follow EditClipCanMove rules (Paste() does it right) AudacityProject *p = GetActiveProject(); - if (!p) return false; + if (!p) + // THROW_INCONSISTENCY_EXCEPTION + ; TrackFactory *f = p->GetTrackFactory(); - if (!f) return false; + if (!f) + // THROW_INCONSISTENCY_EXCEPTION + ; auto tmp = f->NewWaveTrack(GetSampleFormat(), GetRate()); - bool bResult = tmp->InsertSilence(0.0, newT1 - oldT1); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + tmp->InsertSilence(0.0, newT1 - oldT1); tmp->Flush(); - bResult = Paste(oldT1, tmp.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + Paste(oldT1, tmp.get()); } } else if (newT1 < oldT1) { - return Clear(newT1, oldT1); + Clear(newT1, oldT1); } - - // fall-through: no change - return true; } -bool WaveTrack::Paste(double t0, const Track *src) +void WaveTrack::Paste(double t0, const Track *src) // WEAK-GUARANTEE { bool editClipCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove); if( src == NULL ) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; if (src->GetKind() != Track::Wave) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; const WaveTrack* other = static_cast(src); @@ -1237,7 +1229,7 @@ bool WaveTrack::Paste(double t0, const Track *src) // if (other->GetNumClips() == 0) - return false; + return; //printf("paste: we have at least one clip\n"); @@ -1254,9 +1246,7 @@ bool WaveTrack::Paste(double t0, const Track *src) // move everything to the right, then try to paste again if (!IsEmpty(t0, GetEndTime())) { auto tmp = Cut(t0, GetEndTime()+1.0/mRate); - bool bResult = Paste(t0 + insertDuration, tmp.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + Paste(t0 + insertDuration, tmp.get()); } } else { @@ -1351,13 +1341,13 @@ bool WaveTrack::Paste(double t0, const Track *src) mClips.push_back(std::move(newClip)); // transfer ownership } } - return true; } -bool WaveTrack::Silence(double t0, double t1) +void WaveTrack::Silence(double t0, double t1) { if (t1 < t0) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; auto start = (sampleCount)floor(t0 * mRate + 0.5); auto len = (sampleCount)floor(t1 * mRate + 0.5) - start; @@ -1386,25 +1376,25 @@ bool WaveTrack::Silence(double t0, double t1) if (!clip->GetSequence()->SetSilence(inclipDelta, samplesToCopy)) { wxASSERT(false); // should always work - return false; + return; } clip->MarkChanged(); } } - - return result; } -bool WaveTrack::InsertSilence(double t, double len) +void WaveTrack::InsertSilence(double t, double len) { if (len <= 0) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; if (mClips.empty()) { // Special case if there is no clip yet WaveClip* clip = CreateClip(); - return clip->InsertSilence(0, len); + clip->InsertSilence(0, len); + return; } for (const auto &clip : mClips) @@ -1414,12 +1404,10 @@ bool WaveTrack::InsertSilence(double t, double len) else if (clip->WithinClip(t)) { if (!clip->InsertSilence(t, len)) { - return false; + return; } } } - - return true; } //Performs the opposite of Join diff --git a/src/WaveTrack.h b/src/WaveTrack.h index 50e922b2d..c7b8f876d 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -175,16 +175,18 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { Track::Holder Copy(double t0, double t1, bool forClipboard = true) const override; Track::Holder CopyNonconst(double t0, double t1) /* not override */; - bool Clear(double t0, double t1) override; - bool Paste(double t0, const Track *src) override; + void Clear(double t0, double t1) override; + bool Clear1(double t0, double t1) { Clear(t0, t1); return true; } + void Paste(double t0, const Track *src) override; bool ClearAndPaste(double t0, double t1, const Track *src, bool preserve = true, bool merge = true, const TimeWarper *effectWarper = NULL) /* not override */; - bool Silence(double t0, double t1) override; - bool InsertSilence(double t, double len) override; + void Silence(double t0, double t1) override; + bool Silence1(double t0, double t1) { Silence(t0, t1); return true; } + void InsertSilence(double t, double len) override; bool SplitAt(double t) /* not override */; bool Split(double t0, double t1) /* not override */; @@ -200,7 +202,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { bool HandleClear(double t0, double t1, bool addCutLines, bool split); - bool SyncLockAdjust(double oldT1, double newT1) override; + void SyncLockAdjust(double oldT1, double newT1) override; /** @brief Returns true if there are no WaveClips in the specified region * diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index 5b3cb9ec7..7257a99e7 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -1968,8 +1968,7 @@ void Effect::GetSamples( t1 = t0 + mDuration; if (mT0 == mT1) { // Not really part of the calculation, but convenient to put here - bool bResult = track->InsertSilence(t0, t1); - wxASSERT(bResult); // TO DO: Actually handle this. + track->InsertSilence(t0, t1); } } #endif diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index 6adc84ebf..97d4fb631 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -1174,9 +1174,7 @@ bool EffectEqualization::ProcessOne(int count, WaveTrack * t, t->Clear(clipStartEndTimes[i].first,clipStartEndTimes[i].second); auto toClipOutput = output->Copy(clipStartEndTimes[i].first-startT+offsetT0,clipStartEndTimes[i].second-startT+offsetT0); //put the processed audio in - bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + t->Paste(clipStartEndTimes[i].first, toClipOutput.get()); //if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this //This is not true when the selection is fully contained within one clip (second half of conditional) if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || diff --git a/src/effects/Equalization48x.cpp b/src/effects/Equalization48x.cpp index 6e5ced834..028d188da 100644 --- a/src/effects/Equalization48x.cpp +++ b/src/effects/Equalization48x.cpp @@ -559,8 +559,7 @@ bool EffectEqualization48x::ProcessTail(WaveTrack * t, WaveTrack * output, sampl // output->Copy(clipStartEndTimes[i].first-startT+offsetT0,clipStartEndTimes[i].second-startT+offsetT0, &toClipOutput); auto toClipOutput = output->Copy(clipStartEndTimes[i].first-startT, clipStartEndTimes[i].second-startT); //put the processed audio in - bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get()); - wxASSERT(bResult); // TO DO: Actually handle this. + t->Paste(clipStartEndTimes[i].first, toClipOutput.get()); //if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this //This is not true when the selection is fully contained within one clip (second half of conditional) if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || diff --git a/src/effects/Paulstretch.cpp b/src/effects/Paulstretch.cpp index fda0397b4..72b4f66b8 100644 --- a/src/effects/Paulstretch.cpp +++ b/src/effects/Paulstretch.cpp @@ -378,11 +378,11 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun } } - outputTrack->Flush(); + if (!cancelled){ + outputTrack->Flush(); - track->Clear(t0,t1); - bool success = track->Paste(t0, outputTrack.get()); - if (!cancelled && success){ + track->Clear(t0,t1); + track->Paste(t0, outputTrack.get()); m_t1 = mT0 + outputTrack->GetEndTime(); } diff --git a/src/effects/Repeat.cpp b/src/effects/Repeat.cpp index cbeeddbd5..e436cc5e3 100644 --- a/src/effects/Repeat.cpp +++ b/src/effects/Repeat.cpp @@ -139,12 +139,12 @@ bool EffectRepeat::Process() auto dest = track->Copy(mT0, mT1); for(int j=0; jPaste(tc, dest.get()) || - TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. + if (TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. { bGoodResult = false; break; } + track->Paste(tc, dest.get()); tc += tLen; } if (tc > maxDestLen) diff --git a/src/effects/Silence.cpp b/src/effects/Silence.cpp index 1085db9d2..16ca05507 100644 --- a/src/effects/Silence.cpp +++ b/src/effects/Silence.cpp @@ -97,7 +97,6 @@ bool EffectSilence::GenerateTrack(WaveTrack *tmp, const WaveTrack & WXUNUSED(track), int WXUNUSED(ntrack)) { - bool bResult = tmp->InsertSilence(0.0, GetDuration()); - wxASSERT(bResult); - return bResult; + tmp->InsertSilence(0.0, GetDuration()); + return true; } diff --git a/src/effects/StereoToMono.cpp b/src/effects/StereoToMono.cpp index f4721f067..35cd7e2a7 100644 --- a/src/effects/StereoToMono.cpp +++ b/src/effects/StereoToMono.cpp @@ -163,9 +163,9 @@ bool EffectStereoToMono::ProcessOne(int count) } double minStart = wxMin(mLeftTrack->GetStartTime(), mRightTrack->GetStartTime()); - bResult &= mLeftTrack->Clear(mLeftTrack->GetStartTime(), mLeftTrack->GetEndTime()); + mLeftTrack->Clear(mLeftTrack->GetStartTime(), mLeftTrack->GetEndTime()); bResult &= mOutTrack->Flush(); - bResult &= mLeftTrack->Paste(minStart, mOutTrack.get()); + mLeftTrack->Paste(minStart, mOutTrack.get()); mLeftTrack->SetLinked(false); mRightTrack->SetLinked(false); mLeftTrack->SetChannel(Track::MonoChannel); diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 6fc4b24c6..5e3442241 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -1003,9 +1003,7 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) newTrack->InsertSilence(0.0, t0 - t1); newTrack->Flush(); wt->Clear(t1, t0); - bool bResult = wt->Paste(t1, newTrack.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + wt->Paste(t1, newTrack.get()); } recordingTracks.push_back(wt); // Don't record more channels than configured recording pref. From 0d7250578d884f3ed9fdd63eb46dd4604c646cfb Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 22 Mar 2017 13:25:55 -0400 Subject: [PATCH 87/91] Other methods of WaveTrack return void, will throw on failure instead --- src/Menus.cpp | 24 +++--- src/Project.h | 2 +- src/TrackPanel.cpp | 31 ++----- src/WaveTrack.cpp | 140 ++++++++++++-------------------- src/WaveTrack.h | 38 ++++----- src/effects/ChangeSpeed.cpp | 2 +- src/effects/Generator.cpp | 2 +- src/effects/NoiseReduction.cpp | 4 +- src/effects/NoiseRemoval.cpp | 3 +- src/effects/SBSMSEffect.cpp | 7 -- src/effects/StereoToMono.cpp | 4 +- src/effects/nyquist/Nyquist.cpp | 6 +- 12 files changed, 98 insertions(+), 165 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 61e1ff52e..18c4bf000 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -4428,8 +4428,8 @@ void AudacityProject::OnPaste() wxASSERT( n && c ); if (c->GetKind() == Track::Wave && n->GetKind() == Track::Wave) { - bPastedSomething |= - ((WaveTrack*)n)->ClearAndPaste(t0, t1, (WaveTrack*)c, true, true); + bPastedSomething = true; + ((WaveTrack*)n)->ClearAndPaste(t0, t1, (WaveTrack*)c, true, true); } else if (c->GetKind() == Track::Label && n->GetKind() == Track::Label) @@ -4457,7 +4457,8 @@ void AudacityProject::OnPaste() n = iter.Next(); if (n->GetKind() == Track::Wave) { - bPastedSomething |= ((WaveTrack *)n)->ClearAndPaste(t0, t1, c, true, true); + bPastedSomething = true; + ((WaveTrack *)n)->ClearAndPaste(t0, t1, c, true, true); } else { @@ -4497,16 +4498,16 @@ void AudacityProject::OnPaste() if (n->GetSelected() && n->GetKind()==Track::Wave) { if (c) { wxASSERT(c->GetKind() == Track::Wave); - bPastedSomething |= - ((WaveTrack *)n)->ClearAndPaste(t0, t1, (WaveTrack *)c, true, true); + bPastedSomething = true; + ((WaveTrack *)n)->ClearAndPaste(t0, t1, (WaveTrack *)c, true, true); } else { auto tmp = mTrackFactory->NewWaveTrack( ((WaveTrack*)n)->GetSampleFormat(), ((WaveTrack*)n)->GetRate()); tmp->InsertSilence(0.0, msClipT1 - msClipT0); // MJS: Is this correct? tmp->Flush(); - bPastedSomething |= - ((WaveTrack *)n)->ClearAndPaste(t0, t1, tmp.get(), true, true); + bPastedSomething = true; + ((WaveTrack *)n)->ClearAndPaste(t0, t1, tmp.get(), true, true); } } else if (n->GetKind() == Track::Label && n->GetSelected()) @@ -4947,7 +4948,7 @@ void AudacityProject::OnCutLabels() if( gPrefs->Read( wxT( "/GUI/EnableCutLines" ), ( long )0 ) ) EditByLabel( &WaveTrack::ClearAndAddCutLine, true ); else - EditByLabel( &WaveTrack::Clear1, true ); + EditByLabel( &WaveTrack::Clear, true ); msClipProject = this; @@ -5001,7 +5002,7 @@ void AudacityProject::OnDeleteLabels() if( mViewInfo.selectedRegion.isPoint() ) return; - EditByLabel( &WaveTrack::Clear1, true ); + EditByLabel( &WaveTrack::Clear, true ); mViewInfo.selectedRegion.collapseToT0(); @@ -5035,7 +5036,7 @@ void AudacityProject::OnSilenceLabels() if( mViewInfo.selectedRegion.isPoint() ) return; - EditByLabel( &WaveTrack::Silence1, false ); + EditByLabel( &WaveTrack::Silence, false ); PushState( /* i18n-hint: (verb)*/ @@ -7237,8 +7238,7 @@ void AudacityProject::OnResample() // But the thrown exception will cause rollback in the application // level handler. - if (!((WaveTrack*)t)->Resample(newRate, &progress)) - break; + ((WaveTrack*)t)->Resample(newRate, &progress); // Each time a track is successfully, completely resampled, // commit that to the undo stack. The second and later times, diff --git a/src/Project.h b/src/Project.h index 971c92006..0c6c88b44 100644 --- a/src/Project.h +++ b/src/Project.h @@ -382,7 +382,7 @@ public: void SkipEnd(bool shift); - typedef bool (WaveTrack::* EditFunction)(double, double); + typedef void (WaveTrack::* EditFunction)(double, double); typedef std::unique_ptr (WaveTrack::* EditDestFunction)(double, double); void EditByLabel(EditFunction action, bool bSyncLockedTracks); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 14a71406e..8ccc83a28 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -6283,25 +6283,14 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, const wxRect & // When user presses left button on cut line, expand the line again double cutlineStart = 0, cutlineEnd = 0; - if (track->ExpandCutLine(mCapturedTrackLocation.pos, &cutlineStart, &cutlineEnd)) + track->ExpandCutLine(mCapturedTrackLocation.pos, &cutlineStart, &cutlineEnd); { // Assume linked track is wave or null const auto linked = static_cast(track->GetLink()); - if (linked) { + if (linked) // Expand the cutline in the opposite channel if it is present. - - // PRL: Do NOT report that the event is not handled if the other - // channel doesn't also have a cutline to expand at the same time. - // Just ignore the return. Bug1310. - - /* bool success = */ - linked->ExpandCutLine(mCapturedTrackLocation.pos); - /* - if (!success) - return false; - */ - } + linked->ExpandCutLine(mCapturedTrackLocation.pos); mViewInfo->selectedRegion.setTimes(cutlineStart, cutlineEnd); DisplaySelection(); @@ -6311,8 +6300,7 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, const wxRect & } else if (mCapturedTrackLocation.typ == WaveTrackLocation::locationMergePoint) { const double pos = mCapturedTrackLocation.pos; - if (!track->MergeClips(mCapturedTrackLocation.clipidx1, mCapturedTrackLocation.clipidx2)) - return false; + track->MergeClips(mCapturedTrackLocation.clipidx1, mCapturedTrackLocation.clipidx2); // Assume linked track is wave or null const auto linked = @@ -6322,8 +6310,7 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, const wxRect & int idx = FindMergeLine(linked, pos); if (idx >= 0) { WaveTrack::Location location = linked->GetCachedLocations()[idx]; - if (!linked->MergeClips(location.clipidx1, location.clipidx2)) - return false; + linked->MergeClips(location.clipidx1, location.clipidx2); } } @@ -8338,16 +8325,12 @@ void TrackPanel::OnFormatChange(wxCommandEvent & event) if (newFormat == ((WaveTrack*)mPopupMenuTarget)->GetSampleFormat()) return; // Nothing to do. - bool bResult = ((WaveTrack*)mPopupMenuTarget)->ConvertToSampleFormat(newFormat); - wxASSERT(bResult); // TO DO: Actually handle this. + ((WaveTrack*)mPopupMenuTarget)->ConvertToSampleFormat(newFormat); // Assume linked track is wave or null const auto partner = static_cast(mPopupMenuTarget->GetLink()); if (partner) - { - bResult = partner->ConvertToSampleFormat(newFormat); - wxASSERT(bResult); // TO DO: Actually handle this. - } + partner->ConvertToSampleFormat(newFormat); MakeParentPushState(wxString::Format(_("Changed '%s' to %s"), mPopupMenuTarget->GetName(). diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index b5d864aab..b803273b9 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -501,13 +501,13 @@ float WaveTrack::GetChannelGain(int channel) const return right*mGain; } -bool WaveTrack::ConvertToSampleFormat(sampleFormat format) +void WaveTrack::ConvertToSampleFormat(sampleFormat format) +// WEAK-GUARANTEE +// might complete on only some tracks { for (const auto &clip : mClips) clip->ConvertToSampleFormat(format); mFormat = format; - - return true; } bool WaveTrack::IsEmpty(double t0, double t1) const @@ -551,9 +551,7 @@ Track::Holder WaveTrack::SplitCut(double t0, double t1) // SplitCut is the same as 'Copy', then 'SplitDelete' auto tmp = Copy(t0, t1); - if (!SplitDelete(t0, t1)) - //THROW_INCONSISTENCY_EXCEPTION - ; + SplitDelete(t0, t1); return tmp; } @@ -580,7 +578,7 @@ Track::Holder WaveTrack::CutAndAddCutLine(double t0, double t1) //Trim trims within a clip, rather than trimming everything. //If a bound is outside a clip, it trims everything. -bool WaveTrack::Trim (double t0, double t1) +void WaveTrack::Trim (double t0, double t1) { bool inside0 = false; bool inside1 = false; @@ -599,14 +597,14 @@ bool WaveTrack::Trim (double t0, double t1) if(t1 > clip->GetStartTime() && t1 < clip->GetEndTime()) { if (!clip->Clear(t1,clip->GetEndTime())) - return false; + return; inside1 = true; } if(t0 > clip->GetStartTime() && t0 < clip->GetEndTime()) { if (!clip->Clear(clip->GetStartTime(),t0)) - return false; + return; clip->SetOffset(t0); inside0 = true; } @@ -618,12 +616,7 @@ bool WaveTrack::Trim (double t0, double t1) Clear(t1,GetEndTime()); if(false == inside0) - { - if (!SplitDelete(0,t0)) - return false; - } - - return true; + SplitDelete(0,t0); } @@ -713,9 +706,9 @@ void WaveTrack::Clear(double t0, double t1) HandleClear(t0, t1, false, false); } -bool WaveTrack::ClearAndAddCutLine(double t0, double t1) +void WaveTrack::ClearAndAddCutLine(double t0, double t1) { - return HandleClear(t0, t1, true, false); + HandleClear(t0, t1, true, false); } const SpectrogramSettings &WaveTrack::GetSpectrogramSettings() const @@ -793,7 +786,7 @@ void WaveTrack::SetWaveformSettings(std::unique_ptr &&pSetting // be pasted with visible split lines. Normally, effects do not // want these extra lines, so they may be merged out. // -bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear +void WaveTrack::ClearAndPaste(double t0, // Start of time to clear double t1, // End of time to clear const Track *src, // What to paste bool preserve, // Whether to reinsert splits/cuts @@ -808,7 +801,7 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear // If duration is 0, then it's just a plain paste if (dur == 0.0) { Paste(t0, src); - return true; + return; } // If provided time warper was NULL, use a default one that does nothing @@ -860,7 +853,8 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear const auto tolerance = 2.0 / GetRate(); // Now, clear the selection - if (HandleClear(t0, t1, false, false)) { + HandleClear(t0, t1, false, false); + { // And paste in the NEW data Paste(t0, src); @@ -882,11 +876,8 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear // Merge this clip and the previous clip if the end time // falls within it and this isn't the first clip in the track. if (fabs(t1 - clip->GetStartTime()) < tolerance) { - if (prev) { - bool bResult = MergeClips(GetClipIndex(prev), GetClipIndex(clip)); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); - } + if (prev) + MergeClips(GetClipIndex(prev), GetClipIndex(clip)); break; } prev = clip; @@ -902,9 +893,7 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear WaveClip *prev = nullptr; for (const auto clip : clips) { if (prev) { - bool bResult = MergeClips(GetClipIndex(prev), GetClipIndex(clip)); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + MergeClips(GetClipIndex(prev), GetClipIndex(clip)); break; } if (fabs(t0 - clip->GetEndTime()) < tolerance) @@ -952,15 +941,13 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear } } } - - return true; } -bool WaveTrack::SplitDelete(double t0, double t1) +void WaveTrack::SplitDelete(double t0, double t1) { bool addCutLines = false; bool split = true; - return HandleClear(t0, t1, addCutLines, split); + HandleClear(t0, t1, addCutLines, split); } namespace @@ -1018,11 +1005,12 @@ void WaveTrack::AddClip(movable_ptr &&clip) mClips.push_back(std::move(clip)); // transfer ownership } -bool WaveTrack::HandleClear(double t0, double t1, +void WaveTrack::HandleClear(double t0, double t1, bool addCutLines, bool split) { if (t1 < t0) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; bool editClipCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove); @@ -1057,8 +1045,7 @@ bool WaveTrack::HandleClear(double t0, double t1, // Clip data is affected by command if (addCutLines) { - if (!clip->ClearAndAddCutLine(t0,t1)) - return false; + clip->ClearAndAddCutLine(t0,t1); } else { @@ -1140,8 +1127,6 @@ bool WaveTrack::HandleClear(double t0, double t1, for (auto &clip: clipsToAdd) mClips.push_back(std::move(clip)); // transfer ownership - - return true; } void WaveTrack::SyncLockAdjust(double oldT1, double newT1) @@ -1412,7 +1397,7 @@ void WaveTrack::InsertSilence(double t, double len) //Performs the opposite of Join //Analyses selected region for possible Joined clips and disjoins them -bool WaveTrack::Disjoin(double t0, double t1) +void WaveTrack::Disjoin(double t0, double t1) { auto minSamples = TimeToLongSamples( WAVETRACK_MERGE_POINT_TOLERANCE ); const size_t maxAtOnce = 1048576; @@ -1487,11 +1472,9 @@ bool WaveTrack::Disjoin(double t0, double t1) const Region ®ion = regions.at(i); SplitDelete(region.start, region.end ); } - - return true; } -bool WaveTrack::Join(double t0, double t1) +void WaveTrack::Join(double t0, double t1) { // Merge all WaveClips overlapping selection into one @@ -1515,7 +1498,7 @@ bool WaveTrack::Join(double t0, double t1) //if there are no clips to DELETE, nothing to do if( clipsToDelete.size() == 0 ) - return true; + return; newClip = CreateClip(); double t = clipsToDelete[0]->GetOffset(); @@ -1528,9 +1511,7 @@ bool WaveTrack::Join(double t0, double t1) if (clip->GetOffset() - t > (1.0 / mRate)) { double addedSilence = (clip->GetOffset() - t); //printf("Adding %.6f seconds of silence\n"); - bool bResult = newClip->InsertSilence(t, addedSilence); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + newClip->InsertSilence(t, addedSilence); t += addedSilence; } @@ -1543,29 +1524,26 @@ bool WaveTrack::Join(double t0, double t1) auto it = FindClip(mClips, clip); mClips.erase(it); // deletes the clip } - - return true; } -bool WaveTrack::Append(samplePtr buffer, sampleFormat format, +void WaveTrack::Append(samplePtr buffer, sampleFormat format, size_t len, unsigned int stride /* = 1 */, XMLWriter *blockFileLog /* = NULL */) { - return RightmostOrNewClip()->Append(buffer, format, len, stride, + RightmostOrNewClip()->Append(buffer, format, len, stride, blockFileLog); } -bool WaveTrack::AppendAlias(const wxString &fName, sampleCount start, +void WaveTrack::AppendAlias(const wxString &fName, sampleCount start, size_t len, int channel,bool useOD) { - return RightmostOrNewClip()->AppendAlias(fName, start, len, channel, useOD); + RightmostOrNewClip()->AppendAlias(fName, start, len, channel, useOD); } - -bool WaveTrack::AppendCoded(const wxString &fName, sampleCount start, +void WaveTrack::AppendCoded(const wxString &fName, sampleCount start, size_t len, int channel, int decodeType) { - return RightmostOrNewClip()->AppendCoded(fName, start, len, channel, decodeType); + RightmostOrNewClip()->AppendCoded(fName, start, len, channel, decodeType); } ///gets an int with OD flags so that we can determine which ODTasks should be run on this track after save/open, etc. @@ -1636,10 +1614,10 @@ size_t WaveTrack::GetIdealBlockSize() return NewestOrNewClip()->GetSequence()->GetIdealBlockSize(); } -bool WaveTrack::Flush() +void WaveTrack::Flush() { // After appending, presumably. Do this to the clip that gets appended. - return RightmostOrNewClip()->Flush(); + RightmostOrNewClip()->Flush(); } bool WaveTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs) @@ -2039,11 +2017,9 @@ bool WaveTrack::Get(samplePtr buffer, sampleFormat format, return result; } -bool WaveTrack::Set(samplePtr buffer, sampleFormat format, +void WaveTrack::Set(samplePtr buffer, sampleFormat format, sampleCount start, size_t len) { - bool result = true; - for (const auto &clip: mClips) { auto clipStart = clip->GetStartSample(); @@ -2080,13 +2056,11 @@ bool WaveTrack::Set(samplePtr buffer, sampleFormat format, format, inclipDelta, samplesToCopy.as_size_t() )) { wxASSERT(false); // should always work - return false; + return; } clip->MarkChanged(); } } - - return result; } void WaveTrack::GetEnvelopeValues(double *buffer, size_t bufferLen, @@ -2321,15 +2295,14 @@ bool WaveTrack::CanInsertClip(WaveClip* clip) return true; } -bool WaveTrack::Split( double t0, double t1 ) +void WaveTrack::Split( double t0, double t1 ) { - bool ret = SplitAt( t0 ); - if( ret && t0 != t1 ) - ret = SplitAt( t1 ); - return ret; + SplitAt( t0 ); + if( t0 != t1 ) + SplitAt( t1 ); } -bool WaveTrack::SplitAt(double t) +void WaveTrack::SplitAt(double t) { for (const auto &c : mClips) { @@ -2346,11 +2319,11 @@ bool WaveTrack::SplitAt(double t) auto newClip = make_movable( *c, mDirManager, true ); if (!c->Clear(t, c->GetEndTime())) { - return false; + return; } if (!newClip->Clear(c->GetStartTime(), t)) { - return false; + return; } //offset the NEW clip by the splitpoint (noting that it is already offset to c->GetStartTime()) @@ -2359,11 +2332,8 @@ bool WaveTrack::SplitAt(double t) // This could invalidate the iterators for the loop! But we return // at once so it's okay mClips.push_back(std::move(newClip)); // transfer ownership - return true; } } - - return true; } void WaveTrack::UpdateLocationsCache() const @@ -2433,7 +2403,7 @@ void WaveTrack::UpdateLocationsCache() const } // Expand cut line (that is, re-insert audio, then DELETE audio saved in cut line) -bool WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart, +void WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart, double* cutlineEnd) // STRONG-GUARANTEE { @@ -2465,7 +2435,7 @@ bool WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart, } if (!clip->ExpandCutLine(cutLinePosition)) - return false; + return; // STRONG-GUARANTEE provided that the following gives NOFAIL-GUARANTEE @@ -2482,12 +2452,8 @@ bool WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart, if (clip2->GetStartTime() > clip->GetStartTime()) clip2->Offset(end - start); } - - return true; } } - - return false; } bool WaveTrack::RemoveCutLine(double cutLinePosition) @@ -2499,26 +2465,26 @@ bool WaveTrack::RemoveCutLine(double cutLinePosition) return false; } -bool WaveTrack::MergeClips(int clipidx1, int clipidx2) +void WaveTrack::MergeClips(int clipidx1, int clipidx2) { WaveClip* clip1 = GetClipByIndex(clipidx1); WaveClip* clip2 = GetClipByIndex(clipidx2); if (!clip1 || !clip2) // Could happen if one track of a linked pair had a split and the other didn't. - return false; + return; // Don't throw, just do nothing. // Append data from second clip to first clip if (!clip1->Paste(clip1->GetEndTime(), clip2)) - return false; + return; // Delete second clip auto it = FindClip(mClips, clip2); mClips.erase(it); - - return true; } -bool WaveTrack::Resample(int rate, ProgressDialog *progress) +void WaveTrack::Resample(int rate, ProgressDialog *progress) +// WEAK-GUARANTEE +// Partial completion may leave clips at differing sample rates! { for (const auto &clip : mClips) if (!clip->Resample(rate, progress)) @@ -2530,8 +2496,6 @@ bool WaveTrack::Resample(int rate, ProgressDialog *progress) } mRate = rate; - - return true; } namespace { diff --git a/src/WaveTrack.h b/src/WaveTrack.h index c7b8f876d..5aa22d967 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -150,7 +150,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { void SetVirtualState(bool state, bool half=false); #endif sampleFormat GetSampleFormat() const { return mFormat; } - bool ConvertToSampleFormat(sampleFormat format); + void ConvertToSampleFormat(sampleFormat format); const SpectrogramSettings &GetSpectrogramSettings() const; SpectrogramSettings &GetSpectrogramSettings(); @@ -176,31 +176,29 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { Track::Holder CopyNonconst(double t0, double t1) /* not override */; void Clear(double t0, double t1) override; - bool Clear1(double t0, double t1) { Clear(t0, t1); return true; } void Paste(double t0, const Track *src) override; - bool ClearAndPaste(double t0, double t1, + void ClearAndPaste(double t0, double t1, const Track *src, bool preserve = true, bool merge = true, const TimeWarper *effectWarper = NULL) /* not override */; void Silence(double t0, double t1) override; - bool Silence1(double t0, double t1) { Silence(t0, t1); return true; } void InsertSilence(double t, double len) override; - bool SplitAt(double t) /* not override */; - bool Split(double t0, double t1) /* not override */; + void SplitAt(double t) /* not override */; + void Split(double t0, double t1) /* not override */; // Track::Holder CutAndAddCutLine(double t0, double t1) /* not override */; - bool ClearAndAddCutLine(double t0, double t1) /* not override */; + void ClearAndAddCutLine(double t0, double t1) /* not override */; Track::Holder SplitCut(double t0, double t1) /* not override */; - bool SplitDelete(double t0, double t1) /* not override */; - bool Join(double t0, double t1) /* not override */; - bool Disjoin(double t0, double t1) /* not override */; + void SplitDelete(double t0, double t1) /* not override */; + void Join(double t0, double t1) /* not override */; + void Disjoin(double t0, double t1) /* not override */; - bool Trim(double t0, double t1) /* not override */; + void Trim(double t0, double t1) /* not override */; - bool HandleClear(double t0, double t1, bool addCutLines, bool split); + void HandleClear(double t0, double t1, bool addCutLines, bool split); void SyncLockAdjust(double oldT1, double newT1) override; @@ -218,20 +216,20 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { * appended to that clip. If there are no WaveClips in the track, then a NEW * one is created. */ - bool Append(samplePtr buffer, sampleFormat format, + void Append(samplePtr buffer, sampleFormat format, size_t len, unsigned int stride=1, XMLWriter* blockFileLog=NULL); /// Flush must be called after last Append - bool Flush(); + void Flush(); - bool AppendAlias(const wxString &fName, sampleCount start, + void AppendAlias(const wxString &fName, sampleCount start, size_t len, int channel,bool useOD); ///for use with On-Demand decoding of compressed files. ///decodeType should be an enum from ODDecodeTask that specifies what ///Type of encoded file this is, such as eODFLAC //vvv Why not use the ODTypeEnum typedef to enforce that for the parameter? - bool AppendCoded(const wxString &fName, sampleCount start, + void AppendCoded(const wxString &fName, sampleCount start, size_t len, int channel, int decodeType); ///gets an int with OD flags so that we can determine which ODTasks should be run on this track after save/open, etc. @@ -256,7 +254,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { bool Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, fillFormat fill = fillZero, bool mayThrow = true) const; - bool Set(samplePtr buffer, sampleFormat format, + void Set(samplePtr buffer, sampleFormat format, sampleCount start, size_t len); void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0) const; @@ -488,7 +486,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { // Merge two clips, that is append data from clip2 to clip1, // then remove clip2 from track. // clipidx1 and clipidx2 are indices into the clip list. - bool MergeClips(int clipidx1, int clipidx2); + void MergeClips(int clipidx1, int clipidx2); // Cache special locations (e.g. cut lines) for later speedy access void UpdateLocationsCache() const; @@ -497,7 +495,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { const std::vector &GetCachedLocations() const { return mDisplayLocationsCache; } // Expand cut line (that is, re-insert audio, then DELETE audio saved in cut line) - bool ExpandCutLine(double cutLinePosition, double* cutlineStart = NULL, double* cutlineEnd = NULL); + void ExpandCutLine(double cutLinePosition, double* cutlineStart = NULL, double* cutlineEnd = NULL); // Remove cut line, without expanding the audio in it bool RemoveCutLine(double cutLinePosition); @@ -507,7 +505,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { void Merge(const Track &orig) override; // Resample track (i.e. all clips in the track) - bool Resample(int rate, ProgressDialog *progress = NULL); + void Resample(int rate, ProgressDialog *progress = NULL); // // AutoSave related diff --git a/src/effects/ChangeSpeed.cpp b/src/effects/ChangeSpeed.cpp index 17fb84cfe..d764bbce4 100644 --- a/src/effects/ChangeSpeed.cpp +++ b/src/effects/ChangeSpeed.cpp @@ -539,7 +539,7 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track, if (bResult) { LinearTimeWarper warper { mCurT0, mCurT0, mCurT1, mCurT0 + newLength }; - bResult = track->ClearAndPaste( + track->ClearAndPaste( mCurT0, mCurT1, outputTrack.get(), true, false, &warper); } diff --git a/src/effects/Generator.cpp b/src/effects/Generator.cpp index c366aed1e..48c025a2a 100644 --- a/src/effects/Generator.cpp +++ b/src/effects/Generator.cpp @@ -80,7 +80,7 @@ bool Generator::Process() tmp->Flush(); StepTimeWarper warper{ mT0+GetDuration(), GetDuration()-(mT1-mT0) }; - bGoodResult = track->ClearAndPaste( + track->ClearAndPaste( p->GetSel0(), p->GetSel1(), &*tmp, true, false, &warper); } diff --git a/src/effects/NoiseReduction.cpp b/src/effects/NoiseReduction.cpp index 647879780..01192b3be 100644 --- a/src/effects/NoiseReduction.cpp +++ b/src/effects/NoiseReduction.cpp @@ -1333,9 +1333,7 @@ bool EffectNoiseReduction::Worker::ProcessOne double tLen = outputTrack->LongSamplesToTime(len); // Filtering effects always end up with more data than they started with. Delete this 'tail'. outputTrack->HandleClear(tLen, outputTrack->GetEndTime(), false, false); - bool bResult = track->ClearAndPaste(t0, t0 + tLen, &*outputTrack, true, false); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + track->ClearAndPaste(t0, t0 + tLen, &*outputTrack, true, false); } return bLoopSuccess; diff --git a/src/effects/NoiseRemoval.cpp b/src/effects/NoiseRemoval.cpp index 761bf6098..5a12c0693 100644 --- a/src/effects/NoiseRemoval.cpp +++ b/src/effects/NoiseRemoval.cpp @@ -575,8 +575,7 @@ bool EffectNoiseRemoval::ProcessOne(int count, WaveTrack * track, double tLen = mOutputTrack->LongSamplesToTime(len); // Filtering effects always end up with more data than they started with. Delete this 'tail'. mOutputTrack->HandleClear(tLen, mOutputTrack->GetEndTime(), false, false); - bool bResult = track->ClearAndPaste(t0, t0 + tLen, mOutputTrack.get(), true, false); - wxASSERT(bResult); // TO DO: Actually handle this. + track->ClearAndPaste(t0, t0 + tLen, mOutputTrack.get(), true, false); } } diff --git a/src/effects/SBSMSEffect.cpp b/src/effects/SBSMSEffect.cpp index 8278cd7ac..eb7336d49 100644 --- a/src/effects/SBSMSEffect.cpp +++ b/src/effects/SBSMSEffect.cpp @@ -440,19 +440,12 @@ bool EffectSBSMS::Process() if(rightTrack) rb.outputRightTrack->Flush(); - bool bResult = leftTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputLeftTrack.get(), true, false, warper.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); if(rightTrack) - { - bResult = rightTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputRightTrack.get(), true, false, warper.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - } } } mCurTrackNum++; diff --git a/src/effects/StereoToMono.cpp b/src/effects/StereoToMono.cpp index 35cd7e2a7..6599f38f4 100644 --- a/src/effects/StereoToMono.cpp +++ b/src/effects/StereoToMono.cpp @@ -157,14 +157,14 @@ bool EffectStereoToMono::ProcessOne(int count) curMonoFrame = (curLeftFrame + curRightFrame) / 2.0; leftBuffer[i] = curMonoFrame; } - bResult &= mOutTrack->Append((samplePtr)leftBuffer.get(), floatSample, limit); + mOutTrack->Append((samplePtr)leftBuffer.get(), floatSample, limit); if (TrackProgress(count, 2.*(index.as_double() / (mEnd - mStart).as_double()))) return false; } double minStart = wxMin(mLeftTrack->GetStartTime(), mRightTrack->GetStartTime()); mLeftTrack->Clear(mLeftTrack->GetStartTime(), mLeftTrack->GetEndTime()); - bResult &= mOutTrack->Flush(); + mOutTrack->Flush(); mLeftTrack->Paste(minStart, mOutTrack.get()); mLeftTrack->SetLinked(false); mRightTrack->SetLinked(false); diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index 717c1a33e..9b4b2b275 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -1880,11 +1880,9 @@ int NyquistEffect::PutCallback(float *buffer, int channel, } } - if (mOutputTrack[channel]->Append((samplePtr)buffer, floatSample, len)) { - return 0; // success - } + mOutputTrack[channel]->Append((samplePtr)buffer, floatSample, len); - return -1; // failure + return 0; // success }, MakeSimpleGuard( -1 ) ); // translate all exceptions into failure } From 7195f9a3f442c2e1fc21b174c48b0f13b796ef6e Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 31 Mar 2017 22:53:58 -0400 Subject: [PATCH 88/91] fix windows build --- src/WaveTrack.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index b803273b9..18be5d7a9 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -1102,7 +1102,7 @@ void WaveTrack::HandleClear(double t0, double t1, } } if (!clip->Clear(t0,t1)) - return false; + return; clip->GetEnvelope()->RemoveUnneededPoints(t0); } } @@ -1297,7 +1297,8 @@ void WaveTrack::Paste(double t0, const Track *src) } } - return insideClip->Paste(t0, other->GetClipByIndex(0)); + insideClip->Paste(t0, other->GetClipByIndex(0)); + return; } // Just fall through and exhibit NEW behaviour @@ -2492,7 +2493,7 @@ void WaveTrack::Resample(int rate, ProgressDialog *progress) wxLogDebug( wxT("Resampling problem! We're partially resampled") ); // FIXME: The track is now in an inconsistent state since some // clips are resampled and some are not - return false; + return; } mRate = rate; From 59d740ad77c231487f32b98a3411912e7662b090 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 21 Feb 2017 18:05:35 -0800 Subject: [PATCH 89/91] Use a dedicated velocity slider for note tracks This gets rid of the offset rectangle hack that was needed to re-use gain sliders for note track velocities. It also removes the need for changing the style of a single slider. Perhaps most importantly, it fixes link errors regarding GainSlider(int). See https://sourceforge.net/p/audacity/mailman/message/35752524/ for details on why this change is needed and what caused it. --- src/NoteTrack.h | 6 -- src/TrackPanel.cpp | 260 ++++++++++++++++++++++++++------------------- src/TrackPanel.h | 27 ++++- 3 files changed, 173 insertions(+), 120 deletions(-) diff --git a/src/NoteTrack.h b/src/NoteTrack.h index b6d1e5a2a..c0db1bb94 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -177,11 +177,6 @@ class AUDACITY_DLL_API NoteTrack final void StartVScroll(); void VScroll(int start, int end); -#ifdef EXPERIMENTAL_MIDI_OUT - wxRect GetGainPlacementRect() const { return mGainPlacementRect; } - void SetGainPlacementRect(const wxRect &r) { mGainPlacementRect = r; } -#endif - bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override; XMLTagHandler *HandleXMLChild(const wxChar *tag) override; void WriteXML(XMLWriter &xmlFile) const override; @@ -224,7 +219,6 @@ class AUDACITY_DLL_API NoteTrack final int mPitchHeight; int mVisibleChannels; // bit set of visible channels int mLastMidiPosition; - wxRect mGainPlacementRect; }; #endif // USE_MIDI diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 8ccc83a28..7c8e063af 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -1182,7 +1182,8 @@ void TrackPanel::HandleInterruptedDrag() IsGainSliding, IsPanSliding, WasOverCutLine, - IsStretching + IsStretching, + IsVelocitySliding */ // 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 @@ -4841,7 +4842,7 @@ void TrackPanel::HandleMutingSoloing(wxMouseEvent & event, bool solo) } wxRect buttonRect; - mTrackInfo.GetMuteSoloRect(rect, buttonRect, solo, HasSoloButton()); + mTrackInfo.GetMuteSoloRect(rect, buttonRect, solo, HasSoloButton(), t); wxClientDC dc(this); @@ -4906,6 +4907,7 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan) #ifdef EXPERIMENTAL_OUTPUT_DISPLAY bool panZero = false; #endif + wxASSERT(mCapturedTrack->GetKind() == Track::Wave); // On the Mac, we'll lose track capture if the slider dialog // is displayed, but it doesn't hurt to do this for all plats. @@ -4924,20 +4926,15 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan) float newValue = slider->Get(); MixerBoard* pMixerBoard = this->GetMixerBoard(); // Update mixer board, too. -#ifdef EXPERIMENTAL_MIDI_OUT - if (capturedTrack->GetKind() == Track::Wave) -#endif - { - const auto wt = static_cast(capturedTrack); // Assume linked track is wave or null - const auto link = static_cast(wt->GetLink()); + const auto link = static_cast(capturedTrack->GetLink()); if (pan) { #ifdef EXPERIMENTAL_OUTPUT_DISPLAY - panZero = wt->SetPan(newValue); + panZero = capturedTrack->SetPan(newValue); #else - wt->SetPan(newValue); + capturedTrack->SetPan(newValue); #endif if (link) link->SetPan(newValue); @@ -4947,51 +4944,57 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan) #endif if (pMixerBoard) - pMixerBoard->UpdatePan(wt); + pMixerBoard->UpdatePan(capturedTrack); } else { - wt->SetGain(newValue); + capturedTrack->SetGain(newValue); if (link) link->SetGain(newValue); if (pMixerBoard) - pMixerBoard->UpdateGain(wt); + pMixerBoard->UpdateGain(capturedTrack); } - } -#ifdef EXPERIMENTAL_MIDI_OUT - else { - // mCapturedTrack is not wave... - if (!pan) { - // .. so assume it is note - static_cast(mCapturedTrack)->SetVelocity(newValue); -#ifdef EXPERIMENTAL_MIXER_BOARD - if (pMixerBoard) - // probably should modify UpdateGain to take a track that is - // either a WaveTrack or a NoteTrack. - pMixerBoard->UpdateGain((WaveTrack*)capturedTrack); -#endif - } - } -#endif RefreshTrack(capturedTrack); if (event.ButtonUp()) { -#ifdef EXPERIMENTAL_MIDI_OUT - if (capturedTrack->GetKind() == Track::Wave) { -#endif MakeParentPushState(pan ? _("Moved pan slider") : _("Moved gain slider"), pan ? _("Pan") : _("Gain"), UndoPush::CONSOLIDATE); -#ifdef EXPERIMENTAL_MIDI_OUT - } else { - MakeParentPushState(_("Moved velocity slider"), _("Velocity"), UndoPush::CONSOLIDATE); - } -#endif SetCapturedTrack( NULL ); } } +#ifdef EXPERIMENTAL_MIDI_OUT +void TrackPanel::HandleVelocitySlider(wxMouseEvent &event) +{ + wxASSERT(mCapturedTrack->GetKind() == Track::Note); + NoteTrack *capturedTrack = (NoteTrack *) mCapturedTrack; + + LWSlider *slider = mTrackInfo.VelocitySlider(capturedTrack, true); + + slider->OnMouseEvent(event); + + //If we have a double-click, do this... + if (event.LeftDClick()) + mMouseCapture = IsUncaptured; + + float newValue = slider->Get(); + capturedTrack->SetVelocity(newValue); + + MixerBoard* pMixerBoard = this->GetMixerBoard(); // Update mixer board, too. + + if (pMixerBoard) { + pMixerBoard->UpdateVelocity(capturedTrack); + } + RefreshTrack(capturedTrack); + if (event.ButtonUp()) { + MakeParentPushState(_("Moved velocity slider"), _("Velocity"), UndoPush::CONSOLIDATE); + SetCapturedTrack(NULL); + } +} +#endif + // The tracks positions within the list have changed, so update the vertical // ruler size for the track that triggered the event. void TrackPanel::OnTrackListResized(wxCommandEvent & e) @@ -5092,7 +5095,7 @@ void TrackPanel::HandleLabelClick(wxMouseEvent & event) { // DM: Check Mute and Solo buttons on WaveTracks: if (MuteSoloFunc(t, rect, event.m_x, event.m_y, false) || - MuteSoloFunc(t, rect, event.m_x, event.m_y, true)) + MuteSoloFunc(t, rect, event.m_x, event.m_y, true)) return; if (GainFunc(t, rect, event, event.m_x, event.m_y)) @@ -5107,21 +5110,11 @@ void TrackPanel::HandleLabelClick(wxMouseEvent & event) { wxRect midiRect; #ifdef EXPERIMENTAL_MIDI_OUT - // this is an awful hack: make a NEW rectangle at an offset because - // MuteSoloFunc thinks buttons are located below some text, e.g. - // "Mono, 44100Hz 32-bit float", but this is not true for a Note track - wxRect muteSoloRect(rect); - muteSoloRect.y -= 34; // subtract the height of wave track text - if (MuteSoloFunc(t, muteSoloRect, event.m_x, event.m_y, false) || - MuteSoloFunc(t, muteSoloRect, event.m_x, event.m_y, true)) + if (isleft && (MuteSoloFunc(t, rect, event.m_x, event.m_y, false) || + MuteSoloFunc(t, rect, event.m_x, event.m_y, true))) return; - // this is a similar hack: GainFunc expects a Wave track slider, so it's - // looking in the wrong place. We pass it a bogus rectangle created when - // the slider was placed to "fake" GainFunc into finding the slider in - // its actual location. - if (GainFunc(t, ((NoteTrack *) t)->GetGainPlacementRect(), - event, event.m_x, event.m_y)) + if (isleft && VelocityFunc(t, rect, event, event.m_x, event.m_y)) return; #endif mTrackInfo.GetTrackControlsRect(rect, midiRect); @@ -5287,6 +5280,23 @@ bool TrackPanel::PanFunc(Track * t, wxRect rect, wxMouseEvent &event, return true; } +#ifdef EXPERIMENTAL_MIDI_OUT +bool TrackPanel::VelocityFunc(Track * t, wxRect rect, wxMouseEvent &event, + int x, int y) +{ + wxRect sliderRect; + mTrackInfo.GetVelocityRect(rect, sliderRect); + if (!sliderRect.Contains(x, y)) + return false; + + SetCapturedTrack(t, IsVelocitySliding); + mCapturedRect = rect; + HandleVelocitySlider(event); + + return true; +} +#endif + /// Mute or solo the given track (t). If solo is true, we're /// soloing, otherwise we're muting. Basically, check and see /// whether x and y fall within the area of the appropriate button. @@ -5294,7 +5304,7 @@ bool TrackPanel::MuteSoloFunc(Track * t, wxRect rect, int x, int y, bool solo) { wxRect buttonRect; - mTrackInfo.GetMuteSoloRect(rect, buttonRect, solo, HasSoloButton()); + mTrackInfo.GetMuteSoloRect(rect, buttonRect, solo, HasSoloButton(), t); if (!buttonRect.Contains(x, y)) return false; @@ -6182,6 +6192,11 @@ try case IsPanSliding: HandleSliders(event, true); break; +#ifdef EXPERIMENTAL_MIDI_OUT + case IsVelocitySliding: + HandleVelocitySlider(event); + break; +#endif case IsMinimizing: HandleMinimizing(event); break; @@ -7222,11 +7237,6 @@ void TrackPanel::DrawOutside(Track * t, wxDC * dc, const wxRect & rec, #ifdef USE_MIDI else if (bIsNote) { - // Note tracks do not have text, e.g. "Mono, 44100Hz, 32-bit float", so - // Mute & Solo button goes higher. To preserve existing AudioTrack code, - // we move the buttons up by pretending track is higher (at lower y) - rect.y -= 34; - rect.height += 34; wxRect midiRect; mTrackInfo.GetTrackControlsRect(trackRect, midiRect); // Offset by height of Solo/Mute buttons: @@ -7234,36 +7244,22 @@ void TrackPanel::DrawOutside(Track * t, wxDC * dc, const wxRect & rec, midiRect.height -= 21; // allow room for minimize button at bottom #ifdef EXPERIMENTAL_MIDI_OUT - // the offset 2 is just to leave a little space between channel buttons - // and velocity slider (if any) - int h = ((NoteTrack *) t)->DrawLabelControls(*dc, midiRect) + 2; + ((NoteTrack *)t)->DrawLabelControls(*dc, midiRect); - // Draw some lines for MuteSolo buttons: - if (rect.height > 84) { - AColor::Line(*dc, rect.x+48 , rect.y+50, rect.x+48, rect.y + 66); - // bevel below mute/solo - AColor::Line(*dc, rect.x, rect.y + 66, mTrackInfo.GetTrackInfoWidth(), rect.y + 66); - } - mTrackInfo.DrawMuteSolo(dc, rect, t, - (captured && mMouseCapture == IsMuting), false, HasSoloButton()); - mTrackInfo.DrawMuteSolo(dc, rect, t, - (captured && mMouseCapture == IsSoloing), true, HasSoloButton()); + // Draw some lines for MuteSolo buttons (normally handled by DrawBordersWithin but not done for note tracks) + if (rect.height > 48) { + // Note: offset up by 34 units + AColor::Line(*dc, rect.x + 48, rect.y + 16, rect.x + 48, rect.y + 32); // between mute/solo + AColor::Line(*dc, rect.x, rect.y + 32, kTrackInfoWidth, rect.y + 32); // below mute/solo + } + mTrackInfo.DrawMuteSolo(dc, rect, t, + (captured && mMouseCapture == IsMuting), false, HasSoloButton()); + mTrackInfo.DrawMuteSolo(dc, rect, t, + (captured && mMouseCapture == IsSoloing), true, HasSoloButton()); - // place a volume control below channel buttons (this will - // control an offset to midi velocity). - // DrawVelocitySlider places slider assuming this is a Wave track - // and using a large offset to leave room for other things, - // so here we make a fake rectangle as if it is for a Wave - // track, but it is offset to place the slider properly in - // a Note track. This whole placement thing should be redesigned - // to lay out different types of tracks and controls - wxRect gr; // gr is gain rectangle where slider is drawn - mTrackInfo.GetGainRect(rect, gr); - rect.y = rect.y + h - gr.y; // ultimately want slider at rect.y + h - rect.height = rect.height - h + gr.y; - // save for mouse hit detect: - ((NoteTrack *) t)->SetGainPlacementRect(rect); - mTrackInfo.DrawVelocitySlider(dc, (NoteTrack *) t, rect); + // Place a volume control below channel buttons (this will + // control an offset to midi velocity). + mTrackInfo.DrawVelocitySlider(dc, (NoteTrack *)t, rect, captured); #endif } #endif // USE_MIDI @@ -9015,6 +9011,22 @@ TrackInfo::TrackInfo(TrackPanel * pParentIn) PAN_SLIDER); mPanCaptured->SetDefaultValue(0.0); +#ifdef EXPERIMENTAL_MIDI_OUT + GetVelocityRect(rect, sliderRect); + + /* i18n-hint: Title of the Velocity slider, used to adjust the volume of note tracks */ + mVelocity = std::make_unique(pParent, _("Velocity"), + wxPoint(sliderRect.x, sliderRect.y), + wxSize(sliderRect.width, sliderRect.height), + VEL_SLIDER); + mVelocity->SetDefaultValue(0.0); + mVelocityCaptured = std::make_unique(pParent, _("Velocity"), + wxPoint(sliderRect.x, sliderRect.y), + wxSize(sliderRect.width, sliderRect.height), + VEL_SLIDER); + mVelocityCaptured->SetDefaultValue(0.0); +#endif + UpdatePrefs(); } @@ -9043,10 +9055,20 @@ void TrackInfo::GetTitleBarRect(const wxRect & rect, wxRect & dest) const dest.height = kTrackInfoBtnSize; } -void TrackInfo::GetMuteSoloRect(const wxRect & rect, wxRect & dest, bool solo, bool bHasSoloButton) const +void TrackInfo::GetMuteSoloRect(const wxRect & rect, wxRect & dest, bool solo, bool bHasSoloButton, const Track *pTrack) const { - dest.x = rect.x ; + dest.x = rect.x; +#ifdef EXPERIMENTAL_MIDI_OUT + if (pTrack->GetKind() == Track::Note) + dest.y = rect.y + 16; + else + { + wxASSERT(pTrack->GetKind() == Track::Wave); + dest.y = rect.y + 50; + } +#else dest.y = rect.y + 50; +#endif dest.width = 48; dest.height = kTrackInfoBtnSize; @@ -9076,6 +9098,16 @@ void TrackInfo::GetPanRect(const wxRect & rect, wxRect & dest) const dest.height = 25; } +#ifdef EXPERIMENTAL_MIDI_OUT +void TrackInfo::GetVelocityRect(const wxRect & rect, wxRect & dest) const +{ + dest.x = rect.x + 7; + dest.y = rect.y + 100; + dest.width = 84; + dest.height = 25; +} +#endif + void TrackInfo::GetMinimizeRect(const wxRect & rect, wxRect &dest) const { const int kBlankWidth = kTrackInfoBtnSize + 4; @@ -9264,7 +9296,7 @@ void TrackInfo::DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t, wxRect bev; if( solo && !bHasSoloButton ) return; - GetMuteSoloRect(rect, bev, solo, bHasSoloButton); + GetMuteSoloRect(rect, bev, solo, bHasSoloButton, t); bev.Inflate(-1, -1); if (bev.y + bev.height >= rect.y + rect.height - 19) @@ -9342,27 +9374,6 @@ void TrackInfo::DrawMinimize(wxDC * dc, const wxRect & rect, Track * t, bool dow AColor::BevelTrackInfo(*dc, !down, bev); } -#ifdef EXPERIMENTAL_MIDI_OUT -void TrackInfo::DrawVelocitySlider(wxDC *dc, NoteTrack *t, wxRect rect) const -{ - wxRect gainRect; - int index = t->GetIndex(); - - //EnsureSufficientSliders(index); - - GetGainRect(rect, gainRect); - if (gainRect.y + gainRect.height < rect.y + rect.height - 19) { - auto &gain = mGain; // mGains[index]; - gain->SetStyle(VEL_SLIDER); - GainSlider(index)->Move(wxPoint(gainRect.x, gainRect.y)); - GainSlider(index)->Set(t->GetVelocity()); - GainSlider(index)->OnPaint(*dc - // , t->GetSelected() - ); - } -} -#endif - void TrackInfo::DrawSliders(wxDC *dc, WaveTrack *t, wxRect rect, bool captured) const { wxRect sliderRect; @@ -9378,6 +9389,18 @@ void TrackInfo::DrawSliders(wxDC *dc, WaveTrack *t, wxRect rect, bool captured) } } +#ifdef EXPERIMENTAL_MIDI_OUT +void TrackInfo::DrawVelocitySlider(wxDC *dc, NoteTrack *t, wxRect rect, bool captured) const +{ + wxRect sliderRect; + + GetVelocityRect(rect, sliderRect); + if (sliderRect.y + sliderRect.height < rect.y + rect.height - 19) { + VelocitySlider(t, captured)->OnPaint(*dc); + } +} +#endif + LWSlider * TrackInfo::GainSlider(WaveTrack *t, bool captured) const { wxRect rect(kLeftInset, t->GetY() - pParent->GetViewInfo()->vpos + kTopInset, 1, t->GetHeight()); @@ -9412,6 +9435,25 @@ LWSlider * TrackInfo::PanSlider(WaveTrack *t, bool captured) const return (captured ? mPanCaptured : mPan).get(); } +#ifdef EXPERIMENTAL_MIDI_OUT +LWSlider * TrackInfo::VelocitySlider(NoteTrack *t, bool captured) const +{ + wxRect rect(kLeftInset, t->GetY() - pParent->GetViewInfo()->vpos + kTopInset, 1, t->GetHeight()); + wxRect sliderRect; + GetVelocityRect(rect, sliderRect); + + wxPoint pos = sliderRect.GetPosition(); + float velocity = t->GetVelocity(); + + mVelocity->Move(pos); + mVelocity->Set(velocity); + mVelocityCaptured->Move(pos); + mVelocityCaptured->Set(velocity); + + return (captured ? mVelocityCaptured : mVelocity).get(); +} +#endif + void TrackInfo::UpdatePrefs() { // Calculation of best font size depends on language, so it should be redone in case diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 76af1ecc1..2f0ba0841 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -92,10 +92,10 @@ private: void DrawTitleBar(wxDC * dc, const wxRect & rect, Track * t, bool down) const; void DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t, bool down, bool solo, bool bHasSoloButton) const; void DrawVRuler(wxDC * dc, const wxRect & rect, Track * t) const; -#ifdef EXPERIMENTAL_MIDI_OUT - void DrawVelocitySlider(wxDC * dc, NoteTrack *t, wxRect rect) const ; -#endif void DrawSliders(wxDC * dc, WaveTrack *t, wxRect rect, bool captured) const; +#ifdef EXPERIMENTAL_MIDI_OUT + void DrawVelocitySlider(wxDC * dc, NoteTrack *t, wxRect rect, bool captured) const; +#endif // Draw the minimize button *and* the sync-lock track icon, if necessary. void DrawMinimize(wxDC * dc, const wxRect & rect, Track * t, bool down) const; @@ -103,9 +103,13 @@ private: void GetTrackControlsRect(const wxRect & rect, wxRect &dest) const; void GetCloseBoxRect(const wxRect & rect, wxRect &dest) const; void GetTitleBarRect(const wxRect & rect, wxRect &dest) const; - void GetMuteSoloRect(const wxRect & rect, wxRect &dest, bool solo, bool bHasSoloButton) const; + void GetMuteSoloRect(const wxRect & rect, wxRect &dest, bool solo, bool bHasSoloButton, + const Track *pTrack) const; void GetGainRect(const wxRect & rect, wxRect &dest) const; void GetPanRect(const wxRect & rect, wxRect &dest) const; +#ifdef EXPERIMENTAL_MIDI_OUT + void GetVelocityRect(const wxRect & rect, wxRect &dest) const; +#endif void GetMinimizeRect(const wxRect & rect, wxRect &dest) const; void GetSyncLockIconRect(const wxRect & rect, wxRect &dest) const; @@ -114,7 +118,7 @@ public: LWSlider * PanSlider(WaveTrack *t, bool captured = false) const; #ifdef EXPERIMENTAL_MIDI_OUT - LWSlider *GainSlider(int index) const; + LWSlider * VelocitySlider(NoteTrack *t, bool captured = false) const; #endif private: @@ -124,6 +128,9 @@ private: wxFont mFont; std::unique_ptr mGainCaptured, mPanCaptured, mGain, mPan; +#ifdef EXPERIMENTAL_MIDI_OUT + std::unique_ptr mVelocityCaptured, mVelocity; +#endif friend class TrackPanel; }; @@ -415,6 +422,9 @@ protected: virtual void HandleMutingSoloing(wxMouseEvent & event, bool solo); virtual void HandleMinimizing(wxMouseEvent & event); virtual void HandleSliders(wxMouseEvent &event, bool pan); +#ifdef EXPERIMENTAL_MIDI_OUT + virtual void HandleVelocitySlider(wxMouseEvent &event); +#endif // These *Func methods are used in TrackPanel::HandleLabelClick to set up @@ -434,6 +444,10 @@ protected: int x, int y); virtual bool PanFunc(Track * t, wxRect rect, wxMouseEvent &event, int x, int y); +#ifdef EXPERIMENTAL_MIDI_OUT + virtual bool VelocityFunc(Track * t, wxRect rect, wxMouseEvent &event, + int x, int y); +#endif virtual void MakeParentRedrawScrollbars(); @@ -747,6 +761,9 @@ protected: IsStretching, #endif IsZooming, +#ifdef EXPERIMENTAL_MIDI_OUT + IsVelocitySliding, +#endif }; From 1c93198d088f3f897fe318e9714d3dff28216f20 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 21 Feb 2017 18:05:35 -0800 Subject: [PATCH 90/91] Re-implement note tracks in MixerBoard This commit adds note tracks into the mixerboard. It's done as a separate slider this time instead of via subclasses (as PRL requested), so which should be easier to use. This also changes some of the gaurds to EXPERIMENTAL_MIDI_OUT from USE_MIDI, as it's meaningless to have the note track code in mixerboard when it cannot do anything (depends on methods that exist behind EXPERIMENTAL_MIDI_OUT). --- src/Menus.cpp | 6 +- src/MixerBoard.cpp | 109 +++++++++++++++++++++++++------------ src/MixerBoard.h | 19 +++++++ src/commands/CommandFlag.h | 1 + 4 files changed, 99 insertions(+), 36 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 18c4bf000..aaa3f1053 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -728,7 +728,7 @@ void AudacityProject::CreateMenusAndCommands() AudioIONotBusyFlag); c->AddItem(wxT("Karaoke"), _("&Karaoke..."), FN(OnKaraoke), LabelTracksExistFlag, LabelTracksExistFlag); - c->AddItem(wxT("MixerBoard"), _("&Mixer Board..."), FN(OnMixerBoard), WaveTracksExistFlag, WaveTracksExistFlag); + c->AddItem(wxT("MixerBoard"), _("&Mixer Board..."), FN(OnMixerBoard), PlayableTracksExistFlag, PlayableTracksExistFlag); c->AddSeparator(); @@ -1836,6 +1836,7 @@ CommandFlag AudacityProject::GetUpdateFlags(bool checkActive) } else if (t->GetKind() == Track::Wave) { flags |= WaveTracksExistFlag; + flags |= PlayableTracksExistFlag; if (t->GetSelected()) { flags |= TracksSelectedFlag; if (t->GetLinked()) { @@ -1853,6 +1854,9 @@ CommandFlag AudacityProject::GetUpdateFlags(bool checkActive) NoteTrack *nt = (NoteTrack *) t; flags |= NoteTracksExistFlag; +#ifdef EXPERIMENTAL_MIDI_OUT + flags |= PlayableTracksExistFlag; +#endif if (nt->GetSelected()) { flags |= TracksSelectedFlag; diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 2538e85fe..053bcf520 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -24,7 +24,9 @@ #include "AColor.h" #include "AudioIO.h" +#ifdef USE_MIDI #include "NoteTrack.h" +#endif #include "Project.h" #include "TrackPanel.h" // for EVT_TRACK_PANEL_TIMER @@ -137,6 +139,9 @@ enum { ID_BITMAPBUTTON_MUSICAL_INSTRUMENT = 13000, ID_SLIDER_PAN, ID_SLIDER_GAIN, +#ifdef EXPERIMENTAL_MIDI_OUT + ID_SLIDER_VELOCITY, +#endif ID_TOGGLEBUTTON_MUTE, ID_TOGGLEBUTTON_SOLO, }; @@ -148,6 +153,9 @@ BEGIN_EVENT_TABLE(MixerTrackCluster, wxPanelWrapper) EVT_BUTTON(ID_BITMAPBUTTON_MUSICAL_INSTRUMENT, MixerTrackCluster::OnButton_MusicalInstrument) EVT_SLIDER(ID_SLIDER_PAN, MixerTrackCluster::OnSlider_Pan) EVT_SLIDER(ID_SLIDER_GAIN, MixerTrackCluster::OnSlider_Gain) +#ifdef EXPERIMENTAL_MIDI_OUT + EVT_SLIDER(ID_SLIDER_VELOCITY, MixerTrackCluster::OnSlider_Velocity) +#endif //v EVT_COMMAND_SCROLL(ID_SLIDER_GAIN, MixerTrackCluster::OnSliderScroll_Gain) EVT_COMMAND(ID_TOGGLEBUTTON_MUTE, wxEVT_COMMAND_BUTTON_CLICKED, MixerTrackCluster::OnButton_Mute) EVT_COMMAND(ID_TOGGLEBUTTON_SOLO, wxEVT_COMMAND_BUTTON_CLICKED, MixerTrackCluster::OnButton_Solo) @@ -184,37 +192,33 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, // mStaticText_TrackName->SetBackgroundColour(this->GetTrackColor()); - // gain slider at left + // gain and velocity sliders at left (both in same place) ctrlPos.x = kDoubleInset; ctrlPos.y += TRACK_NAME_HEIGHT + kDoubleInset; const int nGainSliderHeight = size.GetHeight() - ctrlPos.y - kQuadrupleInset; ctrlSize.Set(kLeftSideStackWidth - kQuadrupleInset, nGainSliderHeight); -#ifdef USE_MIDI - if (GetNote()) { - mSlider_Gain = - safenew MixerTrackSlider( - this, ID_SLIDER_GAIN, - /* i18n-hint: title of the MIDI Velocity slider */ - _("Velocity"), - ctrlPos, ctrlSize, VEL_SLIDER, true, - true, 0.0, wxVERTICAL); - } - else -#endif - mSlider_Gain = - safenew MixerTrackSlider( - this, ID_SLIDER_GAIN, - /* i18n-hint: title of the Gain slider, used to adjust the volume */ - _("Gain"), - ctrlPos, ctrlSize, DB_SLIDER, true, - true, 0.0, wxVERTICAL); - + mSlider_Gain = + safenew MixerTrackSlider( + this, ID_SLIDER_GAIN, + /* i18n-hint: title of the Gain slider, used to adjust the volume */ + _("Gain"), + ctrlPos, ctrlSize, DB_SLIDER, true, + true, 0.0, wxVERTICAL); mSlider_Gain->SetName(_("Gain")); - this->UpdateGain(); - +#ifdef EXPERIMENTAL_MIDI_OUT + mSlider_Velocity = + safenew MixerTrackSlider( + this, ID_SLIDER_VELOCITY, + /* i18n-hint: title of the MIDI Velocity slider */ + _("Velocity"), + ctrlPos, ctrlSize, VEL_SLIDER, true, + true, 0.0, wxVERTICAL); + mSlider_Velocity->SetName(_("Velocity")); + this->UpdateVelocity(); +#endif // other controls and meter at right @@ -329,7 +333,7 @@ WaveTrack *MixerTrackCluster::GetRight() const return nullptr; } -#ifdef USE_MIDI +#ifdef EXPERIMENTAL_MIDI_OUT NoteTrack *MixerTrackCluster::GetNote() const { return dynamic_cast< NoteTrack * >( mTrack ); @@ -361,6 +365,9 @@ void MixerTrackCluster::HandleResize() // For wxSizeEvents, update gain slider a TRACK_NAME_HEIGHT + kDoubleInset) - // mStaticText_TrackName + margin kQuadrupleInset; // margin below gain slider mSlider_Gain->SetSize(-1, nGainSliderHeight); +#ifdef EXPERIMENTAL_MIDI_OUT + mSlider_Velocity->SetSize(-1, nGainSliderHeight); +#endif bool bSoloNone = mProject->IsSoloNone(); @@ -384,10 +391,6 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/) float fValue = mSlider_Gain->Get(); if (GetWave()) GetWave()->SetGain(fValue); -#ifdef EXPERIMENTAL_MIDI_OUT - else - GetNote()->SetVelocity(fValue); -#endif if (GetRight()) GetRight()->SetGain(fValue); @@ -397,6 +400,20 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/) mProject->TP_PushState(_("Moved gain slider"), _("Gain"), UndoPush::CONSOLIDATE ); } +#ifdef EXPERIMENTAL_MIDI_OUT +void MixerTrackCluster::HandleSliderVelocity(const bool bWantPushState /*= false*/) +{ + float fValue = mSlider_Velocity->Get(); + if (GetNote()) + GetNote()->SetVelocity(fValue); + + // Update the TrackPanel correspondingly. + mProject->RefreshTPTrack(mTrack); + if (bWantPushState) + mProject->TP_PushState(_("Moved velocity slider"), _("Velocity"), UndoPush::CONSOLIDATE); +} +#endif + void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/) { float fValue = mSlider_Pan->Get(); @@ -462,28 +479,33 @@ void MixerTrackCluster::UpdateSolo() void MixerTrackCluster::UpdatePan() { -#ifdef EXPERIMENTAL_MIDI_OUT if (!GetWave()) { mSlider_Pan->Hide(); return; } -#endif mSlider_Pan->Set(GetWave()->GetPan()); } void MixerTrackCluster::UpdateGain() { -#ifdef EXPERIMENTAL_MIDI_OUT if (!GetWave()) { - mSlider_Gain->SetStyle(VEL_SLIDER); - mSlider_Gain->Set(GetNote()->GetVelocity()); + mSlider_Gain->Hide(); return; } - mSlider_Gain->SetStyle(DB_SLIDER); -#endif mSlider_Gain->Set(GetWave()->GetGain()); } +#ifdef EXPERIMENTAL_MIDI_OUT +void MixerTrackCluster::UpdateVelocity() +{ + if (!GetNote()) { + mSlider_Velocity->Hide(); + return; + } + mSlider_Velocity->Set(GetNote()->GetVelocity()); +} +#endif + void MixerTrackCluster::UpdateMeter(const double t0, const double t1) { // NoteTracks do not (currently) register on meters. It would probably be @@ -696,6 +718,13 @@ void MixerTrackCluster::OnSlider_Gain(wxCommandEvent& WXUNUSED(event)) this->HandleSliderGain(); } +#ifdef EXPERIMENTAL_MIDI_OUT +void MixerTrackCluster::OnSlider_Velocity(wxCommandEvent& WXUNUSED(event)) +{ + this->HandleSliderVelocity(); +} +#endif + //v void MixerTrackCluster::OnSliderScroll_Gain(wxScrollEvent& WXUNUSED(event)) //{ //int sliderValue = (int)(mSlider_Gain->Get()); //v mSlider_Gain->GetValue(); @@ -1209,6 +1238,16 @@ void MixerBoard::UpdateGain(const PlayableTrack* pTrack) pMixerTrackCluster->UpdateGain(); } +#ifdef EXPERIMENTAL_MIDI_OUT +void MixerBoard::UpdateVelocity(const PlayableTrack* pTrack) +{ + MixerTrackCluster* pMixerTrackCluster; + FindMixerTrackCluster(pTrack, &pMixerTrackCluster); + if (pMixerTrackCluster) + pMixerTrackCluster->UpdateVelocity(); +} +#endif + void MixerBoard::UpdateMeters(const double t1, const bool bLoopedPlay) { if (!this->IsShown() || (t1 == BAD_STREAM_TIME)) diff --git a/src/MixerBoard.h b/src/MixerBoard.h index ae8f7ad58..56f99d0f3 100644 --- a/src/MixerBoard.h +++ b/src/MixerBoard.h @@ -64,7 +64,9 @@ class Meter; class MixerBoard; class Track; +#ifdef USE_MIDI class NoteTrack; +#endif class PlayableTrack; class WaveTrack; @@ -81,13 +83,18 @@ public: WaveTrack *GetWave() const; WaveTrack *GetRight() const; +#ifdef EXPERIMENTAL_MIDI_OUT NoteTrack *GetNote() const; +#endif void UpdatePrefs(); void HandleResize(); // For wxSizeEvents, update gain slider and meter. void HandleSliderGain(const bool bWantPushState = false); +#ifdef EXPERIMENTAL_MIDI_OUT + void HandleSliderVelocity(const bool bWantPushState = false); +#endif void HandleSliderPan(const bool bWantPushState = false); void ResetMeter(const bool bResetClipping); @@ -99,6 +106,9 @@ public: void UpdateSolo(); void UpdatePan(); void UpdateGain(); +#ifdef EXPERIMENTAL_MIDI_OUT + void UpdateVelocity(); +#endif void UpdateMeter(const double t0, const double t1); private: @@ -113,6 +123,9 @@ private: void OnButton_MusicalInstrument(wxCommandEvent& event); void OnSlider_Gain(wxCommandEvent& event); +#ifdef EXPERIMENTAL_MIDI_OUT + void OnSlider_Velocity(wxCommandEvent& event); +#endif void OnSlider_Pan(wxCommandEvent& event); void OnButton_Mute(wxCommandEvent& event); void OnButton_Solo(wxCommandEvent& event); @@ -133,6 +146,9 @@ private: AButton* mToggleButton_Solo; MixerTrackSlider* mSlider_Pan; MixerTrackSlider* mSlider_Gain; +#ifdef EXPERIMENTAL_MIDI_OUT + MixerTrackSlider* mSlider_Velocity; +#endif Meter* mMeter; public: @@ -222,6 +238,9 @@ public: void UpdateSolo(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks. void UpdatePan(const PlayableTrack* pTrack); void UpdateGain(const PlayableTrack* pTrack); +#ifdef EXPERIMENTAL_MIDI_OUT + void UpdateVelocity(const PlayableTrack* pTrack); +#endif void UpdateMeters(const double t1, const bool bLoopedPlay); diff --git a/src/commands/CommandFlag.h b/src/commands/CommandFlag.h index e88123691..6ae14d055 100644 --- a/src/commands/CommandFlag.h +++ b/src/commands/CommandFlag.h @@ -54,6 +54,7 @@ enum CommandFlag : unsigned long long PausedFlag = 0x200000000ULL, // jkc NotPausedFlag = 0x400000000ULL, // jkc HasWaveDataFlag = 0x800000000ULL, // jkc + PlayableTracksExistFlag = 0x1000000000ULL, NoFlagsSpecifed = ~0ULL }; From 1525f146dae10ce231ac6da8625b2d826e0f44cd Mon Sep 17 00:00:00 2001 From: James Crook Date: Sat, 1 Apr 2017 19:40:54 +0100 Subject: [PATCH 91/91] Update Greek Translation by Dimitris Spingos --- locale/el.po | 106 +++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 55 deletions(-) diff --git a/locale/el.po b/locale/el.po index 47dc739b3..4f38f6e15 100644 --- a/locale/el.po +++ b/locale/el.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: Audacity 1.3.3 b\n" "Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n" "POT-Creation-Date: 2017-03-18 18:41+0000\n" -"PO-Revision-Date: 2017-02-13 23:56+0300\n" +"PO-Revision-Date: 2017-04-01 21:00+0300\n" "Last-Translator: Dimitris Spingos (Δημήτρης Σπίγγος) \n" "Language-Team: team@lists.gnome.gr\n" "Language: el\n" @@ -422,9 +422,8 @@ msgid "Stop script" msgstr "Παύση δέσμης ενεργειών" #: src/AboutDialog.cpp:94 -#, fuzzy msgid "Check Online" -msgstr "Έλεγχος %s" +msgstr "Διαδικτυακός έλεγχος" #: src/AboutDialog.cpp:103 msgid "quality assurance" @@ -795,7 +794,7 @@ msgstr "Εκκίνηση του Audacity ..." #. i18n-hint: "New" is an action (verb) to create a NEW project #: src/AudacityApp.cpp:1533 src/Menus.cpp:304 msgid "&New" -msgstr "&Νέα εργασία" +msgstr "&Νέο έργο" #. i18n-hint: (verb) #: src/AudacityApp.cpp:1534 src/Menus.cpp:309 @@ -845,8 +844,8 @@ msgid "" "Audacity is now going to exit. Please launch Audacity again to use the new " "temporary directory." msgstr "" -"Το Audacity τώρα θα κλείσει. Παρακαλώ άνοιξε ξανά το Audacity για να " -"χρησιμοποιήσεις το νέο φάκελο προσωρινών αρχείων." +"Το Audacity τώρα θα κλείσει. Παρακαλούμε επανεκκινήστε το Audacity για να " +"χρησιμοποιήσετε τον νέο προσωρινό κατάλογο." #: src/AudacityApp.cpp:1820 msgid "" @@ -1143,9 +1142,8 @@ msgid "Could not enumerate files in auto save directory." msgstr "Αδύνατη η απαρίθμηση αρχείων στον κατάλογο αυτόματης αποθήκευσης." #: src/AutoRecovery.cpp:760 -#, fuzzy msgid "Error Decoding File" -msgstr "Σφάλμα κατά την αποκωδικοποίηση του αρχείου" +msgstr "Σφάλμα αποκωδικοποίησης του αρχείου" #: src/BatchCommandDialog.cpp:60 src/BatchCommandDialog.cpp:64 #: src/BatchCommandDialog.cpp:65 @@ -1490,14 +1488,13 @@ msgid "" "There is very little free disk space left on this volume.\n" "Please select another temporary directory in Preferences." msgstr "" -"Υπάρχει πολύ λίγος ελεύθερος χώρος που απέμεινε στον δίσκο σε αυτόν τον " -"τόμο.\n" +"Υπάρχει πολύ λίγος ελεύθερος χώρος που απέμεινε στον δίσκο σε αυτόν τον τόμο." +"\n" "Παρακαλούμε επιλέξτε ένα άλλο προσωρινό κατάλογο στις προτιμήσεις." #: src/DirManager.cpp:424 -#, fuzzy msgid "Cleaning project temporary files" -msgstr "Καθαρισμός προσωρινών αρχείων" +msgstr "Καθαρισμός προσωρινών αρχείων έργου" #: src/DirManager.cpp:437 msgid "Cleaning up temporary files" @@ -2184,25 +2181,32 @@ msgstr "Δεν είναι εγκατεστημένη η Βοήθεια τοπι #: src/HelpText.cpp:198 msgid "Get the Official Released Version of Audacity" -msgstr "" +msgstr "Λήψη της επίσημης έκδοσης του Audacity" #: src/HelpText.cpp:200 msgid "" "

The version of Audacity you are using is an Alpha test version." msgstr "" +"

Η έκδοση του Audacity που χρησιμοποιείτε είναι μια άλφα " +"δοκιμαστική έκδοση." #: src/HelpText.cpp:201 msgid "" "We strongly recommend that you use our latest stable released version, which " "has full documentation and support.

" msgstr "" +"Σας συνιστούμε έντονα να χρησιμοποιήσετε την τελευταία μας σταθερή έκδοση, " +"που έχει πλήρη τεκμηρίωση και υποστήριξη.

" #: src/HelpText.cpp:202 msgid "" "You can help us get Audacity ready for release by joining our [[http://www." "audacityteam.org/community/|community]].


" msgstr "" +"Μπορείτε να μας βοηθήσετε να καταστήσετε το Audacity έτοιμο για έκδοση " +"συμμετέχοντας στην [[http://www.audacityteam.org/community/|κοινότητά]] " +"μας.


" #: src/HelpText.cpp:205 msgid "How to get help" @@ -2255,9 +2259,8 @@ msgstr "" "Το Audacity έχει τη δυνατότητα εισαγωγής απροστάτευτων αρχείων σε πολλές " "άλλες μορφές (όπως M4A και WMA, συμπιεσμένα αρχεία WAV από φορητές συσκευές " "εγγραφής και ήχο από αρχεία βίντεο) εφόσον κατεβάσετε και εγκαταστήσετε την " -"προαιρετική [[http://manual.audacityteam.org/man/" -"faq_opening_and_saving_files.html#foreign| βιβλιοθήκη FFmpeg]] στον " -"υπολογιστή σας." +"προαιρετική [[http://manual.audacityteam.org/man/faq_opening_and_saving_files" +".html#foreign| βιβλιοθήκη FFmpeg]] στον υπολογιστή σας." #: src/HelpText.cpp:227 msgid "" @@ -2530,9 +2533,8 @@ msgstr "" "συστήματος, %s (%s)." #: src/Legacy.cpp:263 -#, fuzzy msgid "Error Converting Legacy Project File" -msgstr "Σφάλμα κατά την αποθήκευση του έργου" +msgstr "Σφάλμα μετατροπής παλιού αρχείου έργου" #: src/Legacy.cpp:304 #, c-format @@ -2826,11 +2828,11 @@ msgstr "στο &τέλος του κομματιού" #: src/Menus.cpp:600 msgid "Store Re&gion" -msgstr "" +msgstr "Αποθήκευση περιο&χής" #: src/Menus.cpp:603 msgid "Retrieve Regio&n" -msgstr "" +msgstr "Ανάκτηση πε&ριοχής" #: src/Menus.cpp:606 msgid "Store Cursor Pos&ition" @@ -3044,7 +3046,7 @@ msgstr "Ηχογράφηση ενερ&γοποιημένου ήχου (ναι/ό #: src/Menus.cpp:798 msgid "Sound Activation Le&vel..." -msgstr "Επί&πεδο ήχου για καταγραφή..." +msgstr "Επί&πεδο ενεργοποίησης ήχου..." #: src/Menus.cpp:801 msgid "A&utomated Recording Level Adjustment (on/off)" @@ -4788,8 +4790,8 @@ msgid "" msgstr "" "Το 'Αποθήκευση συμπιεσμένου έργου' είναι για ένα έργο Audacity, όχι για " "αρχείο ήχου.\n" -"Για αρχείο ήχου που θα ανοίξει σε άλλες εφαρμογές, χρησιμοποιήστε " -"'Εξαγωγή'.\n" +"Για αρχείο ήχου που θα ανοίξει σε άλλες εφαρμογές, χρησιμοποιήστε 'Εξαγωγή'." +"\n" "\n" "Τα συμπιεσμένα αρχεία έργου είναι ένας καλός τρόπος για να διαδώσετε το έργο " "σας\n" @@ -4819,7 +4821,7 @@ msgstr "%sΑποθήκευση έργου \"%s\" ως..." #: src/Project.cpp:4315 msgid "Created new project" -msgstr "Δημιουργία νέου έργου" +msgstr "Δημιουργήθηκε νέο έργο" #: src/Project.cpp:4532 #, c-format @@ -5979,7 +5981,7 @@ msgstr "Έγινε '%s' κομμάτι στέρεο" #: src/TrackPanel.cpp:8163 msgid "Make Stereo" -msgstr "Κάνε στέρεο" +msgstr "Δημιουργία στερεοφωνικού" #: src/TrackPanel.cpp:8198 msgid "" @@ -6174,8 +6176,7 @@ msgstr "Δεν υπάρχει αρκετός διαθέσιμος χώρος γ #: src/WaveTrack.cpp:2486 msgid "There is not enough room available to expand the cut line" -msgstr "" -"Δεν υπάρχει αρκετός διαθέσιμος χώρος για να επεκταθεί η γραμμή αποκοπής" +msgstr "Δεν υπάρχει αρκετός διαθέσιμος χώρος για να επεκταθεί η γραμμή αποκοπής" #: src/commands/CommandManager.cpp:109 src/effects/nyquist/Nyquist.cpp:95 #: src/prefs/KeyConfigPrefs.cpp:804 src/prefs/MousePrefs.cpp:57 @@ -6260,7 +6261,7 @@ msgstr "Ενίσχυση (dB):" #: src/effects/Amplify.cpp:247 msgid "New Peak Amplitude (dB):" -msgstr "Νέα κορυφή πλάτους σήματος (dB):" +msgstr "Νέα πλάτος κορυφής (dB):" #: src/effects/Amplify.cpp:255 msgid "Allow clipping" @@ -8869,7 +8870,7 @@ msgstr "Απολαβή με αντήχηση" # i18n-hint: Title of the Gain slider, used to adjust the volume #: src/effects/Reverb.cpp:54 msgid "DryGain" -msgstr "Απολαβή ανεπεξέργαστου" +msgstr "Απολαβή αρχικού ήχου (DryGain)" #: src/effects/Reverb.cpp:55 msgid "StereoWidth" @@ -9733,7 +9734,7 @@ msgstr "" "εδώ ως Λατινική-1]" #: src/effects/nyquist/Nyquist.cpp:1638 -#, fuzzy, c-format +#, c-format msgid "" "Bad Nyquist 'control' type specification: '%s' in plug-in file '%s'.\n" "Control not created." @@ -9743,7 +9744,6 @@ msgstr "" "Το στοιχείο ελέγχου δεν δημιουργήθηκε." #: src/effects/nyquist/Nyquist.cpp:1746 -#, fuzzy msgid "" "Your code looks like SAL syntax, but there is no 'return' statement.\n" "For SAL, use a return statement such as:\n" @@ -9752,12 +9752,13 @@ msgid "" "\t(mult *track* 0.1)\n" " ." msgstr "" -"Ο κώδικας σας μοιάζει με σύνταξη SAL, αλλά δεν υπάρχει πρόταση επιστροφής. Ή " -"χρησιμοποιήστε μια πρόταση επιστροφής όπως\n" -" return s * 0.1\n" -"για SAL, ή αρχίστε με μια ανοικτή παρένθεση όπως\n" -" (mult s 0.1)\n" -" για LISP." +"Ο κώδικας σας μοιάζει με σύνταξη SAL, αλλά δεν υπάρχει πρόταση 'επιστροφής'." +"\n" +"Για SAL, χρησιμοποιήστε μια πρόταση επιστροφής όπως:\n" +" return *track* * 0.1\n" +"ή για LISP, αρχίστε με μια ανοικτή παρένθεση όπως:\n" +" (mult *track* 0.1)\n" +" ." #: src/effects/nyquist/Nyquist.cpp:1749 msgid "Error in Nyquist code" @@ -9967,9 +9968,8 @@ msgid "Error writing to file: \"%s\"" msgstr "Σφάλμα κατά την εγγραφή στο αρχείο: \"%s\"" #: src/effects/VST/VSTEffect.cpp:3565 -#, fuzzy msgid "Error Saving Effect Presets" -msgstr "Σφάλμα κατά την αποθήκευση του προεπιλογών VST" +msgstr "Σφάλμα αποθήκευσης των προεπιλογών εφέ" #: src/effects/VST/VSTEffect.cpp:3686 #, c-format @@ -10331,9 +10331,8 @@ msgstr "Άνοιγμα προσαρμοσμένων επιλογών μορφή #: src/export/ExportFFmpegDialogs.cpp:498 #: src/export/ExportFFmpegDialogs.cpp:522 -#, fuzzy msgid "Error Saving FFmpeg Presets" -msgstr "Σφάλμα κατά την αποθήκευση του προεπιλογών VST" +msgstr "Σφάλμα αποθήκευσης των προεπιλογών FFmpeg" #: src/export/ExportFFmpegDialogs.cpp:568 #, c-format @@ -11114,11 +11113,11 @@ msgstr "Η βιβλιοθήκη εξαγωγής MP3 δεν βρέθηκε" #: src/export/ExportMultiple.cpp:107 src/export/ExportMultiple.cpp:481 #: src/export/ExportMultiple.cpp:603 msgid "Export Multiple" -msgstr "Εξαγωγή πολλαπλών" +msgstr "Πολλαπλή εξαγωγή" #: src/export/ExportMultiple.cpp:182 src/export/ExportMultiple.cpp:192 msgid "Cannot Export Multiple" -msgstr "Δεν μπορεί να γίνει εξαγωγή πολλαπλών" +msgstr "Δεν μπορεί να γίνει πολλαπλή εξαγωγή" #: src/export/ExportMultiple.cpp:190 msgid "" @@ -11737,11 +11736,11 @@ msgstr "Αδύνατη η λήψη ενδιάμεσης μνήμης πλήρω #. i18n-hint: 'Raw' means 'unprocessed' here and should usually be tanslated. #: src/import/ImportRaw.cpp:238 msgid "Import Raw" -msgstr "Εισαγωγή ανεπεξέργαστων δεδομένων(Raw)" +msgstr "Εισαγωγή ανεπεξέργαστων δεδομένων (Raw)" #: src/import/ImportRaw.cpp:320 msgid "Import Raw Data" -msgstr "Εισάγονται ανεπεξέργαστα δεδομένα" +msgstr "Εισαγωγή ανεπεξέργαστων δεδομένων" # i18n-hint: Refers to byte-order. Don't translate "endianness" if you don't # know the correct technical word. @@ -11899,7 +11898,7 @@ msgstr "Φάκελοι" #: src/prefs/DirectoriesPrefs.cpp:82 msgid "Temporary files directory" -msgstr "Φάκελος προσωρινών αρχείων:" +msgstr "Κατάλογος προσωρινών αρχείων" #: src/prefs/DirectoriesPrefs.cpp:89 msgid "&Location:" @@ -11937,7 +11936,7 @@ msgstr "" #: src/prefs/DirectoriesPrefs.cpp:138 msgid "Choose a location to place the temporary directory" -msgstr "Επέλεξε την τοποθεσία του προσωρινού φακέλου" +msgstr "Επιλέξτε την τοποθεσία του προσωρινού καταλόγου" #: src/prefs/DirectoriesPrefs.cpp:191 msgid "unavailable - above location doesn't exist" @@ -11967,7 +11966,7 @@ msgid "" "Changes to temporary directory will not take effect until Audacity is " "restarted" msgstr "" -"Οι αλλαγές στο προσωρινό φάκελο δεν θα εφαρμοστούν μέχρι να γίνει " +"Οι αλλαγές στο προσωρινό κατάλογο δεν θα εφαρμοστούν μέχρι να γίνει " "επανεκκίνηση του Audacity" #: src/prefs/DirectoriesPrefs.cpp:252 @@ -12028,8 +12027,7 @@ msgstr "Έλεγχος για ενημερωμένα πρόσθετα όταν #: src/prefs/EffectsPrefs.cpp:145 msgid "Rescan plugins next time Audacity is started" -msgstr "" -"Να επανασαρώνονται τα πρόσθετα την επόμενη φορά που αρχίζει το Audacity" +msgstr "Να επανασαρώνονται τα πρόσθετα την επόμενη φορά που αρχίζει το Audacity" #: src/prefs/EffectsPrefs.cpp:153 msgid "Instruction Set" @@ -13352,8 +13350,7 @@ msgstr "" #: src/prefs/TracksPrefs.cpp:156 msgid "Editing a clip can &move other clips" -msgstr "" -"Η επεξεργασία ενός αποσπάσματος μπορεί να &μετακινήσει άλλα αποσπάσματα" +msgstr "Η επεξεργασία ενός αποσπάσματος μπορεί να &μετακινήσει άλλα αποσπάσματα" #: src/prefs/TracksPrefs.cpp:159 msgid "&Type to create a label" @@ -13385,7 +13382,7 @@ msgstr "Αποθήκευση &κενού έργου" #: src/prefs/WarningsPrefs.cpp:63 msgid "&Low disk space at program start up" -msgstr "&Λίγο χώρο στον δίσκο κατά την εκκίνηση του προγράμματος" +msgstr "&Λίγος χώρος στον δίσκο κατά την εκκίνηση του προγράμματος" #: src/prefs/WarningsPrefs.cpp:66 msgid "Mixing down to &mono during export" @@ -14346,9 +14343,8 @@ msgid "NaN" msgstr "NaN" #: src/widgets/numformatter.cpp:146 -#, fuzzy msgid "Infinity" -msgstr "-Άπειρο" +msgstr "Άπειρο" #: src/widgets/numformatter.cpp:150 msgid "-Infinity"