Audacity 3.2.0
Public Member Functions | Private Member Functions | Private Attributes | List of all members
FLACExportProcessor Class Referencefinal
Inheritance diagram for FLACExportProcessor:
[legend]
Collaboration diagram for FLACExportProcessor:
[legend]

Public Member Functions

bool Initialize (AudacityProject &project, const Parameters &parameters, const wxFileNameWrapper &filename, double t0, double t1, bool selectedOnly, double sampleFormat, unsigned channels, MixerOptions::Downmix *mixerSpec, const Tags *tags) override
 Called before start processing. More...
 
ExportResult Process (ExportProcessorDelegate &delegate) override
 
- Public Member Functions inherited from ExportProcessor
 ExportProcessor (const ExportProcessor &)=delete
 
ExportProcessoroperator= (const ExportProcessor &)=delete
 
 ExportProcessor ()=default
 
virtual ~ExportProcessor ()
 
virtual bool Initialize (AudacityProject &project, const Parameters &parameters, const wxFileNameWrapper &filename, double t0, double t1, bool selectedOnly, double rate, unsigned channels, MixerOptions::Downmix *mixerSpec=nullptr, const Tags *tags=nullptr)=0
 Called before start processing. More...
 
virtual ExportResult Process (ExportProcessorDelegate &delegate)=0
 

Private Member Functions

FLAC__StreamMetadataHandle MakeMetadata (AudacityProject *project, const Tags *tags) const
 

Private Attributes

struct {
   TranslatableString   status
 
   double   t0
 
   double   t1
 
   unsigned   numChannels
 
   wxFileNameWrapper   fName
 
   sampleFormat   format
 
   FLAC::Encoder::File   encoder
 
   wxFFile   f
 
   std::unique_ptr< Mixer >   mixer
 
context
 

Additional Inherited Members

- Public Types inherited from ExportProcessor
using Parameters = std::vector< std::tuple< ExportOptionID, ExportValue > >
 

Detailed Description

Definition at line 175 of file ExportFLAC.cpp.

Member Function Documentation

◆ Initialize()

bool FLACExportProcessor::Initialize ( AudacityProject project,
const Parameters parameters,
const wxFileNameWrapper filename,
double  t0,
double  t1,
bool  selectedOnly,
double  rate,
unsigned  channels,
MixerOptions::Downmix mixerSpec,
const Tags tags 
)
overridevirtual

Called before start processing.

Parameters
projectProcessor may access project data, take care to exclude any data race
parametersA format-dependent set of parameters used in exporting
selectedOnlySet to true if all tracks should be mixed, to false if only the selected tracks should be mixed and exported.
tagsA Tags object that will over-ride the one in *project and be used to tag the file that is exported. @retern Implementations may simply return false without any error reporting. This is to temporarily preserve old behavior, which is to be removed in the nearest future.

Implements ExportProcessor.

Definition at line 293 of file ExportFLAC.cpp.

300{
301 context.t0 = t0;
302 context.t1 = t1;
303 context.numChannels = numChannels;
304 context.fName = fName;
305
306 wxLogNull logNo; // temporarily disable wxWidgets error messages
307
308 long levelPref = std::stol(ExportPluginHelpers::GetParameterValue<std::string>(parameters, FlacOptionIDLevel));
309 auto bitDepthPref = ExportPluginHelpers::GetParameterValue<std::string>(parameters, FlacOptionIDBitDepth);
310
311
312 auto& encoder = context.encoder;
313
314 bool success = true;
315 success = success &&
316#ifdef LEGACY_FLAC
317 encoder.set_filename(OSOUTPUT(fName)) &&
318#endif
319 encoder.set_channels(numChannels) &&
320 encoder.set_sample_rate(lrint(sampleRate));
321
322 // See note in MakeMetadata() about a bug in libflac++ 1.1.2
324 if (success)
325 metadata = MakeMetadata(&project, tags);
326
327 if (success && !metadata) {
328 // TODO: more precise message
329 throw ExportErrorException("FLAC:283");
330 }
331
332 if (success && metadata) {
333 // set_metadata expects an array of pointers to metadata and a size.
334 // The size is 1.
335 FLAC__StreamMetadata *p = metadata.get();
336 success = encoder.set_metadata(&p, 1);
337 }
338
339
340 if (bitDepthPref == "24") {
341 context.format = int24Sample;
342 success = success && encoder.set_bits_per_sample(24);
343 } else { //convert float to 16 bits
344 context.format = int16Sample;
345 success = success && encoder.set_bits_per_sample(16);
346 }
347
348
349 // Duplicate the flac command line compression levels
350 if (levelPref < 0 || levelPref > 8) {
351 levelPref = 5;
352 }
353 success = success &&
354 encoder.set_do_exhaustive_model_search(flacLevels[levelPref].do_exhaustive_model_search) &&
355 encoder.set_do_escape_coding(flacLevels[levelPref].do_escape_coding);
356
357 if (numChannels != 2) {
358 success = success &&
359 encoder.set_do_mid_side_stereo(false) &&
360 encoder.set_loose_mid_side_stereo(false);
361 }
362 else {
363 success = success &&
364 encoder.set_do_mid_side_stereo(flacLevels[levelPref].do_mid_side_stereo) &&
365 encoder.set_loose_mid_side_stereo(flacLevels[levelPref].loose_mid_side_stereo);
366 }
367
368 success = success &&
369 encoder.set_qlp_coeff_precision(flacLevels[levelPref].qlp_coeff_precision) &&
370 encoder.set_min_residual_partition_order(flacLevels[levelPref].min_residual_partition_order) &&
371 encoder.set_max_residual_partition_order(flacLevels[levelPref].max_residual_partition_order) &&
372 encoder.set_rice_parameter_search_dist(flacLevels[levelPref].rice_parameter_search_dist) &&
373 encoder.set_max_lpc_order(flacLevels[levelPref].max_lpc_order);
374
375 if (!success) {
376 // TODO: more precise message
377 throw ExportErrorException("FLAC:336");
378 }
379
380#ifdef LEGACY_FLAC
381 encoder.init();
382#else
383 const auto path = fName.GetFullPath();
384 if (!context.f.Open(path, wxT("w+b"))) {
385 throw ExportException(XO("FLAC export couldn't open %s")
386 .Format( path )
387 .Translation());
388 }
389
390 // Even though there is an init() method that takes a filename, use the one that
391 // takes a file handle because wxWidgets can open a file with a Unicode name and
392 // libflac can't (under Windows).
393 int status = encoder.init(context.f.fp());
394 if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
395 throw ExportException(XO("FLAC encoder failed to initialize\nStatus: %d")
396 .Format( status )
397 .Translation());
398 }
399#endif
400
401 metadata.reset();
402
404 project, selectionOnly, t0, t1, numChannels, SAMPLES_PER_RUN, false,
405 sampleRate, context.format, mixerSpec);
406
407 context.status = selectionOnly
408 ? XO("Exporting the selected audio as FLAC")
409 : XO("Exporting the audio as FLAC");
410
411 return true;
412}
wxT("CloseDown"))
bool do_escape_coding
Definition: ExportFLAC.cpp:145
unsigned max_lpc_order
Definition: ExportFLAC.cpp:152
#define SAMPLES_PER_RUN
Definition: ExportFLAC.cpp:133
unsigned min_residual_partition_order
Definition: ExportFLAC.cpp:149
unsigned rice_parameter_search_dist
Definition: ExportFLAC.cpp:151
static struct @169 flacLevels[]
bool do_exhaustive_model_search
Definition: ExportFLAC.cpp:144
bool do_mid_side_stereo
Definition: ExportFLAC.cpp:146
unsigned max_residual_partition_order
Definition: ExportFLAC.cpp:150
bool loose_mid_side_stereo
Definition: ExportFLAC.cpp:147
std::unique_ptr< FLAC__StreamMetadata, FLAC__StreamMetadataDeleter > FLAC__StreamMetadataHandle
Definition: ExportFLAC.cpp:173
unsigned qlp_coeff_precision
Definition: ExportFLAC.cpp:148
XO("Cut/Copy/Paste")
#define OSOUTPUT(X)
Definition: SelectFile.h:48
const auto project
static std::unique_ptr< Mixer > CreateMixer(const AudacityProject &project, bool selectionOnly, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, MixerOptions::Downmix *mixerSpec)
wxFileNameWrapper fName
Definition: ExportFLAC.cpp:183
TranslatableString status
Definition: ExportFLAC.cpp:179
FLAC__StreamMetadataHandle MakeMetadata(AudacityProject *project, const Tags *tags) const
Definition: ExportFLAC.cpp:483
FLAC::Encoder::File encoder
Definition: ExportFLAC.cpp:185
struct FLACExportProcessor::@171 context
Abstract base class used in importing a file.
#define lrint(dbl)
Definition: float_cast.h:169

