//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	RadioEffectUnit::RadioEffectUnit
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RadioEffectUnit::RadioEffectUnit(AudioUnit Component)
	: AUEffectBase(Component)
{
	CreateElements();

	if (!bGLocalized) {		
		// Because we are in a component, we need to load our bundle by identifier so we can access our localized strings
		// It is important that the string passed here exactly matches that in the Info.plist Identifier string
		CFBundleRef bundle = CFBundleGetBundleWithIdentifier( CFSTR("com.epicgames.audiounit.radio") );
		
		if (bundle != NULL) {
			kChebyshevPowerMultiplierName = CFCopyLocalizedStringFromTableInBundle(kChebyshevPowerMultiplierName, CFSTR("Localizable"), bundle, CFSTR(""));
			kChebyshevPowerName = CFCopyLocalizedStringFromTableInBundle(kChebyshevPowerName, CFSTR("Localizable"), bundle, CFSTR(""));
			kChebyshevMultiplierName = CFCopyLocalizedStringFromTableInBundle(kChebyshevMultiplierName, CFSTR("Localizable"), bundle, CFSTR(""));	
			kChebyshevCubedMultiplierName = CFCopyLocalizedStringFromTableInBundle(kChebyshevCubedMultiplierName, CFSTR("Localizable"), bundle, CFSTR(""));	
		}
		bGLocalized = TRUE; //so never pass the test again...
	}

	GFinalBandPassFilter.Initialize( 2000.0f, 400.0f, GetSampleRate() );

	SetParameter(RadioParam_ChebyshevPowerMultiplier, 	kDefaultValue_ChebyshevPowerMultiplier );
	SetParameter(RadioParam_ChebyshevPower, 			kDefaultValue_ChebyshevPower );
	SetParameter(RadioParam_ChebyshevMultiplier, 		kDefaultValue_ChebyshevMultiplier );
	SetParameter(RadioParam_ChebyshevCubedMultiplier,	kDefaultValue_ChebyshevCubedMultiplier );
}
Esempio n. 2
0
	/**
	 * Constructor. 
	 *
	 * @param	InitialSampleRate	The sample rate to process the audio.
	 */
	FXAudio2RadioEffect( float InitialSampleRate )
		:	CXAPOParametersBase( &Registration, ( uint8* )Parameters, sizeof( FAudioRadioEffect ), false )
		,	SampleRate( InitialSampleRate )
	{
		// Initialize the global audio processing helper classes
		GFinalBandPassFilter.Initialize( 2000.0f, 400.0f, SampleRate );

		// Setup default values for the parameters to initialize the rest of the global 
		// audio processing helper classes. See FXAudio2RadioEffect::OnSetParameters().
		FAudioRadioEffect DefaultParameters;
		SetParameters( &DefaultParameters, sizeof( DefaultParameters ) );
	}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	RadioEffectUnit::RadioEffectKernel::Process
