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

📄 audio_mixer.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
📖 第 1 页 / 共 2 页
字号:
				/*done*/				if (ch==10) return;			}			pos = get_channel_out_pos((1<<ch), out_cfg);			assert(pos != GF_SR_MAX_CHANNELS);			inChan[pos] = bckup[i];			ch++;			cfg>>=1;		}		for (i=nb_in; i<nb_out; i++) inChan[i] = 0;	}	/*less output than input channels (eg sound card doesn't support requested format*/	else if (nb_in>nb_out) {		s32 bckup[GF_SR_MAX_CHANNELS];		u32 pos;		u32 cfg = in_cfg;		u32 ch = 0;		memcpy(bckup, inChan, sizeof(s32)*nb_in);		for (i=0; i<nb_in; i++) {			/*get first in channel*/			while (! (cfg & 1)) {				ch++;				cfg>>=1;				/*done*/				if (ch==10) return;			}			pos = get_channel_out_pos( (1<<ch), out_cfg);			/*this channel is present in output, copy over*/			if (pos < GF_SR_MAX_CHANNELS) {				inChan[pos] = bckup[i];			} else {				/*map to stereo (we assume that the driver cannot handle ANY multichannel cfg)*/				switch (1<<ch) {				case GF_AUDIO_CH_FRONT_CENTER:				case GF_AUDIO_CH_LFE:				case GF_AUDIO_CH_BACK_CENTER:					inChan[0] += bckup[i]/2;					inChan[1] += bckup[i]/2;					break;				case GF_AUDIO_CH_BACK_LEFT:				case GF_AUDIO_CH_SIDE_LEFT:					inChan[0] += bckup[i];					break;				case GF_AUDIO_CH_BACK_RIGHT:				case GF_AUDIO_CH_SIDE_RIGHT:					inChan[1] += bckup[i];					break;				}			}			ch++;			cfg>>=1;		}	}}static void AM_GetInputData(GF_AudioMixer *am, MixerInput *in, u32 audio_delay){	u32 i, j, in_ch, out_ch, prev, next, src_samp, ratio, src_size;	Bool use_prev;	s16 *in_s16;	s8 *in_s8;	s32 frac, inChan[GF_SR_MAX_CHANNELS], inChanNext[GF_SR_MAX_CHANNELS];	in_s8 = (s8 *) in->src->FetchFrame(in->src->callback, &src_size, audio_delay);	if (!in_s8) {		in->has_prev = 0;		/*done, stop fill*/		in->out_samples_to_write = 0;		return;	}	ratio = (u32) (in->src->sr * FIX2INT(255*in->speed) / am->sample_rate);	src_samp = (u32) (src_size * 8 / in->src->bps / in->src->chan);	in_ch = in->src->chan;	out_ch = am->nb_channels;	if (in->src->bps == 8) {		in_s16 = NULL;	} else {		in_s16 = (s16 *) in_s8;		in_s8 = NULL;	}	/*just in case, if only 1 sample available in src, copy over and discard frame since we cannot 	interpolate audio*/	if (src_samp==1) {		in->has_prev = 1;		for (j=0; j<in_ch; j++) in->last_channels[j] = in_s16 ? in_s16[j] : in_s8[j];		in->in_bytes_used = src_size;		return;	}	/*while space to fill and input data, convert*/	use_prev = in->has_prev;	i = 0;	next = prev = 0;	while (1) {		prev = (u32) (i*ratio + 1) / 255;		if (prev>=src_samp) break;		next = prev+1;		frac = (i*ratio) - 255*prev;		if (frac && (next==src_samp)) break;		if (use_prev && prev) use_prev = 0;		if (in_s16) {			for (j=0; j<in_ch; j++) {				inChan[j] = use_prev ? in->last_channels[j] : in_s16[in_ch*prev + j];				inChanNext[j] = in_s16[in_ch*next + j];				inChan[j] = (frac*inChanNext[j] + (255-frac)*inChan[j]) / 255;						}		} else {			for (j=0; j<in_ch; j++) {				inChan[j] = use_prev ? in->last_channels[j] : in_s8[in_ch*prev + j];				inChanNext[j] = in_s8[in_ch*next + j];				inChan[j] = (frac*inChanNext[j] + (255-frac)*inChan[j]) / 255;			}		}		am_map_channels(inChan, in_ch, in->src->ch_cfg, out_ch, am->channel_cfg);		for (j=0; j<out_ch ; j++) {			*(in->ch_buf[j] + in->out_samples_written) = (s32) (inChan[j] * FIX2INT(100*in->pan[j]) / 100 );		}		in->out_samples_written ++;		if (in->out_samples_written == in->out_samples_to_write) break;		i++;	}	if (!(ratio%255)) {		in->has_prev = 0;		if (next==src_samp) {			in->in_bytes_used = src_size;		} else {			in->in_bytes_used = MIN(src_size, prev*in->src->bps * in->src->chan / 8);		}	} else {		in->has_prev = 1;		if (next==src_samp) {			for (j=0; j<in_ch; j++) in->last_channels[j] = inChanNext[j];			in->in_bytes_used = src_size;		} else {			in->in_bytes_used = prev*in->src->bps * in->src->chan / 8;			if (in->in_bytes_used>src_size) {				in->in_bytes_used = src_size;				for (j=0; j<in_ch; j++) in->last_channels[j] = inChanNext[j];			} else {				for (j=0; j<in_ch; j++) in->last_channels[j] = in_s16 ? in_s16[in_ch*prev + j] : in_s8[in_ch*prev + j];			}		}	}	/*cf below, make sure we call release*/	in->in_bytes_used += 1;}u32 gf_mixer_get_output(GF_AudioMixer *am, void *buffer, u32 buffer_size){	MixerInput *in, *single_source;	Fixed pan[6];	Bool is_muted;	u32 i, j, count, size, in_size, nb_samples, delay, nb_written;	s32 *out_mix, nb_act_src;	char *data, *ptr;	/*the config has changed we don't write to output since settings change*/	if (gf_mixer_reconfig(am)) return 0;	gf_mixer_lock(am, 1);	count = gf_list_count(am->sources);	if (!count) {		memset(buffer, 0, buffer_size);		gf_mixer_lock(am, 0);		return 0;	}	delay = 0;	if (am->ar && !(am->ar->flags & GF_SR_AUDIO_NO_RESYNC) ) delay = am->ar->audio_delay;	single_source = NULL;	if (count!=1) goto do_mix;	if (am->force_channel_out) goto do_mix;	single_source = (MixerInput *) gf_list_get(am->sources, 0);	/*if cfg changed or unknown return*/	if (!single_source->src->GetConfig(single_source->src, 0)) {		am->must_reconfig = 1;		gf_mixer_reconfig(am);		memset(buffer, 0, buffer_size);		gf_mixer_lock(am, 0);		return 0;	}	/*this happens if input SR cannot be mapped to output audio hardware*/	if (single_source->src->sr != am->sample_rate) goto do_mix;	/*note we don't check output cfg: if the number of channel is the same then the channel cfg is the 	same*/	if (single_source->src->chan != am->nb_channels) goto do_mix;	if (single_source->src->GetSpeed(single_source->src->callback)!=FIX_ONE) goto do_mix;	if (single_source->src->GetChannelVolume(single_source->src->callback, pan)) goto do_mix;single_source_mix:	ptr = (char *)buffer;	in_size = buffer_size;	is_muted = single_source->src->IsMuted(single_source->src->callback);	while (buffer_size) {		data = single_source->src->FetchFrame(single_source->src->callback, &size, delay);		if (!data || !size) break;		/*don't copy more than possible*/		if (size > buffer_size) size = buffer_size;		if (is_muted) {			memset(ptr, 0, size);		} else {			memcpy(ptr, data, size);		}		buffer_size -= size;		ptr += size;		single_source->src->ReleaseFrame(single_source->src->callback, size);		delay = 0;	}	/*not completely filled*/	if (buffer_size) {		if (!data) {			GF_LOG(GF_LOG_WARNING, GF_LOG_RENDER, ("[Audio Mixer] not enough input data (%d still to fill)\n", buffer_size));		}		memset(ptr, 0, buffer_size);	}	gf_mixer_lock(am, 0);	return (in_size - buffer_size);do_mix:	nb_act_src = 0;	nb_samples = buffer_size / (am->nb_channels * am->bits_per_sample / 8);	/*step 1, cfg*/	if (am->output_size<buffer_size) {		if (am->output) free(am->output);		am->output = (s32*)malloc(sizeof(s32) * buffer_size);		am->output_size = buffer_size;	}	single_source = NULL;	for (i=0; i<count; i++) {		in = (MixerInput *)gf_list_get(am->sources, i);		if (in->src->IsMuted(in->src->callback)) continue;		if (in->buffer_size < nb_samples) { 			for (j=0; j<GF_SR_MAX_CHANNELS; j++) {				if (in->ch_buf[j]) free(in->ch_buf[j]); 				in->ch_buf[j] = (s32 *) malloc(sizeof(s32) * nb_samples);			}			in->buffer_size = nb_samples; 		}		in->speed = in->src->GetSpeed(in->src->callback);		if (in->speed<0) in->speed *= -1;				in->out_samples_written = 0;		in->in_bytes_used = 0;		/*if cfg unknown or changed (AudioBuffer child...) invalidate cfg settings*/		if (!in->src->GetConfig(in->src, 0)) {			nb_act_src = 0;			am->must_reconfig = 1;			/*if main mixer reconfig asap*/			if (am->ar) gf_mixer_reconfig(am);			break;		} else if (in->speed==0) {			in->out_samples_to_write = 0;		} else {			assert(in->src->sr);			in->out_samples_to_write = nb_samples;			if (in->src->IsMuted(in->src->callback)) {				memset(in->pan, 0, sizeof(Fixed)*6);			} else {				if (!in->src->GetChannelVolume(in->src->callback, in->pan)) {					/*track first active source with same cfg as mixer*/					if (!single_source && (in->src->sr == am->sample_rate) 						&& (in->src->chan == am->nb_channels) && (in->speed == FIX_ONE) 					) 						single_source = in;				}			}			nb_act_src ++;		}	}	if (!nb_act_src) {		memset(buffer, 0, sizeof(char)*buffer_size);		gf_mixer_lock(am, 0);		return 0;	}	/*if only one active source in native format, process as single source (direct copy)	this is needed because mediaControl on an audio object doesn't deactivate it (eg the audio	object is still present in the mixer). this opt is typically usefull for language selection	content (cf mp4menu)*/	if ((nb_act_src==1) && single_source) goto single_source_mix;	/*step 2, fill all buffers*/	while (nb_act_src) {		u32 nb_to_fill = 0;		/*fill*/		for (i=0; i<count; i++) {			in = (MixerInput *)gf_list_get(am->sources, i);			if (in->out_samples_to_write>in->out_samples_written) {				AM_GetInputData(am, in, in->out_samples_written ? 0 : delay);				if (in->out_samples_to_write>in->out_samples_written) nb_to_fill++;			}		}		/*release - this is done in 2 steps in case 2 audio object use the same source...*/		for (i=0; i<count; i++) {			in = (MixerInput *)gf_list_get(am->sources, i);			if (in->in_bytes_used) in->src->ReleaseFrame(in->src->callback, in->in_bytes_used-1);			in->in_bytes_used = 0;		}		if (!nb_to_fill) break;	}	/*step 3, mix the final buffer*/	memset(am->output, 0, sizeof(s32) * buffer_size);	nb_written = 0;	for (i=0; i<count; i++) {		out_mix = am->output;		in = (MixerInput *)gf_list_get(am->sources, i);		if (!in->out_samples_to_write) continue;		/*only write what has been filled in the source buffer (may be less than output size)*/		for (j=0; j<in->out_samples_written; j++) {			u32 k;			for (k=0; k<am->nb_channels; k++) {				(*out_mix) += * (in->ch_buf[k] + j);				out_mix += 1;			}		}		if (nb_written < in->out_samples_written) nb_written = in->out_samples_written;	}	if (!nb_written) {		memset(buffer, 0, sizeof(char)*buffer_size);		gf_mixer_lock(am, 0);		return 0;	}	out_mix = am->output;	if (am->bits_per_sample==16) {		s16 *out_s16 = (s16 *) buffer;		for (i=0; i<nb_written; i++) {			for (j=0; j<am->nb_channels; j++) {				s32 samp = (*out_mix / nb_act_src);				if (samp > GF_SHORT_MAX) samp = GF_SHORT_MAX;				else if (samp < GF_SHORT_MIN) samp = GF_SHORT_MIN;				(*out_s16) = samp;				out_s16 += 1;				out_mix += 1;			}		}	} else {		s8 *out_s8 = (s8 *) buffer;		for (i=0; i<nb_written; i++) {			for (j=0; j<am->nb_channels; j++) {				s32 samp = (*out_mix / nb_act_src);				if (samp > 127) samp = 127;				else if (samp < -128) samp = -128;				(*out_s8) = samp;				out_s8 += 1;				out_mix += 1;			}		}	}	nb_written *= am->nb_channels*am->bits_per_sample/8;	if (buffer_size > nb_written) 		memset((char *)buffer + nb_written, 0, sizeof(char)*(buffer_size-nb_written));	gf_mixer_lock(am, 0);	return nb_written;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -