How should I use AudioFileStreamOpen Xcode 12 - ios

I have a parser class to play Audio Files, It works on Xcode 11 (swift 4.2), Recently updated to Xcode 12 only this part of code is not working(swift 4.2).
Image
Error:
Cannot convert value of type '(UnsafeMutableRawPointer, UInt32, UInt32, UnsafeRawPointer, UnsafeMutablePointer<AudioStreamPacketDescription>) -> ()' to expected argument type 'AudioFileStream_PacketsProc' (aka '#convention(c) (UnsafeMutableRawPointer, UInt32, UInt32, UnsafeRawPointer, Optional<UnsafeMutablePointer<AudioStreamPacketDescription>>) -> ()')
This the method :
func ParserPacketCallback(_ context: UnsafeMutableRawPointer, _ byteCount: UInt32, _ packetCount: UInt32, _ data: UnsafeRawPointer, _ packetDescriptions: UnsafeMutablePointer<AudioStreamPacketDescription>) {
let parser = Unmanaged<Parser>.fromOpaque(context).takeUnretainedValue()
let packetDescriptionsOrNil: UnsafeMutablePointer<AudioStreamPacketDescription>? = packetDescriptions
let isCompressed = packetDescriptionsOrNil != nil
/// At this point we should definitely have a data format
guard let dataFormat = parser.dataFormat else {
return
}
/// Iterate through the packets and store the data appropriately
if isCompressed {
for i in 0 ..< Int(packetCount) {
let packetDescription = packetDescriptions[i]
let packetStart = Int(packetDescription.mStartOffset)
let packetSize = Int(packetDescription.mDataByteSize)
let packetData = Data(bytes: data.advanced(by: packetStart), count: packetSize)
parser.packets.append((packetData, packetDescription))
}
} else {
let format = dataFormat.streamDescription.pointee
let bytesPerPacket = Int(format.mBytesPerPacket)
for i in 0 ..< Int(packetCount) {
let packetStart = i * bytesPerPacket
let packetSize = bytesPerPacket
let packetData = Data(bytes: data.advanced(by: packetStart), count: packetSize)
parser.packets.append((packetData, nil))
}
}}
May you please help me to solve it?)
Thanks.

You should change packetDescriptions to Optional<UnsafeMutablePointer<AudioStreamPacketDescription>> type. This work for me

Related

Converting bytes to floats in Swift when receiving bluetooth communications [duplicate]

This is my code to convert byte data to float. I tried every answers given in this site. I am getting exponential value for this "<44fa0000>" byte data
static func returnFloatValue(mutableData:NSMutableData)->Float
{
let qtyRange = mutableData.subdataWithRange(NSMakeRange(0, 4))
let qtyString = String(qtyRange)
let qtyTrimString = qtyString.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "<>"))
let qtyValue = Float(strtoul(qtyTrimString, nil, 16)/10)
return qtyValue
}
Thanks
<44fa0000> is the big-endian memory representation of the
binary floating point number 2000.0. To get the number back from
the data, you have to read it into an UInt32 first, convert from
big-endian to host byteorder, and then cast the result to
a Float.
In Swift 2 that would be
func floatValueFromData(data: NSData) -> Float {
return unsafeBitCast(UInt32(bigEndian: UnsafePointer(data.bytes).memory), Float.self)
}
Example:
let bytes: [UInt8] = [0x44, 0xFA, 0x00, 0x00]
let data = NSData(bytes: bytes, length: 4)
print(data) // <44fa0000>
let f = floatValueFromData(data)
print(f) // 2000.0
In Swift 3 you would use Data instead of NSData, and the
unsafeBitCast can be replaced by the Float(bitPattern:)
initializer:
func floatValue(data: Data) -> Float {
return Float(bitPattern: UInt32(bigEndian: data.withUnsafeBytes { $0.pointee } ))
}
In Swift 5 the withUnsafeBytes() method of Data calls the closure with an (untyped) UnsafeRawBufferPointer, and you can load() the value from the raw memory:
func floatValue(data: Data) -> Float {
return Float(bitPattern: UInt32(bigEndian: data.withUnsafeBytes { $0.load(as: UInt32.self) }))
}
Here is some swift 5:
let data = Data([0x44, 0xfa, 0x00, 0x00]) // 0x44fa0000
let floatNb:Float = data.withUnsafeBytes { $0.load(as: Float.self) }
// note that depending on the input endianess, you could add .reversed() to data
let floatNb:Float = data.reversed().withUnsafeBytes { $0.load(as: Float.self) }
WARNING: this sample throws if your Data is under 4 bytes..
.
Safe Data extension:
extension Data {
enum Endianess {
case little
case big
}
func toFloat(endianess: Endianess = .little) -> Float? {
guard self.count <= 4 else { return nil }
switch endianess {
case .big:
let data = [UInt8](repeating: 0x00, count: 4-self.count) + self
return data.withUnsafeBytes { $0.load(as: Float.self) }
case .little:
let data = self + [UInt8](repeating: 0x00, count: 4-self.count)
return data.reversed().withUnsafeBytes { $0.load(as: Float.self) }
}
}
}
Tests:
let opData = Data([0x44, 0xFA, 0x00, 0x00])
let nb42 = Data([0x42, 0x28])
let nb42bigEndian = Data([0x28, 0x42])
let tooBig = Data([0x44, 0xFA, 0x00, 0x00, 0x00])
print("opData: \(opData.toFloat())")
print("nb42: \(nb42.toFloat())")
print("nb42bigEndian: \(nb42bigEndian.toFloat(endianess: .big))")
print("tooBig: \(tooBig.toFloat())")
you may find a faster way but this was good enough for my needs
Use this function:
static func returnFloatValue(data: NSMutableData) -> Float {
let bytes = [UInt8](data as Data)
var f: Float = 0
memcpy(&f, bytes, 4)
return f
}
And you can see it in action here:
var initialValue: Float = 19.200
let data = NSMutableData(bytes: &initialValue, length: 4)
func returnFloatValue(data: NSMutableData) -> Float {
let bytes = [UInt8](data as Data)
var f: Float = 0
memcpy(&f, bytes, 4)
return f
}
var result:Float = returnFloatValue(data: data)
print("f=\(result)")// f=19.2
For 64 bit values the code is:
static func longBitsToDouble(x : Int64) -> Float64
{ return Float64(bitPattern: UInt64(x)) }
Swift 4+.

How to convert data into little endian format?

var val = 1240;
convert into little endian formate swift 3
Ex: 1500 (0x5DC) to 0xDC050000
let value = UInt16(bigEndian: 1500)
print(String(format:"%04X", value.bigEndian)) //05DC
print(String(format:"%04X", value.littleEndian)) //DC05
Make sure you are actually using the bigEndian initializer.
With 32-bit integers:
let value = UInt32(bigEndian: 1500)
print(String(format:"%08X", value.bigEndian)) //000005DC
print(String(format:"%08X", value.littleEndian)) //DC050000
If you want 1500 as an array of bytes in little-endian order:
var value = UInt32(littleEndian: 1500)
let array = withUnsafeBytes(of: &value) { Array($0) }
If you want that as a Data:
let data = Data(array)
Or, if you really wanted that as a hex string:
let string = array.map { String(format: "%02x", $0) }.joined()
let timeDevide = self.setmiliSecond/100
var newTime = UInt32(littleEndian: timeDevide)
let arrayTime = withUnsafeBytes(of: &newTime)
{Array($0)}
let timeDelayValue = [0x0B] + arrayTime
You can do something like
//: Playground - noun: a place where people can play
import UIKit
extension String {
func hexadecimal() -> Data? {
var data = Data(capacity: count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, range: NSRange(location: 0, length: utf16.count)) { match, _, _ in
let byteString = (self as NSString).substring(with: match!.range)
var num = UInt8(byteString, radix: 16)!
data.append(&num, count: 1)
}
guard !data.isEmpty else { return nil }
return data
}
}
func convertInputValue<T: FixedWidthInteger>(_ inputValue: Data) -> T where T: CVarArg {
let stride = MemoryLayout<T>.stride
assert(inputValue.count % (stride / 2) == 0, "invalid pack size")
let fwInt = T.init(littleEndian: inputValue.withUnsafeBytes { $0.pointee })
let valuefwInt = String(format: "%0\(stride)x", fwInt).capitalized
print(valuefwInt)
return fwInt
}
var inputString = "479F"
var inputValue: Data! = inputString.hexadecimal()
let val: UInt16 = convertInputValue(inputValue) //9F47
inputString = "479F8253"
inputValue = inputString.hexadecimal()
let val2: UInt32 = convertInputValue(inputValue) //53829F47

Swift 2 NOT bitwise operation does not behave as expected

I am trying to flip all of the bits of a number in Swift using the bitwise NOT operator ~
func binary(int: Int) -> String {
return String(int, radix: 2)
}
let num = 0b11110000
binary(num) //prints "11110000"
let notNum = ~num
binary(notNum) //prints "-11110001"
It is my understanding that notNum should print out 00001111 (docs) but instead it prints -11110001. What's going on here?
It's not a matter of bitwise operator, but a matter of behavior of the String initializer.
There are 2 init(_:radix:uppercase:) initializer in String
public init<T : _SignedIntegerType>(_ v: T, radix: Int, uppercase: Bool = default)
public init<T : UnsignedIntegerType>(_ v: T, radix: Int, uppercase: Bool = default)
To get a expected result, you have to use UnsignedIntegerType one:
let num:UInt = 0b11110000
let notNum = ~num
String(notNum, radix: 2)
// -> "1111111111111111111111111111111111111111111111111111111100001111"
OR:
let num = 0b11110000
let notNum = ~num
String(UInt(bitPattern: notNum), radix: 2)
// -> "1111111111111111111111111111111111111111111111111111111100001111"
Thats because you are using Int instead of UInt8:
Try like this:
func binary(uint8: UInt8) -> String {
return String(uint8, radix: 2)
}
let num:UInt8 = 0b11110000
binary(num) //prints "11110000"
let notNum = ~num
binary(notNum) //prints "1111"

Convert an Objective-C method into Swift for NSInputStream (convert bytes into double)

I have the following code in Objective-C:
- (double)readDouble
{
double value = 0.0;
if ([self read:(uint8_t *)&value maxLength:8] != 8)
{
NSLog(#"***** Couldn't read double");
}
return value;
}
It works. But I don't know how to convert it to Swift. Here is my code:
public func readDouble() -> Double {
var value : Double = 0.0
var num = self.read((uint8_t *)&value, maxLength:8) // got compiling error here!
if num != 8 {
}
}
The error message is:
Cannot invoke '&' with an argument list of type '($T4, maxLength:
IntegerLiteralConvertible)'
Can anybody help? Thanks
The testing data I'm using (1.25):
14 AE 47 E1 7A 14 F4 3F
UPDATE:
A simple c solution, but how to do this in Swift?
double d = 0;
unsigned char buf[sizeof d] = {0};
memcpy(&d, buf, sizeof d);
This should work:
let num = withUnsafeMutablePointer(&value) {
self.read(UnsafeMutablePointer($0), maxLength: sizeofValue(value))
}
Explanation: withUnsafeMutablePointer() calls the closure (block) with the only argument
($0 in shorthand notation) set to the address of value.
$0 has the type UnsafeMutablePointer<Double> and read() expects an
UnsafeMutablePointer<UInt8> as the first argument, therefore another conversion
is necessary. The return value of the closure is then assigned to num.
The method above does not work for me, using Swift 2 but I discovered a much more simpler method to do this conversion and vice versa:
func binarytotype <T> (value: [UInt8], _: T.Type) -> T
{
return value.withUnsafeBufferPointer
{
return UnsafePointer<T>($0.baseAddress).memory
}
}
func typetobinary <T> (var value: T) -> [UInt8]
{
return withUnsafePointer(&value)
{
Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>($0), count: sizeof(T)))
}
}
let a: Double = 0.25
let b: [UInt8] = typetobinary(a) // -> [0, 0, 0, 0, 0, 0, 208, 63]
let c = binarytotype(b, Double.self) // -> 0.25
I have tested it with Xcode 7.2 in the playground.
Here is the updated version for Swift 3 beta 6 which is different, thanx to Martin.
func binarytotype <T> (_ value: [UInt8], _ : T.Type) -> T
{
return value.withUnsafeBufferPointer
{
UnsafeRawPointer($0.baseAddress!).load(as: T.self)
}
}
func typetobinary <T> (_ value: T) -> [UInt8]
{
var v = value
let size = MemoryLayout<T>.size
return withUnsafePointer(to: &v)
{
$0.withMemoryRebound(to: UInt8.self, capacity: size)
{
Array(UnsafeBufferPointer(start: $0, count: size))
}
}
}
let dd: Double = 1.23456 // -> 1.23456
let d = typetobinary(dd) // -> [56, 50, 143, 252, 193, 192, 243, 63]
let i = binarytotype(d, Double.self) // -> 1.23456

AudioFileReadBytes from a memory block, not a file

I'd like to cache CAF files before converting them to PCM whenever they play.
For example,
char *mybuffer = malloc(mysoundsize);
FILE *f = fopen("mysound.caf", "rb");
fread(mybuffer, mysoundsize, 1, f);
fclose(f);
char *pcmBuffer = malloc(pcmsoundsize);
// Convert to PCM for playing
AudioFileReadBytes(mybuffer, false, 0, mysoundsize, &numbytes, pcmBuffer);
This way, whenever the sound plays, the compressed CAF file is already loaded into memory, avoiding disk access. How can I open a block of memory with an 'AudioFileID' to make AudioFileReadBytes happy? Is there another method I can use?
I have not done it myself, but from the documentation I would think that you have to use AudioFileOpenWithCallbacks and implement callback functions that read from your memory buffer.
You can finish it with AudioFileStreamOpen
fileprivate var streamID: AudioFileStreamID?
public func parse(data: Data) throws {
let streamID = self.streamID!
let count = data.count
_ = try data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
let result = AudioFileStreamParseBytes(streamID, UInt32(count), bytes, [])
guard result == noErr else {
throw ParserError.failedToParseBytes(result)
}
}
}
you can store the data in memory within the callback
func ParserPacketCallback(_ context: UnsafeMutableRawPointer, _ byteCount: UInt32, _ packetCount: UInt32, _ data: UnsafeRawPointer, _ packetDescriptions: Optional<UnsafeMutablePointer<AudioStreamPacketDescription>>) {
let parser = Unmanaged<Parser>.fromOpaque(context).takeUnretainedValue()
/// At this point we should definitely have a data format
guard let dataFormat = parser.dataFormatD else {
return
}
let format = dataFormat.streamDescription.pointee
let bytesPerPacket = Int(format.mBytesPerPacket)
for i in 0 ..< Int(packetCount) {
let packetStart = i * bytesPerPacket
let packetSize = bytesPerPacket
let packetData = Data(bytes: data.advanced(by: packetStart), count: packetSize)
parser.packetsX.append(packetData)
}
}
full code in github repo

Resources