Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Musical Phantoms
Search
TJ Usiyan
September 16, 2016
Programming
0
79
Musical Phantoms
Slides from my NSSpain 2016 talk
TJ Usiyan
September 16, 2016
Tweet
Share
More Decks by TJ Usiyan
See All by TJ Usiyan
Property-Based Testing with SwiftCheck
griotspeak
1
5.5k
Speaking in Types
griotspeak
0
32
Other Decks in Programming
See All in Programming
Devvox Belgium - Agentic AI Patterns
kdubois
1
110
その面倒な作業、「Dart」にやらせませんか? Flutter開発者のための業務効率化
yordgenome03
1
110
CI_CD「健康診断」のススメ。現場でのボトルネック特定から、健康診断を通じた組織的な改善手法
teamlab
PRO
0
200
After go func(): Goroutines Through a Beginner’s Eye
97vaibhav
0
350
Pull-Requestの内容を1クリックで動作確認可能にするワークフロー
natmark
2
490
Go言語の特性を活かした公式MCP SDKの設計
hond0413
1
230
Flutterで分数(Fraction)を表示する方法
koukimiura
0
130
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
400
ソフトウェア設計の実践的な考え方
masuda220
PRO
4
550
Pythonスレッドとは結局何なのか? CPython実装から見るNoGIL時代の変化
curekoshimizu
5
1.7k
Introducing ReActionView: A new ActionView-Compatible ERB Engine @ Kaigi on Rails 2025, Tokyo, Japan
marcoroth
3
980
(Extension DC 2025) Actor境界を越える技術
teamhimeh
1
250
Featured
See All Featured
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Context Engineering - Making Every Token Count
addyosmani
5
220
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
7
900
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
32
2.3k
Into the Great Unknown - MozCon
thekraken
40
2.1k
Art, The Web, and Tiny UX
lynnandtonic
303
21k
For a Future-Friendly Web
brad_frost
180
9.9k
Rebuilding a faster, lazier Slack
samanthasiow
84
9.2k
Fireside Chat
paigeccino
40
3.7k
Facilitating Awesome Meetings
lara
56
6.6k
Code Review Best Practice
trishagee
72
19k
Designing Experiences People Love
moore
142
24k
Transcript
Musical Phantoms © TJ Usiyan, 2016 1
Caveats 4 Details omitted 4 More Signals, Less Types 4
This is all exploratory © TJ Usiyan, 2016 2
This is All Exploratory 4 Problems of Interest 4 Semantics
4 Sample Rate 4 Infinite Sequences 4 User Input © TJ Usiyan, 2016 3
This is All Exploratory 1. Make it work 2. Make
it fast 3. Make it pretty © TJ Usiyan, 2016 4
This is All Exploratory 1. Make it work 2. Make
it pretty 3. Could it be prettier? 4. Make it prettier 5. Make it fast © TJ Usiyan, 2016 5
Stay Calm and Let It Wash Over You © TJ
Usiyan, 2016 6
The Plan 4 Math 4 Audio 4 Types 4 Phantom
Types © TJ Usiyan, 2016 7
Unit Circle1 1 from: Wikipedia, LucasVB Circle_cos_sin © TJ Usiyan,
2016 8
© TJ Usiyan, 2016 9
© TJ Usiyan, 2016 10
Hertz.swift typealias Samples = Int typealias Seconds = Double ///
Cycles (or periods) per second typealias Hertz = Double © TJ Usiyan, 2016 11
SampleRateType.swift public protocol SampleRateType { static var hertz: Hertz {
get } init() } © TJ Usiyan, 2016 12
SampleRateType.swift extension SampleRateType { var frameDuration: Seconds { return 1.0
/ Self.value } func convert(samples: Samples) -> Seconds { return frameDuration * Double(samples) } func convertToSamples(seconds: Seconds) -> Samples { return Int(Self.value * seconds) } } © TJ Usiyan, 2016 13
public struct SampleRate_44100 : SampleRateType { public static let hertz:
Hertz = 44100.0 public init() {} } public struct SampleRate_50 : SampleRateType { public static let hertz: Hertz = 50.0 public init() { } } public struct SampleRate_100 : SampleRateType { public static let hertz: Hertz = 100.0 public init() { } } public struct SampleRate_500 : SampleRateType { public static let hertz: Hertz = 500.0 public init() { } } public struct SampleRate_1000 : SampleRateType { public static let hertz: Hertz = 1000.0 public init() { } } © TJ Usiyan, 2016 14
Signals © TJ Usiyan, 2016 15
public protocol SignalType : Sequence { associatedtype SampleRate : SampleRateType
associatedtype Iterator : SignalGeneratorType } public protocol SignalGeneratorType : IteratorProtocol { associatedtype SampleRate : SampleRateType } © TJ Usiyan, 2016 16
Constant Return an unchanging value © TJ Usiyan, 2016 17
Constant.swift public struct Constant<T, SR : SampleRateType> { public let
value:T public init(value:T) { self.value = value } } © TJ Usiyan, 2016 18
Constant.swift extension Constant : SignalType { public typealias SampleRate =
SR public typealias Iterator = ConstantGenerator<T, SR> public func makeIterator() -> Iterator { return Iterator(signal: self) } } © TJ Usiyan, 2016 19
Constant.swift public struct ConstantGenerator<T, SR : SampleRateType> { fileprivate let
value:T fileprivate init(value:T) { self.value = value } fileprivate init(signal:Constant<T, SR>) { self.init(value: signal.value) } } © TJ Usiyan, 2016 20
SR? © TJ Usiyan, 2016 21
Oscillators © TJ Usiyan, 2016 22
Oscillators Sine(x) © TJ Usiyan, 2016 23
TimeSignal.swift struct TimeSignal<SR : SampleRateType> { init() { } }
© TJ Usiyan, 2016 24
TimeSignal.swift extension TimeSignal : SignalType { typealias SampleRate = SR
typealias Iterator = TimeSignalGenerator<SR> func makeIterator() -> Iterator { return Iterator(index: 0) } } © TJ Usiyan, 2016 25
TimeSignal.swift public struct TimeSignalGenerator<SR : SampleRateType> { fileprivate var index:Index
internal init(index:Index) { self.index = index } } © TJ Usiyan, 2016 26
TimeSignal.swift extension TimeSignalGenerator : SignalGeneratorType { public typealias SampleRate =
SR public typealias Element = (frame:Int, seconds:Double) public typealias Index = Int public mutating func next() -> Element? { let value = (frame:index, seconds:Double(index) / SR.hertz) index += 1 return value } } © TJ Usiyan, 2016 27
TimeSignal.swift extension TimeSignal : SignalType { typealias SampleRate = SR
typealias Iterator = TimeSignalGenerator<SR> func makeIterator() -> Iterator { return Iterator(index: 0) } } © TJ Usiyan, 2016 28
Oscillators are Continuous Functions of Time struct ContinuousTimeFunction<OutputType, SR :
SampleRateType> { let function:(_ time:Double) -> OutputType init(function:@escaping (_ time:Double) -> OutputType) { self.function = function } } © TJ Usiyan, 2016 29
Continuous Functions of Time public struct ContinuousTimeFunctionGenerator<OutputType, SR : SampleRateType>
{ public typealias Index = Int public typealias Function = (_ time:Double) -> OutputType fileprivate var clock:TimeSignal<SR>.Iterator fileprivate let function:Function public init(index:Index, function:@escaping Function) { self.clock = TimeSignalGenerator<SR>(index:index) self.function = function } fileprivate init(clock:TimeSignalGenerator<SR>, function:@escaping Function) { self.clock = clock self.function = function } } © TJ Usiyan, 2016 30
Sine let contFnSin: ContinuousTimeDoubleSignal = { let frequency: Hertz =
2 let period: Second = twoPi let initialPhase: Double = 0 let fn = { sample in return sin(initialPhase + sample * frequency * period) } return ContinuousTimeFunction(function: fn) }() © TJ Usiyan, 2016 31
Phase class Phase<SR : SampleRateType> { var value: Seconds {
didSet { if value >= period { value = value.truncatingRemainder(dividingBy: period) } } } let period: Seconds init(value: Seconds, period: Seconds) { self.value = fabs(value).truncatingRemainder(dividingBy: period) self.period = period } } © TJ Usiyan, 2016 32
Playground © TJ Usiyan, 2016 33
Drawbacks 4 Lock in to sample rate 4 Limitations with
generics 4 Inference. So much inference. © TJ Usiyan, 2016 34
© TJ Usiyan, 2016 35
© TJ Usiyan, 2016 36
© TJ Usiyan, 2016 37
© TJ Usiyan, 2016 38
© TJ Usiyan, 2016 39
Based on "Audio Processing and Sound Synthesis in Haskell" by
Eric Cheng and Paul Hudak © TJ Usiyan, 2016 40
Thank you Questions @griotspeak © TJ Usiyan, 2016 41