decode morse code by character swift - swift

I am trying to make a morse code converter in a swift playground. I got the conversion to work, but I need to make the code "speak" with AVFoundation. How can I decode the morse code string to play the short beep for every '.' and the long beep for every '-'?
Here's my code so far:
func speakTheCode(message: String) {
var speaker = AVAudioPlayer()
let longBeep = URL(fileURLWithPath: Bundle.main.path(forResource: "beep_long", ofType: "mp3")!)
let shortBeep = URL(fileURLWithPath: Bundle.main.path(forResource: "beep_short", ofType: "mp3")!)
try! speaker = AVAudioPlayer(contentsOf: longBeep)
try! speaker = AVAudioPlayer(contentsOf: shortBeep)
speaker.prepareToPlay()
}

Just try to decode the string to the correspondingly audio.
func speakTheCode(message: String) {
var audioItems: [AVPlayerItem] = []
guard let longPath = Bundle.main.path(forResource: "beep_long", ofType: "mp3"),
let shortPath = Bundle.main.path(forResource: "beep_short", ofType: "mp3") else {
print("Path is not availabel")
return
}
let longBeep = AVPlayerItem(url: URL(fileURLWithPath: longPath))
let shortBeep = AVPlayerItem(url: URL(fileURLWithPath: shortPath))
for character in message.characters {
if character == Character("-") {
audioItems.append(longBeep)
} else if character == Character(".") {
audioItems.append(shortBeep)
}
}
let player = AVQueuePlayer(items: audioItems)
player.play()
}
speakTheCode(message: "..--..")

Related

How to play several sound in a row

The goal is to play several sounds one after another (getReady -> nextExercise -> burpees).
The problem is that only the first one is being played
How it should work:
I call playGetReady() from WorkoutTabataViewController
I plays the first sound
After the first sound is finished, automatically "audioPlayerDidFinishPlaying()" is being called
It triggers "playNextSound()" func, which playing next sound
But audioPlayerDidFinishPlaying() is not being called. Or am I missing something and it should work differently?
class AudioPlayerManager: AVAudioPlayerDelegate {
var description: String
static let shared = AudioPlayerManager()
var audioPlayer: AVAudioPlayer?
var workoutVC: WorkoutTabataViewController?
var mainVC: MainTabataViewController?
var currentSound = 0
let urls: [URL]
init() {
self.description = ""
//First sound
let getReady = Bundle.main.path(forResource: "Get ready", ofType: "mp3")!
let urlGetReady = URL(fileURLWithPath: getReady)
//Second sound
let nextExercise = Bundle.main.path(forResource: "Next Exercise", ofType: "mp3")!
let urlNextExercise = URL(fileURLWithPath: nextExercise)
//Third sound
let burpees = Bundle.main.path(forResource: "Burpees", ofType: "mp3")!
let urlBurpees = URL(fileURLWithPath: burpees)
urls = [urlGetReady, urlNextExercise, urlBurpees]
}
func playGetReady() {
do {
audioPlayer = try AVAudioPlayer(contentsOf: urls[currentSound])
audioPlayer?.delegate = self
audioPlayer?.play()
} catch {
print(error)
}
}
func playNextSound() {
currentSound += 1
if currentSound < urls.count {
do {
audioPlayer = try AVAudioPlayer(contentsOf: urls[currentSound])
audioPlayer?.delegate = self
audioPlayer?.play()
} catch {
print(error)
}
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
if flag {
playNextSound()
}
}
}
Your audio manager class is not introspectable. Say #objc func audioPlayerDidFinishPlaying or, better, make it an NSObject.

AVFoundation bugs, No sound when I run audioPlayer.play()

I have a little problem with AVFoundation, when I launch a sound there is nothing that comes out. On the other hand it is enough to add a timer that displays the currentTime of the sound in question and everything works correctly. could you help me? Thanks.
code that does not work:
do {
let path = Bundle.main.path(forResource: "sound1", ofType: "mp3")!
let url = URL(fileURLWithPath: path)
let audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.volume = 1.0
audioPlayer.play()
} catch {
assertionFailure("Failed crating audio player: \(error).")
return
}
just add the timer and everything will work:
do {
let path = Bundle.main.path(forResource: "sound1", ofType: "mp3")!
let url = URL(fileURLWithPath: path)
let audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.volume = 1.0
audioPlayer.play()
print("le son est en cours de lecture !")
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer) in
print(audioPlayer.currentTime)
}
} catch {
assertionFailure("Failed crating audio player: \(error).")
return
}
This worked for me
instead of
let audioPlayer = try AVAudioPlayer(contentsOf: url)
change to
audioPlayer = try AVAudioPlayer(contentsOf: url)

Swift 3: AVAudioPlayer not playing sound

