Audacity  2.2.2
Public Member Functions | Private Member Functions | List of all members
ExportPCM Class Referencefinal
Inheritance diagram for ExportPCM:
ExportPlugin

Public Member Functions

 ExportPCM ()
 
wxWindow * OptionsCreate (wxWindow *parent, int format) override
 
ProgressResult Export (AudacityProject *project, std::unique_ptr< ProgressDialog > &pDialog, unsigned channels, const wxString &fName, bool selectedOnly, double t0, double t1, MixerSpec *mixerSpec=NULL, const Tags *metadata=NULL, int subformat=0) override
 
wxString GetExtension (int index) override
 Return the (first) file name extension for the sub-format. More...
 
bool CheckFileName (wxFileName &filename, int format) override
 
- Public Member Functions inherited from ExportPlugin
 ExportPlugin ()
 
virtual ~ExportPlugin ()
 
int AddFormat ()
 Add a NEW entry to the list of formats this plug-in can export. More...
 
void SetFormat (const wxString &format, int index)
 
void SetDescription (const wxString &description, int index)
 
void AddExtension (const wxString &extension, int index)
 
void SetExtensions (const wxArrayString &extensions, int index)
 
void SetMask (const wxString &mask, int index)
 
void SetMaxChannels (unsigned maxchannels, unsigned index)
 
void SetCanMetaData (bool canmetadata, int index)
 
virtual int GetFormatCount ()
 
virtual wxString GetFormat (int index)
 
virtual wxString GetDescription (int index)
 
virtual wxArrayString GetExtensions (int index=0)
 Return all the file name extensions used for the sub-format. More...
 
virtual wxString GetMask (int index)
 
virtual unsigned GetMaxChannels (int index)
 
virtual bool GetCanMetaData (int index)
 
virtual bool IsExtension (const wxString &ext, int index)
 
virtual bool DisplayOptions (wxWindow *parent, int format=0)
 
virtual int SetNumExportChannels ()
 Exporter plug-ins may override this to specify the number of channels in exported file. -1 for unspecified. More...
 

Private Member Functions

ArrayOf< char > AdjustString (const wxString &wxStr, int sf_format)
 
bool AddStrings (AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format)
 
bool AddID3Chunk (wxString fName, const Tags *tags, int sf_format)
 

Additional Inherited Members

- Protected Member Functions inherited from ExportPlugin
std::unique_ptr< MixerCreateMixer (const WaveTrackConstArray &inputTracks, const TimeTrack *timeTrack, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, bool highQuality=true, MixerSpec *mixerSpec=NULL)
 
- Static Protected Member Functions inherited from ExportPlugin
static void InitProgress (std::unique_ptr< ProgressDialog > &pDialog, const wxString &title, const wxString &message)
 

Detailed Description

Definition at line 315 of file ExportPCM.cpp.

Constructor & Destructor Documentation

ExportPCM::ExportPCM ( )

Definition at line 346 of file ExportPCM.cpp.

References _(), ExportPlugin::AddExtension(), ExportPlugin::AddFormat(), desc, format, kFormats, name, ExportPlugin::SetCanMetaData(), ExportPlugin::SetDescription(), ExportPlugin::SetExtensions(), ExportPlugin::SetFormat(), ExportPlugin::SetMaxChannels(), sf_get_all_extensions(), and sf_header_extension().

