Play sound with AKAudioPlayer - iOS - swift

How to declare AKAudioPlayer?
I'm using AudioKit Lib and I just need help to play .wav file with change file button.
import UIKit
import AudioKit
class ViewController: UIViewController {
let file = NSBundle.mainBundle().pathForResource("song", ofType: "wav")
let song = AKAudioPlayer(file!) // <--- ERROR = instance member 'file' cannot be used on type
override func viewDidLoad() {
super.viewDidLoad()
AudioKit.output = song
AudioKit.start()
song.play()
}
#IBAction func btn(sender: AnyObject) {
song.replaceFile("NewFile")
song.play()
}
}

This is a very fast solution to your problem. It can be done better but at least you can get the idea.
First try to make a new class with a function to play your file and then another function to reload your new replacement file like this.
class PlayMyMusic {
var songFile = NSBundle.mainBundle()
var player: AKAudioPlayer!
func play(file: String, type: String) -> AKAudioPlayer {
let song = songFile.pathForResource(file, ofType: type)
player = AKAudioPlayer(song!)
return player
}
func rePlay(file: String, type: String, curPlay: AKAudioPlayer) {
let song = songFile.pathForResource(file, ofType: type)
curPlay.stop()
curPlay.replaceFile(song!)
curPlay.play()
}
}
Initiate the class inside your view
class testViewController: UIViewController {
let doPlay = PlayMyMusic().play("A", type: "wav")
.........
.........
Play your music inside your view
override func viewDidLoad() {
super.viewDidLoad()
AudioKit.output = self.doPlay
AudioKit.start()
doPlay.looping = true
doPlay.play()
}
Then when you want to reload a new file use the rePlay function
#IBAction func btn(sender: AnyObject) {
PlayMyMusic().rePlay("C", type: "wav", curPlay: self.doPlay)
}

take look on AudioKit playground
update
AKAudioPlayer is deprecated, use AudioPlayer insted and check AudioKit v5 Migration Guide

Related

Do you need to ask for permission to use the microphone when running an app in simulator?

I Created a simple audio player/recorder player using AVAudioPlayer and AVAudioRecorder. The audio player works as expected but the audio recorder doesn't seem to record or playback the recording even though it builds successfully without any errors. Im wondering if it needs permission to the mic? I'm using version 11.X The code is below any help is much appreciated.
import UIKit
import AVFoundation //must import AVFoundation
class ViewController: UIViewController {
// create property called audioPlayer equal to player
var audioPlayer : AVAudioPlayer?
var audioRecorder : AVAudioRecorder?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//create the audio session
let session = AVAudioSession.sharedInstance()
//set category where we want it to happen (PlayAndRecord) try? = if it doesnt work then set it nil
try? session.setCategory(AVAudioSession.Category.playAndRecord)
//play any audio through device speaker
try? session.overrideOutputAudioPort(.speaker)
// set the session to active, if it doesnt work se it to nil
try? session.setActive(true)
//setup the recording and settings to where audio will be saved (Document folder on device) and set the name and file type (iloveaudio.mp3)
if let basePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
let paths = [basePath, "iloveaudioios.mp3"]
if let audioURL = NSURL.fileURL(withPathComponents: paths) {
//create a settings dictionary> orignally it's set to empty using ([:])
var settings : [String : Any] = [:]
//set the file type to mp3
settings[AVFormatIDKey] = Int(kAudioFileMP3Type)
//set the sample rate
settings[AVSampleRateKey] = 44100.0
//set number of channels
settings[AVNumberOfChannelsKey] = 2
// specify the path and settings using var and try to run the recorder if it faile set it to nil
audioRecorder = try? AVAudioRecorder(url: audioURL, settings: settings)
//prepare the recorder of ot fails set it to nil
audioRecorder?.prepareToRecord()
}
}
playerSetup(audioURL: nil)
}
//which file to play if something is recorded
func playerSetup(audioURL:URL?) {
if audioURL == nil {
if let audioPath = Bundle.main.path(forResource: "testaudio", ofType: "mp3") {
let tempAudioURL = URL(fileURLWithPath: audioPath)
audioPlayer = try? AVAudioPlayer(contentsOf: tempAudioURL)
}
} else {
audioPlayer = try? AVAudioPlayer(contentsOf: audioURL!)
}
//check if our audio fille exist? and set it to the proerty audioPath
audioPlayer?.prepareToPlay()
//create audio player, make sure it not nil and if its not the prepare to play, then play
}
#IBAction func PlayPressed(_ sender: Any) {
audioPlayer?.play()
}
#IBAction func Pausedpressed(_ sender: Any) {
audioPlayer?.pause()
}
#IBAction func Stop(_ sender: Any) {
audioPlayer?.stop()
audioPlayer?.currentTime = 0
}
#IBAction func Record(_ sender: Any) {
if let recorder = audioRecorder {
if !recorder.isRecording {
recorder.record()
}
}
}
#IBAction func StopRecord(_ sender: Any) {
if let recorder = audioRecorder {
if recorder.isRecording {
recorder.stop()
playerSetup(audioURL: recorder.url)
}
}
}
}
Yes , You need to add Permission in info.plist
Go to info.plist of your project
Add Privacy - Microphone Usage Description and set it's Value YES(true)
After Setting , when you'll start recording in your app for the first time it will ask for permission , Allow that and you're all set !

