kAudioUnitType_MusicEffect as AVAudioUnit - midi

I'd like to use my kAudioUnitType_MusicEffect AU in an AVAudioEngine graph. So I try to call:
[AVAudioUnitMIDIInstrument instantiateWithComponentDescription:desc options:kAudioComponentInstantiation_LoadInProcess completionHandler:
but that just yeilds a normal AVAudioUnit, so the midi selectors (like -[AVAudioUnit sendMIDIEvent:data1:data2:]:) are unrecognized. It seems AVAudioUnitMIDIInstrument instantiateWithComponentDescription only works with kAudioUnitType_MusicDevice.
Any way to do this? (Note: OS X 10.11)

Make a subclass and call instantiateWithComponentDescription from its init.
Gory details and github project in this blog post
http://www.rockhoppertech.com/blog/multi-timbral-avaudiounitmidiinstrument/#avfoundation
This uses Swift and kAudioUnitSubType_MIDISynth but you can see how to do it.

This works. It's a subclass. You add it to the engine and you route the signal through it.
class MyAVAudioUnitDistortionEffect: AVAudioUnitEffect {
override init() {
var description = AudioComponentDescription()
description.componentType = kAudioUnitType_Effect
description.componentSubType = kAudioUnitSubType_Distortion
description.componentManufacturer = kAudioUnitManufacturer_Apple
description.componentFlags = 0
description.componentFlagsMask = 0
super.init(audioComponentDescription: description)
}
func setFinalMix(finalMix:Float) {
let status = AudioUnitSetParameter(
self.audioUnit,
AudioUnitPropertyID(kDistortionParam_FinalMix),
AudioUnitScope(kAudioUnitScope_Global),
0,
finalMix,
0)
if status != noErr {
print("error \(status)")
}
}

Related

open(FileManager.default.fileSystemRepresentation(withPath: path), O_EVTONLY) returns -1

I am using SKQueue to monitor some folders in the mac filesystem. As per the documentation, I have added the directory paths to the queues but I noticed that while adding the path, the following line of code in SKQueue is returning -1 and hence it is unable to monitor my folder.
This is the SKQueue Documentation.
The following is code from the documentation, written in the controller class.
import SKQueue
class SomeClass: SKQueueDelegate {
func receivedNotification(_ notification: SKQueueNotification, path: String, queue: SKQueue) {
print("\(notification.toStrings().map { $0.rawValue }) # \(path)")
}
}
let delegate = SomeClass()
let queue = SKQueue(delegate: delegate)!
queue.addPath("/Users/steve/Documents")
queue.addPath("/Users/steve/Documents/dog.jpg")
The following is code inside SKQueue dependency.
public func addPath(_ path: String, notifyingAbout notification: SKQueueNotification = SKQueueNotification.Default) {
var fileDescriptor: Int32! = watchedPaths[path]
if fileDescriptor == nil {
fileDescriptor = open(FileManager.default.fileSystemRepresentation(withPath: path), O_EVTONLY)
guard fileDescriptor >= 0 else { return }
watchedPaths[path] = fileDescriptor
}
fileDescriptor =
open(FileManager.default.fileSystemRepresentation(withPath: path),
O_EVTONLY)
The above code is returning -1 and hence it is failing.
I was getting the same -1 return code and couldn't understand why. Whilst looking for a solution I stumbled upon SwiftFolderMonitor at https://github.com/MartinJNash/SwiftFolderMonitor. This class worked so I knew it wasn't a permission problem.
SwiftFolderMonitor uses DispatchSource.makeFileSystemObjectSource rather than kevent, but it also takes a URL parameter rather than a String path. I amended SKQueue to take a URL instead of a String and it works.
Here's my amended addPath:
public func addPath(url: URL, notifyingAbout notification: SKQueueNotification = SKQueueNotification.Default) {
let path = url.absoluteString
var fileDescriptor: Int32! = watchedPaths[path]
if fileDescriptor == nil {
fileDescriptor = open((url as NSURL).fileSystemRepresentation, O_EVTONLY)
guard fileDescriptor >= 0 else { return }
watchedPaths[path] = fileDescriptor
}
var edit = kevent(
ident: UInt(fileDescriptor),
filter: Int16(EVFILT_VNODE),
flags: UInt16(EV_ADD | EV_CLEAR),
fflags: notification.rawValue,
data: 0,
udata: nil
)
kevent(kqueueId, &edit, 1, nil, 0, nil)
if !keepWatcherThreadRunning {
keepWatcherThreadRunning = true
DispatchQueue.global().async(execute: watcherThread)
}
}
I don't know why this works, perhaps someone else can shed some light on this.
I'm still playing with both solutions but it looks like SwiftFolderMonitor does all I need (I just need to know when a specific file has changed) and it's code is clean and minimal so I think I'll use it over SKQueue.
I hope this helps.
The call to open() failed, likely due to insufficient permissions. Since macOS 10.15, apps can't access certain files and folders without permission (the user's home directory, for example). Read more here.

Swift - How to wait for something without making the app hanging

I have a code like this:
print("Migration Execution: Successfully uninstalled MCAfee")
migrationInfoPicture.image = NSImage(named: "Unroll")
migrationInfoText.stringValue = NSLocalizedString("Unrolling from old server... Please wait!", comment: "Unrolling")
while(!readFile(path:logfilePath)!.contains("result: 2 OK")) {
searchLogForError(scriptPath: scriptOnePath)
}
print("Migration Execution: Successfully unrolled from old server")
migrationInfoText.stringValue = NSLocalizedString("Setting up MDM profile... Please wait!", comment: "Setting up MDM")
while(!readFile(path:logfilePath)!.contains("result: 3 OK")) {
searchLogForError(scriptPath: scriptOnePath)
}
It actually works in the background, reading from the file works and logging works but since the GUI will be hanging executing a while loop with a quickly completed task, the image and the text changes will not be visible.
Code for searchForLogError is:
func searchLogForError(scriptPath:String) {
if((readFile(path:logfilePath)!.filter { $0.contains("ERROR") }).contains("ERROR")) {
print("Migration abborted")
migrationInfoPicture.image = NSImage(named: "FatalError")
migrationInfoText.stringValue = NSLocalizedString("An error occured: \n", comment: "Error occurence") + readFile(path:logfilePath)!.filter { $0.contains("ERROR") }[0]
migrationWarningText.stringValue = NSLocalizedString("In order to get further help, please contact: mac.workplace#swisscom.com", comment: "Error support information")
self.view.window?.level = .normal
btnExitApplicationOutlet.isHidden = false
getScriptProcess(path:scriptPath).terminate()
return
}
}
How can I achieve a visible change of NSImage and NSLocalizedString while constantly looking for log file change without a hanging GUI (or even with a hanging GUI, but with enough time to change the visible elements between the while-loops)?
Polling file system resources is a horrible practice. Don't do that. There are dedicated APIs to observe file system resources for example DispatchSourceFileSystemObject
Create a property
var fileSystemObject : DispatchSourceFileSystemObject?
and two methods to start and stop the observer. In the closure of setEventHandler insert the code to read the file
func startObserver(at url: URL)
{
if fileSystemObject != nil { return }
let fileDescriptor : CInt = open(url.path, O_EVTONLY);
if fileDescriptor < 0 {
print("Could not open file descriptor"))
return
}
fileSystemObject = DispatchSource.makeFileSystemObjectSource(fileDescriptor: fileDescriptor, eventMask: [.write, .rename], queue: .global())
if fileSystemObject == nil {
close(fileDescriptor)
print"Could not create Dispatch Source"))
return
}
fileSystemObject!.setEventHandler {
if self.fileSystemObject!.mask.contains(.write) {
// the file has been modified, do something
}
}
fileSystemObject!.setCancelHandler {
close(fileDescriptor)
}
fileSystemObject!.resume()
}
func stopObserver()
{
fileSystemObject?.cancel()
fileSystemObject = nil
}