347 : ExportPlugin()
348 {
349 
350  SF_INFO si;
351 
352  si.samplerate = 0;
353  si.channels = 0;
354 
355  int format; // the index of the format we are setting up at the moment
356 
357  // Add the "special" formats first
358  for (size_t i = 0; i < WXSIZEOF(kFormats); i++)
359  {
360  format = AddFormat() - 1;
361 
362  si.format = kFormats[i].format;
363  for (si.channels = 1; sf_format_check(&si); si.channels++)
364  ;
365  wxString ext = sf_header_extension(si.format);
366 
367  SetFormat(kFormats[i].name, format);
368  SetCanMetaData(true, format);
369  SetDescription(wxGetTranslation(kFormats[i].desc), format);
370  AddExtension(ext, format);
371  SetMaxChannels(si.channels - 1, format);
372  }
373 
374  // Then add the generic libsndfile formats
375  format = AddFormat() - 1; // store the index = 1 less than the count
376  SetFormat(wxT("LIBSNDFILE"), format);
377  SetCanMetaData(true, format);
378  SetDescription(_("Other uncompressed files"), format);
379  wxArrayString allext = sf_get_all_extensions();
380  wxString wavext = sf_header_extension(SF_FORMAT_WAV); // get WAV ext.
381 #if defined(wxMSW)
382  // On Windows make sure WAV is at the beginning of the list of all possible
383  // extensions for this format
384  allext.Remove(wavext);
385  allext.Insert(wavext, 0);
386 #endif
387  SetExtensions(allext, format);
388  SetMaxChannels(255, format);
389 }
const wxChar * desc
Definition: ExportPCM.cpp:58
void SetDescription(const wxString &description, int index)
Definition: Export.cpp:118
void SetFormat(const wxString &format, int index)
Definition: Export.cpp:113
void SetExtensions(const wxArrayString &extensions, int index)
Definition: Export.cpp:128
struct @41 kFormats[]
int format
Definition: ExportPCM.cpp:56
void SetMaxChannels(unsigned maxchannels, unsigned index)
Definition: Export.cpp:138
ExportPlugin()
Definition: Export.cpp:77
wxString sf_header_extension(int format)
Get the most common file extension for the given format.
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
wxArrayString sf_get_all_extensions()
int AddFormat()
Add a NEW entry to the list of formats this plug-in can export.
Definition: Export.cpp:97
void SetCanMetaData(bool canmetadata, int index)
Definition: Export.cpp:143
void AddExtension(const wxString &extension, int index)
Definition: Export.cpp:123
const wxChar * name
Definition: ExportPCM.cpp:57

Member Function Documentation

bool ExportPCM::AddID3Chunk ( wxString  fName,
const Tags tags,
int  sf_format 
)
private

Definition at line 732 of file ExportPCM.cpp.

References Tags::GetRange(), name, TAG_ALBUM, TAG_ARTIST, TAG_COMMENTS, TAG_GENRE, TAG_TITLE, TAG_TRACK, and TAG_YEAR.

Referenced by Export().

