I want to make piano player in which I want to play predefined notes which are some .mid files. Here is my code which is not working.
let soundPath: String? = Bundle.main.path(forResource: "0_100", ofType: "mid")
let midiFile:URL = URL(fileURLWithPath: soundPath ?? "")
var midiPlayer: AVMIDIPlayer?
do {
try midiPlayer = AVMIDIPlayer(contentsOf: midiFile, soundBankURL: nil)
midiPlayer?.prepareToPlay()
midiPlayer?.play {
print("finished playing")
}
} catch {
print("could not create MIDI player")
}
soundBankURL is missing in the following:
try midiPlayer = AVMIDIPlayer(contentsOf: midiFile, soundBankURL: nil)
It's required according to the doc: https://developer.apple.com/documentation/avfoundation/avmidiplayer/1389225-init
Important
For macOS the bankURL can be set to nil to use the default sound bank. However, iOS must always refer to a valid bank file.
A soundBank can be a .sf2 file for instance.
Related
I'm trying to play a file I downloaded from S3, after locating the file and passing the URL to the audio player, the audio file won't play/is missing.
This is the complete fileURL: file:///var/mobile/Containers/Data/Application/61F2FC20-4C62-4263-B147-0010805BC0FA/Documents/Dump%20Trucks.mp3
Here is my code:
func playAudio(){
var soundClip: AVAudioPlayer?
if let directory = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true).first{
let path = NSURL(fileURLWithPath: directory).appendingPathComponent("Dump Trucks.mp3")
print("The path is \(String(describing: path))")
do {
soundClip = try AVAudioPlayer(contentsOf: path!)
soundClip?.play()
} catch {
print("Error: Audio File missing.")
}
}
}
The problem is that your player is a local variable. Thus your method comes to an end and the player is destroyed before it ever has a chance to start playing! Declare it as an instance property instead.
So
func playAudio(){
var soundClip: AVAudioPlayer?
Becomes
var soundClip: AVAudioPlayer?
func playAudio(){
This might not solve all your problems but if you don’t do it you certainly will never hear sound.
import Foundation
import AVFoundation
final class MediaPlayer {
static var player = AVAudioPlayer()
class func play() {
do {
let file = Bundle.main.url(forResource: "file_name", withExtension: "mp3")!
player = try AVAudioPlayer(contentsOf: file)
player.numberOfLoops = 0 // loop count, set -1 for infinite
player.volume = 1
player.prepareToPlay()
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
try AVAudioSession.sharedInstance().setActive(true)
player.play()
} catch _ {
print("catch")
}
}
}
I'm in my first week of coding.
So far the youtube tutorial app I am making in swift is going perfectly apart from the above error message. Here is the code. I have rewritten this twice now exactly as they specify.
I am trying to set up sounds to play with the card game we are making, the sounds play when cards are shuffled, turned around, matched or incorrectly matched.
The error message is shown for "let soundURL" line of code, "Code after 'return' will never be executed".
Please help?
class SoundManager {
static var audioPlayer:AVAudioPlayer?
enum SoundEffect {
case flip
case shuffle
case match
case nomatch
}
static func playSound(_ effect:SoundEffect) {
var soundFilename = ""
// Determine which sound effect we want to play
//and set the appropriate file name
switch effect {
case .flip:
soundFilename = "cardflip"
case .shuffle:
soundFilename = "cardflip"
case .match:
soundFilename = "dingcorrect"
case.nomatch:
soundFilename = "dingwrong"
}
// Get the path to the sound file inside the bundle
let bundlePath = Bundle.main.path(forResource: soundFilename, ofType: "wav")
guard bundlePath != nil else {
print("Couldn't find sound file \(soundFilename) in the bundle")
return
// Create a URL object from this string path
let soundURL = URL(fileURLWithPath: bundlePath!)
do {
// Create audio player object
audioPlayer = try AVAudioPlayer(contentsOf: soundURL)
// Play the sound
audioPlayer?.play()
}
catch {
// Could'nt create audio player object, log the error
print("Could'nt create the audio player object for sound file \(soundFilename)")
}
}
}
}
I believe you want your code to look something like this:
// Get the path to the sound file inside the bundle
let bundlePath = Bundle.main.path(forResource: soundFilename, ofType: "wav")
guard bundlePath != nil else {
print("Couldn't find sound file \(soundFilename) in the bundle")
return
}
// Create a URL object from this string path
let soundURL = URL(fileURLWithPath: bundlePath!)
do {
// Create audio player object
audioPlayer = try AVAudioPlayer(contentsOf: soundURL)
// Play the sound
audioPlayer?.play()
}
catch {
// Could'nt create audio player object, log the error
print("Could'nt create the audio player object for sound file \(soundFilename)")
}
If there is a guard statement with return inside its brackets, you do not want to put any code beneath the return and within the same brackets. None of the code below the return will execute. In my example, the following code is outside of the brackets, meaning it will execute so long as there is a value for bundlePath.
Code after 'return' will never be executed
var soundFilename = ""
// Determine which sound effect we want to play
//and set the appropriate file name
switch effect {
case .flip:
soundFilename = "cardflip"
case .shuffle:
soundFilename = "cardflip"
case .match:
soundFilename = "dingcorrect"
case.nomatch:
soundFilename = "dingwrong"
}
// Get the path to the sound file inside the bundle
let bundlePath = Bundle.main.path(forResource: soundFilename, ofType: "wav")
guard bundlePath != nil else {
print("Couldn't find sound file \(soundFilename) in the bundle")
return
}
// Create a URL object from this string path
let soundURL = URL(fileURLWithPath: bundlePath!)
do {
// Create audio player object
audioPlayer = try AVAudioPlayer(contentsOf: soundURL)
// Play the sound
audioPlayer?.play()
}
catch {
// Could'nt create audio player object, log the error
print("Could'nt create the audio player object for sound file \(soundFilename)")
}
// }
}
I believe that you have misunderstood the guard syntax as it will execute the code when the condition is correct and will fall in else part when the condition is false. So therefore it will use return in else with no other code , So that the method will be terminated gracefully without giving any crash.
The return keyword is used to return something with the method execution or to exit from the method.
So you need to close the else part with “}” and remove one below catch block. Hope this helps.
I am new to Swift and making an audio app using AVAudioPlayer. I am using a remote URL mp3 file for the audio, and this works when it's static.
For my use case, I want to pull a URL for an mp3 file from a JSON array and then pass it into the AVAudioPlayer to run.
If I move the AVAudioPlayer block into the ViewDidLoad and make the mp3 file a static URL, it will run fine.
Then, when I move this code into my block that extracts an mp3 url from JSON, I can print the URL successfully. But when I pass it into my audio player, problems arise. Here's the code.
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "http://www.example.com/example.json")
URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
let json: Any?
do{
json = try JSONSerialization.jsonObject(with: data, options: [])
}
catch{
return
}
guard let data_list = json as? [[String:Any]] else {
return
}
if let foo = data_list.first(where: {$0["episode"] as? String == "Example Preview"}) {
self.audiotest = (foo["audio"] as? String)!
print(self.audiotest) // this prints
// where i'm passing it into the audio player
if let audioUrl = URL(string: self.audiotest) {
// then lets create your document folder url
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// lets create your destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
//let url = Bundle.main.url(forResource: destinationUrl, withExtension: "mp3")!
do {
audioPlayer = try AVAudioPlayer(contentsOf: destinationUrl)
} catch let error {
print(error.localizedDescription)
}
} // end player
// ....
Specifically, I get an error Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value when clicking a play button IBAction that is connected to the audio player. Finally, that action function looks like this:
#IBAction func playPod(_ sender: Any) {
audioPlayer.play()
}
Do you know where I'm going wrong? I'm confused as to why I can't print the URL and also get a response that the URL is nil in the same block, but maybe that's an asynchronous thing.
The problem is that you didn't save the mp3 file to documents and trying to play it
this line
audioPlayer = try AVAudioPlayer(contentsOf: destinationUrl)
assumes that there is a saved mp3 file in that path , but acutally there is no files you appended the audio extension on the fly
besides for steaming audio from a remote server, use AVPlayer instead of AVAudioPLayer.
AVPlayer Documentation
Also try this with urls parsed from json
var urlStr = (foo["audio"] as? String)!
self.audiotest = urlStr.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
I have uploaded some songs in firebase Storage directly,I just want to stream the song in AVAudioPlayer.
Below is the code which I am trying:
var mainRef: FIRStorageReference {
return FIRStorage.storage().reference(forURL: "gs://musicapp-d840c.appspot.com")
}
var audioStorageRef: FIRStorageReference{
return mainRef.child("SongsPath")
}
audioStorageRef.downloadURL { url, error in
if let error = error {
print(error.localizedDescription)
} else {
if let url = url {
do {
self.audioPlayer = try AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: String(describing: url)) as URL)
self.audioPlayer.play()
} catch {}
let storyboard = UIStoryboard(name: "AudioPlayer", bundle: nil)
let audioVc = storyboard.instantiateViewController(withIdentifier: "AudioPlayerViewController") as! AudioPlayerViewController
audioVc.playThisSong = String(describing: url)
self.present(audioVc, animated: false, completion: nil)
}
}
}
Here the song url from the firebase is passing but it is skipping the self.audioPlayer.play. ,I just want to stream the audio. Can I get a proper solution for this?
This is not an answer for streaming.
This is an answer for downloading the file, storing it locally, and playing the audio after the file has finished downloading.
Get a Firebase storage reference using a path string with the file extension. Get a file url to store it on the device using the same path string that we use for the Firebase storage reference.
Initiate the download task using write(toFile: URL). Store the download task in a variable to add observers. When the download is successful, play the audio.
In Swift 4:
var player: AVAudioPlayer?
let pathString = "SongsPath.mp3"
let storageReference = Storage.storage().reference().child(pathString)
let fileUrls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
guard let fileUrl = fileUrls.first?.appendingPathComponent(pathString) else {
return
}
let downloadTask = storageReference.write(toFile: fileUrl)
downloadTask.observe(.success) { _ in
do {
self.player = try AVAudioPlayer(contentsOf: fileUrl)
self.player?.prepareToPlay()
self.player?.play()
} catch let error {
print(error.localizedDescription)
}
}
This is minimal code. Implement error handling as you see fit.
Firebase example of downloading locally
I need to playback a single audio file with TheAmazingAudioEngine framework and Swift.
I'm completely newbie with this framework and tried the code below, but the audio didn't play. What is wrong? How could I play the audio file?
do {
var audioController = AEAudioController(audioDescription: AEAudioController.nonInterleavedFloatStereoAudioDescription())
let file = NSBundle.mainBundle().URLForResource("myaudiofile", withExtension: "wav")!
let channel = try AEAudioFilePlayer(URL: file)
audioController?.addChannels([channel])
channel.playAtTime(0)
} catch {
print("Failure")
}
I missed to start the audioController:
do {
var audioController = AEAudioController(audioDescription: AEAudioController.nonInterleavedFloatStereoAudioDescription())
let file = NSBundle.mainBundle().URLForResource("myaudiofile", withExtension: "wav")!
let channel = try AEAudioFilePlayer(URL: file)
audioController?.addChannels([channel])
try audioController!.start()
} catch {
print("Failure")
}