📄 replaygain.c
字号:
if(instance->channels != 1 && instance->channels != 2) { instance->error = true; return; } if(!grabbag__replaygain_is_valid_sample_frequency(instance->sample_rate)) { instance->error = true; return; } }}static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data){ DecoderInstance *instance = (DecoderInstance*)client_data; (void)decoder, (void)status; instance->error = true;}const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak){ DecoderInstance instance; FLAC__FileDecoder *decoder = FLAC__file_decoder_new(); if(0 == decoder) return "memory allocation error"; instance.error = false; /* It does these three by default but lets be explicit: */ FLAC__file_decoder_set_md5_checking(decoder, false); FLAC__file_decoder_set_metadata_ignore_all(decoder); FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO); FLAC__file_decoder_set_filename(decoder, filename); FLAC__file_decoder_set_write_callback(decoder, write_callback_); FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_); FLAC__file_decoder_set_error_callback(decoder, error_callback_); FLAC__file_decoder_set_client_data(decoder, &instance); if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) { FLAC__file_decoder_delete(decoder); return "initializing decoder"; } if(!FLAC__file_decoder_process_until_end_of_file(decoder) || instance.error) { FLAC__file_decoder_delete(decoder); return "decoding file"; } FLAC__file_decoder_delete(decoder); grabbag__replaygain_get_title(title_gain, title_peak); return 0;}const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak){ const char *error; if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak))) return error; if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) return error; return 0;}const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak){ FLAC__ASSERT(0 != block); FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); if( FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)tag_album_gain_) < 0 || FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)tag_album_peak_) < 0 ) return "memory allocation error"; if( !append_tag_(block, peak_format_, tag_album_peak_, album_peak) || !append_tag_(block, gain_format_, tag_album_gain_, album_gain) ) return "memory allocation error"; return 0;}const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak){ FLAC__ASSERT(0 != block); FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); if( FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)tag_title_gain_) < 0 || FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)tag_title_peak_) < 0 ) return "memory allocation error"; if( !append_tag_(block, peak_format_, tag_title_peak_, title_peak) || !append_tag_(block, gain_format_, tag_title_gain_, title_gain) ) return "memory allocation error"; return 0;}static const char *store_to_file_pre_(const char *filename, FLAC__Metadata_Chain **chain, FLAC__StreamMetadata **block){ FLAC__Metadata_Iterator *iterator; const char *error; FLAC__bool found_vc_block = false; if(0 == (*chain = FLAC__metadata_chain_new())) return "memory allocation error"; if(!FLAC__metadata_chain_read(*chain, filename)) { error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)]; FLAC__metadata_chain_delete(*chain); return error; } if(0 == (iterator = FLAC__metadata_iterator_new())) { FLAC__metadata_chain_delete(*chain); return "memory allocation error"; } FLAC__metadata_iterator_init(iterator, *chain); do { *block = FLAC__metadata_iterator_get_block(iterator); if((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) found_vc_block = true; } while(!found_vc_block && FLAC__metadata_iterator_next(iterator)); if(!found_vc_block) { /* create a new block */ *block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); if(0 == *block) { FLAC__metadata_chain_delete(*chain); FLAC__metadata_iterator_delete(iterator); return "memory allocation error"; } while(FLAC__metadata_iterator_next(iterator)) ; if(!FLAC__metadata_iterator_insert_block_after(iterator, *block)) { error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)]; FLAC__metadata_chain_delete(*chain); FLAC__metadata_iterator_delete(iterator); return error; } /* iterator is left pointing to new block */ FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == *block); } FLAC__metadata_iterator_delete(iterator); FLAC__ASSERT(0 != *block); FLAC__ASSERT((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); return 0;}static const char *store_to_file_post_(const char *filename, FLAC__Metadata_Chain *chain, FLAC__bool preserve_modtime){ struct stat stats; const FLAC__bool have_stats = get_file_stats_(filename, &stats); (void)grabbag__file_change_stats(filename, /*read_only=*/false); FLAC__metadata_chain_sort_padding(chain); if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, preserve_modtime)) { FLAC__metadata_chain_delete(chain); return FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)]; } FLAC__metadata_chain_delete(chain); if(have_stats) set_file_stats_(filename, &stats); return 0;}const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime){ FLAC__Metadata_Chain *chain; FLAC__StreamMetadata *block; const char *error; if(0 != (error = store_to_file_pre_(filename, &chain, &block))) return error; if(0 != (error = grabbag__replaygain_store_to_vorbiscomment(block, album_gain, album_peak, title_gain, title_peak))) { FLAC__metadata_chain_delete(chain); return error; } if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime))) return error; return 0;}const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime){ FLAC__Metadata_Chain *chain; FLAC__StreamMetadata *block; const char *error; if(0 != (error = store_to_file_pre_(filename, &chain, &block))) return error; if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) { FLAC__metadata_chain_delete(chain); return error; } if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime))) return error; return 0;}const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime){ FLAC__Metadata_Chain *chain; FLAC__StreamMetadata *block; const char *error; if(0 != (error = store_to_file_pre_(filename, &chain, &block))) return error; if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak))) { FLAC__metadata_chain_delete(chain); return error; } if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime))) return error; return 0;}static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val){ char s[32], *end; const char *p, *q; double v; FLAC__ASSERT(0 != entry); FLAC__ASSERT(0 != val); p = (const char *)entry->entry; q = strchr(p, '='); if(0 == q) return false; q++; memset(s, 0, sizeof(s)-1); strncpy(s, q, local_min(sizeof(s)-1, entry->length - (q-p))); v = strtod(s, &end); if(end == s) return false; *val = v; return true;}FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, double *gain, double *peak){ int gain_offset, peak_offset; FLAC__ASSERT(0 != block); FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? tag_album_gain_ : tag_title_gain_)))) return false; if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? tag_album_peak_ : tag_title_peak_)))) return false; if(!parse_double_(block->data.vorbis_comment.comments + gain_offset, gain)) return false; if(!parse_double_(block->data.vorbis_comment.comments + peak_offset, peak)) return false; return true;}double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping){ double scale; FLAC__ASSERT(peak >= 0.0); gain += preamp; scale = (float) pow(10.0, gain * 0.05); if(prevent_clipping && peak > 0.0) { const double max_scale = (float)(1.0 / peak); if(scale > max_scale) scale = max_scale; } return scale;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -