OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_metadata(OggFLAC__SeekableStreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks) { FLAC__ASSERT(0 != encoder); FLAC__ASSERT(0 != encoder->private_); FLAC__ASSERT(0 != encoder->protected_); FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder); if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) return false; /* reorder metadata if necessary to ensure that any VORBIS_COMMENT is the first, according to the mapping spec */ if(0 != metadata && num_blocks > 1) { unsigned i; for(i = 1; i < num_blocks; i++) { if(0 != metadata[i] && metadata[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { FLAC__StreamMetadata *vc = metadata[i]; for( ; i > 0; i--) metadata[i] = metadata[i-1]; metadata[0] = vc; break; } } } if(0 != metadata && num_blocks > 0) { unsigned i; for(i = 0; i < num_blocks; i++) { /* keep track of any SEEKTABLE block */ if(0 != metadata[i] && metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) { encoder->private_->seek_table = &metadata[i]->data.seek_table; break; /* take only the first one */ } } } if(!OggFLAC__ogg_encoder_aspect_set_num_metadata(&encoder->protected_->ogg_encoder_aspect, num_blocks)) return false; return FLAC__stream_encoder_set_metadata(encoder->private_->FLAC_stream_encoder, metadata, num_blocks); }
static gint flac_open(void) { flac_encoder = FLAC__stream_encoder_new(); FLAC__stream_encoder_set_channels(flac_encoder, input.channels); FLAC__stream_encoder_set_sample_rate(flac_encoder, input.frequency); FLAC__stream_encoder_init_stream(flac_encoder, flac_write_cb, flac_seek_cb, flac_tell_cb, NULL, output_file); if (tuple) { FLAC__StreamMetadata *meta; meta = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); insert_vorbis_comment (meta, "title", tuple, FIELD_TITLE); insert_vorbis_comment (meta, "artist", tuple, FIELD_ARTIST); insert_vorbis_comment (meta, "album", tuple, FIELD_ALBUM); insert_vorbis_comment (meta, "genre", tuple, FIELD_GENRE); insert_vorbis_comment (meta, "comment", tuple, FIELD_COMMENT); insert_vorbis_comment (meta, "date", tuple, FIELD_DATE); insert_vorbis_comment (meta, "year", tuple, FIELD_YEAR); insert_vorbis_comment (meta, "tracknumber", tuple, FIELD_TRACK_NUMBER); FLAC__stream_encoder_set_metadata(flac_encoder, &meta, 1); } return 1; }
void FlacAudioEncoder::set_tags(AudioMetaData::SharedPtr metadata) { _metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); _metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); set_tag_value(_metadata[0], "TITLE", metadata->title()); set_tag_value(_metadata[0], "TRACKNUMBER", metadata->track_number()); set_tag_value(_metadata[0], "ARTIST", metadata->artist()); set_tag_value(_metadata[0], "ALBUM", metadata->album()); set_tag_value(_metadata[0], "ALBUMARTIST", metadata->artist()); set_tag_value(_metadata[0], "GENRE", metadata->genre()); set_tag_value(_metadata[0], "DATE", metadata->date()); set_tag_value(_metadata[0], "COMMENT", metadata->comment()); _metadata[1]->length = 4096; FLAC__stream_encoder_set_metadata(_encoder, _metadata, 2); }
virtual void WriteMetatags(const FileTags &tags) { ASSERT(inited && !started); flac_metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); AddCommentField("ENCODER", tags.encoder); if(writeTags) { AddCommentField("SOURCEMEDIA", MPT_USTRING("tracked music file")); AddCommentField("TITLE", tags.title ); AddCommentField("ARTIST", tags.artist ); AddCommentField("ALBUM", tags.album ); AddCommentField("DATE", tags.year ); AddCommentField("COMMENT", tags.comments ); AddCommentField("GENRE", tags.genre ); AddCommentField("CONTACT", tags.url ); AddCommentField("BPM", tags.bpm ); // non-standard AddCommentField("TRACKNUMBER", tags.trackno ); } FLAC__stream_encoder_set_metadata(encoder, flac_metadata, 1); }
int main(int argc, char *argv[]) { FLAC__bool ok = true; FLAC__StreamEncoder *encoder = 0; FLAC__StreamEncoderInitStatus init_status; FLAC__StreamMetadata *metadata[2]; FLAC__StreamMetadata_VorbisComment_Entry entry; FILE *fin; unsigned sample_rate = 0; unsigned channels = 0; unsigned bps = 0; if(argc != 3) { fprintf(stderr, "usage: %s infile.wav outfile.flac\n", argv[0]); return 1; } if((fin = fopen(argv[1], "rb")) == NULL) { fprintf(stderr, "ERROR: opening %s for output\n", argv[1]); return 1; } /* read wav header and validate it */ if( fread(buffer, 1, 44, fin) != 44 || memcmp(buffer, "RIFF", 4) || memcmp(buffer+8, "WAVEfmt \020\000\000\000\001\000\002\000", 16) || memcmp(buffer+32, "\004\000\020\000data", 8) ) { fprintf(stderr, "ERROR: invalid/unsupported WAVE file, only 16bps stereo WAVE in canonical form allowed\n"); fclose(fin); return 1; } sample_rate = ((((((unsigned)buffer[27] << 8) | buffer[26]) << 8) | buffer[25]) << 8) | buffer[24]; channels = 2; bps = 16; total_samples = (((((((unsigned)buffer[43] << 8) | buffer[42]) << 8) | buffer[41]) << 8) | buffer[40]) / 4; /* allocate the encoder */ if((encoder = FLAC__stream_encoder_new()) == NULL) { fprintf(stderr, "ERROR: allocating encoder\n"); fclose(fin); return 1; } ok &= FLAC__stream_encoder_set_verify(encoder, true); ok &= FLAC__stream_encoder_set_compression_level(encoder, 5); ok &= FLAC__stream_encoder_set_channels(encoder, channels); ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps); ok &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate); ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, total_samples); /* now add some metadata; we'll add some tags and a padding block */ if(ok) { if( (metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL || (metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL || /* there are many tag (vorbiscomment) functions but these are convenient for this particular use: */ !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ARTIST", "Some Artist") || !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false) || /* copy=false: let metadata object take control of entry's allocated string */ !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "YEAR", "1984") || !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false) ) { fprintf(stderr, "ERROR: out of memory or tag error\n"); ok = false; } metadata[1]->length = 1234; /* set the padding length */ ok = FLAC__stream_encoder_set_metadata(encoder, metadata, 2); } /* initialize encoder */ if(ok) { init_status = FLAC__stream_encoder_init_file(encoder, argv[2], progress_callback, /*client_data=*/NULL); if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]); ok = false; } } /* read blocks of samples from WAVE file and feed to encoder */ if(ok) { size_t left = (size_t)total_samples; while(ok && left) { size_t need = (left>READSIZE? (size_t)READSIZE : (size_t)left); if(fread(buffer, channels*(bps/8), need, fin) != need) { fprintf(stderr, "ERROR: reading from WAVE file\n"); ok = false; } else { /* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */ size_t i; for(i = 0; i < need*channels; i++) { /* inefficient but simple and works on big- or little-endian machines */ pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]); } /* feed samples to encoder */ ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, need); } left -= need; } } ok &= FLAC__stream_encoder_finish(encoder); fprintf(stderr, "encoding: %s\n", ok? "succeeded" : "FAILED"); fprintf(stderr, " state: %s\n", FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder)]); /* now that encoding is finished, the metadata can be freed */ FLAC__metadata_object_delete(metadata[0]); FLAC__metadata_object_delete(metadata[1]); FLAC__stream_encoder_delete(encoder); fclose(fin); return 0; }
static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { FLACClientData &client = *static_cast<FLACClientData *>(client_data); if(!client.started) { client.started = true; client.delaySamples = static_cast<uint32_t>(0.5 + (delay * sampleRate) / 1000.0); for(auto m = client.metadata.begin(); m != client.metadata.end(); m++) { auto metadata = *m; if(metadata->type == FLAC__METADATA_TYPE_APPLICATION && !memcmp(metadata->data.application.id, "riff", 4)) { if(metadata->length > 8 + sizeof(WAVSampleInfoChunk) && !memcmp(metadata->data.application.data, "smpl", 4)) { WAVSampleInfoChunk *smpl = reinterpret_cast<WAVSampleInfoChunk *>(metadata->data.application.data + 8); for(uint32_t i = 0; i < smpl->numLoops; i++) { WAVSampleLoop *loop = reinterpret_cast<WAVSampleLoop *>(smpl + 1) + i; if(loop->loopStart >= client.delaySamples) loop->loopStart -= client.delaySamples; if(loop->loopEnd >= client.delaySamples) loop->loopEnd -= client.delaySamples; } } } } if(!FLAC__stream_encoder_set_metadata(client.encoder, client.metadata.data(), client.metadata.size())) { std::cerr << "Cannot set FLAC metadata!" << std::endl; client.started = false; return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } if(FLAC__stream_encoder_init_FILE(client.encoder, client.of, nullptr, nullptr) != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { std::cerr << "Cannot init FLAC encoder!" << std::endl; client.started = false; return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } } if(client.delaySamples >= frame->header.blocksize) { client.delaySamples -= frame->header.blocksize; } else if(client.delaySamples > 0) { std::vector<const FLAC__int32 *> newBuffer(client.channels); for(uint32_t chn = 0; chn < client.channels; chn++) { newBuffer[chn] = buffer[chn] + client.delaySamples; } FLAC__stream_encoder_process(client.encoder, newBuffer.data(), frame->header.blocksize - client.delaySamples); client.delaySamples = 0; } else { FLAC__stream_encoder_process(client.encoder, buffer, frame->header.blocksize); } return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; }
bool Start(void *ctx, int iInChannels, int iInRate, int iInBits, const char* title, const char* artist, const char* albumartist, const char* album, const char* year, const char* track, const char* genre, const char* comment, int iTrackLength) { flac_context *context = (flac_context *)ctx; if (!context || !context->encoder) return false; // we accept only 2 / 44100 / 16 atm if (iInChannels != 2 || iInRate != 44100 || iInBits != 16) return false; FLAC__bool ok = 1; ok &= FLAC__stream_encoder_set_verify(context->encoder, true); ok &= FLAC__stream_encoder_set_channels(context->encoder, iInChannels); ok &= FLAC__stream_encoder_set_bits_per_sample(context->encoder, iInBits); ok &= FLAC__stream_encoder_set_sample_rate(context->encoder, iInRate); ok &= FLAC__stream_encoder_set_total_samples_estimate(context->encoder, iTrackLength / 4); ok &= FLAC__stream_encoder_set_compression_level(context->encoder, level); // now add some metadata FLAC__StreamMetadata_VorbisComment_Entry entry; if (ok) { if ( (context->metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL || (context->metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ARTIST", artist) || !FLAC__metadata_object_vorbiscomment_append_comment(context->metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ALBUM", album) || !FLAC__metadata_object_vorbiscomment_append_comment(context->metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ALBUMARTIST", albumartist) || !FLAC__metadata_object_vorbiscomment_append_comment(context->metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TITLE", title) || !FLAC__metadata_object_vorbiscomment_append_comment(context->metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "GENRE", genre) || !FLAC__metadata_object_vorbiscomment_append_comment(context->metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TRACKNUMBER", track) || !FLAC__metadata_object_vorbiscomment_append_comment(context->metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "DATE", year) || !FLAC__metadata_object_vorbiscomment_append_comment(context->metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "COMMENT", comment) || !FLAC__metadata_object_vorbiscomment_append_comment(context->metadata[0], entry, false) ) { ok = false; } else { context->metadata[1]->length = 4096; ok = FLAC__stream_encoder_set_metadata(context->encoder, context->metadata, 2); } } // initialize encoder in stream mode if (ok) { FLAC__StreamEncoderInitStatus init_status; init_status = FLAC__stream_encoder_init_stream(context->encoder, write_callback_flac, seek_callback_flac, tell_callback_flac, NULL, context); if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { ok = false; } } if (!ok) { return false; } return true; }
static int flac_output_open(const char *fname, const char *comment) { int fd; int nch; FLAC__StreamMetadata padding; FLAC__StreamMetadata *metadata[4]; int num_metadata = 0; #ifndef LEGACY_FLAC FLAC__StreamEncoderInitStatus init_status; #endif FLAC_ctx *ctx; if (flac_ctx == NULL) flac_session_close(); if (!(flac_ctx = (FLAC_ctx *)calloc(sizeof(FLAC_ctx), 1))) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s", strerror(errno)); return -1; } ctx = flac_ctx; ctx->in_bytes = ctx->out_bytes = 0; if(strcmp(fname, "-") == 0) { fd = 1; /* data to stdout */ if (comment == NULL) comment = "(stdout)"; } else { /* Open the audio file */ fd = open(fname, FILE_OUTPUT_MODE); if(fd < 0) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", fname, strerror(errno)); return -1; } if(comment == NULL) comment = fname; } dpm.fd = fd; nch = (dpm.encoding & PE_MONO) ? 1 : 2; if (0 < flac_options.padding) { padding.is_last = 0; padding.type = FLAC__METADATA_TYPE_PADDING; padding.length = flac_options.padding; metadata[num_metadata++] = &padding; } #ifdef LEGACY_FLAC #ifdef AU_OGGFLAC if (flac_options.isogg) { if ((ctx->encoder.ogg.stream = OggFLAC__stream_encoder_new()) == NULL) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "cannot create OggFLAC stream"); flac_session_close(); return -1; } OggFLAC__stream_encoder_set_channels(ctx->encoder.ogg.stream, nch); /* 16bps only */ OggFLAC__stream_encoder_set_bits_per_sample(ctx->encoder.ogg.stream, 16); /* set sequential number for serial */ serial_number++; if (serial_number == 1) { srand(time(NULL)); serial_number = rand(); } OggFLAC__stream_encoder_set_serial_number(ctx->encoder.ogg.stream, serial_number); OggFLAC__stream_encoder_set_verify(ctx->encoder.ogg.stream, flac_options.verify); if (!FLAC__format_sample_rate_is_valid(dpm.rate)) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "invalid sampling rate %d", dpm.rate); flac_session_close(); return -1; } OggFLAC__stream_encoder_set_sample_rate(ctx->encoder.ogg.stream, dpm.rate); OggFLAC__stream_encoder_set_qlp_coeff_precision(ctx->encoder.ogg.stream, flac_options.qlp_coeff_precision); /* expensive! */ OggFLAC__stream_encoder_set_do_qlp_coeff_prec_search(ctx->encoder.ogg.stream, flac_options.qlp_coeff_precision_search); if (nch == 2) { OggFLAC__stream_encoder_set_do_mid_side_stereo(ctx->encoder.ogg.stream, flac_options.mid_side); OggFLAC__stream_encoder_set_loose_mid_side_stereo(ctx->encoder.ogg.stream, flac_options.adaptive_mid_side); } OggFLAC__stream_encoder_set_max_lpc_order(ctx->encoder.ogg.stream, flac_options.max_lpc_order); OggFLAC__stream_encoder_set_min_residual_partition_order(ctx->encoder.ogg.stream, flac_options.min_residual_partition_order); OggFLAC__stream_encoder_set_max_residual_partition_order(ctx->encoder.ogg.stream, flac_options.max_residual_partition_order); OggFLAC__stream_encoder_set_blocksize(ctx->encoder.ogg.stream, flac_options.blocksize); OggFLAC__stream_encoder_set_client_data(ctx->encoder.ogg.stream, ctx); if (0 < num_metadata) OggFLAC__stream_encoder_set_metadata(ctx->encoder.ogg.stream, metadata, num_metadata); /* set callback */ OggFLAC__stream_encoder_set_write_callback(ctx->encoder.ogg.stream, ogg_stream_encoder_write_callback); ctx->state.ogg = OggFLAC__stream_encoder_init(ctx->encoder.ogg.stream); if (ctx->state.ogg != OggFLAC__STREAM_ENCODER_OK) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "cannot create OggFLAC state (%s)", OggFLAC__StreamEncoderStateString[ctx->state.ogg]); flac_session_close(); return -1; } } else #endif /* AU_OGGFLAC */ if (flac_options.seekable) { if ((ctx->encoder.flac.s_stream = FLAC__seekable_stream_encoder_new()) == NULL) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "cannot create FLAC stream"); flac_session_close(); return -1; } FLAC__seekable_stream_encoder_set_channels(ctx->encoder.flac.s_stream, nch); /* 16bps only */ FLAC__seekable_stream_encoder_set_bits_per_sample(ctx->encoder.flac.s_stream, 16); FLAC__seekable_stream_encoder_set_verify(ctx->encoder.flac.s_stream, flac_options.verify); if (!FLAC__format_sample_rate_is_valid(dpm.rate)) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "invalid sampling rate %d", dpm.rate); flac_session_close(); return -1; } FLAC__seekable_stream_encoder_set_sample_rate(ctx->encoder.flac.s_stream, dpm.rate); FLAC__seekable_stream_encoder_set_qlp_coeff_precision(ctx->encoder.flac.s_stream, flac_options.qlp_coeff_precision); /* expensive! */ FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(ctx->encoder.flac.s_stream, flac_options.qlp_coeff_precision_search); if (nch == 2) { FLAC__seekable_stream_encoder_set_do_mid_side_stereo(ctx->encoder.flac.s_stream, flac_options.mid_side); FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(ctx->encoder.flac.s_stream, flac_options.adaptive_mid_side); } FLAC__seekable_stream_encoder_set_max_lpc_order(ctx->encoder.flac.s_stream, flac_options.max_lpc_order); FLAC__seekable_stream_encoder_set_min_residual_partition_order(ctx->encoder.flac.s_stream, flac_options.min_residual_partition_order); FLAC__seekable_stream_encoder_set_max_residual_partition_order(ctx->encoder.flac.s_stream, flac_options.max_residual_partition_order); FLAC__seekable_stream_encoder_set_blocksize(ctx->encoder.flac.s_stream, flac_options.blocksize); FLAC__seekable_stream_encoder_set_client_data(ctx->encoder.flac.s_stream, ctx); if (0 < num_metadata) FLAC__seekable_stream_encoder_set_metadata(ctx->encoder.flac.s_stream, metadata, num_metadata); /* set callback */ /* FLAC__seekable_stream_encoder_set_metadata_callback(ctx->encoder.flac.s_stream, flac_seekable_stream_encoder_metadata_callback); /* */ #if (!defined(__BORLANDC__) && !defined(__POCC__)) FLAC__stream_encoder_set_metadata_callback(ctx->encoder.flac.s_stream, flac_seekable_stream_encoder_metadata_callback); /* */ #endif FLAC__seekable_stream_encoder_set_write_callback(ctx->encoder.flac.s_stream, flac_seekable_stream_encoder_write_callback); ctx->state.s_flac = FLAC__seekable_stream_encoder_init(ctx->encoder.flac.s_stream); if (ctx->state.s_flac != FLAC__SEEKABLE_STREAM_ENCODER_OK) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "cannot create FLAC state (%s)", FLAC__SeekableStreamEncoderStateString[ctx->state.s_flac]); flac_session_close(); return -1; } } else { if ((ctx->encoder.flac.stream = FLAC__stream_encoder_new()) == NULL) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "cannot create FLAC stream"); flac_session_close(); return -1; } FLAC__stream_encoder_set_channels(ctx->encoder.flac.stream, nch); /* 16bps only */ FLAC__stream_encoder_set_bits_per_sample(ctx->encoder.flac.stream, 16); FLAC__stream_encoder_set_verify(ctx->encoder.flac.stream, flac_options.verify); if (!FLAC__format_sample_rate_is_valid(dpm.rate)) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "invalid sampling rate %d", dpm.rate); flac_session_close(); return -1; } FLAC__stream_encoder_set_sample_rate(ctx->encoder.flac.stream, dpm.rate); FLAC__stream_encoder_set_qlp_coeff_precision(ctx->encoder.flac.stream, flac_options.qlp_coeff_precision); /* expensive! */ FLAC__stream_encoder_set_do_qlp_coeff_prec_search(ctx->encoder.flac.stream, flac_options.qlp_coeff_precision_search); if (nch == 2) { FLAC__stream_encoder_set_do_mid_side_stereo(ctx->encoder.flac.stream, flac_options.mid_side); FLAC__stream_encoder_set_loose_mid_side_stereo(ctx->encoder.flac.stream, flac_options.adaptive_mid_side); } FLAC__stream_encoder_set_max_lpc_order(ctx->encoder.flac.stream, flac_options.max_lpc_order); FLAC__stream_encoder_set_min_residual_partition_order(ctx->encoder.flac.stream, flac_options.min_residual_partition_order); FLAC__stream_encoder_set_max_residual_partition_order(ctx->encoder.flac.stream, flac_options.max_residual_partition_order); FLAC__stream_encoder_set_blocksize(ctx->encoder.flac.stream, flac_options.blocksize); FLAC__stream_encoder_set_client_data(ctx->encoder.flac.stream, ctx); if (0 < num_metadata) FLAC__stream_encoder_set_metadata(ctx->encoder.flac.stream, metadata, num_metadata); /* set callback */ FLAC__stream_encoder_set_metadata_callback(ctx->encoder.flac.stream, flac_stream_encoder_metadata_callback); FLAC__stream_encoder_set_write_callback(ctx->encoder.flac.stream, flac_stream_encoder_write_callback); ctx->state.flac = FLAC__stream_encoder_init(ctx->encoder.flac.stream); if (ctx->state.flac != FLAC__STREAM_ENCODER_OK) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "cannot create FLAC state (%s)", FLAC__StreamEncoderStateString[ctx->state.flac]); flac_session_close(); return -1; } } #else /* !LEGACY_FLAC */ if ((ctx->encoder.flac.stream = FLAC__stream_encoder_new()) == NULL) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "cannot create FLAC stream"); flac_session_close(); return -1; } #ifdef AU_OGGFLAC if (flac_options.isogg) { /* set sequential number for serial */ serial_number++; if (serial_number == 1) { srand(time(NULL)); serial_number = rand(); } FLAC__stream_encoder_set_ogg_serial_number(ctx->encoder.flac.stream, serial_number); } #endif /* AU_OGGFLAC */ FLAC__stream_encoder_set_channels(ctx->encoder.flac.stream, nch); /* 16bps only */ FLAC__stream_encoder_set_bits_per_sample(ctx->encoder.flac.stream, 16); FLAC__stream_encoder_set_verify(ctx->encoder.flac.stream, flac_options.verify); if (!FLAC__format_sample_rate_is_valid(dpm.rate)) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "invalid sampling rate %d", dpm.rate); flac_session_close(); return -1; } FLAC__stream_encoder_set_sample_rate(ctx->encoder.flac.stream, dpm.rate); FLAC__stream_encoder_set_qlp_coeff_precision(ctx->encoder.flac.stream, flac_options.qlp_coeff_precision); /* expensive! */ FLAC__stream_encoder_set_do_qlp_coeff_prec_search(ctx->encoder.flac.stream, flac_options.qlp_coeff_precision_search); if (nch == 2) { FLAC__stream_encoder_set_do_mid_side_stereo(ctx->encoder.flac.stream, flac_options.mid_side); FLAC__stream_encoder_set_loose_mid_side_stereo(ctx->encoder.flac.stream, flac_options.adaptive_mid_side); } FLAC__stream_encoder_set_max_lpc_order(ctx->encoder.flac.stream, flac_options.max_lpc_order); FLAC__stream_encoder_set_min_residual_partition_order(ctx->encoder.flac.stream, flac_options.min_residual_partition_order); FLAC__stream_encoder_set_max_residual_partition_order(ctx->encoder.flac.stream, flac_options.max_residual_partition_order); FLAC__stream_encoder_set_blocksize(ctx->encoder.flac.stream, flac_options.blocksize); if (0 < num_metadata) FLAC__stream_encoder_set_metadata(ctx->encoder.flac.stream, metadata, num_metadata); #ifdef AU_OGGFLAC if (flac_options.isogg) init_status = FLAC__stream_encoder_init_ogg_stream(ctx->encoder.flac.stream, flac_stream_encoder_write_callback, NULL, NULL, NULL, ctx); else #endif init_status = FLAC__stream_encoder_init_stream(ctx->encoder.flac.stream, flac_stream_encoder_write_callback, NULL, NULL, NULL, ctx); if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "cannot create FLAC encoder (init status: %s)", FLAC__StreamEncoderInitStatusString[init_status]); flac_session_close(); return -1; } #endif return 0; }
int __stdcall WWFlacRW_EncodeRun(int id, const wchar_t *path) { FILE *fp = NULL; errno_t ercd; int64_t left; int64_t readPos; int64_t writePos; FLAC__bool ok = true; FLAC__int32 *pcm = NULL; if (NULL == path || wcslen(path) == 0) { return FRT_BadParams; } FLAC__StreamEncoderInitStatus initStatus = FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; FlacEncodeInfo *fei = FlacTInfoFindById<FlacEncodeInfo>(g_flacEncodeInfoMap, id); if (NULL == fei) { return FRT_IdNotFound; } if (0 < fei->pictureBytes && fei->pictureData == NULL) { dprintf("%s picture data is not set yet.\n", __FUNCTION__); return FRT_DataNotReady; } assert(fei->buffPerChannel); ok = FLAC__stream_encoder_set_metadata(fei->encoder, &fei->flacMetaArray[0], fei->flacMetaCount); if(!ok) { dprintf("FLAC__stream_encoder_set_metadata failed\n"); fei->errorCode = FRT_OtherError; goto end; } for (int ch=0; ch<fei->channels; ++ch) { if (fei->buffPerChannel[ch] == NULL){ dprintf("%s pcm buffer is not set yet.\n", __FUNCTION__); return FRT_DataNotReady; } } if (fei->bitsPerSample != 16 && fei->bitsPerSample != 24) { return FRT_InvalidBitsPerSample; } pcm = new FLAC__int32[FLACENCODE_READFRAMES * fei->channels]; if (pcm == NULL) { return FRT_MemoryExhausted; } // Windowsでは、この方法でファイルを開かなければならぬ。 wcsncpy_s(fei->path, path, (sizeof fei->path)/2-1); ercd = _wfopen_s(&fp, fei->path, L"wb"); if (ercd != 0 || NULL == fp) { fei->errorCode = FRT_FileOpenError; goto end; } initStatus = FLAC__stream_encoder_init_FILE(fei->encoder, fp, ProgressCallback, fei); if(initStatus != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { dprintf("FLAC__stream_encoder_init_FILE failed %s\n", FLAC__StreamEncoderInitStatusString[initStatus]); switch (initStatus) { case FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR: { FLAC__StreamDecoderState state = FLAC__stream_encoder_get_verify_decoder_state(fei->encoder); dprintf("decoderState=%d\n", state); } fei->errorCode = FRT_EncoderError; goto end; case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS: fei->errorCode = FRT_InvalidNumberOfChannels; goto end; case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE: fei->errorCode = FRT_InvalidBitsPerSample; goto end; case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE: fei->errorCode = FRT_InvalidSampleRate; goto end; case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA: fei->errorCode = FRT_InvalidMetadata; goto end; case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS: case FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED: case FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER: case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE: case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER: case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION: case FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER: case FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE: default: fei->errorCode = FRT_OtherError; goto end; } } fp = NULL; readPos = 0; left = fei->totalSamples; while(ok && left) { uint32_t need = left>FLACENCODE_READFRAMES ? FLACENCODE_READFRAMES : (unsigned int)left; // create interleaved PCM samples to pcm[] writePos = 0; switch (fei->bitsPerSample) { case 16: for (uint32_t i=0; i<need; ++i) { for (int ch=0; ch<fei->channels;++ch) { uint8_t *p = &fei->buffPerChannel[ch][readPos]; int v = (p[0]<<16) + (p[1]<<24); pcm[writePos] = v>>16; ++writePos; } readPos += 2; } break; case 24: for (uint32_t i=0; i<need; ++i) { for (int ch=0; ch<fei->channels;++ch) { uint8_t *p = &fei->buffPerChannel[ch][readPos]; int v = (p[0]<<8) + (p[1]<<16) + (p[2]<<24); pcm[writePos] = v >> 8; ++writePos; } readPos += 3; } break; default: assert(0); break; } ok = FLAC__stream_encoder_process_interleaved(fei->encoder, pcm, need); left -= need; } if (!ok) { dprintf("FLAC__stream_encoder_process_interleaved failed"); fei->errorCode = FRT_EncoderProcessFailed; } end: delete [] pcm; pcm = NULL; if (NULL != fp) { fclose(fp); fp = NULL; } if (NULL != fei->encoder) { if (initStatus == FLAC__STREAM_ENCODER_INIT_STATUS_OK) { FLAC__stream_encoder_finish(fei->encoder); } DeleteFlacMetaArray(fei); FLAC__stream_encoder_delete(fei->encoder); fei->encoder = NULL; } if (fei->errorCode < 0) { int result = fei->errorCode; FlacTInfoDelete<FlacEncodeInfo>(g_flacEncodeInfoMap, fei); fei = NULL; return result; } return fei->id; }
FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, off_t *output_filesize, unsigned length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, unsigned num_metadata) { FLAC__int32 samples[1024]; FLAC__StreamEncoder *encoder; FLAC__StreamEncoderInitStatus init_status; encoder_client_struct encoder_client_data; unsigned i, n; FLAC__ASSERT(0 != output_filename); FLAC__ASSERT(0 != streaminfo); FLAC__ASSERT(streaminfo->type == FLAC__METADATA_TYPE_STREAMINFO); FLAC__ASSERT((streaminfo->is_last && num_metadata == 0) || (!streaminfo->is_last && num_metadata > 0)); if(0 == (encoder_client_data.file = fopen(output_filename, "wb"))) return false; encoder = FLAC__stream_encoder_new(); if(0 == encoder) { fclose(encoder_client_data.file); return false; } FLAC__stream_encoder_set_ogg_serial_number(encoder, file_utils__ogg_serial_number); FLAC__stream_encoder_set_verify(encoder, true); FLAC__stream_encoder_set_streamable_subset(encoder, true); FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false); FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false); FLAC__stream_encoder_set_channels(encoder, streaminfo->data.stream_info.channels); FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo->data.stream_info.bits_per_sample); FLAC__stream_encoder_set_sample_rate(encoder, streaminfo->data.stream_info.sample_rate); FLAC__stream_encoder_set_blocksize(encoder, streaminfo->data.stream_info.min_blocksize); FLAC__stream_encoder_set_max_lpc_order(encoder, 0); FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0); FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false); FLAC__stream_encoder_set_do_escape_coding(encoder, false); FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false); FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0); FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0); FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0); FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo->data.stream_info.total_samples); FLAC__stream_encoder_set_metadata(encoder, metadata, num_metadata); if(is_ogg) init_status = FLAC__stream_encoder_init_ogg_stream(encoder, /*read_callback=*/0, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data); else init_status = FLAC__stream_encoder_init_stream(encoder, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data); if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { fclose(encoder_client_data.file); return false; } /* init the dummy sample buffer */ for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++) samples[i] = i & 7; while(length > 0) { n = min(length, sizeof(samples) / sizeof(FLAC__int32)); if(!FLAC__stream_encoder_process_interleaved(encoder, samples, n)) { fclose(encoder_client_data.file); return false; } length -= n; } (void)FLAC__stream_encoder_finish(encoder); fclose(encoder_client_data.file); FLAC__stream_encoder_delete(encoder); if(0 != output_filesize) { struct stat filestats; if(stat(output_filename, &filestats) != 0) return false; else *output_filesize = filestats.st_size; } return true; }
static int start_write(sox_format_t * const ft) { priv_t * p = (priv_t *)ft->priv; FLAC__StreamEncoderState status; unsigned compression_level = MAX_COMPRESSION; /* Default to "best" */ if (ft->encoding.compression != HUGE_VAL) { compression_level = ft->encoding.compression; if (compression_level != ft->encoding.compression || compression_level > MAX_COMPRESSION) { lsx_fail_errno(ft, SOX_EINVAL, "FLAC compression level must be a whole number from 0 to %i", MAX_COMPRESSION); return SOX_EOF; } } p->encoder = FLAC__stream_encoder_new(); if (p->encoder == NULL) { lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder instance"); return SOX_EOF; } p->decoded_samples = lsx_malloc(sox_globals.bufsiz * sizeof(FLAC__int32)); p->bits_per_sample = ft->encoding.bits_per_sample; lsx_report("encoding at %i bits per sample", p->bits_per_sample); FLAC__stream_encoder_set_channels(p->encoder, ft->signal.channels); FLAC__stream_encoder_set_bits_per_sample(p->encoder, p->bits_per_sample); FLAC__stream_encoder_set_sample_rate(p->encoder, (unsigned)(ft->signal.rate + .5)); { /* Check if rate is streamable: */ static const unsigned streamable_rates[] = {8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; size_t i; sox_bool streamable = sox_false; for (i = 0; !streamable && i < array_length(streamable_rates); ++i) streamable = (streamable_rates[i] == ft->signal.rate); if (!streamable) { lsx_report("non-standard rate; output may not be streamable"); FLAC__stream_encoder_set_streamable_subset(p->encoder, sox_false); } } #if FLAC_API_VERSION_CURRENT >= 10 FLAC__stream_encoder_set_compression_level(p->encoder, compression_level); #else { static struct { unsigned blocksize; FLAC__bool do_exhaustive_model_search; FLAC__bool do_mid_side_stereo; FLAC__bool loose_mid_side_stereo; unsigned max_lpc_order; unsigned max_residual_partition_order; unsigned min_residual_partition_order; } const options[MAX_COMPRESSION + 1] = { {1152, sox_false, sox_false, sox_false, 0, 2, 2}, {1152, sox_false, sox_true, sox_true, 0, 2, 2}, {1152, sox_false, sox_true, sox_false, 0, 3, 0}, {4608, sox_false, sox_false, sox_false, 6, 3, 3}, {4608, sox_false, sox_true, sox_true, 8, 3, 3}, {4608, sox_false, sox_true, sox_false, 8, 3, 3}, {4608, sox_false, sox_true, sox_false, 8, 4, 0}, {4608, sox_true, sox_true, sox_false, 8, 6, 0}, {4608, sox_true, sox_true, sox_false, 12, 6, 0}, }; #define SET_OPTION(x) do {\ lsx_report(#x" = %i", options[compression_level].x); \ FLAC__stream_encoder_set_##x(p->encoder, options[compression_level].x);\ } while (0) SET_OPTION(blocksize); SET_OPTION(do_exhaustive_model_search); SET_OPTION(max_lpc_order); SET_OPTION(max_residual_partition_order); SET_OPTION(min_residual_partition_order); if (ft->signal.channels == 2) { SET_OPTION(do_mid_side_stereo); SET_OPTION(loose_mid_side_stereo); } #undef SET_OPTION } #endif if (ft->signal.length != 0) { FLAC__stream_encoder_set_total_samples_estimate(p->encoder, (FLAC__uint64)(ft->signal.length / ft->signal.channels)); p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE); if (p->metadata[p->num_metadata] == NULL) { lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table template"); return SOX_EOF; } { #if FLAC_API_VERSION_CURRENT >= 8 if (!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(p->metadata[p->num_metadata], (unsigned)(10 * ft->signal.rate + .5), (FLAC__uint64)(ft->signal.length/ft->signal.channels))) { #else size_t samples = 10 * ft->signal.rate; size_t total_samples = ft->signal.length/ft->signal.channels; if (!FLAC__metadata_object_seektable_template_append_spaced_points(p->metadata[p->num_metadata], total_samples / samples + (total_samples % samples != 0), (FLAC__uint64)total_samples)) { #endif lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table points"); return SOX_EOF; } } p->metadata[p->num_metadata]->is_last = sox_false; /* the encoder will set this for us */ ++p->num_metadata; } if (ft->oob.comments) { /* Make the comment structure */ FLAC__StreamMetadata_VorbisComment_Entry entry; int i; p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); for (i = 0; ft->oob.comments[i]; ++i) { static const char prepend[] = "Comment="; char * text = lsx_calloc(strlen(prepend) + strlen(ft->oob.comments[i]) + 1, sizeof(*text)); /* Prepend `Comment=' if no field-name already in the comment */ if (!strchr(ft->oob.comments[i], '=')) strcpy(text, prepend); entry.entry = (FLAC__byte *) strcat(text, ft->oob.comments[i]); entry.length = strlen(text); FLAC__metadata_object_vorbiscomment_append_comment(p->metadata[p->num_metadata], entry, /*copy= */ sox_true); free(text); } ++p->num_metadata; } if (p->num_metadata) FLAC__stream_encoder_set_metadata(p->encoder, p->metadata, p->num_metadata); #if FLAC_API_VERSION_CURRENT <= 7 FLAC__stream_encoder_set_write_callback(p->encoder, flac_stream_encoder_write_callback); FLAC__stream_encoder_set_metadata_callback(p->encoder, flac_stream_encoder_metadata_callback); FLAC__stream_encoder_set_client_data(p->encoder, ft); status = FLAC__stream_encoder_init(p->encoder); #else status = FLAC__stream_encoder_init_stream(p->encoder, flac_stream_encoder_write_callback, flac_stream_encoder_seek_callback, flac_stream_encoder_tell_callback, flac_stream_encoder_metadata_callback, ft); #endif if (status != FLAC__STREAM_ENCODER_OK) { lsx_fail_errno(ft, SOX_EINVAL, "%s", FLAC__StreamEncoderStateString[status]); return SOX_EOF; } return SOX_SUCCESS; } static size_t write_samples(sox_format_t * const ft, sox_sample_t const * const sampleBuffer, size_t const len) { priv_t * p = (priv_t *)ft->priv; unsigned i; for (i = 0; i < len; ++i) { long pcm = SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i], ft->clips); p->decoded_samples[i] = pcm >> (32 - p->bits_per_sample); switch (p->bits_per_sample) { case 8: p->decoded_samples[i] = SOX_SAMPLE_TO_SIGNED_8BIT(sampleBuffer[i], ft->clips); break; case 16: p->decoded_samples[i] = SOX_SAMPLE_TO_SIGNED_16BIT(sampleBuffer[i], ft->clips); break; case 24: p->decoded_samples[i] = /* sign extension: */ SOX_SAMPLE_TO_SIGNED_24BIT(sampleBuffer[i],ft->clips) << 8; p->decoded_samples[i] >>= 8; break; case 32: p->decoded_samples[i] = SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i],ft->clips); break; } } FLAC__stream_encoder_process_interleaved(p->encoder, p->decoded_samples, (unsigned) len / ft->signal.channels); return FLAC__stream_encoder_get_state(p->encoder) == FLAC__STREAM_ENCODER_OK ? len : 0; }
const char* _edje_multisense_encode_to_flac(char *snd_path, SF_INFO sfinfo) { unsigned int total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */ FLAC__bool ok = 1; FLAC__StreamEncoder *encoder = 0; FLAC__StreamEncoderInitStatus init_status; FLAC__StreamMetadata *metadata[2]; FLAC__StreamMetadata_VorbisComment_Entry entry; SNDFILE *sfile; sf_count_t size; char *tmp; sfile = sf_open(snd_path, SFM_READ, &sfinfo); if (!sfile) return NULL; if (!sf_format_check(&sfinfo)) { sf_close(sfile); return NULL; } size = sf_seek(sfile, 0, SEEK_END); sf_seek(sfile, 0, SEEK_SET); tmp = malloc(strlen(snd_path) + 1 + 5); if (!tmp) { sf_close(sfile); return NULL; } strcpy(tmp, snd_path); snd_path = tmp; strcat(snd_path, ".flac"); total_samples = size; /* allocate the encoder */ if ((encoder = FLAC__stream_encoder_new()) == NULL) { ERR("ERROR: Creating FLAC encoder\n"); free(snd_path); sf_close(sfile); return NULL; } /* Verify it's own encoded output. This will slow the encoding process. */ ok &= FLAC__stream_encoder_set_verify(encoder, 1); //Levels range from 0 (fastest, least compression) to 8 (slowest, most compression). //A value larger than 8 will be treated as 8. //5 is used for good compression and moderate compression/decompression speed. ok &= FLAC__stream_encoder_set_compression_level(encoder, 5); ok &= FLAC__stream_encoder_set_channels(encoder, sfinfo.channels); ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, 16); ok &= FLAC__stream_encoder_set_sample_rate(encoder, sfinfo.samplerate); ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, total_samples); /* now add some metadata; we'll add some tags and a padding block */ if (ok) { if ((metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL || (metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "Encoder", "flac") || !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, 0)) { ERR("ERROR: out of memory error or tag error\n"); ok = 0; } metadata[1]->length = 16; /* set the padding length */ ok = FLAC__stream_encoder_set_metadata(encoder, metadata, 2); } /* initialize encoder */ if (ok) { init_status = FLAC__stream_encoder_init_file(encoder, snd_path, NULL, (void *)(long)(total_samples)); if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { ERR("ERROR: unable to initialize FLAC encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]); ok = 0; } } /* read blocks of samples from WAVE file and feed to encoder */ while (ok) { FLAC__int32 readbuffer[READBUF * 2]; sf_count_t count; int i; count = sf_readf_int(sfile, readbuffer, READBUF); if (count <= 0) break; for (i = 0; i < (count * sfinfo.channels); i++) readbuffer[i] = readbuffer[i] >> 16; ok = FLAC__stream_encoder_process_interleaved(encoder, readbuffer, count); } FLAC__stream_encoder_finish(encoder); /* now that encoding is finished, the metadata can be freed */ FLAC__metadata_object_delete(metadata[0]); FLAC__metadata_object_delete(metadata[1]); FLAC__stream_encoder_delete(encoder); sf_close(sfile); return (snd_path); }
bool CEncoderFlac::Start(int inChannels, int inRate, int inBits, const std::string& title, const std::string& artist, const std::string& albumartist, const std::string& album, const std::string& year, const std::string& track, const std::string& genre, const std::string& comment, int trackLength) { if (!m_encoder) return false; // we accept only 2 / 44100 / 16 atm if (inChannels != 2 || inRate != 44100 || inBits != 16) { kodi::Log(ADDON_LOG_ERROR, "Invalid input format to encode"); return false; } FLAC__bool ok = 1; ok &= FLAC__stream_encoder_set_verify(m_encoder, true); ok &= FLAC__stream_encoder_set_channels(m_encoder, inChannels); ok &= FLAC__stream_encoder_set_bits_per_sample(m_encoder, inBits); ok &= FLAC__stream_encoder_set_sample_rate(m_encoder, inRate); ok &= FLAC__stream_encoder_set_total_samples_estimate(m_encoder, trackLength / 4); ok &= FLAC__stream_encoder_set_compression_level(m_encoder, kodi::GetSettingInt("level")); // now add some metadata FLAC__StreamMetadata_VorbisComment_Entry entry; if (ok) { if ( (m_metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == nullptr || (m_metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == nullptr || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ARTIST", artist.c_str()) || !FLAC__metadata_object_vorbiscomment_append_comment(m_metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ALBUM", album.c_str()) || !FLAC__metadata_object_vorbiscomment_append_comment(m_metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ALBUMARTIST", albumartist.c_str()) || !FLAC__metadata_object_vorbiscomment_append_comment(m_metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TITLE", title.c_str()) || !FLAC__metadata_object_vorbiscomment_append_comment(m_metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "GENRE", genre.c_str()) || !FLAC__metadata_object_vorbiscomment_append_comment(m_metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TRACKNUMBER", track.c_str()) || !FLAC__metadata_object_vorbiscomment_append_comment(m_metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "DATE", year.c_str()) || !FLAC__metadata_object_vorbiscomment_append_comment(m_metadata[0], entry, false) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "COMMENT", comment.c_str()) || !FLAC__metadata_object_vorbiscomment_append_comment(m_metadata[0], entry, false) ) { ok = false; } else { m_metadata[1]->length = 4096; ok = FLAC__stream_encoder_set_metadata(m_encoder, m_metadata, 2); } } // initialize encoder in stream mode if (ok) { FLAC__StreamEncoderInitStatus init_status; init_status = FLAC__stream_encoder_init_stream(m_encoder, write_callback_flac, seek_callback_flac, tell_callback_flac, nullptr, this); if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { ok = false; } } if (!ok) { kodi::Log(ADDON_LOG_ERROR, "Failed to create flac stream encoder"); return false; } return true; }