int ExportFLAC::Export(AudacityProject *project, int numChannels, const wxString &fName, bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, const Tags *metadata, int WXUNUSED(subformat)) { double rate = project->GetRate(); TrackList *tracks = project->GetTracks(); wxLogNull logNo; // temporarily disable wxWidgets error messages int updateResult = eProgressSuccess; int levelPref; gPrefs->Read(wxT("/FileFormats/FLACLevel"), &levelPref, 5); wxString bitDepthPref = gPrefs->Read(wxT("/FileFormats/FLACBitDepth"), wxT("16")); FLAC::Encoder::File encoder; #ifdef LEGACY_FLAC encoder.set_filename(OSOUTPUT(fName)); #endif encoder.set_channels(numChannels); encoder.set_sample_rate(lrint(rate)); // See note in GetMetadata() about a bug in libflac++ 1.1.2 if (!GetMetadata(project, metadata)) { return false; } if (mMetadata) { encoder.set_metadata(&mMetadata, 1); } sampleFormat format; if (bitDepthPref == wxT("24")) { format = int24Sample; encoder.set_bits_per_sample(24); } else { //convert float to 16 bits format = int16Sample; encoder.set_bits_per_sample(16); } // Duplicate the flac command line compression levels if (levelPref < 0 || levelPref > 8) { levelPref = 5; } encoder.set_do_exhaustive_model_search(flacLevels[levelPref].do_exhaustive_model_search); encoder.set_do_escape_coding(flacLevels[levelPref].do_escape_coding); if (numChannels != 2) { encoder.set_do_mid_side_stereo(false); encoder.set_loose_mid_side_stereo(false); } else { encoder.set_do_mid_side_stereo(flacLevels[levelPref].do_mid_side_stereo); encoder.set_loose_mid_side_stereo(flacLevels[levelPref].loose_mid_side_stereo); } encoder.set_qlp_coeff_precision(flacLevels[levelPref].qlp_coeff_precision); encoder.set_min_residual_partition_order(flacLevels[levelPref].min_residual_partition_order); encoder.set_max_residual_partition_order(flacLevels[levelPref].max_residual_partition_order); encoder.set_rice_parameter_search_dist(flacLevels[levelPref].rice_parameter_search_dist); encoder.set_max_lpc_order(flacLevels[levelPref].max_lpc_order); #ifdef LEGACY_FLAC encoder.init(); #else wxFFile f; // will be closed when it goes out of scope if (!f.Open(fName, wxT("w+b"))) { wxMessageBox(wxString::Format(_("FLAC export couldn't open %s"), fName.c_str())); return false; } // Even though there is an init() method that takes a filename, use the one that // takes a file handle because wxWidgets can open a file with a Unicode name and // libflac can't (under Windows). int status = encoder.init(f.fp()); if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { wxMessageBox(wxString::Format(_("FLAC encoder failed to initialize\nStatus: %d"), status)); return false; } #endif if (mMetadata) { ::FLAC__metadata_object_delete(mMetadata); } int numWaveTracks; WaveTrack **waveTracks; tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); Mixer *mixer = CreateMixer(numWaveTracks, waveTracks, tracks->GetTimeTrack(), t0, t1, numChannels, SAMPLES_PER_RUN, false, rate, format, true, mixerSpec); delete [] waveTracks; int i, j; FLAC__int32 **tmpsmplbuf = new FLAC__int32*[numChannels]; for (i = 0; i < numChannels; i++) { tmpsmplbuf[i] = (FLAC__int32 *) calloc(SAMPLES_PER_RUN, sizeof(FLAC__int32)); } { ProgressDialog progress(wxFileName(fName).GetName(), selectionOnly ? _("Exporting the selected audio as FLAC") : _("Exporting the entire project as FLAC")); while (updateResult == eProgressSuccess) { sampleCount samplesThisRun = mixer->Process(SAMPLES_PER_RUN); if (samplesThisRun == 0) { //stop encoding break; } else { for (i = 0; i < numChannels; i++) { samplePtr mixed = mixer->GetBuffer(i); if (format == int24Sample) { for (j = 0; j < samplesThisRun; j++) { tmpsmplbuf[i][j] = ((int *)mixed)[j]; } } else { for (j = 0; j < samplesThisRun; j++) { tmpsmplbuf[i][j] = ((short *)mixed)[j]; } } } encoder.process(tmpsmplbuf, samplesThisRun); } updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0); } f.Detach(); // libflac closes the file encoder.finish(); } for (i = 0; i < numChannels; i++) { free(tmpsmplbuf[i]); } delete mixer; delete[] tmpsmplbuf; return updateResult; }
/** * dop_track_helper */ int dop_track_helper( boost::filesystem::path outpath, DsdSampleReader* dsr, dsf2flac_int64 startPos, dsf2flac_int64 endPos, ID3_Tag id3tag) { // double check the start and end positions! if ( startPos > dsr->getLength()-1 ) startPos = dsr->getLength()-1; if ( endPos > dsr->getLength() ) endPos = dsr->getLength(); // create a dop packer object. DopPacker dopp = DopPacker(dsr); // flac vars bool ok = true; FLAC::Encoder::File encoder; FLAC__StreamEncoderInitStatus init_status; FLAC__StreamMetadata *metadata[2]; // setup the encoder if(!encoder) { fprintf(stderr, "ERROR: allocating encoder\n"); return 0; } ok &= encoder.set_verify(true); ok &= encoder.set_compression_level(5); ok &= encoder.set_channels(dsr->getNumChannels()); ok &= encoder.set_bits_per_sample(24); if ( dsr->getSamplingFreq() == 2822400 ) { ok &= encoder.set_sample_rate(176400); } else if ( dsr->getSamplingFreq() == 5644800 ) { ok &= encoder.set_sample_rate(352800); } else { fprintf(stderr, "ERROR: sample rate not supported by DoP\n"); return 0; } ok &= encoder.set_total_samples_estimate((endPos - startPos)/16); // add tags and a padding block if(ok) { metadata[0] = id3v2_to_flac( id3tag ); metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); metadata[1]->length = 2048; /* set the padding length */ ok = encoder.set_metadata(metadata, 2); } // initialize encoder if(ok) { init_status = encoder.init(outpath.c_str()); if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]); ok = false; } } // return if there is a problem with any of the flac stuff. if (!ok) return ok; // creep up to the start point. while (dsr->getPosition() < startPos) { dsr->step(); } // create a FLAC__int32 buffer to hold the samples as they are converted unsigned int bufferLen = dsr->getNumChannels()*flacBlockLen; FLAC__int32* buffer = new FLAC__int32[bufferLen]; // MAIN CONVERSION LOOP // while (dsr->getPosition() <= endPos-flacBlockLen*16) { dopp.pack_buffer(buffer,bufferLen); if(!(ok = encoder.process_interleaved(buffer, flacBlockLen))) fprintf(stderr, " state: %s\n", encoder.get_state().resolved_as_cstring(encoder)); checkTimer(dsr->getPositionInSeconds(),dsr->getPositionAsPercent()); } // delete the old buffer and make a new one with a single sample per chan delete[] buffer; buffer = new FLAC__int32[dsr->getNumChannels()]; // creep up to the end while (dsr->getPosition() <= endPos) { dopp.pack_buffer(buffer,dsr->getNumChannels()); if(!(ok = encoder.process_interleaved(buffer, 1))) fprintf(stderr, " state: %s\n", encoder.get_state().resolved_as_cstring(encoder)); checkTimer(dsr->getPositionInSeconds(),dsr->getPositionAsPercent()); } delete[] buffer; // close the flac file ok &= encoder.finish(); // report back to the user printf("\33[2K\r"); printf("%3.1f%%\t",dsr->getPositionAsPercent()); if (ok) { printf("Conversion completed sucessfully.\n"); } else { printf("\nError during conversion.\n"); fprintf(stderr, "encoding: %s\n", ok? "succeeded" : "FAILED"); fprintf(stderr, " state: %s\n", encoder.get_state().resolved_as_cstring(encoder)); } // free things FLAC__metadata_object_delete(metadata[0]); FLAC__metadata_object_delete(metadata[1]); return ok; return ok; }