Tightened the source code and README documentations in the library.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
internal import CPlaydate
|
||||
|
||||
extension Sound {
|
||||
/// A synthesizer voice. Wraps `PDSynth`.
|
||||
/// A synthesizer voice. Wraps `PDSynth`. Keeps samples and generators set on it alive.
|
||||
public final class Synth: Source {
|
||||
private static var api: UnsafePointer<playdate_sound_synth> { Playdate.synthAPI.unsafelyUnwrapped }
|
||||
|
||||
@@ -37,7 +37,7 @@ extension Sound {
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies the synth (and its generator, if any).
|
||||
/// An independently owned copy, including any generator.
|
||||
public func copy() -> Synth {
|
||||
Synth(pointer: Synth.api.pointee.copy.unsafelyUnwrapped(pointer).unsafelyUnwrapped,
|
||||
isOwned: true)
|
||||
@@ -49,15 +49,15 @@ extension Sound {
|
||||
Synth.api.pointee.setWaveform.unsafelyUnwrapped(pointer, waveform.cValue)
|
||||
}
|
||||
|
||||
/// Plays a sample instead of a waveform. A nonzero sustain range
|
||||
/// loops that part of the sample while the note is held.
|
||||
/// Plays `sample` (uncompressed PCM, not ADPCM). Frames `sustainStart..<sustainEnd`
|
||||
/// loop while held; `sustainEnd` 0 with nonzero `sustainStart` means the sample's end.
|
||||
public func setSample(_ sample: AudioSample, sustainStart: UInt32 = 0, sustainEnd: UInt32 = 0) {
|
||||
retainedSample = sample
|
||||
Synth.api.pointee.setSample.unsafelyUnwrapped(pointer, sample.pointer, sustainStart, sustainEnd)
|
||||
}
|
||||
|
||||
/// Uses a wavetable for the synth. `log2size` is the base-2 log of
|
||||
/// each waveform's size (e.g. 8 for 256 samples).
|
||||
/// Plays `sample` (16-bit mono, uncompressed) as `columns` × `rows` cells of
|
||||
/// 2^`log2size` samples; parameters 1–4 select the position.
|
||||
public func setWavetable(_ sample: AudioSample, log2size: Int,
|
||||
columns: Int, rows: Int) throws(PlaydateError) {
|
||||
retainedSample = sample
|
||||
@@ -67,7 +67,7 @@ extension Sound {
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides audio via custom Swift callbacks.
|
||||
/// `copy()` shares `generator`.
|
||||
public func setGenerator(stereo: Bool, _ generator: Generator) {
|
||||
let box = Unmanaged.passRetained(GeneratorBox(generator, stereo: stereo))
|
||||
Synth.api.pointee.setGenerator.unsafelyUnwrapped(
|
||||
@@ -108,45 +108,44 @@ extension Sound {
|
||||
|
||||
// MARK: Envelope
|
||||
|
||||
/// The envelope's attack time, in seconds.
|
||||
/// In seconds.
|
||||
public func setAttackTime(_ attack: Float) {
|
||||
Synth.api.pointee.setAttackTime.unsafelyUnwrapped(pointer, attack)
|
||||
}
|
||||
|
||||
/// The envelope's decay time, in seconds.
|
||||
/// In seconds.
|
||||
public func setDecayTime(_ decay: Float) {
|
||||
Synth.api.pointee.setDecayTime.unsafelyUnwrapped(pointer, decay)
|
||||
}
|
||||
|
||||
/// The envelope's sustain level, 0...1.
|
||||
/// 0...1.
|
||||
public func setSustainLevel(_ sustain: Float) {
|
||||
Synth.api.pointee.setSustainLevel.unsafelyUnwrapped(pointer, sustain)
|
||||
}
|
||||
|
||||
/// The envelope's release time, in seconds.
|
||||
/// In seconds.
|
||||
public func setReleaseTime(_ release: Float) {
|
||||
Synth.api.pointee.setReleaseTime.unsafelyUnwrapped(pointer, release)
|
||||
}
|
||||
|
||||
/// The synth's amplitude envelope. Owned by the synth.
|
||||
/// The amplitude envelope; owned by the synth, valid only while it is alive.
|
||||
public var envelope: Envelope? {
|
||||
guard let envelope = Synth.api.pointee.getEnvelope.unsafelyUnwrapped(pointer) else { return nil }
|
||||
return Envelope(pointer: envelope, isOwned: false)
|
||||
}
|
||||
|
||||
/// Clears the synth's envelope so it plays at constant volume.
|
||||
public func clearEnvelope() {
|
||||
Synth.api.pointee.clearEnvelope.unsafelyUnwrapped(pointer)
|
||||
}
|
||||
|
||||
// MARK: Modulation
|
||||
// MARK: Pitch, modulation, and parameters
|
||||
|
||||
/// Transposes played notes by `halfSteps` (fractional values allowed).
|
||||
/// Fractional half-steps allowed.
|
||||
public func setTranspose(_ halfSteps: Float) {
|
||||
Synth.api.pointee.setTranspose.unsafelyUnwrapped(pointer, halfSteps)
|
||||
}
|
||||
|
||||
/// Modulates the synth's frequency.
|
||||
/// 1 is an octave up, -1 an octave down.
|
||||
public var frequencyModulator: SignalValue? {
|
||||
get { SignalValue.wrap(Synth.api.pointee.getFrequencyModulator.unsafelyUnwrapped(pointer)) }
|
||||
set {
|
||||
@@ -155,7 +154,6 @@ extension Sound {
|
||||
}
|
||||
}
|
||||
|
||||
/// Modulates the synth's amplitude.
|
||||
public var amplitudeModulator: SignalValue? {
|
||||
get { SignalValue.wrap(Synth.api.pointee.getAmplitudeModulator.unsafelyUnwrapped(pointer)) }
|
||||
set {
|
||||
@@ -164,26 +162,25 @@ extension Sound {
|
||||
}
|
||||
}
|
||||
|
||||
/// The number of parameters the synth's generator supports.
|
||||
/// The number of parameters the generator supports.
|
||||
public var parameterCount: Int {
|
||||
Int(Synth.api.pointee.getParameterCount.unsafelyUnwrapped(pointer))
|
||||
}
|
||||
|
||||
/// Sets a generator parameter. Returns `false` if the parameter is
|
||||
/// invalid.
|
||||
/// `parameter` is 1-based. Returns `false` if it is invalid.
|
||||
@discardableResult
|
||||
public func setParameter(_ parameter: Int, value: Float) -> Bool {
|
||||
Synth.api.pointee.setParameter.unsafelyUnwrapped(pointer, Int32(parameter), value) != 0
|
||||
}
|
||||
|
||||
/// Modulates a generator parameter.
|
||||
/// `parameter` is 1-based.
|
||||
public func setParameterModulator(_ parameter: Int, _ modulator: SignalValue?) {
|
||||
retain(modulator)
|
||||
Synth.api.pointee.setParameterModulator.unsafelyUnwrapped(pointer, Int32(parameter),
|
||||
modulator?.pointer)
|
||||
}
|
||||
|
||||
/// The modulator installed on a generator parameter, if any.
|
||||
/// `parameter` is 1-based.
|
||||
public func parameterModulator(_ parameter: Int) -> SignalValue? {
|
||||
SignalValue.wrap(Synth.api.pointee.getParameterModulator.unsafelyUnwrapped(pointer, Int32(parameter)))
|
||||
}
|
||||
@@ -196,26 +193,25 @@ extension Sound {
|
||||
|
||||
// MARK: Playing
|
||||
|
||||
/// Plays a note at `frequency` Hz. `length` is in seconds; `nil`
|
||||
/// plays until `noteOff()`. `when` is the audio-clock time to start,
|
||||
/// or 0 for immediately.
|
||||
/// `frequency` in Hz; `length` in seconds, `nil` until `noteOff(when:)`;
|
||||
/// `when` is an audio-clock time, 0 for now.
|
||||
public func playNote(frequency: Float, velocity: Float = 1,
|
||||
length: Float? = nil, when: UInt32 = 0) {
|
||||
Synth.api.pointee.playNote.unsafelyUnwrapped(pointer, frequency, velocity, length ?? -1, when)
|
||||
}
|
||||
|
||||
/// Plays a MIDI note, where 60 is middle C.
|
||||
/// 60 is C4; fractional notes allowed. Other arguments as in `playNote`.
|
||||
public func playMIDINote(_ note: MIDINote, velocity: Float = 1,
|
||||
length: Float? = nil, when: UInt32 = 0) {
|
||||
Synth.api.pointee.playMIDINote.unsafelyUnwrapped(pointer, note, velocity, length ?? -1, when)
|
||||
}
|
||||
|
||||
/// Releases the playing note at time `when`, or immediately if 0.
|
||||
/// Releases the note at audio-clock time `when`, or now if 0.
|
||||
public func noteOff(when: UInt32 = 0) {
|
||||
Synth.api.pointee.noteOff.unsafelyUnwrapped(pointer, when)
|
||||
}
|
||||
|
||||
/// Stops the synth immediately, without playing the release phase.
|
||||
/// Stops immediately, skipping the release phase.
|
||||
public func stop() {
|
||||
Synth.api.pointee.stop.unsafelyUnwrapped(pointer)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user