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*******************************************************************//***************************************************************//***************************************************************//******************************************************************/
35
36#include "Import.h"
37
38#include "ImportPlugin.h"
39
40#include <algorithm>
41#include <unordered_set>
42
43#include <wx/log.h>
44#include "FileNames.h"
45#include "Project.h"
46#include "WaveTrack.h"
47
48#include "Prefs.h"
49
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{
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 { {wxT(""), wxT("AUP,PCM,OGG,FLAC,MP3,LOF,WavPack,FFmpeg") } }
177 // QT and GStreamer are only conditionally compiled and would get
178 // placed at the end if present
179 };
180
181 static struct MyVisitor final : Visitor {
182 MyVisitor()
183 {
184 // Once only, visit the registry to collect the plug-ins properly
185 // sorted
187 Registry::Visit( *this, &top, &ImporterItem::Registry() );
188 }
189
190 void Visit( SingleItem &item, const Path &path ) override
191 {
192 sImportPluginList().push_back(
193 static_cast<ImporterItem&>( item ).mpPlugin.get() );
194 }
195 } visitor;
196
197 // Ordering of the unusable plugin list is not important.
198
200
202
203 return true;
204}
205
207{
209
210 return true;
211}
212
215{
216 // Construct the filter
217 FileNames::FileTypes fileTypes{
219 // Will fill in the list of extensions later:
220 { XO("All supported files"), {} },
222 };
223
224 if ( !extraType.extensions.empty() )
225 fileTypes.push_back( extraType );
226
228 for(const auto &importPlugin : sImportPluginList())
229 {
230 l.emplace_back(importPlugin->GetPluginFormatDescription(),
231 importPlugin->GetSupportedExtensions());
232 }
233
234 FileExtensions extraExtensions = FileNames::AudacityProjects.extensions;
235 extraExtensions.insert(extraExtensions.end(),
236 extraType.extensions.begin(),
237 extraType.extensions.end());
238
239 using ExtensionSet = std::unordered_set< FileExtension >;
240 FileExtensions allList = FileNames::AudacityProjects.extensions, newList;
241 allList.insert(allList.end(), extraType.extensions.begin(), extraType.extensions.end());
242 ExtensionSet allSet{ allList.begin(), allList.end() }, newSet;
243 for ( const auto &format : l ) {
244 newList.clear();
245 newSet.clear();
246 for ( const auto &extension : format.extensions ) {
247 if ( newSet.insert( extension ).second )
248 newList.push_back( extension );
249 if ( allSet.insert( extension ).second )
250 allList.push_back( extension );
251 }
252 fileTypes.push_back( { format.description, newList } );
253 }
254
255 fileTypes[1].extensions = allList;
256 return fileTypes;
257}
258
260{
261 // PRL: Preference key /LastOpenType, unusually, stores a localized
262 // string!
263 // The bad consequences of a change of locale are not severe -- only that
264 // a default choice of file type for an open dialog is not remembered
265 gPrefs->Write(wxT("/LastOpenType"), type.description.Translation());
266 gPrefs->Flush();
267}
268
270{
271 // PRL: Preference key /DefaultOpenType, unusually, stores a localized
272 // string!
273 // The bad consequences of a change of locale are not severe -- only that
274 // a default choice of file type for an open dialog is not remembered
275 gPrefs->Write(wxT("/DefaultOpenType"), type.description.Translation());
276 gPrefs->Flush();
277}
278
280{
281 wxString defaultValue;
282 if ( !fileTypes.empty() )
283 defaultValue = fileTypes[0].description.Translation();
284
285 wxString type = gPrefs->Read(wxT("/DefaultOpenType"), defaultValue);
286 // Convert the type to the filter index
287 auto begin = fileTypes.begin();
288 auto index = std::distance(
289 begin,
290 std::find_if( begin, fileTypes.end(),
291 [&type](const FileNames::FileType &fileType){
292 return fileType.description.Translation() == type; } ) );
293 return (index == fileTypes.size()) ? 0 : index;
294}
295
296void Importer::StringToList(wxString &str, wxString &delims, wxArrayString &list, wxStringTokenizerMode mod)
297{
298 wxStringTokenizer toker;
299
300 for (toker.SetString(str, delims, mod);
301 toker.HasMoreTokens(); list.push_back(toker.GetNextToken()));
302}
303
305{
306 int item_counter = 0;
307 wxStringTokenizer toker;
308 wxString item_name;
309 wxString item_value;
310
312 /* Rule string format is:
313 * extension1:extension2:extension3\mime_type1:mime_type2:mime_type3|filter1:filter2:filter3\unusedfilter1:unusedfilter2
314 * backslashes are escaped and unescaped internally
315 */
316 for (item_counter = 0; true; item_counter++)
317 {
318 wxString condition, filters, used_filters, unused_filters, extensions, mime_types;
319 item_name.Printf (wxT("/ExtImportItems/Item%d"), item_counter);
320 /* Break at first non-existent item */
321 if (!gPrefs->Read(item_name, &item_value))
322 break;
323
324 toker.SetString(item_value, wxT("|"), wxTOKEN_RET_EMPTY_ALL);
325 /* Break at first broken item */
326 if (toker.CountTokens() != 2)
327 break;
328
329 auto new_item = std::make_unique<ExtImportItem>();
330
331 /* First token is the filtering condition, second - the filter list */
332 condition = toker.GetNextToken();
333 filters = toker.GetNextToken();
334
335 /* Condition token consists of extension list and mime type list
336 * mime type list can be omitted entirely (complete with '\' separator)*/
337 toker.SetString(condition, wxT("\\"), wxTOKEN_RET_EMPTY_ALL);
338 extensions = toker.GetNextToken();
339 if (toker.HasMoreTokens())
340 mime_types = toker.GetNextToken();
341
342 wxString delims(wxT(":"));
343 StringToList (extensions, delims, new_item->extensions);
344
345 if (!mime_types.empty())
346 StringToList (mime_types, delims, new_item->mime_types);
347
348 /* Filter token consists of used and unused filter lists */
349 toker.SetString(filters, wxT("\\"), wxTOKEN_RET_EMPTY_ALL);
350 used_filters = toker.GetNextToken();
351 if (toker.HasMoreTokens())
352 unused_filters = toker.GetNextToken();
353
354 StringToList (used_filters, delims, new_item->filters);
355
356 if (!unused_filters.empty())
357 {
358 /* Filters are stored in one list, but the position at which
359 * unused filters start is remembered
360 */
361 new_item->divider = new_item->filters.size();
362 StringToList (unused_filters, delims, new_item->filters);
363 }
364 else
365 new_item->divider = -1;
366
367 /* Find corresponding filter object for each filter ID */
368 for (size_t i = 0; i < new_item->filters.size(); i++)
369 {
370 bool found = false;
371 for (const auto &importPlugin : sImportPluginList())
372 {
373 if (importPlugin->GetPluginStringID() == new_item->filters[i])
374 {
375 new_item->filter_objects.push_back(importPlugin);
376 found = true;
377 break;
378 }
379 }
380 /* IDs that do not have corresponding filters, will be shown as-is */
381 if (!found)
382 new_item->filter_objects.push_back(nullptr);
383 }
384 /* Find all filter objects that are not present in the filter list */
385 for (const auto &importPlugin : sImportPluginList())
386 {
387 bool found = false;
388 for (size_t i = 0; i < new_item->filter_objects.size(); i++)
389 {
390 if (importPlugin == new_item->filter_objects[i])
391 {
392 found = true;
393 break;
394 }
395 }
396 /* Add these filters at the bottom of used filter list */
397 if (!found)
398 {
399 int index = new_item->divider;
400 if (new_item->divider < 0)
401 index = new_item->filters.size();
402 new_item->filters.insert(
403 new_item->filters.begin() + index,
404 importPlugin->GetPluginStringID());
405 new_item->filter_objects.insert(
406 new_item->filter_objects.begin() + index, importPlugin);
407 if (new_item->divider >= 0)
408 new_item->divider++;
409 }
410 }
411 this->mExtImportItems.push_back( std::move(new_item) );
412 }
413}
414
416{
417 size_t i;
418 wxString val, name;
419 for (i = 0; i < this->mExtImportItems.size(); i++)
420 {
421 ExtImportItem *item = mExtImportItems[i].get();
422 val.clear();
423
424 for (size_t j = 0; j < item->extensions.size(); j++)
425 {
426 val.Append (item->extensions[j]);
427 if (j < item->extensions.size() - 1)
428 val.Append (wxT(":"));
429 }
430 val.Append (wxT("\\"));
431 for (size_t j = 0; j < item->mime_types.size(); j++)
432 {
433 val.Append (item->mime_types[j]);
434 if (j < item->mime_types.size() - 1)
435 val.Append (wxT(":"));
436 }
437 val.Append (wxT("|"));
438 for (size_t j = 0; j < item->filters.size() && ((int) j < item->divider || item->divider < 0); j++)
439 {
440 val.Append (item->filters[j]);
441 if (j < item->filters.size() - 1 && ((int) j < item->divider - 1 || item->divider < 0))
442 val.Append (wxT(":"));
443 }
444 if (item->divider >= 0)
445 {
446 val.Append (wxT("\\"));
447 for (size_t j = item->divider; j < item->filters.size(); j++)
448 {
449 val.Append (item->filters[j]);
450 if (j < item->filters.size() - 1)
451 val.Append (wxT(":"));
452 }
453 }
454 name.Printf (wxT("/ExtImportItems/Item%d"), (int)i);
455 gPrefs->Write (name, val);
456 gPrefs->Flush();
457 }
458 /* If we used to have more items than we have now, DELETE the excess items.
459 We just keep deleting items and incrementing until we find there aren't any
460 more to DELETE.*/
461 i = this->mExtImportItems.size();
462 do {
463 name.Printf (wxT("/ExtImportItems/Item%d"), (int)i);
464 // No item to DELETE? Then it's time to finish.
465 if (!gPrefs->Read(name, &val))
466 break;
467 // Failure to DELETE probably means a read-only config file.
468 // no point continuing.
469 // TODO: Possibly report (once).
470 if( !gPrefs->DeleteEntry (name))
471 break;
472 i++;
473 } while( true );
474}
475
476std::unique_ptr<ExtImportItem> Importer::CreateDefaultImportItem()
477{
478 auto new_item = std::make_unique<ExtImportItem>();
479 new_item->extensions.push_back(wxT("*"));
480 new_item->mime_types.push_back(wxT("*"));
481
482 for (const auto &importPlugin : sImportPluginList())
483 {
484 new_item->filters.push_back(importPlugin->GetPluginStringID());
485 new_item->filter_objects.push_back(importPlugin);
486 }
487 new_item->divider = -1;
488 return new_item;
489}
490
491// returns number of tracks imported
493 const FilePath &fName,
494 ImportProgressListener* importProgressListener,
495 WaveTrackFactory *trackFactory,
497 Tags *tags,
498 TranslatableString &errorMessage)
499{
500 AudacityProject *pProj = &project;
501 auto cleanup = valueRestorer( pProj->mbBusyImporting, true );
502
503 const FileExtension extension{ fName.AfterLast(wxT('.')) };
504
505 // Always refuse to import MIDI, even though the FFmpeg plugin pretends to know how (but makes very bad renderings)
506#ifdef USE_MIDI
507 // MIDI files must be imported, not opened
508 if (FileNames::IsMidi(fName)) {
509 errorMessage = XO(
510"\"%s\" \nis a MIDI file, not an audio file. \nAudacity cannot open this type of file for playing, but you can\nedit it by clicking File > Import > MIDI.")
511 .Format( fName );
512 return false;
513 }
514#endif
515
516 // Bug #2647: Peter has a Word 2000 .doc file that is recognized and imported by FFmpeg.
517 if (wxFileName(fName).GetExt() == wxT("doc")) {
518 errorMessage =
519 XO("\"%s\" \nis a not an audio file. \nAudacity cannot open this type of file.")
520 .Format( fName );
521 return false;
522 }
523
524 using ImportPluginPtrs = std::vector< ImportPlugin* >;
525
526 // This list is used to call plugins in correct order
527 ImportPluginPtrs importPlugins;
528
529 // This list is used to remember plugins that should have been compatible with the file.
530 ImportPluginPtrs compatiblePlugins;
531
532 // Not implemented (yet?)
533 wxString mime_type = wxT("*");
534
535 // First, add user-selected filter
536 bool usersSelectionOverrides;
537 gPrefs->Read(wxT("/ExtendedImport/OverrideExtendedImportByOpenFileDialogChoice"), &usersSelectionOverrides, false);
538
539 if (usersSelectionOverrides)
540 {
541 // If user explicitly selected a filter,
542 // then we should try importing via corresponding plugin first
543 wxString type = gPrefs->Read(wxT("/LastOpenType"),wxT(""));
544
545 wxLogDebug(wxT("LastOpenType is %s"),type);
546 wxLogDebug(wxT("OverrideExtendedImportByOpenFileDialogChoice is %i"),usersSelectionOverrides);
547
548 for (const auto &plugin : sImportPluginList())
549 {
550 if (plugin->GetPluginFormatDescription().Translation() == type )
551 {
552 // This plugin corresponds to user-selected filter, try it first.
553 wxLogDebug(wxT("Inserting %s"),plugin->GetPluginStringID());
554 importPlugins.insert(importPlugins.begin(), plugin);
555 }
556 }
557 }
558
559 wxLogMessage(wxT("File name is %s"), fName);
560 wxLogMessage(wxT("Mime type is %s"), mime_type.Lower());
561
562 for (const auto &uItem : mExtImportItems)
563 {
564 ExtImportItem *item = uItem.get();
565 bool matches_ext = false, matches_mime = false;
566 wxLogDebug(wxT("Testing extensions"));
567 for (size_t j = 0; j < item->extensions.size(); j++)
568 {
569 wxLogDebug(wxT("%s"), item->extensions[j].Lower());
570 if (wxMatchWild (item->extensions[j].Lower(),fName.Lower(), false))
571 {
572 wxLogDebug(wxT("Match!"));
573 matches_ext = true;
574 break;
575 }
576 }
577 if (item->extensions.size() == 0)
578 {
579 wxLogDebug(wxT("Match! (empty list)"));
580 matches_ext = true;
581 }
582 if (matches_ext)
583 wxLogDebug(wxT("Testing mime types"));
584 else
585 wxLogDebug(wxT("Not testing mime types"));
586 for (size_t j = 0; matches_ext && j < item->mime_types.size(); j++)
587 {
588 if (wxMatchWild (item->mime_types[j].Lower(),mime_type.Lower(), false))
589 {
590 wxLogDebug(wxT("Match!"));
591 matches_mime = true;
592 break;
593 }
594 }
595 if (item->mime_types.size() == 0)
596 {
597 wxLogDebug(wxT("Match! (empty list)"));
598 matches_mime = true;
599 }
600 if (matches_ext && matches_mime)
601 {
602 wxLogDebug(wxT("Complete match!"));
603 for (size_t j = 0; j < item->filter_objects.size() && (item->divider < 0 || (int) j < item->divider); j++)
604 {
605 // the filter_object can be NULL if a suitable importer was not found
606 // this happens when we recompile with --without-ffmpeg and there
607 // is still ffmpeg in prefs from previous --with-ffmpeg builds
608 if (!(item->filter_objects[j]))
609 continue;
610 wxLogDebug(wxT("Inserting %s"),item->filter_objects[j]->GetPluginStringID());
611 importPlugins.push_back(item->filter_objects[j]);
612 }
613 }
614 }
615
616 // Add all plugins that support the extension
617 for (const auto &plugin : sImportPluginList())
618 {
619 // Make sure its not already in the list
620 if (importPlugins.end() ==
621 std::find(importPlugins.begin(), importPlugins.end(), plugin))
622 {
623 if (plugin->SupportsExtension(extension))
624 {
625 wxLogDebug(wxT("Appending %s"),plugin->GetPluginStringID());
626 importPlugins.push_back(plugin);
627 }
628 }
629 }
630
631 // Add remaining plugins
632 for (const auto &plugin : sImportPluginList())
633 {
634 // Make sure its not already in the list
635 if (importPlugins.end() ==
636 std::find(importPlugins.begin(), importPlugins.end(), plugin))
637 {
638 wxLogDebug(wxT("Appending %s"),plugin->GetPluginStringID());
639 importPlugins.push_back(plugin);
640 }
641 }
642
643 ImportProgressResultProxy importResultProxy(importProgressListener);
644
645 // Try the import plugins, in the permuted sequences just determined
646 for (const auto plugin : importPlugins)
647 {
648 // Try to open the file with this plugin (probe it)
649 wxLogMessage(wxT("Opening with %s"),plugin->GetPluginStringID());
650 auto inFile = plugin->Open(fName, pProj);
651 if ( (inFile != NULL) && (inFile->GetStreamCount() > 0) )
652 {
653 wxLogMessage(wxT("Open(%s) succeeded"), fName);
654 if(!importResultProxy.OnImportFileOpened(*inFile))
655 return false;
656
657 inFile->Import(importResultProxy, trackFactory, tracks, tags);
658 const auto importResult = importResultProxy.GetResult();
661 {
662 // LOF ("list-of-files") has different semantics
663 if (extension.IsSameAs(wxT("lof"), false))
664 {
665 return true;
666 }
667
668 // AUP ("legacy projects") have different semantics
669 if (extension.IsSameAs(wxT("aup"), false))
670 {
671 return true;
672 }
673
674 auto end = tracks.end();
675 auto iter = std::remove_if(tracks.begin(), end,
676 [](auto &pList){ return pList->empty(); });
677 if (iter != end) {
678 // importer shouldn't give us empty groups of channels!
679 assert(false);
680 // But correct that and proceed anyway
681 tracks.erase(iter, end);
682 }
683 if (tracks.size() > 0)
684 // success!
685 return true;
686 }
687
688 if (importResultProxy.GetResult() == ImportProgressListener::ImportResult::Cancelled)
689 return false;
690
691 // We could exit here since we had a match on the file extension,
692 // but there may be another plug-in that can import the file and
693 // that may recognize the extension, so we allow the loop to
694 // continue.
695 }
696 }
697 wxLogError(wxT("Importer::Import: Opening failed."));
698
699 // None of our plugins can handle this file. It might be that
700 // Audacity supports this format, but support was not compiled in.
701 // If so, notify the user of this fact
702 for (const auto &unusableImportPlugin : sUnusableImportPluginList())
703 {
704 if( unusableImportPlugin->SupportsExtension(extension) )
705 {
706 errorMessage = XO("This version of Audacity was not compiled with %s support.")
707 .Format( unusableImportPlugin->GetPluginFormatDescription() );
708 return false;
709 }
710 }
711
712 /* warnings for unsupported data types */
713
714 if (compatiblePlugins.empty())
715 {
716 // if someone has sent us a .cda file, send them away
717 if (extension.IsSameAs(wxT("cda"), false)) {
718 errorMessage = XO(
719/* i18n-hint: %s will be the filename */
720"\"%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.")
721 .Format( fName );
722 return false;
723 }
724
725 // playlist type files
726 if ((extension.IsSameAs(wxT("m3u"), false))||(extension.IsSameAs(wxT("ram"), false))||(extension.IsSameAs(wxT("pls"), false))) {
727 errorMessage = XO(
728/* i18n-hint: %s will be the filename */
729"\"%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.")
730 .Format( fName );
731 return false;
732 }
733 //WMA files of various forms
734 if ((extension.IsSameAs(wxT("wma"), false))||(extension.IsSameAs(wxT("asf"), false))) {
735 errorMessage = XO(
736/* i18n-hint: %s will be the filename */
737"\"%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.")
738 .Format( fName );
739 return false;
740 }
741 //AAC files of various forms (probably not encrypted)
742 if ((extension.IsSameAs(wxT("aac"), false))||(extension.IsSameAs(wxT("m4a"), false))||(extension.IsSameAs(wxT("m4r"), false))||(extension.IsSameAs(wxT("mp4"), false))) {
743 errorMessage = XO(
744/* i18n-hint: %s will be the filename */
745"\"%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.")
746 .Format( fName );
747 return false;
748 }
749 // encrypted itunes files
750 if ((extension.IsSameAs(wxT("m4p"), false))) {
751 errorMessage = XO(
752/* i18n-hint: %s will be the filename */
753"\"%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.")
754 .Format( fName );
755 return false;
756 }
757 // Real Inc. files of various sorts
758 if ((extension.IsSameAs(wxT("ra"), false))||(extension.IsSameAs(wxT("rm"), false))||(extension.IsSameAs(wxT("rpm"), false))) {
759 errorMessage = XO(
760/* i18n-hint: %s will be the filename */
761"\"%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.")
762 .Format( fName );
763 return false;
764 }
765
766 // Other notes-based formats
767 if ((extension.IsSameAs(wxT("kar"), false))||(extension.IsSameAs(wxT("mod"), false))||(extension.IsSameAs(wxT("rmi"), false))) {
768 errorMessage = XO(
769/* i18n-hint: %s will be the filename */
770"\"%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.")
771 .Format( fName );
772 return false;
773 }
774
775 // MusePack files
776 if ((extension.IsSameAs(wxT("mp+"), false))||(extension.IsSameAs(wxT("mpc"), false))||(extension.IsSameAs(wxT("mpp"), false))) {
777 errorMessage = XO(
778/* i18n-hint: %s will be the filename */
779"\"%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.")
780 .Format( fName );
781 return false;
782 }
783
784 // WavPack files
785 if ((extension.IsSameAs(wxT("wv"), false))||(extension.IsSameAs(wxT("wvc"), false))) {
786 errorMessage = XO(
787/* i18n-hint: %s will be the filename */
788"\"%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.")
789 .Format( fName );
790 return false;
791 }
792
793 // AC3 files
794 if ((extension.IsSameAs(wxT("ac3"), false))) {
795 errorMessage = XO(
796/* i18n-hint: %s will be the filename */
797"\"%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.")
798 .Format( fName );
799 return false;
800 }
801
802 // Speex files
803 if ((extension.IsSameAs(wxT("spx"), false))) {
804 errorMessage = XO(
805/* i18n-hint: %s will be the filename */
806"\"%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.")
807 .Format( fName );
808 return false;
809 }
810
811 // Video files of various forms
812 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))) {
813 errorMessage = XO(
814/* i18n-hint: %s will be the filename */
815"\"%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.")
816 .Format( fName );
817 return false;
818 }
819
820 if( !wxFileExists(fName)){
821 errorMessage = XO( "File \"%s\" not found.").Format( fName );
822 return false;
823 }
824
825 // we were not able to recognize the file type
826 TranslatableString extraMessages;
827 for(const auto &importPlugin : sImportPluginList()) {
828 auto message = importPlugin->FailureHint();
829 if (!message.empty()) {
830 extraMessages += message;
831 extraMessages += Verbatim("\n");
832 }
833 }
834
835 errorMessage = XO(
836/* i18n-hint: %s will be the filename */
837"Audacity did not recognize the type of the file '%s'.\n\n%sFor uncompressed files, also try File > Import > Raw Data.")
838 .Format( fName, extraMessages );
839 }
840 else
841 {
842 // We DO have a plugin for this file, but import failed.
843 TranslatableString pluglist;
844
845 for (const auto &plugin : compatiblePlugins)
846 {
847 if (pluglist.empty())
848 pluglist = plugin->GetPluginFormatDescription();
849 else
850 pluglist = XO("%s, %s")
851 .Format( pluglist, plugin->GetPluginFormatDescription() );
852 }
853
854 errorMessage = XO(
855/* i18n-hint: %s will be the filename */
856"Audacity recognized the type of the file '%s'.\nImporters supposedly supporting such files are:\n%s,\nbut none of them understood this file format.")
857 .Format( fName, pluglist );
858 }
859
860 return false;
861}
862
863BoolSetting 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:863
std::vector< std::unique_ptr< ExtImportItem > > ExtImportItems
Definition: Import.h:37
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:251
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
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:344
wxArrayString filters
Definition: Import.h:50
int divider
Definition: Import.h:59
wxArrayString extensions
Definition: Import.h:70
wxArrayString mime_types
Definition: Import.h:76
std::vector< ImportPlugin * > filter_objects
Definition: Import.h:64
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.
Class which actually imports the auido, using functions defined in ImportPCM.cpp, ImportMP3_*....
Definition: Import.h:79
static Importer mInstance
Definition: Import.h:190
static Importer & Get()
Definition: Import.cpp:103
void StringToList(wxString &str, wxString &delims, wxArrayString &list, wxStringTokenizerMode mod=wxTOKEN_RET_EMPTY_ALL)
Definition: Import.cpp:296
bool Import(AudacityProject &project, const FilePath &fName, ImportProgressListener *importProgressListener, WaveTrackFactory *trackFactory, TrackHolders &tracks, Tags *tags, TranslatableString &errorMessage)
Definition: Import.cpp:492
static void SetLastOpenType(const FileNames::FileType &type)
Definition: Import.cpp:259
bool Initialize()
Definition: Import.cpp:167
void WriteImportItems()
Definition: Import.cpp:415
static UnusableImportPluginList & sUnusableImportPluginList()
Definition: Import.cpp:154
ExtImportItems mExtImportItems
Definition: Import.h:192
FileNames::FileTypes GetFileTypes(const FileNames::FileType &extraType={})
Definition: Import.cpp:214
~Importer()
Definition: Import.cpp:112
bool Terminate()
Definition: Import.cpp:206
std::unique_ptr< ExtImportItem > CreateDefaultImportItem()
Definition: Import.cpp:476
static size_t SelectDefaultOpenType(const FileNames::FileTypes &fileTypes)
Definition: Import.cpp:279
void ReadImportItems()
Definition: Import.cpp:304
static void SetDefaultOpenType(const FileNames::FileType &type)
Definition: Import.cpp:269
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:1166
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)
FILES_API bool IsMidi(const FilePath &fName)
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
Definition: Menus.h:35
void Visit(Visitor &visitor, BaseItem *pTopItem, const GroupItemBase *pRegistry)
Definition: Registry.cpp:739
static const auto PathStart
Definition: Import.cpp:123
STL namespace.
TranslatableString description
Definition: FileNames.h:60
FileExtensions extensions
Definition: FileNames.h:61
static Registry::GroupItemBase & Registry()
Definition: Import.cpp:128
ImporterItem(const Identifier &id, std::unique_ptr< ImportPlugin > pPlugin)
Definition: Import.cpp:134
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
Common abstract base class for items that group other items.
Definition: Registry.h:170
Common abstract base class for items that are not groups.
Definition: Registry.h:162