733 {
734 #ifdef USE_LIBID3TAG
735  id3_tag_holder tp { id3_tag_new() };
736 
737  for (const auto &pair : tags->GetRange()) {
738  const auto &n = pair.first;
739  const auto &v = pair.second;
740  const char *name = "TXXX";
741 
742  if (n.CmpNoCase(TAG_TITLE) == 0) {
743  name = ID3_FRAME_TITLE;
744  }
745  else if (n.CmpNoCase(TAG_ARTIST) == 0) {
746  name = ID3_FRAME_ARTIST;
747  }
748  else if (n.CmpNoCase(TAG_ALBUM) == 0) {
749  name = ID3_FRAME_ALBUM;
750  }
751  else if (n.CmpNoCase(TAG_YEAR) == 0) {
752  name = ID3_FRAME_YEAR;
753  }
754  else if (n.CmpNoCase(TAG_GENRE) == 0) {
755  name = ID3_FRAME_GENRE;
756  }
757  else if (n.CmpNoCase(TAG_COMMENTS) == 0) {
758  name = ID3_FRAME_COMMENT;
759  }
760  else if (n.CmpNoCase(TAG_TRACK) == 0) {
761  name = ID3_FRAME_TRACK;
762  }
763  else if (n.CmpNoCase(wxT("composer")) == 0) {
764  name = "TCOM";
765  }
766 
767  struct id3_frame *frame = id3_frame_new(name);
768 
769  if (!n.IsAscii() || !v.IsAscii()) {
770  id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_UTF_16);
771  }
772  else {
773  id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
774  }
775 
777  id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
778 
779  if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
780  // A hack to get around iTunes not recognizing the comment. The
781  // language defaults to XXX and, since it's not a valid language,
782  // iTunes just ignores the tag. So, either set it to a valid language
783  // (which one???) or just clear it. Unfortunately, there's no supported
784  // way of clearing the field, so do it directly.
785  id3_field *f = id3_frame_field(frame, 1);
786  memset(f->immediate.value, 0, sizeof(f->immediate.value));
787  id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
788  }
789  else if (strcmp(name, "TXXX") == 0) {
790  id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
791 
792  ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
793 
794  id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
795  }
796  else {
797  auto addr = ucs4.get();
798  id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
799  }
800 
801  id3_tag_attachframe(tp.get(), frame);
802  }
803 
804  tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
805 
806  // If this version of libid3tag supports it, use v2.3 ID3
807  // tags instead of the newer, but less well supported, v2.4
808  // that libid3tag uses by default.
809 #ifdef ID3_TAG_HAS_TAG_OPTION_ID3V2_3
810  tp->options |= ID3_TAG_OPTION_ID3V2_3;
811 #endif
812 
813  id3_length_t len;
814 
815  len = id3_tag_render(tp.get(), 0);
816  if (len == 0)
817  return true;
818 
819  if ((len % 2) != 0) len++; // Length must be even.
820  ArrayOf<id3_byte_t> buffer { len, true };
821  if (buffer == NULL)
822  return false;
823 
824  // Zero all locations, for ending odd UTF16 content
825  // correctly, i.e., two '\0's at the end.
826 
827  id3_tag_render(tp.get(), buffer.get());
828 
829  wxFFile f(fName, wxT("r+b"));
830  if (f.IsOpened()) {
831  wxUint32 sz;
832 
833  sz = (wxUint32) len;
834  if (!f.SeekEnd(0))
835  return false;
836  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
837  {
838  if (4 != f.Write("id3 ", 4))// Must be lower case for foobar2000.
839  return false ;
840  }
841  else {
842  if (4 != f.Write("ID3 ", 4))
843  return false;
844  sz = wxUINT32_SWAP_ON_LE(sz);
845  }
846  if (4 != f.Write(&sz, 4))
847  return false;
848 
849  if (len != f.Write(buffer.get(), len))
850  return false;
851 
852  sz = (wxUint32) f.Tell() - 8;
853  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
854  sz = wxUINT32_SWAP_ON_LE(sz);
855 
856  if (!f.Seek(4))
857  return false;
858  if (4 != f.Write(&sz, 4))
859  return false;
860 
861  if (!f.Flush())
862  return false;
863 
864  if (!f.Close())
865  return false;
866  }
867  else
868  return false;
869 #endif
870  return true;
871 }
#define TAG_TRACK
Definition: Tags.h:63
#define TAG_TITLE
Definition: Tags.h:60
#define TAG_ARTIST
Definition: Tags.h:61
std::unique_ptr< Character[], freer > MallocString
Definition: MemoryX.h:417
Memory.h template class for making an array of float, bool, etc.
Definition: MemoryX.h:86
#define TAG_COMMENTS
Definition: Tags.h:66
#define TAG_GENRE
Definition: Tags.h:65
Iterators GetRange() const
Definition: Tags.cpp:444
const wxChar * name
Definition: ExportPCM.cpp:57
#define TAG_ALBUM
Definition: Tags.h:62
#define TAG_YEAR
Definition: Tags.h:64
bool ExportPCM::AddStrings ( AudacityProject project,
SNDFILE *  sf,
const Tags tags,
int  sf_format 
)
private

Definition at line 657 of file ExportPCM.cpp.

References AdjustString(), Tags::GetTag(), Tags::HasTag(), TAG_ALBUM, TAG_ARTIST, TAG_COMMENTS, TAG_COPYRIGHT, TAG_GENRE, TAG_SOFTWARE, TAG_TITLE, TAG_TRACK, and TAG_YEAR.

Referenced by Export().

