Audacity 3.2.0
ImportAUP.cpp
Go to the documentation of this file.
1/*!********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file ImportAUP.cpp
6 @brief Upgrading project file formats from before version 3
7
8*//****************************************************************//****************************************************************//*******************************************************************/
19
20
21
22#include "Import.h"
23#include "ImportPlugin.h"
25
26#include "Envelope.h"
27#include "FileFormats.h"
28#include "LabelTrack.h"
29#if defined(USE_MIDI)
30#include "NoteTrack.h"
31#endif
32#include "Project.h"
33#include "ProjectFileManager.h"
34#include "ProjectHistory.h"
36#include "ProjectRate.h"
37#include "ProjectSnap.h"
38#include "ProjectWindows.h"
39#include "Sequence.h"
40#include "Tags.h"
41#include "TimeTrack.h"
42#include "ViewInfo.h"
43#include "WaveClip.h"
44#include "WaveTrack.h"
46#include "XMLFileReader.h"
47#include "wxFileNameWrapper.h"
48#include "ImportUtils.h"
49
51
52#include <map>
53
54#define DESC XO("AUP project files (*.aup)")
55
56static const auto exts = {wxT("aup")};
57
58#include <wx/dir.h>
59#include <wx/ffile.h>
60#include <wx/file.h>
61#include <wx/log.h>
62#include <wx/string.h>
63
65using ImportHandle = std::unique_ptr<ImportFileHandle>;
66
67class AUPImportPlugin final : public ImportPlugin
68{
69public:
72
73 wxString GetPluginStringID() override;
74
76
77 ImportHandle Open(const FilePath &fileName,
78 AudacityProject *project) override;
79};
80
82 public XMLTagHandler
83{
84public:
88
89 TranslatableString GetErrorMessage() const override;
90
92
94
95 void Import(
96 ImportProgressListener& progressListener, WaveTrackFactory* trackFactory,
97 TrackHolders& outTracks, Tags* tags,
98 std::optional<LibFileFormats::AcidizerTags>& outAcidTags) override;
99
100 wxInt32 GetStreamCount() override;
101
102 const TranslatableStrings &GetStreamInfo() override;
103
104 void SetStreamUsage(wxInt32 WXUNUSED(StreamID), bool WXUNUSED(Use)) override;
105
106 bool Open();
107
108private:
109 struct node
110 {
111 wxString parent;
112 wxString tag;
114 };
115 using stack = std::vector<struct node>;
116
117 bool HandleXMLTag(const std::string_view& tag, const AttributesList &attrs) override;
118 void HandleXMLEndTag(const std::string_view& tag) override;
119 XMLTagHandler *HandleXMLChild(const std::string_view& tag) override;
120
121 bool HandleProject(XMLTagHandler *&handle);
122 bool HandleLabelTrack(XMLTagHandler *&handle);
123 bool HandleNoteTrack(XMLTagHandler *&handle);
124 bool HandleTimeTrack(XMLTagHandler *&handle);
125 bool HandleWaveTrack(XMLTagHandler *&handle);
126 bool HandleTags(XMLTagHandler *&handle);
127 bool HandleTag(XMLTagHandler *&handle);
128 bool HandleLabel(XMLTagHandler *&handle);
129 bool HandleWaveClip(XMLTagHandler *&handle);
130 bool HandleSequence(XMLTagHandler *&handle);
131 bool HandleWaveBlock(XMLTagHandler *&handle);
132 bool HandleEnvelope(XMLTagHandler *&handle);
133 bool HandleControlPoint(XMLTagHandler *&handle);
137 bool HandleImport(XMLTagHandler *&handle);
138
139 // Called in first pass to collect information about blocks
140 void AddFile(sampleCount len,
142 const FilePath &blockFilename = wxEmptyString,
143 const FilePath &audioFilename = wxEmptyString,
144 sampleCount origin = 0,
145 int channel = 0);
146
147 // These two use the collected file information in a second pass
148 bool AddSilence(sampleCount len);
149 bool AddSamples(const FilePath &blockFilename,
150 const FilePath &audioFilename,
151 sampleCount len,
153 sampleCount origin = 0,
154 int channel = 0);
155
156 bool SetError(const TranslatableString &msg);
157 bool SetWarning(const TranslatableString &msg);
158
159private:
162
163 // project tag values that will be set in the actual project if the
164 // import is successful
165 #define field(n, t) bool have##n; t n
166 struct
167 {
168 field(vpos, int);
169 field(h, double);
170 field(zoom, double);
171 field(sel0, double);
172 field(sel1, double);
174 field(selHigh, double) = SelectedRegion::UndefinedFrequency;
175 field(rate, double);
176 field(snapto, bool);
177 field(selectionformat, wxString);
178 field(audiotimeformat, wxString);
179 field(frequencyformat, wxString);
180 field(bandwidthformat, wxString);
182 #undef field
183
184 typedef struct
185 {
194 } fileinfo;
195 std::vector<fileinfo> mFiles;
197
199 unsigned long mNumChannels;
200
202 std::string mParentTag;
203 std::string mCurrentTag;
205
206 wxFileName mProjDir;
208 std::map<wxString, std::pair<FilePath, std::shared_ptr<SampleBlock>>>;
210
213 std::vector<WaveClip *> mClips;
214
216 bool mHasParseError { false };
217};
218
219namespace
220{
221// RHS is expected to be lowercase
223 const std::string_view& lhs, const std::string_view& rhsLower)
224{
225 if (lhs.length() != rhsLower.length())
226 return false;
227
228 for (size_t i = 0; i < lhs.length(); ++i)
229 if (std::tolower(lhs[i]) != rhsLower[i])
230 return false;
231
232 return true;
233}
234} // namespace
235
238{
239 static_assert(
240 sizeof(long long) >= sizeof(uint64_t) &&
241 sizeof(long) >= sizeof(uint32_t),
242 "Assumptions about sizes in XMLValueChecker calls are invalid!");
243}
244
246{
247}
248
250{
251 return wxT("legacyaup");
252}
253
255{
256 return DESC;
257}
258
261{
262 auto handle = std::make_unique<AUPImportFileHandle>(fileName, project);
263
264 if (!handle->Open())
265 {
266 // Error or not something that we recognize
267 return nullptr;
268 }
269
270 return handle;
271}
272
274{
275 "AUP", std::make_unique<AUPImportPlugin>()
276};
277
280: ImportFileHandleEx(fileName),
281 mProject(*project)
282{
283}
284
286{
287}
288
290{
291 return DESC;
292}
293
295{
296 return mErrorMsg;
297}
298
300{
301 // TODO: Get Uncompressed byte count.
302 return 0;
303}
304
307 Tags* tags, std::optional<LibFileFormats::AcidizerTags>&)
308{
309 BeginImport();
310
311 mHasParseError = false;
312
313 auto &history = ProjectHistory::Get(mProject);
315 auto &viewInfo = ViewInfo::Get(mProject);
316 auto &formats = ProjectNumericFormats::Get(mProject);
317
318 auto oldNumTracks = tracks.Size();
319 auto cleanup = finally([this, &tracks, oldNumTracks]{
320 if (mHasParseError || IsCancelled()) {
321 // Revoke additions of tracks
322 while (oldNumTracks < tracks.Size())
323 tracks.Remove(**tracks.end().advance(-1));
324 }
325 });
326
327 bool isDirty = history.GetDirty() || !tracks.empty();
328
329 mTotalSamples = 0;
330
331 mTags = tags;
332
333 XMLFileReader xmlFile;
334
335 bool success = xmlFile.Parse(this, GetFilename());
336 if (!success)
337 {
338 mErrorMsg = XO("Couldn't import the project:\n\n%s").Format(xmlFile.GetErrorStr());
340 return;
341 }
342
344 {
346 return;
347 }
348 if(!mErrorMsg.empty())//i.e. warning
349 {
351 mErrorMsg = {};
352 }
353
354 // (If we keep this entire source file at all)
355
356 sampleCount processed = 0;
357 for (auto fi : mFiles)
358 {
359 if(mTotalSamples.as_double() > 0)
360 progressListener.OnImportProgress(processed.as_double() / mTotalSamples.as_double());
361 if(IsCancelled())
362 {
364 return;
365 }
366 else if(IsStopped())
367 {
369 return;
370 }
371 mClip = fi.clip;
372 mWaveTrack = fi.track;
373
374 if (fi.blockFile.empty())
375 {
376 AddSilence(fi.len);
377 }
378 else
379 {
380 if (!AddSamples(fi.blockFile, fi.audioFile,
381 fi.len, fi.format, fi.origin, fi.channel))
382 {
384 return;
385 }
386 }
387
388 processed += fi.len;
389 }
390
391 for (auto pClip : mClips)
392 pClip->UpdateEnvelopeTrackLen();
393
395 tracks,
396 [&](const auto& errorMessage) { SetError(errorMessage); },
397 [&](const auto& unlinkReason) { SetWarning(XO(
398//i18n-hint: Text of the message dialog that may appear on attempt
399//to import an AUP project.
400//%s will be replaced with an explanation of the actual reason of
401//project modification.
402"%s\n"
403"This feature is not supported in Audacity versions past 3.3.3.\n"
404"These stereo tracks have been split into mono tracks.\n"
405"Please verify that everything works as intended before saving.")
406 .Format(unlinkReason));
407 }
408 );
409
411 {
413 return;
414 }
415 if(!mErrorMsg.empty())
416 {
418 mErrorMsg = {};
419 }
420
421 // If the active project is "dirty", then bypass the below updates as we don't
422 // want to going changing things the user may have already set up.
423 if (isDirty)
424 {
426 return;
427 }
428
429 if (mProjectAttrs.haverate)
431
432 if (mProjectAttrs.havesnapto)
433 {
436 }
437
438 if (mProjectAttrs.haveselectionformat)
439 {
440 formats.SetSelectionFormat(mProjectAttrs.selectionformat);
441 }
442
443 if (mProjectAttrs.haveaudiotimeformat)
444 {
445 formats.SetAudioTimeFormat(mProjectAttrs.audiotimeformat);
446 }
447
448 if (mProjectAttrs.havefrequencyformat)
449 {
450 formats.SetFrequencySelectionFormatName(mProjectAttrs.frequencyformat);
451 }
452
453 if (mProjectAttrs.havebandwidthformat)
454 {
455 formats.SetBandwidthSelectionFormatName(mProjectAttrs.bandwidthformat);
456 }
457
458 // PRL: It seems this must happen after SetSnapTo
459 if (mProjectAttrs.havevpos)
460 {
461 viewInfo.vpos = mProjectAttrs.vpos;
462 }
463
464 if (mProjectAttrs.haveh)
465 {
466 viewInfo.hpos = mProjectAttrs.h;
467 }
468
469 if (mProjectAttrs.havezoom)
470 {
471 viewInfo.SetZoom(mProjectAttrs.zoom);
472 }
473
474 if (mProjectAttrs.havesel0)
475 {
476 viewInfo.selectedRegion.setT0(mProjectAttrs.sel0);
477 }
478
479 if (mProjectAttrs.havesel1)
480 {
481 viewInfo.selectedRegion.setT1(mProjectAttrs.sel1);
482 }
483
484 if (mProjectAttrs.haveselLow)
485 {
486 viewInfo.selectedRegion.setF0(mProjectAttrs.selLow);
487 }
488
489 if (mProjectAttrs.haveselHigh)
490 {
491 viewInfo.selectedRegion.setF1(mProjectAttrs.selHigh);
492 }
493
495}
496
498{
499 return 1;
500}
501
503{
504 static TranslatableStrings empty;
505 return empty;
506}
507
508void AUPImportFileHandle::SetStreamUsage(wxInt32 WXUNUSED(StreamID), bool WXUNUSED(Use))
509{
510}
511
513{
514 wxFFile ff(GetFilename(), wxT("rb"));
515 if (ff.IsOpened())
516 {
517 char buf[256];
518
519 int numRead = ff.Read(buf, sizeof(buf));
520
521 ff.Close();
522
523 buf[sizeof(buf) - 1] = '\0';
524
525 if (!wxStrncmp(buf, wxT("AudacityProject"), 15))
526 {
528 XO("This project was saved by Audacity version 1.0 or earlier. The format has\n"
529 "changed and this version of Audacity is unable to import the project.\n\n"
530 "Use a version of Audacity prior to v3.0.0 to upgrade the project and then\n"
531 "you may import it with this version of Audacity."));
532 return false;
533 }
534
535 if (wxStrncmp(buf, "<?xml", 5) == 0 &&
536 (wxStrstr(buf, "<audacityproject") ||
537 wxStrstr(buf, "<project") ))
538 {
539 return true;
540 }
541 }
542
543 return false;
544}
545
547{
548 return this;
549}
550
551void AUPImportFileHandle::HandleXMLEndTag(const std::string_view& tag)
552{
553 if (mHasParseError)
554 {
555 return;
556 }
557
558 struct node node = mHandlers.back();
559
560 if (tag == WaveClip::WaveClip_tag)
561 {
562 mClip = nullptr;
563 }
564
565 if (node.handler)
566 {
568 }
569
570 if (tag == WaveTrack::WaveTrack_tag)
572
573 mHandlers.pop_back();
574
575 if (mHandlers.size())
576 {
577 node = mHandlers.back();
580 }
581}
582
583bool AUPImportFileHandle::HandleXMLTag(const std::string_view& tag, const AttributesList &attrs)
584{
585 if (mHasParseError)
586 {
587 return false;
588 }
589
591 mCurrentTag = std::string(tag);
592 mAttrs = attrs;
593
594 XMLTagHandler *handler = nullptr;
595 bool success = false;
596
597 if (mCurrentTag == "project" ||
598 mCurrentTag == "audacityproject")
599 {
600 success = HandleProject(handler);
601 }
602 else if (mCurrentTag == "labeltrack")
603 {
604 success = HandleLabelTrack(handler);
605 }
606 else if (mCurrentTag == "notetrack")
607 {
608 success = HandleNoteTrack(handler);
609 }
610 else if (mCurrentTag == "timetrack")
611 {
612 success = HandleTimeTrack(handler);
613 }
615 {
616 success = HandleWaveTrack(handler);
617 }
618 else if (mCurrentTag == "tags")
619 {
620 success = HandleTags(handler);
621 }
622 else if (mCurrentTag == "tag")
623 {
624 success = HandleTag(handler);
625 }
626 else if (mCurrentTag == "label")
627 {
628 success = HandleLabel(handler);
629 }
631 {
632 success = HandleWaveClip(handler);
633 }
635 {
636 success = HandleSequence(handler);
637 }
639 {
640 success = HandleWaveBlock(handler);
641 }
642 else if (mCurrentTag == "envelope")
643 {
644 success = HandleEnvelope(handler);
645 }
646 else if (mCurrentTag == "controlpoint")
647 {
648 success = HandleControlPoint(handler);
649 }
650 else if (mCurrentTag == "simpleblockfile")
651 {
653 }
654 else if (mCurrentTag == "silentblockfile")
655 {
657 }
658 else if (mCurrentTag == "pcmaliasblockfile")
659 {
661 }
662 else if (mCurrentTag == "import")
663 {
664 success = HandleImport(handler);
665 }
666
667 if (!success || (handler && !handler->HandleXMLTag(tag, attrs)))
668 {
669 return SetError(XO("Internal error in importer...tag not recognized"));
670 }
671
673
674 return true;
675}
676
678{
679 auto &fileMan = ProjectFileManager::Get(mProject);
680 auto &window = GetProjectFrame(mProject);
681
682 int requiredTags = 0;
683
684 for (auto pair : mAttrs)
685 {
686 auto attr = pair.first;
687 auto value = pair.second;
688
689 double dValue;
690
691#define set(f, v) (mProjectAttrs.have ## f = true, mProjectAttrs.f = v)
692
693 // ViewInfo
694 if (attr == "vpos")
695 {
696 long lValue;
697 if (!value.TryGet(lValue) || (lValue < 0))
698 {
699 return SetError(XO("Invalid project 'vpos' attribute."));
700 }
701
702 set(vpos, (int) lValue);
703 }
704 else if (attr == "h")
705 {
706 if (!value.TryGet(dValue))
707 {
708 return SetError(XO("Invalid project 'h' attribute."));
709 }
710
711 set(h, dValue);
712 }
713 else if (attr == "zoom")
714 {
715 if (!value.TryGet(dValue) || (dValue < 0.0))
716 {
717 return SetError(XO("Invalid project 'zoom' attribute."));
718 }
719
720 set(zoom, dValue);
721 }
722 // Viewinfo.SelectedRegion
723 else if (attr == "sel0")
724 {
725 if (!value.TryGet(dValue))
726 {
727 return SetError(XO("Invalid project 'sel0' attribute."));
728 }
729
730 set(sel0, dValue);
731 }
732 else if (attr == "sel1")
733 {
734 if (!value.TryGet(dValue))
735 {
736 return SetError(XO("Invalid project 'sel1' attribute."));
737 }
738
739 set(sel1, dValue);
740 }
741 else if (attr == "selLow")
742 {
743 if (!value.TryGet(dValue) || (dValue < 0.0))
744 {
745 return SetError(XO("Invalid project 'selLow' attribute."));
746 }
747
748 set(selLow, dValue);
749 }
750 else if (attr == "selHigh")
751 {
752 if (!value.TryGet(dValue) || (dValue < 0.0))
753 {
754 return SetError(XO("Invalid project 'selHigh' attribute."));
755 }
756
757 set(selHigh, dValue);
758 }
759 else if (attr == "version")
760 {
761 requiredTags++;
762 }
763
764 else if (attr == "audacityversion")
765 {
766 requiredTags++;
767 }
768 else if (attr == "projname")
769 {
770 requiredTags++;
771
773 wxString altname = mProjDir.GetName() + wxT("_data");
774 mProjDir.SetFullName(wxEmptyString);
775
776 wxString projName = value.ToWString();
777 bool found = false;
778
779 // First try to load the data files based on the _data dir given in the .aup file
780 if (!projName.empty())
781 {
782 mProjDir.AppendDir(projName);
783 if (!mProjDir.DirExists())
784 {
785 mProjDir.RemoveLastDir();
786 projName.clear();
787 }
788 }
789
790 // If that fails then try to use the filename of the .aup as the base directory
791 // This is because unzipped projects e.g. those that get transferred between mac-pc
792 // may have encoding issues and end up expanding the wrong filenames for certain
793 // international characters (such as capital 'A' with an umlaut.)
794 if (projName.empty())
795 {
796 projName = altname;
797 mProjDir.AppendDir(projName);
798 if (!mProjDir.DirExists())
799 {
800 projName.clear();
801 }
802 }
803
804 // No luck...complain and bail
805 if (projName.empty())
806 {
808 XO("Couldn't find the project data folder: \"%s\"").Format(value.ToWString()));
809 return false;
810 }
811
812 // Collect and hash the file names within the project directory
813 wxArrayString files;
814 size_t cnt = wxDir::GetAllFiles(mProjDir.GetFullPath(),
815 &files,
816 "*.*");
817
818 for (const auto &fn : files)
819 {
820 mFileMap[wxFileNameFromPath(fn)] = {fn, {}};
821 }
822 }
823 else if (attr == "rate")
824 {
825 if (!value.TryGet(dValue) || (dValue < 0.0))
826 {
827 return SetError(XO("Invalid project 'selLow' attribute."));
828 }
829
830 set(rate, dValue);
831 }
832
833 else if (attr == "snapto")
834 {
835 set(snapto, (value.ToWString() == "on" ? true : false));
836 }
837
838 else if (attr == "selectionformat")
839 {
840 set(selectionformat, value.ToWString());
841 }
842
843 else if (attr == "frequencyformat")
844 {
845 set(frequencyformat, value.ToWString());
846 }
847
848 else if (attr == "bandwidthformat")
849 {
850 set(bandwidthformat, value.ToWString());
851 }
852#undef set
853 }
854
855 if (requiredTags < 3)
856 {
857 return false;
858 }
859
860 // Do not set the handler - already handled
861
862 return true;
863}
864
866{
867 handler = TrackList::Get(mProject).Add(std::make_shared<LabelTrack>());
868
869 return true;
870}
871
873{
874#if defined(USE_MIDI)
875 handler = TrackList::Get(mProject).Add(std::make_shared<NoteTrack>());
876
877 return true;
878#else
880 XO("MIDI tracks found in project file, but this build of Audacity does not include MIDI support, bypassing track."));
881 return false;
882#endif
883}
884
886{
888
889 // Bypass this timetrack if the project already has one
890 // (See HandleTimeEnvelope and HandleControlPoint also)
891 if (*tracks.Any<TimeTrack>().begin())
892 {
894 XO("The active project already has a time track and one was encountered in the project being imported, bypassing imported time track."));
895 return true;
896 }
897
898 handler =
899 TrackList::Get(mProject).Add(std::make_shared<TimeTrack>());
900
901 return true;
902}
903
905{
906 auto &trackFactory = WaveTrackFactory::Get(mProject);
908 TrackList::Get(mProject).Add(trackFactory.Create());
909
910 // No active clip. In early versions of Audacity, there was a single
911 // implied clip so we'll create a clip when the first "sequence" is
912 // found.
913 mClip = nullptr;
914
915 return true;
916}
917
919{
920 wxString n;
921 wxString v;
922
923 // Support for legacy tags
924 for (auto pair : mAttrs)
925 {
926 auto attr = pair.first;
927 auto value = pair.second;
928
929 if (attr == "id3v2")
930 {
931 continue;
932 }
933 else if (attr == "track")
934 {
935 n = wxT("TRACKNUMBER");
936 }
937 else
938 {
939 n = std::string(attr);
940 n.MakeUpper();
941 }
942
943 v = value.ToWString();
944
945 if (!v.empty())
946 mTags->SetTag(n, value.ToWString());
947 }
948
949 // Do not set the handler - already handled
950
951 return true;
952}
953
955{
956 if (mParentTag != "tags")
957 {
958 return false;
959 }
960
961 wxString n, v;
962
963 for (auto pair : mAttrs)
964 {
965 auto attr = pair.first;
966 auto value = pair.second;
967
968 if (attr == "name")
969 {
970 n = value.ToWString();
971 }
972 else if (attr == "value")
973 {
974 v = value.ToWString();
975 }
976 }
977
978 if (n == wxT("id3v2"))
979 {
980 // LLL: This is obsolete, but it must be handled and ignored.
981 }
982 else
983 {
984 mTags->SetTag(n, v);
985 }
986
987 // Do not set the handler - already handled
988
989 return true;
990}
991
993{
994 if (mParentTag != "labeltrack")
995 {
996 return false;
997 }
998
999 // The parent handler also handles this tag
1000 handler = mHandlers.back().handler;
1001
1002 return true;
1003}
1004
1006{
1007 struct node node = mHandlers.back();
1008
1010 {
1011 WaveTrack *wavetrack = static_cast<WaveTrack *>(node.handler);
1012
1013 const auto pInterval = wavetrack->CreateClip();
1014 wavetrack->InsertInterval(pInterval, true, true);
1015 handler = pInterval.get();
1016 }
1018 {
1019 // Nested wave clips are cut lines
1020 WaveClip *waveclip = static_cast<WaveClip *>(node.handler);
1021
1022 handler = waveclip->HandleXMLChild(mCurrentTag);
1023 }
1024
1025 mClip = static_cast<WaveClip *>(handler);
1026 mClips.push_back(mClip);
1027
1028 return true;
1029}
1030
1032{
1033 struct node node = mHandlers.back();
1034
1035 if (mParentTag == "timetrack")
1036 {
1037 // If an imported timetrack was bypassed, then we want to bypass the
1038 // envelope as well. (See HandleTimeTrack and HandleControlPoint)
1039 if (node.handler)
1040 {
1041 TimeTrack *timetrack = static_cast<TimeTrack *>(node.handler);
1042
1043 handler = timetrack->GetEnvelope();
1044 }
1045 }
1046 // Earlier versions of Audacity had a single implied waveclip, so for
1047 // these versions, we get or create the only clip in the track.
1049 {
1050 handler = &(*mWaveTrack->RightmostOrNewClip()->Channels().begin())
1051 ->GetEnvelope();
1052 }
1053 // Nested wave clips are cut lines
1055 {
1056 WaveClip *waveclip = static_cast<WaveClip *>(node.handler);
1057
1058 handler = &waveclip->GetEnvelope();
1059 }
1060
1061 return true;
1062}
1063
1065{
1066 struct node node = mHandlers.back();
1067
1068 if (mParentTag == "envelope")
1069 {
1070 // If an imported timetrack was bypassed, then we want to bypass the
1071 // control points as well. (See HandleTimeTrack and HandleEnvelope)
1072 if (node.handler)
1073 {
1074 Envelope *envelope = static_cast<Envelope *>(node.handler);
1075
1076 handler = envelope->HandleXMLChild(mCurrentTag);
1077 }
1078 }
1079
1080 return true;
1081}
1082
1084{
1085 struct node node = mHandlers.back();
1086
1087 WaveClip *waveclip = static_cast<WaveClip *>(node.handler);
1088
1089 // Earlier versions of Audacity had a single implied waveclip, so for
1090 // these versions, we get or create the only clip in the track.
1092 {
1093 XMLTagHandler *dummy;
1094 HandleWaveClip(dummy);
1095 waveclip = mClip;
1096 }
1097
1098 auto pSequence =
1099 static_cast<Sequence*>(waveclip->HandleXMLChild(Sequence::Sequence_tag));
1100
1101 for (auto pair : mAttrs) {
1102 auto attr = pair.first;
1103 auto value = pair.second;
1104
1105 if (attr == "maxsamples")
1106 {
1107 // This attribute is a sample count, so can be 64bit
1108 long long llvalue;
1109 if (!value.TryGet(llvalue) || (llvalue < 0))
1110 {
1111 return SetError(XO("Invalid sequence 'maxsamples' attribute."));
1112 }
1113
1114 // Dominic, 12/10/2006:
1115 // Let's check that maxsamples is >= 1024 and <= 64 * 1024 * 1024
1116 // - that's a pretty wide range of reasonable values.
1117 if ((llvalue < 1024) || (llvalue > 64 * 1024 * 1024))
1118 {
1119 return SetError(XO("Invalid sequence 'maxsamples' attribute."));
1120 }
1121 }
1122 else if (attr == "sampleformat")
1123 {
1124 // This attribute is a sample format, normal int
1125 long fValue;
1126 if (!value.TryGet(fValue) || (fValue < 0) || !Sequence::IsValidSampleFormat(fValue))
1127 {
1128 return SetError(XO("Invalid sequence 'sampleformat' attribute."));
1129 }
1130
1131 mFormat = (sampleFormat) fValue;
1132 // Assume old AUP format file never had wide clips
1133 pSequence->ConvertToSampleFormat(mFormat);
1134 }
1135 else if (attr == "numsamples")
1136 {
1137 // This attribute is a sample count, so can be 64bit
1138 long long llvalue;
1139 if (!value.TryGet(llvalue) || (llvalue < 0))
1140 {
1141 return SetError(XO("Invalid sequence 'numsamples' attribute."));
1142 }
1143 }
1144 }
1145
1146 // Do not set the handler - already handled
1147
1148 return true;
1149}
1150
1152{
1153 for (auto pair : mAttrs)
1154 {
1155 auto attr = pair.first;
1156 auto value = pair.second;
1157
1158 if (attr == "start")
1159 {
1160 // making sure that values > 2^31 are OK because long clips will need them.
1161 long long llvalue;
1162 if (!value.TryGet(llvalue) || (llvalue < 0))
1163 {
1164 return SetError(XO("Unable to parse the waveblock 'start' attribute"));
1165 }
1166 }
1167 }
1168
1169 // Do not set the handler - already handled
1170
1171 return true;
1172}
1173
1175{
1176 FilePath filename;
1177 size_t len = 0;
1178
1179 for (auto pair : mAttrs)
1180 {
1181 auto attr = pair.first;
1182 auto value = pair.second;
1183
1184 // Can't use XMLValueChecker::IsGoodFileName here, but do part of its test.
1185 if (CaseInsensitiveEquals(attr, "filename"))
1186 {
1187 const wxString strValue = value.ToWString();
1188
1190 {
1191 if (mFileMap.find(strValue) != mFileMap.end())
1192 {
1193 filename = mFileMap[strValue].first;
1194 }
1195 else
1196 {
1197 SetWarning(XO("Missing project file %s\n\nInserting silence instead.")
1198 .Format(strValue));
1199 }
1200 }
1201 }
1202 else if (attr == "len")
1203 {
1204 long lValue;
1205 if (!value.TryGet(lValue) || (lValue <= 0))
1206 {
1207 return SetError(XO("Missing or invalid simpleblockfile 'len' attribute."));
1208 }
1209
1210 len = lValue;
1211 }
1212 }
1213
1214 // Do not set the handler - already handled
1215
1216 AddFile(len, mFormat, filename, filename);
1217
1218 return true;
1219}
1220
1222{
1223 FilePath filename;
1224 size_t len = 0;
1225
1226 for (auto pair : mAttrs)
1227 {
1228 auto attr = pair.first;
1229 auto value = pair.second;
1230
1231 if (attr == "len")
1232 {
1233 long lValue;
1234 if (!value.TryGet(lValue) || !(lValue > 0))
1235 {
1236 return SetError(XO("Missing or invalid silentblockfile 'len' attribute."));
1237 }
1238
1239 len = lValue;
1240 }
1241 }
1242
1243 // Do not set the handler - already handled
1244
1245 AddFile(len, mFormat);
1246
1247 return true;
1248}
1249
1251{
1252 wxString summaryFilename;
1253 wxFileName filename;
1254 sampleCount start = 0;
1255 size_t len = 0;
1256 int channel = 0;
1257 wxString name;
1258
1259 for (auto pair : mAttrs)
1260 {
1261 auto attr = pair.first;
1262 auto value = pair.second;
1263
1264 if (CaseInsensitiveEquals(attr, "aliasfile"))
1265 {
1266 const wxString strValue = value.ToWString();
1267
1268 if (XMLValueChecker::IsGoodPathName(strValue))
1269 {
1270 filename.Assign(strValue);
1271 }
1272 else if (XMLValueChecker::IsGoodFileName(strValue, mProjDir.GetPath()))
1273 {
1274 // Allow fallback of looking for the file name, located in the data directory.
1275 filename.Assign(mProjDir.GetPath(), strValue);
1276 }
1277 else if (XMLValueChecker::IsGoodPathString(strValue))
1278 {
1279 // If the aliased file is missing, we failed XMLValueChecker::IsGoodPathName()
1280 // and XMLValueChecker::IsGoodFileName, because both do existence tests.
1281 SetWarning(XO("Missing alias file %s\n\nInserting silence instead.")
1282 .Format(strValue));
1283 }
1284 }
1285 else if (CaseInsensitiveEquals(attr, "summaryfile"))
1286 {
1287 summaryFilename = value.ToWString();
1288 }
1289 else if (CaseInsensitiveEquals(attr, "aliasstart"))
1290 {
1291 long long llValue;
1292 if (!value.TryGet(llValue) || (llValue < 0))
1293 {
1294 return SetError(XO("Missing or invalid pcmaliasblockfile 'aliasstart' attribute."));
1295 }
1296
1297 start = llValue;
1298 }
1299 else if (CaseInsensitiveEquals(attr, "aliaslen"))
1300 {
1301 long lValue;
1302 if (!value.TryGet(lValue) || (lValue <= 0))
1303 {
1304 return SetError(XO("Missing or invalid pcmaliasblockfile 'aliaslen' attribute."));
1305 }
1306
1307 len = lValue;
1308 }
1309 else if (CaseInsensitiveEquals(attr, "aliaschannel"))
1310 {
1311 long lValue;
1312 if (!value.TryGet(lValue) || (lValue < 0))
1313 {
1314 return SetError(XO("Missing or invalid pcmaliasblockfile 'aliaslen' attribute."));
1315 }
1316
1317 channel = lValue;
1318 }
1319 }
1320
1321 // Do not set the handler - already handled
1322
1323 if (filename.IsOk())
1324 AddFile(len, mFormat,
1325 summaryFilename, filename.GetFullPath(),
1326 start, channel);
1327 else
1328 AddFile(len, mFormat); // will add silence instead
1329
1330 return true;
1331}
1332
1334{
1335 // Adapted from ImportXMLTagHandler::HandleXMLTag as in version 2.4.2
1336 if (mAttrs.empty() || mAttrs.front().first != "filename")
1337 return false;
1338
1339 wxString strAttr = mAttrs.front().second.ToWString();
1340
1341 if (!XMLValueChecker::IsGoodPathName(strAttr))
1342 {
1343 // Maybe strAttr is just a fileName, not the full path. Try the project data directory.
1344 wxFileNameWrapper fileName0{ GetFilename() };
1345 fileName0.SetExt({});
1346 wxFileNameWrapper fileName{
1347 fileName0.GetFullPath() + wxT("_data"), strAttr };
1348 if (XMLValueChecker::IsGoodFileName(strAttr, fileName.GetPath(wxPATH_GET_VOLUME)))
1349 strAttr = fileName.GetFullPath();
1350 else
1351 {
1352 wxLogWarning(wxT("Could not import file: %s"), strAttr);
1353 return false;
1354 }
1355 }
1356
1358 auto oldNumTracks = tracks.Size();
1359 Track *pLast = nullptr;
1360 if (oldNumTracks > 0)
1361 pLast = *tracks.rbegin();
1362
1363 // Guard this call so that C++ exceptions don't propagate through
1364 // the expat library
1366 [&] { ProjectFileManager::Get(mProject).Import(strAttr, false); },
1367 [&](AudacityException*) {});
1368
1369 if (oldNumTracks == tracks.Size())
1370 return false;
1371
1372 // Handle other attributes, now that we have the tracks.
1373 // Apply them to all new wave tracks.
1374 bool bSuccess = true;
1375
1376 auto range = tracks.Any();
1377 if (pLast) {
1378 range = range.StartingWith(pLast);
1379 ++range.first;
1380 }
1381
1382 mAttrs.erase(mAttrs.begin());
1383
1384 for (auto pTrack: range.Filter<WaveTrack>()) {
1385 // Most of the "import" tag attributes are the same as for "wavetrack" tags,
1386 // so apply them via WaveTrack::HandleXMLTag().
1387 bSuccess = pTrack->HandleXMLTag(WaveTrack::WaveTrack_tag, mAttrs);
1388
1389 // "offset" tag is ignored in WaveTrack::HandleXMLTag except for legacy projects,
1390 // so handle it here.
1391 double dblValue;
1392 for (auto pair : mAttrs) {
1393 auto attr = pair.first;
1394 auto value = pair.second;
1395 if (attr == "offset" && value.TryGet(dblValue))
1396 pTrack->MoveTo(dblValue);
1397 }
1398 }
1399 return bSuccess;
1400}
1401
1404 const FilePath &blockFilename /* = wxEmptyString */,
1405 const FilePath &audioFilename /* = wxEmptyString */,
1406 sampleCount origin /* = 0 */,
1407 int channel /* = 0 */)
1408{
1409 fileinfo fi = {};
1410 fi.track = mWaveTrack;
1411 fi.clip = mClip;
1412 fi.blockFile = blockFilename;
1413 fi.audioFile = audioFilename;
1414 fi.len = len;
1415 fi.format = format,
1416 fi.origin = origin,
1417 fi.channel = channel;
1418
1419 mFiles.push_back(fi);
1420
1421 mTotalSamples += len;
1422}
1423
1425{
1426 wxASSERT(mClip || mWaveTrack);
1427
1428 if (mClip)
1429 {
1431 }
1432 else if (mWaveTrack)
1433 {
1436 }
1437
1438 return true;
1439}
1440
1441// All errors that occur here will simply insert silence and allow the
1442// import to continue.
1444 const FilePath &audioFilename,
1445 sampleCount len,
1447 sampleCount origin /* = 0 */,
1448 int channel /* = 0 */)
1449{
1450 auto pClip = mClip ? mClip : mWaveTrack->RightmostOrNewClip().get();
1451 auto &pBlock = mFileMap[wxFileNameFromPath(blockFilename)].second;
1452 if (pBlock) {
1453 // Replicate the sharing of blocks
1454 if (pClip->NChannels() != 1)
1455 return false;
1456 pClip->AppendLegacySharedBlock( pBlock );
1457 return true;
1458 }
1459
1460 // Third party library has its own type alias, check it before
1461 // adding origin + size_t
1462 static_assert(sizeof(sampleCount::type) <= sizeof(sf_count_t),
1463 "Type sf_count_t is too narrow to hold a sampleCount");
1464
1465 SF_INFO info;
1466 memset(&info, 0, sizeof(info));
1467
1468 wxFile f; // will be closed when it goes out of scope
1469 SNDFILE *sf = nullptr;
1470 bool success = false;
1471
1472#ifndef UNCAUGHT_EXCEPTIONS_UNAVAILABLE
1473 const auto uncaughtExceptionsCount = std::uncaught_exceptions();
1474#endif
1475
1476 auto cleanup = finally([&]
1477 {
1478 // Do this before any throwing might happen
1479 if (sf)
1480 {
1481 SFCall<int>(sf_close, sf);
1482 }
1483
1484 if (!success)
1485 {
1486 SetWarning(XO("Error while processing %s\n\nInserting silence.").Format(audioFilename));
1487
1488 // If we are unwinding for an exception, don't do another
1489 // potentially throwing operation
1490#ifdef UNCAUGHT_EXCEPTIONS_UNAVAILABLE
1491 if (!std::uncaught_exception())
1492#else
1493 if (uncaughtExceptionsCount == std::uncaught_exceptions())
1494#endif
1495 // If this does throw, let that propagate, don't guard the call
1496 AddSilence(len);
1497 }
1498 });
1499
1500 if (!f.Open(audioFilename))
1501 {
1502 SetWarning(XO("Failed to open %s").Format(audioFilename));
1503
1504 return true;
1505 }
1506
1507 // Even though there is an sf_open() that takes a filename, use the one that
1508 // takes a file descriptor since wxWidgets can open a file with a Unicode name and
1509 // libsndfile can't (under Windows).
1510 sf = SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_READ, &info, FALSE);
1511 if (!sf)
1512 {
1513 SetWarning(XO("Failed to open %s").Format(audioFilename));
1514
1515 return true;
1516 }
1517
1518 if (origin > 0)
1519 {
1520 if (SFCall<sf_count_t>(sf_seek, sf, origin.as_long_long(), SEEK_SET) < 0)
1521 {
1522 SetWarning(XO("Failed to seek to position %lld in %s")
1523 .Format(origin.as_long_long(), audioFilename));
1524
1525 return true;
1526 }
1527 }
1528
1529 sf_count_t cnt = len.as_size_t();
1530 int channels = info.channels;
1531
1532 wxASSERT(channels >= 1);
1533 wxASSERT(channel < channels);
1534
1535 SampleBuffer buffer(cnt, format);
1536 samplePtr bufptr = buffer.ptr();
1537
1538 size_t framesRead = 0;
1539
1540 // These cases preserve the logic formerly in BlockFile.cpp,
1541 // which was deleted at commit 98d1468.
1542 if (channels == 1 && format == int16Sample && sf_subtype_is_integer(info.format))
1543 {
1544 // If both the src and dest formats are integer formats,
1545 // read integers directly from the file, conversions not needed
1546 framesRead = SFCall<sf_count_t>(sf_readf_short, sf, (short *) bufptr, cnt);
1547 }
1548 else if (channels == 1 && format == int24Sample && sf_subtype_is_integer(info.format))
1549 {
1550 framesRead = SFCall<sf_count_t>(sf_readf_int, sf, (int *) bufptr, cnt);
1551 if (framesRead != cnt)
1552 {
1553 SetWarning(XO("Unable to read %lld samples from %s")
1554 .Format(cnt, audioFilename));
1555
1556 return true;
1557 }
1558
1559 // libsndfile gave us the 3 byte sample in the 3 most
1560 // significant bytes -- we want it in the 3 least
1561 // significant bytes.
1562 int *intPtr = (int *) bufptr;
1563 for (size_t i = 0; i < framesRead; i++)
1564 {
1565 intPtr[i] = intPtr[i] >> 8;
1566 }
1567 }
1568 else if (format == int16Sample && !sf_subtype_more_than_16_bits(info.format))
1569 {
1570 // Special case: if the file is in 16-bit (or less) format,
1571 // and the calling method wants 16-bit data, go ahead and
1572 // read 16-bit data directly. This is a pretty common
1573 // case, as most audio files are 16-bit.
1574 SampleBuffer temp(cnt * channels, int16Sample);
1575 short *tmpptr = (short *) temp.ptr();
1576
1577 framesRead = SFCall<sf_count_t>(sf_readf_short, sf, tmpptr, cnt);
1578 if (framesRead != cnt)
1579 {
1580 SetWarning(XO("Unable to read %lld samples from %s")
1581 .Format(cnt, audioFilename));
1582
1583 return true;
1584 }
1585
1586 for (size_t i = 0; i < framesRead; i++)
1587 {
1588 ((short *)bufptr)[i] = tmpptr[(channels * i) + channel];
1589 }
1590 }
1591 else
1592 {
1593 /*
1594 Therefore none of the three cases above:
1595 !(channels == 1 && format == int16Sample && sf_subtype_is_integer(info.format))
1596 &&
1597 !(channels == 1 && format == int24Sample && sf_subtype_is_integer(info.format))
1598 &&
1599 !(format == int16Sample && !sf_subtype_more_than_16_bits(info.format))
1600
1601 So format is not 16 bits with wider file format (third conjunct),
1602 but still maybe it is 24 bits with float file format (second conjunct).
1603 */
1604
1605 // Otherwise, let libsndfile handle the conversion and
1606 // scaling, and pass us normalized data as floats. We can
1607 // then convert to whatever format we want.
1608 SampleBuffer tmpbuf(cnt * channels, floatSample);
1609 float *tmpptr = (float *) tmpbuf.ptr();
1610
1611 framesRead = SFCall<sf_count_t>(sf_readf_float, sf, tmpptr, cnt);
1612 if (framesRead != cnt)
1613 {
1614 SetWarning(XO("Unable to read %lld samples from %s")
1615 .Format(cnt, audioFilename));
1616
1617 return true;
1618 }
1619
1620 /*
1621 Dithering will happen in CopySamples if format is 24 bits.
1622 Should that be done?
1623
1624 Either the file is an ordinary simple block file -- and presumably the
1625 track was saved specifying a matching format, so format is float and
1626 there is no dithering.
1627
1628 Or else this is the very unusual case of an .auf file, importing PCM data
1629 on demand. The destination format is narrower, requiring dither, only
1630 if the user also specified a narrow format for the track. In such a
1631 case, dithering is right.
1632 */
1633 CopySamples((samplePtr)(tmpptr + channel),
1635 bufptr,
1636 format,
1637 framesRead,
1638 gHighQualityDither /* high quality by default */,
1639 channels /* source stride */);
1640 }
1641
1642 wxASSERT(mClip || mWaveTrack);
1643
1644 // Add the samples to the clip/track
1645 if (pClip)
1646 {
1647 if (pClip->NChannels() != 1)
1648 return false;
1649 pBlock = pClip->AppendLegacyNewBlock(bufptr, format, cnt);
1650 }
1651
1652 // Let the finally block know everything is good
1653 success = true;
1654
1655 return true;
1656}
1657
1659{
1660 wxLogError(msg.Debug());
1661
1662 if (mErrorMsg.empty() || !mHasParseError)
1663 {
1664 mErrorMsg = msg;
1665 }
1666
1667 mHasParseError = true;
1668 return false;
1669}
1670
1672{
1673 wxLogWarning(msg.Debug());
1674
1675 if (mErrorMsg.empty())
1676 {
1677 mErrorMsg = msg;
1678 }
1679
1680 return false;
1681}
wxT("CloseDown"))
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
const TranslatableString name
Definition: Distortion.cpp:76
bool sf_subtype_is_integer(unsigned int format)
bool sf_subtype_more_than_16_bits(unsigned int format)
XO("Cut/Copy/Paste")
static const auto exts
Definition: ImportAUP.cpp:56
#define DESC
Definition: ImportAUP.cpp:54
#define field(n, t)
Definition: ImportAUP.cpp:165
#define set(f, v)
static Importer::RegisteredImportPlugin registered
Definition: ImportAUP.cpp:274
std::unique_ptr< ImportFileHandle > ImportHandle
Definition: ImportAUP.cpp:65
The interface that all file import "plugins" (if you want to call them that) must implement....
std::vector< std::shared_ptr< Track > > TrackHolders
Definition: ImportRaw.h:24
wxString FilePath
Definition: Project.h:21
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 ...
accessors for certain important windows associated with each project
DitherType gHighQualityDither
void CopySamples(constSamplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, size_t len, DitherType ditherType, unsigned int srcStride, unsigned int dstStride)
Copy samples from any format to any other format; apply dithering only if narrowing the format.
sampleFormat
The ordering of these values with operator < agrees with the order of increasing bit width.
Definition: SampleFormat.h:30
char * samplePtr
Definition: SampleFormat.h:57
const auto tracks
const auto project
std::vector< TranslatableString > TranslatableStrings
static const auto fn
std::vector< Attribute > AttributesList
Definition: XMLTagHandler.h:40
An ImportFileHandle for AUP files (pre-AUP3)
Definition: ImportAUP.cpp:83
TranslatableString mErrorMsg
Definition: ImportAUP.cpp:215
bool AddSamples(const FilePath &blockFilename, const FilePath &audioFilename, sampleCount len, sampleFormat format, sampleCount origin=0, int channel=0)
Definition: ImportAUP.cpp:1443
struct AUPImportFileHandle::@137 mProjectAttrs
sampleFormat mFormat
Definition: ImportAUP.cpp:198
std::string mParentTag
Definition: ImportAUP.cpp:202
bool HandlePCMAliasBlockFile(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:1250
unsigned long mNumChannels
Definition: ImportAUP.cpp:199
AUPImportFileHandle(const FilePath &name, AudacityProject *project)
Definition: ImportAUP.cpp:278
BlockFileMap mFileMap
Definition: ImportAUP.cpp:209
ByteCount GetFileUncompressedBytes() override
Definition: ImportAUP.cpp:299
AudacityProject & mProject
Definition: ImportAUP.cpp:160
bool HandleProject(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:677
bool HandleSilentBlockFile(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:1221
bool HandleLabel(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:992
void HandleXMLEndTag(const std::string_view &tag) override
Definition: ImportAUP.cpp:551
bool HandleWaveBlock(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:1151
bool HandleLabelTrack(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:865
WaveTrack * mWaveTrack
Definition: ImportAUP.cpp:211
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
Definition: ImportAUP.cpp:583
wxFileName mProjDir
Definition: ImportAUP.cpp:206
std::vector< WaveClip * > mClips
Definition: ImportAUP.cpp:213
TranslatableString GetFileDescription() override
Definition: ImportAUP.cpp:289
TranslatableString GetErrorMessage() const override
Definition: ImportAUP.cpp:294
std::map< wxString, std::pair< FilePath, std::shared_ptr< SampleBlock > > > BlockFileMap
Definition: ImportAUP.cpp:208
bool HandleSequence(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:1083
bool SetError(const TranslatableString &msg)
Definition: ImportAUP.cpp:1658
bool HandleWaveTrack(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:904
wxInt32 GetStreamCount() override
Definition: ImportAUP.cpp:497
sampleCount mTotalSamples
Definition: ImportAUP.cpp:196
std::vector< struct node > stack
Definition: ImportAUP.cpp:115
bool HandleNoteTrack(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:872
bool SetWarning(const TranslatableString &msg)
Definition: ImportAUP.cpp:1671
void Import(ImportProgressListener &progressListener, WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags, std::optional< LibFileFormats::AcidizerTags > &outAcidTags) override
Definition: ImportAUP.cpp:305
void SetStreamUsage(wxInt32 WXUNUSED(StreamID), bool WXUNUSED(Use)) override
Definition: ImportAUP.cpp:508
bool HandleTimeTrack(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:885
bool HandleControlPoint(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:1064
bool HandleImport(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:1333
bool HandleWaveClip(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:1005
bool HandleTag(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:954
std::vector< fileinfo > mFiles
Definition: ImportAUP.cpp:195
bool HandleSimpleBlockFile(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:1174
std::string mCurrentTag
Definition: ImportAUP.cpp:203
const TranslatableStrings & GetStreamInfo() override
Definition: ImportAUP.cpp:502
bool HandleTags(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:918
bool AddSilence(sampleCount len)
Definition: ImportAUP.cpp:1424
bool HandleEnvelope(XMLTagHandler *&handle)
Definition: ImportAUP.cpp:1031
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
Definition: ImportAUP.cpp:546
void AddFile(sampleCount len, sampleFormat format, const FilePath &blockFilename=wxEmptyString, const FilePath &audioFilename=wxEmptyString, sampleCount origin=0, int channel=0)
Definition: ImportAUP.cpp:1402
AttributesList mAttrs
Definition: ImportAUP.cpp:204
An ImportPlugin for AUP files (pre-AUP3)
Definition: ImportAUP.cpp:68
TranslatableString GetPluginFormatDescription() override
Definition: ImportAUP.cpp:254
ImportHandle Open(const FilePath &fileName, AudacityProject *project) override
Definition: ImportAUP.cpp:259
wxString GetPluginStringID() override
Definition: ImportAUP.cpp:249
Base class for exceptions specially processed by the application.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
Piecewise linear or piecewise exponential function from double to double.
Definition: Envelope.h:72
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
Definition: Envelope.cpp:334
Abstract base class used in importing a file.
bool IsStopped() const noexcept
FilePath GetFilename() const override
bool IsCancelled() const noexcept
unsigned long long ByteCount
Definition: ImportPlugin.h:114
Base class for FlacImportPlugin, LOFImportPlugin, MP3ImportPlugin, OggImportPlugin and PCMImportPlugi...
Definition: ImportPlugin.h:67
Interface used to report on import state and progress.
virtual void OnImportResult(ImportResult result)=0
Used to report on import result for file handle passed as argument to OnImportFileOpened.
virtual void OnImportProgress(double progress)=0
static void ShowMessageBox(const TranslatableString &message, const TranslatableString &caption=XO("Import Project"))
Definition: ImportUtils.cpp:43
static void FixTracks(TrackList &tracks, const std::function< void(const TranslatableString &)> &onError, const std::function< void(const TranslatableString &)> &onUnlink)
Attempts to find and fix problems in tracks.
bool Import(const std::vector< FilePath > &fileNames, bool addToHistory=true)
static ProjectFileManager & Get(AudacityProject &project)
static ProjectHistory & Get(AudacityProject &project)
static ProjectNumericFormats & Get(AudacityProject &project)
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
void SetRate(double rate)
Definition: ProjectRate.cpp:58
void SetSnapMode(SnapMode mode)
Definition: ProjectSnap.cpp:41
static ProjectSnap & Get(AudacityProject &project)
Definition: ProjectSnap.cpp:27
samplePtr ptr() const
Definition: SampleFormat.h:165
static const int UndefinedFrequency
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
Definition: Sequence.h:53
static const char * Sequence_tag
Definition: Sequence.h:56
static const char * WaveBlock_tag
Definition: Sequence.h:57
static bool IsValidSampleFormat(const int nValue)
true if nValue is one of the sampleFormat enum values
Definition: Sequence.cpp:1905
ID3 Tags (for MP3)
Definition: Tags.h:73
void SetTag(const wxString &name, const wxString &value, const bool bSpecialTag=false)
Definition: Tags.cpp:431
A kind of Track used to 'warp time'.
Definition: TimeTrack.h:24
BoundedEnvelope * GetEnvelope()
Definition: TimeTrack.h:83
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:110
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:314
TrackKind * Add(const std::shared_ptr< TrackKind > &t, bool assignIds=true)
Definition: Track.h:1048
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Debug() const
Format as an English string for debugging logs and developers' eyes, not for end users.
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:238
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
Definition: WaveClip.cpp:1034
double GetPlayEndTime() const override
Definition: WaveClip.cpp:1763
void InsertSilence(double t, double len, double *pEnvelopeValue=nullptr)
Definition: WaveClip.cpp:1229
Envelope & GetEnvelope() noexcept
Definition: WaveClip.h:553
static const char * WaveClip_tag
Definition: WaveClip.h:249
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:870
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:3349
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
IntervalHolder RightmostOrNewClip()
Get access to the last (rightmost) clip, or create a clip, if there is not already one.
Definition: WaveTrack.cpp:2990
void InsertSilence(double t, double len) override
Definition: WaveTrack.cpp:2002
IntervalHolder CreateClip(double offset=.0, const wxString &name=wxEmptyString, const Interval *pToCopy=nullptr, bool copyCutlines=true)
Definition: WaveTrack.cpp:2934
void InsertInterval(const IntervalHolder &interval, bool newClip, bool allowEmpty=false)
Definition: WaveTrack.cpp:3208
static const char * WaveTrack_tag
Definition: WaveTrack.h:206
void SetLegacyFormat(sampleFormat format)
Definition: WaveTrack.cpp:2308
double GetEndTime() const override
Implement WideSampleSequence.
Definition: WaveTrack.cpp:2586
double LongSamplesToTime(sampleCount pos) const
Reads a file and passes the results through an XMLTagHandler.
Definition: XMLFileReader.h:19
const TranslatableString & GetErrorStr() const
bool Parse(XMLTagHandler *baseHandler, const FilePath &fname)
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:42
virtual void HandleXMLEndTag(const std::string_view &WXUNUSED(tag))
Definition: XMLTagHandler.h:59
static bool IsGoodFileString(const FilePath &str)
static bool IsGoodPathName(const FilePath &strPathName)
static bool IsGoodPathString(const FilePath &str)
static bool IsGoodFileName(const FilePath &strFileName, const FilePath &strDirName={})
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
long long as_long_long() const
Definition: SampleCount.h:48
long long type
Definition: SampleCount.h:21
size_t as_size_t() const
Definition: SampleCount.cpp:16
double as_double() const
Definition: SampleCount.h:46
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
bool CaseInsensitiveEquals(const std::string_view &lhs, const std::string_view &rhsLower)
Definition: ImportAUP.cpp:222
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
const char * begin(const char *str) noexcept
Definition: StringUtils.h:101
XMLTagHandler * handler
Definition: ImportAUP.cpp:113