Remote video stream is not being rendered to the UIView even though the IBOutlet is connected

I can't seem to get remote video stream to render properly to my UIView. I can hear the two participants but can't seem to render the video stream even though the IO.
Any ideas why? Here's my code:
func rtcEngine(_ engine: AgoraRtcEngineKit, firstRemoteVideoDecodedOfUid uid:UInt, size:CGSize, elapsed:Int) {
DispatchQueue.main.async {
if (self.remoteVideo.isHidden) {
self.remoteVideo.isHidden = false
}
self.agoraKit.muteLocalAudioStream(false)
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = 0
videoCanvas.view = self.remoteVideo
videoCanvas.renderMode = .adaptive
self.agoraKit.setupRemoteVideo(videoCanvas)
}
}
From your code, I see you are assigning the UID to be 0. That means it will automatically generate a new UID for the remote view. You can set the UID to 0 to auto generate the local video stream if you'd like. However, for the remote stream, you need to grab the assigned UID of the remote stream which is provided in the callback method's parameter as the uid variable.
Also, you need to make sure that you are adding the delegate methods in an extension that adopts the AgoraRtcEngineDelegate protocol.
extension VideoChatViewController: AgoraRtcEngineDelegate {
// Tutorial Step 5
func rtcEngine(_ engine: AgoraRtcEngineKit, firstRemoteVideoDecodedOfUid uid:UInt, size:CGSize, elapsed:Int) {
DispatchQueue.main.async {
if (self.remoteVideo.isHidden) {
self.remoteVideo.isHidden = false
}
self.agoraKit.muteLocalAudioStream(false)
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
videoCanvas.view = self.remoteVideo
videoCanvas.renderMode = .adaptive
self.agoraKit.setupRemoteVideo(videoCanvas)
}
}
}

CLGeocoder geocodeAddressString() hitting the limit

