Showing posts with label audio. Show all posts
Showing posts with label audio. Show all posts

Sunday, May 21, 2017

Conversion from Numbered Musical Notation to Musical Note Letters

The code below converts Numbered Musical Notation (簡譜) to musical note letters using Xcode 8.3.2 playground in Swift 3.1. Techniques used in the code involves:

1. Separating a string into an array
2. Type casting each array element into an integer

3. Converting the numerical notation into a matched letter
4. Joining all letters into a single string

//Twinkle, Twinkle, Little Star 一閃一閃亮晶晶
let numberedNotation = "1 1 5 5 6 6 5"

//1. Separating a string into an array let numberedNoteArray = numberedNotation.components(separatedBy: " ")

let lookupTable = ["C","D","E","F","G","A","B"]

var noteArray = [String]()

for note in numberedNoteArray {
    //2. Type casting each array element into an integer
    let noteInt = Int(note)!

    //3. Converting the numerical notation into a matched letter
    let noteChar = lookupTable[noteInt-1]
    noteArray.append(noteChar)
}

//4. Joining all letters into a single string let noteString = noteArray.joined(separator: " ")

print("\(noteString)")

Result:

C C G G A A G

Sunday, May 7, 2017

Modified Version of AudioKit's Microphone Analysis Example without using the Storyboard

The code below is modified from AudioKit's Microphone Analysis example. The UI components are written programmatically without using the storyboard. The code is developed with Xcode 8.3.2 (Swift 3.1) and iOS 10.

1. Use CocoaPods to include the AudioKit framework by add this line to the Podfile:

pod 'AudioKit'

*************** Updated October 4, 2020 for AudioKit 4 *****************
Type this terminal command:

pod install



*************************** Update 2020 End *****************************

2. Enable the microphone by adding NSMicrophoneUsageDescription and a request string such as "This app needs microphone access." to Info.plist.

Your Info.plist should be like this:


When app is run at the first time, this message should be displayed:



Without this modification, you'll see error like this:


This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSMicrophoneUsageDescription key with a string value explaining to the user how the app uses this data.

3. Modify ViewController.swift as below

import UIKit
import AudioKit

class ViewController: UIViewController {
    
    var labelFrequencyValue : UILabel!
    var labelAmplitudeValue : UILabel!
    var labelSharpValue : UILabel!
    var labelFlatValue : UILabel!
    let mic = AKMicrophone()
    var tracker : AKFrequencyTracker!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let labelSing = UILabel(frame: CGRect(x: 0, y: 28, width: view.frame.width, height: 50))
        labelSing.text = "Sing into the Microphone"
        labelSing.textAlignment = .center
        labelSing.font = UIFont.systemFont(ofSize: 24, weight: UIFontWeightBold) //System Font Bold
        labelSing.textColor = UIColor.white
        labelSing.backgroundColor = UIColor(red: 2/255, green: 181/255, blue: 31/255, alpha: 1.0)
        view.addSubview(labelSing)
        
        let labelFrequency = UILabel(frame: CGRect(x: 16, y: 86, width: 85.5, height: 20.5))
        labelFrequency.text = "Frequency:"
        view.addSubview(labelFrequency)
        
        labelFrequencyValue = UILabel(frame: CGRect(x: view.frame.width-70, y: 86, width: 50, height: 20.5))
        labelFrequencyValue.text = "0"
        labelFrequencyValue.textAlignment = .right
        view.addSubview(labelFrequencyValue)
        
        let labelAmplitude = UILabel(frame: CGRect(x: 16, y: 114.5, width: 85.5, height: 20.5))
        labelAmplitude.text = "Amplitude:"
        view.addSubview(labelAmplitude)
        
        labelAmplitudeValue = UILabel(frame: CGRect(x: view.frame.width-70, y: 114.5, width: 50, height: 20.5))
        labelAmplitudeValue.text = "0"
        labelAmplitudeValue.textAlignment = .right
        view.addSubview(labelAmplitudeValue)
        
