bool FlacAudioEncoder::set_tag_value(FLAC__StreamMetadata* metadata, const std::string& key, const std::string& value) { FLAC__StreamMetadata_VorbisComment_Entry entry; return FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, key.c_str(), value.c_str()) and FLAC__metadata_object_vorbiscomment_append_comment(metadata, entry, false); }
static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, const FLAC__byte *name, float value) { char buffer[256]; char *saved_locale; FLAC__StreamMetadata_VorbisComment_Entry entry; FLAC__ASSERT(0 != block); FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); FLAC__ASSERT(0 != name); FLAC__ASSERT(0 != value); buffer[sizeof(buffer)-1] = '\0'; /* * We need to save the old locale and switch to "C" because the locale * influences the formatting of %f and we want it a certain way. */ saved_locale = setlocale(LC_ALL, 0); setlocale(LC_ALL, "C"); #if defined _MSC_VER || defined __MINGW32__ _snprintf(buffer, sizeof(buffer)-1, format, name, value); #else snprintf(buffer, sizeof(buffer)-1, format, name, value); #endif setlocale(LC_ALL, saved_locale); entry.entry = (FLAC__byte *)buffer; entry.length = strlen(buffer); return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true); }
void AddCommentField(const std::string &field, const mpt::ustring &data) { if(!field.empty() && !data.empty()) { FLAC__StreamMetadata_VorbisComment_Entry entry; FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field.c_str(), mpt::ToCharset(mpt::CharsetUTF8, data).c_str()); FLAC__metadata_object_vorbiscomment_append_comment(flac_metadata[0], entry, false); } }
int flac_write( const char* filename, const char *predicate, const char* uri ) { if (strcmp(predicate, LL_LICENSE) != 0) { return -LL_E_MODULE_WRITE_FAIL; /* We only know License */ } int ret = 1; FLAC__Metadata_SimpleIterator *iter = FLAC__metadata_simple_iterator_new(); if (FLAC__metadata_simple_iterator_init(iter,filename,false,false) && FLAC__metadata_simple_iterator_is_writable(iter)) { FLAC__bool found_vc = false; do { if (FLAC__metadata_simple_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_VORBIS_COMMENT) { FLAC__StreamMetadata *vc; found_vc = true; vc = FLAC__metadata_simple_iterator_get_block(iter); if (uri) { FLAC__StreamMetadata_VorbisComment_Entry entry; FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "LICENSE", uri); FLAC__metadata_object_vorbiscomment_replace_comment(vc,entry,true,false); } else { int i = FLAC__metadata_object_vorbiscomment_find_entry_from(vc,0,"LICENSE"); if (i != -1) { FLAC__metadata_object_vorbiscomment_delete_comment(vc,i); } } ret = FLAC__metadata_simple_iterator_set_block(iter, vc, true); FLAC__metadata_object_delete(vc); break; } } while (FLAC__metadata_simple_iterator_next(iter)); if (!found_vc && uri) { FLAC__StreamMetadata *vc = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); FLAC__StreamMetadata_VorbisComment_Entry entry; FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "LICENSE", uri); FLAC__metadata_object_vorbiscomment_append_comment(vc,entry,false); ret = FLAC__metadata_simple_iterator_insert_block_after(iter,vc,true); FLAC__metadata_object_delete(vc); } } else { ret = 0; } FLAC__metadata_simple_iterator_delete(iter); return ret; }
/* * vc_block_append_other_tag: * @vc_block: the Vorbis comment in which to add the tag * @tag: the name and value of the tag * * Append the unsupported (not shown in the UI) @tag to @vc_block. */ static void vc_block_append_other_tag (FLAC__StreamMetadata *vc_block, const gchar *tag) { FLAC__StreamMetadata_VorbisComment_Entry field; field.entry = (FLAC__byte *)tag; field.length = strlen (tag); /* Safe to pass const data, if the last argument (copy) is true, according * to the FLAC API reference. */ if (!FLAC__metadata_object_vorbiscomment_append_comment (vc_block, field, true)) { g_critical ("Invalid Vorbis comment, or memory allocation failed, when writing other FLAC tag '%s'", tag); } }
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy) { FLAC__ASSERT(0 != entry.entry && entry.length > 0); if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) return false; { int i; unsigned field_name_length; const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); FLAC__ASSERT(0 != eq); if(0 == eq) return false; /* double protection */ field_name_length = eq-entry.entry; if((i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length)) >= 0) { unsigned index = (unsigned)i; if(!FLAC__metadata_object_vorbiscomment_set_comment(object, index, entry, copy)) return false; if(all && (index+1 < object->data.vorbis_comment.num_comments)) { for(i = vorbiscomment_find_entry_from_(object, index+1, (const char *)entry.entry, field_name_length); i >= 0; ) { if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i)) return false; if((unsigned)i < object->data.vorbis_comment.num_comments) i = vorbiscomment_find_entry_from_(object, (unsigned)i, (const char *)entry.entry, field_name_length); else i = -1; } } return true; } else return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy); } }
/* * vc_block_append_single_tag: * @vc_block: the Vorbis comment in which to add the tag * @tag_name: the name of the tag * @value: the value of the tag * * Save field value in a single tag. */ static void vc_block_append_single_tag (FLAC__StreamMetadata *vc_block, const gchar *tag_name, const gchar *value) { FLAC__StreamMetadata_VorbisComment_Entry field; if (!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair (&field, tag_name, value)) { g_critical ("Invalid Vorbis comment, or memory allocation failed, when creating FLAC entry from tag name '%s' and value '%s'", tag_name, value); return; } if (!FLAC__metadata_object_vorbiscomment_append_comment (vc_block, field, false)) { g_critical ("Invalid Vorbis comment, or memory allocation failed, when writing FLAC tag '%s' with value '%s'", tag_name, value); } }
/* slight modification: no 'filename' arg, and errors are passed back in 'violation' instead of printed to stderr */ static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw, const char **violation) { FLAC__StreamMetadata_VorbisComment_Entry entry; char *converted; FLAC__ASSERT(0 != block); FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); FLAC__ASSERT(0 != field); FLAC__ASSERT(0 != needs_write); if(field->field_value_from_file) { /* read the file into 'data' */ FILE *f = 0; char *data = 0; const off_t size = grabbag__file_get_filesize(field->field_value); if(size < 0) { *violation = "can't open file for tag value"; return false; } if(size >= 0x100000) { /* magic arbitrary limit, actual format limit is near 16MB */ *violation = "file for tag value is too large"; return false; } if(0 == (data = malloc(size+1))) die("out of memory allocating tag value"); data[size] = '\0'; if(0 == (f = fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) { free(data); if(f) fclose(f); *violation = "error while reading file for tag value"; return false; } fclose(f); if(strlen(data) != (size_t)size) { free(data); *violation = "file for tag value has embedded NULs"; return false; } /* move 'data' into 'converted', converting to UTF-8 if necessary */ if(raw) { converted = data; } else if(utf8_encode(data, &converted) >= 0) { free(data); } else { free(data); *violation = "error converting file contents to UTF-8 for tag value"; return false; } /* create and entry and append it */ if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field->field_name, converted)) { free(converted); *violation = "file for tag value is not valid UTF-8"; return false; } free(converted); if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) { *violation = "memory allocation failure"; return false; } *needs_write = true; return true; } else { FLAC__bool needs_free = false; if(raw) { entry.entry = (FLAC__byte *)field->field; } else if(utf8_encode(field->field, &converted) >= 0) { entry.entry = (FLAC__byte *)converted; needs_free = true; } else { *violation = "error converting comment to UTF-8"; return false; } entry.length = strlen((const char *)entry.entry); if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) { if(needs_free) free(converted); /* * our previous parsing has already established that the field * name is OK, so it must be the field value */ *violation = "tag value for is not valid UTF-8"; return false; } if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) { if(needs_free) free(converted); *violation = "memory allocation failure"; return false; } *needs_write = true; if(needs_free) free(converted); return true; } }
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; }
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 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; }