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; }
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; }