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 "ProjectRate.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/wxWidgetsWindowPlacement.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 = ProjectRate::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  auto 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  const_cast<samplePtr>(mixed) // PRL fix this!
656  + (c * SAMPLE_SIZE(format)), format,
657  numSamples, DitherType::none, info.channels, info.channels);
658  }
659  }
660 
661  if (format == int16Sample)
662  samplesWritten = SFCall<sf_count_t>(sf_writef_short, sf.get(), (const short *)mixed, numSamples);
663  else
664  samplesWritten = SFCall<sf_count_t>(sf_writef_float, sf.get(), (const float *)mixed, numSamples);
665 
666  if (static_cast<size_t>(samplesWritten) != numSamples) {
667  char buffer2[1000];
668  sf_error_str(sf.get(), buffer2, 1000);
669  //Used to give this error message
670 #if 0
672  XO(
673  /* i18n-hint: %s will be the error message from libsndfile, which
674  * is usually something unhelpful (and untranslated) like "system
675  * error" */
676 "Error while writing %s file (disk full?).\nLibsndfile says \"%s\"")
677  .Format( formatStr, wxString::FromAscii(buffer2) ));
678 #else
679  // But better to give the same error message as for
680  // other cases of disk exhaustion.
681  // The thrown exception doesn't escape but GuardedCall
682  // will enqueue a message.
683  GuardedCall([&fName]{
684  throw FileException{
685  FileException::Cause::Write, fName }; });
686 #endif
687  updateResult = ProgressResult::Cancelled;
688  break;
689  }
690 
691  updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
692  }
693  }
694 
695  // Install the WAV metata in a "LIST" chunk at the end of the file
696  if (updateResult == ProgressResult::Success ||
697  updateResult == ProgressResult::Stopped) {
698  if (fileFormat == SF_FORMAT_WAV ||
699  fileFormat == SF_FORMAT_WAVEX) {
700  if (!AddStrings(project, sf.get(), metadata, sf_format)) {
701  // TODO: more precise message
702  ShowExportErrorDialog("PCM:675");
704  }
705  }
706  if (0 != sf.close()) {
707  // TODO: more precise message
708  ShowExportErrorDialog("PCM:681");
710  }
711  }
712  }
713 
714  if (updateResult == ProgressResult::Success ||
715  updateResult == ProgressResult::Stopped)
716  if ((fileFormat == SF_FORMAT_AIFF) ||
717  (fileFormat == SF_FORMAT_WAV))
718  // Note: file has closed, and gets reopened and closed again here:
719  if (!AddID3Chunk(fName, metadata, sf_format) ) {
720  // TODO: more precise message
721  ShowExportErrorDialog("PCM:694");
723  }
724 
725  return updateResult;
726 }
727 
728 ArrayOf<char> ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
729 {
730  bool b_aiff = false;
731  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
732  b_aiff = true; // Apple AIFF file
733 
734  // We must convert the string to 7 bit ASCII
735  size_t sz = wxStr.length();
736  if(sz == 0)
737  return {};
738  // Size for secure allocation in case of local wide char usage
739  size_t sr = (sz+4) * 2;
740 
741  ArrayOf<char> pDest{ sr, true };
742  if (!pDest)
743  return {};
744  ArrayOf<char> pSrc{ sr, true };
745  if (!pSrc)
746  return {};
747 
748  if(wxStr.mb_str(wxConvISO8859_1))
749  strncpy(pSrc.get(), wxStr.mb_str(wxConvISO8859_1), sz);
750  else if(wxStr.mb_str())
751  strncpy(pSrc.get(), wxStr.mb_str(), sz);
752  else
753  return {};
754 
755  char *pD = pDest.get();
756  char *pS = pSrc.get();
757  unsigned char c;
758 
759  // ISO Latin to 7 bit ascii conversion table (best approximation)
760  static char aASCII7Table[256] = {
761  0x00, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
762  0x5f, 0x09, 0x0a, 0x5f, 0x0d, 0x5f, 0x5f, 0x5f,
763  0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
764  0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
765  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
766  0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
767  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
768  0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
769  0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
770  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
771  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
772  0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
773  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
774  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
775  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
776  0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
777  0x45, 0x20, 0x2c, 0x53, 0x22, 0x2e, 0x2b, 0x2b,
778  0x5e, 0x25, 0x53, 0x28, 0x4f, 0x20, 0x5a, 0x20,
779  0x20, 0x27, 0x27, 0x22, 0x22, 0x2e, 0x2d, 0x5f,
780  0x22, 0x54, 0x73, 0x29, 0x6f, 0x20, 0x7a, 0x59,
781  0x20, 0x21, 0x63, 0x4c, 0x6f, 0x59, 0x7c, 0x53,
782  0x22, 0x43, 0x61, 0x22, 0x5f, 0x2d, 0x43, 0x2d,
783  0x6f, 0x7e, 0x32, 0x33, 0x27, 0x75, 0x50, 0x27,
784  0x2c, 0x31, 0x6f, 0x22, 0x5f, 0x5f, 0x5f, 0x3f,
785  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43,
786  0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
787  0x44, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x78,
788  0x4f, 0x55, 0x55, 0x55, 0x55, 0x59, 0x70, 0x53,
789  0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x63,
790  0x65, 0x65, 0x65, 0x65, 0x69, 0x69, 0x69, 0x69,
791  0x64, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x2f,
792  0x6f, 0x75, 0x75, 0x75, 0x75, 0x79, 0x70, 0x79
793  };
794 
795  size_t i;
796  for(i = 0; i < sr; i++) {
797  c = (unsigned char) *pS++;
798  *pD++ = aASCII7Table[c];
799  if(c == 0)
800  break;
801  }
802  *pD = '\0';
803 
804  if(b_aiff) {
805  int len = (int)strlen(pDest.get());
806  if((len % 2) != 0) {
807  // In case of an odd length string, add a space char
808  strcat(pDest.get(), " ");
809  }
810  }
811 
812  return pDest;
813 }
814 
815 bool ExportPCM::AddStrings(AudacityProject * WXUNUSED(project), SNDFILE *sf, const Tags *tags, int sf_format)
816 {
817  if (tags->HasTag(TAG_TITLE)) {
818  auto ascii7Str = AdjustString(tags->GetTag(TAG_TITLE), sf_format);
819  if (ascii7Str) {
820  sf_set_string(sf, SF_STR_TITLE, ascii7Str.get());
821  }
822  }
823 
824  if (tags->HasTag(TAG_ALBUM)) {
825  auto ascii7Str = AdjustString(tags->GetTag(TAG_ALBUM), sf_format);
826  if (ascii7Str) {
827  sf_set_string(sf, SF_STR_ALBUM, ascii7Str.get());
828  }
829  }
830 
831  if (tags->HasTag(TAG_ARTIST)) {
832  auto ascii7Str = AdjustString(tags->GetTag(TAG_ARTIST), sf_format);
833  if (ascii7Str) {
834  sf_set_string(sf, SF_STR_ARTIST, ascii7Str.get());
835  }
836  }
837 
838  if (tags->HasTag(TAG_COMMENTS)) {
839  auto ascii7Str = AdjustString(tags->GetTag(TAG_COMMENTS), sf_format);
840  if (ascii7Str) {
841  sf_set_string(sf, SF_STR_COMMENT, ascii7Str.get());
842  }
843  }
844 
845  if (tags->HasTag(TAG_YEAR)) {
846  auto ascii7Str = AdjustString(tags->GetTag(TAG_YEAR), sf_format);
847  if (ascii7Str) {
848  sf_set_string(sf, SF_STR_DATE, ascii7Str.get());
849  }
850  }
851 
852  if (tags->HasTag(TAG_GENRE)) {
853  auto ascii7Str = AdjustString(tags->GetTag(TAG_GENRE), sf_format);
854  if (ascii7Str) {
855  sf_set_string(sf, SF_STR_GENRE, ascii7Str.get());
856  }
857  }
858 
859  if (tags->HasTag(TAG_COPYRIGHT)) {
860  auto ascii7Str = AdjustString(tags->GetTag(TAG_COPYRIGHT), sf_format);
861  if (ascii7Str) {
862  sf_set_string(sf, SF_STR_COPYRIGHT, ascii7Str.get());
863  }
864  }
865 
866  if (tags->HasTag(TAG_SOFTWARE)) {
867  auto ascii7Str = AdjustString(tags->GetTag(TAG_SOFTWARE), sf_format);
868  if (ascii7Str) {
869  sf_set_string(sf, SF_STR_SOFTWARE, ascii7Str.get());
870  }
871  }
872 
873  if (tags->HasTag(TAG_TRACK)) {
874  auto ascii7Str = AdjustString(tags->GetTag(TAG_TRACK), sf_format);
875  if (ascii7Str) {
876  sf_set_string(sf, SF_STR_TRACKNUMBER, ascii7Str.get());
877  }
878  }
879 
880  return true;
881 }
882 
883 #ifdef USE_LIBID3TAG
884 struct id3_tag_deleter {
885  void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
886 };
887 using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
888 #endif
889 
891  const wxFileNameWrapper &fName, const Tags *tags, int sf_format)
892 {
893 #ifdef USE_LIBID3TAG
894  id3_tag_holder tp { id3_tag_new() };
895 
896  for (const auto &pair : tags->GetRange()) {
897  const auto &n = pair.first;
898  const auto &v = pair.second;
899  const char *name = "TXXX";
900 
901  if (n.CmpNoCase(TAG_TITLE) == 0) {
902  name = ID3_FRAME_TITLE;
903  }
904  else if (n.CmpNoCase(TAG_ARTIST) == 0) {
905  name = ID3_FRAME_ARTIST;
906  }
907  else if (n.CmpNoCase(TAG_ALBUM) == 0) {
908  name = ID3_FRAME_ALBUM;
909  }
910  else if (n.CmpNoCase(TAG_YEAR) == 0) {
911  name = ID3_FRAME_YEAR;
912  }
913  else if (n.CmpNoCase(TAG_GENRE) == 0) {
914  name = ID3_FRAME_GENRE;
915  }
916  else if (n.CmpNoCase(TAG_COMMENTS) == 0) {
917  name = ID3_FRAME_COMMENT;
918  }
919  else if (n.CmpNoCase(TAG_TRACK) == 0) {
920  name = ID3_FRAME_TRACK;
921  }
922  else if (n.CmpNoCase(wxT("composer")) == 0) {
923  name = "TCOM";
924  }
925 
926  struct id3_frame *frame = id3_frame_new(name);
927 
928  if (!n.IsAscii() || !v.IsAscii()) {
929  id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_UTF_16);
930  }
931  else {
932  id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
933  }
934 
936  id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
937 
938  if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
939  // A hack to get around iTunes not recognizing the comment. The
940  // language defaults to XXX and, since it's not a valid language,
941  // iTunes just ignores the tag. So, either set it to a valid language
942  // (which one???) or just clear it. Unfortunately, there's no supported
943  // way of clearing the field, so do it directly.
944  id3_field *f = id3_frame_field(frame, 1);
945  memset(f->immediate.value, 0, sizeof(f->immediate.value));
946  id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
947  }
948  else if (strcmp(name, "TXXX") == 0) {
949  id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
950 
951  ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
952 
953  id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
954  }
955  else {
956  auto addr = ucs4.get();
957  id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
958  }
959 
960  id3_tag_attachframe(tp.get(), frame);
961  }
962 
963  tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
964 
965  // If this version of libid3tag supports it, use v2.3 ID3
966  // tags instead of the newer, but less well supported, v2.4
967  // that libid3tag uses by default.
968 #ifdef ID3_TAG_HAS_TAG_OPTION_ID3V2_3
969  tp->options |= ID3_TAG_OPTION_ID3V2_3;
970 #endif
971 
972  id3_length_t len;
973 
974  len = id3_tag_render(tp.get(), 0);
975  if (len == 0)
976  return true;
977 
978  if ((len % 2) != 0) len++; // Length must be even.
979  ArrayOf<id3_byte_t> buffer { len, true };
980  if (buffer == NULL)
981  return false;
982 
983  // Zero all locations, for ending odd UTF16 content
984  // correctly, i.e., two '\0's at the end.
985 
986  id3_tag_render(tp.get(), buffer.get());
987 
988  wxFFile f(fName.GetFullPath(), wxT("r+b"));
989  if (f.IsOpened()) {
990  wxUint32 sz;
991 
992  sz = (wxUint32) len;
993  if (!f.SeekEnd(0))
994  return false;
995  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
996  {
997  if (4 != f.Write("id3 ", 4))// Must be lower case for foobar2000.
998  return false ;
999  }
1000  else {
1001  if (4 != f.Write("ID3 ", 4))
1002  return false;
1003  sz = wxUINT32_SWAP_ON_LE(sz);
1004  }
1005  if (4 != f.Write(&sz, 4))
1006  return false;
1007 
1008  if (len != f.Write(buffer.get(), len))
1009  return false;
1010 
1011  sz = (wxUint32) f.Tell() - 8;
1012  if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
1013  sz = wxUINT32_SWAP_ON_LE(sz);
1014 
1015  if (!f.Seek(4))
1016  return false;
1017  if (4 != f.Write(&sz, 4))
1018  return false;
1019 
1020  if (!f.Flush())
1021  return false;
1022 
1023  if (!f.Close())
1024  return false;
1025  }
1026  else
1027  return false;
1028 #endif
1029  return true;
1030 }
1031 
1033 {
1034  switch (format)
1035  {
1036 #if defined(__WXMAC__)
1037  case FMT_AIFF:
1038 #endif
1039  case FMT_WAV:
1040  case FMT_OTHER:
1042  break;
1043 
1044  default:
1046  break;
1047  }
1048 }
1049 
1050 wxString ExportPCM::GetFormat(int index)
1051 {
1052  if (index != FMT_OTHER)
1053  {
1054  return ExportPlugin::GetFormat(index);
1055  }
1056 
1057  // Get the saved type
1058  int typ = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
1059 
1060  // Return the format name for that type
1061  return sf_header_shortname(typ);
1062 }
1063 
1065 {
1066  if (index != FMT_OTHER)
1067  {
1068  return ExportPlugin::GetExtension(index);
1069  }
1070 
1071  // Get the saved type
1072  int typ = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
1073 
1074  // Return the extension for that type
1075  return sf_header_extension(typ);
1076 }
1077 
1078 unsigned ExportPCM::GetMaxChannels(int index)
1079 {
1080  SF_INFO si = {};
1081 
1082  if (index < FMT_OTHER)
1083  {
1084  si.format = kFormats[index].format;
1085  }
1086  else
1087  {
1088  // Get the saved type
1089  si.format = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
1090  si.format |= LoadEncoding(si.format);
1091  }
1092 
1093  for (si.channels = 1; sf_format_check(&si); si.channels++)
1094  {
1095  // just counting
1096  }
1097 
1098  // Return the max number of channels
1099  return si.channels - 1;
1100 }
1101 
1103  []{ return std::make_unique< ExportPCM >(); }
1104 };
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
wxFileNameWrapper.h
BasicUI::ProgressResult::Success
@ Success
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Definition: AudacityMessageBox.cpp:17
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:127
ShowExportErrorDialog
void ShowExportErrorDialog(wxString ErrorCode, TranslatableString message, const TranslatableString &caption)
Definition: Export.cpp:1519
wxPanelWrapper
Definition: wxPanelWrapper.h:41
ProjectRate::Get
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:42
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:1064
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
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:1078
ExportPlugin::GetFormat
virtual wxString GetFormat(int index)
Definition: Export.cpp:152
ExportPlugin::GetExtension
virtual FileExtension GetExtension(int index=0)
Return the (first) file name extension for the sub-format.
Definition: Export.cpp:162
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: wxWidgetsWindowPlacement.h:22
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:132
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:251
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:117
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:1032
none
@ none
Definition: Dither.h:20
ExportPCMOptions
Definition: ExportPCM.cpp:114
ExportPCM::GetFormat
wxString GetFormat(int index) override
Definition: ExportPCM.cpp:1050
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:122
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
ProjectRate::GetRate
double GetRate() const
Definition: ProjectRate.cpp: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:142
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:506
ExportPCM::AddStrings
bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format)
Definition: ExportPCM.cpp:815
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:728
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
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:223
ExportPlugin::SetCanMetaData
void SetCanMetaData(bool canmetadata, int index)
Definition: Export.cpp:147
ExportPlugin::OptionsCreate
virtual void OptionsCreate(ShuttleGui &S, int format)=0
Definition: Export.cpp:209
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
ProjectRate.h
an object holding per-project preferred sample rate
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:101
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:55
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:1102
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:890
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