1#include "../CommonCommandFlags.h"
10#include "../ProjectSettings.h"
13#include "../ProjectWindows.h"
14#include "../SelectUtilities.h"
18#include "../TrackPanel.h"
19#include "../TrackUtilities.h"
27#include "../effects/EffectUI.h"
29#include "../tracks/playabletrack/wavetrack/ui/WaveTrackControls.h"
30#include "../toolbars/ToolManager.h"
31#include "../widgets/ASlider.h"
36#include <wx/combobox.h>
38#ifdef EXPERIMENTAL_SCOREALIGN
39#include "../effects/ScoreAlignDialog.h"
40#include "audioreader.h"
41#include "scorealign.h"
42#include "scorealign-glue.h"
59 tracks.MakeUniqueTrackName(
_(
"Mix")),
60 &trackFactory, rate, defaultFormat, 0.0, 0.0);
66 auto last = *trackRange.rbegin();
67 auto insertionPoint = * ++
tracks.Find(last);
69 auto selectedCount = trackRange.size();
72 while (!trackRange.empty())
73 tracks.Remove(**trackRange.first++);
77 const bool stereo = newTrack->
NChannels() > 1;
78 const auto firstName = newTrack->
GetName();
83 if (selectedCount >= 1)
84 pNewTrack->SetSelected(!toNewTrack);
90 std::vector<Track *> arr;
91 arr.reserve(
tracks.Size());
92 size_t iBegin = 0, ii = 0;
93 for (
const auto pTrack :
tracks) {
94 arr.push_back(pTrack);
95 if (pTrack == insertionPoint)
99 const auto end = arr.end(),
106 if (selectedCount == 1) {
107 auto msg =
XO(
"Rendered all audio in track '%s'").Format(firstName);
114 ?
XO(
"Mixed and rendered %d tracks into one new stereo track")
115 :
XO(
"Mixed and rendered %d tracks into one new mono track")
117 .
Format((
int)selectedCount);
121 trackPanel.SetFocus();
134 auto count = selectedRange.
size();
137 for (
auto left : count == 0 ? range : selectedRange )
138 left->SetPan( PanValue );
143 .
PushState(
XO(
"Panned audio track(s)"),
XO(
"Pan Track"), flags);
158static const std::vector< ComponentInterfaceSymbol >
159&
alignLabels() {
static std::vector< ComponentInterfaceSymbol > symbols{
160 {
wxT(
"StartToZero"),
XXO(
"Start to &Zero") },
161 {
wxT(
"StartToSelStart"),
XXO(
"Start to &Cursor/Selection Start") },
162 {
wxT(
"StartToSelEnd"),
XXO(
"Start to Selection &End") },
163 {
wxT(
"EndToSelStart"),
XXO(
"End to Cu&rsor/Selection Start") },
164 {
wxT(
"EndToSelEnd"),
XXO(
"End to Selection En&d") },
177 double newPos = -1.0;
184 auto firstTrackOffset = [&]{
return FindOffset( *trackRange.begin() ); };
185 auto minOffset = [&]{
return trackRange.min( FindOffset ); };
186 auto avgOffset = [&]{
187 return trackRange.sum( FindOffset ) /
188 std::max(
size_t(1), trackRange.size() ); };
190 auto maxEndOffset = [&]{
195 delta = -minOffset();
202 ?
XO(
"Aligned/Moved start to zero")
203 :
XO(
"Aligned start to zero");
204 shortAction = moveSel
207 ?
XO(
"Align/Move Start")
211 delta = selectedRegion.t0() - minOffset();
213 ?
XO(
"Aligned/Moved start to cursor/selection start")
214 :
XO(
"Aligned start to cursor/selection start");
215 shortAction = moveSel
216 ?
XO(
"Align/Move Start")
220 delta = selectedRegion.t1() - minOffset();
222 ?
XO(
"Aligned/Moved start to selection end")
223 :
XO(
"Aligned start to selection end");
224 shortAction = moveSel
225 ?
XO(
"Align/Move Start")
229 delta = selectedRegion.t0() - maxEndOffset();
231 ?
XO(
"Aligned/Moved end to cursor/selection start")
232 :
XO(
"Aligned end to cursor/selection start");
235 ?
XO(
"Align/Move End")
239 delta = selectedRegion.t1() - maxEndOffset();
241 ?
XO(
"Aligned/Moved end to selection end")
242 :
XO(
"Aligned end to selection end");
245 ?
XO(
"Align/Move End")
250 newPos = firstTrackOffset();
252 ?
XO(
"Aligned/Moved end to end")
253 :
XO(
"Aligned end to end");
256 ?
XO(
"Align/Move End to End")
257 :
XO(
"Align End to End");
260 newPos = avgOffset();
262 ?
XO(
"Aligned/Moved together")
263 :
XO(
"Aligned together");
266 ?
XO(
"Align/Move Together")
267 :
XO(
"Align Together");
278 newPos += (t->GetEndTime() - t->GetStartTime());
281 viewport.ZoomFitHorizontally();
286 for (
auto t :
tracks.Any()
288 t->MoveTo(t->GetStartTime() + delta);
292 selectedRegion.move(delta);
297#ifdef EXPERIMENTAL_SCOREALIGN
312#define AUDIO_WORK_UNIT 0.004F
313#define MIDI_WORK_UNIT 0.0001F
314#define MATRIX_WORK_UNIT 0.000002F
315#define SMOOTHING_WORK_UNIT 0.000001F
321#define COLLECT_TIMING_DATA
324class ASAProgress final :
public SAProgress {
331 std::optional<ProgressDialog> mProgress;
332 #ifdef COLLECT_TIMING_DATA
334 wxDateTime mStartTime;
341 #ifdef COLLECT_TIMING_DATA
342 mTimeFile = fopen(
"timing-data.txt",
"w");
346 #ifdef COLLECT_TIMING_DATA
350 void set_phase(
int i)
override {
352 float work2, work3 = 0;
353 SAProgress::set_phase(i);
354 #ifdef COLLECT_TIMING_DATA
356 wxDateTime now = wxDateTime::UNow();
357 wxFprintf(mTimeFile,
"Phase %d begins at %s\n",
358 i, now.FormatTime());
360 ms = now.Subtract(mStartTime).GetMilliseconds().ToLong();
365 for (
int j = 0; j < 2; j++) {
366 mFrames[j] = durations[j] / frame_period;
369 for (
int j = 0; j < 2; j++) {
371 (is_audio[j] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[j];
372 mTotalWork += work[j];
374 mTotalCells = mFrames[0] * mFrames[1];
375 work2 = mTotalCells * MATRIX_WORK_UNIT;
381 wxMax(mFrames[0], mFrames[1]) * SMOOTHING_WORK_UNIT * 40;
384 #ifdef COLLECT_TIMING_DATA
386 " mTotalWork (an estimate) = %g\n", mTotalWork);
387 wxFprintf(mTimeFile,
" work0 = %g, frames %g, is_audio %d\n",
388 work[0], mFrames[0], is_audio[0]);
389 wxFprintf(mTimeFile,
" work1 = %g, frames %g, is_audio %d\n",
390 work[1], mFrames[1], is_audio[1]);
391 wxFprintf(mTimeFile,
"work2 = %g, work3 = %g\n", work2, work3);
393 mProgress.emplace(
XO(
"Synchronize MIDI with Audio"),
394 XO(
"Synchronizing MIDI and Audio Tracks"));
397 "Phase %d took %d ms for %g frames, coefficient = %g s/frame\n",
398 i - 1, ms, mFrames[i - 1], (ms * 0.001) / mFrames[i - 1]);
401 "Phase 2 took %d ms for %d cells, coefficient = %g s/cell\n",
402 ms, mCellCount, (ms * 0.001) / mCellCount);
405 "Phase 3 took %d ms for %d iterations on %g frames, "
406 "coefficient = %g s per frame per iteration\n",
407 ms, iterations, wxMax(mFrames[0], mFrames[1]),
408 (ms * 0.001) / (wxMax(mFrames[0], mFrames[1]) * iterations));
411 bool set_feature_progress(
float s)
override {
414 float f = s / frame_period;
415 work = (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * f;
416 }
else if (phase == 1) {
417 float f = s / frame_period;
418 work = (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[0] +
419 (is_audio[1] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * f;
421 auto updateResult = mProgress->Update((
int)(work), (
int)(mTotalWork));
424 bool set_matrix_progress(
int cells)
override {
427 (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[0] +
428 (is_audio[1] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[1];
429 work += mCellCount * MATRIX_WORK_UNIT;
430 auto updateResult = mProgress->Update((
int)(work), (
int)(mTotalWork));
433 bool set_smoothing_progress(
int i)
override {
436 (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[0] +
437 (is_audio[1] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[1] +
438 MATRIX_WORK_UNIT * mFrames[0] * mFrames[1];
439 work += i * wxMax(mFrames[0], mFrames[1]) * SMOOTHING_WORK_UNIT;
440 auto updateResult = mProgress->Update((
int)(work), (
int)(mTotalWork));
446long mixer_process(
void *mixer,
float **buffer,
long n)
449 long frame_count = mix->
Process(std::max(0L, n));
463 auto GetTime = [](
const Track &t) {
464 return t.TypeSwitch<
double>(
466 auto stime = w.GetEndTime();
469 for (ndx = 0; ndx < w.GetNumClips(); ndx++) {
470 const auto c = w.GetClip(ndx);
471 if (c->GetVisibleSampleCount() == 0)
473 stime =
std::min(stime, c->GetPlayStartTime());
478 return l.GetStartTime();
483 std::vector<Track *> arr;
485 arr.reserve(
tracks.Size());
488 for (
const auto pTrack :
tracks) {
489 auto &track = *pTrack;
490 const auto size = arr.size();
492 for (; ndx <
size; ++ndx) {
493 Track &arrTrack = *arr[ndx];
505 track.GetName().CompareTo(arrTrack.
GetName()) > 0))
510 if (GetTime(track) < GetTime(arrTrack))
513 arr.insert(arr.begin() + ndx, &track);
523 float newValue = slider->
Get();
536 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, per-track real-time effects,...
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 return true if successful.
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
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
const PluginID & GetByCommandIdentifier(const CommandID &strTarget)
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 * VolumeSlider(CellularPanel &panel, const WaveTrack &wt)
static LWSlider * PanSlider(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.
size_t NChannels() const override
A constant property.
void SetVolume(float newVolume)
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.
bool DoEffect(const PluginID &ID, AudacityProject &project, unsigned flags)
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.