        let labelSharp = UILabel(frame: CGRect(x: 16, y: 142, width: 111.5, height: 20.5))
        labelSharp.text = "Note (Sharps):"
        view.addSubview(labelSharp)
        
        labelSharpValue = UILabel(frame: CGRect(x: view.frame.width-70, y: 142, width: 50, height: 20.5))
        labelSharpValue.text = "C4"
        labelSharpValue.textAlignment = .right
        view.addSubview(labelSharpValue)
        
        let labelFlat = UILabel(frame: CGRect(x: 16, y: 170.5, width: 94, height: 20.5))
        labelFlat.text = "Note (Flats):"
        view.addSubview(labelFlat)
        
        labelFlatValue = UILabel(frame: CGRect(x: view.frame.width-70, y: 170.5, width: 50, height: 20.5))
        labelFlatValue.text = "F4"
        labelFlatValue.textAlignment = .right
        view.addSubview(labelFlatValue)
        
        let labelPlot = UILabel(frame: CGRect(x: 0, y: 199, width: view.frame.width, height: 21.5))
        labelPlot.text = "Audio Input Plot"
        labelPlot.textAlignment = .center
        view.addSubview(labelPlot)
        

        tracker = AKFrequencyTracker.init(mic)
        let silence = AKBooster(tracker, gain: 0)
        AudioKit.output = silence
        AudioKit.start()
        
        setupPlot()
        
        Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateUI), userInfo: nil, repeats: true)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    func setupPlot() {
        let audioInputPlot = EZAudioPlot(frame: CGRect(x: 0, y: view.center.y, width: view.frame.width, height: 200))
        
        let plot = AKNodeOutputPlot(mic, frame: audioInputPlot.bounds)
        plot.plotType = .rolling
        plot.shouldFill = true
        plot.shouldMirror = true
        plot.color = UIColor.blue
        audioInputPlot.addSubview(plot)
        view.addSubview(audioInputPlot)
    }
    
    func updateUI() {
        
        let noteFrequencies = [16.35,17.32,18.35,19.45,20.6,21.83,23.12,24.5,25.96,27.5,29.14,30.87]
        let noteNamesWithSharps = ["C", "C","D","D","E","F","F","G","G","A","A","B"]
        let noteNamesWithFlats = ["C", "D","D","E","E","F","G","G","A","A","B","B"]
        
        if tracker.amplitude > 0.1 {
            labelFrequencyValue.text = String(format: "%0.1f", tracker.frequency)
        
            var frequency = Float(tracker.frequency)
            while (frequency > Float(noteFrequencies[noteFrequencies.count-1])){
                frequency = frequency / 2.0
            }
            while (frequency < Float(noteFrequencies[0])) {
                frequency = frequency * 2.0
            }
            
            var minDistance : Float = 10000.0
            var index = 0
            
            for i in 0..<noteFrequencies.count {
                let distance = fabsf(Float(noteFrequencies[i]) - frequency)
                if (distance < minDistance) {
                    index = i
                    minDistance = distance
                }
            }
            let octave = Int(log2f(Float(tracker.frequency) / frequency))
            labelSharpValue.text = "\(noteNamesWithSharps[index])\(octave)"
            labelFlatValue.text = "\(noteNamesWithFlats[index])\(octave)"
        }
        labelAmplitudeValue.text = String(format: "%0.2f", tracker.amplitude)
    }

}

4. Result:



Related Information

AudioKit
Beethoven (Pitch Detection)




Tuesday, June 7, 2016

Select the iOS device or bluetooth audio output with action sheet

While playing a sound file with AVAudioPlayer, the following code may be used to select the audio output between the speaker of an iPhone/iPad or the bluetooth headset in an action sheet:


let buttonOutput = UIButton(frame: CGRectMake(0, 0, 200, 30))
buttonOutput.center = CGPointMake(view.center.x, view.center.y+200)
buttonOutput.setTitle("Output", forState: UIControlState.Normal)
buttonOutput.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
buttonOutput.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
buttonOutput.addTarget(self, action: #selector(buttonOutputPressed), forControlEvents: UIControlEvents.TouchUpInside)

view.addSubview(buttonOutput)

and

func buttonOutputPressed() {
        
    let model = UIDevice.currentDevice().model
        
    let session = AVAudioSession()
        
    let controller = UIAlertController(title: "Select Output", message: "", preferredStyle: UIAlertControllerStyle.ActionSheet)
        controller.addAction(UIAlertAction(title: model, style: UIAlertActionStyle.Default, handler: { action in
    do {
        try session.setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: AVAudioSessionCategoryOptions.DefaultToSpeaker)
    } catch {
        print("AVAudioSession error!")
    }
    }))
    controller.addAction(UIAlertAction(title: "Bluetooth", style: UIAlertActionStyle.Default, handler: { action in
    do {
        try session.setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: AVAudioSessionCategoryOptions.AllowBluetooth)
    } catch {
        print("AVAudioSession error!")
    }
    }))
    presentViewController(controller, animated: true, completion: nil)
}

Result:



Sunday, May 29, 2016

Play a sound file with AVAudioPlayer

The example below plays an audio file in Swift 2.2 with Xcode 7.3.1.

1. Drag and add the example.mp3 sound file to the project.

2. Modify ViewController.swift as:


import UIKit
import AVFoundation

class ViewController: UIViewController {
    
    var button : UIButton!
    var buttonStop : UIButton!
    
    var player : AVAudioPlayer!
    let url = NSBundle.mainBundle().URLForResource("example", withExtension: "mp3")!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        //Play/Pause button
        button = UIButton(frame: CGRectMake(0, 0, 200, 30))
        button.center = view.center
        button.setTitle("Play", forState: UIControlState.Normal)
        button.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
        button.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
        button.addTarget(self, action: #selector(buttonPressed), forControlEvents: UIControlEvents.TouchUpInside)
        view.addSubview(button)
        
        //Stop button
        buttonStop = UIButton(frame: CGRectMake(0, 0, 200, 30))
        buttonStop.center = CGPointMake(view.center.x, view.center.y+100)
        buttonStop.setTitle("Stop", forState: UIControlState.Normal)
        buttonStop.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
        buttonStop.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
        buttonStop.addTarget(self, action: #selector(buttonStopPressed), forControlEvents: UIControlEvents.TouchUpInside)
        buttonStop.hidden = true
        view.addSubview(buttonStop)
        
        do {
            player = try AVAudioPlayer(contentsOfURL: url)
        } catch {
            print("Error!")
        }
    }
    
    func buttonPressed() {
        if player.playing {
            player.pause()
            button.setTitle("Play", forState: UIControlState.Normal)
        } else {
            player.play()
            button.setTitle("Pause", forState: UIControlState.Normal)
            buttonStop.hidden = false
        }
    }
    
    func buttonStopPressed() {
        player.stop()
        player.currentTime = 0 //rewind
        buttonStop.hidden = true
        button.setTitle("Play", forState: UIControlState.Normal)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

Tuesday, January 13, 2015

AVSpeechSynthesizer - Text-to-Speech (TTS) function

import UIKit
import AVFoundation

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let mySynthesizer = AVSpeechSynthesizer()
        let myUtterence = AVSpeechUtterance(string: "Hello World. Testing 1 2 3.")
        myUtterence.rate = AVSpeechUtteranceMinimumSpeechRate
        myUtterence.voice = AVSpeechSynthesisVoice(language: "en-au")
        myUtterence.pitchMultiplier = 0.5 //between 0.5 and 2.0. Default is 1.0.
        mySynthesizer.speakUtterance(myUtterence)

    }