658 {
659  if (tags->HasTag(TAG_TITLE)) {
660  auto ascii7Str = AdjustString(tags->GetTag(TAG_TITLE), sf_format);
661  if (ascii7Str) {
662  sf_set_string(sf, SF_STR_TITLE, ascii7Str.get());
663  }
664  }
665 
666  if (tags->HasTag(TAG_ALBUM)) {
667  auto ascii7Str = AdjustString(tags->GetTag(TAG_ALBUM), sf_format);
668  if (ascii7Str) {
669  sf_set_string(sf, SF_STR_ALBUM, ascii7Str.get());
670  }
671  }
672 
673  if (tags->HasTag(TAG_ARTIST)) {
674  auto ascii7Str = AdjustString(tags->GetTag(TAG_ARTIST), sf_format);
675  if (ascii7Str) {
676  sf_set_string(sf, SF_STR_ARTIST, ascii7Str.get());
677  }
678  }
679 
680  if (tags->HasTag(TAG_COMMENTS)) {
681  auto ascii7Str = AdjustString(tags->GetTag(TAG_COMMENTS), sf_format);
682  if (ascii7Str) {
683  sf_set_string(sf, SF_STR_COMMENT, ascii7Str.get());
684  }
685  }
686 
687  if (tags->HasTag(TAG_YEAR)) {
688  auto ascii7Str = AdjustString(tags->GetTag(TAG_YEAR), sf_format);
689  if (ascii7Str) {
690  sf_set_string(sf, SF_STR_DATE, ascii7Str.get());
691  }
692  }
693 
694  if (tags->HasTag(TAG_GENRE)) {
695  auto ascii7Str = AdjustString(tags->GetTag(TAG_GENRE), sf_format);
696  if (ascii7Str) {
697  sf_set_string(sf, SF_STR_GENRE, ascii7Str.get());
698  }
699  }
700 
701  if (tags->HasTag(TAG_COPYRIGHT)) {
702  auto ascii7Str = AdjustString(tags->GetTag(TAG_COPYRIGHT), sf_format);
703  if (ascii7Str) {
704  sf_set_string(sf, SF_STR_COPYRIGHT, ascii7Str.get());
705  }
706  }
707 
708  if (tags->HasTag(TAG_SOFTWARE)) {
709  auto ascii7Str = AdjustString(tags->GetTag(TAG_SOFTWARE), sf_format);
710  if (ascii7Str) {
711  sf_set_string(sf, SF_STR_SOFTWARE, ascii7Str.get());
712  }
713  }
714 
715  if (tags->HasTag(TAG_TRACK)) {
716  auto ascii7Str = AdjustString(tags->GetTag(TAG_TRACK), sf_format);
717  if (ascii7Str) {
718  sf_set_string(sf, SF_STR_TRACKNUMBER, ascii7Str.get());
719  }
720  }
721 
722  return true;
723 }
#define TAG_TRACK
Definition: Tags.h:63
#define TAG_TITLE
Definition: Tags.h:60
#define TAG_ARTIST
Definition: Tags.h:61
#define TAG_SOFTWARE
Definition: Tags.h:67
ArrayOf< char > AdjustString(const wxString &wxStr, int sf_format)
Definition: ExportPCM.cpp:570
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:424
#define TAG_COPYRIGHT
Definition: Tags.h:68
#define TAG_COMMENTS
Definition: Tags.h:66
#define TAG_GENRE
Definition: Tags.h:65
#define TAG_ALBUM
Definition: Tags.h:62
#define TAG_YEAR
Definition: Tags.h:64
bool HasTag(const wxString &name) const
Definition: Tags.cpp:415
ArrayOf< char > ExportPCM::AdjustString ( const wxString &  wxStr,
int  sf_format 
)
private

Definition at line 570 of file ExportPCM.cpp.

Referenced by AddStrings().

571 {
572  bool b_aiff = false;
573  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
574  b_aiff = true; // Apple AIFF file
575 
576  // We must convert the string to 7 bit ASCII
577  size_t sz = wxStr.length();
578  if(sz == 0)
579  return {};
580  // Size for secure allocation in case of local wide char usage
581  size_t sr = (sz+4) * 2;
582 
583  ArrayOf<char> pDest{ sr, true };
584  if (!pDest)
585  return {};
586  ArrayOf<char> pSrc{ sr, true };
587  if (!pSrc)
588  return {};
589 
590  if(wxStr.mb_str(wxConvISO8859_1))
591  strncpy(pSrc.get(), wxStr.mb_str(wxConvISO8859_1), sz);
592  else if(wxStr.mb_str())
593  strncpy(pSrc.get(), wxStr.mb_str(), sz);
594  else
595  return {};
596 
597  char *pD = pDest.get();
598  char *pS = pSrc.get();
599  unsigned char c;
600 
601  // ISO Latin to 7 bit ascii conversion table (best approximation)
602  static char aASCII7Table[256] = {
603  0x00, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
604  0x5f, 0x09, 0x0a, 0x5f, 0x0d, 0x5f, 0x5f, 0x5f,
605  0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
606  0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
607  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
608  0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
609  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
610  0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
611  0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
612  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
613  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
614  0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
615  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
616  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
617  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
618  0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
619  0x45, 0x20, 0x2c, 0x53, 0x22, 0x2e, 0x2b, 0x2b,
620  0x5e, 0x25, 0x53, 0x28, 0x4f, 0x20, 0x5a, 0x20,
621  0x20, 0x27, 0x27, 0x22, 0x22, 0x2e, 0x2d, 0x5f,
622  0x22, 0x54, 0x73, 0x29, 0x6f, 0x20, 0x7a, 0x59,
623  0x20, 0x21, 0x63, 0x4c, 0x6f, 0x59, 0x7c, 0x53,
624  0x22, 0x43, 0x61, 0x22, 0x5f, 0x2d, 0x43, 0x2d,
625  0x6f, 0x7e, 0x32, 0x33, 0x27, 0x75, 0x50, 0x27,
626  0x2c, 0x31, 0x6f, 0x22, 0x5f, 0x5f, 0x5f, 0x3f,
627  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43,
628  0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
629  0x44, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x78,
630  0x4f, 0x55, 0x55, 0x55, 0x55, 0x59, 0x70, 0x53,
631  0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x63,
632  0x65, 0x65, 0x65, 0x65, 0x69, 0x69, 0x69, 0x69,
633  0x64, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x2f,
634  0x6f, 0x75, 0x75, 0x75, 0x75, 0x79, 0x70, 0x79
635  };
636 
637  size_t i;
638  for(i = 0; i < sr; i++) {
639  c = (unsigned char) *pS++;
640  *pD++ = aASCII7Table[c];
641  if(c == 0)
642  break;
643  }
644  *pD = '\0';
645 
646  if(b_aiff) {
647  int len = (int)strlen(pDest.get());
648  if((len % 2) != 0) {
649  // In case of an odd length string, add a space char
650  strcat(pDest.get(), " ");
651  }
652  }
653 
654  return pDest;
655 }
bool ExportPCM::CheckFileName ( wxFileName &  filename,
int  format 
)
overridevirtual

Reimplemented from ExportPlugin.

Definition at line 897 of file ExportPCM.cpp.

References ExportPlugin::CheckFileName(), format, GetExtension(), ExportPlugin::IsExtension(), and kFormats.

898 {
899  if (format == WXSIZEOF(kFormats) &&
900  IsExtension(filename.GetExt(), format)) {
901  // PRL: Bug1217
902  // If the user left the extension blank, then the
903  // file dialog will have defaulted the extension, beyond our control,
904  // to the first in the wildcard list or (Linux) the last-saved extension,
905  // ignoring what we try to do with the additional drop-down mHeaderChoice.
906  // Here we can intercept file name processing and impose the correct default.
907  // However this has the consequence that in case an explicit extension was typed,
908  // we override it without asking.
909  filename.SetExt(GetExtension(format));
910  }
911 
912  return ExportPlugin::CheckFileName(filename, format);
913 }
virtual bool CheckFileName(wxFileName &filename, int format=0)
Definition: Export.cpp:85
virtual bool IsExtension(const wxString &ext, int index)
Definition: Export.cpp:196
wxString GetExtension(int index) override
Return the (first) file name extension for the sub-format.
Definition: ExportPCM.cpp:885
struct @41 kFormats[]
int format
Definition: ExportPCM.cpp:56
ProgressResult ExportPCM::Export ( AudacityProject project,
std::unique_ptr< ProgressDialog > &  pDialog,
unsigned  numChannels,
const wxString &  fName,
bool  selectionOnly,
double  t0,
double  t1,
MixerSpec mixerSpec = NULL,
const Tags metadata = NULL,
int  subformat = 0 
)
overridevirtual
Parameters
subformatControl whether we are doing a "preset" export to a popular file type, or giving the user full control over libsndfile.

Implements ExportPlugin.

Definition at line 396 of file ExportPCM.cpp.

References _(), AddID3Chunk(), AddStrings(), AudacityMessageBox(), Cancelled, SFFile::close(), ExportPlugin::CreateMixer(), floatSample, format, AudacityProject::GetRate(), AudacityProject::GetTags(), TrackList::GetTimeTrack(), AudacityProject::GetTracks(), TrackList::GetWaveTrackConstArray(), ExportPlugin::InitProgress(), int16Sample, kFormats, ReadExportFormatPref(), sf_header_name(), sf_subtype_is_integer(), sf_subtype_more_than_16_bits(), Stopped, and Success.

