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; }
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); }
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); } }
// ======================================== // Vorbis comment utilities // ======================================== static bool SetVorbisComment(FLAC__StreamMetadata *block, const char *key, CFStringRef value) { assert(NULL != block); assert(NULL != key); // Remove the existing comment with this name if(-1 == FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, key)) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger("org.sbooth.AudioEngine.AudioMetadata.FLAC"); LOG4CXX_WARN(logger, "FLAC__metadata_object_vorbiscomment_remove_entry_matching() failed"); return false; } // Nothing left to do if value is NULL if(NULL == value) return true; CFIndex valueCStringSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), kCFStringEncodingUTF8) + 1; char valueCString [valueCStringSize]; if(!CFStringGetCString(value, valueCString, valueCStringSize, kCFStringEncodingUTF8)) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger("org.sbooth.AudioEngine.AudioMetadata.FLAC"); LOG4CXX_WARN(logger, "CFStringGetCString() failed"); return false; } FLAC__StreamMetadata_VorbisComment_Entry entry; if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, key, valueCString)) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger("org.sbooth.AudioEngine.AudioMetadata.FLAC"); LOG4CXX_WARN(logger, "FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair() failed"); return false; } if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, false, false)) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger("org.sbooth.AudioEngine.AudioMetadata.FLAC"); LOG4CXX_WARN(logger, "FLAC__metadata_object_vorbiscomment_replace_comment() failed"); return false; } return true; }
/* * 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; }
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; }