40#include <wx/textctrl.h>
57#define LIBTWOLAME_STATIC
66 struct id3_frame *id3_frame_new(
char const *);
67 id3_length_t id3_latin1_length(id3_latin1_t
const *);
68 void id3_latin1_decode(id3_latin1_t
const *, id3_ucs4_t *);
126 ExportMP2Options(wxWindow *parent,
int format);
127 virtual ~ExportMP2Options();
130 bool TransferDataToWindow()
override;
131 bool TransferDataFromWindow()
override;
136ExportMP2Options::ExportMP2Options(wxWindow *parent,
int WXUNUSED(
format))
140 PopulateOrExchange(
S);
142 TransferDataToWindow();
147ExportMP2Options::~ExportMP2Options()
149 TransferDataFromWindow();
154void ExportMP2Options::PopulateOrExchange(
ShuttleGui &
S)
157 S.StartVerticalLay();
159 S.StartHorizontalLay(wxCENTER);
161 S.StartMultiColumn(2, wxCENTER);
168 S.EndHorizontalLay();
175bool ExportMP2Options::TransferDataToWindow()
182bool ExportMP2Options::TransferDataFromWindow()
185 PopulateOrExchange(
S);
206 std::unique_ptr<BasicUI::ProgressDialog> &pDialog,
213 const Tags *metadata = NULL,
214 int subformat = 0)
override;
220 void AddFrame(
struct id3_tag *tp,
const wxString & n,
const wxString & v,
const char *
name);
225ExportMP2::ExportMP2()
229 SetFormat(
wxT(
"MP2"),0);
230 AddExtension(
wxT(
"mp2"),0);
232 SetCanMetaData(
true,0);
233 SetDescription(
XO(
"MP2 Files"),0);
237 std::unique_ptr<BasicUI::ProgressDialog> &pDialog,
239 bool selectionOnly,
double t0,
double t1,
MixerSpec *mixerSpec,
const Tags *metadata,
240 int WXUNUSED(subformat))
242 bool stereo = (channels == 2);
243 long bitrate =
gPrefs->Read(
wxT(
"/FileFormats/MP2Bitrate"), 160);
249 twolame_options *encodeOptions;
250 encodeOptions = twolame_init();
251 auto cleanup =
finally( [&] { twolame_close(&encodeOptions); } );
253 twolame_set_in_samplerate(encodeOptions, (
int)(rate + 0.5));
254 twolame_set_out_samplerate(encodeOptions, (
int)(rate + 0.5));
255 twolame_set_bitrate(encodeOptions, bitrate);
256 twolame_set_num_channels(encodeOptions, stereo ? 2 : 1);
258 if (twolame_init_params(encodeOptions) != 0)
261 XO(
"Cannot export MP2 with this sample rate and bit rate"),
268 if (metadata == NULL)
272 if (!outFile.IsOpened()) {
280 id3len = AddTags(project, id3buffer, &endOfFile, metadata);
281 if (id3len && !endOfFile) {
282 if ( outFile.Write(id3buffer.get(), id3len).GetLastError() ) {
290 const size_t pcmBufferSize = 9216 / 2;
291 const size_t mp2BufferSize = 16384u;
300 auto mixer = CreateMixer(tracks, selectionOnly,
302 stereo ? 2 : 1, pcmBufferSize,
true,
305 InitProgress( pDialog, fName,
307 ?
XO(
"Exporting selected audio at %ld kbps")
309 :
XO(
"Exporting the audio at %ld kbps")
311 auto &progress = *pDialog;
314 auto pcmNumSamples = mixer->Process();
315 if (pcmNumSamples == 0)
318 short *pcmBuffer = (
short *)mixer->GetBuffer();
320 int mp2BufferNumBytes = twolame_encode_buffer_interleaved(
327 if (mp2BufferNumBytes < 0) {
334 if ( outFile.Write(mp2Buffer.get(), mp2BufferNumBytes).GetLastError() ) {
340 updateResult = progress.Poll(mixer->MixGetCurrentTime() - t0, t1 - t0);
344 int mp2BufferNumBytes = twolame_encode_flush(
349 if (mp2BufferNumBytes > 0)
350 if ( outFile.Write(mp2Buffer.get(), mp2BufferNumBytes).GetLastError() ) {
358 if (id3len && endOfFile)
359 if ( outFile.Write(id3buffer.get(), id3len).GetLastError() ) {
365 if ( !outFile.Close() ) {
381struct id3_tag_deleter {
382 void operator () (id3_tag *p)
const {
if (p) id3_tag_delete(p); }
384using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
388int ExportMP2::AddTags(
390 bool *endOfFile,
const Tags *tags)
393 id3_tag_holder tp { id3_tag_new() };
395 for (
const auto &pair : tags->
GetRange()) {
396 const auto &n = pair.first;
397 const auto &v = pair.second;
398 const char *
name =
"TXXX";
401 name = ID3_FRAME_TITLE;
404 name = ID3_FRAME_ARTIST;
407 name = ID3_FRAME_ALBUM;
409 else if (n.CmpNoCase(
TAG_YEAR) == 0) {
412 AddFrame(tp.get(), n, v,
"TYER");
413 name = ID3_FRAME_YEAR;
416 name = ID3_FRAME_GENRE;
419 name = ID3_FRAME_COMMENT;
422 name = ID3_FRAME_TRACK;
425 AddFrame(tp.get(), n, v,
name);
428 tp->options &= (~ID3_TAG_OPTION_COMPRESSION);
433 #ifdef ID3_TAG_HAS_TAG_OPTION_ID3V2_3
434 tp->options |= ID3_TAG_OPTION_ID3V2_3;
441 len = id3_tag_render(tp.get(), 0);
443 len = id3_tag_render(tp.get(), (id3_byte_t *)buffer.get());
453void ExportMP2::AddFrame(
struct id3_tag *tp,
const wxString & n,
const wxString & v,
const char *
name)
455 struct id3_frame *frame = id3_frame_new(
name);
457 if (!n.IsAscii() || !v.IsAscii()) {
458 id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_UTF_16);
461 id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
465 id3_utf8_ucs4duplicate((id3_utf8_t *) (
const char *) v.mb_str(wxConvUTF8)) };
467 if (strcmp(
name, ID3_FRAME_COMMENT) == 0) {
473 id3_field *f = id3_frame_field(frame, 1);
474 memset(f->immediate.value, 0,
sizeof(f->immediate.value));
475 id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
477 else if (strcmp(
name,
"TXXX") == 0) {
478 id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
480 ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (
const char *) n.mb_str(wxConvUTF8)));
482 id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
485 auto addr = ucs4.get();
486 id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
489 id3_tag_attachframe(tp, frame);
494 []{
return std::make_unique< ExportMP2 >(); }
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
const TranslatableString name
void ShowExportErrorDialog(wxString ErrorCode, TranslatableString message, const TranslatableString &caption, bool allowReporting)
void ShowDiskFullExportErrorDialog(const wxFileNameWrapper &fileName)
static Exporter::RegisteredExportPlugin sRegisteredPlugin
TranslatableString n_kbps(int n)
XXO("&Cut/Copy/Paste Toolbar")
std::unique_ptr< Character[], freer > MallocString
an object holding per-project preferred sample rate
declares abstract base class Track, TrackList, and iterators over TrackList
std::vector< TranslatableString > TranslatableStrings
void reinit(Integral count, bool initialize=false)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
virtual ProgressResult Export(AudacityProject *project, std::unique_ptr< BasicUI::ProgressDialog > &pDialog, unsigned channels, const wxFileNameWrapper &fName, bool selectedOnly, double t0, double t1, MixerSpec *mixerSpec=NULL, const Tags *metadata=NULL, int subformat=0)=0
called to export audio into a file.
virtual void OptionsCreate(ShuttleGui &S, int format)=0
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Specialization of Setting for int.
A matrix of booleans, one row per input channel, column per output.
static ProjectRate & Get(AudacityProject &project)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
static TrackList & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
const std::vector< int > BitRateValues
const TranslatableStrings BitRateNames