406 {
407  double rate = project->GetRate();
408  const TrackList *tracks = project->GetTracks();
409  int sf_format;
410 
411  if (subformat < 0 || static_cast<unsigned int>(subformat) >= WXSIZEOF(kFormats))
412  {
413  sf_format = ReadExportFormatPref();
414  }
415  else
416  {
417  sf_format = kFormats[subformat].format;
418  }
419 
420  auto updateResult = ProgressResult::Success;
421  {
422  wxFile f; // will be closed when it goes out of scope
423  SFFile sf; // wraps f
424 
425  wxString formatStr;
426  SF_INFO info;
427  //int err;
428 
429  //This whole operation should not occur while a file is being loaded on OD,
430  //(we are worried about reading from a file being written to,) so we block.
431  //Furthermore, we need to do this because libsndfile is not threadsafe.
432  formatStr = SFCall<wxString>(sf_header_name, sf_format & SF_FORMAT_TYPEMASK);
433 
434  // Use libsndfile to export file
435 
436  info.samplerate = (unsigned int)(rate + 0.5);
437  info.frames = (unsigned int)((t1 - t0)*rate + 0.5);
438  info.channels = numChannels;
439  info.format = sf_format;
440  info.sections = 1;
441  info.seekable = 0;
442 
443  // If we can't export exactly the format they requested,
444  // try the default format for that header type...
445  if (!sf_format_check(&info))
446  info.format = (info.format & SF_FORMAT_TYPEMASK);
447  if (!sf_format_check(&info)) {
448  AudacityMessageBox(_("Cannot export audio in this format."));
450  }
451 
452  if (f.Open(fName, wxFile::write)) {
453  // Even though there is an sf_open() that takes a filename, use the one that
454  // takes a file descriptor since wxWidgets can open a file with a Unicode name and
455  // libsndfile can't (under Windows).
456  sf.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_WRITE, &info, FALSE));
457  //add clipping for integer formats. We allow floats to clip.
458  sf_command(sf.get(), SFC_SET_CLIPPING, NULL, sf_subtype_is_integer(sf_format)?SF_TRUE:SF_FALSE) ;
459  }
460 
461  if (!sf) {
462  AudacityMessageBox(wxString::Format(_("Cannot export audio to %s"),
463  fName));
465  }
466  // Retrieve tags if not given a set
467  if (metadata == NULL)
468  metadata = project->GetTags();
469 
470  // Install the metata at the beginning of the file (except for
471  // WAV and WAVEX formats)
472  if ((sf_format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WAV &&
473  (sf_format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WAVEX) {
474  if (!AddStrings(project, sf.get(), metadata, sf_format)) {
476  }
477  }
478 
480  if (sf_subtype_more_than_16_bits(info.format))
481  format = floatSample;
482  else
483  format = int16Sample;
484 
485  size_t maxBlockLen = 44100 * 5;
486 
487  const WaveTrackConstArray waveTracks =
488  tracks->GetWaveTrackConstArray(selectionOnly, false);
489  {
490  wxASSERT(info.channels >= 0);
491  auto mixer = CreateMixer(waveTracks,
492  tracks->GetTimeTrack(),
493  t0, t1,
494  info.channels, maxBlockLen, true,
495  rate, format, true, mixerSpec);
496 
497  InitProgress( pDialog, wxFileName(fName).GetName(),
498  selectionOnly
499  ? wxString::Format(_("Exporting the selected audio as %s"),
500  formatStr)
501  : wxString::Format(_("Exporting the audio as %s"),
502  formatStr) );
503  auto &progress = *pDialog;
504 
505  while (updateResult == ProgressResult::Success) {
506  sf_count_t samplesWritten;
507  size_t numSamples = mixer->Process(maxBlockLen);
508 
509  if (numSamples == 0)
510  break;
511 
512  samplePtr mixed = mixer->GetBuffer();
513 
514  if (format == int16Sample)
515  samplesWritten = SFCall<sf_count_t>(sf_writef_short, sf.get(), (short *)mixed, numSamples);
516  else
517  samplesWritten = SFCall<sf_count_t>(sf_writef_float, sf.get(), (float *)mixed, numSamples);
518 
519  if (static_cast<size_t>(samplesWritten) != numSamples) {
520  char buffer2[1000];
521  sf_error_str(sf.get(), buffer2, 1000);
522  AudacityMessageBox(wxString::Format(
523  /* i18n-hint: %s will be the error message from libsndfile, which
524  * is usually something unhelpful (and untranslated) like "system
525  * error" */
526  _("Error while writing %s file (disk full?).\nLibsndfile says \"%s\""),
527  formatStr,
528  wxString::FromAscii(buffer2)));
529  updateResult = ProgressResult::Cancelled;
530  break;
531  }
532 
533  updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
534  }
535  }
536 
537  // Install the WAV metata in a "LIST" chunk at the end of the file
538  if (updateResult == ProgressResult::Success ||
539  updateResult == ProgressResult::Stopped) {
540  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV ||
541  (sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAVEX) {
542  if (!AddStrings(project, sf.get(), metadata, sf_format)) {
543  // TODO: more precise message
544  AudacityMessageBox(_("Unable to export"));
546  }
547  }
548  if (0 != sf.close()) {
549  // TODO: more precise message
550  AudacityMessageBox(_("Unable to export"));
552  }
553  }
554  }
555 
556  if (updateResult == ProgressResult::Success ||
557  updateResult == ProgressResult::Stopped)
558  if (((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) ||
559  ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV))
560  // Note: file has closed, and gets reopened and closed again here:
561  if (!AddID3Chunk(fName, metadata, sf_format) ) {
562  // TODO: more precise message
563  AudacityMessageBox(_("Unable to export"));
565  }
566 
567  return updateResult;
568 }
A list of TrackListNode items.
Definition: Track.h:619
bool sf_subtype_more_than_16_bits(unsigned int format)
bool AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
Definition: ExportPCM.cpp:732
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
std::unique_ptr< Mixer > CreateMixer(const WaveTrackConstArray &inputTracks, const TimeTrack *timeTrack, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, bool highQuality=true, MixerSpec *mixerSpec=NULL)
Definition: Export.cpp:235
TimeTrack * GetTimeTrack()
Definition: Track.cpp:1244
struct @41 kFormats[]
int format
Definition: ExportPCM.cpp:56
WaveTrackConstArray GetWaveTrackConstArray(bool selectionOnly, bool includeMuted=true) const
Definition: Track.cpp:1349
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:67
int close()
Definition: FileFormats.h:139
wxString sf_header_name(int format)
Get the string name of the specified container format.
sampleFormat
Definition: Types.h:188
bool sf_subtype_is_integer(unsigned int format)
char * samplePtr
Definition: Types.h:203
bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format)
Definition: ExportPCM.cpp:657
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
const Tags * GetTags()
Definition: Project.cpp:1460
static int ReadExportFormatPref()
Definition: ExportPCM.cpp:75
double GetRate() const
Definition: Project.h:199
TrackList * GetTracks()
Definition: Project.h:192
static void InitProgress(std::unique_ptr< ProgressDialog > &pDialog, const wxString &title, const wxString &message)
Definition: Export.cpp:253
wxString ExportPCM::GetExtension ( int  index)
overridevirtual

Return the (first) file name extension for the sub-format.

Parameters
indexThe sub-format for which the extension is wanted

Reimplemented from ExportPlugin.

Definition at line 885 of file ExportPCM.cpp.

References ExportPlugin::GetExtension(), kFormats, ReadExportFormatPref(), and sf_header_extension().

Referenced by CheckFileName().

886 {
887  if (index == WXSIZEOF(kFormats)) {
888  // get extension libsndfile thinks is correct for currently selected format
890  }
891  else {
892  // return the default
893  return ExportPlugin::GetExtension(index);
894  }
895 }
struct @41 kFormats[]
wxString sf_header_extension(int format)
Get the most common file extension for the given format.
virtual wxString GetExtension(int index=0)
Return the (first) file name extension for the sub-format.
Definition: Export.cpp:158
static int ReadExportFormatPref()
Definition: ExportPCM.cpp:75
wxWindow * ExportPCM::OptionsCreate ( wxWindow *  parent,
int  format 
)
overridevirtual

Implements ExportPlugin.

Definition at line 873 of file ExportPCM.cpp.

References kFormats, ExportPlugin::OptionsCreate(), and safenew.

874 {
875  wxASSERT(parent); // to justify safenew
876  // default, full user control
877  if (format < 0 || static_cast<unsigned int>(format) >= WXSIZEOF(kFormats))
878  {
879  return safenew ExportPCMOptions(parent, format);
880  }
881 
882  return ExportPlugin::OptionsCreate(parent, format);
883 }
virtual wxWindow * OptionsCreate(wxWindow *parent, int format)=0
Definition: Export.cpp:215
#define safenew
Definition: Audacity.h:230
struct @41 kFormats[]
int format
Definition: ExportPCM.cpp:56

The documentation for this class was generated from the following file: