From 1745f5eb6010011724f8b02cb26e429608b786a3 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 14 Mar 2024 00:34:10 +0100 Subject: [PATCH] Add basic doc comments (#2) Adds doc comments on some of the core types. --- Sources/swift-audio/AudioBuffer.swift | 7 ++++--- Sources/swift-audio/Waveforms/Saw.swift | 14 ++++++++++++++ Sources/swift-audio/Waveforms/Signal.swift | 3 +++ Sources/swift-audio/Waveforms/Square.swift | 13 ++++++++++++- Sources/swift-audio/Waveforms/Triangle.swift | 6 ++++++ Sources/swift-audio/main.swift | 6 ++++-- 6 files changed, 43 insertions(+), 6 deletions(-) diff --git a/Sources/swift-audio/AudioBuffer.swift b/Sources/swift-audio/AudioBuffer.swift index 14be877..b008f1f 100644 --- a/Sources/swift-audio/AudioBuffer.swift +++ b/Sources/swift-audio/AudioBuffer.swift @@ -10,14 +10,15 @@ // //===----------------------------------------------------------------------===// +/// A non-copyable buffer of audio samples. struct AudioBuffer: ~Copyable { let storage: UnsafeMutableBufferPointer - init(capacity: Int) { + /// Allocates an audio buffer and fills it with samples from a given signal. + /// - Parameter capacity: the number of samples + init(capacity: Int, source: inout some Signal) { self.storage = .allocate(capacity: capacity) - } - func fill(source: inout some Signal) { for i in self.storage.indices { let sample = source.next() self.storage[i] = sample diff --git a/Sources/swift-audio/Waveforms/Saw.swift b/Sources/swift-audio/Waveforms/Saw.swift index bd7a588..93bd324 100644 --- a/Sources/swift-audio/Waveforms/Saw.swift +++ b/Sources/swift-audio/Waveforms/Saw.swift @@ -10,17 +10,31 @@ // //===----------------------------------------------------------------------===// +/// Number of samples generated per second. let sampleRate = 44_100 +/// Stateless sawtooth-shaped waveform function. +/// - Parameters: +/// - time: Number of seconds passed since the current oscillation started. +/// - frequency: Frequency of oscillation, in hertz. +/// - Returns: An audio sample in the normalized range of -1.0...1.0 func saw(time: Float, frequency: Float) -> Float { let phase = time * frequency return 2 * (phase - (0.5 + phase).rounded(.down)) } +/// Stateful sawtooth-shaped signal. struct Saw: Signal { + /// Frequency of oscillation, in hertz. var frequency: Float = 440.0 + + /// The "volume" of the signal, i.e. the absolute boundary of the range in which this signal oscillates. Default + /// amplitude of 1.0 means that samples returned from ``Saw/next()`` will always stay in `-1.0...1.0` range. var amplitude: Float = 1.0 + + /// Number of seconds passed since the current oscillation started. To avoid overflowing, this value is reset t + /// 0.0 after every oscillation. var currentTime: Float = 0.0 mutating func next() -> Float { diff --git a/Sources/swift-audio/Waveforms/Signal.swift b/Sources/swift-audio/Waveforms/Signal.swift index b1fa8ca..bc2e7af 100644 --- a/Sources/swift-audio/Waveforms/Signal.swift +++ b/Sources/swift-audio/Waveforms/Signal.swift @@ -10,6 +10,9 @@ // //===----------------------------------------------------------------------===// +/// An abstract digital signal that produces an infinite amount of samples. protocol Signal { + /// Updates current state of the signal and produces the next sample. + /// - Returns: The latest sample in this signal. mutating func next() -> Float } diff --git a/Sources/swift-audio/Waveforms/Square.swift b/Sources/swift-audio/Waveforms/Square.swift index b4199ca..fb0ca38 100644 --- a/Sources/swift-audio/Waveforms/Square.swift +++ b/Sources/swift-audio/Waveforms/Square.swift @@ -10,15 +10,26 @@ // //===----------------------------------------------------------------------===// +/// Stateful square-shaped waveform. For values of ``Square/pulseWidth`` other than the default 0.5, strictly speaking +/// it produces a rectangular-shaped waveform. struct Square: Signal { + /// Frequency of oscillations in hertz. var frequency: Float { didSet { self.saw.frequency = self.frequency } } + + /// The "volume" of the signal, i.e. the absolute boundary of the range in which this signal oscillates. Default + /// amplitude of 1.0 means that samples returned from ``Square/next()`` will always stay in `-1.0...1.0` range. var amplitude: Float + + /// The ratio of a width of a pulse in this waveform in the range of `0.0..<1.0`. The default value of 0.5 makes + /// the pulse look like a square. Values smaller than 0.5 will make it more narrow, values larger than 0.5 make it + /// wider. var pulseWidth: Float + /// The underlying saw-shaped waveform used as a helper to compute samples. private var saw: Saw init( @@ -39,4 +50,4 @@ struct Square: Signal { -amplitude } } -} \ No newline at end of file +} diff --git a/Sources/swift-audio/Waveforms/Triangle.swift b/Sources/swift-audio/Waveforms/Triangle.swift index 9b669c7..c3cced7 100644 --- a/Sources/swift-audio/Waveforms/Triangle.swift +++ b/Sources/swift-audio/Waveforms/Triangle.swift @@ -12,10 +12,16 @@ import VultDSP +/// Stateful triangle-shaped waveform. struct Triangle: Signal { + /// The pitch parameter of the waveform that sets its tone. var pitch: Pitch + + /// The "volume" of the signal, i.e. the absolute boundary of the range in which this signal oscillates. Default + /// amplitude of 1.0 means that samples returned from ``Triangle/next()`` will always stay in `-1.0...1.0` range. var amplitude: Float = 1.0 + /// The state managed by the underlying VultDSP implementation of the signal. var state = Triangle__ctx_type_0() mutating func next() -> Float { diff --git a/Sources/swift-audio/main.swift b/Sources/swift-audio/main.swift index e96a7ec..8ee3be7 100644 --- a/Sources/swift-audio/main.swift +++ b/Sources/swift-audio/main.swift @@ -48,8 +48,10 @@ func main() { ) let totalLengthInSeconds = 6 - let buffer = AudioBuffer(capacity: sampleRate * totalLengthInSeconds) - buffer.fill(source: &mixer) + let buffer = AudioBuffer( + capacity: sampleRate * totalLengthInSeconds, + source: &mixer + ) Audio.encode(buffer) Plotter(