References context, ExportPluginHelpers::CreateMixer(), do_escape_coding, do_exhaustive_model_search, do_mid_side_stereo, encoder, flacLevels, anonymous_namespace{ExportFLAC.cpp}::FlacOptionIDBitDepth, anonymous_namespace{ExportFLAC.cpp}::FlacOptionIDLevel, fName, int16Sample, int24Sample, loose_mid_side_stereo, lrint, MakeMetadata(), max_lpc_order, max_residual_partition_order, min_residual_partition_order, numChannels, OSOUTPUT, project, qlp_coeff_precision, rice_parameter_search_dist, anonymous_namespace{ClipSegmentTest.cpp}::sampleRate, SAMPLES_PER_RUN, status, t0, t1, wxT(), and XO().

Here is the call graph for this function:

◆ MakeMetadata()

FLAC__StreamMetadataHandle FLACExportProcessor::MakeMetadata ( AudacityProject project,
const Tags tags 
) const
private

Definition at line 483 of file ExportFLAC.cpp.

484{
485 // Retrieve tags if needed
486 if (tags == NULL)
487 tags = &Tags::Get( *project );
488
489 auto metadata = FLAC__StreamMetadataHandle(
490 ::FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)
491 );
492
493 wxString n;
494 for (const auto &pair : tags->GetRange()) {
495 n = pair.first;
496 const auto &v = pair.second;
497 if (n == TAG_YEAR) {
498 n = wxT("DATE");
499 }
500 else if (n == TAG_COMMENTS) {
501 // Some apps like Foobar use COMMENT and some like Windows use DESCRIPTION,
502 // so add both to try and make everyone happy.
503 n = wxT("COMMENT");
504 FLAC::Metadata::VorbisComment::Entry entry(n.mb_str(wxConvUTF8),
505 v.mb_str(wxConvUTF8));
506 if (! ::FLAC__metadata_object_vorbiscomment_append_comment(metadata.get(),
507 entry.get_entry(),
508 true) ) {
509 return {};
510 }
511 n = wxT("DESCRIPTION");
512 }
513 FLAC::Metadata::VorbisComment::Entry entry(n.mb_str(wxConvUTF8),
514 v.mb_str(wxConvUTF8));
515 if (! ::FLAC__metadata_object_vorbiscomment_append_comment(metadata.get(),
516 entry.get_entry(),
517 true) ) {
518 return {};
519 }
520 }
521
522 return metadata;
523}
static ProjectFileIORegistry::AttributeWriterEntry entry
#define TAG_COMMENTS
Definition: Tags.h:64
#define TAG_YEAR
Definition: Tags.h:62
Iterators GetRange() const
Definition: Tags.cpp:426
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:214

References entry, Tags::Get(), Tags::GetRange(), project, TAG_COMMENTS, TAG_YEAR, and wxT().

Referenced by Initialize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Process()

ExportResult FLACExportProcessor::Process ( ExportProcessorDelegate delegate)
overridevirtual

Implements ExportProcessor.

Definition at line 414 of file ExportFLAC.cpp.

