void			WaveformViewDemo::GetWaveformOverview(WaveformOverview* data)
{	
	AudioBufferList *bufferList = &mFetchingBufferList->GetModifiableBufferList();
	UInt32 num = data->mNumDataPoints;
	SampleTime t = (SampleTime) data->mFetchStamp.mSampleTime;
	mAudioBuffer->Fetch(bufferList, num, t, false);	

	Float32* b = (Float32*) bufferList->mBuffers[data->mChannel].mData;
	memcpy(data->mOverview, b, num*sizeof(Float32));	
	
	vDSP_maxmgv(b, 1, &(data->mMax), num);
	vDSP_minmgv (b, 1,&(data->mMin), num);
  
	
#pragma warning we are pulling all the data but only need a certain channel
	data->mFetchStamp.mSampleTime += (Float64) num;	
}
Example #2
0
void vmaxmgv(const float* sourceP,
             int sourceStride,
             float* maxP,
             size_t framesToProcess) {
    vDSP_maxmgv(sourceP, sourceStride, maxP, framesToProcess);
}
bool SFB::Audio::ReplayGainAnalyzer::AnalyzeURL(CFURLRef url, CFErrorRef *error)
{
	if(nullptr == url)
		return false;

	auto decoder = Decoder::CreateDecoderForURL(url, error);
	if(!decoder || !decoder->Open(error))
		return false;
	
	AudioStreamBasicDescription inputFormat = decoder->GetFormat();

	// Higher sampling rates aren't natively supported but are handled via resampling
	int32_t decoderSampleRate = (int32_t)inputFormat.mSampleRate;

	bool validSampleRate = EvenMultipleSampleRateIsSupported(decoderSampleRate);
	if(!validSampleRate) {
		if(error) {
			SFB::CFString description = CFCopyLocalizedString(CFSTR("The file “%@” does not contain audio at a supported sample rate."), "");
			SFB::CFString failureReason = CFCopyLocalizedString(CFSTR("Only sample rates of 8.0 KHz, 11.025 KHz, 12.0 KHz, 16.0 KHz, 22.05 KHz, 24.0 KHz, 32.0 KHz, 44.1 KHz, 48 KHz and multiples are supported."), "");
			SFB::CFString recoverySuggestion = CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "");

			*error = CreateErrorForURL(ReplayGainAnalyzer::ErrorDomain, ReplayGainAnalyzer::FileFormatNotSupportedError, description, url, failureReason, recoverySuggestion);
		}

		return false;
	}

	Float64 replayGainSampleRate = GetBestReplayGainSampleRateForSampleRate(decoderSampleRate);

	if(!(1 == inputFormat.mChannelsPerFrame || 2 == inputFormat.mChannelsPerFrame)) {
		if(error) {
			SFB::CFString description = CFCopyLocalizedString(CFSTR("The file “%@” does not contain mono or stereo audio."), "");
			SFB::CFString failureReason = CFCopyLocalizedString(CFSTR("Only mono or stereo files supported"), "");
			SFB::CFString recoverySuggestion = CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "");

			*error = CreateErrorForURL(ReplayGainAnalyzer::ErrorDomain, ReplayGainAnalyzer::FileFormatNotSupportedError, description, url, failureReason, recoverySuggestion);
		}

		return false;
	}

	AudioStreamBasicDescription outputFormat = {
		.mFormatID				= kAudioFormatLinearPCM,
		.mFormatFlags			= kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved,
		.mReserved				= 0,
		.mSampleRate			= replayGainSampleRate,
		.mChannelsPerFrame		= inputFormat.mChannelsPerFrame,
		.mBitsPerChannel		= 32,
		.mBytesPerPacket		= 4,
		.mBytesPerFrame			= 4,
		.mFramesPerPacket		= 1
	};
	
	if(!SetSampleRate((int32_t)outputFormat.mSampleRate)) {
		if(error) {
			SFB::CFString description = CFCopyLocalizedString(CFSTR("The file “%@” does not contain audio at a supported sample rate."), "");
			SFB::CFString failureReason = CFCopyLocalizedString(CFSTR("Only sample rates of 8.0 KHz, 11.025 KHz, 12.0 KHz, 16.0 KHz, 22.05 KHz, 24.0 KHz, 32.0 KHz, 44.1 KHz, 48 KHz and multiples are supported."), "");
			SFB::CFString recoverySuggestion = CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "");

			*error = CreateErrorForURL(ReplayGainAnalyzer::ErrorDomain, ReplayGainAnalyzer::FileFormatNotSupportedError, description, url, failureReason, recoverySuggestion);
		}

		return false;
	}

	// Converter takes ownership of decoder
	Converter converter(std::move(decoder), outputFormat);
	if(!converter.Open(error))
		return false;
	
	const UInt32 bufferSizeFrames = 512;
	BufferList outputBuffer(outputFormat, bufferSizeFrames);

	bool isStereo = (2 == outputFormat.mChannelsPerFrame);

	for(;;) {
		UInt32 frameCount = converter.ConvertAudio(outputBuffer, bufferSizeFrames);
		if(0 == frameCount)
			break;

		// Find the peak sample magnitude
		float lpeak, rpeak;
		vDSP_maxmgv((const float *)outputBuffer->mBuffers[0].mData, 1, &lpeak, frameCount);
		if(isStereo) {
			vDSP_maxmgv((const float *)outputBuffer->mBuffers[1].mData, 1, &rpeak, frameCount);
			priv->trackPeak = std::max(priv->trackPeak, std::max(lpeak, rpeak));
		}
		else
			priv->trackPeak = std::max(priv->trackPeak, lpeak);

		// The replay gain analyzer expects 16-bit sample size passed as floats
		const float scale = 1u << 15;
		vDSP_vsmul((const float *)outputBuffer->mBuffers[0].mData, 1, &scale, (float *)outputBuffer->mBuffers[0].mData, 1, frameCount);
		if(isStereo) {
			vDSP_vsmul((const float *)outputBuffer->mBuffers[1].mData, 1, &scale, (float *)outputBuffer->mBuffers[1].mData, 1, frameCount);
			AnalyzeSamples((const float *)outputBuffer->mBuffers[0].mData, (const float *)outputBuffer->mBuffers[1].mData, frameCount, true);
		}
		else
			AnalyzeSamples((const float *)outputBuffer->mBuffers[0].mData, nullptr, frameCount, false);
	}

	priv->albumPeak = std::max(priv->albumPeak, priv->trackPeak);

	return true;
}

bool SFB::Audio::ReplayGainAnalyzer::GetTrackGain(float& trackGain)
{
	if(!analyzeResult(priv->A, sizeof(priv->A) / sizeof(*(priv->A)), trackGain))
		return false;

	for(uint32_t i = 0; i < sizeof(priv->A) / sizeof(*(priv->A)); ++i) {
		priv->B[i] += priv->A[i];
		priv->A[i]  = 0;
	}

	priv->Zero();

	priv->totsamp	= 0;
	priv->lsum		= priv->rsum = 0.;

	return true;
}

bool SFB::Audio::ReplayGainAnalyzer::GetTrackPeak(float& trackPeak)
{
	trackPeak = priv->trackPeak;
	priv->trackPeak = 0.;
	return true;
}