Unable to load WAV to AKMidiSampler on MacOSX - audiokit

I'm trying to work with AKMidiSampler on Mac OSX. I'm unable to load sample data from a file. The following code will illustrate the problem when put into the Development Playground in the AudioKit for macOS project:
import AudioKit
let sampler1 = AKMIDISampler()
sampler1.loadPath("/Users/shane/Documents/Cel1.wav")
AudioKit.output = sampler1
AudioKit.start()
sampler1.play(noteNumber: 64, velocity: 100, channel: 0)
sleep(5)
sampler1.stop(noteNumber: 64, channel: 0)
The error happens right at line 2:
AKSampler.swift:loadPath:114:Error loading audio file at /Users/shane/Documents/samples/Cel1.wav
and all I hear is the default sine tone. I've checked the obvious things, e.g. the file is quite definitely present, permissions OK (actually rwx for everybody, just in case). Earlier experiments trying to load an ESX file indicated permission errors (code -54).
Can anyone verify that AKSampler and/or AKMIDISampler actually work in OSX?

Update March 20, 2018: The AudioKit team has since made some additions to the AKSampler/AKMIDISampler API to allow loading sample files from arbitrary file paths.
I have been invited to join the AudioKit core team, and have written a new sampler engine from scratch. In the next AudioKit release (expected within a day or two), the name "AKSampler" will refer to this newer code, but users should be aware that it is not a direct replacement for the older AKSampler, which will be renamed "AKAppleSampler" to reflect the fact that it is a wrapper for Apple's built-in "AUSampler" audio unit. The AKMIDISampler class (the one most people actually use) will remain unchanged as a wrapper for AKAppleSampler.

In the AudioKit source code, loadPath(_ :) calls loadInstrument(_ : type:) which looks in the bundle for your file. See a copy of the sources here:
#objc open func loadPath(_ filePath: String) {
do {
try samplerUnit.loadInstrument(at: URL(fileURLWithPath: filePath))
} catch {
AKLog("Error loading audio file at \(filePath)")
}
}
internal func loadInstrument(_ file: String, type: String) throws {
//AKLog("filename is \(file)")
guard let url = Bundle.main.url(forResource: file, withExtension: type) else {
fatalError("file not found.")
}
do {
try samplerUnit.loadInstrument(at: url)
} catch let error as NSError {
AKLog("Error loading instrument resource \(file)")
throw error
}
}
So you need to put your audio file in the app's or playground's bundle for this to call for this to work.

Related

Move all files into another location in a Swift script

To start, I am a total noob at Swift.
I am trying to move files from one location to another in Swift. For example, I have a function which lets me use bash commands within my Swift script. I simply had the following to move all files from one folder into current location: shell("mv \(currentDirectory)/archive/*.crash \(currentDirectory)").
However I was told to use the fileManager API to move files and by using filemanager I could have have better error reporting capability. I did see that Apple has the following command: https://developer.apple.com/documentation/foundation/filemanager/1414750-moveitem
EDIT**: So I have been able to figure out how to do this with the following code:
let files = try? fileManager.contentsOfDirectory(atPath: "\(currentDirectory)/archive")
if let files = files {
for file in files {
do {
try fileManager.moveItem(atPath: "\(currentDirectory)/archive/\(file)",
toPath:"\(currentDirectory)/ips/\(file)")
print(files.count)
} catch {
print("Error \(error)")
}
}
}
}
However, when I run my script, it moves the files as expected but now it is crashing my script with a Fatal error: Index out of range
See screenshot below:
Does anyone know if this is due to the contentOfDirectory throwing an empty array?

AudioKit: how to perform frequency modulation for AKPlayer