Im using MapKit's CLGeocoder().geocodeAddressString() to get the coordinates and county information for a list of addresses. Everything works great as long as the # of requests is under 50. but anything over 50 and im hitting API's limit. Since CLGeocoder calls are asynchronous, i can't easily throttle/control the flow of the calls (calling one address at a time, for instance). How would I do this correctly in the "asynchronous world"? (DISCLAIMER: I'm new to the world of GCD and asynchronous flow control, so I think I might require a more detailed response)
Here's the relevant code:
method of Class Property that calls CLGeocoder on the Property's Adress:
func initializeCoordinates() {
let addressForCoords = self.address.getAddress()
CLGeocoder().geocodeAddressString(addressForCoords, completionHandler: { (placemarks, error) -> Void in
if error != nil {
print(error!)
return
}
if placemarks!.count > 0 {
let placemark = placemarks?[0]
let location = placemark?.location
self.coordinates = location?.coordinate
if let subAdminArea = placemark?.subAdministrativeArea {
self.address.county = subAdminArea
}
}
})
}
and then in the section in the ImportVC that imports all the property's addresses from a textBox (and makes the call to initializeCoordinates method on each Property:
for line in importText {
let newAddress = Address()
let newHouse = Property()
// parse the tab delimited address for each line of input
let address = line.components(separatedBy: "\t")
if address.count == 4 {
newAddress.street = address[0]
newAddress.city = address[1]
newAddress.state = trimState(state: address[2])
newAddress.zip = address[3]
newHouse.address = newAddress
newHouse.initializeCoordinates()
houses.append(newHouse)
}
}
I faced a similar problem recently. Replace your for-loop with a recursive function that calls itself at the end. However the trick is to call its self with a 0.2 second delay. I use 0.4 to be on the safe side. This will increase the waiting time for the user, although we have no choice due to the API limit.

How to modify a struct with async callbacks?

I'm trying to update a struct with multi-level nested async callback, Since each level callback provides info for next batch of requests till everything is done. It's like a tree structure. And each time I can only get to one level below.
However, the first attempt with inout parameter failed. I now learned the reason, thanks to great answers here:
Inout parameter in async callback does not work as expected
My quest is still there to be solved. The only way I can think of is to store the value to a local file or persistent store and modify it directly each time. And after writing the sample code, I think a global var can help me out on this as well. But I guess the best way is to have a struct instance for this job. And for each round of requests, I store info for this round in one place to avoid the mess created by different rounds working on the same time.
With sample code below, only the global var update works. And I believe the reason the other two fail is the same as the question I mentioned above.
func testThis() {
var d = Data()
d.getData()
}
let uriBase = "https://hacker-news.firebaseio.com/v0/"
let u: [String] = ["bane", "LiweiZ", "rdtsc", "ssivark", "sparkzilla", "Wogef"]
var successfulRequestCounter = 0
struct A {}
struct Data {
var dataOkRequestCounter = 0
var dataArray = [A]()
mutating func getData() {
for s in u {
let p = uriBase + "user/" + s + ".json"
getAnApiData(p)
}
}
mutating func getAnApiData(path: String) {
var req = NSURLRequest(URL: NSURL(string: path)!)
var config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
var session = NSURLSession(configuration: config)
println("p: \(path)")
var task = session.dataTaskWithRequest(req) {
(data: NSData!, res: NSURLResponse!, err: NSError!) in
if let e = err {
// Handle error
} else if let d = data {
// Successfully got data. Based on this data, I need to further get more data by sending requests accordingly.
self.handleSuccessfulResponse()
}
}
task.resume()
}
mutating func handleSuccessfulResponse() {
println("successfulRequestCounter before: \(successfulRequestCounter)")
successfulRequestCounter++
println("successfulRequestCounter after: \(successfulRequestCounter)")
println("dataOkRequestCounter before: \(dataOkRequestCounter)")
dataOkRequestCounter++
println("dataOkRequestCounter after: \(dataOkRequestCounter)")
println("dataArray count before: \(dataArray.count)")
dataArray.append(A())
println("dataArray count after: \(dataArray.count)")
if successfulRequestCounter == 6 {
println("Proceeded")
getData()
}
}
}
func getAllApiData() {
for s in u {
let p = uriBase + "user/" + s + ".json"
getOneApiData(p)
}
}
Well, in my actual project, I successfully append a var in the struct in the first batch of callbacks and it failed in the second one. But I failed to make it work in the sample code. I tried many times so that it took me so long to update my question with sample code. Anyway, I think the main issue is to learn appropriate approach for this task. So I just put it aside for now.
I guess there is no way to do it with closure, given how closure works. But still want to ask and learn the best way.
Thanks.
What I did was use an inout NSMutableDictionary.
func myAsyncFunc(inout result: NSMutableDictionary){
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let intValue = result.valueForKey("intValue")
if intValue as! Int > 0 {
//Do Work
}
}
dispatch_async(dispatch_get_main_queue()) {
result.setValue(0, forKey: "intValue")
}
}
I know you already tried using inout, but NSMutableDictionary worked for me when no other object did.