Loading correct image to detail view

I have a TableView app that plays music. The tracks are named: 0.mp3, 1.mp3 etc. They play in a detail view where I also want an image of the cover. I named the cover images: 0.png, 1.png etc.
I tried to load the correct image with the code:
self.bookImage.image = UIImage(named: ("/\(trackID!).png"))
but it doesn't work.
Here's some more of my code:
import UIKit
import AVFoundation
class AudioPlayerVC: UIViewController {
var trackID: Int!
var audioPlayer:AVAudioPlayer!
#IBOutlet var bookImage: UIImageView!
#IBAction func play(_ sender: AnyObject) {
if !audioPlayer.isPlaying{
audioPlayer.play()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.bookImage.image = UIImage(named: ("/\(trackID!).png"))
trackLbl.text = "Track \(trackID!)"
let path: String! = Bundle.main.resourcePath?.appending("/\(trackID!).mp3")
let mp3URL = NSURL(fileURLWithPath: path)
do
{
audioPlayer = try AVAudioPlayer(contentsOf: mp3URL as URL)
audioPlayer.play()
}
}
}
You need
self.bookImage.image = UIImage(named:"\(trackID).png")
Or
self.bookImage.image = UIImage(named:"\(trackID)")
First, you don't need / character after opening quotation mark.
self.bookImage.image = UIImage(named:"\(trackID).png")
Should work just fine.
1) Please add your images to Assets.xcassets
2) Name images like 0,1,2,3 in Assets.xcassets
3) Write a code:
let trackId = String(trackId)
self.bookImage.image = UIImage(named: trackId)

How to loop background music without lag/delay when song repeats (seamless)

I am trying to make a game with background music looping in it. I made the song file in Adobe Audition (which is similar to audacity) and when I play it in a loop in Adobe Audition it loops how I want it.
When I play it in Xcode however, it has a lag in between the loops. I am using AVFoundations for the sound playing.
I have searched everywhere but I can't find the solution for the problem.
Is there any way you can loop audio files without there being any lags in between ? (I believe its called "seamless looping" )
here is the code:
class GameScene: SKScene {
...// Other Code
var ButtonAudio = URL(fileURLWithPath: Bundle.main.path(forResource: "Gamescene(new)", ofType: "mp3")!)
var ButtonAudioPlayer = AVAudioPlayer()
... //Other Code
}
And When I Call it:
override func didMove(to view: SKView) {
...//Code
ButtonAudioPlayer = try! AVAudioPlayer(contentsOf: ButtonAudio, fileTypeHint: nil)
ButtonAudioPlayer.numberOfLoops = -1
ButtonAudioPlayer.prepareToPlay()
ButtonAudioPlayer.play()
...//More Code
}
Can someone help me with this issue ?
Thank you in advance!
You can use AVPlayerLooper and AVQueuePlayer to do this.
import UIKit
import AVFoundation
class ViewController: UIViewController {
var queuePlayer = AVQueuePlayer()
var playerLooper: AVPlayerLooper?
override func viewDidLoad() {
super.viewDidLoad()
guard let url = Bundle.main.url(forResource: "Gamescene(new)", withExtension: "mp3") else { return }
let playerItem = AVPlayerItem(asset: AVAsset(url: url))
playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: playerItem)
queuePlayer.play()
}
}
The solution proposed by #dave234 only works in iOS > 10. Since I needed to make seamless playback in iOS > 9, I did something different:
Instead of AVPlayer, I created AVQueuePlayer and immediately added two identical melodies to the queue.
Next, I made a listener to the penultimate melody.
When the listener was triggered, I added another similar record to the queue after the last one.
In fact, in order to avoid delay, I always play the penultimate record.
My code:
var player: AVQueuePlayer?
override func viewDidLoad() {
super.viewDidLoad()
if let path = Bundle.main.path(forResource: "music_file", ofType: "mp3") {
player = createPlayer(url: URL(fileURLWithPath: path))
}
}
func createPlayer(url: URL) -> AVQueuePlayer {
let player = AVQueuePlayer(items: [AVPlayerItem(url: url), AVPlayerItem(url: url)])
loopPlayer(playerItem: player.items()[player.items().count - 2])
return player
}
func loopPlayer(playerItem: AVPlayerItem) {
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: playerItem, queue: .main) { _ in
if let player = self.player, let url = (playerItem.asset as? AVURLAsset)?.url {
player.insert(AVPlayerItem(url: url), after: player.items()[player.items().count - 1])
self.loopPlayer(playerItem: player.items()[player.items().count - 2])
}
}
}

