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