Audacity 3.2.0
Import.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 Import.cpp
6
7 Dominic Mazzoni
8
9*******************************************************************//***************************************************************//***************************************************************//******************************************************************/
34
35#include "Import.h"
36
37#include "ImportPlugin.h"
38
39#include <algorithm>
40#include <unordered_set>
41
42#include <wx/log.h>
43#include "FileNames.h"
44#include "Project.h"
45#include "WaveTrack.h"
46
47#include "Prefs.h"
48
50
51namespace {
52
53//Proxy class used by importer to capture import result
55{
56 ImportProgressListener* mListener{nullptr};
57 ImportResult mResult { ImportResult::Error };
58public:
59
61 : mListener(listener)
62 {
63
64 }
65
66 bool OnImportFileOpened(ImportFileHandle& importFileHandle) override
67 {
68 mResult = ImportResult::Error;
69 if(mListener)
70 return mListener->OnImportFileOpened(importFileHandle);
71 return true;
72 }
73
74 void OnImportProgress(double progress) override
75 {
76 if(mListener)
77 mListener->OnImportProgress(progress);
78 }
79
80 void OnImportResult(ImportResult result) override
81 {
82 mResult = result;
83 if(mListener)
84 mListener->OnImportResult(result);
85 }
86
87 ImportResult GetResult() const noexcept
88 {
89 return mResult;
90 }
91};
92
93}
94
95// ============================================================================
96//
97// Return reference to singleton
98//
99// (Thread-safe...no active threading during construction or after destruction)
100// ============================================================================
103{
104 return mInstance;
105}
106
108{
109}
110
112{
113}
114
116{
117 static ImportPluginList theList;
118 return theList;
119}
120
121namespace {
122static const auto PathStart = L"Importers";
123
124
125}
126
128{
129 static Registry::GroupItem<Traits> registry{ PathStart };
130 return registry;
131}
132
133Importer::ImporterItem::ImporterItem( const Identifier &id, std::unique_ptr<ImportPlugin> pPlugin )
134 : SingleItem{ id }
135 , mpPlugin{ std::move( pPlugin ) }
136{}
137
139
141 const Identifier &id,
142 std::unique_ptr<ImportPlugin> pPlugin,
143 const Registry::Placement &placement )
144 : RegisteredItem{
145 pPlugin
146 ? std::make_unique< ImporterItem >( id, std::move( pPlugin ) )
147 : nullptr,
148 placement
149 }
150{
151}
152
154{
155 static UnusableImportPluginList theList;
156 return theList;
157}
158
160 std::unique_ptr<UnusableImportPlugin> pPlugin )
161{
162 if ( pPlugin )
163 sUnusableImportPluginList().emplace_back( std::move( pPlugin ) );
164}
165
167{
168 // build the list of import plugin and/or unusableImporters.
169 // order is significant. If none match, they will all be tried
170 // in the order defined here.
171
172 using namespace Registry;
174 PathStart,
175 // FFmpeg is in default of all other modules that might handle a format
176 // better and specially; including MIDI import
177 { {wxT(""), wxT("AUP,PCM,OGG,FLAC,MP3,LOF,WavPack,portsmf,FFmpeg") } }
178 };
179
180 // Once only, visit the registry to collect the plug-ins properly
181 // sorted
182 static std::once_flag flag;
183 std::call_once(flag, []{
186 [](const ImporterItem &item, auto&) {
187 sImportPluginList().push_back(item.mpPlugin.get()); },
188 &top, &ImporterItem::Registry());
189 });
190
191 // Ordering of the unusable plugin list is not important.
192
194
196
197 return true;
198}
199
201{
203
204 return true;
205}
206
209{
210 // Construct the filter
211 FileNames::FileTypes fileTypes{
213 // Will fill in the list of extensions later:
214 { XO("All supported files"), {} },
216 };
217
218 if ( !extraType.extensions.empty() )
219 fileTypes.push_back( extraType );
220
222 for(const auto &importPlugin : sImportPluginList())
223 {
224 l.emplace_back(importPlugin->GetPluginFormatDescription(),
225 importPlugin->GetSupportedExtensions());
226 }
227
228 FileExtensions extraExtensions = FileNames::AudacityProjects.extensions;
229 extraExtensions.insert(extraExtensions.end(),
230 extraType.extensions.begin(),
231 extraType.extensions.end());
232
233 using ExtensionSet = std::unordered_set< FileExtension >;
234 FileExtensions allList = FileNames::AudacityProjects.extensions, newList;
235 allList.insert(allList.end(), extraType.extensions.begin(), extraType.extensions.end());
236 ExtensionSet allSet{ allList.begin(), allList.end() }, newSet;
237 for ( const auto &format : l ) {
238 newList.clear();
239 newSet.clear();
240 for ( const auto &extension : format.extensions ) {
241 if ( newSet.insert( extension ).second )
242 newList.push_back( extension );
243 if ( allSet.insert( extension ).second )
244 allList.push_back( extension );
245 }
246 fileTypes.push_back( { format.description, newList } );
247 }
248
249 fileTypes[1].extensions = allList;
250 return fileTypes;
251}
252
254{
255 // PRL: Preference key /LastOpenType, unusually, stores a localized
256 // string!
257 // The bad consequences of a change of locale are not severe -- only that
258 // a default choice of file type for an open dialog is not remembered
259 gPrefs->Write(wxT("/LastOpenType"), type.description.Translation());
260 gPrefs->Flush();
261}
262
264{
265 // PRL: Preference key /DefaultOpenType, unusually, stores a localized
266 // string!
267 // The bad consequences of a change of locale are not severe -- only that
268 // a default choice of file type for an open dialog is not remembered
269 gPrefs->Write(wxT("/DefaultOpenType"), type.description.Translation());
270 gPrefs->Flush();
271}
272
274{
275 wxString defaultValue;
276 if ( !fileTypes.empty() )
277 defaultValue = fileTypes[0].description.Translation();
278
279 wxString type = gPrefs->Read(wxT("/DefaultOpenType"), defaultValue);
280 // Convert the type to the filter index
281 auto begin = fileTypes.begin();
282 auto index = std::distance(
283 begin,
284 std::find_if( begin, fileTypes.end(),
285 [&type](const FileNames::FileType &fileType){
286 return fileType.description.Translation() == type; } ) );
287 return (index == fileTypes.size()) ? 0 : index;
288}
289
290void Importer::StringToList(wxString &str, wxString &delims, wxArrayString &list, wxStringTokenizerMode mod)
291{
292 wxStringTokenizer toker;
293
294 for (toker.SetString(str, delims, mod);
295 toker.HasMoreTokens(); list.push_back(toker.GetNextToken()));
296}
297
299{
300 int item_counter = 0;
301 wxStringTokenizer toker;
302 wxString item_name;
303 wxString item_value;
304
306 /* Rule string format is:
307 * extension1:extension2:extension3\mime_type1:mime_type2:mime_type3|filter1:filter2:filter3\unusedfilter1:unusedfilter2
308 * backslashes are escaped and unescaped internally
309 */
310 for (item_counter = 0; true; item_counter++)
311 {
312 wxString condition, filters, used_filters, unused_filters, extensions, mime_types;
313 item_name.Printf (wxT("/ExtImportItems/Item%d"), item_counter);
314 /* Break at first non-existent item */
315 if (!gPrefs->Read(item_name, &item_value))
316 break;
317
318 toker.SetString(item_value, wxT("|"), wxTOKEN_RET_EMPTY_ALL);
319 /* Break at first broken item */
320 if (toker.CountTokens() != 2)
321 break;
322
323 auto new_item = std::make_unique<ExtImportItem>();
324
325 /* First token is the filtering condition, second - the filter list */
326 condition = toker.GetNextToken();
327 filters = toker.GetNextToken();
328
329 /* Condition token consists of extension list and mime type list
330 * mime type list can be omitted entirely (complete with '\' separator)*/
331 toker.SetString(condition, wxT("\\"), wxTOKEN_RET_EMPTY_ALL);
332 extensions = toker.GetNextToken();
333 if (toker.HasMoreTokens())
334 mime_types = toker.GetNextToken();
335
336 wxString delims(wxT(":"));
337 StringToList (extensions, delims, new_item->extensions);
338
339 if (!mime_types.empty())
340 StringToList (mime_types, delims, new_item->mime_types);
341
342 /* Filter token consists of used and unused filter lists */
343 toker.SetString(filters, wxT("\\"), wxTOKEN_RET_EMPTY_ALL);
344 used_filters = toker.GetNextToken();
345 if (toker.HasMoreTokens())
346 unused_filters = toker.GetNextToken();
347
348 StringToList (used_filters, delims, new_item->filters);
349
350 if (!unused_filters.empty())
351 {
352 /* Filters are stored in one list, but the position at which
353 * unused filters start is remembered
354 */
355 new_item->divider = new_item->filters.size();
356 StringToList (unused_filters, delims, new_item->filters);
357 }
358 else
359 new_item->divider = -1;
360
361 /* Find corresponding filter object for each filter ID */
362 for (size_t i = 0; i < new_item->filters.size(); i++)
363 {
364 bool found = false;
365 for (const auto &importPlugin : sImportPluginList())
366 {
367 if (importPlugin->GetPluginStringID() == new_item->filters[i])
368 {
369 new_item->filter_objects.push_back(importPlugin);
370 found = true;
371 break;
372 }
373 }
374 /* IDs that do not have corresponding filters, will be shown as-is */
375 if (!found)
376 new_item->filter_objects.push_back(nullptr);
377 }
378 /* Find all filter objects that are not present in the filter list */
379 for (const auto &importPlugin : sImportPluginList())
380 {
381 bool found = false;
382 for (size_t i = 0; i < new_item->filter_objects.size(); i++)
383 {
384 if (importPlugin == new_item->filter_objects[i])
385 {
386 found = true;
387 break;
388 }
389 }
390 /* Add these filters at the bottom of used filter list */
391 if (!found)
392 {
393 int index = new_item->divider;
394 if (new_item->divider < 0)
395 index = new_item->filters.size();
396 new_item->filters.insert(
397 new_item->filters.begin() + index,
398 importPlugin->GetPluginStringID());
399 new_item->filter_objects.insert(
400 new_item->filter_objects.begin() + index, importPlugin);
401 if (new_item->divider >= 0)
402 new_item->divider++;
403 }
404 }
405 this->mExtImportItems.push_back( std::move(new_item) );
406 }
407}
408
410{
411 size_t i;
412 wxString val, name;
413 for (i = 0; i < this->mExtImportItems.size(); i++)
414 {
415 ExtImportItem *item = mExtImportItems[i].get();
416 val.clear();
417
418 for (size_t j = 0; j < item->extensions.size(); j++)
419 {
420 val.Append (item->extensions[j]);
421 if (j < item->extensions.size() - 1)
422 val.Append (wxT(":"));
423 }
424 val.Append (wxT("\\"));
425 for (size_t j = 0; j < item->mime_types.size(); j++)
426 {
427 val.Append (item->mime_types[j]);
428 if (j < item->mime_types.size() - 1)
429 val.Append (wxT(":"));
430 }
431 val.Append (wxT("|"));
432 for (size_t j = 0; j < item->filters.size() && ((int) j < item->divider || item->divider < 0); j++)
433 {
434 val.Append (item->filters[j]);
435 if (j < item->filters.size() - 1 && ((int) j < item->divider - 1 || item->divider < 0))
436 val.Append (wxT(":"));
437 }
438 if (item->divider >= 0)
439 {
440 val.Append (wxT("\\"));
441 for (size_t j = item->divider; j < item->filters.size(); j++)
442 {
443 val.Append (item->filters[j]);
444 if (j < item->filters.size() - 1)
445 val.Append (wxT(":"));
446 }
447 }
448 name.Printf (wxT("/ExtImportItems/Item%d"), (int)i);
449 gPrefs->Write (name, val);
450 gPrefs->Flush();
451 }
452 /* If we used to have more items than we have now, DELETE the excess items.
453 We just keep deleting items and incrementing until we find there aren't any
454 more to DELETE.*/
455 i = this->mExtImportItems.size();
456 do {
457 name.Printf (wxT("/ExtImportItems/Item%d"), (int)i);
458 // No item to DELETE? Then it's time to finish.
459 if (!gPrefs->Read(name, &val))
460 break;
461 // Failure to DELETE probably means a read-only config file.
462 // no point continuing.
463 // TODO: Possibly report (once).
464 if( !gPrefs->DeleteEntry (name))
465 break;
466 i++;
467 } while( true );
468}
469
470std::unique_ptr<ExtImportItem> Importer::CreateDefaultImportItem()
471{
472 auto new_item = std::make_unique<ExtImportItem>();
473 new_item->extensions.push_back(wxT("*"));
474 new_item->mime_types.push_back(wxT("*"));
475
476 for (const auto &importPlugin : sImportPluginList())
477 {
478 new_item->filters.push_back(importPlugin->GetPluginStringID());
479 new_item->filter_objects.push_back(importPlugin);
480 }
481 new_item->divider = -1;
482 return new_item;
483}
484
485// returns number of tracks imported
487 AudacityProject& project, const FilePath& fName,
488 ImportProgressListener* importProgressListener,
489 WaveTrackFactory* trackFactory, TrackHolders& tracks, Tags* tags,
490 std::optional<LibFileFormats::AcidizerTags>& outAcidTags,
491 TranslatableString& errorMessage)
492{
493 AudacityProject *pProj = &project;
494 auto cleanup = valueRestorer( pProj->mbBusyImporting, true );
495
496 const FileExtension extension{ fName.AfterLast(wxT('.')) };
497
498 // Bug #2647: Peter has a Word 2000 .doc file that is recognized and imported by FFmpeg.
499 if (wxFileName(fName).GetExt() == wxT("doc")) {
500 errorMessage =
501 XO("\"%s\" \nis a not an audio file. \nAudacity cannot open this type of file.")
502 .Format( fName );
503 return false;
504 }
505
506 using ImportPluginPtrs = std::vector< ImportPlugin* >;
507
508 // This list is used to call plugins in correct order
509 ImportPluginPtrs importPlugins;
510
511 // This list is used to remember plugins that should have been compatible with the file.
512 ImportPluginPtrs compatiblePlugins;
513
514 // Not implemented (yet?)
515 wxString mime_type = wxT("*");
516
517 // First, add user-selected filter
518 bool usersSelectionOverrides;
519 gPrefs->Read(wxT("/ExtendedImport/OverrideExtendedImportByOpenFileDialogChoice"), &usersSelectionOverrides, false);
520
521 if (usersSelectionOverrides)
522 {
523 // If user explicitly selected a filter,
524 // then we should try importing via corresponding plugin first
525 wxString type = gPrefs->Read(wxT("/LastOpenType"),wxT(""));
526
527 wxLogDebug(wxT("LastOpenType is %s"),type);
528 wxLogDebug(wxT("OverrideExtendedImportByOpenFileDialogChoice is %i"),usersSelectionOverrides);
529
530 for (const auto &plugin : sImportPluginList())
531 {
532 if (plugin->GetPluginFormatDescription().Translation() == type )
533 {
534 // This plugin corresponds to user-selected filter, try it first.
535 wxLogDebug(wxT("Inserting %s"),plugin->GetPluginStringID());
536 importPlugins.insert(importPlugins.begin(), plugin);
537 }
538 }
539 }
540
541 wxLogMessage(wxT("File name is %s"), fName);
542 wxLogMessage(wxT("Mime type is %s"), mime_type.Lower());
543
544 for (const auto &uItem : mExtImportItems)
545 {
546 ExtImportItem *item = uItem.get();
547 bool matches_ext = false, matches_mime = false;
548 wxLogDebug(wxT("Testing extensions"));
549 for (size_t j = 0; j < item->extensions.size(); j++)
550 {
551 wxLogDebug(wxT("%s"), item->extensions[j].Lower());
552 if (wxMatchWild (item->extensions[j].Lower(),fName.Lower(), false))
553 {
554 wxLogDebug(wxT("Match!"));
555 matches_ext = true;
556 break;
557 }
558 }
559 if (item->extensions.size() == 0)
560 {
561 wxLogDebug(wxT("Match! (empty list)"));
562 matches_ext = true;
563 }
564 if (matches_ext)
565 wxLogDebug(wxT("Testing mime types"));
566 else
567 wxLogDebug(wxT("Not testing mime types"));
568 for (size_t j = 0; matches_ext && j < item->mime_types.size(); j++)
569 {
570 if (wxMatchWild (item->mime_types[j].Lower(),mime_type.Lower(), false))
571 {
572 wxLogDebug(wxT("Match!"));
573 matches_mime = true;
574 break;
575 }
576 }
577 if (item->mime_types.size() == 0)
578 {
579 wxLogDebug(wxT("Match! (empty list)"));
580 matches_mime = true;
581 }
582 if (matches_ext && matches_mime)
583 {
584 wxLogDebug(wxT("Complete match!"));
585 for (size_t j = 0; j < item->filter_objects.size() && (item->divider < 0 || (int) j < item->divider); j++)
586 {
587 // the filter_object can be NULL if a suitable importer was not found
588 // this happens when we recompile with --without-ffmpeg and there
589 // is still ffmpeg in prefs from previous --with-ffmpeg builds
590 if (!(item->filter_objects[j]))
591 continue;
592 wxLogDebug(wxT("Inserting %s"),item->filter_objects[j]->GetPluginStringID());
593 importPlugins.push_back(item->filter_objects[j]);
594 }
595 }
596 }
597
598 // Add all plugins that support the extension
599 for (const auto &plugin : sImportPluginList())
600 {
601 // Make sure its not already in the list
602 if (importPlugins.end() ==
603 std::find(importPlugins.begin(), importPlugins.end(), plugin))
604 {
605 if (plugin->SupportsExtension(extension))
606 {
607 wxLogDebug(wxT("Appending %s"),plugin->GetPluginStringID());
608 importPlugins.push_back(plugin);
609 }
610 }
611 }
612
613 // Add remaining plugins
614 for (const auto &plugin : sImportPluginList())
615 {
616 // Make sure its not already in the list
617 if (importPlugins.end() ==
618 std::find(importPlugins.begin(), importPlugins.end(), plugin))
619 {
620 wxLogDebug(wxT("Appending %s"),plugin->GetPluginStringID());
621 importPlugins.push_back(plugin);
622 }
623 }
624
625 ImportProgressResultProxy importResultProxy(importProgressListener);
626
627 // Try the import plugins, in the permuted sequences just determined
628 for (const auto plugin : importPlugins)
629 {
630 // Try to open the file with this plugin (probe it)
631 wxLogMessage(wxT("Opening with %s"),plugin->GetPluginStringID());
632 auto inFile = plugin->Open(fName, pProj);
633 if ( (inFile != NULL) && (inFile->GetStreamCount() > 0) )
634 {
635 wxLogMessage(wxT("Open(%s) succeeded"), fName);
636 if(!importResultProxy.OnImportFileOpened(*inFile))
637 return false;
638
639 inFile->Import(
640 importResultProxy, trackFactory, tracks, tags, outAcidTags);
641 const auto importResult = importResultProxy.GetResult();
644 {
645 // LOF ("list-of-files") has different semantics
646 if (extension.IsSameAs(wxT("lof"), false))
647 {
648 return true;
649 }
650
651 // AUP ("legacy projects") have different semantics
652 if (extension.IsSameAs(wxT("aup"), false))
653 {
654 return true;
655 }
656
657 auto end = tracks.end();
658 auto iter = std::remove_if(tracks.begin(), end,
659 [](auto &pList){ return pList->empty(); });
660 if (iter != end) {
661 // importer shouldn't give us empty groups of channels!
662 assert(false);
663 // But correct that and proceed anyway
664 tracks.erase(iter, end);
665 }
666 if (tracks.size() > 0)
667 // success!
668 return true;
669 }
670
671 if (importResultProxy.GetResult() == ImportProgressListener::ImportResult::Cancelled)
672 return false;
673
674 // We could exit here since we had a match on the file extension,
675 // but there may be another plug-in that can import the file and
676 // that may recognize the extension, so we allow the loop to
677 // continue.
678 }
679 }
680 wxLogError(wxT("Importer::Import: Opening failed."));
681
682 // None of our plugins can handle this file. It might be that
683 // Audacity supports this format, but support was not compiled in.
684 // If so, notify the user of this fact
685 for (const auto &unusableImportPlugin : sUnusableImportPluginList())
686 {
687 if( unusableImportPlugin->SupportsExtension(extension) )
688 {
689 errorMessage = XO("This version of Audacity was not compiled with %s support.")
690 .Format( unusableImportPlugin->GetPluginFormatDescription() );
691 return false;
692 }
693 }
694
695 /* warnings for unsupported data types */
696
697 if (compatiblePlugins.empty())
698 {
699 // if someone has sent us a .cda file, send them away
700 if (extension.IsSameAs(wxT("cda"), false)) {
701 errorMessage = XO(
702/* i18n-hint: %s will be the filename */
703"\"%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.")
704 .Format( fName );
705 return false;
706 }
707
708 // playlist type files
709 if ((extension.IsSameAs(wxT("m3u"), false))||(extension.IsSameAs(wxT("ram"), false))||(extension.IsSameAs(wxT("pls"), false))) {
710 errorMessage = XO(
711/* i18n-hint: %s will be the filename */
712"\"%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.")
713 .Format( fName );
714 return false;
715 }
716 //WMA files of various forms
717 if ((extension.IsSameAs(wxT("wma"), false))||(extension.IsSameAs(wxT("asf"), false))) {
718 errorMessage = XO(
719/* i18n-hint: %s will be the filename */
720"\"%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.")
721 .Format( fName );
722 return false;
723 }
724 //AAC files of various forms (probably not encrypted)
725 if ((extension.IsSameAs(wxT("aac"), false))||(extension.IsSameAs(wxT("m4a"), false))||(extension.IsSameAs(wxT("m4r"), false))||(extension.IsSameAs(wxT("mp4"), false))) {
726 errorMessage = XO(
727/* i18n-hint: %s will be the filename */
728"\"%s\" is an Advanced Audio Coding file.\nWithout the optional FFmpeg library, Audacity cannot open this type of file.\nOtherwise, you need to convert it to a supported audio format, such as WAV or AIFF.")
729 .Format( fName );
730 return false;
731 }
732 // encrypted itunes files
733 if ((extension.IsSameAs(wxT("m4p"), false))) {
734 errorMessage = XO(
735/* i18n-hint: %s will be the filename */
736"\"%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.")
737 .Format( fName );
738 return false;
739 }
740 // Real Inc. files of various sorts
741 if ((extension.IsSameAs(wxT("ra"), false))||(extension.IsSameAs(wxT("rm"), false))||(extension.IsSameAs(wxT("rpm"), false))) {
742 errorMessage = XO(
743/* i18n-hint: %s will be the filename */
744"\"%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.")
745 .Format( fName );
746 return false;
747 }
748
749 // Other notes-based formats
750 if ((extension.IsSameAs(wxT("kar"), false))||(extension.IsSameAs(wxT("mod"), false))||(extension.IsSameAs(wxT("rmi"), false))) {
751 errorMessage = XO(
752/* i18n-hint: %s will be the filename */
753"\"%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.")
754 .Format( fName );
755 return false;
756 }
757
758 // MusePack files
759 if ((extension.IsSameAs(wxT("mp+"), false))||(extension.IsSameAs(wxT("mpc"), false))||(extension.IsSameAs(wxT("mpp"), false))) {
760 errorMessage = XO(
761/* i18n-hint: %s will be the filename */
762"\"%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.")
763 .Format( fName );
764 return false;
765 }
766
767 // WavPack files
768 if ((extension.IsSameAs(wxT("wv"), false))||(extension.IsSameAs(wxT("wvc"), false))) {
769 errorMessage = XO(
770/* i18n-hint: %s will be the filename */
771"\"%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.")
772 .Format( fName );
773 return false;
774 }
775
776 // AC3 files
777 if ((extension.IsSameAs(wxT("ac3"), false))) {
778 errorMessage = XO(
779/* i18n-hint: %s will be the filename */
780"\"%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.")
781 .Format( fName );
782 return false;
783 }
784
785 // Speex files
786 if ((extension.IsSameAs(wxT("spx"), false))) {
787 errorMessage = XO(
788/* i18n-hint: %s will be the filename */
789"\"%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.")
790 .Format( fName );
791 return false;
792 }
793
794 // Video files of various forms
795 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))) {
796 errorMessage = XO(
797/* i18n-hint: %s will be the filename */
798"\"%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.")
799 .Format( fName );
800 return false;
801 }
802
803 if( !wxFileExists(fName)){
804 errorMessage = XO( "File \"%s\" not found.").Format( fName );
805 return false;
806 }
807
808 // we were not able to recognize the file type
809 TranslatableString extraMessages;
810 for(const auto &importPlugin : sImportPluginList()) {
811 auto message = importPlugin->FailureHint();
812 if (!message.empty()) {
813 extraMessages += message;
814 extraMessages += Verbatim("\n");
815 }
816 }
817
818 errorMessage = XO(
819/* i18n-hint: %s will be the filename */
820"Audacity did not recognize the type of the file '%s'.\n\n%sFor uncompressed files, also try File > Import > Raw Data.")
821 .Format( fName, extraMessages );
822 }
823 else
824 {
825 // We DO have a plugin for this file, but import failed.
826 TranslatableString pluglist;
827
828 for (const auto &plugin : compatiblePlugins)
829 {
830 if (pluglist.empty())
831 pluglist = plugin->GetPluginFormatDescription();
832 else
833 pluglist = XO("%s, %s")
834 .Format( pluglist, plugin->GetPluginFormatDescription() );
835 }
836
837 errorMessage = XO(
838/* i18n-hint: %s will be the filename */
839"Audacity recognized the type of the file '%s'.\nImporters supposedly supporting such files are:\n%s,\nbut none of them understood this file format.")
840 .Format( fName, pluglist );
841 }
842
843 return false;
844}
845
846BoolSetting NewImportingSession{ L"/NewImportingSession", false };
wxT("CloseDown"))
#define str(a)
const TranslatableString name
Definition: Distortion.cpp:76
XO("Cut/Copy/Paste")
wxString FileExtension
File extension, not including any leading dot.
Definition: Identifier.h:224
BoolSetting NewImportingSession
Definition: Import.cpp:846
std::vector< std::unique_ptr< ExtImportItem > > ExtImportItems
Definition: Import.h:42
std::vector< std::unique_ptr< UnusableImportPlugin > > UnusableImportPluginList
std::vector< ImportPlugin * > ImportPluginList
The interface that all file import "plugins" (if you want to call them that) must implement....
std::vector< std::shared_ptr< TrackList > > TrackHolders
Definition: ImportRaw.h:24
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:250
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
wxString FilePath
Definition: Project.h:21
const auto tracks
const auto project
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
int id
static std::once_flag flag
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
bool mbBusyImporting
Definition: Project.h:130
This specialization of Setting for bool adds a Toggle method to negate the saved value.
Definition: Prefs.h:346
wxArrayString filters
Definition: Import.h:55
int divider
Definition: Import.h:64
wxArrayString extensions
Definition: Import.h:75
wxArrayString mime_types
Definition: Import.h:81
std::vector< ImportPlugin * > filter_objects
Definition: Import.h:69
std::vector< FileType > FileTypes
Definition: FileNames.h:75
FILES_API const FileType AllFiles
Definition: FileNames.h:70
FILES_API const FileType AudacityProjects
Definition: FileNames.h:71
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
Base class for FlacImportFileHandle, LOFImportFileHandle, MP3ImportFileHandle, OggImportFileHandle an...
Definition: ImportPlugin.h:111
Interface used to report on import state and progress.
Singleton class which actually imports the audio, using ImportPlugin objects that are registered by m...
Definition: Import.h:84
static Importer mInstance
Definition: Import.h:198
static Importer & Get()
Definition: Import.cpp:102
void StringToList(wxString &str, wxString &delims, wxArrayString &list, wxStringTokenizerMode mod=wxTOKEN_RET_EMPTY_ALL)
Definition: Import.cpp:290
static void SetLastOpenType(const FileNames::FileType &type)
Definition: Import.cpp:253
bool Initialize()
Definition: Import.cpp:166
void WriteImportItems()
Definition: Import.cpp:409
static UnusableImportPluginList & sUnusableImportPluginList()
Definition: Import.cpp:153
ExtImportItems mExtImportItems
Definition: Import.h:200
FileNames::FileTypes GetFileTypes(const FileNames::FileType &extraType={})
Definition: Import.cpp:208
~Importer()
Definition: Import.cpp:111
bool Import(AudacityProject &project, const FilePath &fName, ImportProgressListener *importProgressListener, WaveTrackFactory *trackFactory, TrackHolders &tracks, Tags *tags, std::optional< LibFileFormats::AcidizerTags > &outAcidTags, TranslatableString &errorMessage)
Definition: Import.cpp:486
bool Terminate()
Definition: Import.cpp:200
std::unique_ptr< ExtImportItem > CreateDefaultImportItem()
Definition: Import.cpp:470
static size_t SelectDefaultOpenType(const FileNames::FileTypes &fileTypes)
Definition: Import.cpp:273
void ReadImportItems()
Definition: Import.cpp:298
static void SetDefaultOpenType(const FileNames::FileType &type)
Definition: Import.cpp:263
static ImportPluginList & sImportPluginList()
Definition: Import.cpp:115
Importer()
Definition: Import.cpp:107
ID3 Tags (for MP3)
Definition: Tags.h:73
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:1279
ImportProgressResultProxy(ImportProgressListener *listener)
Definition: Import.cpp:60
bool OnImportFileOpened(ImportFileHandle &importFileHandle) override
Definition: Import.cpp:66
void OnImportResult(ImportResult result) override
Used to report on import result for file handle passed as argument to OnImportFileOpened.
Definition: Import.cpp:80
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
bool DeleteEntry(const wxString &key)
Deletes specified entry if exists.
virtual bool Read(const wxString &key, bool *value) const =0
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
iterator insert(const_iterator pos, std::initializer_list< T > items)
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
void Visit(const Visitors &visitors, const GroupItem< RegistryTraits > *pTopItem, const GroupItem< RegistryTraits > *pRegistry={}, typename RegistryTraits::ComputedItemContextType &computedItemContext=RegistryTraits::ComputedItemContextType::Instance)
Definition: Registry.h:609
static const auto PathStart
Definition: Import.cpp:122
STL namespace.
TranslatableString description
Definition: FileNames.h:60
FileExtensions extensions
Definition: FileNames.h:61
ImporterItem(const Identifier &id, std::unique_ptr< ImportPlugin > pPlugin)
Definition: Import.cpp:133
std::unique_ptr< ImportPlugin > mpPlugin
Definition: Import.h:195
static Registry::GroupItem< Traits > & Registry()
Definition: Import.cpp:127
RegisteredImportPlugin(const Identifier &id, std::unique_ptr< ImportPlugin >, const Registry::Placement &placement={ wxEmptyString, {} })
Definition: Import.cpp:140
RegisteredUnusableImportPlugin(std::unique_ptr< UnusableImportPlugin >)
Definition: Import.cpp:159