415{
416 delegate.SetStatusString(context.status);
417
418 auto exportResult = ExportResult::Success;
419
420 auto cleanup2 = finally( [&] {
421 if (exportResult == ExportResult::Cancelled || exportResult == ExportResult::Error) {
422#ifndef LEGACY_FLAC
423 context.f.Detach(); // libflac closes the file
424#endif
425 context.encoder.finish();
426 }
427 } );
428
429 ArraysOf<FLAC__int32> tmpsmplbuf{ context.numChannels, SAMPLES_PER_RUN, true };
430
431 while (exportResult == ExportResult::Success) {
432 auto samplesThisRun = context.mixer->Process();
433 if (samplesThisRun == 0) //stop encoding
434 break;
435
436 for (size_t i = 0; i < context.numChannels; i++) {
437 auto mixed = context.mixer->GetBuffer(i);
438 if (context.format == int24Sample) {
439 for (decltype(samplesThisRun) j = 0; j < samplesThisRun; j++) {
440 tmpsmplbuf[i][j] = ((const int *)mixed)[j];
441 }
442 }
443 else {
444 for (decltype(samplesThisRun) j = 0; j < samplesThisRun; j++) {
445 tmpsmplbuf[i][j] = ((const short *)mixed)[j];
446 }
447 }
448 }
449 if (! context.encoder.process(
450 reinterpret_cast<FLAC__int32**>( tmpsmplbuf.get() ),
451 samplesThisRun) ) {
452 // TODO: more precise message
453 throw ExportDiskFullError(context.fName);
454 }
456 delegate, *context.mixer, context.t0, context.t1);
457 }
458
459 if (exportResult != ExportResult::Cancelled && exportResult != ExportResult::Error) {
460#ifndef LEGACY_FLAC
461 context.f.Detach(); // libflac closes the file
462#endif
463 if (!context.encoder.finish())
464 {
465 return ExportResult::Error;
466 }
467#ifdef LEGACY_FLAC
468 if (!context.f.Flush() || !context.f.Close())
469 {
470 return ExportResult::Error;
471 }
472#endif
473 }
474 return exportResult;
475}
static ExportResult UpdateProgress(ExportProcessorDelegate &delegate, Mixer &mixer, double t0, double t1)
Sends progress update to delegate and retrieves state update from it. Typically used inside each expo...
virtual void SetStatusString(const TranslatableString &str)=0

References Cancelled, context, Error, int24Sample, SAMPLES_PER_RUN, ExportProcessorDelegate::SetStatusString(), Success, and ExportPluginHelpers::UpdateProgress().

Here is the call graph for this function:

Member Data Documentation

◆ 

struct { ... } FLACExportProcessor::context

Referenced by Initialize(), and Process().

◆ encoder

FLAC::Encoder::File FLACExportProcessor::encoder

Definition at line 185 of file ExportFLAC.cpp.

Referenced by Initialize().

◆ f

wxFFile FLACExportProcessor::f

Definition at line 186 of file ExportFLAC.cpp.

◆ fName

wxFileNameWrapper FLACExportProcessor::fName

Definition at line 183 of file ExportFLAC.cpp.

Referenced by Initialize().

◆ format

sampleFormat FLACExportProcessor::format

Definition at line 184 of file ExportFLAC.cpp.

◆ mixer

std::unique_ptr<Mixer> FLACExportProcessor::mixer

Definition at line 187 of file ExportFLAC.cpp.

◆ numChannels

unsigned FLACExportProcessor::numChannels

Definition at line 182 of file ExportFLAC.cpp.

Referenced by Initialize().

◆ status

TranslatableString FLACExportProcessor::status

Definition at line 179 of file ExportFLAC.cpp.

Referenced by Initialize().

◆ t0

double FLACExportProcessor::t0

Definition at line 180 of file ExportFLAC.cpp.

Referenced by Initialize().

◆ t1

double FLACExportProcessor::t1

Definition at line 181 of file ExportFLAC.cpp.

Referenced by Initialize().


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