I have a struct with my audio player in it:
struct MT_Audio {
func playAudio(_ fileName:String, _ fileExtension:String, _ atVolume:Float) {
var audioPlayer = AVAudioPlayer()
if let audioPath = Bundle.main.path(forResource: fileName, ofType: fileExtension) {
let audioURL = URL(string:audioPath)
do {
audioPlayer = try AVAudioPlayer(contentsOf: audioURL!)
audioPlayer.volume = atVolume
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print(error)
}
}
}
}
//I'm calling it in viewDidLoad like this:
guard let fileURL = Bundle.main.url(forResource:"heartbeat-01a", withExtension: "mp3")
else {
print("can't find file")
return
}
let myAudioPlayer = MT_Audio() //<--RESOLVED THE ISSUE BY MAKING THIS A PROPERTY OF THE VIEWCONTROLLER
myAudioPlayer.playAudio("heartbeat-01a", "mp3", 1.0)
Since it doesn't crash and burn on the guard I know the file is there. I've also put a break point in after the try and I am getting to the audio player. When I go to the actual file and click on it in Xcode it plays. This fails on both the sim and device. Any help would be appreciated.
Looks like your audioPlayer is only stored within your playAudio function.
Try to keep the audioPlayer as an variable inside your class like this:
struct MT_Audio {
var audioPlayer: AVAudioPlayer?
mutating func playAudio(_ fileName:String, _ fileExtension:String, _ atVolume:Float) {
// is now member of your struct -> var audioPlayer = AVAudioPlayer()
if let audioPath = Bundle.main.path(forResource: fileName, ofType: fileExtension) {
let audioURL = URL(string:audioPath)
do {
let audioPlayer = try AVAudioPlayer(contentsOf: audioURL!)
audioPlayer.volume = atVolume
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print(error)
}
}
}
}

Create a function from code

How do I create a function from this code in swift3?
I have a button which is pressed then plays this sound "push"
How can it be simplified when there are lots of buttons? I don't want to add all codes to every button.
var myAudio = AVAudioPlayer()
// Add sound
do {
try myAudio = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath:
Bundle.main.path(forResource: "push", ofType: "mp3")!) as URL)
} catch {
NSLog("No file!")
}
//call the sound
myAudio.play()
I made this change
func play(name : String){
do {
try myAudio = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath:
Bundle.main.path(forResource: name, ofType: "mp3")!) as URL)
} catch {
NSLog("No file!")
}
}
#IBAction func buttonFirst(_ sender: UIButton) {
play(name: "push")
myAudio.play()
}
#IBAction func buttonSecond(_ sender: UIButton) {
play(name: "second")
myAudio.play()
}
I got this output:
2017-07-25 16:13:23.270349+0100 sound[1728:933024] [aqme] 254: AQDefaultDevice (173): skipping input stream 0 0 0x0
Is that a problem?
I think you forgot the prepare
var audioPlayer = AVAudioPlayer()
let sound = URL(fileURLWithPath: Bundle.main.path(forResource: "sound", ofType: "mp3")!)
try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try! AVAudioSession.sharedInstance().setActive(true)
try! audioPlayer = AVAudioPlayer(contentsOf: sound)
audioPlayer.prepareToPlay()
audioPlayer.play()
You can use it in the following way
var myAudio : AVAudioPlayer?
func playSound(){
let path = Bundle.main.path(forResource: "push", ofType:"mp3")!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
self.myAudio = sound
sound.numberOfLoops = 1
sound.prepareToPlay()
sound.play()
} catch {
print("error loading file")
// couldn't load file :(
}
}
Furthermore you can use SwiftySound that lets you play sounds easily in Swift 3.
for example
Sound.play(file: "push.mp3")

Swift 3 enum in functions causes app to crash

I'm trying to play a sound based on file name. I created an enum with all file names. Everything works, except this case, where I check for the soundType.click
func playSound(type: soundType) {
var soundUrl = URL.init(fileURLWithPath: Bundle.main.path(forResource: type.rawValue, ofType: "aiff")!)
if type.rawValue == soundType.click.rawValue {
soundUrl = URL.init(fileURLWithPath: Bundle.main.path(forResource: type.rawValue, ofType: "wav")!)
}
do {
audioPlayer = try AVAudioPlayer(contentsOf: soundUrl)
audioPlayer.play()
} catch _ { }
}
And here is my enum
enum soundType: String {
case selectAnswer = "answerSelected"
case correctAnswer = "correctAnswer"
case wrongAnswer = "wrongAnswer"
case click = "click"
}
The problem is here where I check for "type.rawValue == soundType.click.rawValue"
Here is the error
fatal error: unexpectedly found nil while unwrapping an Optional value
You should take a look at this line of code first.
var soundUrl = URL.init(fileURLWithPath: Bundle.main.path(forResource: type.rawValue, ofType: "aiff")!)
soundUrl = URL.init(fileURLWithPath: Bundle.main.path(forResource: type.rawValue, ofType: "wav")!)
Here, you are force unwrapping a failable initializer. You should check if Bundle.main.path(forResource: type.rawValue, ofType: "aiff")!) exists first by doing something like this...
if let soundUrl = URL.init(fileURLWithPath: Bundle.main.path(forResource: type.rawValue, ofType: "aiff")){
if type.rawValue == soundType.click.rawValue {
...
}
or you could also use a guard statement..
Check this blog post by Natashtherobot to learn more about how to unwrap stuff well. https://www.natashatherobot.com/swift-guard-better-than-if/