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

487{
488 // Retrieve tags if needed
489 if (tags == NULL)
490 tags = &Tags::Get( *project );
491
492 auto metadata = FLAC__StreamMetadataHandle(
493 ::FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)
494 );
495
496 wxString n;
497 for (const auto &pair : tags->GetRange()) {
498 n = pair.first;
499 const auto &v = pair.second;
500 if (n == TAG_YEAR) {
501 n = wxT("DATE");
502 }
503 else if (n == TAG_COMMENTS) {
504 // Some apps like Foobar use COMMENT and some like Windows use DESCRIPTION,
505 // so add both to try and make everyone happy.
506 n = wxT("COMMENT");
507 FLAC::Metadata::VorbisComment::Entry entry(n.mb_str(wxConvUTF8),
508 v.mb_str(wxConvUTF8));
509 if (! ::FLAC__metadata_object_vorbiscomment_append_comment(metadata.get(),
510 entry.get_entry(),
511 true) ) {
512 return {};
513 }
514 n = wxT("DESCRIPTION");
515 }
516 FLAC::Metadata::VorbisComment::Entry entry(n.mb_str(wxConvUTF8),
517 v.mb_str(wxConvUTF8));
518 if (! ::FLAC__metadata_object_vorbiscomment_append_comment(metadata.get(),
519 entry.get_entry(),
520 true) ) {
521 return {};
522 }
523 }
524
525 return metadata;
526}
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 417 of file ExportFLAC.cpp.

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