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