Ejemplo n.º 1
0
bool SoundBuffer_Session_Impl::mix_to(float **sample_data, float **temp_data, int num_samples, int num_channels)
{
	MutexSection mutex_lock(&mutex);
	get_data_in_mixer_frequency(num_samples, temp_data);
	run_filters(temp_data, num_samples);
	mix_channels(num_channels, num_samples, sample_data, temp_data);
	return playing;
}
Ejemplo n.º 2
0
	unsigned long operator()(
		SampleSource &sample_source, InputProperties const &input_properties,
		void *output, unsigned long const num_output_samples, OutputProperties const &output_properties,
		unsigned int const volume, unsigned int const max_volume
	)
	{
		// prerequisites

		unsigned int num_input_channels = get_num_channels(input_properties);
		unsigned int num_output_channels = get_num_channels(output_properties);
		unsigned int input_frequency = get_frequency(input_properties);
		unsigned int output_frequency = get_frequency(output_properties);

		if (input_frequency == 0) // if the input frequency is 0, then the sample source can adapt to the output frequency
			input_frequency = output_frequency;

		bool frequencies_match = (input_frequency == output_frequency);
		bool num_channels_match = (num_input_channels == num_output_channels);
		bool sample_types_match = get_sample_type(input_properties) == get_sample_type(output_properties);


		// if the properties fully match, no processing is necessary - just transmit the samples directly to the output and exit
		// do a volume processing if necessary, but otherwise its just one transmission
		if (frequencies_match && sample_types_match && num_channels_match)
		{
			unsigned long num_retrieved_samples = retrieve_samples(sample_source, output, num_output_samples);

			if (volume != max_volume)
			{
				sample_type output_sample_type = get_sample_type(output_properties);
				for (unsigned long i = 0; i < num_retrieved_samples * num_output_channels; ++i)
				{
					set_sample_value(
						output, i,
						adjust_sample_volume(get_sample_value(output, i, output_sample_type), volume, max_volume),
						output_sample_type
					);
				}
			}

			return num_retrieved_samples;
		}


		unsigned long num_retrieved_samples = 0;
		uint8_t *resampler_input = 0;
		sample_type dest_type = sample_unknown;
		// note that this returns true if the resampler is in an uninitialized state
		bool resampler_needed_more_input = is_more_input_needed_for(resampler, num_output_samples);



		// first processing stage: convert samples & mix channels if necessary
		// also, the resampler input is prepared here
		// if resampling is necessary, and the resampler has enough input data for now, this stage is bypassed

		if (frequencies_match || resampler_needed_more_input)
		{
			// with the adjusted value from above, retrieve samples from the sample source, and resize the buffer to the number of actually retrieved samples
			// (since the sample source may have given us less samples than we requested)
			unsigned long num_samples_to_retrieve = num_output_samples;
			source_data_buffer.resize(num_samples_to_retrieve * num_input_channels * get_sample_size(get_sample_type(input_properties)));
			num_retrieved_samples = retrieve_samples(sample_source, &source_data_buffer[0], num_samples_to_retrieve);
			source_data_buffer.resize(num_retrieved_samples * num_input_channels * get_sample_size(get_sample_type(input_properties)));

			// here, the dest and dest_type values are set, as well as the resampler input (if necessary)
			// several optimizations are done here: if the resampler is not necessary, then dest points to the output - any conversion steps will write data directly to the output then
			// if the resampler is necessary, and the sample types match, then the resampler's input is the source data buffer, otherwise it is the "dest" pointer
			// the reason for this is: if the sample types match, no conversion step is necessary, and the resampler can pull data directly from the source data buffer;
			// otherwise, the conversion step needs to convert to an intermediate buffer (the buffer the dest pointer points at), and then the resampler pulls data from this buffer
			uint8_t *dest;
			if (frequencies_match)
			{
				// frequencies match - dest is set to point at the output, meaning that the next step will directly write to the output
				dest_type = get_sample_type(output_properties);
				dest = reinterpret_cast < uint8_t* > (output);
			}
			else
			{
				// frequencies do not match, resampling is necessary - dest is set to point at an intermediate buffer, which the resampler will use

				// ask the resampler what resampling input type it needs - this may differ from the output properties' sample type, but this is ok,
				// since with resampling, an intermediate step between sample type conversion & mixing and actual output is present anyway
				dest_type = find_compatible_type(resampler, get_sample_type(input_properties));

				if (sample_types_match && num_channels_match)
				{
					// if the sample types and channel count match, then no conversion step is necessary, and the resampler can pull data from the source data buffer directly
					resampler_input = &source_data_buffer[0];
					dest = 0;
				}
				else
				{
					// if the sample types and channel count do not match, then the resampler needs to pull data from the intermediate buffer dest points to
					// the conversion step will write to dest
					resampling_input_buffer.resize(num_output_samples * num_output_channels * get_sample_size(dest_type));
					dest = &resampling_input_buffer[0];
					resampler_input = dest;
				}
			}


			// actual mixing and conversion is done here
			if (num_channels_match)
			{
				// channel counts match, no mixing necessary

				if (!sample_types_match)
				{
					assert(dest != 0);

					// sample types do not match
					// go through all the input samples, convert them, and write them to dest
					for (unsigned long i = 0; i < num_retrieved_samples * num_input_channels; ++i)
					{
						set_sample_value(
							dest, i,
							convert_sample_value(
								get_sample_value(&source_data_buffer[0], i, get_sample_type(input_properties)),
								get_sample_type(input_properties), dest_type
							),
							dest_type
						);
					}
				}

				// if the sample types match, nothing needs to be done here
			}
			else
			{
				// channels count do not match - call the mixer
				mix_channels(&source_data_buffer[0], dest, num_retrieved_samples, get_sample_type(input_properties), dest_type, get_num_channels(input_properties), get_num_channels(output_properties));
			}
		}
		else
		{
			// either resampling is not necessary, or the resampler does not need any new input for now
			// set number of retrieved samples to number of output samples, and if resampling is necessary, set the dest_type value

			num_retrieved_samples = num_output_samples;

			// the dest_type value is set, since the resampler might reset itself if it sees a change in the input type
			if (!frequencies_match)
				dest_type = find_compatible_type(resampler, get_sample_type(input_properties));
		}


		// the final stage adjusts the output volume; if the volume equals the max volume, it is unnecessary
		// this boolean conditionally enables this stage
		bool do_volume_stage = (volume != max_volume);


		// second processing stage: resample if necessary (otherwise this stage is bypassed)
		if (!frequencies_match)
		{
			sample_type resampler_input_type = dest_type;

			// the resampler may have only support for a fixed number of sample types - let it choose a suitable output one
			sample_type resampler_output_type = find_compatible_type(resampler, resampler_input_type, get_sample_type(output_properties));
			sample_type output_type = get_sample_type(output_properties);
			bool conversion_needed = (resampler_output_type != output_type);

			uint8_t *resampler_output = reinterpret_cast < uint8_t* > (output);
			if (conversion_needed)
			{
				resampling_output_buffer.resize(num_output_samples * num_output_channels * get_sample_size(resampler_output_type));
				resampler_output = &resampling_output_buffer[0];
			}

			// resampler input -can- be zero - sometimes the resampler does not need any more input
			assert(!resampler_needed_more_input || (resampler_input != 0));

			// call the actual resampler, which returns the number of samples that were actually sent to output
			// if this is the first call since the resampler was reset(), this call internally initializes the resampler
			// and sets its internal values to the given ones
			// note that the is_more_input_needed_for() call returns true if the resampler is in such an uninitialized state
			// if the resampler was initialized already, it may reinitialize itself internally if certain parameters change
			// (this is entirely implementation-dependent; from the outside, no such reinitialization is noticeable)
			num_retrieved_samples = resample(
				resampler,
				resampler_input, num_retrieved_samples,
				resampler_output, num_output_samples,
				input_frequency, output_frequency,
				resampler_input_type, resampler_output_type,
				num_output_channels
			);

			// the output type chosen by the resampler may not match the output type given by the output properties, so a final conversion step may be necessary
			if (conversion_needed)
			{
				if (do_volume_stage)
				{
					// if the volume stage is required, use the opportunity to do it together with the final conversion step
					for (unsigned long i = 0; i < num_retrieved_samples * num_output_channels; ++i)
					{
						set_sample_value(
							output, i,
							adjust_sample_volume(
								get_sample_value(resampler_output, i, resampler_output_type),
								volume, max_volume
							),
							output_type
						);
					}

					// volume adjustment was done in-line in the conversion step above -> no further volume adjustment required
					do_volume_stage = false;
				}
				else
				{
					// conversion without volume adjustment
					for (unsigned long i = 0; i < num_retrieved_samples * num_output_channels; ++i)
						set_sample_value(output, i, get_sample_value(resampler_output, i, output_type), output_type);
				}
			}
		}


		// do the volume stage if required
		if (do_volume_stage)
		{
			sample_type output_sample_type = get_sample_type(output_properties);
			for (unsigned long i = 0; i < num_retrieved_samples * num_output_channels; ++i)
			{
				set_sample_value(
					output, i,
					adjust_sample_volume(get_sample_value(output, i, output_sample_type), volume, max_volume),
					output_sample_type
				);
			}
		}


		// finally, return the number of retrieved samples, either from the resampler, or from the source directly,
		// depending on whether or not resampling was necessary
		return num_retrieved_samples;
	}