1#include "../CommonCommandFlags.h"
2#include "../LabelTrack.h"
10#include "../ProjectSettings.h"
13#include "../ProjectWindows.h"
14#include "../SelectUtilities.h"
18#include "../TrackPanel.h"
19#include "../TrackUtilities.h"
26#include "../effects/EffectManager.h"
27#include "../effects/EffectUI.h"
29#include "../tracks/playabletrack/wavetrack/ui/WaveTrackControls.h"
30#include "../toolbars/ToolManager.h"
31#include "../widgets/ASlider.h"
35#include <wx/combobox.h>
37#ifdef EXPERIMENTAL_SCOREALIGN
38#include "../effects/ScoreAlignDialog.h"
39#include "audioreader.h"
40#include "scorealign.h"
41#include "scorealign-glue.h"
58 tracks.MakeUniqueTrackName(
_(
"Mix")),
59 &trackFactory, rate, defaultFormat, 0.0, 0.0);
65 auto last = *trackRange.rbegin();
66 auto insertionPoint = * ++
tracks.Find(last);
68 auto selectedCount = trackRange.size();
71 while (!trackRange.empty())
72 tracks.Remove(**trackRange.first++);
76 const bool stereo = newTrack->
NChannels() > 1;
77 const auto firstName = newTrack->
GetName();
82 if (selectedCount >= 1)
83 pNewTrack->SetSelected(!toNewTrack);
89 std::vector<Track *> arr;
90 arr.reserve(
tracks.Size());
91 size_t iBegin = 0, ii = 0;
92 for (
const auto pTrack :
tracks) {
93 arr.push_back(pTrack);
94 if (pTrack == insertionPoint)
98 const auto end = arr.end(),
105 if (selectedCount == 1) {
106 auto msg =
XO(
"Rendered all audio in track '%s'").Format(firstName);
113 ?
XO(
"Mixed and rendered %d tracks into one new stereo track")
114 :
XO(
"Mixed and rendered %d tracks into one new mono track")
116 .
Format((
int)selectedCount);
120 trackPanel.SetFocus();
133 auto count = selectedRange.
size();
136 for (
auto left : count == 0 ? range : selectedRange )
137 left->SetPan( PanValue );
142 .
PushState(
XO(
"Panned audio track(s)"),
XO(
"Pan Track"), flags);
157static const std::vector< ComponentInterfaceSymbol >
158&
alignLabels() {
static std::vector< ComponentInterfaceSymbol > symbols{
159 {
wxT(
"StartToZero"),
XXO(
"Start to &Zero") },
160 {
wxT(
"StartToSelStart"),
XXO(
"Start to &Cursor/Selection Start") },
161 {
wxT(
"StartToSelEnd"),
XXO(
"Start to Selection &End") },
162 {
wxT(
"EndToSelStart"),
XXO(
"End to Cu&rsor/Selection Start") },
163 {
wxT(
"EndToSelEnd"),
XXO(
"End to Selection En&d") },
176 double newPos = -1.0;
183 auto firstTrackOffset = [&]{
return FindOffset( *trackRange.begin() ); };
184 auto minOffset = [&]{
return trackRange.min( FindOffset ); };
185 auto avgOffset = [&]{
186 return trackRange.sum( FindOffset ) /
187 std::max(
size_t(1), trackRange.size() ); };
189 auto maxEndOffset = [&]{
194 delta = -minOffset();
201 ?
XO(
"Aligned/Moved start to zero")
202 :
XO(
"Aligned start to zero");
203 shortAction = moveSel
206 ?
XO(
"Align/Move Start")
210 delta = selectedRegion.t0() - minOffset();
212 ?
XO(
"Aligned/Moved start to cursor/selection start")
213 :
XO(
"Aligned start to cursor/selection start");
214 shortAction = moveSel
215 ?
XO(
"Align/Move Start")
219 delta = selectedRegion.t1() - minOffset();
221 ?
XO(
"Aligned/Moved start to selection end")
222 :
XO(
"Aligned start to selection end");
223 shortAction = moveSel
224 ?
XO(
"Align/Move Start")
228 delta = selectedRegion.t0() - maxEndOffset();
230 ?
XO(
"Aligned/Moved end to cursor/selection start")
231 :
XO(
"Aligned end to cursor/selection start");
234 ?
XO(
"Align/Move End")
238 delta = selectedRegion.t1() - maxEndOffset();
240 ?
XO(
"Aligned/Moved end to selection end")
241 :
XO(
"Aligned end to selection end");
244 ?
XO(
"Align/Move End")
249 newPos = firstTrackOffset();
251 ?
XO(
"Aligned/Moved end to end")
252 :
XO(
"Aligned end to end");
255 ?
XO(
"Align/Move End to End")
256 :
XO(
"Align End to End");
259 newPos = avgOffset();
261 ?
XO(
"Aligned/Moved together")
262 :
XO(
"Aligned together");
265 ?
XO(
"Align/Move Together")
266 :
XO(
"Align Together");
277 newPos += (t->GetEndTime() - t->GetStartTime());
280 viewport.ZoomFitHorizontally();
285 for (
auto t :
tracks.Any()
287 t->MoveTo(t->GetStartTime() + delta);
291 selectedRegion.move(delta);
296#ifdef EXPERIMENTAL_SCOREALIGN
311#define AUDIO_WORK_UNIT 0.004F
312#define MIDI_WORK_UNIT 0.0001F
313#define MATRIX_WORK_UNIT 0.000002F
314#define SMOOTHING_WORK_UNIT 0.000001F
320#define COLLECT_TIMING_DATA
323class ASAProgress final :
public SAProgress {
330 std::optional<ProgressDialog> mProgress;
331 #ifdef COLLECT_TIMING_DATA
333 wxDateTime mStartTime;
340 #ifdef COLLECT_TIMING_DATA
341 mTimeFile = fopen(
"timing-data.txt",
"w");
345 #ifdef COLLECT_TIMING_DATA
349 void set_phase(
int i)
override {
351 float work2, work3 = 0;
352 SAProgress::set_phase(i);
353 #ifdef COLLECT_TIMING_DATA
355 wxDateTime now = wxDateTime::UNow();
356 wxFprintf(mTimeFile,
"Phase %d begins at %s\n",
357 i, now.FormatTime());
359 ms = now.Subtract(mStartTime).GetMilliseconds().ToLong();
364 for (
int j = 0; j < 2; j++) {
365 mFrames[j] = durations[j] / frame_period;
368 for (
int j = 0; j < 2; j++) {
370 (is_audio[j] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[j];
371 mTotalWork += work[j];
373 mTotalCells = mFrames[0] * mFrames[1];
374 work2 = mTotalCells * MATRIX_WORK_UNIT;
380 wxMax(mFrames[0], mFrames[1]) * SMOOTHING_WORK_UNIT * 40;
383 #ifdef COLLECT_TIMING_DATA
385 " mTotalWork (an estimate) = %g\n", mTotalWork);
386 wxFprintf(mTimeFile,
" work0 = %g, frames %g, is_audio %d\n",
387 work[0], mFrames[0], is_audio[0]);
388 wxFprintf(mTimeFile,
" work1 = %g, frames %g, is_audio %d\n",
389 work[1], mFrames[1], is_audio[1]);
390 wxFprintf(mTimeFile,
"work2 = %g, work3 = %g\n", work2, work3);
392 mProgress.emplace(
XO(
"Synchronize MIDI with Audio"),
393 XO(
"Synchronizing MIDI and Audio Tracks"));
396 "Phase %d took %d ms for %g frames, coefficient = %g s/frame\n",
397 i - 1, ms, mFrames[i - 1], (ms * 0.001) / mFrames[i - 1]);
400 "Phase 2 took %d ms for %d cells, coefficient = %g s/cell\n",
401 ms, mCellCount, (ms * 0.001) / mCellCount);
404 "Phase 3 took %d ms for %d iterations on %g frames, "
405 "coefficient = %g s per frame per iteration\n",
406 ms, iterations, wxMax(mFrames[0], mFrames[1]),
407 (ms * 0.001) / (wxMax(mFrames[0], mFrames[1]) * iterations));
410 bool set_feature_progress(
float s)
override {
413 float f = s / frame_period;
414 work = (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * f;
415 }
else if (phase == 1) {
416 float f = s / frame_period;
417 work = (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[0] +
418 (is_audio[1] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * f;
420 auto updateResult = mProgress->Update((
int)(work), (
int)(mTotalWork));
423 bool set_matrix_progress(
int cells)
override {
426 (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[0] +
427 (is_audio[1] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[1];
428 work += mCellCount * MATRIX_WORK_UNIT;
429 auto updateResult = mProgress->Update((
int)(work), (
int)(mTotalWork));
432 bool set_smoothing_progress(
int i)
override {
435 (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[0] +
436 (is_audio[1] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[1] +
437 MATRIX_WORK_UNIT * mFrames[0] * mFrames[1];
438 work += i * wxMax(mFrames[0], mFrames[1]) * SMOOTHING_WORK_UNIT;
439 auto updateResult = mProgress->Update((
int)(work), (
int)(mTotalWork));
445long mixer_process(
void *mixer,
float **buffer,
long n)
448 long frame_count = mix->
Process(std::max(0L, n));
462 auto GetTime = [](
const Track &t) {
463 return t.TypeSwitch<
double>(
465 auto stime = w.GetEndTime();
468 for (ndx = 0; ndx < w.GetNumClips(); ndx++) {
469 const auto c = w.GetClip(ndx);
470 if (c->GetVisibleSampleCount() == 0)
472 stime =
std::min(stime, c->GetPlayStartTime());
477 return l.GetStartTime();
482 std::vector<Track *> arr;
484 arr.reserve(
tracks.Size());
487 for (
const auto pTrack :
tracks) {
488 auto &track = *pTrack;
489 const auto size = arr.size();
491 for (; ndx <
size; ++ndx) {
492 Track &arrTrack = *arr[ndx];
504 track.GetName().CompareTo(arrTrack.
GetName()) > 0))
509 if (GetTime(track) < GetTime(arrTrack))
512 arr.insert(arr.begin() + ndx, &track);
522 float newValue = slider->
Get();
535 float newValue = slider->
Get();
588 rate.Printf(
wxT(
"%ld"),
lrint(projectRate));
606 S.StartVerticalLay(
true);
610 S.StartHorizontalLay(wxCENTER,
false);
612 cb =
S.AddCombo(
XXO(
"New sample rate (Hz):"),
616 S.EndHorizontalLay();
620 S.AddStandardButtons();
628 if (dlg.ShowModal() != wxID_OK)
632 if (cb->GetValue().ToLong(&lrate) && lrate >= 1 && lrate <= 1000000) {
633 newRate = (int)lrate;
638 XO(
"The entered value is invalid"),
647 auto msg =
XO(
"Resampling track %d").Format(++ndx);
657 wt->Resample(newRate, progress.get());
664 XO(
"Resampled audio track(s)"),
XO(
"Resample Track"), flags);
668 undoManager.StopConsolidating();
689 for (
auto pt : iter) {
749 gPrefs->
Read(
wxT(
"/GUI/MoveSelectionWithTracks"), &bMoveWith,
false);
764 gPrefs->
Read(
wxT(
"/GUI/MoveSelectionWithTracks"), &bMoveWith,
false);
770#ifdef EXPERIMENTAL_SCOREALIGN
777 int numWaveTracksSelected = 0;
778 int numNoteTracksSelected = 0;
779 int numOtherTracksSelected = 0;
780 double endTime = 0.0;
786 numWaveTracksSelected++;
790 numNoteTracksSelected++;
793 numOtherTracksSelected++;
797 if(numWaveTracksSelected == 0 ||
798 numNoteTracksSelected != 1 ||
799 numOtherTracksSelected != 0){
801 XO(
"Please select at least one audio track and one MIDI track.") );
813 CloseScoreAlignDialog();
815 if (
params.mStatus != wxID_OK)
return;
821 auto holder = nt->Duplicate();
822 auto alignedNoteTrack =
static_cast<NoteTrack*
>(holder.get());
825 if (alignedNoteTrack->GetOffset() < 0) {
827 nt->
Clear(alignedNoteTrack->GetOffset(), 0);
828 }
else if (alignedNoteTrack->GetOffset() > 0) {
829 alignedNoteTrack->Shift(alignedNoteTrack->GetOffset());
831 alignedNoteTrack->MoveTo(0);
834 tracks->GetWaveTrackConstArray(
true );
852 ASAProgress progress;
860#ifndef SKIP_ACTUAL_SCORE_ALIGNMENT
861 result = scorealign((
void *) &mix, &mixer_process,
862 2 , 44100.0 , endTime,
863 &alignedNoteTrack->GetSeq(), &progress,
params);
869 if (result == SA_SUCCESS) {
870 tracks->Replace(nt, holder);
872 XO(
"Alignment completed: MIDI from %.2f to %.2f secs, Audio from %.2f to %.2f secs.")
877 .
PushState(
XO(
"Sync MIDI with Audio"),
XO(
"Sync MIDI with Audio"));
878 }
else if (result == SA_TOOSHORT) {
881"Alignment error: input too short: MIDI from %.2f to %.2f secs, Audio from %.2f to %.2f secs.")
885 }
else if (result == SA_CANCEL) {
925 trackPanel.Refresh(
false);
936 if (track) track->TypeSwitch( [&](
WaveTrack &wt) {
949 if (track) track->TypeSwitch( [&](
WaveTrack &wt) {
962 if (track) track->TypeSwitch( [&](
WaveTrack &wt) {
976 if (track) track->TypeSwitch( [&](
WaveTrack &wt) {
989 if (track) track->TypeSwitch( [&](
WaveTrack &wt) {
1002 if (track) track->TypeSwitch( [&](
WaveTrack &wt) {
1014 trackPanel.OnTrackMenu();
1055 XO(
"Can't delete track with active audio"));
1062 trackPanel.UpdateViewIfNoTracks();
1063 trackPanel.Refresh(
false);
1073 if (focusedTrack &&
tracks.CanMoveUp(*focusedTrack)) {
1075 trackPanel.Refresh(
false);
1086 if (focusedTrack &&
tracks.CanMoveDown(*focusedTrack)) {
1088 trackPanel.Refresh(
false);
1099 if (focusedTrack &&
tracks.CanMoveUp(*focusedTrack)) {
1101 trackPanel.Refresh(
false);
1112 if (focusedTrack &&
tracks.CanMoveDown(*focusedTrack)) {
1114 trackPanel.Refresh(
false);
1125 static auto menu = std::shared_ptr{
1155 XXO(
"Mix and Render to Ne&w Track"),
1204 {
wxT(
"EndToEnd"),
XXO(
"&Align End to End") },
1205 {
wxT(
"Together"),
XXO(
"Align &Together") },
1219 XXO(
"&Move Selection with Tracks"),
1229 Menu(
wxT(
"MoveSelectionAndTracks"),
XO(
"Move Sele&ction and Tracks"), {
1237 #ifdef EXPERIMENTAL_SCOREALIGN
1238 Command(
wxT(
"ScoreAlign"),
XXO(
"Synchronize MIDI with Audio"),
1258 Command(
wxT(
"SyncLock"),
XXO(
"Keep tracks synchronized (Sync-&Lock)"),
1271 static auto menu = std::shared_ptr{
1273 Command(
wxT(
"TrackPan"),
XXO(
"Change P&an on Focused Track..."),
1276 Command(
wxT(
"TrackPanLeft"),
XXO(
"Pan &Left on Focused Track"),
1279 Command(
wxT(
"TrackPanRight"),
XXO(
"Pan &Right on Focused Track"),
1282 Command(
wxT(
"TrackGain"),
XXO(
"Change Gai&n on Focused Track..."),
1285 Command(
wxT(
"TrackGainInc"),
XXO(
"&Increase Gain on Focused Track"),
1288 Command(
wxT(
"TrackGainDec"),
XXO(
"&Decrease Gain on Focused Track"),
1291 Command(
wxT(
"TrackMenu"),
XXO(
"Op&en Menu on Focused Track..."),
1295 Command(
wxT(
"TrackMute"),
XXO(
"M&ute/Unmute Focused Track"),
1298 Command(
wxT(
"TrackSolo"),
XXO(
"&Solo/Unsolo Focused Track"),
1308 Command(
wxT(
"TrackMoveDown"),
XXO(
"Move Focused Track Do&wn"),
1311 Command(
wxT(
"TrackMoveTop"),
XXO(
"Move Focused Track to T&op"),
1314 Command(
wxT(
"TrackMoveBottom"),
XXO(
"Move Focused Track to &Bottom"),
1322 wxT(
"Optional/Extra/Part2")
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
AttachedItem sAttachment1
AttachedItem sAttachment2
constexpr CommandFlag AlwaysEnabledFlag
const ReservedCommandFlag & AudioIONotBusyFlag()
const ReservedCommandFlag & StereoRequiredFlag()
const ReservedCommandFlag & EditableTracksSelectedFlag()
const ReservedCommandFlag & AnyTracksSelectedFlag()
const ReservedCommandFlag & TracksExistFlag()
const ReservedCommandFlag & WaveTracksSelectedFlag()
const ReservedCommandFlag & TrackPanelHasFocus()
EffectDistortionSettings params
XXO("&Cut/Copy/Paste Toolbar")
Track::Holder MixAndRender(const TrackIterRange< const WaveTrack > &trackRange, const Mixer::WarpOptions &warpOptions, const wxString &newTrackName, WaveTrackFactory *trackFactory, double rate, sampleFormat format, double startTime, double endTime)
Mixes together all input tracks, applying any envelopes, amplitude gain, panning, and real-time effec...
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
EnumSetting< SoloBehavior > TracksBehaviorsSolo
audacity::BasicSettings * gPrefs
an object holding per-project preferred sample rate
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
BoolSetting SyncLockTracks
static Settings & settings()
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Track subclass holding data representing sound (as notes, or samples, or ...)
bool Toggle()
Write the negation of the previous value, and then return the current value.
double GetEndTime() const
Get the maximum of End() values of intervals, or 0 when none.
double GetStartTime() const
Get the minimum of Start() values of intervals, or 0 when none.
size_t size() const
How many attachment pointers are in the Site.
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
TemporarySelection temporarySelection
AudacityProject & project
static EffectManager & Get()
const PluginID & GetEffectByIdentifier(const CommandID &strTarget)
Lightweight version of ASlider. In other words it does not have a window permanently associated with ...
void Decrease(float steps)
void Increase(float steps)
float Get(bool convert=true)
A LabelTrack is a Track that holds labels (LabelStruct).
Functions for doing the mixdown of the tracks.
size_t Process(size_t maxSamples)
constSamplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
A Track that is used for Midi notes. (Somewhat old code).
void Clear(double t0, double t1) override
AudioTrack subclass that can also be audibly replayed by the program.
const PluginDescriptor * GetPlugin(const PluginID &ID) const
static PluginManager & Get()
bool IsAudioActive() const
static ProjectAudioIO & Get(AudacityProject &project)
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
static ProjectRate & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
static ProjectStatus & Get(AudacityProject &project)
void Set(const TranslatableString &msg, StatusBarField field=MainStatusBarField())
Generates classes whose instances register items at construction.
ScoreAlignDialog is \TODO.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
static bool IsSelectedOrSyncLockSelectedP(const Track *pTrack)
Abstract base class for an object holding data associated with points on a time axis.
const wxString & GetName() const
Name is always the same for all channels of a group.
static TrackList & Get(AudacityProject &project)
auto Selected() -> TrackIterRange< TrackType >
static TrackPanel & Get(AudacityProject &project)
void RefreshTrack(Track *trk, bool refreshbacking=true)
Holds a msgid for the translation catalog; may also bind format arguments.
static UndoManager & Get(AudacityProject &project)
NotifyingSelectedRegion selectedRegion
static ViewInfo & Get(AudacityProject &project)
void ShowTrack(const Track &track)
static Viewport & Get(AudacityProject &project)
static LWSlider * PanSlider(CellularPanel &panel, const WaveTrack &wt)
static LWSlider * GainSlider(CellularPanel &panel, const WaveTrack &wt)
static WaveTrackFactory & Get(AudacityProject &project)
A Track that contains audio waveform data.
void SetPan(float newPan)
double GetEndTime() const override
Implement WideSampleSequence.
void SetGain(float newGain)
size_t NChannels() const override
A constant property.
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
std::unique_ptr< ProgressDialog > MakeProgress(const TranslatableString &title, const TranslatableString &message, unsigned flags=(ProgressShowStop|ProgressShowCancel), const TranslatableString &remainingLabelText={})
Create and display a progress dialog.
AUDACITY_DLL_API bool DoEffect(const PluginID &ID, const CommandContext &context, unsigned flags)
'Repeat Last Effect'.
PROJECT_RATE_API sampleFormat SampleFormatChoice()
std::unique_ptr< detail::IndirectItem< Item > > Indirect(const std::shared_ptr< Item > &ptr)
A convenience function.
AUDACITY_DLL_API void DoMoveTrack(AudacityProject &project, Track &target, MoveChoice choice)
Move a track up, down, to top or to bottom.
AUDACITY_DLL_API void DoRemoveTrack(AudacityProject &project, Track &toRemove)
AUDACITY_DLL_API void DoTrackSolo(AudacityProject &project, Track &track, bool exclusive)
AUDACITY_DLL_API void DoTrackMute(AudacityProject &project, Track &track, bool exclusive)
"exclusive" mute means mute the chosen track and unmute all others.
AUDACITY_DLL_API void DoRemoveTracks(AudacityProject &)
const char * end(const char *str) noexcept
void rotate(const float *oldPhase, const float *newPhase, std::complex< float > *dst, int32_t n)
Immutable structure is an argument to Mixer's constructor.