How to write code to stop multiple audio files swift?

good morning
How to write code to stop multiple audio files in this code
I looked for it and did not find anything useful please help me
import UIKit
import AVFoundation
class ViewController: UIViewController {
let soundFilenames = ["001" , "002" , "003" , "004" , "005" , "006" , "007" , "008"]
var Audios = [AVAudioPlayer]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
for sound in soundFilenames {
do {
let url = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(sound, ofType: "mp3")!)
let audioPlayer = try AVAudioPlayer(contentsOfURL: url)
Audios.append(audioPlayer)
}catch{
Audios.append(AVAudioPlayer())
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttun001(sender: UIButton) {
let audioplayer = Audios [sender.tag]
audioplayer.play()
}
}
Use a normal loop, check if is playing and stop the ones playing
func stopAudios(){
for audioPLayer in Audios{
if audioPLayer.playing{
audioPLayer.stop()
}
}
}
Also don't forget to prepare your AVAudioPlayer
audioPlayer.prepareToPlay()

Why the AVAudioPlayer var equals nil? - Swift

This is my function:
func playMusic(filename :String!) {
var playIt : AVAudioPlayer!
let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
if url == nil {
println("could not find \(filename)")
return
}
var error : NSError?
playIt = AVAudioPlayer(contentsOfURL: url, error: &error)
if playIt==nil {
println("could not create audio player")
return
}
playIt.numberOfLoops = -1
playIt.prepareToPlay()
playIt.play()
}
I debugged my app and i saw that the console tells me: could't create audio player
it looks like my playIt var is nil
how do i fix it?
There's another problem with your code: once you find out why playIt is nil and fix that, you'll discover that playMusic runs without errors, but no sound plays. That's because you've declared playIt as a local variable inside playMusic. Just as it starts playing, you reach the end of playMusic, when all its local variables go out of scope and cease to exist. Microseconds after playIt starts to play, it gets wiped out of existence.
To fix this, declare playIt outside playMusic, as an instance variable. Here's the code for a view controller that uses your playMusic method with my one suggested change:
import UIKit
import AVFoundation
class ViewController: UIViewController {
// Declare playIt here instead
var playIt : AVAudioPlayer!
override func viewDidLoad() {
super.viewDidLoad()
playMusic("sad trombone.mp3")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttonPressed(sender: AnyObject) {
}
func playMusic(filename :String!) {
// var playIt : AVAudioPlayer! *** this is where you originally declared playIt
let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
if url == nil {
println("could not find \(filename)")
return
}
var error : NSError?
playIt = AVAudioPlayer(contentsOfURL: url, error: &error)
if playIt==nil {
println("could not create audio player")
return
}
playIt.numberOfLoops = -1
playIt.prepareToPlay()
playIt.play()
}
}
Try it both ways -- with playIt declared as an instance variable, and playIt as a local variable inside playMusic. You'll want to go with the former.
I'm also seconding nhgrif's suggestion: playMusic should take a String or String? parameter; not String!