⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 replaygain.c

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 + -