I'm trying to perform frequency modulation on a signal coming from AKPlayer, which in return plays a mp3 file.
I've tried to work with AKOperationEffect, but it doesn't work as expected:
let modulatedPlayer = AKOperationEffect(player) { player, _ in
let oscillator = AKOperation.fmOscillator(baseFrequency: modulationFrequency,
carrierMultiplier: player.toMono(),
modulatingMultiplier: 100,
modulationIndex: 0,
amplitude: 1)
return oscillator
}
Has anybody an idea how to get the mp3 modulated?
Unfortunately, the AudioKit API is not so well documented .... there are a tons of examples, but they all deal with synthetic sounds such as sine, square waves etc.
I took the time to create a working practical example to help you #Ulrich, you can drop and play if you have the playground environment available, or just use it as a reference trusting me it works to amend your code, it's self-explanatory but you can read more about why my version work after the code TLDR;
Before <audio>
After <audio>
The following was tested and ran without problems in the latest XCode and Swift at the time of writing (XCode 11.4, Swift 5.2 and AudioKit 4.9.5):
import AudioKitPlaygrounds
import AudioKit
let audiofile = try! AKAudioFile(readFileName: "demo.mp3")
let player = AKPlayer(audioFile: audiofile)
let generator = AKOperationEffect(player) { player, _ in
let oscillator = AKOperation.fmOscillator(baseFrequency: 400,
carrierMultiplier: player.toMono(),
modulatingMultiplier: 100,
modulationIndex: 0,
amplitude: 1)
return oscillator
}
AudioKit.output = generator
try! AudioKit.start()
player.play()
generator.start()
Find the playground ready to use in the Download page ( https://audiokit.io/downloads/ )
As you can see, apart from declaring a path to the mp3 file when initializing a new AKAudioFile and passing to an AKPlayer instance, there are three steps that you need to occur in a certain order:
1) Assign an `AKNode` to the AudioKit output
2) Start the AudioKit engine
3) Start the `player` to generate output
4) Start the generator to moderate your sound
The best way to understand why this is to forget about code for a bit and imagine patching things in the real world; and finally, try to imagine the audio flow.
Hope this helps you and future readers!

AudioKit export song pre iOS 11

Note that this is NOT a duplicate of this SO Post because in that post only WHAT method to use is given but there's no example on HOW should I use it.
So, I have dug into AKOfflineRenderNode as much as I can and have viewed all examples I could find. However, my code never seemed to work correctly on iOS 10.3.1 devices(and other iOS 10 versions), for the result is always silent. I try to follow examples provided in other SO posts but no success. I try to follow that in SongProcessor but it uses an older version of Swift and I can't even compile it. Trying SongProcessor's way to use AKOfflineRenderNode didn't help either. It always turned out silent.
I created a demo project just to test this. Because I don't own the audio file I used to test with, I couldn't upload it to my GitHub. Please add an audio file named "Test" into the project before compiling onto an iOS 10.3.1 simulator. (And if your file isn't in m4a, remember to change the file type in code where I initialize AKPlayer)
If you don't want to download and run the sample, the essential part is here:
#IBAction func export() {
// url, player, offlineRenderer and others are predefined and connected as player >> aPitchShifter >> offlineRenderer
// AudioKit.output is already offlineRenderer
offlineRenderer.internalRenderEnabled = false
try! AudioKit.start()
// I also tried using AKAudioPlayer instead of AKPlayer
// Also tried getting time in these ways:
// AVAudioTime.secondsToAudioTime(hostTime: 0, time: 0)
// player.audioTime(at: 0)
// And for hostTime I've tried 0 as well as mach_absolute_time()
// None worked
let time = AVAudioTime(sampleTime: 0, atRate: offlineRenderer.avAudioNode.inputFormat(forBus: 0).sampleRate)
player.play(at: time)
try! offlineRenderer.renderToURL(url, duration: player.duration)
player.stop()
player.disconnectOutput()
offlineRenderer.internalRenderEnabled = true
try? AudioKit.stop()
}

How to add url in avaudioplayer in swift

i just want to ask on how to play audio using avAudion using url link..
and im getting error bad request.. can someone help me?
i already tried using avplayer but it is not suitable for me.. though it is working but.. i kinda prefer to use avaudioplayer
let mp3URL = NSURL(fileURLWithPath:"https://s3.amazonaws.com/kargopolov/kukushka.mp3")
do {
// 2
audioPlayer = try AVAudioPlayer(contentsOf: mp3URL as URL)
audioPlayer.play()
// 3
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateAudioProgressView), userInfo: nil, repeats: true)
progressView.setProgress(Float(audioPlayer.currentTime/audioPlayer.duration), animated: false)
}
catch {
print("An error occurred while trying to extract audio file")
}
According to the AVAudioPlayer documentation, if you want to play audio over the internet (that's not already downloaded to disk or memory) you should use AVPlayer.
The docs describe AVAudioPlayer as
An audio player that provides playback of audio data from a file or memory.
A little further down, in the overview section, emphasis added:
Use this class for audio playback unless you are playing audio captured from a network stream or require very low I/O latency.
Notes
You can get some more information from the runtime by accessing the error object that is thrown when the connection fails. Change catch { to catch let error { and then you can log out the error as part of your message, like so:
catch let error{
print("An error occurred while trying to extract audio file: \(error)")
}
When I run your sample code in Xcode playgrounds with the change noted above, I see the following:
An error occurred while trying to extract audio file: Error Domain=NSOSStatusErrorDomain Code=2003334207 "(null)"
Notice the error's Domain and Code. Pasting that error into Google yields some results that indicate that the URL might not be resolving correctly. (Indeed, clicking on that mp3 link shows a bad access error message.)
The first result is another StackOverflow post with a similar issues. The second one is an Apple Developer Forum post which has some more information.
Let's try to change the URL to a publicly accessible sample mp3 file. (I found this one by searching the web for "test mp3 file" on Google.)
You'll want to change NSURL to URL, and instead of fileURLWithPath, you're going to want to use another initializer. (Say, string:.)
Whenever you see contentsOf...: in a media or file API, there's a good chance it expects data or a file, to the exclusion of a network stream. Similarly, when you see an initializer or method that takes a fileURL..., the system expects to be pointing to a local resource, not a network URL.
if let mp3URL = URL(string: "https://s3.amazonaws.com/kargopolov/kukushka.mp3"){
// do s.t
}
Anyway, you should know the basics of ios

NSFileProvider importDocument provides fileURL of empty file when saving new document from MSOffice apps

I'm trying to create a new document in Word.app and save to my app via FileProvider extension. My implementation of appropriate method is:
override func importDocument(at fileURL: URL,
toParentItemIdentifier parentItemIdentifier: NSFileProviderItemIdentifier,
completionHandler: #escaping (NSFileProviderItem?, Error?) -> Void)
{
let internalUrl = NSFileProviderManager.default.documentStorageURL.appendingPathComponent(fileURL.lastPathComponent, isDirectory: false)
guard fileURL.startAccessingSecurityScopedResource() else { fatalError() }
try! FileManager.default.copyItem(at: fileURL, to: internalUrl) // breakpoint here
fileURL.stopAccessingSecurityScopedResource()
// update local db, whatever
completionHandler(TemporaryItem(forImporting: internalUrl, into: parentItemIdentifier), nil)
}
Apparently, when I'm putting the breakpoint and inspecting file attributes via po FileManager.default.attributesOfItem(forPath: fileURL.path) command, value for NSFileSize is 0.
Command po FileManager.default.contents(atPath: fileURL.path) returns me 0 byte Data with 0x000000000000bad0 pointer.
The file being written to internalUrl is empty as well.
The strangest thing is that this situation happens only with MS Word, Excel and PowerPoint apps. Same code for files saved from PSPDFKit, Files or Photos works perfectly. On the other side, Word correctly saves files to other file providers like Dropbox, so the problem should not be there.
I've tried to do that with file coordinator, but that didn't help. I've verified that every startAccessingSecurityScopedResource() has it's stopAccessingSecurityScopedResource(). I've tested on two iOS11.3 devices - same bahavior. I've even found other open source application which does same operations.
What am I doing wrong except expecting iOS app extension to work?
Because the the Word app will trigger several times of importDocument...
At first importDocument calling, it tries to create empty file on file provider extension. That's why the size of imported file is 0.
If you handle it well, the Word app will get the saved file path and update the file on it.
And then it will trigger next itemChangedAtURL: api with the file path it just got.

Resources