//
//		pass-through unit
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void RadioEffectUnit::RadioEffectKernel::Process(	const AudioUnitSampleType *		InSourceP,
                                                    AudioUnitSampleType *			InDestP,
                                                    UInt32							InFramesToProcess,
                                                    UInt32							InNumChannels,
                                                    bool &							IOSilence )
{
// we should be doing something with the silence flag if it is true
// like not doing any work because:
// (1) we would only be processing silence and
// (2) we don't have any latency or tail times to worry about here
//
// So, we don't reset this flag, because it is true on input and we're not doing anything
// to it so we want it to be true on output.


// BUT: your code probably will need to take into account tail processing (or latency) that 
// it has once its input becomes silent... then at some point in the future, your output
// will also be silent.
    
	
	UInt32 NumSampleFrames = InFramesToProcess;
	const AudioUnitSampleType *SourceP = InSourceP;
	AudioUnitSampleType *DestP = InDestP;

	const FLOAT ChebyshevPowerMultiplier = GetParameter(RadioParam_ChebyshevPowerMultiplier);
	const FLOAT ChebyshevPower = GetParameter(RadioParam_ChebyshevPower);
	const FLOAT ChebyshevCubedMultiplier = GetParameter(RadioParam_ChebyshevCubedMultiplier);
	const FLOAT ChebyshevMultiplier = GetParameter(RadioParam_ChebyshevMultiplier);

	while (NumSampleFrames-- > 0) {
		AudioUnitSampleType InputSample = *SourceP;
		SourceP += InNumChannels;	// advance to next frame (e.g. if stereo, we're advancing 2 samples);
									// we're only processing one of an arbitrary number of interleaved channels

			// here's where you do your DSP work

		// Early-out of processing if the sample is zero because a zero sample 
		// will still create some static even if no audio is playing.
		if( InputSample != 0.0f ) {
			// Waveshape it
			const FLOAT SampleCubed = InputSample * InputSample * InputSample;
			InputSample = ( ChebyshevPowerMultiplier * appPow( InputSample, ChebyshevPower ) ) - ( ChebyshevCubedMultiplier * SampleCubed ) + ( ChebyshevMultiplier * InputSample );
			
			// Again with the bandpass
			InputSample = GFinalBandPassFilter.Process( InputSample );
		}
		
		*DestP = InputSample;
		DestP += InNumChannels;
	}
}
Esempio n. 4
0
	/**
	 * Adds a radio distortion to the input buffer if the radio effect is enabled. 
	 *
	 * @param	InputProcessParameterCount	Number of elements in pInputProcessParameters.
	 * @param	pInputProcessParameters		Input buffer containing audio samples. 
	 * @param	OutputProcessParameterCount	Number of elements in pOutputProcessParameters. 
	 * @param	pOutputProcessParameters	Output buffer, which is not touched by this xAPO. 
	 * @param	IsEnabled					true if this effect is enabled; false, otherwise. 
	 */
	STDMETHOD_( void, Process )(	UINT32 InputProcessParameterCount,
									const XAPO_PROCESS_BUFFER_PARAMETERS *pInputProcessParameters,
									UINT32 OutputProcessParameterCount,
									XAPO_PROCESS_BUFFER_PARAMETERS *pOutputProcessParameters,
									BOOL IsEnabled )
	{
		// Verify several condition based on the registration 
		// properties we used to create the class. 
		check( IsLocked() );
		check( InputProcessParameterCount == 1 );
		check( OutputProcessParameterCount == 1 );
		check( pInputProcessParameters[0].pBuffer == pOutputProcessParameters[0].pBuffer );

		// Check the global volume multiplier because this effect 
		// will continue to play if the editor loses focus.
		if (IsEnabled && FApp::GetVolumeMultiplier() != 0.0f)
		{
			FAudioRadioEffect* RadioParameters = ( FAudioRadioEffect* )BeginProcess();
			check( RadioParameters );

			// The total sample size must account for multiple channels. 
			const uint32 SampleSize = pInputProcessParameters[0].ValidFrameCount * WaveFormat.nChannels;

			const float ChebyshevPowerMultiplier = Radio_ChebyshevPowerMultiplier->GetValueOnAnyThread();
			const float ChebyshevPower = Radio_ChebyshevPower->GetValueOnAnyThread();
			const float ChebyshevCubedMultiplier = Radio_ChebyshevCubedMultiplier->GetValueOnAnyThread();
			const float ChebyshevMultiplier = Radio_ChebyshevMultiplier->GetValueOnAnyThread();

			// If we have a silent buffer, then allocate the samples. Then, set the sample values 
			// to zero to avoid getting NANs. Otherwise, the user may hear an annoying popping noise.
			if( pInputProcessParameters[0].BufferFlags == XAPO_BUFFER_VALID )
			{
				float* SampleData = ( float* )pInputProcessParameters[0].pBuffer;

				// Process each sample one at a time
				for( uint32 SampleIndex = 0; SampleIndex < SampleSize; ++SampleIndex )
				{
					float Sample = SampleData[SampleIndex];

					// Early-out of processing if the sample is zero because a zero sample 
					// will still create some static even if no audio is playing.
					if( Sample == 0.0f )
					{
						continue;
					}

					// Waveshape it
					const float SampleCubed = Sample * Sample * Sample;
					Sample = ( ChebyshevPowerMultiplier * FMath::Pow( Sample, ChebyshevPower ) ) - ( ChebyshevCubedMultiplier * SampleCubed ) + ( ChebyshevMultiplier * Sample );

					// Again with the bandpass
					Sample = GFinalBandPassFilter.Process( Sample );

					// Store the value after done processing
					SampleData[SampleIndex] = Sample;
				}

				EndProcess();
			}
		}
	}