Audacity  3.0.3
ExportPCM.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  ExportPCM.cpp
6 
7  Dominic Mazzoni
8 
9 **********************************************************************/
10 
11 
12 
13 #include <wx/defs.h>
14 
15 #include <wx/app.h>
16 #include <wx/choice.h>
17 #include <wx/dynlib.h>
18 #include <wx/filename.h>
19 #include <wx/intl.h>
20 #include <wx/timer.h>
21 #include <wx/string.h>
22 #include <wx/textctrl.h>
23 #include <wx/window.h>
24 
25 #include "sndfile.h"
26 
27 #include "Dither.h"
28 #include "../FileFormats.h"
29 #include "../Mix.h"
30 #include "Prefs.h"
31 #include "../ProjectSettings.h"
32 #include "../ShuttleGui.h"
33 #include "../Tags.h"
34 #include "../Track.h"
35 #include "../widgets/AudacityMessageBox.h"
36 #include "../widgets/ProgressDialog.h"
37 #include "../widgets/wxWidgetsBasicUI.h"
38 #include "../wxFileNameWrapper.h"
39 
40 #include "Export.h"
41 
42 #ifdef USE_LIBID3TAG
43  #include <id3tag.h>
44  // DM: the following functions were supposed to have been
45  // included in id3tag.h - should be fixed in the next release
46  // of mad.
47  extern "C" {
48  struct id3_frame *id3_frame_new(char const *);
49  id3_length_t id3_latin1_length(id3_latin1_t const *);
50  void id3_latin1_decode(id3_latin1_t const *, id3_ucs4_t *);
51  }
52 #endif
53 
54 struct
55 {
56  int format;
57  const wxChar *name;
59 }
60 static const kFormats[] =
61 {
62 #if defined(__WXMAC__)
63  {SF_FORMAT_AIFF | SF_FORMAT_PCM_16, wxT("AIFF"), XO("AIFF (Apple/SGI)")},
64 #endif
65  {SF_FORMAT_WAV | SF_FORMAT_PCM_16, wxT("WAV"), XO("WAV (Microsoft)")},
66 };
67 
68 enum
69 {
70 #if defined(__WXMAC__)
71  FMT_AIFF,
72 #endif
74  FMT_OTHER
75 };
76 
77 //----------------------------------------------------------------------------
78 // Statics
79 //----------------------------------------------------------------------------
80 
81 static int LoadOtherFormat(int def = 0)
82 {
83  return gPrefs->Read(wxT("/FileFormats/ExportFormat_SF1"),
84  kFormats[0].format & SF_FORMAT_TYPEMASK);
85 }
86 
87 static void SaveOtherFormat(int val)
88 {
89  gPrefs->Write(wxT("/FileFormats/ExportFormat_SF1"), val);
90  gPrefs->Flush();
91 }
92 
93 static int LoadEncoding(int type)
94 {
95  return gPrefs->Read(wxString::Format(wxT("/FileFormats/ExportFormat_SF1_Type/%s_%x"),
96  sf_header_shortname(type), type), (long int) 0);
97 }
98 
99 static void SaveEncoding(int type, int val)
100 {
101  gPrefs->Write(wxString::Format(wxT("/FileFormats/ExportFormat_SF1_Type/%s_%x"),
102  sf_header_shortname(type), type), val);
103  gPrefs->Flush();
104 }
105 
106 //----------------------------------------------------------------------------
107 // ExportPCMOptions Class
108 //----------------------------------------------------------------------------
109 
110 #define ID_HEADER_CHOICE 7102
111 #define ID_ENCODING_CHOICE 7103
112 
113 class ExportPCMOptions final : public wxPanelWrapper
114 {
115 public:
116 
117  ExportPCMOptions(wxWindow *parent, int format);
118  virtual ~ExportPCMOptions();
119 
120  void PopulateOrExchange(ShuttleGui & S);
121 
122  void OnShow(wxShowEvent & evt);
123  void OnHeaderChoice(wxCommandEvent & evt);
124  void OnEncodingChoice(wxCommandEvent & evt);
125 
126 private:
127 
128  void GetTypes();
129  void GetEncodings(int enc = 0);
130  void SendSuffixEvent();
131 
132 private:
133 
134  std::vector<int> mHeaderIndexes;
136  wxChoice *mHeaderChoice;
138 
139  std::vector<int> mEncodingIndexes;
141  wxChoice *mEncodingChoice;
143 
145  int mType;
146 
147  DECLARE_EVENT_TABLE()
148 };
149 
150 BEGIN_EVENT_TABLE(ExportPCMOptions, wxPanelWrapper)
154 
155 ExportPCMOptions::ExportPCMOptions(wxWindow *parent, int selformat)
156 : wxPanelWrapper(parent, wxID_ANY)
157 {
158  // Remember the selection format
159  mSelFormat = selformat;
160 
161  // Init choices
162  mHeaderFromChoice = 0;
163  mEncodingFromChoice = 0;
164 
165  if (mSelFormat < FMT_OTHER)
166  {
167  mType = kFormats[selformat].format & SF_FORMAT_TYPEMASK;
168  GetEncodings(mType & SF_FORMAT_SUBMASK);
169  }
170  else
171  {
172  GetTypes();
173  GetEncodings();
174  }
175 
177  PopulateOrExchange(S);
178 
179  parent->Bind(wxEVT_SHOW, &ExportPCMOptions::OnShow, this);
180 }
181 
183 {
184  // Save the encoding
187 }
188 
190 {
191  S.StartVerticalLay();
192  {
193  S.StartHorizontalLay(wxCENTER);
194  {
195  S.StartMultiColumn(2, wxCENTER);
196  {
197  S.SetStretchyCol(1);
198  if (mSelFormat == FMT_OTHER)
199  {
201  .AddChoice(XXO("Header:"),
202  mHeaderNames,
204  }
206  .AddChoice(XXO("Encoding:"),
209  }
210  S.EndMultiColumn();
211  }
212  S.EndHorizontalLay();
213  }
214  S.EndVerticalLay();
215 
216  return;
217 }
218 
219 void ExportPCMOptions::OnShow(wxShowEvent & evt)
220 {
221  evt.Skip();
222 
223  // Since the initial file name may not have the "correct" extension,
224  // send off an event to have it changed. Note that this will be
225  // done every time a user changes filters in the dialog.
226  if (evt.IsShown())
227  {
228  SendSuffixEvent();
229  }
230 }
231 
232 void ExportPCMOptions::OnHeaderChoice(wxCommandEvent & evt)
233 {
234  evt.Skip();
235 
236  // Remember new selection
237  mHeaderFromChoice = evt.GetInt();
238 
239  // Get the type for this selection
241 
242  // Save the newly selected type
244 
245  // Reload the encodings valid for this new type
246  GetEncodings();
247 
248  // Repopulate the encoding choices
249  mEncodingChoice->Clear();
250  for (int i = 0, num = mEncodingNames.size(); i < num; ++i)
251  {
252  mEncodingChoice->AppendString(mEncodingNames[i].StrippedTranslation());
253  }
254 
255  // Select the desired encoding
256  mEncodingChoice->SetSelection(mEncodingFromChoice);
257 
258  // Send the event indicating a file suffix change.
259  SendSuffixEvent();
260 }
261 
262 void ExportPCMOptions::OnEncodingChoice(wxCommandEvent & evt)
263 {
264  evt.Skip();
265 
266  // Remember new selection
267  mEncodingFromChoice = evt.GetInt();
268 
269  // And save it
271 }
272 
274 {
275  // Reset arrays
276  mHeaderIndexes.clear();
277  mHeaderNames.clear();
278 
279  // Get the previously saved type. Note that this is ONLY used for
280  // the FMT_OTHER ("Other uncompressed files") types.
281  int typ = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
282 
283  // Rebuild the arrays
284  mHeaderFromChoice = 0;
285  for (int i = 0, num = sf_num_headers(); i < num; ++i)
286  {
287  int type = sf_header_index_to_type(i);
288 
289  switch (type)
290  {
291  // On the Mac, do not include in header list
292 #if defined(__WXMAC__)
293  case SF_FORMAT_AIFF:
294  break;
295 #endif
296 
297  // Do not include in header list
298  case SF_FORMAT_WAV:
299  break;
300 
301  default:
302  // Remember the index if this is the desired type
303  if (type == typ)
304  {
306  }
307 
308  // Store index and name
309  mHeaderIndexes.push_back(i);
311  break;
312  }
313  }
314 
315  // Refresh the current type
317 }
318 
320 {
321  // Setup for queries
322  SF_INFO info = {};
323  info.samplerate = 44100;
324  info.channels = 1;
325  info.sections = 1;
326 
327  // Reset arrays
328  mEncodingIndexes.clear();
329  mEncodingNames.clear();
330 
331  // If the encoding wasn't supplied, look it up
332  if (!(enc & SF_FORMAT_SUBMASK))
333  {
334  enc = LoadEncoding(mType);
335  }
336  enc &= SF_FORMAT_SUBMASK;
337 
338  // Fix for Bug 1218 - AIFF with no encoding should default to 16 bit.
339  if (mType == SF_FORMAT_AIFF && enc == 0)
340  {
341  enc = SF_FORMAT_PCM_16;
342  }
343 
344  // Rebuild the arrays
346  for (int i = 0, num = sf_num_encodings(); i < num; ++i)
347  {
348  int sub = sf_encoding_index_to_subtype(i);
349 
350  // Since we're traversing the subtypes linearly, we have to
351  // make sure it can be paired with our current type.
352  info.format = mType | sub;
353  if (sf_format_check(&info))
354  {
355  // If this subtype matches our last saved encoding, remember
356  // its index so we can set it in the dialog.
357  if (sub == enc)
358  {
360  }
361 
362  // Store index and name
363  mEncodingIndexes.push_back(i);
365  }
366  }
367 }
368 
370 {
371  // Synchronously process a change in suffix.
372  wxCommandEvent evt(AUDACITY_FILE_SUFFIX_EVENT, GetId());
373  evt.SetEventObject(this);
374  evt.SetString(sf_header_extension(mType));
375  ProcessWindowEvent(evt);
376 }
377 
378 //----------------------------------------------------------------------------
379 // ExportPCM Class
380 //----------------------------------------------------------------------------
381 
382 class ExportPCM final : public ExportPlugin
383 {
384 public:
385 
386  ExportPCM();
387 
388  // Required
389 
390  void OptionsCreate(ShuttleGui &S, int format) override;
392  std::unique_ptr<ProgressDialog> &pDialog,
393  unsigned channels,
394  const wxFileNameWrapper &fName,
395  bool selectedOnly,
396  double t0,
397  double t1,
398  MixerSpec *mixerSpec = NULL,
399  const Tags *metadata = NULL,
400  int subformat = 0) override;
401  // optional
402  wxString GetFormat(int index) override;
403  FileExtension GetExtension(int index) override;
404  unsigned GetMaxChannels(int index) override;
405 
406 private:
407  void ReportTooBigError(wxWindow * pParent);
408  ArrayOf<char> AdjustString(const wxString & wxStr, int sf_format);
409  bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format);
410  bool AddID3Chunk(
411  const wxFileNameWrapper &fName, const Tags *tags, int sf_format);
412 
413 };
414 
416  : ExportPlugin()
417 {
418  int selformat; // the index of the format we are setting up at the moment
419 
420  // Add the "special" formats first
421  for (size_t i = 0; i < WXSIZEOF(kFormats); ++i)
422  {
423  selformat = AddFormat() - 1;
425  SetFormat(kFormats[i].name, selformat);
426  SetDescription(kFormats[i].desc, selformat);
427  SetCanMetaData(true, selformat);
428  SetMaxChannels(255, selformat);
429  }
430 
431  // Then add the generic libsndfile "format"
432  selformat = AddFormat() - 1; // Matches FMT_OTHER
433  SetExtensions(sf_get_all_extensions(), selformat);
434  SetFormat(wxT("LIBSNDFILE"), selformat);
435  SetDescription(XO("Other uncompressed files"), selformat);
436  SetCanMetaData(true, selformat);
437  SetMaxChannels(255, selformat);
438 }
439 
440 void ExportPCM::ReportTooBigError(wxWindow * pParent)
441 {
442  //Temporary translation hack, to say 'WAV or AIFF' rather than 'WAV'
443  auto message =
444  XO("You have attempted to Export a WAV or AIFF file which would be greater than 4GB.\n"
445  "Audacity cannot do this, the Export was abandoned.");
446 
448  XO("Error Exporting"), message,
449  wxT("Size_limits_for_WAV_and_AIFF_files"));
450 
451 // This alternative error dialog was to cover the possibility we could not
452 // compute the size in advance.
453 #if 0
455  XO("Error Exporting"),
456  XO("Your exported WAV file has been truncated as Audacity cannot export WAV\n"
457  "files bigger than 4GB."),
458  wxT("Size_limits_for_WAV_files"));
459 #endif
460 }
461 
468  std::unique_ptr<ProgressDialog> &pDialog,
469  unsigned numChannels,
470  const wxFileNameWrapper &fName,
471  bool selectionOnly,
472  double t0,
473  double t1,
474  MixerSpec *mixerSpec,
475  const Tags *metadata,
476  int subformat)
477 {
478  double rate = ProjectSettings::Get( *project ).GetRate();
479  const auto &tracks = TrackList::Get( *project );
480 
481  // Set a default in case the settings aren't found
482  int sf_format;
483 
484  switch (subformat)
485  {
486 #if defined(__WXMAC__)
487  case FMT_AIFF:
488  sf_format = SF_FORMAT_AIFF;
489  break;
490 #endif
491 
492  case FMT_WAV:
493  sf_format = SF_FORMAT_WAV;
494  break;
495 
496  default:
497  // Retrieve the current format.
498  sf_format = LoadOtherFormat();
499  break;
500  }
501 
502  // Prior to v2.4.0, sf_format will include the subtype. If not present,
503  // check for the format specific preference.
504  if (!(sf_format & SF_FORMAT_SUBMASK))
505  {
506  sf_format |= LoadEncoding(sf_format);
507  }
508 
509  // If subtype is still not specified, supply a default.
510  if (!(sf_format & SF_FORMAT_SUBMASK))
511  {
512  sf_format |= SF_FORMAT_PCM_16;
513  }
514 
515  int fileFormat = sf_format & SF_FORMAT_TYPEMASK;
516 
517  auto updateResult = ProgressResult::Success;
518  {
519  wxFile f; // will be closed when it goes out of scope
520  SFFile sf; // wraps f
521 
522  wxString formatStr;
523  SF_INFO info;
524  //int err;
525 
526  //This whole operation should not occur while a file is being loaded on OD,
527  //(we are worried about reading from a file being written to,) so we block.
528  //Furthermore, we need to do this because libsndfile is not threadsafe.
529  formatStr = SFCall<wxString>(sf_header_name, fileFormat);
530 
531  // Use libsndfile to export file
532 
533  info.samplerate = (unsigned int)(rate + 0.5);
534  info.frames = (unsigned int)((t1 - t0)*rate + 0.5);
535  info.channels = numChannels;
536  info.format = sf_format;
537  info.sections = 1;
538  info.seekable = 0;
539 
540  // Bug 46. Trap here, as sndfile.c does not trap it properly.
541  if( (numChannels != 1) && ((sf_format & SF_FORMAT_SUBMASK) == SF_FORMAT_GSM610) )
542  {
543  AudacityMessageBox( XO("GSM 6.10 requires mono") );
545  }
546 
547  if (sf_format == SF_FORMAT_WAVEX + SF_FORMAT_GSM610) {
549  XO("WAVEX and GSM 6.10 formats are not compatible") );
551  }
552 
553  // If we can't export exactly the format they requested,
554  // try the default format for that header type...
555  //
556  // LLL: I don't think this is valid since libsndfile checks
557  // for all allowed subtypes explicitly and doesn't provide
558  // for an unspecified subtype.
559  if (!sf_format_check(&info))
560  info.format = (info.format & SF_FORMAT_TYPEMASK);
561  if (!sf_format_check(&info)) {
562  AudacityMessageBox( XO("Cannot export audio in this format.") );
564  }
565  const auto path = fName.GetFullPath();
566  if (f.Open(path, wxFile::write)) {
567  // Even though there is an sf_open() that takes a filename, use the one that
568  // takes a file descriptor since wxWidgets can open a file with a Unicode name and
569  // libsndfile can't (under Windows).
570  sf.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_WRITE, &info, FALSE));
571  //add clipping for integer formats. We allow floats to clip.
572  sf_command(sf.get(), SFC_SET_CLIPPING, NULL, sf_subtype_is_integer(sf_format)?SF_TRUE:SF_FALSE) ;
573  }
574 
575  if (!sf) {
576  AudacityMessageBox( XO("Cannot export audio to %s").Format( path ) );
578  }
579  // Retrieve tags if not given a set
580  if (metadata == NULL)
581  metadata = &Tags::Get( *project );
582 
583  // Install the meta data at the beginning of the file (except for
584  // WAV and WAVEX formats)
585  if (fileFormat != SF_FORMAT_WAV &&
586  fileFormat != SF_FORMAT_WAVEX) {
587  if (!AddStrings(project, sf.get(), metadata, sf_format)) {
589  }
590  }
591 
593  if (sf_subtype_more_than_16_bits(info.format))
595  else
597 
598  // Bug 2200
599  // Only trap size limit for file types we know have an upper size limit.
600  // The error message mentions aiff and wav.
601  if( (fileFormat == SF_FORMAT_WAV) ||
602  (fileFormat == SF_FORMAT_WAVEX) ||
603  (fileFormat == SF_FORMAT_AIFF ))
604  {
605  float sampleCount = (float)(t1-t0)*rate*info.channels;
606  float byteCount = sampleCount * sf_subtype_bytes_per_sample( info.format);
607  // Test for 4 Gibibytes, rather than 4 Gigabytes
608  if( byteCount > 4.295e9)
609  {
610  ReportTooBigError( wxTheApp->GetTopWindow() );
611  return ProgressResult::Failed;
612  }
613  }
614  size_t maxBlockLen = 44100 * 5;
615 
616  {
617  std::vector<char> dither;
618  if ((info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_24) {
619  dither.reserve(maxBlockLen * info.channels * SAMPLE_SIZE(int24Sample));
620  }
621 
622  wxASSERT(info.channels >= 0);
623  auto mixer = CreateMixer(tracks, selectionOnly,
624  t0, t1,
625  info.channels, maxBlockLen, true,
626  rate, format, mixerSpec);
627 
628  InitProgress( pDialog, fName,
629  (selectionOnly
630  ? XO("Exporting the selected audio as %s")
631  : XO("Exporting the audio as %s"))
632  .Format( formatStr ) );
633  auto &progress = *pDialog;
634 
635  while (updateResult == ProgressResult::Success) {
636  sf_count_t samplesWritten;
637  size_t numSamples = mixer->Process(maxBlockLen);
638 
639  if (numSamples == 0)
640  break;
641 
642  samplePtr mixed = mixer->GetBuffer();
643 
644  // Bug 1572: Not ideal, but it does add the desired dither
645  if ((info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_24) {
646  for (int c = 0; c < info.channels; ++c) {
647  CopySamples(
648  mixed + (c * SAMPLE_SIZE(format)), format,
649  dither.data() + (c * SAMPLE_SIZE(int24Sample)), int24Sample,
650  numSamples, gHighQualityDither, info.channels, info.channels
651  );
652  // Copy back without dither
653  CopySamples(
654  dither.data() + (c * SAMPLE_SIZE(int24Sample)), int24Sample,
655  mixed + (c * SAMPLE_SIZE(format)), format,
656  numSamples, DitherType::none, info.channels, info.channels);
657  }
658  }
659 
660  if (format == int16Sample)
661  samplesWritten = SFCall<sf_count_t>(sf_writef_short, sf.get(), (short *)mixed, numSamples);
662  else
663  samplesWritten = SFCall<sf_count_t>(sf_writef_float, sf.get(), (float *)mixed, numSamples);
664 
665  if (static_cast<size_t>(samplesWritten) != numSamples) {
666  char buffer2[1000];
667  sf_error_str(sf.get(), buffer2, 1000);
668  //Used to give this error message
669 #if 0
671  XO(
672  /* i18n-hint: %s will be the error message from libsndfile, which
673  * is usually something unhelpful (and untranslated) like "system
674  * error" */
675 "Error while writing %s file (disk full?).\nLibsndfile says \"%s\"")
676  .Format( formatStr, wxString::FromAscii(buffer2) ));
677 #else
678  // But better to give the same error message as for
679  // other cases of disk exhaustion.
680  // The thrown exception doesn't escape but GuardedCall
681  // will enqueue a message.
682  GuardedCall([&fName]{
683  throw FileException{
684  FileException::Cause::Write, fName }; });
685 #endif
686  updateResult = ProgressResult::Cancelled;
687  break;
688  }
689 
690  updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
691  }
692  }
693 
694  // Install the WAV metata in a "LIST" chunk at the end of the file
695  if (updateResult == ProgressResult::Success ||
696  updateResult == ProgressResult::Stopped) {
697  if (fileFormat == SF_FORMAT_WAV ||
698  fileFormat == SF_FORMAT_WAVEX) {
699  if (!AddStrings(project, sf.get(), metadata, sf_format)) {
700  // TODO: more precise message
701  ShowExportErrorDialog("PCM:675");
703  }
704  }
705  if (0 != sf.close()) {
706  // TODO: more precise message
707  ShowExportErrorDialog("PCM:681");
709  }
710  }
711  }
712 
713  if (updateResult == ProgressResult::Success ||
714  updateResult == ProgressResult::Stopped)
715  if ((fileFormat == SF_FORMAT_AIFF) ||
716  (fileFormat == SF_FORMAT_WAV))
717  // Note: file has closed, and gets reopened and closed again here:
718  if (!AddID3Chunk(fName, metadata, sf_format) ) {
719  // TODO: more precise message
720  ShowExportErrorDialog("PCM:694");
722  }
723 
724  return updateResult;
725 }
726 
727 ArrayOf<char> ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
728 {
729  bool b_aiff = false;
730  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
731  b_aiff = true; // Apple AIFF file
732 
733  // We must convert the string to 7 bit ASCII
734  size_t sz = wxStr.length();
735  if(sz == 0)
736  return {};
737  // Size for secure allocation in case of local wide char usage
738  size_t sr = (sz+4) * 2;
739 
740  ArrayOf<char> pDest{ sr, true };
741  if (!pDest)
742  return {};
743  ArrayOf<char> pSrc{ sr, true };
744  if (!pSrc)
745  return {};
746 
747  if(wxStr.mb_str(wxConvISO8859_1))
748  strncpy(pSrc.get(), wxStr.mb_str(wxConvISO8859_1), sz);
749  else if(wxStr.mb_str())
750  strncpy(pSrc.get(), wxStr.mb_str(), sz);
751  else
752  return {};
753 
754  char *pD = pDest.get();
755  char *pS = pSrc.get();
756  unsigned char c;
757 
758  // ISO Latin to 7 bit ascii conversion table (best approximation)
759  static char aASCII7Table[256] = {
760  0x00, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
761  0x5f, 0x09, 0x0a, 0x5f, 0x0d, 0x5f, 0x5f, 0x5f,
762  0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
763  0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
764  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
765  0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
766  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
767  0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
768  0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
769  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
770  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
771  0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
772  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
773  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
774  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
775  0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
776  0x45, 0x20, 0x2c, 0x53, 0x22, 0x2e, 0x2b, 0x2b,
777  0x5e, 0x25, 0x53, 0x28, 0x4f, 0x20, 0x5a, 0x20,
778  0x20, 0x27, 0x27, 0x22, 0x22, 0x2e, 0x2d, 0x5f,
779  0x22, 0x54, 0x73, 0x29, 0x6f, 0x20, 0x7a, 0x59,
780  0x20, 0x21, 0x63, 0x4c, 0x6f, 0x59, 0x7c, 0x53,
781  0x22, 0x43, 0x61, 0x22, 0x5f, 0x2d, 0x43, 0x2d,
782  0x6f, 0x7e, 0x32, 0x33, 0x27, 0x75, 0x50, 0x27,
783  0x2c, 0x31, 0x6f, 0x22, 0x5f, 0x5f, 0x5f, 0x3f,
784  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43,
785  0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
786  0x44, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x78,
787  0x4f, 0x55, 0x55, 0x55, 0x55, 0x59, 0x70, 0x53,
788  0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x63,
789  0x65, 0x65, 0x65, 0x65, 0x69, 0x69, 0x69, 0x69,
790  0x64, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x2f,
791  0x6f, 0x75, 0x75, 0x75, 0x75, 0x79, 0x70, 0x79
792  };
793 
794  size_t i;
795  for(i = 0; i < sr; i++) {
796  c = (unsigned char) *pS++;
797  *pD++ = aASCII7Table[c];
798  if(c == 0)
799  break;
800  }
801  *pD = '\0';
802 
803  if(b_aiff) {
804  int len = (int)strlen(pDest.get());
805  if((len % 2) != 0) {
806  // In case of an odd length string, add a space char
807  strcat(pDest.get(), " ");
808  }
809  }
810 
811  return pDest;
812 }
813 
814 bool ExportPCM::AddStrings(AudacityProject * WXUNUSED(project), SNDFILE *sf, const Tags *tags, int sf_format)
815 {
816  if (tags->HasTag(TAG_TITLE)) {
817  auto ascii7Str = AdjustString(tags->GetTag(TAG_TITLE), sf_format);
818  if (ascii7Str) {
819  sf_set_string(sf, SF_STR_TITLE, ascii7Str.get());
820  }
821  }
822 
823  if (tags->HasTag(TAG_ALBUM)) {
824  auto ascii7Str = AdjustString(tags->GetTag(TAG_ALBUM), sf_format);
825  if (ascii7Str) {
826  sf_set_string(sf, SF_STR_ALBUM, ascii7Str.get());
827  }
828  }
829 
830  if (tags->HasTag(TAG_ARTIST)) {
831  auto ascii7Str = AdjustString(tags->GetTag(TAG_ARTIST), sf_format);
832  if (ascii7Str) {
833  sf_set_string(sf, SF_STR_ARTIST, ascii7Str.get());
834  }
835  }
836 
837  if (tags->HasTag(TAG_COMMENTS)) {
838  auto ascii7Str = AdjustString(tags->GetTag(TAG_COMMENTS), sf_format);
839  if (ascii7Str) {
840  sf_set_string(sf, SF_STR_COMMENT, ascii7Str.get());
841  }
842  }
843 
844  if (tags->HasTag(TAG_YEAR)) {
845  auto ascii7Str = AdjustString(tags->GetTag(TAG_YEAR), sf_format);
846  if (ascii7Str) {
847  sf_set_string(sf, SF_STR_DATE, ascii7Str.get());
848  }
849  }
850 
851  if (tags->HasTag(TAG_GENRE)) {
852  auto ascii7Str = AdjustString(tags->GetTag(TAG_GENRE), sf_format);
853  if (ascii7Str) {
854  sf_set_string(sf, SF_STR_GENRE, ascii7Str.get());
855  }
856  }
857 
858  if (tags->HasTag(TAG_COPYRIGHT)) {
859  auto ascii7Str = AdjustString(tags->GetTag(TAG_COPYRIGHT), sf_format);
860  if (ascii7Str) {
861  sf_set_string(sf, SF_STR_COPYRIGHT, ascii7Str.get());
862  }
863  }
864 
865  if (tags->HasTag(TAG_SOFTWARE)) {
866  auto ascii7Str = AdjustString(tags->GetTag(TAG_SOFTWARE), sf_format);
867  if (ascii7Str) {
868  sf_set_string(sf, SF_STR_SOFTWARE, ascii7Str.get());
869  }
870  }
871 
872  if (tags->HasTag(TAG_TRACK)) {
873  auto ascii7Str = AdjustString(tags->GetTag(TAG_TRACK), sf_format);
874  if (ascii7Str) {
875  sf_set_string(sf, SF_STR_TRACKNUMBER, ascii7Str.get());
876  }
877  }
878 
879  return true;
880 }
881 
882 #ifdef USE_LIBID3TAG
883 struct id3_tag_deleter {
884  void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
885 };
886 using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
887 #endif
888 
890  const wxFileNameWrapper &fName, const Tags *tags, int sf_format)
891 {
892 #ifdef USE_LIBID3TAG
893  id3_tag_holder tp { id3_tag_new() };
894 
895  for (const auto &pair : tags->GetRange()) {
896  const auto &n = pair.first;
897  const auto &v = pair.second;
898  const char *name = "TXXX";
899 
900  if (n.CmpNoCase(TAG_TITLE) == 0) {
901  name = ID3_FRAME_TITLE;
902  }
903  else if (n.CmpNoCase(TAG_ARTIST) == 0) {
904  name = ID3_FRAME_ARTIST;
905  }
906  else if (n.CmpNoCase(TAG_ALBUM) == 0) {
907  name = ID3_FRAME_ALBUM;
908  }
909  else if (n.CmpNoCase(TAG_YEAR) == 0) {
910  name = ID3_FRAME_YEAR;
911  }
912  else if (n.CmpNoCase(TAG_GENRE) == 0) {
913  name = ID3_FRAME_GENRE;
914  }
915  else if (n.CmpNoCase(TAG_COMMENTS) == 0) {
916  name = ID3_FRAME_COMMENT;
917  }
918  else if (n.CmpNoCase(TAG_TRACK) == 0) {
919  name = ID3_FRAME_TRACK;
920  }
921  else if (n.CmpNoCase(wxT("composer")) == 0) {
922  name = "TCOM";
923  }
924 
925  struct id3_frame *frame = id3_frame_new(name);
926 
927  if (!n.IsAscii() || !v.IsAscii()) {
928  id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_UTF_16);
929  }
930  else {
931  id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
932  }
933 
935  id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
936 
937  if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
938  // A hack to get around iTunes not recognizing the comment. The
939  // language defaults to XXX and, since it's not a valid language,
940  // iTunes just ignores the tag. So, either set it to a valid language
941  // (which one???) or just clear it. Unfortunately, there's no supported
942  // way of clearing the field, so do it directly.
943  id3_field *f = id3_frame_field(frame, 1);
944  memset(f->immediate.value, 0, sizeof(f->immediate.value));
945  id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
946  }
947  else if (strcmp(name, "TXXX") == 0) {
948  id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
949 
950  ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
951 
952  id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
953  }
954  else {
955  auto addr = ucs4.get();
956  id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
957  }
958 
959  id3_tag_attachframe(tp.get(), frame);
960  }
961 
962  tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
963 
964  // If this version of libid3tag supports it, use v2.3 ID3
965  // tags instead of the newer, but less well supported, v2.4
966  // that libid3tag uses by default.
967 #ifdef ID3_TAG_HAS_TAG_OPTION_ID3V2_3
968  tp->options |= ID3_TAG_OPTION_ID3V2_3;
969 #endif
970 
971  id3_length_t len;
972 
973  len = id3_tag_render(tp.get(), 0);
974  if (len == 0)
975  return true;
976 
977  if ((len % 2) != 0) len++; // Length must be even.
978  ArrayOf<id3_byte_t> buffer { len, true };
979  if (buffer == NULL)
980  return false;
981 
982  // Zero all locations, for ending odd UTF16 content
983  // correctly, i.e., two '\0's at the end.
984 
985  id3_tag_render(tp.get(), buffer.get());
986 
987  wxFFile f(fName.GetFullPath(), wxT("r+b"));
988  if (f.IsOpened()) {
989  wxUint32 sz;
990 
991  sz = (wxUint32) len;
992  if (!f.SeekEnd(0))
993  return false;
994  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
995  {
996  if (4 != f.Write("id3 ", 4))// Must be lower case for foobar2000.
997  return false ;
998  }
999  else {
1000  if (4 != f.Write("ID3 ", 4))
1001  return false;
1002  sz = wxUINT32_SWAP_ON_LE(sz);
1003  }
1004  if (4 != f.Write(&sz, 4))
1005  return false;
1006 
1007  if (len != f.Write(buffer.get(), len))
1008  return false;
1009 
1010  sz = (wxUint32) f.Tell() - 8;
1011  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
1012  sz = wxUINT32_SWAP_ON_LE(sz);
1013 
1014  if (!f.Seek(4))
1015  return false;
1016  if (4 != f.Write(&sz, 4))
1017  return false;
1018 
1019  if (!f.Flush())
1020  return false;
1021 
1022  if (!f.Close())
1023  return false;
1024  }
1025  else
1026  return false;
1027 #endif
1028  return true;
1029 }
1030 
1032 {
1033  switch (format)
1034  {
1035 #if defined(__WXMAC__)
1036  case FMT_AIFF:
1037 #endif
1038  case FMT_WAV:
1039  case FMT_OTHER:
1041  break;
1042 
1043  default:
1045  break;
1046  }
1047 }
1048 
1049 wxString ExportPCM::GetFormat(int index)
1050 {
1051  if (index != FMT_OTHER)
1052  {
1053  return ExportPlugin::GetFormat(index);
1054  }
1055 
1056  // Get the saved type
1057  int typ = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
1058 
1059  // Return the format name for that type
1060  return sf_header_shortname(typ);
1061 }
1062 
1064 {
1065  if (index != FMT_OTHER)
1066  {
1067  return ExportPlugin::GetExtension(index);
1068  }
1069 
1070  // Get the saved type
1071  int typ = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
1072 
1073  // Return the extension for that type
1074  return sf_header_extension(typ);
1075 }
1076 
1077 unsigned ExportPCM::GetMaxChannels(int index)
1078 {
1079  SF_INFO si = {};
1080 
1081  if (index < FMT_OTHER)
1082  {
1083  si.format = kFormats[index].format;
1084  }
1085  else
1086  {
1087  // Get the saved type
1088  si.format = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
1089  si.format |= LoadEncoding(si.format);
1090  }
1091 
1092  for (si.channels = 1; sf_format_check(&si); si.channels++)
1093  {
1094  // just counting
1095  }
1096 
1097  // Return the max number of channels
1098  return si.channels - 1;
1099 }
1100 
1102  []{ return std::make_unique< ExportPCM >(); }
1103 };
ExportPCMOptions::mEncodingFromChoice
int mEncodingFromChoice
Definition: ExportPCM.cpp:142
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
ShuttleGuiBase::AddChoice
wxChoice * AddChoice(const TranslatableString &Prompt, const TranslatableStrings &choices, int Selected=-1)
Definition: ShuttleGui.cpp:398
ShuttleGuiBase::StartVerticalLay
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:1184
sf_header_shortname
wxString sf_header_shortname(int format)
Get an abbreviated form of the string name of the specified format.
Definition: FileFormats.cpp:122
GuardedCall
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), std::function< void(AudacityException *)> delayedHandler=DefaultDelayedHandlerAction{})
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
Definition: AudacityException.h:202
ExportPCMOptions::GetEncodings
void GetEncodings(int enc=0)
Definition: ExportPCM.cpp:319
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption=XO("Message"), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: AudacityMessageBox.h:20
BasicUI::ProgressResult::Success
@ Success
wxFileNameWrapper
Definition: wxFileNameWrapper.h:21
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
ExportPCMOptions::OnHeaderChoice
void OnHeaderChoice(wxCommandEvent &evt)
Definition: ExportPCM.cpp:232
TranslatableStrings
std::vector< TranslatableString > TranslatableStrings
Definition: TranslatableString.h:295
BasicUI::ShowErrorDialog
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
Definition: BasicUI.h:233
ExportPCMOptions::mEncodingIndexes
std::vector< int > mEncodingIndexes
Definition: ExportPCM.cpp:139
ExportPlugin::AddExtension
void AddExtension(const FileExtension &extension, int index)
Definition: Export.cpp:126
ShowExportErrorDialog
void ShowExportErrorDialog(wxString ErrorCode, TranslatableString message, const TranslatableString &caption)
Definition: Export.cpp:1518
wxPanelWrapper
Definition: wxPanelWrapper.h:41
ID_HEADER_CHOICE
#define ID_HEADER_CHOICE
Definition: ExportPCM.cpp:110
FileException::Cause::Write
@ Write
most important to detect when storage space is exhausted
Tags::HasTag
bool HasTag(const wxString &name) const
Definition: Tags.cpp:452
Tags
ID3 Tags (for MP3)
Definition: Tags.h:74
sf_header_index_to_type
unsigned int sf_header_index_to_type(int i)
Definition: FileFormats.cpp:59
Format
Abstract base class used in importing a file.
TAG_TRACK
#define TAG_TRACK
Definition: Tags.h:63
BasicUI::ProgressResult
ProgressResult
Definition: BasicUI.h:145
Tags::GetRange
Iterators GetRange() const
Definition: Tags.cpp:481
ExportPCM::GetExtension
FileExtension GetExtension(int index) override
Return the (first) file name extension for the sub-format.
Definition: ExportPCM.cpp:1063
ExportPCM
Definition: ExportPCM.cpp:383
ExportPCMOptions::PopulateOrExchange
void PopulateOrExchange(ShuttleGui &S)
Definition: ExportPCM.cpp:189
FileException
Thrown for failure of file or database operations in deeply nested places.
Definition: FileException.h:19
sf_header_name
wxString sf_header_name(int format)
Get the string name of the specified container format.
Definition: FileFormats.cpp:111
SAMPLE_SIZE
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:44
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
MallocString
std::unique_ptr< Character[], freer > MallocString
Definition: MemoryX.h:274
XO
#define XO(s)
Definition: Internat.h:31
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:40
int24Sample
@ int24Sample
Definition: SampleFormat.h:33
ShuttleGuiBase::EndMultiColumn
void EndMultiColumn()
Definition: ShuttleGui.cpp:1238
TAG_SOFTWARE
#define TAG_SOFTWARE
Definition: Tags.h:67
LoadEncoding
static int LoadEncoding(int type)
Definition: ExportPCM.cpp:93
Tags::GetTag
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:461
desc
const TranslatableString desc
Definition: ExportPCM.cpp:58
sf_encoding_index_to_subtype
unsigned int sf_encoding_index_to_subtype(int i)
Definition: FileFormats.cpp:95
ExportPCM::GetMaxChannels
unsigned GetMaxChannels(int index) override
Definition: ExportPCM.cpp:1077
ExportPlugin::GetFormat
virtual wxString GetFormat(int index)
Definition: Export.cpp:151
ExportPlugin::GetExtension
virtual FileExtension GetExtension(int index=0)
Return the (first) file name extension for the sub-format.
Definition: Export.cpp:161
Tags::Get
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:237
ShuttleGui::Id
ShuttleGui & Id(int id)
Definition: ShuttleGui.cpp:2274
wxWidgetsWindowPlacement
Window placement information for wxWidgetsBasicUI can be constructed from a wxWindow pointer.
Definition: wxWidgetsBasicUI.h:20
ExportPCM::ExportPCM
ExportPCM()
Definition: ExportPCM.cpp:415
floatSample
@ floatSample
Definition: SampleFormat.h:34
ExportPCMOptions::mHeaderNames
TranslatableStrings mHeaderNames
Definition: ExportPCM.cpp:135
FileExtension
wxString FileExtension
File extension, not including any leading dot.
Definition: Identifier.h:224
ExportPCMOptions::mType
int mType
Definition: ExportPCM.cpp:145
XXO
#define XXO(s)
Definition: Internat.h:44
ShuttleGuiBase::EndHorizontalLay
void EndHorizontalLay()
Definition: ShuttleGui.cpp:1177
sf_header_index_name
wxString sf_header_index_name(int format)
Get the name of a container format from libsndfile.
Definition: FileFormats.cpp:47
ExportPlugin::SetExtensions
void SetExtensions(FileExtensions extensions, int index)
Definition: Export.cpp:131
ExportPCMOptions::mEncodingNames
TranslatableStrings mEncodingNames
Definition: ExportPCM.cpp:140
ExportPlugin::InitProgress
static void InitProgress(std::unique_ptr< ProgressDialog > &pDialog, const TranslatableString &title, const TranslatableString &message)
Definition: Export.cpp:250
SFFile::close
int close()
Definition: FileFormats.h:150
ShuttleGuiBase::StartHorizontalLay
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:1167
CopySamples
void CopySamples(constSamplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, size_t len, DitherType ditherType, unsigned int srcStride, unsigned int dstStride)
Copy samples from any format to any other format; apply dithering only if narrowing the format.
Definition: SampleFormat.cpp:111
ShuttleGuiBase::StartMultiColumn
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
Definition: ShuttleGui.cpp:1229
ExportPlugin::SetFormat
void SetFormat(const wxString &format, int index)
Definition: Export.cpp:116
SaveOtherFormat
static void SaveOtherFormat(int val)
Definition: ExportPCM.cpp:87
ShuttleGuiBase::EndVerticalLay
void EndVerticalLay()
Definition: ShuttleGui.cpp:1203
int16Sample
@ int16Sample
Definition: SampleFormat.h:32
ExportPCM::OptionsCreate
void OptionsCreate(ShuttleGui &S, int format) override
Definition: ExportPCM.cpp:1031
none
@ none
Definition: Dither.h:20
ExportPCMOptions
Definition: ExportPCM.cpp:114
ExportPCM::GetFormat
wxString GetFormat(int index) override
Definition: ExportPCM.cpp:1049
TAG_GENRE
#define TAG_GENRE
Definition: Tags.h:65
format
int format
Definition: ExportPCM.cpp:56
ShuttleGuiBase::GetParent
wxWindow * GetParent()
Definition: ShuttleGui.h:496
Export.h
ShuttleGuiBase::AddWindow
wxWindow * AddWindow(wxWindow *pWindow, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:299
TAG_YEAR
#define TAG_YEAR
Definition: Tags.h:64
ExportPlugin::SetDescription
void SetDescription(const TranslatableString &description, int index)
Definition: Export.cpp:121
SFFile
Definition: FileFormats.h:143
sf_num_headers
int sf_num_headers()
Get the number of container formats supported by libsndfile.
Definition: FileFormats.cpp:37
TAG_COPYRIGHT
#define TAG_COPYRIGHT
Definition: Tags.h:68
ExportPCMOptions::GetTypes
void GetTypes()
Definition: ExportPCM.cpp:273
ExportPCMOptions::mEncodingChoice
wxChoice * mEncodingChoice
Definition: ExportPCM.cpp:141
SaveEncoding
static void SaveEncoding(int type, int val)
Definition: ExportPCM.cpp:99
ID_ENCODING_CHOICE
#define ID_ENCODING_CHOICE
Definition: ExportPCM.cpp:111
sf_num_encodings
int sf_num_encodings()
Get the number of data encodings libsndfile supports (in any container or none.
Definition: FileFormats.cpp:75
ExportPCM::Export
ProgressResult Export(AudacityProject *project, std::unique_ptr< ProgressDialog > &pDialog, unsigned channels, const wxFileNameWrapper &fName, bool selectedOnly, double t0, double t1, MixerSpec *mixerSpec=NULL, const Tags *metadata=NULL, int subformat=0) override
Definition: ExportPCM.cpp:467
ExportPCMOptions::ExportPCMOptions
ExportPCMOptions(wxWindow *parent, int format)
Definition: ExportPCM.cpp:155
sampleFormat
sampleFormat
Definition: SampleFormat.h:29
ExportPCMOptions::~ExportPCMOptions
virtual ~ExportPCMOptions()
Definition: ExportPCM.cpp:182
samplePtr
char * samplePtr
Definition: SampleFormat.h:49
ExportPlugin::SetMaxChannels
void SetMaxChannels(unsigned maxchannels, unsigned index)
Definition: Export.cpp:141
LoadOtherFormat
static int LoadOtherFormat(int def=0)
Definition: ExportPCM.cpp:81
sf_subtype_bytes_per_sample
int sf_subtype_bytes_per_sample(unsigned int format)
Definition: FileFormats.cpp:207
name
const wxChar * name
Definition: ExportPCM.cpp:57
Exporter::RegisteredExportPlugin
Definition: Export.h:177
sf_subtype_more_than_16_bits
bool sf_subtype_more_than_16_bits(unsigned int format)
Definition: FileFormats.cpp:190
kFormats
struct @0 kFormats[]
FileConfig::Flush
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
FMT_WAV
@ FMT_WAV
Definition: ExportPCM.cpp:73
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:495
ExportPCM::AddStrings
bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format)
Definition: ExportPCM.cpp:814
sampleCount
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
ExportPCM::AdjustString
ArrayOf< char > AdjustString(const wxString &wxStr, int sf_format)
Definition: ExportPCM.cpp:727
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:113
FMT_OTHER
@ FMT_OTHER
Definition: ExportPCM.cpp:74
ExportPlugin::CreateMixer
std::unique_ptr< Mixer > CreateMixer(const TrackList &tracks, bool selectionOnly, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, MixerSpec *mixerSpec)
Definition: Export.cpp:222
ProjectSettings::GetRate
double GetRate() const
Definition: ProjectSettings.cpp:168
ExportPlugin::SetCanMetaData
void SetCanMetaData(bool canmetadata, int index)
Definition: Export.cpp:146
ExportPlugin::OptionsCreate
virtual void OptionsCreate(ShuttleGui &S, int format)=0
Definition: Export.cpp:208
TAG_COMMENTS
#define TAG_COMMENTS
Definition: Tags.h:66
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
TAG_ARTIST
#define TAG_ARTIST
Definition: Tags.h:61
ExportPlugin::AddFormat
int AddFormat()
Add a NEW entry to the list of formats this plug-in can export.
Definition: Export.cpp:100
gHighQualityDither
DitherType gHighQualityDither
Definition: SampleFormat.cpp:50
ExportPCMOptions::OnEncodingChoice
void OnEncodingChoice(wxCommandEvent &evt)
Definition: ExportPCM.cpp:262
Prefs.h
ExportPCMOptions::SendSuffixEvent
void SendSuffixEvent()
Definition: ExportPCM.cpp:369
ExportPCMOptions::OnShow
void OnShow(wxShowEvent &evt)
Definition: ExportPCM.cpp:219
sf_get_all_extensions
FileExtensions sf_get_all_extensions()
Definition: FileFormats.cpp:241
MixerSpec
Class used with Mixer.
Definition: Mix.h:59
sf_subtype_is_integer
bool sf_subtype_is_integer(unsigned int format)
Definition: FileFormats.cpp:199
eIsCreatingFromPrefs
@ eIsCreatingFromPrefs
Definition: ShuttleGui.h:47
ExportPlugin
Definition: Export.h:65
sf_header_extension
wxString sf_header_extension(int format)
Get the most common file extension for the given format.
Definition: FileFormats.cpp:146
safenew
#define safenew
Definition: MemoryX.h:10
ShuttleGuiBase::SetStretchyCol
void SetStretchyCol(int i)
Used to modify an already placed FlexGridSizer to make a column stretchy.
Definition: ShuttleGui.cpp:202
ExportPCMOptions::mHeaderFromChoice
int mHeaderFromChoice
Definition: ExportPCM.cpp:137
ExportPCMOptions::mSelFormat
int mSelFormat
Definition: ExportPCM.cpp:144
ExportPCM::ReportTooBigError
void ReportTooBigError(wxWindow *pParent)
Definition: ExportPCM.cpp:440
END_EVENT_TABLE
END_EVENT_TABLE()
sRegisteredPlugin
static Exporter::RegisteredExportPlugin sRegisteredPlugin
Definition: ExportPCM.cpp:1101
sf_encoding_index_name
wxString sf_encoding_index_name(int i)
Get the string name of the data encoding of the requested format.
Definition: FileFormats.cpp:84
ArrayOf< char >
ExportPCMOptions::mHeaderChoice
wxChoice * mHeaderChoice
Definition: ExportPCM.cpp:136
ExportPCMOptions::mHeaderIndexes
std::vector< int > mHeaderIndexes
Definition: ExportPCM.cpp:134
TAG_TITLE
#define TAG_TITLE
Definition: Tags.h:60
ExportPCM::AddID3Chunk
bool AddID3Chunk(const wxFileNameWrapper &fName, const Tags *tags, int sf_format)
Definition: ExportPCM.cpp:889
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
Dither.h
TAG_ALBUM
#define TAG_ALBUM
Definition: Tags.h:62