In my iOS application, using swift
i am getting audio from digital health device (BLE). In the form of audio data, to hear heart beats.
- We have ADPCM decoded file. That we have decoded using ADPCM decoder.
We want to remove the background noise from it.
2. For that, we apply low pass filter and high pass filter using apple's DSP code. We are getting float samples, after after filtering.
So, first question is Conversion of Data to float is correct ?
let samples = convertUInt8ToFloats(sampleData: audioData)
let samples1 = musicProvider.loadAudioSamples(samples: samples)
func convertUInt8ToFloats(sampleData: Data) -> [Float] {
let factor = Float(UInt8.max)
let samples = sampleData.withUnsafeBytes {
UnsafeBufferPointer<UInt8>(start: $0, count: sampleData.count / MemoryLayout<UInt8>.size)
}
var floats: [Float] = Array(repeating: 0.0, count: samples.count)
for i in 0..<samples.count {
floats[i] = Float(samples[i]) / factor
}
return floats
}
In Apple's sample code they are loading assets like this, But i can not load assets like this, as i have raw audio file, is above convertUInt8ToFloats conversion same as below ?
let asset = AVAsset(url: path.absoluteURL)
let reader = try AVAssetReader(asset: asset)
guard let track = try await asset.load(.tracks).first else {
return nil
}
let outputSettings: [String: Int] = [
AVFormatIDKey: Int(kAudioFormatLinearPCM),
AVNumberOfChannelsKey: 1,
AVLinearPCMIsBigEndianKey: 0,
AVLinearPCMIsFloatKey: 1,
AVLinearPCMBitDepthKey: 32,
AVLinearPCMIsNonInterleaved: 1
]
let output = AVAssetReaderTrackOutput(track: track,
outputSettings: outputSettings)
reader.add(output)
reader.startReading()
var samplesData = [Float]()
while reader.status == .reading {
if
let sampleBuffer = output.copyNextSampleBuffer(),
let dataBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
let bufferLength = CMBlockBufferGetDataLength(dataBuffer)
let count = bufferLength / 4
let data = [Float](unsafeUninitializedCapacity: count) {
buffer, initializedCount in
CMBlockBufferCopyDataBytes(dataBuffer,
atOffset: 0,
dataLength: bufferLength,
destination: buffer.baseAddress!)
initializedCount = count
}
samplesData.append(contentsOf: data)
}
}
This is all the information needed. You need to convert Data to SInt16 (i.e. s16le), and then SInt16 to Float.
Using the Apple sample code, this would be:
You can then apply filters as in Apple's sample code.
To reverse the process, multiply rather than divide. You'll want to operate in the Int space and clamp to avoid crashing in cases where your algorithm might stray slightly outside the strict [-1, 1] range (which sometimes happens).
If your algorithm may emit outrageous values outside the range of Int, or infinity or NaN, you can do some more work to deal with those values and avoid crashing, but this is going to create noise in your output, and you should really just make sure the input is normalized before converting.
Here's an example of a way to make it safe from crashes, however, if you want it: