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