Skip to content

Instantly share code, notes, and snippets.

@traviskirton
Created May 30, 2016 21:52
Show Gist options
  • Save traviskirton/bdf1a71d1efae9b87d90a4c3a4258618 to your computer and use it in GitHub Desktop.
Save traviskirton/bdf1a71d1efae9b87d90a4c3a4258618 to your computer and use it in GitHub Desktop.
Radial Audio Tutorial
class WorkSpace: CanvasController {
var player: AudioPlayer!
var timer: Timer?
//create tuples for storing paths
var maxPaths = (Path(), Path())
var avgPaths = (Path(), Path())
//create tuples for storing shapes to represent the paths
var maxShapes = (Shape(), Shape())
var avgShapes = (Shape(), Shape())
//the current angle for drawing
var Θ = 0.0
//store the max values for peak and average for the sample
//we will use these to normalize the metered values
var maxPeak = (30.981050491333, 31.1506500244141)
var avgPeak = (63.9939880371094, 63.8977127075195)
override func setup() {
canvas.backgroundColor = Color(red: 0.933, green: 1.0, blue: 0.0, alpha: 1.0)
setupShapes()
setupPlayer()
setupLogo()
setupTimer()
}
func setupLogo() {
let logo = Image("LFLogo")
logo?.anchorPoint = Point(0.337, 0.468)
logo?.center = canvas.center
canvas.add(logo)
}
func setupPlayer() {
player = AudioPlayer("BlackVelvet.mp3")
player?.meteringEnabled = true //needs to be on
player?.loops = true
player?.play()
}
func normalize(val: Double, max: Double) -> Double {
//Normalizes an incoming value based on a provided max
var normMax = abs(val)
//gives us a value between 0 and 1
normMax /= max
//map the value so that the shape doesn't overlap with the logo
return map(normMax, min: 0, max: 1, toMin: 100, toMax: 200)
}
func setupTimer() {
//create a timer to run at 60fps
timer = Timer(interval: 1.0/60.0) {
self.player.updateMeters()
self.generateNextPoints()
self.updateShapes()
}
timer?.start()
}
//from a given value, generates a point x, y, based on the stored angle
func generatePoint(radius: Double) -> Point {
return Point(radius * cos(Θ), radius * sin(Θ))
}
func generateNextPoints() {
//generates new points for each path
let max0 = normalize(player.peakPower(0), max: maxPeak.0)
maxPaths.0.addLineToPoint(generatePoint(max0))
let max1 = normalize(player.peakPower(1), max: maxPeak.1)
maxPaths.1.addLineToPoint(generatePoint(max1))
let avg0 = normalize(player.averagePower(0), max: avgPeak.0)
avgPaths.0.addLineToPoint(generatePoint(avg0))
let avg1 = normalize(player.averagePower(1), max: avgPeak.1)
avgPaths.1.addLineToPoint(generatePoint(avg1))
//increments the current angle
Θ += M_PI / 180.0
//resets the paths for each full rotation
if Θ >= 2 * M_PI {
Θ = 0.0
resetPaths()
}
}
func updateShapes() {
//set the path for each shape, and recenter it
maxShapes.0.path = maxPaths.0
maxShapes.0.center = canvas.center
maxShapes.1.path = maxPaths.1
maxShapes.1.center = canvas.center
avgShapes.0.path = avgPaths.0
avgShapes.0.center = canvas.center
avgShapes.1.path = avgPaths.1
avgShapes.1.center = canvas.center
}
func setupShapes() {
//set the paths for each shape
maxShapes.0.path = maxPaths.0
maxShapes.1.path = maxPaths.1
avgShapes.0.path = avgPaths.0
avgShapes.1.path = avgPaths.1
//style all the shapes
styleShape(maxShapes.0)
styleShape(maxShapes.1)
styleShape(avgShapes.0)
styleShape(avgShapes.1)
//add them all the the canvas
canvas.add(maxShapes.0)
canvas.add(maxShapes.1)
canvas.add(avgShapes.0)
canvas.add(avgShapes.1)
//rotate the 2nd, 3rd, and 4th shapes
maxShapes.1.transform.rotate(M_PI)
avgShapes.0.transform.rotate(M_PI_2)
avgShapes.1.transform.rotate(M_PI_2 * 3)
}
func styleShape(shape: Shape) {
shape.lineWidth = 0.5
shape.fillColor = clear
shape.strokeColor = black
}
//empties the paths of all points
//this will happen every time the angle gets to 2Pi
func resetPaths() {
maxPaths = (Path(), Path())
avgPaths = (Path(), Path())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment