40#include <unordered_set>
69 mResult = ImportResult::Error;
71 return mListener->OnImportFileOpened(importFileHandle);
78 mListener->OnImportProgress(progress);
85 mListener->OnImportResult(result);
136 , mpPlugin{
std::move( pPlugin ) }
143 std::unique_ptr<ImportPlugin> pPlugin,
161 std::unique_ptr<UnusableImportPlugin> pPlugin )
178 { {
wxT(
""),
wxT(
"AUP,PCM,OGG,FLAC,MP3,LOF,WavPack,portsmf,FFmpeg") } }
183 static std::once_flag
flag;
184 std::call_once(
flag, []{
215 {
XO(
"All supported files"), {} },
220 fileTypes.push_back( extraType );
225 l.emplace_back(importPlugin->GetPluginFormatDescription(),
226 importPlugin->GetSupportedExtensions());
230 extraExtensions.
insert(extraExtensions.end(),
234 using ExtensionSet = std::unordered_set< FileExtension >;
237 ExtensionSet allSet{ allList.begin(), allList.end() }, newSet;
238 for (
const auto &
format : l ) {
247 fileTypes.push_back( {
format.description, newList } );
250 fileTypes[1].extensions = allList;
276 wxString defaultValue;
277 if ( !fileTypes.empty() )
278 defaultValue = fileTypes[0].description.Translation();
280 wxString type =
gPrefs->
Read(
wxT(
"/DefaultOpenType"), defaultValue);
282 auto begin = fileTypes.begin();
283 auto index = std::distance(
285 std::find_if(
begin, fileTypes.end(),
287 return fileType.description.Translation() == type; } ) );
288 return (index == fileTypes.size()) ? 0 : index;
293 wxStringTokenizer toker;
295 for (toker.SetString(
str, delims, mod);
296 toker.HasMoreTokens(); list.push_back(toker.GetNextToken()));
301 int item_counter = 0;
302 wxStringTokenizer toker;
311 for (item_counter = 0;
true; item_counter++)
313 wxString condition, filters, used_filters, unused_filters, extensions, mime_types;
314 item_name.Printf (
wxT(
"/ExtImportItems/Item%d"), item_counter);
319 toker.SetString(item_value,
wxT(
"|"), wxTOKEN_RET_EMPTY_ALL);
321 if (toker.CountTokens() != 2)
324 auto new_item = std::make_unique<ExtImportItem>();
327 condition = toker.GetNextToken();
328 filters = toker.GetNextToken();
332 toker.SetString(condition,
wxT(
"\\"), wxTOKEN_RET_EMPTY_ALL);
333 extensions = toker.GetNextToken();
334 if (toker.HasMoreTokens())
335 mime_types = toker.GetNextToken();
337 wxString delims(
wxT(
":"));
338 StringToList (extensions, delims, new_item->extensions);
340 if (!mime_types.empty())
341 StringToList (mime_types, delims, new_item->mime_types);
344 toker.SetString(filters,
wxT(
"\\"), wxTOKEN_RET_EMPTY_ALL);
345 used_filters = toker.GetNextToken();
346 if (toker.HasMoreTokens())
347 unused_filters = toker.GetNextToken();
351 if (!unused_filters.empty())
356 new_item->divider = new_item->filters.size();
357 StringToList (unused_filters, delims, new_item->filters);
360 new_item->divider = -1;
363 for (
size_t i = 0; i < new_item->filters.size(); i++)
368 if (importPlugin->GetPluginStringID() == new_item->filters[i])
370 new_item->filter_objects.push_back(importPlugin);
377 new_item->filter_objects.push_back(
nullptr);
383 for (
size_t i = 0; i < new_item->filter_objects.size(); i++)
385 if (importPlugin == new_item->filter_objects[i])
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)
419 for (
size_t j = 0; j < item->
extensions.size(); j++)
422 if (j < item->extensions.size() - 1)
423 val.Append (
wxT(
":"));
425 val.Append (
wxT(
"\\"));
426 for (
size_t j = 0; j < item->
mime_types.size(); j++)
429 if (j < item->mime_types.size() - 1)
430 val.Append (
wxT(
":"));
432 val.Append (
wxT(
"|"));
433 for (
size_t j = 0; j < item->
filters.size() && ((
int) j < item->divider || item->
divider < 0); j++)
436 if (j < item->filters.size() - 1 && ((
int) j < item->divider - 1 || item->
divider < 0))
437 val.Append (
wxT(
":"));
441 val.Append (
wxT(
"\\"));
442 for (
size_t j = item->
divider; j < item->filters.size(); j++)
445 if (j < item->filters.size() - 1)
446 val.Append (
wxT(
":"));
449 name.Printf (
wxT(
"/ExtImportItems/Item%d"), (
int)i);
458 name.Printf (
wxT(
"/ExtImportItems/Item%d"), (
int)i);
473 auto new_item = std::make_unique<ExtImportItem>();
474 new_item->extensions.push_back(
wxT(
"*"));
475 new_item->mime_types.push_back(
wxT(
"*"));
479 new_item->filters.push_back(importPlugin->GetPluginStringID());
480 new_item->filter_objects.push_back(importPlugin);
482 new_item->divider = -1;
491 std::optional<LibFileFormats::AcidizerTags>& outAcidTags,
500 if (wxFileName(fName).GetExt() ==
wxT(
"doc")) {
502 XO(
"\"%s\" \nis a not an audio file. \nAudacity cannot open this type of file.")
507 using ImportPluginPtrs = std::vector< ImportPlugin* >;
510 ImportPluginPtrs importPlugins;
513 ImportPluginPtrs compatiblePlugins;
516 wxString mime_type =
wxT(
"*");
519 bool usersSelectionOverrides;
520 gPrefs->
Read(
wxT(
"/ExtendedImport/OverrideExtendedImportByOpenFileDialogChoice"), &usersSelectionOverrides,
false);
522 if (usersSelectionOverrides)
528 wxLogDebug(
wxT(
"LastOpenType is %s"),type);
529 wxLogDebug(
wxT(
"OverrideExtendedImportByOpenFileDialogChoice is %i"),usersSelectionOverrides);
533 if (plugin->GetPluginFormatDescription().Translation() == type )
536 wxLogDebug(
wxT(
"Inserting %s"),plugin->GetPluginStringID());
537 importPlugins.insert(importPlugins.begin(), plugin);
542 wxLogMessage(
wxT(
"File name is %s"), fName);
543 wxLogMessage(
wxT(
"Mime type is %s"), mime_type.Lower());
548 bool matches_ext =
false, matches_mime =
false;
549 wxLogDebug(
wxT(
"Testing extensions"));
550 for (
size_t j = 0; j < item->
extensions.size(); j++)
553 if (wxMatchWild (item->
extensions[j].Lower(),fName.Lower(),
false))
555 wxLogDebug(
wxT(
"Match!"));
562 wxLogDebug(
wxT(
"Match! (empty list)"));
566 wxLogDebug(
wxT(
"Testing mime types"));
568 wxLogDebug(
wxT(
"Not testing mime types"));
569 for (
size_t j = 0; matches_ext && j < item->
mime_types.size(); j++)
571 if (wxMatchWild (item->
mime_types[j].Lower(),mime_type.Lower(),
false))
573 wxLogDebug(
wxT(
"Match!"));
580 wxLogDebug(
wxT(
"Match! (empty list)"));
583 if (matches_ext && matches_mime)
585 wxLogDebug(
wxT(
"Complete match!"));
586 for (
size_t j = 0; j < item->
filter_objects.size() && (item->
divider < 0 || (
int) j < item->divider); j++)
603 if (importPlugins.end() ==
604 std::find(importPlugins.begin(), importPlugins.end(), plugin))
606 if (plugin->SupportsExtension(
extension))
608 wxLogDebug(
wxT(
"Appending %s"),plugin->GetPluginStringID());
609 importPlugins.push_back(plugin);
618 if (importPlugins.end() ==
619 std::find(importPlugins.begin(), importPlugins.end(), plugin))
621 wxLogDebug(
wxT(
"Appending %s"),plugin->GetPluginStringID());
622 importPlugins.push_back(plugin);
626 ImportProgressResultProxy importResultProxy(importProgressListener);
629 for (
const auto plugin : importPlugins)
632 wxLogMessage(
wxT(
"Opening with %s"),plugin->GetPluginStringID());
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))
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)
647 errorMessage =
XO(
"Operation was canceled by user");
650 memset(&s, 0,
sizeof(
struct stat));
651 err = stat(fName.data(), &s);
655 auto inFile = plugin->Open(fName, pProj);
656 if ( (inFile != NULL) && (inFile->GetStreamCount() > 0) )
658 wxLogMessage(
wxT(
"Open(%s) succeeded"), fName);
659 if(!importResultProxy.OnImportFileOpened(*inFile))
663 importResultProxy, trackFactory,
tracks, tags, outAcidTags);
664 const auto importResult = importResultProxy.GetResult();
694 wxLogError(
wxT(
"Importer::Import: Opening failed."));
701 if( unusableImportPlugin->SupportsExtension(
extension) )
703 errorMessage =
XO(
"This version of Audacity was not compiled with %s support.")
704 .Format( unusableImportPlugin->GetPluginFormatDescription() );
711 if (compatiblePlugins.empty())
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.")
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.")
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.")
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.")
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.")
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.")
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.")
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.")
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.")
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.")
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.")
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.")
817 if( !wxFileExists(fName)){
818 errorMessage =
XO(
"File \"%s\" not found.").Format( fName );
825 auto message = importPlugin->FailureHint();
826 if (!message.empty()) {
827 extraMessages += message;
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 );
842 for (
const auto &plugin : compatiblePlugins)
844 if (pluglist.
empty())
845 pluglist = plugin->GetPluginFormatDescription();
847 pluglist =
XO(
"%s, %s")
848 .Format( pluglist, plugin->GetPluginFormatDescription() );
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 );
Toolkit-neutral facade for basic user interface services.
wxString FileExtension
File extension, not including any leading dot.
BoolSetting NewImportingSession
std::vector< std::unique_ptr< ExtImportItem > > ExtImportItems
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
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
audacity::BasicSettings * gPrefs
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
This specialization of Setting for bool adds a Toggle method to negate the saved value.
std::vector< ImportPlugin * > filter_objects
std::vector< FileType > FileTypes
FILES_API const FileType AllFiles
FILES_API const FileType AudacityProjects
An explicitly nonlocalized string, not meant for the user to see.
Base class for FlacImportFileHandle, LOFImportFileHandle, MP3ImportFileHandle, OggImportFileHandle an...
Interface used to report on import state and progress.
Singleton class which actually imports the audio, using ImportPlugin objects that are registered by m...
static Importer mInstance
void StringToList(wxString &str, wxString &delims, wxArrayString &list, wxStringTokenizerMode mod=wxTOKEN_RET_EMPTY_ALL)
static void SetLastOpenType(const FileNames::FileType &type)
static UnusableImportPluginList & sUnusableImportPluginList()
ExtImportItems mExtImportItems
FileNames::FileTypes GetFileTypes(const FileNames::FileType &extraType={})
bool Import(AudacityProject &project, const FilePath &fName, ImportProgressListener *importProgressListener, WaveTrackFactory *trackFactory, TrackHolders &tracks, Tags *tags, std::optional< LibFileFormats::AcidizerTags > &outAcidTags, TranslatableString &errorMessage)
std::unique_ptr< ExtImportItem > CreateDefaultImportItem()
static size_t SelectDefaultOpenType(const FileNames::FileTypes &fileTypes)
static void SetDefaultOpenType(const FileNames::FileType &type)
static ImportPluginList & sImportPluginList()
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...
ImportResult GetResult() const noexcept
ImportProgressResultProxy(ImportProgressListener *listener)
bool OnImportFileOpened(ImportFileHandle &importFileHandle) override
void OnImportResult(ImportResult result) override
Used to report on import result for file handle passed as argument to OnImportFileOpened.
void OnImportProgress(double progress) override
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)
@ ProgressShowElapsedTime
void Yield()
Dispatch waiting events, including actions enqueued by CallAfter.
void Visit(const Visitors &visitors, const GroupItem< RegistryTraits > *pTopItem, const GroupItem< RegistryTraits > *pRegistry={}, typename RegistryTraits::ComputedItemContextType &computedItemContext=RegistryTraits::ComputedItemContextType::Instance)
ProjectFileIOExtensionRegistry::Extension extension
static const auto PathStart
const char * begin(const char *str) noexcept
TranslatableString description
FileExtensions extensions
ImporterItem(const Identifier &id, std::unique_ptr< ImportPlugin > pPlugin)
std::unique_ptr< ImportPlugin > mpPlugin
static Registry::GroupItem< Traits > & Registry()
RegisteredImportPlugin(const Identifier &id, std::unique_ptr< ImportPlugin >, const Registry::Placement &placement={ wxEmptyString, {} })
RegisteredUnusableImportPlugin(std::unique_ptr< UnusableImportPlugin >)